Merge branch 'branch-1.3' into debian
authorBdale Garbee <bdale@gag.com>
Thu, 19 Dec 2013 08:38:40 +0000 (01:38 -0700)
committerBdale Garbee <bdale@gag.com>
Thu, 19 Dec 2013 08:38:40 +0000 (01:38 -0700)
Conflicts:
ChangeLog
altoslib/AltosRecordMM.java
altosui/Makefile.am
altosui/altos-windows.nsi.in
configure.ac
debian/changelog
debian/control
doc/Makefile
doc/altusmetrum.xsl
doc/release-notes-1.2.1.xsl
doc/release-notes-1.2.xsl

589 files changed:
.gitignore
.gitmodules [new file with mode: 0644]
ChangeLog
Makefile.am
Releasing
altosdroid/AndroidManifest.xml
altosdroid/Notebook
altosdroid/src/org/altusmetrum/AltosDroid/AltosBluetooth.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidPreferences.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosDroidTab.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
altosdroid/src/org/altusmetrum/AltosDroid/Dumper.java
altosdroid/src/org/altusmetrum/AltosDroid/TabAscent.java
altosdroid/src/org/altusmetrum/AltosDroid/TabDescent.java
altosdroid/src/org/altusmetrum/AltosDroid/TabLanded.java
altosdroid/src/org/altusmetrum/AltosDroid/TabMap.java
altosdroid/src/org/altusmetrum/AltosDroid/TabPad.java
altosdroid/src/org/altusmetrum/AltosDroid/TelemetryLogger.java
altosdroid/src/org/altusmetrum/AltosDroid/TelemetryReader.java
altosdroid/src/org/altusmetrum/AltosDroid/TelemetryService.java
altoslib/AltosAccel.java
altoslib/AltosCRCException.java
altoslib/AltosCompanion.java [new file with mode: 0644]
altoslib/AltosConfigData.java
altoslib/AltosConfigValues.java
altoslib/AltosConvert.java
altoslib/AltosDebug.java
altoslib/AltosDistance.java
altoslib/AltosEeprom.java [new file with mode: 0644]
altoslib/AltosEepromChunk.java
altoslib/AltosEepromDownload.java [new file with mode: 0644]
altoslib/AltosEepromFile.java [new file with mode: 0644]
altoslib/AltosEepromHeader.java [new file with mode: 0644]
altoslib/AltosEepromIterable.java
altoslib/AltosEepromList.java [new file with mode: 0644]
altoslib/AltosEepromLog.java
altoslib/AltosEepromMega.java
altoslib/AltosEepromMegaIterable.java [deleted file]
altoslib/AltosEepromMetrum2.java [new file with mode: 0644]
altoslib/AltosEepromMini.java [new file with mode: 0644]
altoslib/AltosEepromMonitor.java [new file with mode: 0644]
altoslib/AltosEepromRecord.java [deleted file]
altoslib/AltosEepromTM.java [new file with mode: 0644]
altoslib/AltosEepromTeleScience.java [deleted file]
altoslib/AltosEepromTm.java [new file with mode: 0644]
altoslib/AltosFile.java
altoslib/AltosFlash.java
altoslib/AltosFlashListener.java
altoslib/AltosFlightReader.java
altoslib/AltosFrequency.java
altoslib/AltosGPS.java
altoslib/AltosGPSQuery.java [deleted file]
altoslib/AltosGPSSat.java
altoslib/AltosGreatCircle.java
altoslib/AltosHeight.java
altoslib/AltosHexfile.java
altoslib/AltosHexsym.java [new file with mode: 0644]
altoslib/AltosIMU.java
altoslib/AltosIMUQuery.java [deleted file]
altoslib/AltosIdle.java [new file with mode: 0644]
altoslib/AltosIdleFetch.java [new file with mode: 0644]
altoslib/AltosIdleMonitor.java
altoslib/AltosIdleMonitorListener.java
altoslib/AltosIgnite.java
altoslib/AltosLib.java
altoslib/AltosLine.java
altoslib/AltosLink.java
altoslib/AltosListenerState.java
altoslib/AltosLog.java
altoslib/AltosMag.java
altoslib/AltosMma655x.java [new file with mode: 0644]
altoslib/AltosMs5607.java
altoslib/AltosMs5607Query.java [deleted file]
altoslib/AltosNoSymbol.java [new file with mode: 0644]
altoslib/AltosOrderedMegaRecord.java [deleted file]
altoslib/AltosOrderedRecord.java [deleted file]
altoslib/AltosParse.java
altoslib/AltosPreferences.java
altoslib/AltosPreferencesBackend.java
altoslib/AltosProgrammer.java [new file with mode: 0644]
altoslib/AltosPyro.java
altoslib/AltosRecord.java [deleted file]
altoslib/AltosRecordCompanion.java [deleted file]
altoslib/AltosRecordIterable.java [deleted file]
altoslib/AltosRecordMM.java [deleted file]
altoslib/AltosRecordNone.java [deleted file]
altoslib/AltosRecordTM.java [deleted file]
altoslib/AltosReplayReader.java
altoslib/AltosRomconfig.java
altoslib/AltosSelfFlash.java [new file with mode: 0644]
altoslib/AltosSensorEMini.java [new file with mode: 0644]
altoslib/AltosSensorMM.java
altoslib/AltosSensorMega.java [new file with mode: 0644]
altoslib/AltosSensorMetrum.java [new file with mode: 0644]
altoslib/AltosSensorTM.java
altoslib/AltosSensorTMini.java [new file with mode: 0644]
altoslib/AltosSpeed.java
altoslib/AltosState.java
altoslib/AltosStateIterable.java [new file with mode: 0644]
altoslib/AltosStateUpdate.java [new file with mode: 0644]
altoslib/AltosTelemetry.java
altoslib/AltosTelemetryConfiguration.java [new file with mode: 0644]
altoslib/AltosTelemetryFile.java [new file with mode: 0644]
altoslib/AltosTelemetryIterable.java
altoslib/AltosTelemetryLegacy.java [new file with mode: 0644]
altoslib/AltosTelemetryLocation.java [new file with mode: 0644]
altoslib/AltosTelemetryMap.java
altoslib/AltosTelemetryMegaData.java [new file with mode: 0644]
altoslib/AltosTelemetryMegaSensor.java [new file with mode: 0644]
altoslib/AltosTelemetryMetrumData.java [new file with mode: 0644]
altoslib/AltosTelemetryMetrumSensor.java [new file with mode: 0644]
altoslib/AltosTelemetryMini.java [new file with mode: 0644]
altoslib/AltosTelemetryRaw.java [new file with mode: 0644]
altoslib/AltosTelemetryReader.java
altoslib/AltosTelemetryRecord.java [deleted file]
altoslib/AltosTelemetryRecordCompanion.java [deleted file]
altoslib/AltosTelemetryRecordConfiguration.java [deleted file]
altoslib/AltosTelemetryRecordGeneral.java [deleted file]
altoslib/AltosTelemetryRecordLegacy.java [deleted file]
altoslib/AltosTelemetryRecordLocation.java [deleted file]
altoslib/AltosTelemetryRecordMegaData.java [deleted file]
altoslib/AltosTelemetryRecordMegaSensor.java [deleted file]
altoslib/AltosTelemetryRecordRaw.java [deleted file]
altoslib/AltosTelemetryRecordSatellite.java [deleted file]
altoslib/AltosTelemetryRecordSensor.java [deleted file]
altoslib/AltosTelemetrySatellite.java [new file with mode: 0644]
altoslib/AltosTelemetrySensor.java [new file with mode: 0644]
altoslib/AltosTelemetryStandard.java [new file with mode: 0644]
altoslib/AltosTemperature.java
altoslib/AltosUnits.java
altoslib/AltosUnitsListener.java
altoslib/Makefile.am
altosui/.gitignore
altosui/Altos.java
altosui/AltosAscent.java
altosui/AltosBTKnown.java
altosui/AltosBTManage.java
altosui/AltosCSV.java
altosui/AltosCSVUI.java
altosui/AltosCompanionInfo.java
altosui/AltosConfig.java
altosui/AltosConfigFreqUI.java
altosui/AltosConfigPyroUI.java
altosui/AltosConfigTD.java
altosui/AltosConfigTDUI.java
altosui/AltosConfigUI.java
altosui/AltosDataChooser.java
altosui/AltosDescent.java
altosui/AltosDisplayThread.java
altosui/AltosEepromDelete.java
altosui/AltosEepromDownload.java [deleted file]
altosui/AltosEepromList.java [deleted file]
altosui/AltosEepromManage.java
altosui/AltosEepromMonitorUI.java [new file with mode: 0644]
altosui/AltosEepromSelect.java
altosui/AltosFlashUI.java
altosui/AltosFlightDisplay.java
altosui/AltosFlightStats.java
altosui/AltosFlightStatsTable.java
altosui/AltosFlightStatus.java
altosui/AltosFlightStatusTableModel.java
altosui/AltosFlightStatusUpdate.java
altosui/AltosFlightUI.java
altosui/AltosFreqList.java
altosui/AltosGraph.java
altosui/AltosGraphDataPoint.java
altosui/AltosGraphDataSet.java
altosui/AltosGraphUI.java
altosui/AltosIdleMonitorUI.java
altosui/AltosIgniteUI.java
altosui/AltosInfoTable.java
altosui/AltosKML.java
altosui/AltosLanded.java
altosui/AltosPad.java
altosui/AltosRomconfigUI.java
altosui/AltosScanUI.java
altosui/AltosSerial.java
altosui/AltosSiteMap.java
altosui/AltosSiteMapTile.java
altosui/AltosUI.java
altosui/AltosUIPreferencesBackend.java
altosui/AltosWriter.java
altosui/Makefile.am
altosui/altos-windows.nsi.in
altosuilib/AltosUIAxis.java
altosuilib/AltosUIEnable.java
altosuilib/AltosUIGraph.java
altosuilib/AltosUIGrapher.java
altosuilib/AltosUILib.java
altosuilib/AltosUIMarker.java
altosuilib/AltosUIPreferences.java
altosuilib/AltosUIPreferencesBackend.java
altosuilib/AltosUISeries.java
altosuilib/AltosUSBDevice.java
altosuilib/Makefile.am
ao-bringup/cal-accel [new file with mode: 0755]
ao-bringup/cal-freq [new file with mode: 0755]
ao-bringup/get-radio-cal [new file with mode: 0755]
ao-bringup/turnon_telebt
ao-bringup/turnon_telemega [new file with mode: 0755]
ao-bringup/turnon_teleminiv2 [new file with mode: 0755]
ao-tools/Makefile.am
ao-tools/ao-dbg/Makefile.am
ao-tools/ao-dbg/ao-dbg-command.c
ao-tools/ao-dbg/ao-dbg-main.c
ao-tools/ao-dbg/ao-dbg-parse.c
ao-tools/ao-elftohex/Makefile.am [new file with mode: 0644]
ao-tools/ao-elftohex/ao-elftohex.1 [new file with mode: 0644]
ao-tools/ao-elftohex/ao-elftohex.c [new file with mode: 0644]
ao-tools/ao-flash/Makefile.am [new file with mode: 0644]
ao-tools/ao-flash/ao-flash-lpc [new file with mode: 0644]
ao-tools/ao-flash/ao-flash-lpc.1 [new file with mode: 0644]
ao-tools/ao-flash/ao-flash-stm [new file with mode: 0644]
ao-tools/ao-flash/ao-flash-stm.1 [new file with mode: 0644]
ao-tools/ao-load/ao-load.c
ao-tools/ao-mega/.gitignore [new file with mode: 0644]
ao-tools/ao-mega/Makefile.am [new file with mode: 0644]
ao-tools/ao-mega/ao-mega.1 [new file with mode: 0644]
ao-tools/ao-mega/ao-mega.c [new file with mode: 0644]
ao-tools/ao-rawload/ao-rawload.c
ao-tools/ao-stmload/Makefile.am
ao-tools/ao-stmload/ao-elf.c [deleted file]
ao-tools/ao-stmload/ao-elf.h [deleted file]
ao-tools/ao-stmload/ao-selfload.c [deleted file]
ao-tools/ao-stmload/ao-stmload.c
ao-tools/ao-stmload/ao-stmload.h
ao-tools/ao-telem/ao-telem.c
ao-tools/ao-usbload/Makefile.am [new file with mode: 0644]
ao-tools/ao-usbload/ao-usbload.1 [new file with mode: 0644]
ao-tools/ao-usbload/ao-usbload.c [new file with mode: 0644]
ao-tools/ao-usbload/ao-usbload.h [new file with mode: 0644]
ao-tools/lib/Makefile.am
ao-tools/lib/ao-editaltos.c [new file with mode: 0644]
ao-tools/lib/ao-editaltos.h [new file with mode: 0644]
ao-tools/lib/ao-elf.c [new file with mode: 0644]
ao-tools/lib/ao-elf.h [new file with mode: 0644]
ao-tools/lib/ao-hex.c [new file with mode: 0644]
ao-tools/lib/ao-hex.h [new file with mode: 0644]
ao-tools/lib/ao-selfload.c [new file with mode: 0644]
ao-tools/lib/ao-selfload.h [new file with mode: 0644]
ao-tools/lib/ao-verbose.c [new file with mode: 0644]
ao-tools/lib/ao-verbose.h [new file with mode: 0644]
ao-tools/lib/cc-mega.c [new file with mode: 0644]
ao-tools/lib/cc-telemetry.h
ao-tools/lib/cc.h
ao-tools/lib/ccdbg-command.c
ao-tools/lib/ccdbg-flash.c
ao-tools/lib/ccdbg-hex.c [deleted file]
ao-tools/lib/ccdbg-memory.c
ao-tools/lib/ccdbg-rom.c
ao-tools/lib/ccdbg.h
autogen.sh
configure.ac
debian/altos.install
debian/control
debian/rules
doc/Makefile
doc/altos.xsl
doc/altosui.png [new file with mode: 0644]
doc/altusmetrum.xsl
doc/ascent.png [new file with mode: 0644]
doc/companion.xsl
doc/configure-altimeter.png [new file with mode: 0644]
doc/configure-altosui.png [new file with mode: 0644]
doc/configure-groundstation.png [new file with mode: 0644]
doc/configure-pyro.png [new file with mode: 0644]
doc/descent.png [new file with mode: 0644]
doc/device-selection.png [new file with mode: 0644]
doc/easymini-outline.pdf [new file with mode: 0644]
doc/easymini-outline.svg [new file with mode: 0644]
doc/easymini-top.jpg [new file with mode: 0644]
doc/fire-igniter.png [new file with mode: 0644]
doc/graph-configure.png [new file with mode: 0644]
doc/graph-map.png [new file with mode: 0644]
doc/graph-stats.png [new file with mode: 0644]
doc/graph.png [new file with mode: 0644]
doc/landed.png [new file with mode: 0644]
doc/launch-pad.png [new file with mode: 0644]
doc/load-maps.png [new file with mode: 0644]
doc/micropeak.xsl
doc/release-notes-0.7.1.xsl
doc/release-notes-0.8.xsl
doc/release-notes-0.9.2.xsl
doc/release-notes-0.9.xsl
doc/release-notes-1.0.1.xsl
doc/release-notes-1.1.1.xsl
doc/release-notes-1.1.xsl
doc/release-notes-1.2.1.xsl
doc/release-notes-1.2.xsl
doc/release-notes-1.3.xsl [new file with mode: 0644]
doc/scan-channels.png [new file with mode: 0644]
doc/site-map.png [new file with mode: 0644]
doc/table.png [new file with mode: 0644]
doc/telemega-v1.0-top.jpg [new file with mode: 0644]
doc/telemetrum-v1.1-thside.jpg [new file with mode: 0644]
doc/telemetry.xsl
doc/telemini-v1-top.jpg [new file with mode: 0644]
doc/telemini-v2-top.jpg [new file with mode: 0644]
doc/xorg-fo.xsl [new file with mode: 0644]
libaltos/.gitignore
libaltos/Makefile.am
libaltos/cjnitest.c
libaltos/libaltos.c
libaltos/libaltos.dylib
micropeak/Makefile.am
micropeak/MicroData.java
micropeak/MicroDownload.java
micropeak/MicroExport.java
micropeak/MicroFile.java
micropeak/MicroFileChooser.java
micropeak/MicroGraph.java
micropeak/MicroPeak.java
micropeak/MicroRaw.java
micropeak/MicroSave.java
micropeak/MicroStats.java
micropeak/MicroStatsTable.java
micropeak/micropeak.1 [new file with mode: 0644]
pdclib [new submodule]
src/.gitignore
src/Makedefs.in [new file with mode: 0644]
src/Makefile
src/aes/ao_aes.c
src/attiny/ao_arch_funcs.h
src/attiny/ao_async.c [new file with mode: 0644]
src/attiny/ao_async.h [new file with mode: 0644]
src/attiny/ao_exti.h
src/avr-demo/Makefile
src/avr/Makefile.defs [new file with mode: 0644]
src/cc1111/Makefile.cc1111
src/cc1111/ao_adc.c
src/cc1111/ao_arch.h
src/cc1111/ao_arch_funcs.h
src/cc1111/ao_exti.c [new file with mode: 0644]
src/cc1111/ao_exti.h [new file with mode: 0644]
src/cc1111/ao_radio.c
src/cc1111/ao_spi.c
src/cc1111/ao_timer.c
src/cc1111/ao_usb.c
src/core/ao.h
src/core/ao_adc.h
src/core/ao_cmd.c
src/core/ao_config.c
src/core/ao_config.h [new file with mode: 0644]
src/core/ao_data.c [new file with mode: 0644]
src/core/ao_data.h
src/core/ao_debounce.c [new file with mode: 0644]
src/core/ao_debounce.h [new file with mode: 0644]
src/core/ao_eeprom.h [new file with mode: 0644]
src/core/ao_flight.c
src/core/ao_flight.h
src/core/ao_gps_report.c
src/core/ao_gps_report_mega.c
src/core/ao_gps_report_metrum.c [new file with mode: 0644]
src/core/ao_gps_show.c [new file with mode: 0644]
src/core/ao_ignite.c
src/core/ao_int64.c [new file with mode: 0644]
src/core/ao_int64.h [new file with mode: 0644]
src/core/ao_kalman.c
src/core/ao_log.c
src/core/ao_log.h
src/core/ao_log_mega.c
src/core/ao_log_metrum.c [new file with mode: 0644]
src/core/ao_log_micro.c [new file with mode: 0644]
src/core/ao_log_micro.h [new file with mode: 0644]
src/core/ao_log_mini.c [new file with mode: 0644]
src/core/ao_log_telem.c
src/core/ao_log_tiny.c
src/core/ao_microflight.c [new file with mode: 0644]
src/core/ao_microkalman.c [new file with mode: 0644]
src/core/ao_product.c
src/core/ao_pyro.c
src/core/ao_pyro.h
src/core/ao_quaternion.h [new file with mode: 0644]
src/core/ao_report_micro.c [new file with mode: 0644]
src/core/ao_sample.c
src/core/ao_sample.h
src/core/ao_sample_profile.c
src/core/ao_storage.c
src/core/ao_storage.h
src/core/ao_task.c
src/core/ao_task.h
src/core/ao_telemetry.c
src/core/ao_telemetry.h
src/core/ao_usb.h
src/drivers/ao_74hc165.c [new file with mode: 0644]
src/drivers/ao_74hc165.h [new file with mode: 0644]
src/drivers/ao_button.c
src/drivers/ao_cc1120.c
src/drivers/ao_cc1120.h
src/drivers/ao_cc115l.c
src/drivers/ao_event.c
src/drivers/ao_event.h
src/drivers/ao_gps_sirf.c
src/drivers/ao_gps_skytraq.c
src/drivers/ao_gps_ublox.c
src/drivers/ao_m25.c
src/drivers/ao_mma655x.c
src/drivers/ao_mpu6000.c
src/drivers/ao_mpu6000.h
src/drivers/ao_ms5607.c
src/drivers/ao_ms5607.h
src/drivers/ao_ms5607_convert.c
src/drivers/ao_ms5607_convert_8051.c [new file with mode: 0644]
src/drivers/ao_pad.c
src/drivers/ao_pca9922.c
src/drivers/ao_quadrature.c
src/drivers/ublox-csum.5c [new file with mode: 0644]
src/easymini-v1.0/.gitignore [new file with mode: 0644]
src/easymini-v1.0/Makefile [new file with mode: 0644]
src/easymini-v1.0/ao_easymini.c [new file with mode: 0644]
src/easymini-v1.0/ao_pins.h [new file with mode: 0644]
src/easymini-v1.0/flash-loader/Makefile [new file with mode: 0644]
src/easymini-v1.0/flash-loader/ao_pins.h [new file with mode: 0644]
src/lpc/Makefile-flash.defs [new file with mode: 0644]
src/lpc/Makefile-lpc.defs [new file with mode: 0644]
src/lpc/Makefile.defs [new file with mode: 0644]
src/lpc/altos-loader.ld [new file with mode: 0644]
src/lpc/altos-standalone.ld [new file with mode: 0644]
src/lpc/altos.ld [new file with mode: 0644]
src/lpc/ao_adc_lpc.c [new file with mode: 0644]
src/lpc/ao_arch.h [new file with mode: 0644]
src/lpc/ao_arch_funcs.h [new file with mode: 0644]
src/lpc/ao_beep_lpc.c [new file with mode: 0644]
src/lpc/ao_boot.h [new file with mode: 0644]
src/lpc/ao_boot_chain.c [new file with mode: 0644]
src/lpc/ao_boot_pin.c [new file with mode: 0644]
src/lpc/ao_exti.h [new file with mode: 0644]
src/lpc/ao_exti_lpc.c [new file with mode: 0644]
src/lpc/ao_flash.h [new file with mode: 0644]
src/lpc/ao_flash_loader_lpc.c [new file with mode: 0644]
src/lpc/ao_flash_lpc.c [new file with mode: 0644]
src/lpc/ao_flash_lpc_pins.h [new file with mode: 0644]
src/lpc/ao_interrupt.c [new file with mode: 0644]
src/lpc/ao_led_lpc.c [new file with mode: 0644]
src/lpc/ao_romconfig.c [new file with mode: 0644]
src/lpc/ao_serial_lpc.c [new file with mode: 0644]
src/lpc/ao_spi_lpc.c [new file with mode: 0644]
src/lpc/ao_timer_lpc.c [new file with mode: 0644]
src/lpc/ao_usb_lpc.c [new file with mode: 0644]
src/lpc/baud_rate [new file with mode: 0644]
src/lpc/figure-checksum [new file with mode: 0755]
src/lpc/lpc.h [new file with mode: 0644]
src/lpc/registers.ld [new file with mode: 0644]
src/lpcxpresso/.gitignore [new file with mode: 0644]
src/lpcxpresso/Makefile [new file with mode: 0644]
src/lpcxpresso/ao_demo.c [new file with mode: 0644]
src/lpcxpresso/ao_pins.h [new file with mode: 0644]
src/math/ef_acos.c [new file with mode: 0644]
src/math/ef_rem_pio2.c [new file with mode: 0644]
src/math/ef_sqrt.c [new file with mode: 0644]
src/math/fdlibm.h [new file with mode: 0644]
src/math/ieeefp.h [new file with mode: 0644]
src/math/kf_cos.c [new file with mode: 0644]
src/math/kf_rem_pio2.c [new file with mode: 0644]
src/math/kf_sin.c [new file with mode: 0644]
src/math/machine/ieeefp.h [new file with mode: 0644]
src/math/math.h [new file with mode: 0644]
src/math/sf_copysign.c [new file with mode: 0644]
src/math/sf_cos.c [new file with mode: 0644]
src/math/sf_fabs.c [new file with mode: 0644]
src/math/sf_floor.c [new file with mode: 0644]
src/math/sf_scalbn.c [new file with mode: 0644]
src/math/sf_sin.c [new file with mode: 0644]
src/megadongle-v0.1/Makefile
src/micropeak/Makefile
src/micropeak/ao_async.c [deleted file]
src/micropeak/ao_async.h [deleted file]
src/micropeak/ao_log_micro.c [deleted file]
src/micropeak/ao_log_micro.h [deleted file]
src/micropeak/ao_microflight.c [deleted file]
src/micropeak/ao_microkalman.c [deleted file]
src/micropeak/ao_micropeak.c [deleted file]
src/micropeak/ao_micropeak.h [deleted file]
src/micropeak/ao_report_tiny.c [deleted file]
src/nanopeak-v0.1/.gitignore [new file with mode: 0644]
src/nanopeak-v0.1/Makefile [new file with mode: 0644]
src/nanopeak-v0.1/ao_pins.h [new file with mode: 0644]
src/product/Makefile.teledongle
src/product/Makefile.telelaunch
src/product/Makefile.telemetrum
src/product/Makefile.telemini
src/product/Makefile.telenano
src/product/ao_flash_pins.h
src/product/ao_flash_task.c
src/product/ao_micropeak.c [new file with mode: 0644]
src/product/ao_micropeak.h [new file with mode: 0644]
src/product/ao_terraui.c
src/spiradio-v0.1/Makefile
src/stm-bringup/Makefile
src/stm-demo/Makefile
src/stm-demo/ao_demo.c
src/stm-flash/Makefile
src/stm/Makefile-flash.defs
src/stm/Makefile.defs
src/stm/altos-loader.ld
src/stm/ao_adc_stm.c
src/stm/ao_arch.h
src/stm/ao_arch_funcs.h
src/stm/ao_beep_stm.c
src/stm/ao_data.c [deleted file]
src/stm/ao_eeprom_stm.c
src/stm/ao_exti.h
src/stm/ao_exti_stm.c
src/stm/ao_fast_timer.c [new file with mode: 0644]
src/stm/ao_fast_timer.h [new file with mode: 0644]
src/stm/ao_flash_stm.c
src/stm/ao_timer.c
src/stm/ao_usb_stm.c
src/stm/stm32l.h
src/teleballoon-v1.1/Makefile
src/teleballoon-v1.1/ao_balloon.c
src/telebt-v1.0/Makefile
src/telefire-v0.1/Makefile
src/telefire-v0.1/ao_pins.h
src/telefire-v0.2/.gitignore [new file with mode: 0644]
src/telefire-v0.2/.sdcdbrc [new file with mode: 0644]
src/telefire-v0.2/Makefile [new file with mode: 0644]
src/telefire-v0.2/ao_pins.h [new file with mode: 0644]
src/telefire-v0.2/ao_telefire.c [new file with mode: 0644]
src/telegps-v0.1/Makefile
src/telegps-v0.1/ao_pins.h
src/telegps-v0.1/ao_telegps.c
src/telegps-v0.3/.gitignore [new file with mode: 0644]
src/telegps-v0.3/Makefile [new file with mode: 0644]
src/telegps-v0.3/ao_pins.h [new file with mode: 0644]
src/telegps-v0.3/ao_telegps.c [new file with mode: 0644]
src/telegps-v0.3/flash-loader/Makefile [new file with mode: 0644]
src/telegps-v0.3/flash-loader/ao_pins.h [new file with mode: 0644]
src/telelco-v0.1/Makefile
src/telelco-v0.2/Makefile
src/telelco-v0.2/ao_lco.c
src/telelco-v0.2/ao_pins.h
src/telelco-v0.2/ao_telelco.c
src/telemega-v0.1/Makefile
src/telemega-v0.1/ao_pins.h
src/telemega-v0.1/ao_telemega.c
src/telemega-v0.3/.gitignore [deleted file]
src/telemega-v0.3/Makefile [deleted file]
src/telemega-v0.3/ao_pins.h [deleted file]
src/telemega-v0.3/ao_telemega.c [deleted file]
src/telemega-v0.3/flash-loader/Makefile [deleted file]
src/telemega-v0.3/flash-loader/ao_pins.h [deleted file]
src/telemega-v1.0/.gitignore [new file with mode: 0644]
src/telemega-v1.0/Makefile [new file with mode: 0644]
src/telemega-v1.0/ao_pins.h [new file with mode: 0644]
src/telemega-v1.0/ao_telemega.c [new file with mode: 0644]
src/telemega-v1.0/flash-loader/Makefile [new file with mode: 0644]
src/telemega-v1.0/flash-loader/ao_pins.h [new file with mode: 0644]
src/telemetrum-v0.1-sky/Makefile
src/telemetrum-v1.0/Makefile
src/telemetrum-v1.1/Makefile
src/telemetrum-v1.2/Makefile
src/telemetrum-v2.0/.gitignore [new file with mode: 0644]
src/telemetrum-v2.0/Makefile [new file with mode: 0644]
src/telemetrum-v2.0/ao_pins.h [new file with mode: 0644]
src/telemetrum-v2.0/ao_telemetrum.c [new file with mode: 0644]
src/telemetrum-v2.0/flash-loader/Makefile [new file with mode: 0644]
src/telemetrum-v2.0/flash-loader/ao_pins.h [new file with mode: 0644]
src/telemini-v2.0/.gitignore [new file with mode: 0644]
src/telemini-v2.0/.sdcdbrc [new file with mode: 0644]
src/telemini-v2.0/Makefile [new file with mode: 0644]
src/telemini-v2.0/ao_pins.h [new file with mode: 0644]
src/telemini-v2.0/ao_telemini.c [new file with mode: 0644]
src/telepyro-v0.1/Makefile
src/telescience-pwm/.gitignore
src/telescience-pwm/Makefile
src/telescience-v0.1/Makefile
src/telescience-v0.2/Makefile
src/telescience-v0.2/flash-loader/Makefile [new file with mode: 0644]
src/telescience-v0.2/flash-loader/ao_pins.h [new file with mode: 0644]
src/teleshield-v0.1/Makefile
src/teleterra-v0.2/Makefile
src/test/.gitignore
src/test/Makefile
src/test/ao_flight_test.c
src/test/ao_gps_test.c
src/test/ao_gps_test_skytraq.c
src/test/ao_gps_test_ublox.c
src/test/ao_int64_test.c [new file with mode: 0644]
src/test/ao_ms5607_convert_test.c [new file with mode: 0644]
src/test/ao_quaternion_test.c [new file with mode: 0644]
src/test/mega.flights [new file with mode: 0644]
src/test/plot-rot [new file with mode: 0755]
src/test/plotmm
src/test/run-all-mm [new file with mode: 0755]
src/test/run-mm
src/tidongle/Makefile
telemetrum.inf

index 5dec09a5479055ebed7232343b0c1454fa57f5d6..61f48048b88aae31a664151618befeebfe2d734f 100644 (file)
@@ -32,16 +32,19 @@ ao-tools/ao-dumplog/ao-dumplog
 ao-tools/ao-dump-up/ao-dump-up
 ao-tools/ao-eeprom/ao-eeprom
 ao-tools/ao-edit-telem/ao-edit-telem
+ao-tools/ao-elftohex/ao-elftohex
 ao-tools/ao-list/ao-list
 ao-tools/ao-load/ao-load
 ao-tools/ao-postflight/ao-postflight
 ao-tools/ao-rawload/ao-rawload
 ao-tools/ao-send-telem/ao-send-telem
 ao-tools/ao-sky-flash/ao-sky-flash
+ao-tools/ao-usbload/ao-usbload
 ao-tools/ao-view/ao-view
 ao-view/Makefile
 ao-view/ao-view
 autom4te.cache
+compile
 config.*
 config.h
 config.h.in
@@ -61,3 +64,4 @@ doc/telemetrum.fo
 doc/telemetrum.html
 doc/telemetrum.pdf
 altosui/altos-windows.log
+pdclib-root
diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..719da19
--- /dev/null
@@ -0,0 +1,3 @@
+[submodule "pdclib"]
+       path = pdclib
+       url = git://git.gag.com/fw/pdclib
index c93d031b28b61888156af3f42008b9c2b1fdfac6..4f9316a19c90d41dcb2127f3d932438fea280dc7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
-commit 5a329c7f588334df7443b47c8f478ebadf312f62
-Merge: 9b13822 03fe10e
+commit 701c26ed85c28ac59e338975f2a6ba6bd25f6493
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Dec 19 00:16:16 2013 -0800
+
+    altosdroid: bump versionName to 1.3 and versionCode to 4
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9f95ffbad918a73cfd5460d6ce037d680465c35d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Dec 19 00:12:21 2013 -0800
+
+    altosui: When device has no valid romconfig, set RF cal to 0
+    
+    This is intended to signal to the user that no valid value was found
+    and that they'd best pick something sensible.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a04c1dd5df76c9127615bc797a9d9f764eec1234
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Dec 19 00:08:50 2013 -0800
+
+    altos/lpc: Stop sending SETUP IN when the requested size is reached
+    
+    The host won't keep asking for SETUP IN packets once it has received
+    the amount of data requested, so check to see if we've sent that much
+    and flip back to IDLE state if so.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1ab12861c3e70d7c22b27d988546a925616a0adc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 23:27:34 2013 -0800
+
+    altos/lpc: Reset less of the device on USB reset.
+    
+    This leaves most of the device configured across USB reset, which
+    appears to help when sending a IN reply to the first SETUP packet;
+    without this change, the IN reply would always get a length of 0,
+    which is fine for SET_ADDRESS, but not for GET_DESCRIPTOR_DEVICE,
+    which OS X appears to send before setting the address (go figure).
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3b13cc2ca035b13582cd2e59ba7286f872f43c6e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 22:00:13 2013 -0800
+
+    altoslib: Remove some old debug printfs for self flashing
+    
+    These aren't necessary anymore and just slow down flashing boards.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 408b0dea338147382e94717dab85b4a204e7bdf5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 21:08:33 2013 -0800
+
+    micropeak: Add micropeak man page
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2b2ba87d5f68b9e052dddd49d69341f36d777122
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 21:02:15 2013 -0800
+
+    ao-tools: Add man pages for ao-flash utilities
+    
+    These aren't very wordy, but these tools are pretty simple scripts.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 39cb8c2896317b7538353be979ac99baffc14489
+Merge: 2a6016c ee42796
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Dec 18 21:53:52 2013 -0700
+
+    Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit 2a6016cfabc8cd56f5219871e3b3df316a639289
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Dec 18 21:53:36 2013 -0700
+
+    update Debian standards version we claim compliance with
+
+commit ee4279613b4757453d0d8f8afc06037c61eeb520
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 20:32:05 2013 -0800
+
+    altos: Try IMU self-test 10 times before giving up
+    
+    This should keep the device from failing to boot unless the IMU is
+    actually broken. Oh, and if self test does fail, this places the
+    flight computer in 'Invalid' state rather than panic.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1bf84ec28a41f7bd1b11ba45b4639856266227bc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 20:30:58 2013 -0800
+
+    doc: Add tables describing AltOS beeps and flashes
+    
+    Provide a convenient place to reference when listening to the device.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0673344289772ed89483948184d6608c272c7c26
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 18:20:55 2013 -0800
+
+    altos/stm: Semantic error in STM usb disable caused it to not work
+    
+    The USB enable register wasn't actually getting rewritten with the
+    enable bit turned off, so the USB device was still powered on in flight.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 122f491e459b6ff417932370b3f1aa2091c71aca
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Dec 18 18:30:54 2013 -0700
+
+    update release docs to include option for submodules
+
+commit d9982c257463f23be940eea66bd4dc3aadff0043
+Merge: 1b97ed2 b63fc05
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Dec 18 18:25:35 2013 -0700
+
+    Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit 1b97ed2b64bcbcd969124964f1e49837899f1c70
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Dec 18 18:25:03 2013 -0700
+
+    we're using packaged and local-to-our-tree ARM toolchain now
+
+commit b63fc05481bf6d57e6385704ce53c1c19afa9c2e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 14:34:31 2013 -0800
+
+    doc: typo in micropeak doc hole->hold
+
+commit 6827961c002757f8e74de44f6eb9c9029d099ebc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 14:25:41 2013 -0800
+
+    doc: Update micropeak quick start guide to note new boost detect
+    
+    Now waits for one minute and 30m of altitude change to avoid false detections.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c0966cd40f05f3a65b0c977b4b92586a58192f4b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 14:22:51 2013 -0800
+
+    micropeak: Compile for java 6
+    
+    Don't a require later version as not all target OSes support it
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eea036650e62bc0f8652155974b512686754fd13
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 14:08:41 2013 -0800
+
+    Move pdclib build results to pdclib-root
+    
+    This makes pdclib easier to manage as a submodule
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c1bfe09b6d3eb28d0c7cfe07a248843cf81bcd25
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 13:36:04 2013 -0800
+
+    altosui: Remove some debug printfs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 58ceb9c845d51547244538fe6beec27e9a232af8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 13:25:31 2013 -0800
+
+    altosdroid: Use altoslib standard voltages to control lights
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dbcf3264f950c4e1d450828c9f161b4c418bee97
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 13:22:45 2013 -0800
+
+    altoslib: Define 3.8 as a good battery and 3.5 as a good igniter
+    
+    Use defined values everywhere instead of copying. Adjust battery up to
+    3.8 to ensure there's enough voltage to not trip the comparators
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b19a648b667c298d2d9d5ed4ee9db661be058d1a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 13:09:48 2013 -0800
+
+    altoslib: create eeprom download thread before telling monitor about it
+    
+    Telling the monitor too early resulted in passing a null thread
+    handle, which meant that 'cancel' wouldn't ever work.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 216405bc49ef2fc0e9941989f054e41f2fef9cfe
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 12:40:22 2013 -0800
+
+    altoslib: Don't close telemetry reader at startup unless something fails
+    
+    Was always closing the file, which led to very little telemetry being received.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f2e589c59ed0a4c586c5accca8772df15010c46a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 12:16:55 2013 -0800
+
+    libaltos: Import newly build libaltos.dylib
+
+commit 0484ca97828da0d56be7bf395fa4a4b09c591e02
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 12:15:54 2013 -0800
+
+    libaltos: remove usb id filtering from darwin code
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 36197a388a9ba1d1ee4acd96ac0079ad3af9d3d0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 12:15:22 2013 -0800
+
+    libaltos: fix test harness main type
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 119dd56512404e0c39dd5001ba4da9373515c02c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 11:25:05 2013 -0800
+
+    altosui: Add docs to Mac OS X dmg distribution
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6df58bb0115a8da13d35ab38861f6231bea7f2a7
+Merge: 4383baf 02195f2
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Dec 18 12:19:31 2013 -0700
+
+    Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit 4383bafc6ccdde10f06882ba3e96126c61d5e988
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Dec 18 12:18:30 2013 -0700
+
+    a fresher changelog entry for test builds
+
+commit 7db8e8190bc8b9a17a7b5107954e2362a0e9c7a2
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Wed Dec 18 11:08:55 2013 -0700
+
+    need to include the Cortex toolchain
+
+commit 02195f2970fb7243fd9a9992abb6ada6709db4e1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 11:14:40 2013 -0800
+
+    fix git: path for pdclib
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fbca372edd5609bc253b622b55b7faffd19ae6cd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 11:12:44 2013 -0800
+
+    Use git: path for pdclib
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e2635d07d0f0a91dd7d59f2c94765a40907d2732
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 11:08:11 2013 -0800
+
+    Ignore .dll files in libaltos
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8fdbdebdbb4d1579fd2af47430807d0d2a78105b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 11:07:55 2013 -0800
+
+    ao-tools: complain if st-flash is not available
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8f529633cd4be8a0edb1b067bbf5d7cc055dcc1b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 10:55:06 2013 -0800
+
+    altos: get stm-bringup building again
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 262ee65885d55902df96f4aec6a114f5ac6f2c61
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 10:53:09 2013 -0800
+
+    Remove stale stm test apps from regular build
+
+commit 90386115204bd3bfa55deb5ebe1972bacdba725a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 10:50:45 2013 -0800
+
+    altos/stm: Update pdclib paths for flash-loader builds
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eb659fb0ee80c25312be36b3d8adb686813db125
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 10:43:16 2013 -0800
+
+    altos: create target pdclib directories before building
+
+commit 9c200c3bc742b4dd1a7e28bfce9d5b27e833aae5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 10:01:29 2013 -0800
+
+    altos: Build pdclib locally if necessary
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fbde0c3e4bdb419d6bd4dbcc96b0e01c59e9fa13
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 09:59:33 2013 -0800
+
+    include pdclib in wrong place
+
+commit 77b04d662a6704f5db10522a2f9b169d31df5bea
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 02:03:15 2013 -0800
+
+    altosui: Hide non-applicable altimeter config values
+    
+    This makes configuring EasyMini a lot easier...
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 012abeda6ae846d74729e96e7ed7c8af2edca572
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 02:02:12 2013 -0800
+
+    altos/lpc: Be a bit more resistant to toolchain section name changes
+    
+    Just add some wild cards on the ends of each section name in case the
+    toolchain changes names in the future.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e26306c9350ef1d107d4257ef1c09d15165c9154
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 01:14:11 2013 -0800
+
+    altoslib: Pass InterruptedException up the stack instead of hiding it
+    
+    When interrupting a thread that is talking to a serial device, it's
+    important not to have that thread discard the InterruptedException so
+    that it will actually terminate. This patch removes a bunch of places
+    that were discarding InterruptedExceptions and lets higher level code
+    see them so that they can exit cleanly.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 18852efa108ba6e6e69dfd5076d4f4c01f62b4ef
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Dec 18 01:12:11 2013 -0800
+
+    altos: Make TeleMega v0.1 work more like TeleMega v1.0
+    
+    I've still got one working v0.1 board which is useful for testing
+    stuff, so make it work more like the released TeleMega:
+    
+     * Use E for drogue, F for main
+     * Use on-chip eeprom for config
+     * Fix ADC report printf to match
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1f035ac2df1cfa6964ae904aba0aedde279ca921
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 17 23:50:54 2013 -0800
+
+    altos: Use all 16 bits of setup packet len when limiting reply len
+    
+    We were only using the low 8 bits of the setup packet reply max len,
+    which meant that if the other side sent a weird max len (as Windows 7
+    does), then we'd truncate our setup reply to whatever was in the low 8
+    bits of that value.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1280ba2e51b36f417f3adb6d101405ee75e7e509
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 17 22:53:45 2013 -0800
+
+    altosui: Add EasyMini bits to fat distribution images. Update telemetrum.inf
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 212a1b66ae04317b7b42ba57573b910fde09ca6c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 17 20:24:19 2013 -0800
+
+    doc: Publish images with HTML bits
+    
+    Otherwise the html won't render right.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2ecb6a8276b2ce40d2a4da586dbc17581cfda26d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 17 20:23:00 2013 -0800
+
+    altos: Broke TeleMetrum GPS reporting by holding the GPS mutex too much
+    
+    We can't hold the GPS mutex while waiting for the GPS receiver to load
+    data as it protects the GPS data with the GPS mutex.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e44ce127ece149e7b07be49142bc0f9d50bbe97d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 17 20:05:12 2013 -0800
+
+    doc: Add screen shots everywhere
+    
+    This has screen shots of every dialog in altosui
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e4b223df372348718b74d2ecad4957f3e30f8d79
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 17 17:37:39 2013 -0800
+
+    Add altosui image and attempt to add launch photo to title
+
+commit 1d093383fe58fc8c8c11e1c7cd1cd929ae1bd9e4
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Dec 17 14:53:59 2013 -0700
+
+    further documentation tweaks
+
+commit 90c88bab305c43eb62f964fd3ff350b8b0b5320d
+Merge: d5d6d10 dffbdd9
 Author: Bdale Garbee <bdale@gag.com>
-Date:   Tue May 21 09:31:48 2013 -0600
+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
+
+commit d5d6d10ceb724081c7cf89a3885d7e6c3da14604
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Dec 17 14:08:12 2013 -0700
+
+    capture my changes so far
+
+commit dffbdd93d7a86a12d83a412de37dfd2a5f063995
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 17 11:38:46 2013 -0800
+
+    doc: Add product pictures to manual
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9d8da4ef325171960e16fc027c6039cb63eae942
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 17 11:19:54 2013 -0800
+
+    Keep tables together on a page
+
+commit 7acd0cf17c5ca7a00893f35c7fe9c657389070e0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 17 10:33:29 2013 -0800
+
+    doc: Convert several more itemizedlists to variablelists
+    
+    When defining a term, use variablelist to pull the term out to the left.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8bb6dd75a602792936d623713fb009fea25ef491
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 16 21:21:24 2013 -0800
+
+    Clean up reflashing section, include section on self-flash recovery
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1562affc4951e147eba20380ea5be2e9f7152789
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 14 11:47:31 2013 -0800
+
+    ao-tools: Use st-flash for STM flashing instead of openocd
+    
+    st-flash, from the stlink tools, appears more reliable when flashing
+    STM CPUs.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7d7ae63d8dfcc99a30285e0bd2411901941d1813
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sat Dec 14 12:16:03 2013 -0700
+
+    add serial number to ao-usbload call, pass SERIAL to cal-freq
+
+commit c94ca50fd9f24f271c160f6e0e95cb7340289354
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri Dec 13 18:37:29 2013 -0700
+
+    temporarily force stlink location in debian/rules to allow complete build
+
+commit 6545a72012e94a50d185e1c4ecff3c3769d60acd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 10 00:54:32 2013 -0800
+
+    java: Missed libaltos java compile flags from previous patch
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8959c059ec67f5334e31abbe3f831dd571a0b464
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 10 00:51:01 2013 -0800
+
+    java: Add -target 1.6 to all java compiles
+    
+    This makes sure the results can run with the old JVM
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a4596c134aa5e7867f1ca1d86d36afb2af9b8999
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 10 00:39:52 2013 -0800
+
+    altos: Remove ARM .ihx files on 'make clean'
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 50753e84871b2a01d270d28b8b77a19614d2180c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 10 00:03:20 2013 -0800
+
+    Set version to 1.3 in preparation for release
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 54f7888dc65ffc27c6ee5ef93953bd9b8fc029ed
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Dec 10 00:00:31 2013 -0800
+
+    doc: More altusmetrum.xsl updates for 1.3
+    
+    Spell checking even
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a140b3ad689bcebdcf87caab1e64048f693a9b85
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 9 23:16:13 2013 -0800
+
+    debian: .ihx and .map files are left in subdirs now
+    
+    Install them from the right place
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 95c1a5a61267233cf2c16175aeb73bfb7d12ba8f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 9 23:14:55 2013 -0800
+
+    altosui: Ship TeleMega-v1.0 firmware
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b023c87e2b86ba57cbf97be1ab76b532e0a00fad
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 9 23:12:40 2013 -0800
+
+    ao-bringup: Add turnon_telemega script
+    
+    And a few helper programs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ecb0465be76e9299511aeec663d267967834f6c3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Dec 9 16:06:22 2013 -0800
+
+    altos: Rename telemega-v0.3 to telemega-v1.0
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dd91a5d5069ff940e07b8817a934ee65d4e8e235
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 21:08:36 2013 -0800
+
+    altos: Oops. Was only filling out part of the TeleMetrum ADC record
+    
+    Because it's missing a return, we'd end up filling out one element of
+    the ADC record per interrupt, and rotating through which one was set,
+    hitting all of the even offsets within the struct. Yikes!
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c1711890c002fe359bd6c3fdf4092b35d464c6d9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 21:07:17 2013 -0800
+
+    altosui: When flashing to TeleDongle or TeleBT, match any .ihx file
+    
+    Let the user pick any .ihx file when using a device which can only be
+    used as a pair programmer. Note that 'telemetrum' can be either, and
+    we'll assume that it's a self-programmed device (v2) for now.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 710343a23c7e6e9c079eafdf3aeea8a40cc2ce61
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 20:34:11 2013 -0800
+
+    altosui: Match directories in hex file matcher
+    
+    This makes it possible to navigate around the file system
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fd92bb8ff3be257925bf6e969d93a7f9dd941fb8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 20:33:22 2013 -0800
+
+    altoslib: Don't require radio_cal or usb_descriptors in AltosRomconfig
+    
+    Not all products will have these values, so allow them to be missing
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 68adbf5bf08ed8af2f34c0d95d9c3d457574372d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 20:11:46 2013 -0800
+
+    Add new tools to .gitignore
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2cdb90d9214f8e66b3574cbd9c5ed073a7861681
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 20:09:10 2013 -0800
+
+    altoslib: Add self-flashing code
+    
+    This adds the ability to use the AltOS flash-loader on both STM and
+    NXP processors.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 70d0841b4017e7580c893c7033c04fb2964adab6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 20:07:23 2013 -0800
+
+    altoslib: Add AltosNoSymbol exception
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4e1b134e29313a1bdac18de57fe547299e5ded2a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 20:04:43 2013 -0800
+
+    altoslib: Use symbols in AltosRomconfig instead of fixed offsets
+    
+    The new Hexfile symbol code automatically adds the needed romconfig
+    symbols for cc1111 products, and ARM-based products have symbols in
+    the .ihx files. This means that we can rely on using symbols when
+    finding config values in memory.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1183417145de549b9281f9e210d216facf3a94ef
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 19:59:37 2013 -0800
+
+    altosuilib: Don't match product_altusmetrum for product_basestation or product_altimeter
+    
+    It's been years since we've shipped boards configured with
+    product_altusmetrum, but now we've repurposed that code for the flash
+    loader. When matching an explicit product, go ahead and also match
+    altusmetrum so that the flash loader will fit, but when matching
+    basestation or altimeter, don't as that will avoid popping up the
+    flight monitor UI at startup when a board is running the boot loader.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e0af4569446b12c026aa0ffd52c55839d69af0e1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 19:48:27 2013 -0800
+
+    altoslib: Publish mapping from product name back to USB id
+    
+    This lets us choose which device to flash based on the filename
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 88fa5fa6acbdd66d1338ca73cbbac219d62b5136
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 19:47:44 2013 -0800
+
+    altoslib: Create AltosProgrammer class
+    
+    This provides an abstract interface to flashing boards, for
+    dongle-based and self-programming boards.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7b0c1fbccb4ef1ae2ed356292cc8762360532b7f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 19:46:30 2013 -0800
+
+    altoslib: Add symbols to .ihx files
+    
+    Create a new 0xfe record type to hold the symbols, and append them
+    after the EOF record so that other tools might continue to work.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b1ffdaf1f5e9b6e8ff0d4e08d8c504f8dfacd3a4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 19:43:13 2013 -0800
+
+    altoslib: Support binary reading/writing in AltosLink
+    
+    Binary reads require an explicit length, and do not work while
+    telemetry is running.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2cb7a96567e1302a699f78290fab5e29693940ab
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 19:05:01 2013 -0800
+
+    altos/stm: arm-none-eabi-binutils now puts 'main' into .text.startup
+    
+    Change name of .text.ram to .ramtext, then load .text* into flash and
+    .ramtext into ram. This ensures that 'main' and anything else in a
+    random .text.* segment will get loaded into flash as appropriate.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3e22a0dce4248cce862147c985078de44c427b12
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 19:04:11 2013 -0800
+
+    ao-tools: build ao-usbload by default
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b1f3525afa801038f7087a3a2caf369f2460a5db
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 11:41:09 2013 -0800
+
+    altoslib: AltosEepromMonitor had false import of altosuilib
+    
+    Not needed, and breaks the build
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eded084c6caa1f9423d690c8b45c8042f8355987
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 11:17:28 2013 -0800
+
+    altos: remove all versions of stm-demo executable
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bb72b4018dd6a422afe1916d9538bb9ff1e45353
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 11:15:37 2013 -0800
+
+    altos: Change flash loader name to just AltosFlash
+    
+    Remove the software version string from the product name
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 52b19511222980138faddb2047707baceff0a596
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 11:14:29 2013 -0800
+
+    altos: Build .ihx files for all arm projects
+    
+    The .ihx version can be processed by the java loader
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a1e4750a7d4af72e8e9086735885f48c9b56c18e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 11:11:41 2013 -0800
+
+    altos: Allow products to override default 100mA USB current
+    
+    This will allow products to specify their own current limit.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 25aaf6122cbddcbc6a80460dac8ccb9f45743ae0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 11:10:00 2013 -0800
+
+    ao-tools: Clean up ao-stmload and ao-usbload options. Add --raw
+    
+    ao-stmload only uses stlink, ao-usbload only uses self-flashing, so
+    clear up the options in the two programs. The new --raw option skips
+    the serial and radio cal rewriting when flashing the boot loader.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ebb36d56c732ffe9cdb8d2ea53d00e1d4ece8f97
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Dec 8 11:07:46 2013 -0800
+
+    ao-tools: Allow building without stlink and readline
+    
+    This adds --without-stlink and --without-readline options to configure
+    to disable these features, and adjusts the build process and code to
+    handle that.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5fd0dc6f69e7614ba71bbc215b32260a11595af3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 7 23:27:30 2013 -0800
+
+    ao-tools: Add ao-flash-stm and ao-flash-lpc scripts
+    
+    These use openocd to download boot loaders to the arm-based products
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eee9b3ce1e5adae5aa4566050b6d6048344e92c4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 7 09:54:17 2013 -0800
+
+    altosuilib: Deal with AltosUnits API change
+    
+    The abstract methods in AltosUnits now pass the 'imperial_units' flag
+    explicitly, so deal with that in AltosUnits itself
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 407696f11ac1736e840c9b702592c46197d14c2c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 7 09:53:10 2013 -0800
+
+    altosui: Clean up serial close handling
+    
+    Unify serial close processing in a single function (close_serial),
+    make everyone else call that. This avoids a couple of cases where the
+    device would be closed and not removed from the devices_opened list,
+    leading to 'device is already in use' messages.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1a47532f411488f003726aa9365ede5dc90c5b78
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 7 09:51:58 2013 -0800
+
+    altosui: Don't try to report bearing/elevation without GPS
+    
+    If the distance from the pad cannot be computed (due to lacking GPS),
+    then don't try to report it.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 44249a9262a16ed103aedf30a300003fc2a17579
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 7 09:49:00 2013 -0800
+
+    altos: Nothing in altos uses AES decryption, so don't compile it
+    
+    Saves a bit of space where AES is used, and avoids some compiler warnings.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cdb32b1717db4e8cb8cf94d810e74ce2b569566b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 7 09:47:45 2013 -0800
+
+    altos/test: Compute and plot tilt based on GPS track
+    
+    This lets us compare the gyro-computed tilt angle against the actual
+    flight path.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6fbf4829569d5edb476654f4e383b834af527dc6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 7 09:40:53 2013 -0800
+
+    altos: Telemega uses eeprom, include it in main file
+    
+    ao_telemega.c didn't include ao_eeprom.h leaving a function undefined
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2a9b0cdff5db03dc11b6ef69cf5436c834c3acc4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 7 09:39:41 2013 -0800
+
+    altos: Add lots more GPS data to mega log
+    
+    There's plenty of space in the GPS log packets to hold course, speed,
+    climb and DOP values, so just stick them in.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit de2e812b02a99a2f6d85f15a9600265931f6f6b0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Dec 7 09:38:50 2013 -0800
+
+    src/cc1111: Turn off RC osc after xtal is running
+    
+    There's no reason to keep running the RC oscillator after we switch to
+    the crystal, so turn it off.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 473ae38ade0552c5ff3ca088b21345ed5dfad5d0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 28 15:21:26 2013 -0800
+
+    doc: First pass for 1.3 finished; docs have most major sections updated.
+    
+    Final edits and corrections still required.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6d9b93bfd637eb690159fc5efda0390eb602c6a7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 28 10:44:07 2013 -0800
+
+    ao-tools: Split out USB loader to ao-usbload
+    
+    Leave ao-stmload using just stlinkv2
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f27dff090c8f3a63bd932715643980703160bde6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 28 10:31:32 2013 -0800
+
+    ao-tools: Split out altos symbol editing from ao-stmload
+    
+    to be shared with ao-usbload
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5ef287723f8d8bfbfb3582d22bfb5c2a3129414a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 28 09:52:38 2013 -0800
+
+    ao-tools: Missing ao-selfload.h
+
+commit e6c9ca218d944443c86555e513534d82713af936
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 28 09:52:01 2013 -0800
+
+    ao-tools: move 16/32-bit readers from ao-stmload to lib
+
+commit d93a65a90f19e4816231e03b1f399af6e3742aee
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 28 09:46:13 2013 -0800
+
+    ao-tools: Move ao-selfload into library
+    
+    This needs to be shared between ao-stmload and ao-usbload
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 14204e3d147ad99cc249ad8de254809180fe5c38
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 28 09:31:02 2013 -0800
+
+    ao-tools: Add ao-elftohex and .ihx symbol support
+    
+    ao-elftohex converts an elf file into a hex file so that we can load
+    it with java.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ee07f1a0f8e431bebb3b948f6249f5f33413e966
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Nov 28 09:29:52 2013 -0800
+
+    ao-tools: Add debug printf support
+
+commit 95a8180f3d7929dbad65c80421f99c925f245af0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Nov 27 13:59:06 2013 -0800
+
+    ao-tools: Create general elf and hex library routines
+    
+    Pulls the elf stuff out of ao-stmload, change the hex stuff into ao_
+    routines.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 73b1a7e644e255558378ab66de6426a7dfd8a7dc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 25 01:15:36 2013 -0800
+
+    doc: Work on AltosUI Pyro config docs a bit more.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 82b42935d047d2f7c2f7a63a3efb72a3f1d5594e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 25 00:02:06 2013 -0800
+
+    altosui: Handle units in pyro config.
+    
+    This lets you edit the pyro configuration using imperial units if
+    desired.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8da565bbafa2925aa889cf9249497a709a814b7f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 25 00:01:20 2013 -0800
+
+    doc: Add telemetry enable and APRS interval config docs
+    
+    Also starts working on the pyro channel config window docs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f743934ebd1a7c7c8b6db0223f0309e590aa15cd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 24 21:55:20 2013 -0800
+
+    doc: use correct quotes in altusmetrum.xsl
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6f4abc14065aebceaac9313e4dcd4300e19999cf
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 24 21:50:27 2013 -0800
+
+    doc: "rocketry electronics" instead of listing products
+
+commit 31a1c701bfaea97225e12ea0688b934790e3737e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 24 21:28:26 2013 -0800
+
+    Use more 1/4 single characters
+
+commit 96f33e780958adaaa4a9cc127caecaeb3f4c978c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 24 21:25:06 2013 -0800
+
+    Remove duplicate log description. Describe pyro config.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3eaaefe6d746a2f53995a2470c5024f37c87c393
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Nov 24 20:05:52 2013 -0800
+
+    Extend the hardware overview chapter. Edit System Operations
+    
+    Extend the overview chapter to include tables describing the
+    electronic and physical board characteristics of each board.
+    
+    Finish most of the System Operation stuff, still need to add pyro
+    channel configuration
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ceed62fd97972b35f4cf6560625135723cb8610f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 18 13:48:18 2013 -0800
+
+    debian: Build now depends on 'xmlto' for docs
+    
+    This wraps xsltproc, fop and xmllint for formatting pdf files
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 92753d4b8d6b17ebc7a9b65680abd46648726393
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 18 12:43:33 2013 -0800
+
+    doc: Use system fo docbool.xsl instead of network one
+    
+    Instead of reading the master stylesheet from the network, just use
+    the one installed on the system.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 89fc38f2cf143bed1fe8c4a4972267b15c9aa467
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 18 12:42:38 2013 -0800
+
+    doc: Make pdf files depend on local stylesheet
+    
+    Now that we're using our own, rebuild the docs when it changes
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f9bbca59a9034cf7e6df4577e627d7447f3a9d51
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 18 12:42:20 2013 -0800
+
+    doc: Make micropeak.xsl validate
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0a3e27e3a392be4cfe03d200068a7e69bb2f3fdb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 18 12:38:52 2013 -0800
+
+    Make companion.xsl validate
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d212d782bff977d609a9da1b805de4a2615fb474
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 18 12:37:23 2013 -0800
+
+    doc: Make telemetry.xsl validate
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 87fbe12bdaf10c9ba7ba43608b1e980cdc09d496
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 18 12:29:42 2013 -0800
+
+    doc: Make altos.xsl validate
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 963a61986ea4b48fdca0989479e9c50acb0f1a9d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 18 12:12:54 2013 -0800
+
+    doc: Switch to xorg style to generate index
+    
+    This style sheet generates a nice PDF index
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9953a5f0440b269dac5c675f120e6a31dde8ec69
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 18 12:06:31 2013 -0800
+
+    doc: Get altusmetrum.xsl to validate
+    
+    Mostly involved getting the listitem contents into para elements.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 152d978dc4be49b6b764e5e1966bd860c46054ea
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Nov 18 12:05:10 2013 -0800
+
+    doc: Start work on 1.3 doc updates
+    
+    Add 1.3 release notes.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 71705532374f222e51c66e2f1214dd01b3efc8bd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 15:02:50 2013 +0900
+
+    Bump to version 1.2.9.4
+
+commit 12481415c2e5fb03b003343c9499df711eb14f91
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 16:26:02 2013 +0900
+
+    altos: include ao_eeprom.h in ao_telemetrum.c to define ao_eeprom_init
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bf893a4149b05b97f18f9f487af805adef859d74
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 16:22:49 2013 +0900
+
+    altos: Make sure flight erase log comes after config blog
+    
+    Oops. When converting from ao_storage to ao_config, I accidentally had
+    the flight erase log overwriting the config block.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 92eafd01f2809f39c5bc4058977c790d94a99df1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 16:08:50 2013 +0900
+
+    altos: Move telemega to using internal eeprom for config
+    
+    And crank up the default per-flight storage to 1MB
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9c53ad6f8222878a26efecebd3bb1d1fe054a4b6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 16:06:59 2013 +0900
+
+    altos: Move TeleMetrum v2.0 to using internal eeprom for config
+    
+    This leaves the whole 8MB of flash for flight storage
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 83437b2fe304599e22d0a98b5410808bcb67dc97
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 15:45:32 2013 +0900
+
+    altos: Allow use of internal EEPROM for config storage
+    
+    This stops exposing eeprom as 'storage' and instead exposes it with a
+    separate eeprom API so that it can be used for config storage without
+    also using it for flight log storage.
+    
+    The config code has been changed to allow it to either use storage for
+    configuration data or eeprom.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b57f1cabfe5052306cb4c28793bea477f4aeb2d2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 15:18:58 2013 +0900
+
+    altos: Don't hold GPS mutex while waiting in TM v2.0 report
+    
+    Holding the GPS mutex while waiting for the GPS code to dump data into
+    the GPS variables is rather counter-productive.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0951b1ef83d8d741d65811fa23bde43ee843a939
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 15:18:53 2013 +0900
+
+    altos: Build TM v2.0 firmware by default
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3c40272713d93e79bb0989eefe191cd2bfe56a44
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 15:01:13 2013 +0900
+
+    ignore "compile" script
+
+commit 28327883d377896caddbad0f9efded56a227edd1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 14:59:40 2013 +0900
+
+    Add TeleMini v2.0 turnon script
+
+commit cffbc025532487bbd9b467476be05d0997b5133e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 14:56:47 2013 +0900
+
+    ao-tools: add ao-mega man page, ignore executable
+
+commit 40d3575a9365d77ca507ebee226d51d081e1ecc6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 14:54:57 2013 +0900
+
+    altos: Clean up .gitignore and add a few random files
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9d2eb0b00a5a0faefce95bce949be7206b0aad37
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 14:48:21 2013 +0900
+
+    Add ublox checksum generating program
+
+commit d5367f20fa1ae71496fde071953c2cda89654071
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 14:45:51 2013 +0900
+
+    Ignore mac .dmg files
+
+commit 0093d5b368669e0c324f8d9dfcd2f004de85ee5c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 14:37:57 2013 +0900
+
+    altosui, altoslib: Move eeprom download code to altoslib
+    
+    This should make adding eeprom downloading to altosdroid easier
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 45db3076b257adcf2c9f69ed0927f09d94af7a50
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 14:28:30 2013 +0900
+
+    altosui: Make AltosEepromDownload not swing-dependent
+    
+    Will move to altoslib
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6aa99c160f0695eb25ccc0598e4c36224c89dab4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 14:06:20 2013 +0900
+
+    altoslib: Start moving eeprom download logic to altoslib
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 74d73a2cd0b6a228eb396552e1d16685669349c0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 14:03:42 2013 +0900
+
+    altoslib: Raise ParseException on invalid eeprom format
+    
+    Make sure the user knows when data are not downloaded successfully
+    because the UI doesn't understand the eeprom format.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bdd6244d8b4a55c9aa4fb79b0cb1a0727afbc2ac
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Nov 12 14:01:55 2013 +0900
+
+    altos: Add orientation tracking to ao_flight_test
+    
+    Shows calculated offset from vertical in ao_flight_test output
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 29b48b63305881471d9b97ef3fb236af03cb79f5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 28 00:36:13 2013 -0700
+
+    altos: Don't hold GPS mutex while waiting for GPS data in report code
+    
+    Oops. This kinda breaks anyone else waiting for GPS data
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d3628bd2dd3612065792aef6c7ae5bc967b4f081
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 28 00:24:59 2013 -0700
+
+    altos: sample profile address range was too narrow
+    
+    The range was cranked down at some point to diagnose issues within the
+    task scheduler. Unfortunately, that change got merged, which meant
+    that general profiling lost information outside of the lower 4kB of code.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7c1c6728bce4237ca3a8f6fde01356697a465dfd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:47:27 2013 -0700
+
+    altos: Make telemega v0.3 compile with new quaternion code
+    
+    Adds lots more math code
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e838bd2847e5684ce93b6f7cbe736ebed681c3c6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:46:54 2013 -0700
+
+    altos: Make telemega v0.1 compile with new quaternion code
+    
+    Adds the necessary math code
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9b0ce8ca65d76b9cf55dfff002e13ce2fbb5f7fc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:45:48 2013 -0700
+
+    altos: Add orientation test when HAS_FLIGHT_DEBUG is set
+    
+    This just dumps the current orientation to stdout so you can monitor
+    it in real time
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5d9e715d570b24ac124c30772b11923bd26ed670
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:44:47 2013 -0700
+
+    altos: Update quaternion tests to check vectors_to_rotation
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 195fd70cdc7f519cd8d4ac323088ed0b6c188280
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:42:58 2013 -0700
+
+    altos: Change ao_mpu6000_gyro arg to float
+    
+    This lets callers pass more precision than just the original sensor value
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3d3fe7e9b6502432868f4430befac871dfea4869
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:42:26 2013 -0700
+
+    altos: Fixup for 32-bit gyro averages
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4bebade9e9004bad81df1a423687f3e3f356f1c2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:37:55 2013 -0700
+
+    altos: Correct incremental rotation computation
+    
+    Trying to compute the combined rotation by taking the x/y/z rotations
+    as a vector is a good approximation, but not accurate enough for our
+    application given the large angles we sometimes see.
+    
+    Instead, use a correct-but-expensive function with a pile of
+    transcendental function calls. The STM32L seems to be fast enough at least...
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 06b0c1b768a7d3eae57e66bc9aea25db49f9ea8a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:35:54 2013 -0700
+
+    altos: Compute initial rotation from vertical
+    
+    This initializes the rotation with the angle from vertical, rather
+    than simply recording the off-angle vector. Doing this allows us to
+    accurately track the true orientation of the rocket, instead of just
+    the offset from the initial non-vertical orientation.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cdbe8ce33e4a75e85caf07538ed7e997f462b758
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:33:11 2013 -0700
+
+    altos: Fixup for ao_sample_orient rename
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d96fd33aa8a220d547512eb43c88fc8f5651e39e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:28:50 2013 -0700
+
+    altos: Add sinf to math code
+    
+    Needed for the quaternion gyro tracking code
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fa7d0ba0efdde3ac9fb4df0589f9ead07b7ffff5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:26:28 2013 -0700
+
+    altos: Keep 9 more bits of average pad IMU gyro data
+    
+    This reduces the offset error by a bit, minimizing gyro drift.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 58f08c4b3cb9049d0c9cb02cde0d8dbdc3d33920
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:23:59 2013 -0700
+
+    altos: Rename ao_orient to ao_sample_orient
+    
+    Keeps it clear where this name comes from.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c10cb9d31765e6ef0ba737bc484c5aed22a332f9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:11:37 2013 -0700
+
+    altos: Add functions to init quaternions from vector pairs and euler angles
+    
+    Our low sampling rate means that the "cheap" hack for
+    integrating quaternion rotations by using sin(x) ≃ x doesn't work, so
+    instead we have to compute the partial rotation the hard way.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3b25860b5b3b69642928dd9c30dec4b4b937a88c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:11:09 2013 -0700
+
+    altos: Add some comments describing quaternion multiplication
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 616977d2955da13383a1869b9ccdb07338172109
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 23:10:13 2013 -0700
+
+    altos: Mark arguments to quaternion functions as const
+    
+    Lets us pass constants without the compile whinging
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e923e11e185fd42d2a83e18b3d13bd839a72b1aa
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 27 22:44:49 2013 -0700
+
+    altos: IMU accel calibration values need to be signed
+    
+    The MPU6000 reports signed values.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 351d53836e201834a2d89773a08ab7c2dab2b2f4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Oct 25 04:34:16 2013 -0700
+
+    altos: Calibrate IMU accelerometers too
+    
+    Average the IMU accelerometer values pointing up and down so that we
+    have a zero-g offset for all three axes. This can then be used to
+    compute which direction the rocket is pointing while sitting on the pad.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 08143a922fe27bc50a19924f46538f9476ab5fd1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Oct 25 04:05:09 2013 -0700
+
+    altos: Add gyro-based orientation tracking
+    
+    This tracks the angle-from-vertical as an additional input to the pyro
+    channels.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ba99630f33440b993c69830856d2a7741ffdef71
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Oct 25 04:03:39 2013 -0700
+
+    altos: Fix GPS test frameworks to handle shared ao_gps_new variable
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b83876718b1a535ee04ca0351ad57814454ec646
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Oct 25 04:00:49 2013 -0700
+
+    altos: Add floating point math functions from newlib
+    
+    These are all BSD licensed, so we can simply include them directly
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 039446f54ef6968a3f0b37ce32ca6bdcdbe62546
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 14 22:41:43 2013 -0700
+
+    altos: Merge GPS logging into a single function
+    
+    Create a new global, ao_gps_new, which indicates new GPS position and
+    satellite data.
+    
+    Use ao_gps_new as the new sleep/wakeup address.
+    
+    Merge the separate gps position/satellite logging tasks into a single
+    function which waits for new data and writes out the changed values.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5c4b3658a96f1a64ccebf7bddda06b15b4ac4a6f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 14 21:49:39 2013 -0700
+
+    altos: Use #define values for ublox packet types
+    
+    One case was using hex values instead of the #define equivalents.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit db4cd8b3838d27bebdeb6a085a739a36f7634a91
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 14 20:42:14 2013 -0700
+
+    altoslib,altosui: Be more robust when graphing bogus .telem files
+    
+    Deal with files containing multiple serial number/flight number values
+    by preserving the boost_tick value across state resets.
+    
+    Check for invalid state when computing actual boost time for the stats
+    window.
+    
+    Ignore invalid speed/accel values when computing averages.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1bd9786802751391cca3b83ac3045029e00e39ee
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Oct 13 22:05:20 2013 -0700
+
+    altos/micropeak: Increase boost detect to 30m
+    
+    This meant increasing the data buffering as well so that we could
+    reliably capture the flight data back to the ground, even for slow
+    flights.
+    
+    And, with the buffer extra large, we work backwards from the current
+    buffer location to find the last ground location rather than working
+    forwards from the first buffered location. This ensures that we don't
+    capture noise before boost and instead capture a nice flight curve instead.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e0e98597887a970f31b33895adb77d35e06b34ff
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Oct 10 14:35:54 2013 -0700
+
+    updated turn-on script for telebt 1.1
+
+commit 8af5dd05fe56768f225251bbc66831494d80048e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Oct 10 10:02:03 2013 -0700
+
+    Another try at skipping broken avr-gcc
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2296175eff9e4286eaf44451690701a46595987e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Oct 10 09:47:52 2013 -0700
+
+    Make sure the AVR compiler can actually link stuff
+    
+    avr-gcc was broken for a while, causing all linking to fail. Check for
+    that and don't try to build avr bits in that case.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit aa169b80039728e35b0dec3be66a8483d48a3458
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Oct 10 08:04:22 2013 -0700
+
+    altos: Fix stm-bringup demo build to use installed pdclib
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d8d3835fedf9b7c4d203f321e72c2b086ebb3b97
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Oct 10 00:00:05 2013 -0700
+
+    altos: Use installed pdclib
+    
+    Switch over to the installed pdclib everywhere
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7f6cbfac7c1965add91ebfc28ca3eac4561b4fb6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Oct 9 12:04:14 2013 -0700
+
+    Bump version to 1.2.9.3
+    
+    Rocketober, 2013
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e947bc5e1abcd054a584d69240f91123bad2178e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Oct 9 12:06:30 2013 -0700
+
+    doc: Add easymini outline to distribution
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 18cb5f0b8f0917cbd4ff80f0920e8e5b35c822a1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Oct 9 10:14:16 2013 -0700
+
+    doc: Add EasyMini outline drawing
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c584b5fc1128c7bfd7fb921ddc3a8ec498803b53
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Oct 9 12:37:30 2013 -0700
+
+    altos: Messed up the ifeq syntax a bit so ARM bits weren't getting built
+    
+    $(x) is not the same as ($x)
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 74885d75621dad04984d8309c2618202f4d2b35e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Oct 8 10:03:50 2013 -0700
+
+    altosui: Binaries to package are only in per-product dirs now
+    
+    Each cc1111 project used to stick the binary in src/, but I got rid of
+    that when we ended up with so much stuff in src that it was a mess.
+    
+    Building the release now requires looking in the appropriate directory
+    for each binary to ship.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0e5d1f3ce39495e3702ecd22cb45972e13a5c986
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Oct 8 09:50:21 2013 -0700
+
+    altos: avr-gcc appears to find the loader scripts without help now
+    
+    At some point, avr-gcc lost its ability to find the loader scripts
+    necessary to link programs. That appears to be fixed now, at least on
+    my machine.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f7cccbb7a624a2a47b21682f416a135a28319b41
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Oct 8 09:39:29 2013 -0700
+
+    altos: Broken test for M0 compiler in src/Makefile
+    
+    Was causing it to try to compiler M0 progs only when *no* compiler was found.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 488a527267decece48e6682e0e0c7fc29cbed329
+Merge: 6a1e398 f6661cc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Oct 8 09:26:41 2013 -0700
+
+    Merge remote-tracking branch 'origin/master'
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+    
+    Conflicts:
+       configure.ac
+
+commit 6a1e398e590121458176758858bb4210f3eb5a55
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Oct 8 09:22:03 2013 -0700
+
+    Add --with parameters to configure for compiler selection
+    
+    This allows the user to specify which compiler to use for each target
+    CPU. Also checks to make sure the arm compiler supports -m0 and -m3
+    cpu type flags. The build now actually uses the specified compilers too.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 16965716c02eb79b449d9d3b264814d775660134
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Oct 8 09:20:12 2013 -0700
+
+    altos/stm: New GAS version requires flags in APSR assignment
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 258d225df1f4afe1cfdc9c43208bcd75d18cdf2d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 7 22:00:15 2013 -0700
+
+    altos: Rename easymini-v0.1 to easymini-v1.0
+    
+    The production boards are the same as the modified v0.1 boards
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8f7edcee2db30652ce0b147f282de3396c3786ad
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 7 21:53:53 2013 -0700
+
+    altos/lpc, altos/stm: ARM requires ISB after switching stack pointers
+    
+    This sticks a barrier in the CPU to prevent using the wrong stack
+    register past the change.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4254de22864de2ed7ae5928c6b8bfd9df1c8a3fb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 7 21:51:30 2013 -0700
+
+    altos: Don't require an LED for ao_flight
+    
+    EasyMini has no LEDs. Deal with it.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 71666409624bf544e8a55fa5ee91d2f8514a03ca
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Oct 7 21:49:55 2013 -0700
+
+    Change differentiation filter constants and limits
+    
+    Larger limits avoids clipping legit data. Using the same filter time
+    for both ascent and descent makes the results look a bit cleaner.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f6661cc015e1a92450dc3eede97d66005f69cc72
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Oct 7 21:56:46 2013 -0600
+
+    new toolchain for STM32L is in /usr/bin, not /opt/cortex/bin
+
+commit 8bd218854e968d2b9407489359be0c4a1aefd2c8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 19 00:29:25 2013 -0500
+
+    altos: Set TeleMini v2.0 USB ID correctly
+    
+    Uses 0x0027
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3bf7ed1761e08d0cb43b0ed330226ec38c844591
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 19 00:28:55 2013 -0500
+
+    Add TeleMini v2.0 telemetry support
+    
+    Includes AltosLib and ao-telem
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit be7f56b86478ef4a23a2af77338c580b9c9e5e3b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 19 00:26:24 2013 -0500
+
+    altoslib: Prefer averaged ground pres for ground alt computation
+    
+    If ground pressure is recorded (as from an eeprom file), then prefer
+    that value to the average of the pre-boost ground pressures when
+    computing the ground altitude.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 56b577e55c264c8e3152bb2b2cca02fa8836ac1e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Sep 15 14:29:46 2013 -0700
+
+    altos/telemetrum-v2.0: Use red LED during boot time
+    
+    If the LED is stuck on, then the board has failed to initialize,
+    so use red instead of green as a warning indicator.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1fa3ff9ba6d04303b3de6952675532492c85182f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Sep 15 14:29:09 2013 -0700
+
+    altos/telemini-v2.0: Change initialization order
+    
+    Make sure busses are running before devices are initialized
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0ff5f0fbc4900ad45bb7910ffc0c5a4e4cc4b857
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Sep 15 14:21:08 2013 -0700
+
+    altos: Stop copying cc1111 binaries to the altos/src dir
+    
+    Just clutters up that directory.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b86c69d56261da54745076b1f5a9c8e8e44787c2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Sep 15 14:13:59 2013 -0700
+
+    altos: Add nanopeak-v0.1
+    
+    The same as micropeak, just a few different pins
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 690094e2d7d9cfe5eb4edb478fd79e5d133c6b4b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Sep 15 14:11:50 2013 -0700
+
+    altos: Move micropeak sources around
+    
+    This sticks the micropeak sources in appropriate directories, rather
+    than in the micropeak product directory so that they can be shared
+    with future micropeak-style products.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2449d123690746d0d0d5d66dfc4d3a05b9f5dc0c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 6 18:24:46 2013 -0700
+
+    altosui: Include device name in Table view
+    
+    It's part of the telemetry, so we might as well display it
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ae675c66594d366774d8f7f9c78f1236d3810eed
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 6 18:23:06 2013 -0700
+
+    altoslib: TeleMetrum v2 telemetry includes computes Pa/°C, not raw values
+    
+    Telemetry sends converted pressure/temp values as it doesn't include the
+    MS5607 calibration data.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4e22b34bde421a9df090c9196fd4347468c8176a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 6 16:54:07 2013 -0700
+
+    altoslib: Add receiver serial to telem file names
+    
+    Makes it easy to record telemetry from multiple sites and compare them later.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0ad95614685a73856bb26a94866909e5fc025434
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 6 16:52:51 2013 -0700
+
+    altosui: Set 'flight' value in AltosEepromMonitor window during download
+    
+    This feature was lost in the AltosState updates
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b66e0d4c107a0727279d03d1d0e1e40a9eaaa3bc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 6 16:52:06 2013 -0700
+
+    altosui: Load Telem files in AltosDataChooser too
+    
+    Telem file loading was stubbed out from AltosState changes
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a1512255d20c8a395f30ed4914ddd3295842312b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 6 16:51:44 2013 -0700
+
+    altoslib: Add TeleMini eeprom file to Makefile.am
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1e52d34137626ca756ea01f317ef7c359e464a5b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 6 16:50:46 2013 -0700
+
+    altoslib: Lock access to AltosLink config_data
+    
+    Prevents multiple callers from trying to get config data at the same
+    time and messing up the serial line
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 29bb16397f14ed617ca3fbf48f2a7b726fd627d8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 6 16:49:36 2013 -0700
+
+    altoslib: Set 'valid' for valid TeleMetrum eeprom download
+    
+    Had separate 'tick_valid' value, which wasn't useful as the supertype
+    didn't look there.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a299a5a9a1b89c7ebc00ebd33a789793a6835181
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Sep 6 16:48:52 2013 -0700
+
+    altoslib/altosui: Add TeleMini-v1.0 eeprom support
+    
+    Got lost in the AltosState transition
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 82b3e3e4889aa5d4d157df1ad82e28068fda9e2a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 23:31:22 2013 -0700
+
+    altosui: Remove debugging printf from InfoTable
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7f4650990e8a7cfcf8461e8928dfc426c9a563cc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 22:57:19 2013 -0700
+
+    altos: Set tick value in new TeleMetrum v2 sensor packets
+    
+    Was getting left with the old value, which wasn't very useful
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7314bf807544eecf2fd970e93c752ff15688bb42
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 22:56:57 2013 -0700
+
+    ao-tools/ao-telem: Parse new TM v2 packets
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ffdf82445817d1c97699f7de82534420b87d0ea7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 22:56:11 2013 -0700
+
+    altosui: Fix 'Graph Flight' button in landed dialog
+    
+    Telemetry file reading was broken (oops!)
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0e3edacceb169326b8f5727bb5737d8238e9e40b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 22:55:43 2013 -0700
+
+    altoslib: Remove debug printf from AltosTelemetryMetrumSensor
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 59f0deff6d7bae22fb1b9a0649f3481b3d287d8e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 22:55:09 2013 -0700
+
+    altoslib: Rewrite AltosTelemetryIterable
+    
+    Sort while reading instead of sorting separately.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit effc62354fc82bb937c6f445a147fc92153a0731
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 22:54:02 2013 -0700
+
+    altoslib: Record time_change in AltosState correctly
+    
+    time_change is used to make real-time playback work.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b9ee58a7af839462680a0bdf1c1721017269986f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 22:53:14 2013 -0700
+
+    altoslib: Update received time when replaying flights
+    
+    Received time is otherwise recorded as the time when the packets were
+    read from the file, which doesn't work in real-time playback
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e17e3691d93636eebbd7381f2df1303dc46ea96c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 22:52:22 2013 -0700
+
+    altoslib: Only open log file when both flight and serial are known
+    
+    Some telemetry formats include serial and flight in different packets,
+    so wait for both before creating the file
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a9c495c7ca1e08b7ac76b0dab8b3bd9bd3a7edfc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 15:03:07 2013 -0700
+
+    altoslib: Use AltosTelemetry.parse to pull telem lines apart
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9f017b4837b106e8c422955a95762f1bf3c78016
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 15:02:47 2013 -0700
+
+    altoslib: Remove more AltosRecord based files
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 984515452f9ab56dad112d725469acfa54e2233b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 11:55:24 2013 -0700
+
+    altoslib: remove AltosRecord based eeprom code
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3325df306933f080619f13ba1db45de484613d5a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 11:50:41 2013 -0700
+
+    altoslib: Remove AltosRecord-based telemetry code
+    
+    All of this is now AltosState based
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e9e9c6592c49109288a4e02e780b130fadb97db7
+Author: Mike Beattie <mike@ethernal.org>
+Date:   Tue Sep 3 15:11:33 2013 +1200
+
+    altosdroid: convert rogue files to unix line endings
+    
+    Signed-off-by: Mike Beattie <mike@ethernal.org>
+
+commit 93e66b4911b7285f9095712ef746571153c3f088
+Author: Mike Beattie <mike@ethernal.org>
+Date:   Thu Sep 5 03:11:42 2013 +1200
+
+    altosdroid: more updates for new AltosState
+    
+    Signed-off-by: Mike Beattie <mike@ethernal.org>
+    
+    Conflicts:
+       altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.java
+
+commit ee14ad16c242e8bd7a9d33ebf569211d1490b8e1
+Author: Mike Beattie <mike@ethernal.org>
+Date:   Tue Sep 3 15:10:23 2013 +1200
+
+    altosdroid: update to support new state code
+    
+    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
+
+commit 5b976a6651f4eb05d30afc08b9e1f27c7e52ae00
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Sep 5 11:33:48 2013 -0700
+
+    altoslib: Finish AltosState changes. Update version number.
+    
+    Removes all of the AltosRecord bits, changes the monitor idle bits to
+    have per-object state updaters.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b984ff81d6b8979574e0248ffe8876634b8e1942
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 3 17:42:42 2013 -0600
+
+    altoslib: Set measured acceleration for measured acceleration
+    
+    Was setting computed acceleration even for measured data
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 96a651cc1b81b30f4cbde454e34cf80ed8825945
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 3 17:42:00 2013 -0600
+
+    altoslib: Clear sat data when tick changes
+    
+    Sat data comes in multiple records, but the tick is always the same,
+    so use that to tell when the set of sats is new
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4de934c283a839fcbb246b36aa15362f3cf8629c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 3 17:41:12 2013 -0600
+
+    altoslib: Start integrated value at 0 by default
+    
+    Check for MISSING and start at zero in that case
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cfd8e4ebb3cb63937a71537095adb911d6211817
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 3 17:40:04 2013 -0600
+
+    altoslib: Use first few baro samples for ground pressure on TM
+    
+    TM didn't record the ground baro reading in the log file, so pull out
+    the first few measured baro samples and use those instead.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6ee99c1861ef1898a77aead41d80383e697bd248
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 3 17:38:20 2013 -0600
+
+    altoslib: Make Ascent/descent use different filter values. Always filter.
+    
+    In derivative code, use a shorter filter during ascent as the baro
+    sensor is cleaner then. Then, make sure to always filter the values as
+    the very first few baro samples can be noisy, which generates a bad
+    starting speed.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 70e67925cff98984d49fbc3f60e880c91e6d5079
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 3 17:36:16 2013 -0600
+
+    altoslib: Remove duplicate cmd/tick from TM eeprom file code
+    
+    Also replace tick setting with super call (which does that)
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bc54014cfd4dbca67fa9db66e906ab8212a2eaa2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 3 17:35:23 2013 -0600
+
+    altoslib: Clean up metrum eeprom file reading
+    
+    Spurious tick setting, fix some local variable names
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d203a2da2641bec21a4257c8a7b03d9a1eba53a5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 3 17:34:41 2013 -0600
+
+    altoslib: Correct mega/metrum eeprom years by adding 2000
+    
+    The files contain a single byte for year, which is always years since 2000.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 999c3c7866613e658a6c26374499bc516bbc944d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 3 17:32:37 2013 -0600
+
+    altoslib: Correct tick wrapping in eeprom file reading
+    
+    Just need to signal that at least one record has been read to know
+    when to start checking for wrap
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7d3af3d74f70a0933829be91ad3e3be04b1f1023
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Sep 3 17:31:58 2013 -0600
+
+    altoslib: Ensure eeprom file body always exists
+    
+    Create an empty list of body elements if none were read from the file
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 528e2e41112cad8a81bccbb89c3bd202b818a506
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Sep 2 23:10:23 2013 -0600
+
+    altoslib: More AltosState hacking
+    
+    EasyMini graphs are looking good now.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 224a1e01bacb7db0076129906ed58e1c785e1b14
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Sep 2 23:08:34 2013 -0600
+
+    altos: Not all products have pins to control flash loader
+    
+    TeleGPS has no exposed pins for this function
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 77dc89ed5b7bf8f5b3fa3b6131660f1a98f583ea
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 31 23:11:39 2013 -0500
+
+    altoslib/altosui: Further AltosState transition work
+    
+    Parses most eeprom and telem records now; altosui updated to show from
+    AltosState info.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c781469ff907a32bd43a5d781391b6859b14cd32
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 31 23:10:56 2013 -0500
+
+    altos/telegps: Initialize logging system
+    
+    Otherwise, very little logging works
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7ec1b97d278c7aec3199fb7270f0dcf9484c879f
+Merge: 017ed54 4188153
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 31 08:22:09 2013 -0500
+
+    Merge branch 'master' into new-state
+
+commit 4188153548fca104bb49cda2d502c708fe4b49d7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 31 08:20:48 2013 -0500
+
+    altos/lpc: Add bits for building flash loaders
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 017ed54ff69ef2f7740ea2578e22bf72e88deafb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 31 08:19:28 2013 -0500
+
+    altoslib/altosui: Fixes for state changes
+    
+    Format for gps alt (now double).
+    Use new code for csv file loading.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f07f6d55edf5b97020680b3ce1d9e00bb3df64a6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 31 01:48:02 2013 -0500
+
+    altoslib/altosui: Get legacy telem working with new AltosState structure
+    
+    Make AltosTelemetry work without AltosRecord
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit de8d9c5630ae46378c50faf97f7d2e97fe139e30
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 29 19:24:51 2013 -0500
+
+    altoslib, altosui: Restructured state management now does TM eeprom files
+    
+    Removed uses of AltosRecord from AltosState, now just need to rewrite
+    the other AltosState changing code to match
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ce1378385ef273010498e81c205f42d8e32c7dc1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Aug 29 19:22:18 2013 -0500
+
+    altos: Split EasyMini and TeleMini log formats
+    
+    Same data, but EasyMini uses a 3.0V supply while TeleMini uses 3.3V,
+    which changes the intepretation of all of the ADC values
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 04d7d0f829ba953ffeca8ad9887a4b6b2b5d5087
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 27 21:28:07 2013 -0600
+
+    altoslib: Start restructuring AltosState harder
+    
+    Make per-packet code update state itself rather than having all state
+    updates done centrally. Will make adding new packet types easier.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dcc51bb18985c24fa35bce0dd42ea3d847b960bf
+Merge: 7c82acc a73b025
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Aug 28 22:52:58 2013 -0600
+
+    Merge remote-tracking branch 'origin/telemini'
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+    
+    Conflicts:
+       src/core/ao_telemetry.c
+       src/core/ao_telemetry.h
+    
+    Added both Mini and Metrum telemetry defines
+
+commit 7c82acc1c1c5b7b4da7c7ecb3b2fd90140e4c703
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Aug 28 22:12:25 2013 -0600
+
+    altos/stm: Make sure we switch to MSI during timer init
+    
+    Need to ensure that the CPU is actually using the MSI during timer
+    init or all of the other clock changes won't work
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6802b6a65b1fec06c2c873282be792c40b3c8f5e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Aug 28 22:10:58 2013 -0600
+
+    altos/stm: Remove stale timer defines
+    
+    Stuff from when we weren't using systick
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8e9ed70f50e3f535c2580820771bb1bc3cd055fe
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Aug 28 22:08:51 2013 -0600
+
+    altos/stm: Make sampling profiler work again
+    
+    Disable the separate stack as that means we can't figure out the PC
+    from the timer interrupt. Move ao_idle_loc after the interrupt release
+    so that we see idle tasks correctly.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2fa87754c5c11bb86e9b1878580c3d4f4b2463f5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Aug 28 22:08:04 2013 -0600
+
+    altos/stm: New compiler doesn't correctly build flash bits yet
+    
+    Use /opt/cortex until we make the packaged one work
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4887af0bf90661a3fdca76f1797a704888edab06
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Aug 28 22:04:18 2013 -0600
+
+    altos: Force u-blox to 9600 baud for now
+    
+    The Max-7 parts just aren't happy switching baud rates, managing only
+    about half the time. Someday I'll figure out why, but until then, make
+    things work by just leaving the chips at 9600 baud
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 61163980f096d555a843e25cd9fe1aec93bbbbba
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Aug 28 22:02:48 2013 -0600
+
+    altos: Add debugging to ublox GPS driver
+    
+    The new max 7 parts seem to be unhappy about switching baud rates, so
+    I've added a pile of debugging to help out. Some day, I'll figure out
+    how to make them work, this code is being left in place to help with that.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 44d4c66b21d6b5a0c656fdff6d01ef1d125c1101
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Aug 28 21:54:31 2013 -0600
+
+    altos: Update time for next alarm each time a task is added
+    
+    Adding a task with a sooner timeout than existing alarm tasks was not
+    correctly updating the time to fire the next alarm, causing tasks to
+    be delayed by the wrong amount.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 39475c7b8da4f29936f73ffa2bff112f50ee9328
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Aug 28 21:52:29 2013 -0600
+
+    altos: TM v2 places the MMA6555 upside down compared to Tmega
+    
+    Means we need to invert the data coming out to make it work
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f222e8504bfd01027e3c380c239a2cde2c367d74
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 27 22:00:29 2013 -0600
+
+    altos/telemetrum-v2.0: Use 9600 baud for ublox
+    
+    Something is up with the Max 7
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit abde595116f6e8b60ec9ce81554c05de11fd456e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 27 21:36:02 2013 -0600
+
+    altos/telemetrum-v2.0: Fix MMA6555 SPI pin assignment
+    
+    For TM v2.0, it's on PB 3-5, not PE13-15
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 454a41359b94e9bcf8582420abc359bbab9d8176
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Aug 23 11:25:56 2013 -0700
+
+    altos: Rename TeleMetrum v2.0 ADC sense members
+    
+    Use sense_a and sense_m instead of sense[2]
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6aade70be0a7669d65a8606753d21e4eef5592cd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 20 14:20:56 2013 -0700
+
+    altos: Add TeleMetrum v2.0 boot loader
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7b0f9b25a56fa8b4aa1c2e9d79c43e6a97cab0c0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 20 11:40:17 2013 -0700
+
+    altos: Initial TeleMetrum v2.0 bits
+    
+    Adds new telemetry and logging formats along with code for TeleMetrum
+    v2.0 design.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a73b02518fcbc9fc0807ed8e141d3a06e8ad8214
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 18:46:02 2013 -0700
+
+    altos: Don't use ao_data on cc1111 projects
+    
+    cc1111 ao_adc.c supplies the needed globals at this point, and linking
+    both into the program leads to two different versions of each at
+    different addresses (yay SDCC linker!)
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d54156caf856ab5570f050692b333a2c5d991265
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 18:44:23 2013 -0700
+
+    altos: Make ao_wakeup reentrant
+    
+    In case we end up invoking it from two places at once.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7e941695aa27e5eaf453ca1128b8d835472410a4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 18:43:20 2013 -0700
+
+    altos: Check for MS5607 MISO low before sleeping
+    
+    If the MISO line goes low before we manage to configure the
+    interrupts, we'll miss it entirely unless we check the pin explicitly.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9b9acb88aa97e8565cdf9342fc59a5aee08e3d34
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 17:18:57 2013 -0700
+
+    altos/telemini-v2.0: Add ao_exti.h depend. Init beeper and usb.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7274b77666df9d2cab2854ec1a403d80e5fce73b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 17:18:17 2013 -0700
+
+    altos: Use %ld and %lu for MS5607 debug output
+    
+    The value are 'long', so use the right printf format.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4e3955a5b0ac125bd807920c467f959618449fbc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 17:17:47 2013 -0700
+
+    altos/cc1111: Wake up non-ADC sensor code each timer tick
+    
+    Make sure the MS5607 code gets told to sample every tick
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3b2f83a7d686b5fbc0aaa56d48cb734f353631c8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 17:16:54 2013 -0700
+
+    altos/cc1111: Leave pin interrupts completely disabled at init time
+    
+    Don't even turn in the PICTL bits as that seems to cause the chip to
+    be unhappy.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8ca98dc8c868c47c372d6b666c36e691fa402824
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 17:15:55 2013 -0700
+
+    altos: Get telemini to copy current MS5607 state to ring.
+    
+    The ADC code is responsible for actually inserting the non-ADC data
+    into the ring, so do the copy there.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit af9f9cf0c21630562c74fae41773319229bf44d3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 16:42:45 2013 -0700
+
+    cc1111: Hacky pin interrupt support. Only useful for TeleMini v2
+    
+    This code is designed to support the MS5607 MISO interrupt bits.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2380a4b9bd69629c78eec0a87ff8681a0524d8d2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 16:41:33 2013 -0700
+
+    cc1111: Rework ADC configuration a bit, fix Tm V2 ADC usage
+    
+    The Tm v2 ADC code was not actually fetching and storing the ADC
+    conversion values.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit aeb1c8a2aa533cb2805f0dbe848e098c8cae2b39
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Aug 26 16:39:47 2013 -0700
+
+    ao-tools: Use TeleDongle for default ao-dbg target
+    
+    Makes more sense than assuming we're still using the old TI developer board.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 377a44cbfd5c8a659d2fecabb154726717a41900
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 25 22:34:09 2013 -0700
+
+    altos: Build more products by default
+    
+    We keep creating more hardware...
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e72147e215a982ce701099626424b9a856ac9d09
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 25 22:33:30 2013 -0700
+
+    altos: Changes required by cc1111 multi-spi support
+    
+    These drivers got missed
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit af6f4205b00669af40acffc528cc8093b0236cf6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 25 22:29:46 2013 -0700
+
+    Bump version to 1.2.9.2
+    
+    Set version for Airfest testing
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 312f6194a4bc75473cb0d61a6d58b66fb1f7c068
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 12 00:43:31 2013 -0700
+
+    altos/teletiny-v2.0: Support multiple SPI busses on CC1111
+    
+    Needed for TeleMini v2.0
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2c2bbfd9a1a4b9de42cf566f21f179ff5ede0419
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 23 16:52:59 2013 -0600
+
+    altos: Add exti and spi to telemini-v2.0
+    
+    No longer builds like this
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 56911f27376b0fe91a464e369bb8aa1531b3c7dc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 23 02:17:51 2013 -0600
+
+    altos: Make TeleMini v2.0 fit
+    
+    Mash lots of storage locations and code around to shrink stuff down to size
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cb844328322fd7d9f4dafb58b322257a70b347e6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 22 19:20:54 2013 -0600
+
+    altos: Add 64-bit subtraction
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5ccd902d0fd2adc40c72982babb60fac4da6a087
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 22 17:08:55 2013 -0700
+
+    altos: Add 64x64 multiply. Test 64 ops for dest same as either source
+    
+    The test change is to ensure that the destination may be one of the 64
+    bit sources.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f7602ae566a5cbf2d2cbb1d68bad7e2d1177a33a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 22 14:38:19 2013 -0700
+
+    altos: Make 64x16 mul a bit faster
+    
+    the unsigned 32x32 multiply really does work, just use it
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3114baef45803250a2e5cdd2ee4a9171f2045b0c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 22 14:32:50 2013 -0700
+
+    altos: Add 64-bit add/mul/shift for SDCC
+    
+    SDCC doeesn't provide a native 64-bit type (sigh), so
+    implement the minimal operations necessary for the MS5607 conversion
+    routine.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d0b4e926ecececa7499a301b6135189be119512e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 22 13:03:06 2013 -0700
+
+    Initial TeleMini bits
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3ded57394f6dfd7beb9526c031a5c6c6c9926917
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 25 22:22:55 2013 -0700
+
+    altos: Explicitly list the linker script needed for AVR targets.
+    
+    Something changed in the binutils-avr package which makes the linker
+    fail to find the script in the default location.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 203951f6e049ec7e95489849a2bfaa01aa19c0c9
+Merge: 4babe73 b363a62
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Aug 25 22:00:27 2013 -0700
+
+    Merge branch 'master' into telegps-v0.3
+
+commit b363a628fc6137c3395a48ef13de7a799ec3e2c3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 22 19:31:15 2013 -0600
+
+    altos: MS5607 pressure computation for low temperatures was wrong
+    
+    Second correction only applies to temps < -15°C, not 15°C.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit aa2948803d33dbee6f1eab30370178252df2b56d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 17:45:06 2013 +0200
+
+    altos: Wake up on LPC usart ISR only once
+    
+    Instead of waking up after every character, wait until the FIFO is
+    empty to reduce overhead
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 10f88c46df9a266f62452dc25275c79a3bb0653d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 17:43:18 2013 +0200
+
+    altos: Set default LPC stack to 512 bytes, Em to 384 bytes
+    
+    The default for lpc has been raised to 512 bytes, but Em doesn't have
+    enough RAM for that.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 41428d1e1e44a17eea5fda2b34cabafbdebf1464
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 17:35:08 2013 +0200
+
+    altosdroid: Add note to report TeleBT battery level
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e908eb090fc2aaa03b35dc37c3e008b05ad44d80
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Aug 23 11:24:18 2013 -0700
+
+    altos: Use installed arm compiler for LPC
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1aed2eb5c7d477a2f3d4fada22980041aba97cb8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Aug 23 11:22:10 2013 -0700
+
+    altos/lpc: Stop using burst mode for LPC ADC
+    
+    Burst mode doesn't stop after one round of conversions, so we end up
+    getting incorrect values in whatever the last conversion register is.
+    
+    Just use single conversions and take an interrupt per channel.
+    
+    Also, slow down the ADC so that our values are more stable -- just
+    need to make sure we get the whole conversion sequence done 100 times
+    a second.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4babe7310f78338ca36ab9d31ac833eada27485f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 24 23:22:18 2013 -0700
+
+    altos: Allow products to disable RDF entirely
+    
+    TeleGPS doesn't ever want RDF
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a1ec15f4585e23eb67affbe7d9d97261576b198d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 24 23:21:53 2013 -0700
+
+    altos: Add telegps v0.3 product
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e2f385946132690ca6dc141d7c7830ae0cfe3458
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Aug 20 08:54:44 2013 -0700
+
+    altos: various cc115l driver hacks
+    
+    Try to recover from TX_FIFO_UNDERFLOW by resetting the chip at idle
+    time.
+    
+    Do a calibration phase during setup.
+    
+    Program power to ramp up to limit key down noise.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0dd55f66d79f54b450fd8122aecd84d68b810bf4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 17:45:06 2013 +0200
+
+    altos: Wake up on LPC usart ISR only once
+    
+    Instead of waking up after every character, wait until the FIFO is
+    empty to reduce overhead
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a0dd93ccf0920260b41c4003955617fd0cd1c8b4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 17:43:18 2013 +0200
+
+    altos: Set default LPC stack to 512 bytes, Em to 384 bytes
+    
+    The default for lpc has been raised to 512 bytes, but Em doesn't have
+    enough RAM for that.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9a22a300009679a14d66214a5d61e9e6a177279f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 17:40:33 2013 +0200
+
+    altos: Allow ublox to run at other baud rates
+    
+    Provides a configuration option to set the ublox serial baud rate to
+    something other than 57600 baud
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e0a0a747624c2df66ca4a73b5a0de014ea204dca
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 17:36:35 2013 +0200
+
+    altos: allow projects to override default config values
+    
+    Override default radio power and APRS interval
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bed68ef5a6999b2e23853958502a689a7dbc15b3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 17:35:08 2013 +0200
+
+    altosdroid: Add note to report TeleBT battery level
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f0e126251360f050b7121f167771c057bda8747e
+Merge: d95a2c5 4fe47ad
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 17:33:31 2013 +0200
+
+    Merge branch 'master' into telegps-v0.3
+
+commit 4fe47adc7aca54951a50b1c1ae95cb02e46f8d3d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 17:30:52 2013 +0200
+
+    altosui: AltosDbm class was missing somehow
+    
+    This doesn't appear to have been added?
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4ff54bb96f6c00c0c2c7dd32f81403bac331621a
+Merge: fa0859a 01f8df0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 16:03:26 2013 +0200
+
+    Merge remote-tracking branch 'origin/master'
+
+commit fa0859a51576efe231effcb5995f325f9e7e0fcb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Aug 17 16:01:44 2013 +0200
+
+    altos: Make FAT test program link explicitly against libcrypto
+    
+    For some reason, the MD5_Final symbol isn't resolved when linking only
+    against libssl.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 01f8df088759ee7e6bc3900a013e0ea4fafaf984
+Merge: e2ebe60 15063cb
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Jul 30 00:15:06 2013 -0600
+
+    Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit e2ebe60adf061479a1259a5c68b9cd5f5bacf644
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Tue Jul 30 00:14:41 2013 -0600
+
+    add a note about callsign matching and case sensitivity to the manual
+
+commit d95a2c5d1ddce913dcb1d1ab5dc59f6a588ab599
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 24 14:29:43 2013 -0700
+
+    altos: Remove ao_radio_gpio_bits from normal build
+    
+    Only needed for the CC115L_TRACE code, and it only builds on STM
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c542a2ed0f222bd0ec84e4a9651585d441dd7ccf
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 24 14:29:01 2013 -0700
+
+    altos/lpc: Rename serial port to 'serial0'
+    
+    This lets existing serial port users find the right function.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 324ceea43c115f4bed3a5276e57559c6c76b07c1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jul 2 17:54:38 2013 -0700
+
+    micropeak: Add Download button to menu bar
+    
+    It's the most common activity, after all
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 156e60954fae15bc090984f79cd5594f910ca913
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jul 2 17:53:51 2013 -0700
+
+    altosdroid: Just use GPS location provider to build on 4.2
+    
+    Attempts to use the network provider cause the app to crash
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e148582217d6e02ac90a68e2bb2532947378d36f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 24 14:28:06 2013 -0700
+
+    altos: Support mega-style logging without ADC
+    
+    Used for TeleGPS, just exposes the necessary log writing function
+    without also including the ADC writing code.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 261ec8fc7043e9314469e919aa96acc461f7e5f2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 24 14:26:23 2013 -0700
+
+    altosui: Add EasyMini USB ids
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0dd148e388944d8d265da51d62806c4a00b2c13d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 24 14:23:53 2013 -0700
+
+    altos/lpc: Add boot loader
+    
+    Support the USB boot loader, add USB pull-up support.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2568b36ae9d38ae1607ec08b84b06e0fe84bd3ba
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 22 00:53:38 2013 -0700
+
+    altos/telefire-v0.1: Use same LED selection as the v0.2 setup
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 58eda6f873f5d6e8e219f769bdf67ce4dbc96fd7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 21 19:40:59 2013 -0700
+
+    altos/lpc: Don't disable all interrupts when disabling one interrupt
+    
+    The nvic iser and icer registers read value indicates all enabled
+    interrupts, icer writes disable the set interrupts. Re-writing icer
+    with the current value ends up disabling all interrupts, not exactly
+    what we wanted.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9081d881bc48bf7fdce617d300ac02c1a5962239
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 21 19:40:03 2013 -0700
+
+    altos/lpc: Remove ao_usb_task structure
+    
+    It's not used
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 23f11b188fc6aacd29e7f01a7d8a40853b7655df
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 21 19:39:27 2013 -0700
+
+    altos/lpc: Enable brown-out-detector
+    
+    Make sure the processor does something sensible when the power disappears.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e9e713bc8ab2080d5c1c38570b112f13c886bd11
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 19 22:45:54 2013 -0700
+
+    altos/telefire: Radio status (no data, weak data, good data) on LEDs
+    
+    Instead of blinking RX/TX, report the radio status on the telefire
+    nodes, just like telelco does. This makes the LEDs on telefire
+    *exactly the same* as the LEDs on telelco, which seems like a good idea.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d90c2fa650de4cdb008d5e2559463c08da8db934
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 19 22:44:16 2013 -0700
+
+    altos: PCA9922 LED driver needs Enable driven low to latch values
+    
+    Driving Enable high means anything going past on the clock and data
+    pair is reflected on the LEDs, which isn't terribly useful
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 572faa19b9a496866e3b589d5eb9f37a680206ab
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 19 22:42:58 2013 -0700
+
+    altos/cc1111: Fetch RSSI for TeleFire from correct byte
+    
+    Reading the status byte doesn't provide very useful RSSI info
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 025beb0fea011d0e3dab59b5d16e7ffae97c613c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 17 14:52:32 2013 -0700
+
+    altos/lpc: Get rid of ADC filter
+    
+    Now that the source of the Vcc noise has been identified, remove the
+    unnecessary ADC filtering.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 10f3d0084ff1c0b3dbf28c5d44727b514caeee20
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 17 14:00:43 2013 -0700
+
+    altosui: Add raw pressure to the AltosUI graph
+    
+    A nice addition, and useful when diagnosing baro sensor issues
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 298e54856b5f8809b43f24407caa4a6be60822f3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 17 14:00:11 2013 -0700
+
+    altos/lpc: Get the IRC turned off after boot time
+    
+    This involved carefully moving the USB away from the IRC before
+    turning it off.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b3ad488477def157e277e239e81f164b49725925
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 17 13:58:41 2013 -0700
+
+    altos: Disable USB on all flight computers when in flight mode
+    
+    There was a check to only disable USB on boards with radios, but for
+    EasyMini, we want to disable USB too for flight mode.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2e2f3f2556e714833d8b7d0f65877b07b3dc2cb5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 16 22:32:16 2013 -0700
+
+    altos: Declare m25 write-in-progress as 'ao_port_t'
+    
+    This lets us use port bits greater than 7 for M25 chip selects
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dcf769198863c1b0f1b05f41d0c052a3dbfef247
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 16 22:31:58 2013 -0700
+
+    altos/lpc: Remove spurious semicolon
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d040adeef9df4cda31dce603db81dc7ce19ec0d1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 16 22:31:31 2013 -0700
+
+    altos/lpc: Don't disable all of the clocks just yet, USB doesn't work
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1676c7dbc3dcce2962be9ef9a58d37c7b48e3c0f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 16 15:07:54 2013 -0700
+
+    altos/lpc: Turn off more clocks, disable USART for easymini
+    
+    Try to reduce noise on the power supply.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit be9ee9ed2d041c4ab4e77ee2010fe3c7a1ca6597
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 15 01:20:49 2013 -0700
+
+    altos/lpc: Filter ADC inputs
+    
+    They're amazingly noisy on EasyMini, so just filter them as the only
+    thing we use them for is battery and pyro numbers.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7361371190bf3805b6d0414e61f697aca7c7cff1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 14 04:38:11 2013 -0700
+
+    altos/lpc: Make ADC inputs work
+    
+    They're still very unstable (bouncing around a lot), but at least they
+    seem to report useful stuff now.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6827d0a7c59d606ea05387465f1ad4d914babd49
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 11 16:31:20 2013 -0700
+
+    altosui: Use preferred units for main deployment height configuration
+    
+    Show and accept values in the preferred units; create a separate list
+    of preferred values for each set of units
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 15063cbb8f76bffea71575d295ca87b7ceca36d8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 9 23:18:09 2013 -0700
+
+    altos/telelco: Add 30ms delay in search after finding a box
+    
+    This gives the remote boxes time to get back to listening for messages
+    after receiving the packet from the found box.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 988924b51980ad43e39bc4785a625ff25eb16449
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 9 22:09:13 2013 -0700
+
+    altos: Add fast-timer API. Use for quadrature and button drivers
+    
+    This splits the fast-timer portion out of the debounce helper code and
+    shares that with the quadrature driver which now uses it directly.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 72b6c699d355fcd41addb9919d846e63105b9db7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 13 22:34:19 2013 -0700
+
+    altos: Add debounce helper. Use in button and quadrature drivers for TeleLCO
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 47b7e1d819e48aaebf6ffda49effbee041ce8750
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 9 12:13:06 2013 -0700
+
+    altos/telefire: Leave siren on all the time. Add siren/strobe debugging.
+    
+    The 50% duty cycle wasn't actually loud enough outside.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 187f661c2512e4260d0ca64134de8fad199f5944
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 9 10:00:54 2013 -0700
+
+    altos: Add telefire v0.2 support
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8ba2035c78293bc312804722249df76dd4692d71
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 9 09:53:07 2013 -0700
+
+    altos: Add driver for 74hc165 shift register
+    
+    Just reads one byte from the shift register using the SPI driver and returns it
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3e8b72a9dc5b6c3a0f6132dc2dec04f8c08a1deb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 22:38:56 2013 -0600
+
+    altos: Add pyro operations to regular ignite commands
+    
+    Instead of having separate commands, just mix the two sets together.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4bc1f3390b9ebbe07af4bc0f0a1c0915193ddf42
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 19:41:22 2013 -0600
+
+    Set version to 1.2.9.1
+    
+    Mark bits to be used on Monday of NSL 2013
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6f131e740477d29b6623fa336da79e53f765a55b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 19:48:03 2013 -0600
+
+    altos: Make manual pyro firing command work again
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5ca472333a3587f0e47d54f5edc287494262ef98
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 19:47:02 2013 -0600
+
+    altos: write pyro fired to correct log field
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 956f4dff1cc521059434743624b1271fb92b96ae
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 19:39:13 2013 -0600
+
+    altos: Light pyro charges simultaneously if so configured
+    
+    Don't try to be nice to the battery, just let the pyro circuit deal
+    with it and try to get all of the specified circuits going at the same
+    time if they're configured to do so.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 62547a042d042fadec652c5081f96816a8e66970
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 19:03:12 2013 -0600
+
+    altos,altosui: Add pyro state logging for TeleMega
+    
+    Only in the log file (no obvious space in the telem packets), but at
+    least we should be able to check for pyro failures.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 277577fecc71e3c52b823938f396cf42be403ebe
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 19:01:58 2013 -0600
+
+    altos: Add pyro code testing to ao_flight_test for TeleMega
+    
+    This parses the pyro settings and signals when the pyro channels are
+    fired in the output.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b1408c13f176f3f021e9face48c4cd33528ee96c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 18:58:41 2013 -0600
+
+    ao-tools/ao-mega: Dump 'pyro' state from mega log
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8083aa731c99d09bdd4a8c216bb11f846734d7df
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 18:57:58 2013 -0600
+
+    ao-tools: Add ao-mega tool to parse TeleMega eeprom files
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 21689ef744ddf43965ccad89dc1133a905011d7f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 18:54:02 2013 -0600
+
+    altosui: Missing 'break' after selecting 'mega' format detection
+    
+    Caused 'mega' logs to be dumped in 'mini' format which didn't work well.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 17e0ccccc8619f96d2cf56bd98d63a7e59f5301d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 26 18:50:10 2013 -0600
+
+    altosui: Stop downloading mega eeprom on empty block
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 013cba5ed1fde72240a68ec648bd14977f5e48a4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 20 21:41:01 2013 -0700
+
+    doc: Update description of graph window to note new tabs (config and map)
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e711c708b0d2c8d8c2d72e34a795ad8e9b5ab5de
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 20 21:37:20 2013 -0700
+
+    Create release notes for 1.2.1
+    
+    Move most of the 1.2 content to the 1.2.1 block
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2344ba81fa51215471099e56518112478bdf2e73
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 21 11:31:05 2013 -0700
+
+    Separate out cortex-m0 compiler tests in configure
+    
+    The summon arm toolchain doesn't work for cortex-m0 parts, but the
+    linaro toolchain does. Look in /usr/bin for the -m0 compiler but
+    continue to use /opt/cortex/bin for the -m3 compiler
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 85eb75c3251d8e141d7269fc7ffa6197174ea8c3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 21 11:30:44 2013 -0700
+
+    altos: Can't use inline functions because SDCC doesn't do that
+    
+    Sigh.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fd5567882b732f8947b44b217552077c82a3d28e
+Merge: fd55c1f 57b4d82
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 21 11:16:54 2013 -0700
+
+    Merge branch 'lpc'
+
+commit fd55c1fe53adf5c50dcd3ce8296f80871cec73e9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 21 11:16:33 2013 -0700
+
+    Bump master version to 1.2.9 to avoid confusion with 1.2 releases
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1bffe8caf0294e9cfef2dab1c6b5a8d1d87ac3a2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 21 11:08:15 2013 -0700
+
+    altos: Set the path for the STM32L compiler explicitly
+    
+    This makes sure we use the known toolchain for STM32L builds
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7282fab337dc48d32606276e5f51c057a3bff8cb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 21 11:04:25 2013 -0700
+
+    altosui: Add TeleBT firmware to release
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 57b4d82dee10b142b820aa306028a288a85214f6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 23:07:54 2013 -0700
+
+    Add Mini logging format. Use in EasyMini
+    
+    This is a 16-byte record that includes all of the sensor data in each
+    sensor record, along with records for flight state changes.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 27e9b93f3d35890a49575b2ead1983ce3c2fc213
+Merge: a4df257 d9cbef8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:40:42 2013 -0700
+
+    Merge branch 'master' into lpc
+
+commit d9cbef8cd364aae54855cc5bc64fb8c2b22057b0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:35:42 2013 -0700
+
+    altos/telemega: The last two igniters are apogee and main
+    
+    Not the first two. TeleMega v0.3 has these marked on the silk
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a4df2575b4e782e83cc4e9b1d2e5cd2397a97dd8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:33:35 2013 -0700
+
+    altos/easymini: Initialize beep and ADC. Declare use of igniter bits.
+    
+    This makes easymini actually work!
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a87a8e8067d7b2d0ff3a3274af9f1e919b5b7793
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:32:34 2013 -0700
+
+    altos/easymini: Use different pins for igniter outputs
+    
+    Was using the I2C outputs which are open drain, which makes it
+    impossible to force them high as needed to driver our igniters.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 16eb0b04df3d1db65bd40717133abe94db0f2a15
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:31:48 2013 -0700
+
+    altos/easymini: MS5607 chip select bits were defined wrong
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 455802b7e853956180799c058e9561876d98d831
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:30:49 2013 -0700
+
+    altos/easymini: Easymini doesn't have USB connect or VBUS wiring
+    
+    Disable these in ao_pins.h
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 35b120c4154df0351c3a802f86dda224a7643068
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:27:53 2013 -0700
+
+    altos/lpc: Force idle mode if USB gets an address during boot time
+    
+    This lets EasyMini be booted to idle mode by simply plugging it into USB.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c1f01cd4406063191a51cb68fc4634eabfc60fc2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:27:05 2013 -0700
+
+    altos/lpc: Reset SPI device at startup time
+    
+    Wasn't doing the reset sequence correctly (write 0, then write 1).
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e0ad8b5b5e1b4c7a9ffba9d25f3c32ce708c3ec5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:26:07 2013 -0700
+
+    altos/lpc: Configuring wrong pin for SPI1 MOSI
+    
+    Was setting configuration for PIO1_21 instead of PIO0_21.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b9bb088a36fd351809f4c378356327ffa663c974
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:25:13 2013 -0700
+
+    altos/lpc: Allow for alternate SPI SCLK0 pin usage
+    
+    SPI SCLK0 can appear on three different pins; let the application
+    configure which one it wants.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 397109139fb9ff27ec7cfb0cafa65d1dbea053bd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:24:11 2013 -0700
+
+    altos/lpc: Leave SPI enabled all the time
+    
+    Might be able to turn it off with some care; more experimentation required.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e383d7a28d01729c50f933ceda77ea767d1b8087
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:22:20 2013 -0700
+
+    altos/lpc: Create TX/RX busy macros for SPI driver
+    
+    Check for both fifo status *and* device busy to make sure the device
+    is idle before we touch any registers.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 07d261c08214837b5d5cac4d2be43e51a0c47868
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:19:15 2013 -0700
+
+    altos/lpc: Fix beeper driver
+    
+    Set prescale limit, not current prescale value (pr instead of pc).
+    Flip output 1 on PWM match (set emc toggle for channel 1).
+    Don't hold counter in reset (turn off CRST bit).
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3fe11b277dd7268eb445d120c8f9537f95148891
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:18:44 2013 -0700
+
+    altos/lpc: Missing parens around ao_gpio_set macro
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a78012782c779de3433b91e6b854b2fdbd7230fd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:17:48 2013 -0700
+
+    altos/lpc: SPI runs off main clock (48MHz), not sysclk (24MHz)
+    
+    Update SPI speed definitions to match
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d51c9fda3478f205e4bcdf1b7bf21eb1e0a516bc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:07:52 2013 -0700
+
+    altos/lpc: Pull ADC data from the correct registers
+    
+    Was just stepping through register space arbitrarily, which would have
+    worked for EasyMini, but might have failed later if the ADC pin usage
+    wasn't consecutive.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
 
-    Merge branch 'branch-1.2' of ssh://git.gag.com/scm/git/fw/altos into branch-1.2
+commit 6343bd774f542a4f915cf1fca2053d03e93bf2c3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:06:03 2013 -0700
 
-commit 9b138221283f0b8e8df5a799f75d73fd456028a0
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Tue May 21 09:29:30 2013 -0600
+    altos/lpc: Don't use loader to place USB endpoint data in USB ram
+    
+    Instead, just assign a fixed address in registers.ld. This avoids a
+    confusing section in the elf file.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
 
-    update changelog for 1.2.1 release
+commit 35a05041d3ca3e69a146bd3bf8038c0f1cbc1b42
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:04:29 2013 -0700
 
-commit 6f51726b1c04940c5be3b6f320d6aa529afff9ca
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Tue May 21 09:28:53 2013 -0600
+    altos: Add EXTI_PIN_NOCONFIGURE to exti interface, use for MS5607
+    
+    This asks the EXTI code to not mess with the pin configuration so that
+    the MS5607 driver can get interrupts on the MISO pin while still using
+    it for SPI.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 098fd43a740ee2a782f82b6b71965b60cdba2d62
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 19 20:00:24 2013 -0700
 
-    update configure.ac to reflect version 1.2.1
+    altos/lpc: Make EXTI code work.
+    
+    Clear rise/fall bits in ISR to avoid re-entering.
+    Block interrupts around enable/disable bits.
+    Create shared _ao_exti_set_enable function to control mask changes.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit 03fe10efd307da10e35c5f6a46f0c8b1a3888c57
+commit f794e6c95697b034be315632fddb3a5475c43b5b
 Author: Keith Packard <keithp@keithp.com>
-Date:   Mon May 20 21:41:01 2013 -0700
+Date:   Sun May 19 19:57:23 2013 -0700
 
-    doc: Update description of graph window to note new tabs (config and map)
+    altos: Use ao_spi_get/put_bit in MS5607 driver
+    
+    Replace open-coded ao_spi_get/put and ao_gpio_set sequences
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit db9ea188aebe5299f46bbd4fca5317c1bc95f3f5
+commit b7ab41e4dc92dcd382f4c05459088d8df8b70075
 Author: Keith Packard <keithp@keithp.com>
-Date:   Mon May 20 21:37:20 2013 -0700
+Date:   Sun May 19 19:51:32 2013 -0700
 
-    Create release notes for 1.2.1
+    altos/attiny: Fix ao_spi_get_bit/ao_spi_put_bit macros
     
-    Move most of the 1.2 content to the 1.2.1 block
+    These were never written, so just use ao_spi_get/put_mask.
+    
+    A precursor to changing how the MS5607 drives the SPI bus
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit 51f2c4ce2692ee3e898b4e94232c45a608932c15
+commit 49f9cdda5f1812687b82915acc78a9d9136255bf
 Author: Keith Packard <keithp@keithp.com>
-Date:   Sun May 19 20:35:42 2013 -0700
+Date:   Sat May 18 03:54:30 2013 -0700
 
-    altos/telemega: The last two igniters are apogee and main
+    altos: ignore built files in easymini-v0.1
     
-    Not the first two. TeleMega v0.3 has these marked on the silk
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c57e1630002c921739ff22395497d93027d381b6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:53:32 2013 -0700
+
+    altos: Build easymini-v0.1
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit 8d40c37bae0c58037f267e54de40071cd19c931d
+commit 278300b2bc98b92cc71ec016ab0fc93eb3696435
 Author: Keith Packard <keithp@keithp.com>
-Date:   Fri May 17 03:27:20 2013 -0700
+Date:   Sat May 18 03:52:59 2013 -0700
 
-    libaltos: Build the linux library targets when doing a 'fat' build
+    altos: Initialize SPI for easymini
     
-    These are necessary for the fat release, so make sure they're built then.
+    Doesn't work very well without this
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cbe5eee76faf386eefe69539935ab318944ac452
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:52:14 2013 -0700
+
+    altos/lpc: Stick USB control structure in USB memory
+    
+    No reason to have that in regular ram, and it means we've got space
+    for large enough stacks now
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3587bfd248e115bb1abb28f71b263575b4e8e367
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:22:10 2013 -0700
+
+    altos: Add easymini-v0.1 product
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c4991db4809ae547fdb245e3cb42517fa7524de5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:21:43 2013 -0700
+
+    altos/lpc: Use separate interrupt stack
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5311720525ac73e9d42067b68adf25fc2e054af5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:21:20 2013 -0700
+
+    altos/lpc: Try a smaller stack.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f5218e2544dcb659aec6c3adee50d61cab1bba3a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:19:41 2013 -0700
+
+    altos/lpc: Add pin interrupt driver
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c0d0147251bfcebd753196b74c22c00c3116fd22
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:18:55 2013 -0700
+
+    altos/lpc: Add beep driver
+    
+    Hardwired to our current beeper pin
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 166977c65bddb50d600a3c1e1f278c425b673697
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:18:19 2013 -0700
+
+    altos/lpc: Add ADC driver
+    
+    Uses burst mode to get the whole set of values in one interrupt
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ed25a46571d988ccf37ae915dff97b5f00bcf9cf
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:16:41 2013 -0700
+
+    altos/lpc: add gpio int, spi, adc and ct32b defines to lpc.h
+    
+    Lots more devices
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2b0b7bf1462341718e582223a880f2dfcd79e2ad
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:15:58 2013 -0700
+
+    altos/lpc: Clean up broken IOCONF defines
+    
+    Missing comment closes
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 08887678f900adae81dcb1a7f5353d98d127aafd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:14:57 2013 -0700
+
+    altos/lpc: Fix ao_enable_input, add ao_enable_analog
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 15ca452b60271e3a0f7327216df04eef5b985240
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:14:16 2013 -0700
+
+    altos: LPC interrupt priorities are just 0-3
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 935a7ff38010ec4ad19f315f8a2a1557c01ae554
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:13:17 2013 -0700
+
+    altos: Add LPC spi driver
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d9b42470e8889b44bb08858a610285410a200ab9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:02:38 2013 -0700
+
+    altos: Use ao_port_t in m25 driver
+    
+    This uses ao_port_t for all of the chip select masks
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 28890aa5893898cd0bb0ac033e491eb307a84ca5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 03:02:01 2013 -0700
+
+    altos: Use ao_data_pres macro in ao_log_tiny
+    
+    Now it works on easymini too
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 82afe3a3b737c43dbeaad41ea5af1841357297a6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 02:54:55 2013 -0700
+
+    altos: Check for packet mode before trying to disable it in flight code
+    
+    This is only relevant for telemini
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 52063c2679752033135fff928c7686e368d2a825
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 02:54:30 2013 -0700
+
+    altos: ao_data_get is in ao_data.c now, not ao_adc.c
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e4385d29fc1b233b3ad56d4af68a175e760c1751
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 02:53:32 2013 -0700
+
+    altos: Allow architecture to define the type of port registers
+    
+    LPC11U14 has 32-bit ports, STM32 has 16 bit ports.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ca4f3161258356c06fe1270f7ccdf0d6939e2d34
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 18 02:52:49 2013 -0700
+
+    altos: Move ao_data.c from stm to core
+    
+    This should be used on every processor
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ac089d4fb930b7dbc4161259fd9bddba94395ebc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri May 17 03:36:47 2013 -0700
+
+    altos/lpc: Get USB working
+    
+    The lpc demo now has a USB command line.
+    Also allocates system stack so we know when ram is tight at build time
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 185e6d15bcda229949a984910d7394203d301db9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 16 18:58:24 2013 -0700
+
+    altos: Allow target-specific USB endpoint specifications
+    
+    The LPC has only a small number of endpoints, and those are not
+    configurable. Let the LPC USB driver pick the IN and OUT endpoints by itself.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6c35e21a86ab32bc91eb10a60c071b702fc0f963
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 7 19:27:17 2013 -0700
+
+    altos: Finish off LPC USB register definitions
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 918342016705303baa1630c62c290aaf2dcc2801
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Apr 25 20:38:32 2013 -0700
+
+    altos/lpc: Start adding USB register defines
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 91d201abcbe9373360919406427b7e4fb9e1b42e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Apr 22 17:10:24 2013 -0500
+
+    altos/lpc: Start adding USB register definitions
+    
+    Just the bare struct, no defines yet.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9bf67798b134ad796c2f4bc9240ee450722148ec
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 20 00:40:38 2013 -0500
+
+    altos/lpc: Take advantage of USART TX fifo
+    
+    The USART has a 16-byte TX fifo; keep rough track of how full it is to
+    avoid waiting for an interrupt after every TX byte.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9e8f6ba8b779cd9635f82d6da5f113715c3ee4c7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 20 00:20:55 2013 -0500
+
+    altos/lpc: Get USART running
+    
+    Adds a simple demo thread that spews data to the serial port
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f9d0eb3f3154f98abb0c8952d7171f3e7d3de9b2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Apr 18 16:15:52 2013 -0500
+
+    altos/lpc: Get 100Hz timer running
+    
+    Use systick, which is built into the ARM core
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 04b243e6ef212f54ed284cfbde6d5abb637bf60e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Apr 18 15:55:26 2013 -0500
+
+    lpcxpresso: Add ao_demo.c
+    
+    Kinda necessary for the demo to build
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bcc65597d3d20f1d58df784100af766cee5f0f20
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Apr 18 15:54:13 2013 -0500
+
+    lpc: Initial lpcxpresso bits
+    
+    This gets the LPC11U14 clock set to the PLL and blinks the LED.
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit fbe7857e371fa8ffa726fda2b43d4eddd551eaa4
+commit 6735a391c2a1e3be01ac9e68b44ec0974592c11c
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri May 17 03:34:50 2013 -0700
 
@@ -67,7 +3996,17 @@ Date:   Fri May 17 03:34:50 2013 -0700
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit 3b457ff8d43630c04e0cb22bb3a2765be5e188bd
+commit bd8d061d0f63158b5b03814d77cb76fdf5a0abad
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri May 17 03:27:20 2013 -0700
+
+    libaltos: Build the linux library targets when doing a 'fat' build
+    
+    These are necessary for the fat release, so make sure they're built then.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8a19805a6b079450b5afd5fa2334cede8495ae4a
 Author: Keith Packard <keithp@keithp.com>
 Date:   Fri May 17 03:21:08 2013 -0700
 
@@ -124,11 +4063,107 @@ Date:   Fri May 17 03:21:08 2013 -0700
     
     Signed-off-by: Keith Packard <keithp@keithp.com>
 
-commit 7699a55aed3a9a7daeb4c6a5a9a280f43edf455f
-Author: Bdale Garbee <bdale@gag.com>
-Date:   Thu May 16 00:34:26 2013 -0600
+commit 4ef0136c27e8f47a1eb38f9cbcd2c61288732d78
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 15 15:32:59 2013 -0700
+
+    altos: Generate unmodulated carrier for CC1120 test mode
+    
+    This sets the deviation to 0, enables the preamble and turns on the
+    transmitter. It will sit there happily sending a bare carrier forever
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1931e028bebc3cd8df9392e30eb0e888d0799768
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 14 22:29:06 2013 -0700
+
+    altos: Move MS5607 info from 'v' to 'c s'
+    
+    Makes more sense there.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 69b9f613ad36b8039f223ed30f8c75913916d82c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 14 22:19:07 2013 -0700
+
+    altos: Remove some MMA655x debugging printfs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0571531066918fdefe9447f3b4192d0c6c477afa
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 14 10:48:24 2013 -0700
+
+    altos: Grab SPI mutex until MPU6000 I2C mode is disabled
+    
+    If other drivers use the SPI bus, the MPU6000 gets confused as its
+    sitting on the bus looking for I2C messages. Just grab the mutex
+    before the OS is running and hold onto it until the MPU6000 has been initialized.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9beacd77b3e8106e036e50a67312dfee414fbc51
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 14 09:01:49 2013 -0700
+
+    altos: Initialize MPU6000 CS pin for SPI mode
+    
+    Without this, we can't talk to the chip very well
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6d553230903ddd0ec522c07be0df975b38ef23d3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 14 09:56:16 2013 -0700
+
+    altos: Fix telemega v0.3 igniter order (drogue/main moved). Label ADC dump
+    
+    telemega moves the igniters around so that E/F are now drogue/main.
+    Add custom labels for ADC values to make parsing possible
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a4e4eec827d61a05fda52ddb68b55f17b6028d5e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 14 09:25:08 2013 -0700
+
+    altos: gps serial routines are called ao_gps_*, not ao_ublox_*
+    
+    This caused the u-blox driver to use serial port 1 instead of the
+    project-specified serial port.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 461215eea72ff9d64748304e76b08da37ee3dfe9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 14 09:21:54 2013 -0700
+
+    altos: Give u-blox 3 seconds after boot before we bug it
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5e9193f6375be27e5f7a0321fd34b6acfe81247f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 14 09:12:29 2013 -0700
 
-    update ChangeLog for release
+    altos: Add 'g' command to ublox GPS code.
+    
+    Take the gps_dump function from ao_gps_skytraq.c and move it to a new
+    file so it can be shared with the u-blox driver. That affects every
+    skytraq and u-blox user as they need to include the new file.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cdad289a0803babecd30cbc0a95be99c5caadeb5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 15 01:24:56 2013 -0700
+
+    altos: Add flash-loader for telescience-v0.2
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+>>>>>>> branch-1.3
 
 commit 116d8570766fbd3ef529111171935637a2e466af
 Author: Keith Packard <keithp@keithp.com>
index bd7772e832cb8a8df89560863126beeacf6340c7..fa4da1fe65939473c1f2c9fe54b294d11a4180dc 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS=src doc altoslib libaltos altosuilib altosui micropeak ao-tools ao-utils altosdroid
+SUBDIRS=ao-tools src doc altoslib libaltos altosuilib altosui micropeak ao-utils altosdroid
 
 EXTRA_DIST = ChangeLog
 
index ce4df7c279c177522437c4935271b295492af436..1711779d69894b803f95b24842dfbf540a98c12e 100644 (file)
--- a/Releasing
+++ b/Releasing
@@ -1,7 +1,5 @@
 These are Bdale's notes on how to do a release.
 
-       - make sure there's a suitable ARM Cortex toolchain in /opt/cortex!
-
        git checkout master
 
        - make sure there is a doc/release-notes-<version>.xsl
@@ -12,7 +10,11 @@ These are Bdale's notes on how to do a release.
        - update the version in configure.ac
         git log > ChangeLog
        git commit -a
+
        - make absolutely sure checked-out tree is "clean" 
+       - make absolutely sure the pdclib/ submodule is on the master branch,
+         up to date, and "clean"
+
        - if this is an x.y release, then:
                git checkout -b branch-<version>
                git tag -a <version>
@@ -33,12 +35,12 @@ These are Bdale's notes on how to do a release.
         git commit -n debian/changelog -m "update changelog for Debian build"
 
        - if this is a -1 release, then
-               git-buildpackage --git-no-pristine-tar 
+               git-buildpackage --git-no-pristine-tar --git-submodules
                pristine-tar commit \
                        ../build-area/altos/altos_<version>.orig.tar.gz \
                        branch-<version>
          else if this is not a -1 release
-               git-buildpackage
+               git-buildpackage --git-submodules
 
        git tag debian/<version>
 
index 04a679e1574823cb1e8b02eab7f604af282f8969..06644fbb67b08ca09fa0f662c2bdb8e2df5d2672 100644 (file)
@@ -17,8 +17,8 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="org.altusmetrum.AltosDroid"
-          android:versionCode="3"
-          android:versionName="1.2">
+          android:versionCode="4"
+          android:versionName="1.3">
     <uses-sdk android:targetSdkVersion="10" android:minSdkVersion="10"/>
     <!-- Google Maps -->
     <uses-feature android:glEsVersion="0x00020000" android:required="true"/>
index b4ae2b7f51ef21ac73f8f36ebc9ba6da172d8223..ebb3578d0f4d4202db3390151338053e4f9bd868 100644 (file)
@@ -28,3 +28,5 @@ Desired AltosDroid feature list
     'find my rocket' mode after shutting down the application.
 
  *) Imperial Units mode
+
+ *) TeleBT battery voltage
index 0aea06f1cf22a242cf89489768070522caafdf15..643e94f5fa3f8802fef2b7985c058d4dd2deec0c 100644 (file)
@@ -31,7 +31,7 @@ import android.os.Handler;
 //import android.os.Message;
 import android.util.Log;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosBluetooth extends AltosLink {
 
@@ -162,6 +162,20 @@ public class AltosBluetooth extends AltosLink {
                }
        }
 
+       public void putchar(byte c) {
+               byte[] bytes = { c };
+               if (D) Log.d(TAG, "print(): begin");
+               try {
+                       wait_connected();
+                       output.write(bytes);
+                       if (D) Log.d(TAG, "print(): Wrote byte: '" + c + "'");
+               } catch (IOException e) {
+                       connection_lost();
+               } catch (InterruptedException e) {
+                       connection_lost();
+               }
+       }               
+
        public int getchar() {
                try {
                        wait_connected();
index e10982f7cc8873832c99fa21e2937c260deab64f..92287476b7dbf56fc654c408e5ddeb8c5ba41fd4 100644 (file)
@@ -49,7 +49,7 @@ import android.widget.Toast;
 import android.app.AlertDialog;
 import android.location.Location;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosDroid extends FragmentActivity {
        // Debugging
@@ -147,7 +147,7 @@ public class AltosDroid extends FragmentActivity {
                        case MSG_CRC_ERROR:
                        case MSG_UPDATE_AGE:
                                if (ad.saved_state != null) {
-                                       ad.mAgeView.setText(String.format("%d", (System.currentTimeMillis() - ad.saved_state.report_time + 500) / 1000));
+                                       ad.mAgeView.setText(String.format("%d", (System.currentTimeMillis() - ad.saved_state.received_time + 500) / 1000));
                                }
                                break;
                        }
@@ -243,11 +243,11 @@ public class AltosDroid extends FragmentActivity {
                }
 
                if (state != null) {
-                       mCallsignView.setText(state.data.callsign);
-                       mSerialView.setText(String.format("%d", state.data.serial));
-                       mFlightView.setText(String.format("%d", state.data.flight));
-                       mStateView.setText(state.data.state());
-                       mRSSIView.setText(String.format("%d", state.data.rssi));
+                       mCallsignView.setText(state.callsign);
+                       mSerialView.setText(String.format("%d", state.serial));
+                       mFlightView.setText(String.format("%d", state.flight));
+                       mStateView.setText(state.state_name());
+                       mRSSIView.setText(String.format("%d", state.rssi));
                }
 
                for (AltosDroidTab mTab : mTabs)
@@ -266,7 +266,7 @@ public class AltosDroid extends FragmentActivity {
 
        static String pos(double p, String pos, String neg) {
                String  h = pos;
-               if (p == AltosRecord.MISSING)
+               if (p == AltosLib.MISSING)
                        return "";
                if (p < 0) {
                        h = neg;
@@ -278,13 +278,13 @@ public class AltosDroid extends FragmentActivity {
        }
 
        static String number(String format, double value) {
-               if (value == AltosRecord.MISSING)
+               if (value == AltosLib.MISSING)
                        return "";
                return String.format(format, value);
        }
 
        static String integer(String format, int value) {
-               if (value == AltosRecord.MISSING)
+               if (value == AltosLib.MISSING)
                        return "";
                return String.format(format, value);
        }
index fd4b0768ac33f8d60e55946be7f0d6bb1ad39d09..59fef84279d6c2b6985f9d192e05fd69e894dd48 100644 (file)
@@ -23,7 +23,7 @@ import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Environment;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosDroidPreferences implements AltosPreferencesBackend {
        public final static String        NAME    = "org.altusmetrum.AltosDroid";
index 6ebb47f74e3b1ff9f3218f5655c5e1d43d6e2237..c652a1694f24b62df27f2ca829f0868ac79b0265 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import android.location.Location;
 
 public interface AltosDroidTab {
index b3dba62693714403f95f0b312beeb890f6e88b1a..f17cb82171e2f54e34eca4cd799677a95bdc1d2c 100644 (file)
-/*\r
- * Copyright © 2011 Keith Packard <keithp@keithp.com>\r
- * Copyright © 2012 Mike Beattie <mike@ethernal.org>\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; version 2 of the License.\r
- *\r
- * This program is distributed in the hope that it will be useful, but\r
- * WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License along\r
- * with this program; if not, write to the Free Software Foundation, Inc.,\r
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.\r
- */\r
-\r
-package org.altusmetrum.AltosDroid;\r
-\r
-import android.speech.tts.TextToSpeech;\r
-import android.speech.tts.TextToSpeech.OnInitListener;\r
-\r
-import org.altusmetrum.altoslib_1.*;\r
-\r
-public class AltosVoice {\r
-\r
-       private TextToSpeech tts         = null;\r
-       private boolean      tts_enabled = false;\r
-\r
-       private IdleThread   idle_thread = null;\r
-\r
-       private AltosState   old_state   = null;\r
-\r
-       public AltosVoice(AltosDroid a) {\r
-\r
-               tts = new TextToSpeech(a, new OnInitListener() {\r
-                       public void onInit(int status) {\r
-                               if (status == TextToSpeech.SUCCESS) tts_enabled = true;\r
-                               if (tts_enabled) {\r
-                                       idle_thread = new IdleThread();\r
-                               }\r
-                       }\r
-               });\r
-\r
-       }\r
-\r
-       public void speak(String s) {\r
-               if (!tts_enabled) return;\r
-               tts.speak(s, TextToSpeech.QUEUE_ADD, null);\r
-       }\r
-\r
-       public void stop() {\r
-               if (tts != null) tts.shutdown();\r
-               if (idle_thread != null) {\r
-                       idle_thread.interrupt();\r
-                       idle_thread = null;\r
-               }\r
-       }\r
-\r
-       public void tell(AltosState state) {\r
-               if (!tts_enabled) return;\r
-\r
-               boolean spoke = false;\r
-               if (old_state == null || old_state.state != state.state) {\r
-                       speak(state.data.state());\r
-                       if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) &&\r
-                           state.state > AltosLib.ao_flight_boost) {\r
-                               speak(String.format("max speed: %d meters per second.", (int) (state.max_speed() + 0.5)));\r
-                               spoke = true;\r
-                       } else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) &&\r
-                                  state.state >= AltosLib.ao_flight_drogue) {\r
-                               speak(String.format("max height: %d meters.", (int) (state.max_height + 0.5)));\r
-                               spoke = true;\r
-                       }\r
-               }\r
-               if (old_state == null || old_state.gps_ready != state.gps_ready) {\r
-                       if (state.gps_ready) {\r
-                               speak("GPS ready");\r
-                               spoke = true;\r
-                       } else if (old_state != null) {\r
-                               speak("GPS lost");\r
-                               spoke = true;\r
-                       }\r
-               }\r
-               old_state = state;\r
-               idle_thread.notice(state, spoke);\r
-       }\r
-\r
-\r
-       class IdleThread extends Thread {\r
-               boolean            started;\r
-               private AltosState state;\r
-               int                reported_landing;\r
-               int                report_interval;\r
-               long               report_time;\r
-\r
-               public synchronized void report(boolean last) {\r
-                       if (state == null)\r
-                               return;\r
-\r
-                       /* reset the landing count once we hear about a new flight */\r
-                       if (state.state < AltosLib.ao_flight_drogue)\r
-                               reported_landing = 0;\r
-\r
-                       /* Shut up once the rocket is on the ground */\r
-                       if (reported_landing > 2) {\r
-                               return;\r
-                       }\r
-\r
-                       /* If the rocket isn't on the pad, then report height */\r
-                       if (AltosLib.ao_flight_drogue <= state.state &&\r
-                           state.state < AltosLib.ao_flight_landed &&\r
-                           state.range >= 0)\r
-                       {\r
-                               speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n",\r
-                                                   (int) (state.height + 0.5),\r
-                                       state.from_pad.bearing_words(\r
-                                             AltosGreatCircle.BEARING_VOICE),\r
-                                                   (int) (state.from_pad.bearing + 0.5),\r
-                                                   (int) (state.elevation + 0.5),\r
-                                                   (int) (state.range + 0.5)));\r
-                       } else if (state.state > AltosLib.ao_flight_pad) {\r
-                               speak(String.format("%d meters", (int) (state.height + 0.5)));\r
-                       } else {\r
-                               reported_landing = 0;\r
-                       }\r
-\r
-                       /* If the rocket is coming down, check to see if it has landed;\r
-                        * either we've got a landed report or we haven't heard from it in\r
-                        * a long time\r
-                        */\r
-                       if (state.state >= AltosLib.ao_flight_drogue &&\r
-                           (last ||\r
-                            System.currentTimeMillis() - state.report_time >= 15000 ||\r
-                            state.state == AltosLib.ao_flight_landed))\r
-                       {\r
-                               if (Math.abs(state.baro_speed) < 20 && state.height < 100)\r
-                                       speak("rocket landed safely");\r
-                               else\r
-                                       speak("rocket may have crashed");\r
-                               if (state.from_pad != null)\r
-                                       speak(String.format("Bearing %d degrees, range %d meters.",\r
-                                                           (int) (state.from_pad.bearing + 0.5),\r
-                                                           (int) (state.from_pad.distance + 0.5)));\r
-                               ++reported_landing;\r
-                       }\r
-               }\r
-\r
-               long now () {\r
-                       return System.currentTimeMillis();\r
-               }\r
-\r
-               void set_report_time() {\r
-                       report_time = now() + report_interval;\r
-               }\r
-\r
-               public void run () {\r
-                       try {\r
-                               for (;;) {\r
-                                       set_report_time();\r
-                                       for (;;) {\r
-                                               synchronized (this) {\r
-                                                       long sleep_time = report_time - now();\r
-                                                       if (sleep_time <= 0)\r
-                                                               break;\r
-                                                       wait(sleep_time);\r
-                                               }\r
-                                       }\r
-                                       report(false);\r
-                               }\r
-                       } catch (InterruptedException ie) {\r
-                       }\r
-               }\r
-\r
-               public synchronized void notice(AltosState new_state, boolean spoken) {\r
-                       AltosState old_state = state;\r
-                       state = new_state;\r
-                       if (!started && state.state > AltosLib.ao_flight_pad) {\r
-                               started = true;\r
-                               start();\r
-                       }\r
-\r
-                       if (state.state < AltosLib.ao_flight_drogue)\r
-                               report_interval = 10000;\r
-                       else\r
-                               report_interval = 20000;\r
-                       if (old_state != null && old_state.state != state.state) {\r
-                               report_time = now();\r
-                               this.notify();\r
-                       } else if (spoken)\r
-                               set_report_time();\r
-               }\r
-\r
-               public IdleThread() {\r
-                       state = null;\r
-                       reported_landing = 0;\r
-                       report_interval = 10000;\r
-               }\r
-       }\r
-\r
-}\r
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ * Copyright © 2012 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; 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.
+ */
+
+package org.altusmetrum.AltosDroid;
+
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnInitListener;
+
+import org.altusmetrum.altoslib_2.*;
+
+public class AltosVoice {
+
+       private TextToSpeech tts         = null;
+       private boolean      tts_enabled = false;
+
+       private IdleThread   idle_thread = null;
+
+       private AltosState   old_state   = null;
+
+       public AltosVoice(AltosDroid a) {
+
+               tts = new TextToSpeech(a, new OnInitListener() {
+                       public void onInit(int status) {
+                               if (status == TextToSpeech.SUCCESS) tts_enabled = true;
+                               if (tts_enabled) {
+                                       idle_thread = new IdleThread();
+                               }
+                       }
+               });
+
+       }
+
+       public void speak(String s) {
+               if (!tts_enabled) return;
+               tts.speak(s, TextToSpeech.QUEUE_ADD, null);
+       }
+
+       public void stop() {
+               if (tts != null) tts.shutdown();
+               if (idle_thread != null) {
+                       idle_thread.interrupt();
+                       idle_thread = null;
+               }
+       }
+
+       public void tell(AltosState state) {
+               if (!tts_enabled) return;
+
+               boolean spoke = false;
+               if (old_state == null || old_state.state != state.state) {
+                       speak(state.state_name());
+                       if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) &&
+                           state.state > AltosLib.ao_flight_boost) {
+                               speak(String.format("max speed: %d meters per second.", (int) (state.max_speed() + 0.5)));
+                               spoke = true;
+                       } else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) &&
+                                  state.state >= AltosLib.ao_flight_drogue) {
+                               speak(String.format("max height: %d meters.", (int) (state.max_height() + 0.5)));
+                               spoke = true;
+                       }
+               }
+               if (old_state == null || old_state.gps_ready != state.gps_ready) {
+                       if (state.gps_ready) {
+                               speak("GPS ready");
+                               spoke = true;
+                       } else if (old_state != null) {
+                               speak("GPS lost");
+                               spoke = true;
+                       }
+               }
+               old_state = state;
+               idle_thread.notice(state, spoke);
+       }
+
+
+       class IdleThread extends Thread {
+               boolean            started;
+               private AltosState state;
+               int                reported_landing;
+               int                report_interval;
+               long               report_time;
+
+               public synchronized void report(boolean last) {
+                       if (state == null)
+                               return;
+
+                       /* reset the landing count once we hear about a new flight */
+                       if (state.state < AltosLib.ao_flight_drogue)
+                               reported_landing = 0;
+
+                       /* Shut up once the rocket is on the ground */
+                       if (reported_landing > 2) {
+                               return;
+                       }
+
+                       /* If the rocket isn't on the pad, then report height */
+                       if (AltosLib.ao_flight_drogue <= state.state &&
+                           state.state < AltosLib.ao_flight_landed &&
+                           state.range >= 0)
+                       {
+                               speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n",
+                                                   (int) (state.height() + 0.5),
+                                       state.from_pad.bearing_words(
+                                             AltosGreatCircle.BEARING_VOICE),
+                                                   (int) (state.from_pad.bearing + 0.5),
+                                                   (int) (state.elevation + 0.5),
+                                                   (int) (state.range + 0.5)));
+                       } else if (state.state > AltosLib.ao_flight_pad) {
+                               speak(String.format("%d meters", (int) (state.height() + 0.5)));
+                       } else {
+                               reported_landing = 0;
+                       }
+
+                       /* If the rocket is coming down, check to see if it has landed;
+                        * either we've got a landed report or we haven't heard from it in
+                        * a long time
+                        */
+                       if (state.state >= AltosLib.ao_flight_drogue &&
+                           (last ||
+                            System.currentTimeMillis() - state.received_time >= 15000 ||
+                            state.state == AltosLib.ao_flight_landed))
+                       {
+                               if (Math.abs(state.speed()) < 20 && state.height() < 100)
+                                       speak("rocket landed safely");
+                               else
+                                       speak("rocket may have crashed");
+                               if (state.from_pad != null)
+                                       speak(String.format("Bearing %d degrees, range %d meters.",
+                                                           (int) (state.from_pad.bearing + 0.5),
+                                                           (int) (state.from_pad.distance + 0.5)));
+                               ++reported_landing;
+                       }
+               }
+
+               long now () {
+                       return System.currentTimeMillis();
+               }
+
+               void set_report_time() {
+                       report_time = now() + report_interval;
+               }
+
+               public void run () {
+                       try {
+                               for (;;) {
+                                       set_report_time();
+                                       for (;;) {
+                                               synchronized (this) {
+                                                       long sleep_time = report_time - now();
+                                                       if (sleep_time <= 0)
+                                                               break;
+                                                       wait(sleep_time);
+                                               }
+                                       }
+                                       report(false);
+                               }
+                       } catch (InterruptedException ie) {
+                       }
+               }
+
+               public synchronized void notice(AltosState new_state, boolean spoken) {
+                       AltosState old_state = state;
+                       state = new_state;
+                       if (!started && state.state > AltosLib.ao_flight_pad) {
+                               started = true;
+                               start();
+                       }
+
+                       if (state.state < AltosLib.ao_flight_drogue)
+                               report_interval = 10000;
+                       else
+                               report_interval = 20000;
+                       if (old_state != null && old_state.state != state.state) {
+                               report_time = now();
+                               this.notify();
+                       } else if (spoken)
+                               set_report_time();
+               }
+
+               public IdleThread() {
+                       state = null;
+                       reported_landing = 0;
+                       report_interval = 10000;
+               }
+       }
+
+}
index 17e4cf5b4c4497fc11b53bdaedd3311005d28e8f..2797fc5ee32f22d490aec5e21c5c7f5426dc1ab0 100644 (file)
-package org.altusmetrum.AltosDroid;\r
-\r
-       import java.lang.reflect.Array;\r
-       import java.lang.reflect.Field;\r
-       import java.util.HashMap;\r
-\r
-       public class Dumper {\r
-               private static Dumper instance = new Dumper();\r
-\r
-               protected static Dumper getInstance() {\r
-                       return instance;\r
-               }\r
-\r
-               class DumpContext {\r
-                       int maxDepth = 0;\r
-                       int maxArrayElements = 0;\r
-                       int callCount = 0;\r
-                       HashMap<String, String> ignoreList = new HashMap<String, String>();\r
-                       HashMap<Object, Integer> visited = new HashMap<Object, Integer>();\r
-               }\r
-\r
-               public static String dump(Object o) {\r
-                       return dump(o, 0, 0, null);\r
-               }\r
-\r
-               public static String dump(Object o, int maxDepth, int maxArrayElements, String[] ignoreList) {\r
-                       DumpContext ctx = Dumper.getInstance().new DumpContext();\r
-                       ctx.maxDepth = maxDepth;\r
-                       ctx.maxArrayElements = maxArrayElements;\r
-\r
-                       if (ignoreList != null) {\r
-                               for (int i = 0; i < Array.getLength(ignoreList); i++) {\r
-                                       int colonIdx = ignoreList[i].indexOf(':');\r
-                                       if (colonIdx == -1)\r
-                                               ignoreList[i] = ignoreList[i] + ":";\r
-                                       ctx.ignoreList.put(ignoreList[i], ignoreList[i]);\r
-                               }\r
-                       }\r
-\r
-                       return dump(o, ctx);\r
-               }\r
-\r
-               protected static String dump(Object o, DumpContext ctx) {\r
-                       if (o == null) {\r
-                               return "<null>";\r
-                       }\r
-\r
-                       ctx.callCount++;\r
-                       StringBuffer tabs = new StringBuffer();\r
-                       for (int k = 0; k < ctx.callCount; k++) {\r
-                               tabs.append("\t");\r
-                       }\r
-                       StringBuffer buffer = new StringBuffer();\r
-                       @SuppressWarnings("rawtypes")\r
-                       Class oClass = o.getClass();\r
-\r
-                       String oSimpleName = getSimpleNameWithoutArrayQualifier(oClass);\r
-\r
-                       if (ctx.ignoreList.get(oSimpleName + ":") != null)\r
-                               return "<Ignored>";\r
-\r
-                       if (oClass.isArray()) {\r
-                               buffer.append("\n");\r
-                               buffer.append(tabs.toString().substring(1));\r
-                               buffer.append("[\n");\r
-                               int rowCount = ctx.maxArrayElements == 0 ? Array.getLength(o) : Math.min(ctx.maxArrayElements, Array.getLength(o));\r
-                               for (int i = 0; i < rowCount; i++) {\r
-                                       buffer.append(tabs.toString());\r
-                                       try {\r
-                                               Object value = Array.get(o, i);\r
-                                               buffer.append(dumpValue(value, ctx));\r
-                                       } catch (Exception e) {\r
-                                               buffer.append(e.getMessage());\r
-                                       }\r
-                                       if (i < Array.getLength(o) - 1)\r
-                                               buffer.append(",");\r
-                                       buffer.append("\n");\r
-                               }\r
-                               if (rowCount < Array.getLength(o)) {\r
-                                       buffer.append(tabs.toString());\r
-                                       buffer.append(Array.getLength(o) - rowCount + " more array elements...");\r
-                                       buffer.append("\n");\r
-                               }\r
-                               buffer.append(tabs.toString().substring(1));\r
-                               buffer.append("]");\r
-                       } else {\r
-                               buffer.append("\n");\r
-                               buffer.append(tabs.toString().substring(1));\r
-                               buffer.append("{\n");\r
-                               buffer.append(tabs.toString());\r
-                               buffer.append("hashCode: " + o.hashCode());\r
-                               buffer.append("\n");\r
-                               while (oClass != null && oClass != Object.class) {\r
-                                       Field[] fields = oClass.getDeclaredFields();\r
-\r
-                                       if (ctx.ignoreList.get(oClass.getSimpleName()) == null) {\r
-                                               if (oClass != o.getClass()) {\r
-                                                       buffer.append(tabs.toString().substring(1));\r
-                                                       buffer.append("  Inherited from superclass " + oSimpleName + ":\n");\r
-                                               }\r
-\r
-                                               for (int i = 0; i < fields.length; i++) {\r
-\r
-                                                       String fSimpleName = getSimpleNameWithoutArrayQualifier(fields[i].getType());\r
-                                                       String fName = fields[i].getName();\r
-\r
-                                                       fields[i].setAccessible(true);\r
-                                                       buffer.append(tabs.toString());\r
-                                                       buffer.append(fName + "(" + fSimpleName + ")");\r
-                                                       buffer.append("=");\r
-\r
-                                                       if (ctx.ignoreList.get(":" + fName) == null &&\r
-                                                               ctx.ignoreList.get(fSimpleName + ":" + fName) == null &&\r
-                                                               ctx.ignoreList.get(fSimpleName + ":") == null) {\r
-\r
-                                                               try {\r
-                                                                       Object value = fields[i].get(o);\r
-                                                                       buffer.append(dumpValue(value, ctx));\r
-                                                               } catch (Exception e) {\r
-                                                                       buffer.append(e.getMessage());\r
-                                                               }\r
-                                                               buffer.append("\n");\r
-                                                       } else {\r
-                                                               buffer.append("<Ignored>");\r
-                                                               buffer.append("\n");\r
-                                                       }\r
-                                               }\r
-                                               oClass = oClass.getSuperclass();\r
-                                               oSimpleName = oClass.getSimpleName();\r
-                                       } else {\r
-                                               oClass = null;\r
-                                               oSimpleName = "";\r
-                                       }\r
-                               }\r
-                               buffer.append(tabs.toString().substring(1));\r
-                               buffer.append("}");\r
-                       }\r
-                       ctx.callCount--;\r
-                       return buffer.toString();\r
-               }\r
-\r
-               protected static String dumpValue(Object value, DumpContext ctx) {\r
-                       if (value == null) {\r
-                               return "<null>";\r
-                       }\r
-                       if (value.getClass().isPrimitive() ||\r
-                               value.getClass() == java.lang.Short.class ||\r
-                               value.getClass() == java.lang.Long.class ||\r
-                               value.getClass() == java.lang.String.class ||\r
-                               value.getClass() == java.lang.Integer.class ||\r
-                               value.getClass() == java.lang.Float.class ||\r
-                               value.getClass() == java.lang.Byte.class ||\r
-                               value.getClass() == java.lang.Character.class ||\r
-                               value.getClass() == java.lang.Double.class ||\r
-                               value.getClass() == java.lang.Boolean.class) {\r
-\r
-                               return value.toString();\r
-\r
-                       } else {\r
-\r
-                               Integer visitedIndex = ctx.visited.get(value);\r
-                               if (visitedIndex == null) {\r
-                                       ctx.visited.put(value, ctx.callCount);\r
-                                       if (ctx.maxDepth == 0 || ctx.callCount < ctx.maxDepth) {\r
-                                               return dump(value, ctx);\r
-                                       } else {\r
-                                               return "<Reached max recursion depth>";\r
-                                       }\r
-                               } else {\r
-                                       return "<Previously visited - see hashCode " + value.hashCode() + ">";\r
-                               }\r
-                       }\r
-               }\r
-\r
-\r
-               private static String getSimpleNameWithoutArrayQualifier(@SuppressWarnings("rawtypes") Class clazz) {\r
-                       String simpleName = clazz.getSimpleName();\r
-                       int indexOfBracket = simpleName.indexOf('['); \r
-                       if (indexOfBracket != -1)\r
-                               return simpleName.substring(0, indexOfBracket);\r
-                       return simpleName;\r
-               }\r
-}\r
+package org.altusmetrum.AltosDroid;
+
+       import java.lang.reflect.Array;
+       import java.lang.reflect.Field;
+       import java.util.HashMap;
+
+       public class Dumper {
+               private static Dumper instance = new Dumper();
+
+               protected static Dumper getInstance() {
+                       return instance;
+               }
+
+               class DumpContext {
+                       int maxDepth = 0;
+                       int maxArrayElements = 0;
+                       int callCount = 0;
+                       HashMap<String, String> ignoreList = new HashMap<String, String>();
+                       HashMap<Object, Integer> visited = new HashMap<Object, Integer>();
+               }
+
+               public static String dump(Object o) {
+                       return dump(o, 0, 0, null);
+               }
+
+               public static String dump(Object o, int maxDepth, int maxArrayElements, String[] ignoreList) {
+                       DumpContext ctx = Dumper.getInstance().new DumpContext();
+                       ctx.maxDepth = maxDepth;
+                       ctx.maxArrayElements = maxArrayElements;
+
+                       if (ignoreList != null) {
+                               for (int i = 0; i < Array.getLength(ignoreList); i++) {
+                                       int colonIdx = ignoreList[i].indexOf(':');
+                                       if (colonIdx == -1)
+                                               ignoreList[i] = ignoreList[i] + ":";
+                                       ctx.ignoreList.put(ignoreList[i], ignoreList[i]);
+                               }
+                       }
+
+                       return dump(o, ctx);
+               }
+
+               protected static String dump(Object o, DumpContext ctx) {
+                       if (o == null) {
+                               return "<null>";
+                       }
+
+                       ctx.callCount++;
+                       StringBuffer tabs = new StringBuffer();
+                       for (int k = 0; k < ctx.callCount; k++) {
+                               tabs.append("\t");
+                       }
+                       StringBuffer buffer = new StringBuffer();
+                       @SuppressWarnings("rawtypes")
+                       Class oClass = o.getClass();
+
+                       String oSimpleName = getSimpleNameWithoutArrayQualifier(oClass);
+
+                       if (ctx.ignoreList.get(oSimpleName + ":") != null)
+                               return "<Ignored>";
+
+                       if (oClass.isArray()) {
+                               buffer.append("\n");
+                               buffer.append(tabs.toString().substring(1));
+                               buffer.append("[\n");
+                               int rowCount = ctx.maxArrayElements == 0 ? Array.getLength(o) : Math.min(ctx.maxArrayElements, Array.getLength(o));
+                               for (int i = 0; i < rowCount; i++) {
+                                       buffer.append(tabs.toString());
+                                       try {
+                                               Object value = Array.get(o, i);
+                                               buffer.append(dumpValue(value, ctx));
+                                       } catch (Exception e) {
+                                               buffer.append(e.getMessage());
+                                       }
+                                       if (i < Array.getLength(o) - 1)
+                                               buffer.append(",");
+                                       buffer.append("\n");
+                               }
+                               if (rowCount < Array.getLength(o)) {
+                                       buffer.append(tabs.toString());
+                                       buffer.append(Array.getLength(o) - rowCount + " more array elements...");
+                                       buffer.append("\n");
+                               }
+                               buffer.append(tabs.toString().substring(1));
+                               buffer.append("]");
+                       } else {
+                               buffer.append("\n");
+                               buffer.append(tabs.toString().substring(1));
+                               buffer.append("{\n");
+                               buffer.append(tabs.toString());
+                               buffer.append("hashCode: " + o.hashCode());
+                               buffer.append("\n");
+                               while (oClass != null && oClass != Object.class) {
+                                       Field[] fields = oClass.getDeclaredFields();
+
+                                       if (ctx.ignoreList.get(oClass.getSimpleName()) == null) {
+                                               if (oClass != o.getClass()) {
+                                                       buffer.append(tabs.toString().substring(1));
+                                                       buffer.append("  Inherited from superclass " + oSimpleName + ":\n");
+                                               }
+
+                                               for (int i = 0; i < fields.length; i++) {
+
+                                                       String fSimpleName = getSimpleNameWithoutArrayQualifier(fields[i].getType());
+                                                       String fName = fields[i].getName();
+
+                                                       fields[i].setAccessible(true);
+                                                       buffer.append(tabs.toString());
+                                                       buffer.append(fName + "(" + fSimpleName + ")");
+                                                       buffer.append("=");
+
+                                                       if (ctx.ignoreList.get(":" + fName) == null &&
+                                                               ctx.ignoreList.get(fSimpleName + ":" + fName) == null &&
+                                                               ctx.ignoreList.get(fSimpleName + ":") == null) {
+
+                                                               try {
+                                                                       Object value = fields[i].get(o);
+                                                                       buffer.append(dumpValue(value, ctx));
+                                                               } catch (Exception e) {
+                                                                       buffer.append(e.getMessage());
+                                                               }
+                                                               buffer.append("\n");
+                                                       } else {
+                                                               buffer.append("<Ignored>");
+                                                               buffer.append("\n");
+                                                       }
+                                               }
+                                               oClass = oClass.getSuperclass();
+                                               oSimpleName = oClass.getSimpleName();
+                                       } else {
+                                               oClass = null;
+                                               oSimpleName = "";
+                                       }
+                               }
+                               buffer.append(tabs.toString().substring(1));
+                               buffer.append("}");
+                       }
+                       ctx.callCount--;
+                       return buffer.toString();
+               }
+
+               protected static String dumpValue(Object value, DumpContext ctx) {
+                       if (value == null) {
+                               return "<null>";
+                       }
+                       if (value.getClass().isPrimitive() ||
+                               value.getClass() == java.lang.Short.class ||
+                               value.getClass() == java.lang.Long.class ||
+                               value.getClass() == java.lang.String.class ||
+                               value.getClass() == java.lang.Integer.class ||
+                               value.getClass() == java.lang.Float.class ||
+                               value.getClass() == java.lang.Byte.class ||
+                               value.getClass() == java.lang.Character.class ||
+                               value.getClass() == java.lang.Double.class ||
+                               value.getClass() == java.lang.Boolean.class) {
+
+                               return value.toString();
+
+                       } else {
+
+                               Integer visitedIndex = ctx.visited.get(value);
+                               if (visitedIndex == null) {
+                                       ctx.visited.put(value, ctx.callCount);
+                                       if (ctx.maxDepth == 0 || ctx.callCount < ctx.maxDepth) {
+                                               return dump(value, ctx);
+                                       } else {
+                                               return "<Reached max recursion depth>";
+                                       }
+                               } else {
+                                       return "<Previously visited - see hashCode " + value.hashCode() + ">";
+                               }
+                       }
+               }
+
+
+               private static String getSimpleNameWithoutArrayQualifier(@SuppressWarnings("rawtypes") Class clazz) {
+                       String simpleName = clazz.getSimpleName();
+                       int indexOfBracket = simpleName.indexOf('['); 
+                       if (indexOfBracket != -1)
+                               return simpleName.substring(0, indexOfBracket);
+                       return simpleName;
+               }
+}
index 0e141ae47e942e2983333a1ef526c79b67b13c2d..3eaf12dbd1f53ca0124794c5ebb52990d1136132 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import android.app.Activity;
 import android.os.Bundle;
@@ -87,12 +87,12 @@ public class TabAscent extends Fragment implements AltosDroidTab {
 
        public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
                if (state != null) {
-                       mHeightView.setText(AltosDroid.number("%6.0f m", state.height));
-                       mMaxHeightView.setText(AltosDroid.number("%6.0f m", state.max_height));
+                       mHeightView.setText(AltosDroid.number("%6.0f m", state.height()));
+                       mMaxHeightView.setText(AltosDroid.number("%6.0f m", state.max_height()));
                        mSpeedView.setText(AltosDroid.number("%6.0f m/s", state.speed()));
                        mMaxSpeedView.setText(AltosDroid.number("%6.0f m/s", state.max_speed()));
-                       mAccelView.setText(AltosDroid.number("%6.0f m/s²", state.acceleration));
-                       mMaxAccelView.setText(AltosDroid.number("%6.0f m/s²", state.max_acceleration));
+                       mAccelView.setText(AltosDroid.number("%6.0f m/s²", state.acceleration()));
+                       mMaxAccelView.setText(AltosDroid.number("%6.0f m/s²", state.max_acceleration()));
 
                        if (state.gps != null) {
                                mLatitudeView.setText(AltosDroid.pos(state.gps.lat, "N", "S"));
@@ -102,11 +102,11 @@ public class TabAscent extends Fragment implements AltosDroidTab {
                                mLongitudeView.setText("");
                        }
 
-                       mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.drogue_sense));
-                       mApogeeLights.set(state.drogue_sense > 3.2, state.drogue_sense == AltosRecord.MISSING);
+                       mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.apogee_voltage));
+                       mApogeeLights.set(state.apogee_voltage > 3.2, state.apogee_voltage == AltosLib.MISSING);
 
-                       mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_sense));
-                       mMainLights.set(state.main_sense > 3.2, state.main_sense == AltosRecord.MISSING);
+                       mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_voltage));
+                       mMainLights.set(state.main_voltage > 3.2, state.main_voltage == AltosLib.MISSING);
                }
        }
 }
index 09e7169b229ff1c126405ac9f8fe8a3fdbedabc6..e4a954ca1603e7fc38d9ffd46558fe597463f082 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import android.app.Activity;
 import android.os.Bundle;
@@ -92,7 +92,7 @@ public class TabDescent extends Fragment implements AltosDroidTab {
        public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
                if (state != null) {
                        mSpeedView.setText(AltosDroid.number("%6.0f m/s", state.speed()));
-                       mHeightView.setText(AltosDroid.number("%6.0f m", state.height));
+                       mHeightView.setText(AltosDroid.number("%6.0f m", state.height()));
                        if (from_receiver != null) {
                                mElevationView.setText(AltosDroid.number("%3.0f°", from_receiver.elevation));
                                mRangeView.setText(AltosDroid.number("%6.0f m", from_receiver.range));
@@ -111,11 +111,11 @@ public class TabDescent extends Fragment implements AltosDroidTab {
                                mLongitudeView.setText(AltosDroid.pos(state.gps.lon, "W", "E"));
                        }
 
-                       mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.drogue_sense));
-                       mApogeeLights.set(state.drogue_sense > 3.2, state.drogue_sense == AltosRecord.MISSING);
+                       mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.apogee_voltage));
+                       mApogeeLights.set(state.apogee_voltage > 3.2, state.apogee_voltage == AltosLib.MISSING);
 
-                       mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_sense));
-                       mMainLights.set(state.main_sense > 3.2, state.main_sense == AltosRecord.MISSING);
+                       mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_voltage));
+                       mMainLights.set(state.main_voltage > 3.2, state.main_voltage == AltosLib.MISSING);
                }
        }
 
index f42b46b55520d7fbf8551e676ddda47dfebafe41..40399f2aed0df4d0fe31ad6e5fec78c0fb814d45 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import android.app.Activity;
 import android.os.Bundle;
@@ -89,8 +89,8 @@ public class TabLanded extends Fragment implements AltosDroidTab {
                }
               
                if (state != null) {
-                       mMaxHeightView.setText(String.format("%6.0f m", state.max_height));
-                       mMaxAccelView.setText(String.format("%6.0f m/s²", state.max_acceleration));
+                       mMaxHeightView.setText(String.format("%6.0f m", state.max_height()));
+                       mMaxAccelView.setText(String.format("%6.0f m/s²", state.max_acceleration()));
                        mMaxSpeedView.setText(String.format("%6.0f m/s", state.max_speed()));
                }
        }
index d831f1172761cfabf52a5b404a8b1ba585d200c9..a4e224aad486ac6f3216f728868c5ce3b00d53c0 100644 (file)
@@ -19,7 +19,7 @@ package org.altusmetrum.AltosDroid;
 
 import java.util.Arrays;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import com.google.android.gms.maps.CameraUpdateFactory;
 import com.google.android.gms.maps.GoogleMap;
index 066c1353ef792a87896a18a3522d9623725a0e2d..b9e878f12519be8ac4ecf2325fe668db3e1a7f6e 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import android.app.Activity;
 import android.os.Bundle;
@@ -103,26 +103,26 @@ public class TabPad extends Fragment implements AltosDroidTab {
 
        public void update_ui(AltosState state, AltosGreatCircle from_receiver, Location receiver) {
                if (state != null) {
-                       mBatteryVoltageView.setText(AltosDroid.number("%4.2f V", state.battery));
-                       mBatteryLights.set(state.battery > 3.7, state.battery == AltosRecord.MISSING);
+                       mBatteryVoltageView.setText(AltosDroid.number("%4.2f V", state.battery_voltage));
+                       mBatteryLights.set(state.battery_voltage >= AltosLib.ao_battery_good, state.battery_voltage == AltosLib.MISSING);
 
-                       mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.drogue_sense));
-                       mApogeeLights.set(state.drogue_sense > 3.2, state.drogue_sense == AltosRecord.MISSING);
+                       mApogeeVoltageView.setText(AltosDroid.number("%4.2f V", state.apogee_voltage));
+                       mApogeeLights.set(state.apogee_voltage >= AltosLib.ao_igniter_good, state.apogee_voltage == AltosLib.MISSING);
 
-                       mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_sense));
-                       mMainLights.set(state.main_sense > 3.2, state.main_sense == AltosRecord.MISSING);
+                       mMainVoltageView.setText(AltosDroid.number("%4.2f V", state.main_voltage));
+                       mMainLights.set(state.main_voltage >= AltosLib.ao_igniter_good, state.main_voltage == AltosLib.MISSING);
 
-                       if (state.data.flight != 0) {
-                               if (state.data.state <= AltosLib.ao_flight_pad)
+                       if (state.flight != 0) {
+                               if (state.state <= AltosLib.ao_flight_pad)
                                        mDataLoggingView.setText("Ready to record");
-                               else if (state.data.state < AltosLib.ao_flight_landed)
+                               else if (state.state < AltosLib.ao_flight_landed)
                                        mDataLoggingView.setText("Recording data");
                                else
                                        mDataLoggingView.setText("Recorded data");
                        } else {
                                mDataLoggingView.setText("Storage full");
                        }
-                       mDataLoggingLights.set(state.data.flight != 0, state.data.flight == AltosRecord.MISSING);
+                       mDataLoggingLights.set(state.flight != 0, state.flight == AltosLib.MISSING);
 
                        if (state.gps != null) {
                                mGPSLockedView.setText(AltosDroid.integer("%4d sats", state.gps.nsat));
index 3ece04ac3e8596b0ef1f64b40f430e5280c13d74..4d793413a8983e3403775b1e6217d03b034c0435 100644 (file)
@@ -1,6 +1,6 @@
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
index 716ec5894c9df42c5e0a975591ba8464c42e91bd..45604284e0767a405de80b2f5d6b8c66d77cb24a 100644 (file)
@@ -1,94 +1,95 @@
-/*\r
- * Copyright © 2011 Keith Packard <keithp@keithp.com>\r
- * Copyright © 2012 Mike Beattie <mike@ethernal.org>\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; version 2 of the License.\r
- *\r
- * This program is distributed in the hope that it will be useful, but\r
- * WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License along\r
- * with this program; if not, write to the Free Software Foundation, Inc.,\r
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.\r
- */\r
-\r
-\r
-package org.altusmetrum.AltosDroid;\r
-\r
-import java.text.*;\r
-import java.io.*;\r
-import java.util.concurrent.*;\r
-import android.util.Log;\r
-import android.os.Handler;\r
-\r
-import org.altusmetrum.altoslib_1.*;\r
-\r
-\r
-public class TelemetryReader extends Thread {\r
-\r
-       private static final String TAG = "TelemetryReader";\r
-\r
-       int         crc_errors;\r
-\r
-       Handler     handler;\r
-\r
-       AltosLink   link;\r
-       AltosRecord previous;\r
-\r
-       LinkedBlockingQueue<AltosLine> telem;\r
-\r
-       public AltosRecord read() throws ParseException, AltosCRCException, InterruptedException, IOException {\r
-               AltosLine l = telem.take();\r
-               if (l.line == null)\r
-                       throw new IOException("IO error");\r
-               AltosRecord     next = AltosTelemetry.parse(l.line, previous);\r
-               previous = next;\r
-               return next;\r
-       }\r
-\r
-       public void close() {\r
-               previous = null;\r
-               link.remove_monitor(telem);\r
-               link = null;\r
-               telem.clear();\r
-               telem = null;\r
-       }\r
-\r
-       public void run() {\r
-               AltosState  state = null;\r
-\r
-               try {\r
-                       for (;;) {\r
-                               try {\r
-                                       AltosRecord record = read();\r
-                                       if (record == null)\r
-                                               break;\r
-                                       state = new AltosState(record, state);\r
-                                       handler.obtainMessage(TelemetryService.MSG_TELEMETRY, state).sendToTarget();\r
-                               } catch (ParseException pp) {\r
-                                       Log.e(TAG, String.format("Parse error: %d \"%s\"", pp.getErrorOffset(), pp.getMessage()));\r
-                               } catch (AltosCRCException ce) {\r
-                                       ++crc_errors;\r
-                                       handler.obtainMessage(TelemetryService.MSG_CRC_ERROR, new Integer(crc_errors)).sendToTarget();\r
-                               }\r
-                       }\r
-               } catch (InterruptedException ee) {\r
-               } catch (IOException ie) {\r
-               } finally {\r
-                       close();\r
-               }\r
-       }\r
-\r
-       public TelemetryReader (AltosLink in_link, Handler in_handler) {\r
-               link    = in_link;\r
-               handler = in_handler;\r
-\r
-               previous = null;\r
-               telem = new LinkedBlockingQueue<AltosLine>();\r
-               link.add_monitor(telem);\r
-       }\r
-}\r
+/*
+ * Copyright © 2011 Keith Packard <keithp@keithp.com>
+ * Copyright © 2012 Mike Beattie <mike@ethernal.org>
+ *
+ * This program is free software; 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.
+ */
+
+
+package org.altusmetrum.AltosDroid;
+
+import java.text.*;
+import java.io.*;
+import java.util.concurrent.*;
+import android.util.Log;
+import android.os.Handler;
+
+import org.altusmetrum.altoslib_2.*;
+
+
+public class TelemetryReader extends Thread {
+
+       private static final String TAG = "TelemetryReader";
+
+       int         crc_errors;
+
+       Handler     handler;
+
+       AltosLink   link;
+       AltosState  state = null;
+
+       LinkedBlockingQueue<AltosLine> telemQueue;
+
+       public AltosState read() throws ParseException, AltosCRCException, InterruptedException, IOException {
+               AltosLine l = telemQueue.take();
+               if (l.line == null)
+                       throw new IOException("IO error");
+               AltosTelemetry telem = AltosTelemetryLegacy.parse(l.line);
+               if (state == null)
+                       state = new AltosState();
+               else
+                       state = state.clone();
+               telem.update_state(state);
+               return state;
+       }
+
+       public void close() {
+               state = null;
+               link.remove_monitor(telemQueue);
+               link = null;
+               telemQueue.clear();
+               telemQueue = null;
+       }
+
+       public void run() {
+               AltosState  state = null;
+
+               try {
+                       for (;;) {
+                               try {
+                                       state = read();
+                                       handler.obtainMessage(TelemetryService.MSG_TELEMETRY, state).sendToTarget();
+                               } catch (ParseException pp) {
+                                       Log.e(TAG, String.format("Parse error: %d \"%s\"", pp.getErrorOffset(), pp.getMessage()));
+                               } catch (AltosCRCException ce) {
+                                       ++crc_errors;
+                                       handler.obtainMessage(TelemetryService.MSG_CRC_ERROR, new Integer(crc_errors)).sendToTarget();
+                               }
+                       }
+               } catch (InterruptedException ee) {
+               } catch (IOException ie) {
+               } finally {
+                       close();
+               }
+       }
+
+       public TelemetryReader (AltosLink in_link, Handler in_handler) {
+               link    = in_link;
+               handler = in_handler;
+
+               state = null;
+               telemQueue = new LinkedBlockingQueue<AltosLine>();
+               link.add_monitor(telemQueue);
+       }
+}
index 0236b537a2271d41028e9ad7d6ab48238a49853a..76efa74968ca557627ce2cf5495e7dbecd5b4645 100644 (file)
@@ -36,13 +36,15 @@ import android.os.Handler;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
+import android.os.Looper;
 import android.util.Log;
 import android.widget.Toast;
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationListener;
+import android.location.Criteria;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 
 public class TelemetryService extends Service implements LocationListener {
@@ -280,8 +282,8 @@ public class TelemetryService extends Service implements LocationListener {
                // Listen for GPS and Network position updates
                LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
                
-               locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
-               locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
+               locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, this);
+//             locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
        }
 
        @Override
index d02b32385f348e1dfdf28eabb5afd1219dbcf07b..b838d30b23e815581f0d038bff783d6658e4574b 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosAccel extends AltosUnits {
 
-       public double value(double v) {
-               if (AltosConvert.imperial_units)
+       public double value(double v, boolean imperial_units) {
+               if (imperial_units)
                        return AltosConvert.meters_to_feet(v);
                return v;
        }
 
-       public String show_units() {
-               if (AltosConvert.imperial_units)
+       public double inverse(double v, boolean imperial_units) {
+               if (imperial_units)
+                       return AltosConvert.feet_to_meters(v);
+               return v;
+       }
+
+       public String show_units(boolean imperial_units) {
+               if (imperial_units)
                        return "ft/s²";
                return "m/s²";
        }
 
-       public String say_units() {
-               if (AltosConvert.imperial_units)
+       public String say_units(boolean imperial_units) {
+               if (imperial_units)
                        return "feet per second squared";
                return "meters per second squared";
        }
 
-       public int show_fraction(int width) {
+       public int show_fraction(int width, boolean imperial_units) {
                return width / 9;
        }
 }
\ No newline at end of file
index 76e79add1255c1cb9157564c59ae7851d15a5864..be2ec4fec48e0bd00e311ea7b6c410718e07c4ac 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosCRCException extends Exception {
        public int rssi;
diff --git a/altoslib/AltosCompanion.java b/altoslib/AltosCompanion.java
new file mode 100644 (file)
index 0000000..57bb21a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosCompanion {
+       public final static int board_id_telescience = 0x0a;
+       public final static int MAX_CHANNELS = 12;
+
+       public int      tick;
+       public int      board_id;
+       public int      update_period;
+       public int      channels;
+       public int[]    companion_data;
+
+       public AltosCompanion(int in_channels) {
+               channels = in_channels;
+               if (channels < 0)
+                       channels = 0;
+               if (channels > MAX_CHANNELS)
+                       channels = MAX_CHANNELS;
+               companion_data = new int[channels];
+       }
+}
index 2ca5a7a56f74093227285d72176f62b51307e304..1c3085bd7efc2f39ee41bddabdb806fe82960bfd 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.util.*;
 import java.text.*;
@@ -336,6 +336,10 @@ public class AltosConfigData implements Iterable<String> {
        public double frequency() {
                int     channel = radio_channel;
                int     setting = radio_setting;
+
+               if (radio_frequency < 0 && channel < 0 && setting < 0)
+                       return -1;
+
                if (channel < 0)
                        channel = 0;
                if (setting < 0)
index 027d10f4dfb92be98d04d41a5a161b2d48c64dbb..fd5584c2422b0552bc4dfa4086bf288354dd69c3 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public interface AltosConfigValues {
        /* set and get all of the dialog values */
index a42b36c46fc5debdb669ea17f7dd5f88ef379e6f..8d0b74ddf475051c3d587edab328ddf28a6d3a5c 100644 (file)
@@ -18,7 +18,7 @@
 /*
  * Sensor data conversion functions
  */
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosConvert {
        /*
@@ -190,6 +190,46 @@ public class AltosConvert {
                return ignite / 32767 * 15.0;
        }
 
+       public static double
+       barometer_to_pressure(double count)
+       {
+               return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0;
+       }
+
+       static double
+       thermometer_to_temperature(double thermo)
+       {
+               return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247;
+       }
+
+       static double mega_adc(int raw) {
+               return raw / 4095.0;
+       }
+
+       static public double mega_battery_voltage(int v_batt) {
+               if (v_batt != AltosLib.MISSING)
+                       return 3.3 * mega_adc(v_batt) * (15.0 + 27.0) / 27.0;
+               return AltosLib.MISSING;
+       }
+
+       static double mega_pyro_voltage(int raw) {
+               if (raw != AltosLib.MISSING)
+                       return 3.3 * mega_adc(raw) * (100.0 + 27.0) / 27.0;
+               return AltosLib.MISSING;
+       }
+
+       static double tele_mini_voltage(int sensor) {
+               double  supply = 3.3;
+
+               return sensor / 32767.0 * supply * 127/27;
+       }
+
+       static double easy_mini_voltage(int sensor) {
+               double  supply = 3.0;
+
+               return sensor / 32767.0 * supply * 127/27;
+       }
+
        public static double radio_to_frequency(int freq, int setting, int cal, int channel) {
                double  f;
 
@@ -242,14 +282,26 @@ public class AltosConvert {
                return meters * (100 / (2.54 * 12));
        }
 
+       public static double feet_to_meters(double feet) {
+               return feet * 12 * 2.54 / 100.0;
+       }
+
        public static double meters_to_miles(double meters) {
                return meters_to_feet(meters) / 5280;
        }
 
+       public static double miles_to_meters(double miles) {
+               return feet_to_meters(miles * 5280);
+       }
+
        public static double meters_to_mph(double mps) {
                return meters_to_miles(mps) * 3600;
        }
 
+       public static double mph_to_meters(double mps) {
+               return miles_to_meters(mps) / 3600;
+       }
+
        public static double meters_to_mach(double meters) {
                return meters / 343;            /* something close to mach at usual rocket sites */
        }
@@ -262,6 +314,10 @@ public class AltosConvert {
                return c * 9/5 + 32;
        }
 
+       public static double f_to_c(double c) {
+               return (c - 32) * 5/9;
+       }
+
        public static boolean imperial_units = false;
 
        public static AltosDistance distance = new AltosDistance();
index 4d8e3ae7cfa994bb7718ac41bbf0691a98111c76..fb11d39abac0b49e01abf532eabaca4429cb1b89 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 
@@ -56,13 +56,10 @@ public class AltosDebug {
 
        boolean debug_mode;
 
-       void ensure_debug_mode() {
+       void ensure_debug_mode() throws InterruptedException {
                if (!debug_mode) {
                        link.printf("D\n");
-                       try {
-                               link.flush_input();
-                       } catch (InterruptedException ie) {
-                       }
+                       link.flush_input();
                        debug_mode = true;
                }
        }
@@ -81,13 +78,16 @@ public class AltosDebug {
        }
 
        public void close() {
-               link.close();
+               try {
+                       link.close();
+               } catch (InterruptedException ie) {
+               }
        }
 
        /*
         * Write target memory
         */
-       public void write_memory(int address, byte[] bytes, int start, int len) {
+       public void write_memory(int address, byte[] bytes, int start, int len) throws InterruptedException {
                ensure_debug_mode();
 //             dump_memory("write_memory", address, bytes, start, len);
                link.printf("O %x %x\n", len, address);
@@ -95,7 +95,7 @@ public class AltosDebug {
                        link.printf("%02x", bytes[start + i]);
        }
 
-       public void write_memory(int address, byte[] bytes) {
+       public void write_memory(int address, byte[] bytes) throws InterruptedException {
                write_memory(address, bytes, 0, bytes.length);
        }
 
@@ -132,7 +132,7 @@ public class AltosDebug {
        /*
         * Write raw bytes to the debug link using the 'P' command
         */
-       public void write_bytes(byte[] bytes) throws IOException {
+       public void write_bytes(byte[] bytes) throws IOException, InterruptedException {
                int i = 0;
                ensure_debug_mode();
                while (i < bytes.length) {
@@ -147,7 +147,7 @@ public class AltosDebug {
                }
        }
 
-       public void write_byte(byte b) throws IOException {
+       public void write_byte(byte b) throws IOException, InterruptedException {
                byte[] bytes = { b };
                write_bytes(bytes);
        }
@@ -257,12 +257,12 @@ public class AltosDebug {
                return true;
        }
 
-       public AltosRomconfig romconfig() {
+       public AltosRomconfig romconfig() throws InterruptedException {
                try {
                        byte[] bytes = read_memory(0xa0, 10);
-                       return new AltosRomconfig(bytes, 0);
+                       AltosHexfile hexfile = new AltosHexfile (bytes, 0xa0);
+                       return new AltosRomconfig(hexfile);
                } catch (IOException ie) {
-               } catch (InterruptedException ie) {
                }
                return new AltosRomconfig();
        }
index 25028ac79a2ae255717c901ef41f0460dbdca71c..8d359feb9a0cacbbd4a270a19600b5551b717cf8 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosDistance extends AltosUnits {
 
-       public double value(double v) {
-               if (AltosConvert.imperial_units)
+       public double value(double v, boolean imperial_units) {
+               if (imperial_units)
                        return AltosConvert.meters_to_miles(v);
                return v;
        }
 
-       public String show_units() {
-               if (AltosConvert.imperial_units)
+       public double inverse(double v, boolean imperial_units) {
+               if (imperial_units)
+                       return AltosConvert.miles_to_meters(v);
+               return v;
+       }
+
+       public String show_units(boolean imperial_units) {
+               if (imperial_units)
                        return "miles";
                return "m";
        }
 
-       public String say_units() {
-               if (AltosConvert.imperial_units)
+       public String say_units(boolean imperial_units) {
+               if (imperial_units)
                        return "miles";
                return "meters";
        }
 
-       public int show_fraction(int width) {
-               if (AltosConvert.imperial_units)
+       public int show_fraction(int width, boolean imperial_units) {
+               if (imperial_units)
                        return width / 3;
                return width / 9;
        }
 
-       public int say_fraction() {
-               if (AltosConvert.imperial_units)
+       public int say_fraction(boolean imperial_units) {
+               if (imperial_units)
                        return 1;
                return 0;
        }
diff --git a/altoslib/AltosEeprom.java b/altoslib/AltosEeprom.java
new file mode 100644 (file)
index 0000000..dd5993c
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public abstract class AltosEeprom implements AltosStateUpdate {
+       public int      cmd;
+       public int      tick;
+       public int      data8[];
+       public boolean  valid;
+
+       public int data8(int i) {
+               return data8[i];
+       }
+
+       public int data16(int i) {
+               return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16;
+       }
+
+       public int data24(int i) {
+               return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16);
+       }
+
+       public int data32(int i) {
+               return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24);
+       }
+
+       public final static int header_length = 4;
+
+       public abstract int record_length();
+
+       public void update_state(AltosState state) {
+               if (cmd == AltosLib.AO_LOG_FLIGHT)
+                       state.set_boost_tick(tick);
+               else
+                       state.set_tick(tick);
+       }
+
+       public void write(PrintStream out) {
+               out.printf("%c %04x", cmd, tick);
+               if (data8 != null) {
+                       for (int i = 0; i < data8.length; i++)
+                               out.printf (" %02x", data8[i]);
+               }
+               out.printf ("\n");
+       }
+
+       public String string() {
+               String  s;
+
+               s = String.format("%c %04x", cmd, tick);
+               if (data8 != null) {
+                       for (int i = 0; i < data8.length; i++) {
+                               String  d = String.format(" %02x", data8[i]);
+                               s = s.concat(d);
+                       }
+               }
+               s = s.concat("\n");
+               return s;
+       }
+
+       void parse_chunk(AltosEepromChunk chunk, int start) throws ParseException {
+               cmd = chunk.data(start);
+
+               int data_length = record_length() - header_length;
+
+               valid = !chunk.erased(start, record_length());
+               if (valid) {
+                       if (AltosConvert.checksum(chunk.data, start, record_length()) != 0)
+                               throw new ParseException(String.format("invalid checksum at 0x%x",
+                                                                      chunk.address + start), 0);
+               } else {
+                       cmd = AltosLib.AO_LOG_INVALID;
+               }
+
+               tick = chunk.data16(start+2);
+
+               data8 = new int[data_length];
+               for (int i = 0; i < data_length; i++)
+                       data8[i] = chunk.data(start + header_length + i);
+       }
+
+       void parse_string(String line) {
+               valid = false;
+               tick = 0;
+               cmd = AltosLib.AO_LOG_INVALID;
+
+               int data_length = record_length() - header_length;
+
+               if (line == null)
+                       return;
+               try {
+                       String[] tokens = line.split("\\s+");
+
+                       if (tokens[0].length() == 1) {
+                               if (tokens.length == 2 + data_length) {
+                                       cmd = tokens[0].codePointAt(0);
+                                       tick = Integer.parseInt(tokens[1],16);
+                                       valid = true;
+                                       data8 = new int[data_length];
+
+                                       for (int i = 0; i < data_length; i++)
+                                               data8[i] = Integer.parseInt(tokens[2 + i],16);
+                               }
+                       }
+               } catch (NumberFormatException ne) {
+               }
+       }
+}
index b1bba3bb56d67154c8cc49f23e3ab76c6cd84c02..c03fa931fdc0f230b307e97d726b4ea31570e23f 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.text.*;
 import java.util.concurrent.*;
@@ -62,6 +62,34 @@ public class AltosEepromChunk {
                return true;
        }
 
+       public AltosEeprom eeprom(int offset, int log_format, AltosState state) throws ParseException {
+               AltosEeprom     eeprom = null;
+               switch (log_format) {
+               case AltosLib.AO_LOG_FORMAT_FULL:
+                       eeprom = new AltosEepromTM(this, offset);
+                       break;
+               case AltosLib.AO_LOG_FORMAT_TINY:
+                       eeprom = new AltosEepromTm(this, offset, state);
+                       break;
+               case AltosLib.AO_LOG_FORMAT_TELEMETRY:
+               case AltosLib.AO_LOG_FORMAT_TELESCIENCE:
+                       break;
+               case AltosLib.AO_LOG_FORMAT_TELEMEGA:
+                       eeprom = new AltosEepromMega(this, offset);
+                       break;
+               case AltosLib.AO_LOG_FORMAT_TELEMETRUM:
+                       eeprom = new AltosEepromMetrum2(this, offset);
+                       break;
+               case AltosLib.AO_LOG_FORMAT_TELEMINI:
+               case AltosLib.AO_LOG_FORMAT_EASYMINI:
+                       eeprom = new AltosEepromMini(this, offset);
+                       break;
+               default:
+                       throw new ParseException("unknown eeprom format " + log_format, 0);
+               }
+               return eeprom;
+       }
+
        public AltosEepromChunk(AltosLink link, int block, boolean flush)
                throws TimeoutException, InterruptedException {
 
diff --git a/altoslib/AltosEepromDownload.java b/altoslib/AltosEepromDownload.java
new file mode 100644 (file)
index 0000000..1b04316
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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; 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.concurrent.*;
+
+public class AltosEepromDownload implements Runnable {
+
+       AltosLink               link;
+       boolean                 remote;
+       Thread                  eeprom_thread;
+       AltosEepromMonitor      monitor;
+
+       boolean                 want_file;
+       FileWriter              eeprom_file;
+       LinkedList<String>      eeprom_pending;
+
+       AltosEepromList         flights;
+       boolean                 success;
+       ParseException          parse_exception;
+       AltosState              state;
+
+       private void FlushPending() throws IOException {
+               for (String s : flights.config_data) {
+                       eeprom_file.write(s);
+                       eeprom_file.write('\n');
+               }
+
+               for (String s : eeprom_pending)
+                       eeprom_file.write(s);
+       }
+
+       private void CheckFile(boolean force) throws IOException {
+               if (eeprom_file != null)
+                       return;
+               if (force || (state.flight != 0 && want_file)) {
+                       AltosFile               eeprom_name;
+                       AltosGPS                gps = state.gps;
+
+                       if (gps != null &&
+                           gps.year != AltosLib.MISSING &&
+                           gps.month != AltosLib.MISSING &&
+                           gps.day != AltosLib.MISSING)
+                       {
+                               eeprom_name = new AltosFile(gps.year, gps.month, gps.day,
+                                                           state.serial, state.flight, "eeprom");
+                       } else
+                               eeprom_name = new AltosFile(state.serial, state.flight, "eeprom");
+
+                       eeprom_file = new FileWriter(eeprom_name);
+                       if (eeprom_file != null) {
+                               monitor.set_filename(eeprom_name.getName());
+                               FlushPending();
+                               eeprom_pending = null;
+                       }
+               }
+       }
+
+       boolean                 done;
+       boolean                 start;
+
+       void LogEeprom(AltosEeprom r) throws IOException {
+               if (r.cmd != AltosLib.AO_LOG_INVALID) {
+                       String line = r.string();
+                       if (eeprom_file != null)
+                               eeprom_file.write(line);
+                       else
+                               eeprom_pending.add(line);
+               }
+       }
+
+       void CaptureEeprom(AltosEepromChunk eechunk, int log_format) throws IOException, ParseException {
+               boolean any_valid = false;
+               boolean got_flight = false;
+
+               int record_length = 8;
+
+               state.set_serial(flights.config_data.serial);
+               monitor.set_serial(flights.config_data.serial);
+
+               for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += record_length) {
+                       AltosEeprom r = eechunk.eeprom(i, log_format, state);
+
+                       if (r == null)
+                               continue;
+
+                       record_length = r.record_length();
+
+                       r.update_state(state);
+
+                       if (!got_flight && state.flight != AltosLib.MISSING)
+                               monitor.set_flight(state.flight);
+
+                       /* Monitor state transitions to update display */
+                       if (state.state != AltosLib.ao_flight_invalid &&
+                           state.state <= AltosLib.ao_flight_landed)
+                       {
+                               if (state.state > AltosLib.ao_flight_pad)
+                                       want_file = true;
+                               if (state.state == AltosLib.ao_flight_landed)
+                                       done = true;
+                       }
+
+                       if (state.gps != null)
+                               want_file = true;
+
+                       if (r.valid) {
+                               any_valid = true;
+                               LogEeprom(r);
+                       }
+               }
+               if (!any_valid)
+                       done = true;
+
+               CheckFile(false);
+       }
+       
+       void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException, ParseException {
+               int                     block, state_block = 0;
+               int                     log_format = flights.config_data.log_format;
+
+               state = new AltosState();
+
+               done = false;
+               start = true;
+
+               if (flights.config_data.serial < 0)
+                       throw new IOException("no serial number found");
+
+               /* Reset per-capture variables */
+               want_file = false;
+               eeprom_file = null;
+               eeprom_pending = new LinkedList<String>();
+
+               /* Set serial number in the monitor dialog window */
+               /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */
+
+               state_block = log.start_block;
+               for (block = log.start_block; !done && block < log.end_block; block++) {
+                       monitor.set_value(state.state_name(),
+                                         state.state,
+                                         block - state_block,
+                                         block - log.start_block);
+
+                       AltosEepromChunk        eechunk = new AltosEepromChunk(link, block, block == log.start_block);
+
+                       /*
+                        * Guess what kind of data is there if the device
+                        * didn't tell us
+                        */
+
+                       if (log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN) {
+                               if (block == log.start_block) {
+                                       if (eechunk.data(0) == AltosLib.AO_LOG_FLIGHT)
+                                               log_format = AltosLib.AO_LOG_FORMAT_FULL;
+                                       else
+                                               log_format = AltosLib.AO_LOG_FORMAT_TINY;
+                               }
+                       }
+
+                       CaptureEeprom (eechunk, log_format);
+               }
+               CheckFile(true);
+               if (eeprom_file != null) {
+                       eeprom_file.flush();
+                       eeprom_file.close();
+               }
+       }
+
+       public void run () {
+               try {
+                       boolean failed = false;
+                       if (remote)
+                               link.start_remote();
+
+                       for (AltosEepromLog log : flights) {
+                               parse_exception = null;
+                               if (log.selected) {
+                                       monitor.reset();
+                                       try {
+                                               CaptureLog(log);
+                                       } catch (ParseException e) {
+                                               parse_exception = e;
+                                       }
+                               }
+                               if (parse_exception != null) {
+                                       failed = true;
+                                       monitor.show_message(String.format("Flight %d download error\n%s\nValid log data saved",
+                                                                          log.flight,
+                                                                          parse_exception.getMessage()),
+                                                            link.name,
+                                                            AltosEepromMonitor.WARNING_MESSAGE);
+                               }
+                       }
+                       success = !failed;
+               } catch (IOException ee) {
+                       monitor.show_message(ee.getLocalizedMessage(),
+                                            link.name,
+                                            AltosEepromMonitor.ERROR_MESSAGE);
+               } catch (InterruptedException ie) {
+                       monitor.show_message(String.format("Connection to \"%s\" interrupted",
+                                                          link.name),
+                                            "Connection Interrupted",
+                                            AltosEepromMonitor.ERROR_MESSAGE);
+               } catch (TimeoutException te) {
+                       monitor.show_message(String.format("Connection to \"%s\" failed",
+                                                          link.name),
+                                            "Connection Failed",
+                                            AltosEepromMonitor.ERROR_MESSAGE);
+               } finally {
+                       if (remote) {
+                               try {
+                                       link.stop_remote();
+                               } catch (InterruptedException ie) {
+                               }
+                       }
+                       link.flush_output();
+               }
+               monitor.done(success);
+       }
+
+       public void start() {
+               eeprom_thread = new Thread(this);
+               monitor.set_thread(eeprom_thread);
+               eeprom_thread.start();
+       }
+
+       public AltosEepromDownload(AltosEepromMonitor given_monitor,
+                                  AltosLink given_link,
+                                  boolean given_remote,
+                                  AltosEepromList given_flights) {
+
+               monitor = given_monitor;
+               link = given_link;
+               remote = given_remote;
+               flights = given_flights;
+               success = false;
+
+               monitor.set_states(AltosLib.ao_flight_boost, AltosLib.ao_flight_landed);
+
+               monitor.start();
+       }
+}
diff --git a/altoslib/AltosEepromFile.java b/altoslib/AltosEepromFile.java
new file mode 100644 (file)
index 0000000..60ab257
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+class AltosEepromIterator implements Iterator<AltosState> {
+       AltosState              state;
+       Iterator<AltosEeprom>   body;
+       AltosEeprom             next;
+       boolean                 seen;
+
+       public boolean hasNext() {
+               return !seen || body.hasNext();
+       }
+
+       public AltosState next() {
+               if (seen) {
+                       AltosState      n = state.clone();
+                       AltosEeprom     e = body.next();
+
+                       e.update_state(n);
+                       state = n;
+               }
+               seen = true;
+               return state;
+       }
+
+       public void remove () {
+       }
+
+       public AltosEepromIterator(AltosState start, Iterator<AltosEeprom> body) {
+               this.state = start;
+               this.body = body;
+               this.seen = false;
+       }
+}
+
+public class AltosEepromFile extends AltosStateIterable {
+
+       AltosEepromIterable     headers;
+       AltosEepromIterable     body;
+       AltosState              start;
+
+       public void write_comments(PrintStream out) {
+               headers.write(out);
+       }
+
+       public void write(PrintStream out) {
+               headers.write(out);
+               body.write(out);
+       }
+
+       public AltosEepromFile(FileInputStream input) {
+               headers = new AltosEepromIterable(AltosEepromHeader.read(input));
+
+               start = headers.state();
+               start.set_state(AltosLib.ao_flight_pad);
+
+               switch (start.log_format) {
+               case AltosLib.AO_LOG_FORMAT_FULL:
+                       body = new AltosEepromIterable(AltosEepromTM.read(input));
+                       break;
+               case AltosLib.AO_LOG_FORMAT_TINY:
+                       body = new AltosEepromIterable(AltosEepromTm.read(input));
+                       break;
+               case AltosLib.AO_LOG_FORMAT_TELEMETRY:
+               case AltosLib.AO_LOG_FORMAT_TELESCIENCE:
+               case AltosLib.AO_LOG_FORMAT_TELEMEGA:
+                       body = new AltosEepromIterable(AltosEepromMega.read(input));
+                       break;
+               case AltosLib.AO_LOG_FORMAT_TELEMETRUM:
+                       body = new AltosEepromIterable(AltosEepromMetrum2.read(input));
+                       break;
+               case AltosLib.AO_LOG_FORMAT_TELEMINI:
+               case AltosLib.AO_LOG_FORMAT_EASYMINI:
+                       body = new AltosEepromIterable(AltosEepromMini.read(input));
+                       break;
+               default:
+                       body = new AltosEepromIterable(new LinkedList<AltosEeprom>());
+                       break;
+               }
+
+               /* Find boost tick */
+               AltosState      state = start.clone();
+               for (AltosEeprom eeprom : body) {
+                       eeprom.update_state(state);
+                       state.finish_update();
+                       if (state.state >= AltosLib.ao_flight_boost) {
+                               start.set_boost_tick(state.tick);
+                               break;
+                       }
+               }
+       }
+
+       public Iterator<AltosState> iterator() {
+               AltosState              state = start.clone();
+               Iterator<AltosEeprom>   i = body.iterator();
+
+               while (i.hasNext() && !state.valid()) {
+                       i.next().update_state(state);
+                       state.finish_update();
+               }
+               return new AltosEepromIterator(state, i);
+       }
+}
\ No newline at end of file
diff --git a/altoslib/AltosEepromHeader.java b/altoslib/AltosEepromHeader.java
new file mode 100644 (file)
index 0000000..0aeb78d
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromHeader extends AltosEeprom {
+
+       public int      cmd;
+       public String   data;
+       public int      config_a, config_b;
+       public boolean  last;
+       public boolean  valid;
+
+       public int record_length () { return 0; }
+
+       /* XXX pull rest of config data to state */
+       public void update_state(AltosState state) {
+               switch (cmd) {
+               case AltosLib.AO_LOG_CONFIG_VERSION:
+                       break;
+               case AltosLib.AO_LOG_MAIN_DEPLOY:
+                       break;
+               case AltosLib.AO_LOG_APOGEE_DELAY:
+                       break;
+               case AltosLib.AO_LOG_RADIO_CHANNEL:
+                       break;
+               case AltosLib.AO_LOG_CALLSIGN:
+                       state.set_callsign(data);
+                       break;
+               case AltosLib.AO_LOG_ACCEL_CAL:
+                       state.set_accel_g(config_a, config_b);
+                       break;
+               case AltosLib.AO_LOG_RADIO_CAL:
+                       break;
+               case AltosLib.AO_LOG_MANUFACTURER:
+                       break;
+               case AltosLib.AO_LOG_PRODUCT:
+                       break;
+               case AltosLib.AO_LOG_LOG_FORMAT:
+                       state.log_format = config_a;
+                       break;
+               case AltosLib.AO_LOG_SERIAL_NUMBER:
+                       state.set_serial(config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_RESERVED:
+                       state.make_baro();
+                       state.baro.reserved = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_SENS:
+                       state.make_baro();
+                       state.baro.sens = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_OFF:
+                       state.make_baro();
+                       state.baro.off = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TCS:
+                       state.make_baro();
+                       state.baro.tcs = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TCO:
+                       state.make_baro();
+                       state.baro.tco = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TREF:
+                       state.make_baro();
+                       state.baro.tref = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TEMPSENS:
+                       state.make_baro();
+                       state.baro.tempsens = config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_CRC:
+                       state.make_baro();
+                       state.baro.crc = config_a;
+                       break;
+               case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                       state.set_firmware_version(data);
+                       break;
+               }
+       }
+
+       public void write(PrintStream out) {
+               switch (cmd) {
+               case AltosLib.AO_LOG_CONFIG_VERSION:
+                       out.printf("# Config version: %s\n", data);
+                       break;
+               case AltosLib.AO_LOG_MAIN_DEPLOY:
+                       out.printf("# Main deploy: %s\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_APOGEE_DELAY:
+                       out.printf("# Apogee delay: %s\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_RADIO_CHANNEL:
+                       out.printf("# Radio channel: %s\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_CALLSIGN:
+                       out.printf("# Callsign: %s\n", data);
+                       break;
+               case AltosLib.AO_LOG_ACCEL_CAL:
+                       out.printf ("# Accel cal: %d %d\n", config_a, config_b);
+                       break;
+               case AltosLib.AO_LOG_RADIO_CAL:
+                       out.printf ("# Radio cal: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
+                       out.printf ("# Max flight log: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_MANUFACTURER:
+                       out.printf ("# Manufacturer: %s\n", data);
+                       break;
+               case AltosLib.AO_LOG_PRODUCT:
+                       out.printf ("# Product: %s\n", data);
+                       break;
+               case AltosLib.AO_LOG_SERIAL_NUMBER:
+                       out.printf ("# Serial number: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                       out.printf ("# Software version: %s\n", data);
+                       break;
+               case AltosLib.AO_LOG_BARO_RESERVED:
+                       out.printf ("# Baro reserved: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_SENS:
+                       out.printf ("# Baro sens: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_OFF:
+                       out.printf ("# Baro off: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_TCS:
+                       out.printf ("# Baro tcs: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_TCO:
+                       out.printf ("# Baro tco: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_TREF:
+                       out.printf ("# Baro tref: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_TEMPSENS:
+                       out.printf ("# Baro tempsens: %d\n", config_a);
+                       break;
+               case AltosLib.AO_LOG_BARO_CRC:
+                       out.printf ("# Baro crc: %d\n", config_a);
+                       break;
+               }
+       }
+       
+       public AltosEepromHeader (String[] tokens) {
+               last = false;
+               valid = true;
+               try {
+                       if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
+                               cmd = AltosLib.AO_LOG_CONFIG_VERSION;
+                               data = tokens[2];
+                       } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
+                               cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
+                               config_a = Integer.parseInt(tokens[2]);
+                       } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
+                               cmd = AltosLib.AO_LOG_APOGEE_DELAY;
+                               config_a = Integer.parseInt(tokens[2]);
+                       } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
+                               cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
+                               config_a = Integer.parseInt(tokens[2]);
+                       } else if (tokens[0].equals("Callsign:")) {
+                               cmd = AltosLib.AO_LOG_CALLSIGN;
+                               data = tokens[1].replaceAll("\"","");
+                       } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
+                               cmd = AltosLib.AO_LOG_ACCEL_CAL;
+                               config_a = Integer.parseInt(tokens[3]);
+                               config_b = Integer.parseInt(tokens[5]);
+                       } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
+                               cmd = AltosLib.AO_LOG_RADIO_CAL;
+                               config_a = Integer.parseInt(tokens[2]);
+                       } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
+                               cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
+                               config_a = Integer.parseInt(tokens[3]);
+                       } else if (tokens[0].equals("manufacturer")) {
+                               cmd = AltosLib.AO_LOG_MANUFACTURER;
+                               data = tokens[1];
+                       } else if (tokens[0].equals("product")) {
+                               cmd = AltosLib.AO_LOG_PRODUCT;
+                               data = tokens[1];
+                       } else if (tokens[0].equals("serial-number")) {
+                               cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
+                               config_a = Integer.parseInt(tokens[1]);
+                       } else if (tokens[0].equals("log-format")) {
+                               cmd = AltosLib.AO_LOG_LOG_FORMAT;
+                               config_a = Integer.parseInt(tokens[1]);
+                       } else if (tokens[0].equals("software-version")) {
+                               cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
+                               data = tokens[1];
+                               last = true;
+                       } else if (tokens[0].equals("ms5607")) {
+                               if (tokens[1].equals("reserved:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_RESERVED;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("sens:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_SENS;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("off:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_OFF;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("tcs:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_TCS;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("tco:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_TCO;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("tref:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_TREF;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("tempsens:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_TEMPSENS;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[1].equals("crc:")) {
+                                       cmd = AltosLib.AO_LOG_BARO_CRC;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else {
+                                       cmd = AltosLib.AO_LOG_INVALID;
+                                       data = tokens[2];
+                               }
+                       } else
+                               valid = false;
+               } catch (Exception e) {
+                       valid = false;
+               }
+       }
+
+       static public LinkedList<AltosEeprom> read(FileInputStream input) {
+               LinkedList<AltosEeprom> headers = new LinkedList<AltosEeprom>();
+
+               for (;;) {
+                       try {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               AltosEepromHeader header = new AltosEepromHeader(line);
+                               headers.add(header);
+                               if (header.last)
+                                       break;
+                       } catch (IOException ie) {
+                               break;
+                       }
+               }
+
+               return headers;
+       }
+
+       static public void write (PrintStream out, LinkedList<AltosEepromHeader> headers) {
+               out.printf("# Comments\n");
+               for (AltosEepromHeader header : headers) {
+                       header.write(out);
+               }
+               
+       }
+
+       public AltosEepromHeader (String line) {
+               this(line.split("\\s+"));
+       }
+}
index b84574ef9647261ea724d9510f0946f03469f544..fc793579f41837469a54c8924a6b85025d9c23e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2010 Keith Packard <keithp@keithp.com>
+ * 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
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 import java.util.*;
 import java.text.*;
 
-public class AltosEepromIterable extends AltosRecordIterable {
+class AltosEepromOrdered implements Comparable<AltosEepromOrdered> {
+       AltosEeprom     eeprom;
+       int             index;
+       int             tick;
 
-       static final int        seen_basic = AltosRecord.seen_flight|AltosRecord.seen_sensor;
-
-       boolean                 has_accel;
-       boolean                 has_gps;
-       boolean                 has_ignite;
-
-       AltosEepromRecord       flight_record;
-       AltosEepromRecord       gps_date_record;
-
-       TreeSet<AltosOrderedRecord>     records;
-
-       LinkedList<AltosRecord> list;
-
-       class EepromState {
-               int     seen;
-               int     n_pad_samples;
-               double  ground_pres;
-               int     gps_tick;
-               int     boost_tick;
-               int     sensor_tick;
-
-               EepromState() {
-                       seen = 0;
-                       n_pad_samples = 0;
-                       ground_pres = 0.0;
-                       gps_tick = 0;
-               }
+       int cmdi() {
+               if (eeprom.cmd == AltosLib.AO_LOG_FLIGHT)
+                       return 0;
+               return 1;
        }
 
-       void update_state(AltosRecordTM state, AltosEepromRecord record, EepromState eeprom) {
-               state.tick = record.tick;
-               switch (record.cmd) {
-               case AltosLib.AO_LOG_FLIGHT:
-                       eeprom.seen |= AltosRecord.seen_flight;
-                       state.ground_accel = record.a;
-                       state.flight_accel = record.a;
-                       state.flight = record.b;
-                       eeprom.boost_tick = record.tick;
-                       break;
-               case AltosLib.AO_LOG_SENSOR:
-                       state.accel = record.a;
-                       state.pres = record.b;
-                       if (state.state < AltosLib.ao_flight_boost) {
-                               eeprom.n_pad_samples++;
-                               eeprom.ground_pres += state.pres;
-                               state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
-                               state.flight_pres = state.ground_pres;
-                       } else {
-                               state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
-                       }
-                       state.flight_accel = (state.flight_accel * 15 + state.accel) / 16;
-                       if ((eeprom.seen & AltosRecord.seen_sensor) == 0)
-                               eeprom.sensor_tick = record.tick - 1;
-                       state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick);
-                       eeprom.seen |= AltosRecord.seen_sensor;
-                       eeprom.sensor_tick = record.tick;
-                       has_accel = true;
-                       break;
-               case AltosLib.AO_LOG_PRESSURE:
-                       state.pres = record.b;
-                       state.flight_pres = state.pres;
-                       if (eeprom.n_pad_samples == 0) {
-                               eeprom.n_pad_samples++;
-                               state.ground_pres = state.pres;
-                       }
-                       eeprom.seen |= AltosRecord.seen_sensor;
-                       break;
-               case AltosLib.AO_LOG_TEMP_VOLT:
-                       state.temp = record.a;
-                       state.batt = record.b;
-                       eeprom.seen |= AltosRecord.seen_temp_volt;
-                       break;
-               case AltosLib.AO_LOG_DEPLOY:
-                       state.drogue = record.a;
-                       state.main = record.b;
-                       eeprom.seen |= AltosRecord.seen_deploy;
-                       has_ignite = true;
-                       break;
-               case AltosLib.AO_LOG_STATE:
-                       state.state = record.a;
-                       break;
-               case AltosLib.AO_LOG_GPS_TIME:
-                       eeprom.gps_tick = state.tick;
-                       eeprom.seen |= AltosRecord.seen_gps_time;
-                       AltosGPS old = state.gps;
-                       state.gps = new AltosGPS();
+       public int compareTo(AltosEepromOrdered o) {
+               int     cmd_diff = cmdi() - o.cmdi();
 
-                       /* GPS date doesn't get repeated through the file */
-                       if (old != null) {
-                               state.gps.year = old.year;
-                               state.gps.month = old.month;
-                               state.gps.day = old.day;
-                       }
-                       state.gps.hour = (record.a & 0xff);
-                       state.gps.minute = (record.a >> 8);
-                       state.gps.second = (record.b & 0xff);
+               if (cmd_diff != 0)
+                       return cmd_diff;
 
-                       int flags = (record.b >> 8);
-                       state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
-                       state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
-                       state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
-                               AltosLib.AO_GPS_NUM_SAT_SHIFT;
-                       state.gps_sequence++;
-                       has_gps = true;
-                       break;
-               case AltosLib.AO_LOG_GPS_LAT:
-                       eeprom.seen |= AltosRecord.seen_gps_lat;
-                       int lat32 = record.a | (record.b << 16);
-                       if (state.gps == null)
-                               state.gps = new AltosGPS();
-                       state.gps.lat = (double) lat32 / 1e7;
-                       break;
-               case AltosLib.AO_LOG_GPS_LON:
-                       eeprom.seen |= AltosRecord.seen_gps_lon;
-                       int lon32 = record.a | (record.b << 16);
-                       if (state.gps == null)
-                               state.gps = new AltosGPS();
-                       state.gps.lon = (double) lon32 / 1e7;
-                       break;
-               case AltosLib.AO_LOG_GPS_ALT:
-                       if (state.gps == null)
-                               state.gps = new AltosGPS();
-                       state.gps.alt = record.a;
-                       break;
-               case AltosLib.AO_LOG_GPS_SAT:
-                       if (state.tick == eeprom.gps_tick) {
-                               int svid = record.a;
-                               int c_n0 = record.b >> 8;
-                               if (state.gps == null)
-                                       state.gps = new AltosGPS();
-                               state.gps.add_sat(svid, c_n0);
-                       }
-                       break;
-               case AltosLib.AO_LOG_GPS_DATE:
-                       if (state.gps == null)
-                               state.gps = new AltosGPS();
-                       state.gps.year = (record.a & 0xff) + 2000;
-                       state.gps.month = record.a >> 8;
-                       state.gps.day = record.b & 0xff;
-                       break;
+               int     tick_diff = tick - o.tick;
 
-               case AltosLib.AO_LOG_CONFIG_VERSION:
-                       break;
-               case AltosLib.AO_LOG_MAIN_DEPLOY:
-                       break;
-               case AltosLib.AO_LOG_APOGEE_DELAY:
-                       break;
-               case AltosLib.AO_LOG_RADIO_CHANNEL:
-                       break;
-               case AltosLib.AO_LOG_CALLSIGN:
-                       state.callsign = record.data;
-                       break;
-               case AltosLib.AO_LOG_ACCEL_CAL:
-                       state.accel_plus_g = record.a;
-                       state.accel_minus_g = record.b;
-                       break;
-               case AltosLib.AO_LOG_RADIO_CAL:
-                       break;
-               case AltosLib.AO_LOG_MANUFACTURER:
-                       break;
-               case AltosLib.AO_LOG_PRODUCT:
-                       break;
-               case AltosLib.AO_LOG_SERIAL_NUMBER:
-                       state.serial = record.a;
-                       break;
-               case AltosLib.AO_LOG_SOFTWARE_VERSION:
-                       break;
-               }
-               state.seen |= eeprom.seen;
+               if (tick_diff != 0)
+                       return tick_diff;
+               return index - o.index;
        }
 
-       LinkedList<AltosRecord> make_list() {
-               LinkedList<AltosRecord>         list = new LinkedList<AltosRecord>();
-               Iterator<AltosOrderedRecord>    iterator = records.iterator();
-               AltosOrderedRecord              record = null;
-               AltosRecordTM                   state = new AltosRecordTM();
-               //boolean                               last_reported = false;
-               EepromState                     eeprom = new EepromState();
-
-               state.state = AltosLib.ao_flight_pad;
-               state.accel_plus_g = 15758;
-               state.accel_minus_g = 16294;
-               state.flight_vel = 0;
-
-               /* Pull in static data from the flight and gps_date records */
-               if (flight_record != null)
-                       update_state(state, flight_record, eeprom);
-               if (gps_date_record != null)
-                       update_state(state, gps_date_record, eeprom);
+       AltosEepromOrdered (AltosEeprom eeprom, int index, int tick) {
+               this.eeprom = eeprom;
+               this.index = index;
+               this.tick = tick;
+       }
+}
 
-               while (iterator.hasNext()) {
-                       record = iterator.next();
-                       if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
-                               AltosRecordTM r = state.clone();
-                               r.time = (r.tick - eeprom.boost_tick) / 100.0;
-                               list.add(r);
+class AltosEepromOrderedIterator implements Iterator<AltosEeprom> {
+       TreeSet<AltosEepromOrdered>     olist;
+       Iterator<AltosEepromOrdered>    oiterator;
+
+       public AltosEepromOrderedIterator(Iterable<AltosEeprom> eeproms) {
+               olist = new TreeSet<AltosEepromOrdered>();
+
+               int     tick = 0;
+               int     index = 0;
+               boolean first = true;
+
+               for (AltosEeprom e : eeproms) {
+                       int     t = e.tick;
+                       if (first)
+                               tick = t;
+                       else {
+                               while (t < tick - 32767)
+                                       t += 65536;
+                               tick = t;
                        }
-                       update_state(state, record, eeprom);
+                       olist.add(new AltosEepromOrdered(e, index++, tick));
+                       first = false;
                }
-               AltosRecordTM r = state.clone();
-               r.time = (r.tick - eeprom.boost_tick) / 100.0;
-               list.add(r);
-       return list;
-       }
 
-       public Iterator<AltosRecord> iterator() {
-               if (list == null)
-                       list = make_list();
-               return list.iterator();
+               oiterator = olist.iterator();
        }
 
-       public boolean has_gps() { return has_gps; }
-       public boolean has_accel() { return has_accel; }
-       public boolean has_ignite() { return has_ignite; }
-
-       public void write_comments(PrintStream out) {
-               Iterator<AltosOrderedRecord>    iterator = records.iterator();
-               out.printf("# Comments\n");
-               while (iterator.hasNext()) {
-                       AltosOrderedRecord      record = iterator.next();
-                       switch (record.cmd) {
-                       case AltosLib.AO_LOG_CONFIG_VERSION:
-                               out.printf("# Config version: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_MAIN_DEPLOY:
-                               out.printf("# Main deploy: %s\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_APOGEE_DELAY:
-                               out.printf("# Apogee delay: %s\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_RADIO_CHANNEL:
-                               out.printf("# Radio channel: %s\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_CALLSIGN:
-                               out.printf("# Callsign: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_ACCEL_CAL:
-                               out.printf ("# Accel cal: %d %d\n", record.a, record.b);
-                               break;
-                       case AltosLib.AO_LOG_RADIO_CAL:
-                               out.printf ("# Radio cal: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
-                               out.printf ("# Max flight log: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_MANUFACTURER:
-                               out.printf ("# Manufacturer: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_PRODUCT:
-                               out.printf ("# Product: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_SERIAL_NUMBER:
-                               out.printf ("# Serial number: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_SOFTWARE_VERSION:
-                               out.printf ("# Software version: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_BARO_RESERVED:
-                               out.printf ("# Baro reserved: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_SENS:
-                               out.printf ("# Baro sens: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_OFF:
-                               out.printf ("# Baro off: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TCS:
-                               out.printf ("# Baro tcs: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TCO:
-                               out.printf ("# Baro tco: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TREF:
-                               out.printf ("# Baro tref: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TEMPSENS:
-                               out.printf ("# Baro tempsens: %d\n", record.a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_CRC:
-                               out.printf ("# Baro crc: %d\n", record.a);
-                               break;
-                       }
-               }
+       public boolean hasNext() {
+               return oiterator.hasNext();
        }
 
-       /*
-        * Given an AO_LOG_GPS_TIME record with correct time, and one
-        * missing time, rewrite the missing time values with the good
-        * ones, assuming that the difference between them is 'diff' seconds
-        */
-       void update_time(AltosOrderedRecord good, AltosOrderedRecord bad) {
-
-               int diff = (bad.tick - good.tick + 50) / 100;
-
-               int hour = (good.a & 0xff);
-               int minute = (good.a >> 8);
-               int second = (good.b & 0xff);
-               int flags = (good.b >> 8);
-               int seconds = hour * 3600 + minute * 60 + second;
-
-               /* Make sure this looks like a good GPS value */
-               if ((flags & AltosLib.AO_GPS_NUM_SAT_MASK) >> AltosLib.AO_GPS_NUM_SAT_SHIFT < 4)
-                       flags = (flags & ~AltosLib.AO_GPS_NUM_SAT_MASK) | (4 << AltosLib.AO_GPS_NUM_SAT_SHIFT);
-               flags |= AltosLib.AO_GPS_RUNNING;
-               flags |= AltosLib.AO_GPS_VALID;
-
-               int new_seconds = seconds + diff;
-               if (new_seconds < 0)
-                       new_seconds += 24 * 3600;
-               int new_second = (new_seconds % 60);
-               int new_minutes = (new_seconds / 60);
-               int new_minute = (new_minutes % 60);
-               int new_hours = (new_minutes / 60);
-               int new_hour = (new_hours % 24);
-
-               bad.a = new_hour + (new_minute << 8);
-               bad.b = new_second + (flags << 8);
+       public AltosEeprom next() {
+               return oiterator.next().eeprom;
        }
 
-       /*
-        * Read the whole file, dumping records into a RB tree so
-        * we can enumerate them in time order -- the eeprom data
-        * are sometimes out of order with GPS data getting timestamps
-        * matching the first packet out of the GPS unit but not
-        * written until the final GPS packet has been received.
-        */
-       public AltosEepromIterable (FileInputStream input) {
-               records = new TreeSet<AltosOrderedRecord>();
-
-               AltosOrderedRecord last_gps_time = null;
-
-               int index = 0;
-               int prev_tick = 0;
-               boolean prev_tick_valid = false;
-               boolean missing_time = false;
+       public void remove () {
+       }
+}
 
-               try {
-                       for (;;) {
-                               String line = AltosLib.gets(input);
-                               if (line == null)
-                                       break;
-                               AltosOrderedRecord record = new AltosOrderedRecord(line, index++, prev_tick, prev_tick_valid);
-                               if (record.cmd == AltosLib.AO_LOG_INVALID)
-                                       continue;
-                               prev_tick = record.tick;
-                               if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION)
-                                       prev_tick_valid = true;
-                               if (record.cmd == AltosLib.AO_LOG_FLIGHT) {
-                                       flight_record = record;
-                                       continue;
-                               }
+public class AltosEepromIterable implements Iterable<AltosEeprom> {
+       public LinkedList<AltosEeprom> eeproms;
 
-                               /* Two firmware bugs caused the loss of some GPS data.
-                                * The flight date would never be recorded, and often
-                                * the flight time would get overwritten by another
-                                * record. Detect the loss of the GPS date and fix up the
-                                * missing time records
-                                */
-                               if (record.cmd == AltosLib.AO_LOG_GPS_DATE) {
-                                       gps_date_record = record;
-                                       continue;
-                               }
+       public void write(PrintStream out) {
+               for (AltosEeprom eeprom : eeproms)
+                       eeprom.write(out);
+       }
 
-                               /* go back and fix up any missing time values */
-                               if (record.cmd == AltosLib.AO_LOG_GPS_TIME) {
-                                       last_gps_time = record;
-                                       if (missing_time) {
-                                               Iterator<AltosOrderedRecord> iterator = records.iterator();
-                                               while (iterator.hasNext()) {
-                                                       AltosOrderedRecord old = iterator.next();
-                                                       if (old.cmd == AltosLib.AO_LOG_GPS_TIME &&
-                                                           old.a == -1 && old.b == -1)
-                                                       {
-                                                               update_time(record, old);
-                                                       }
-                                               }
-                                               missing_time = false;
-                                       }
-                               }
+       public AltosState state() {
+               AltosState      state = new AltosState();
 
-                               if (record.cmd == AltosLib.AO_LOG_GPS_LAT) {
-                                       if (last_gps_time == null || last_gps_time.tick != record.tick) {
-                                               AltosOrderedRecord add_gps_time = new AltosOrderedRecord(AltosLib.AO_LOG_GPS_TIME,
-                                                                                                        record.tick,
-                                                                                                        -1, -1, index-1);
-                                               if (last_gps_time != null)
-                                                       update_time(last_gps_time, add_gps_time);
-                                               else
-                                                       missing_time = true;
+               for (AltosEeprom header : eeproms)
+                       header.update_state(state);
+               return state;
+       }
 
-                                               records.add(add_gps_time);
-                                               record.index = index++;
-                                       }
-                               }
-                               records.add(record);
+       public AltosEepromIterable(LinkedList<AltosEeprom> eeproms) {
+               this.eeproms = eeproms;
+       }
 
-                               /* Bail after reading the 'landed' record; we're all done */
-                               if (record.cmd == AltosLib.AO_LOG_STATE &&
-                                   record.a == AltosLib.ao_flight_landed)
-                                       break;
-                       }
-               } catch (IOException io) {
-               } catch (ParseException pe) {
-               }
-               try {
-                       input.close();
-               } catch (IOException ie) {
-               }
+       public Iterator<AltosEeprom> iterator() {
+               if (eeproms == null)
+                       eeproms = new LinkedList<AltosEeprom>();
+               return new AltosEepromOrderedIterator(eeproms);
        }
-}
+}
\ No newline at end of file
diff --git a/altoslib/AltosEepromList.java b/altoslib/AltosEepromList.java
new file mode 100644 (file)
index 0000000..763bd1e
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.concurrent.*;
+
+/*
+ * Temporary structure to hold the list of stored flights;
+ * each of these will be queried in turn to generate more
+ * complete information
+ */
+
+class AltosEepromFlight {
+       int     flight;
+       int     start;
+       int     end;
+
+       public AltosEepromFlight(int in_flight, int in_start, int in_end) {
+               flight = in_flight;
+               start = in_start;
+               end = in_end;
+       }
+}
+
+/*
+ * Construct a list of flights available in a connected device
+ */
+
+public class AltosEepromList extends ArrayList<AltosEepromLog> {
+       public AltosConfigData  config_data;
+
+       public AltosEepromList (AltosLink link, boolean remote)
+               throws IOException, InterruptedException, TimeoutException
+       {
+               try {
+                       if (remote)
+                               link.start_remote();
+                       config_data = new AltosConfigData (link);
+//                     if (config_data.serial == 0)
+//                             throw new IOException("no serial number found");
+
+                       ArrayList<AltosEepromFlight> flights = new ArrayList<AltosEepromFlight>();
+
+                       if (config_data.flight_log_max != 0 || config_data.log_format != 0) {
+
+                               /* Devices with newer firmware will support the 'l'
+                                * command which will list the region of storage
+                                * occupied by each available flight
+                                */
+                               link.printf("l\n");
+                               for (;;) {
+                                       String line = link.get_reply(5000);
+                                       if (line == null)
+                                               throw new TimeoutException();
+                                       if (line.contains("done"))
+                                               break;
+                                       if (line.contains("Syntax"))
+                                               continue;
+                                       String[] tokens = line.split("\\s+");
+                                       if (tokens.length < 6)
+                                               break;
+
+                                       int     flight = -1, start = -1, end = -1;
+                                       try {
+                                               if (tokens[0].equals("flight"))
+                                                       flight = AltosParse.parse_int(tokens[1]);
+                                               if (tokens[2].equals("start"))
+                                                       start = AltosParse.parse_hex(tokens[3]);
+                                               if (tokens[4].equals("end"))
+                                                       end = AltosParse.parse_hex(tokens[5]);
+                                               if (flight > 0 && start >= 0 && end > 0)
+                                                       flights.add(new AltosEepromFlight(flight, start, end));
+                                       } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); }
+                               }
+                       } else {
+
+                               /* Older devices will hold only a single
+                                * flight. This also assumes that any older
+                                * device will have a 1MB flash device
+                                */
+                               flights.add(new AltosEepromFlight(0, 0, 0xfff));
+                       }
+
+                       /* With the list of flights collected, collect more complete
+                        * information on them by reading the first block or two of
+                        * data. This will add GPS coordinates and a date. For older
+                        * firmware, this will also extract the flight number.
+                        */
+                       for (AltosEepromFlight flight : flights) {
+                               add(new AltosEepromLog(config_data, link,
+                                                      flight.flight, flight.start, flight.end));
+                       }
+               } finally {
+                       if (remote)
+                               link.stop_remote();
+                       link.flush_output();
+               }
+       }
+}
\ No newline at end of file
index 20026c6d33139a76b4c8014f15e284defd0c3b48..95c0c3f6c5bcb272ba8db7b8cfbd89b8640d198c 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.text.*;
 import java.util.concurrent.*;
@@ -72,9 +72,9 @@ public class AltosEepromLog {
                        for (block = in_start_block; block < in_end_block; block++) {
                                AltosEepromChunk eechunk = new AltosEepromChunk(link, block, block == in_start_block);
 
-                               for (int i = 0; i < AltosEepromChunk.chunk_size; i += AltosEepromRecord.record_length) {
+                               for (int i = 0; i < AltosEepromChunk.chunk_size; i += AltosEepromTM.record_length) {
                                        try {
-                                               AltosEepromRecord r = new AltosEepromRecord(eechunk, i);
+                                               AltosEepromTM r = new AltosEepromTM(eechunk, i);
 
                                                if (r.cmd == AltosLib.AO_LOG_FLIGHT) {
                                                        flight = r.b;
index b077e26cefd582d104963478d7eab42c633d06bd..7a4ee52d10680e1e61c3289bb029a12e079b444c 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
+import java.io.*;
+import java.util.*;
 import java.text.*;
 
-public class AltosEepromMega {
-       public int      cmd;
-       public int      tick;
-       public boolean  valid;
-       public String   data;
-       public int      config_a, config_b;
-
-       public int      data8[];
-
+public class AltosEepromMega extends AltosEeprom {
        public static final int record_length = 32;
-       static final int        header_length = 4;
-       static final int        data_length = record_length - header_length;
-
-       public int data8(int i) {
-               return data8[i];
-       }
 
-       public int data16(int i) {
-               return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16;
-       }
-
-       public int data32(int i) {
-               return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24);
-       }
+       public int record_length() { return record_length; }
 
        /* AO_LOG_FLIGHT elements */
        public int flight() { return data16(0); }
@@ -68,11 +50,12 @@ public class AltosEepromMega {
        public int mag_z() { return data16(24); }
        public int accel() { return data16(26); }
 
-       /* AO_LOG_VOLT elements */
+       /* AO_LOG_TEMP_VOLT elements */
        public int v_batt() { return data16(0); }
        public int v_pbatt() { return data16(2); }
        public int nsense() { return data16(4); }
        public int sense(int i) { return data16(6 + i * 2); }
+       public int pyro() { return data16(26); }
 
        /* AO_LOG_GPS_TIME elements */
        public int latitude() { return data32(0); }
@@ -90,131 +73,139 @@ public class AltosEepromMega {
        public int nsat() { return data16(0); }
        public int svid(int n) { return data8(2 + n * 2); }
        public int c_n(int n) { return data8(2 + n * 2 + 1); }
+
        public AltosEepromMega (AltosEepromChunk chunk, int start) throws ParseException {
-               cmd = chunk.data(start);
-
-               valid = !chunk.erased(start, record_length);
-               if (valid) {
-                       if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
-                               throw new ParseException(String.format("invalid checksum at 0x%x",
-                                                                      chunk.address + start), 0);
-               } else {
-                       cmd = AltosLib.AO_LOG_INVALID;
-               }
+               parse_chunk(chunk, start);
+       }
 
-               tick = chunk.data16(start+2);
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               AltosGPS        gps;
+
+               /* Flush any pending GPS changes */
+               if (state.gps_pending) {
+                       switch (cmd) {
+                       case AltosLib.AO_LOG_GPS_LAT:
+                       case AltosLib.AO_LOG_GPS_LON:
+                       case AltosLib.AO_LOG_GPS_ALT:
+                       case AltosLib.AO_LOG_GPS_SAT:
+                       case AltosLib.AO_LOG_GPS_DATE:
+                               break;
+                       default:
+                               state.set_temp_gps();
+                               break;
+                       }
+               }
 
-               data8 = new int[data_length];
-               for (int i = 0; i < data_length; i++)
-                       data8[i] = chunk.data(start + header_length + i);
+               switch (cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       state.set_boost_tick(tick);
+                       state.set_flight(flight());
+                       state.set_ground_accel(ground_accel());
+                       state.set_ground_pressure(ground_pres());
+                       state.set_temperature(ground_temp() / 100.0);
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.set_tick(tick);
+                       state.set_state(state());
+                       break;
+               case AltosLib.AO_LOG_SENSOR:
+                       state.set_tick(tick);
+                       state.set_ms5607(pres(), temp());
+
+                       AltosIMU imu = new AltosIMU();
+                       imu.accel_x = accel_x();
+                       imu.accel_y = accel_y();
+                       imu.accel_z = accel_z();
+
+                       imu.gyro_x = gyro_x();
+                       imu.gyro_y = gyro_y();
+                       imu.gyro_z = gyro_z();
+                       state.imu = imu;
+
+                       AltosMag mag = new AltosMag();
+                       mag.x = mag_x();
+                       mag.y = mag_y();
+                       mag.z = mag_z();
+
+                       state.mag = mag;
+
+                       state.set_accel(accel());
+
+                       break;
+               case AltosLib.AO_LOG_TEMP_VOLT:
+                       state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt()));
+                       state.set_pyro_voltage(AltosConvert.mega_pyro_voltage(v_pbatt()));
+
+                       int nsense = nsense();
+
+                       state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense(nsense-2)));
+                       state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense(nsense-1)));
+
+                       double voltages[] = new double[nsense-2];
+                       for (int i = 0; i < nsense-2; i++)
+                               voltages[i] = AltosConvert.mega_pyro_voltage(sense(i));
+
+                       state.set_ignitor_voltage(voltages);
+                       break;
+               case AltosLib.AO_LOG_GPS_TIME:
+                       state.set_tick(tick);
+                       gps = state.make_temp_gps(false);
+                       gps.lat = latitude() / 1e7;
+                       gps.lon = longitude() / 1e7;
+                       gps.alt = altitude();
+
+                       gps.hour = hour();
+                       gps.minute = minute();
+                       gps.second = second();
+
+                       int flags = flags();
+
+                       gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
+                       gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
+                       gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
+                               AltosLib.AO_GPS_NUM_SAT_SHIFT;
+
+                       gps.year = 2000 + year();
+                       gps.month = month();
+                       gps.day = day();
+                       break;
+               case AltosLib.AO_LOG_GPS_SAT:
+                       state.set_tick(tick);
+                       gps = state.make_temp_gps(true);
+
+                       int n = nsat();
+                       for (int i = 0; i < n; i++)
+                               gps.add_sat(svid(i), c_n(i));
+                       break;
+               }
        }
 
        public AltosEepromMega (String line) {
-               valid = false;
-               tick = 0;
+               parse_string(line);
+       }
 
-               if (line == null) {
-                       cmd = AltosLib.AO_LOG_INVALID;
-                       line = "";
-               } else {
+       static public LinkedList<AltosEeprom> read(FileInputStream input) {
+               LinkedList<AltosEeprom> megas = new LinkedList<AltosEeprom>();
+
+               for (;;) {
                        try {
-                               String[] tokens = line.split("\\s+");
-
-                               if (tokens[0].length() == 1) {
-                                       if (tokens.length != 2 + data_length) {
-                                               cmd = AltosLib.AO_LOG_INVALID;
-                                               data = line;
-                                       } else {
-                                               cmd = tokens[0].codePointAt(0);
-                                               tick = Integer.parseInt(tokens[1],16);
-                                               valid = true;
-                                               data8 = new int[data_length];
-                                               for (int i = 0; i < data_length; i++)
-                                                       data8[i] = Integer.parseInt(tokens[2 + i],16);
-                                       }
-                               } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
-                                       cmd = AltosLib.AO_LOG_CONFIG_VERSION;
-                                       data = tokens[2];
-                               } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
-                                       cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
-                                       config_a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
-                                       cmd = AltosLib.AO_LOG_APOGEE_DELAY;
-                                       config_a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
-                                       cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
-                                       config_a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Callsign:")) {
-                                       cmd = AltosLib.AO_LOG_CALLSIGN;
-                                       data = tokens[1].replaceAll("\"","");
-                               } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
-                                       cmd = AltosLib.AO_LOG_ACCEL_CAL;
-                                       config_a = Integer.parseInt(tokens[3]);
-                                       config_b = Integer.parseInt(tokens[5]);
-                               } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
-                                       cmd = AltosLib.AO_LOG_RADIO_CAL;
-                                       config_a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
-                                       cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
-                                       config_a = Integer.parseInt(tokens[3]);
-                               } else if (tokens[0].equals("manufacturer")) {
-                                       cmd = AltosLib.AO_LOG_MANUFACTURER;
-                                       data = tokens[1];
-                               } else if (tokens[0].equals("product")) {
-                                       cmd = AltosLib.AO_LOG_PRODUCT;
-                                       data = tokens[1];
-                               } else if (tokens[0].equals("serial-number")) {
-                                       cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
-                                       config_a = Integer.parseInt(tokens[1]);
-                               } else if (tokens[0].equals("log-format")) {
-                                       cmd = AltosLib.AO_LOG_LOG_FORMAT;
-                                       config_a = Integer.parseInt(tokens[1]);
-                               } else if (tokens[0].equals("software-version")) {
-                                       cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
-                                       data = tokens[1];
-                               } else if (tokens[0].equals("ms5607")) {
-                                       if (tokens[1].equals("reserved:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_RESERVED;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("sens:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_SENS;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("off:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_OFF;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("tcs:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_TCS;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("tco:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_TCO;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("tref:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_TREF;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("tempsens:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_TEMPSENS;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else if (tokens[1].equals("crc:")) {
-                                               cmd = AltosLib.AO_LOG_BARO_CRC;
-                                               config_a = Integer.parseInt(tokens[2]);
-                                       } else {
-                                               cmd = AltosLib.AO_LOG_INVALID;
-                                               data = line;
-                                       }
-                               } else {
-                                       cmd = AltosLib.AO_LOG_INVALID;
-                                       data = line;
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               try {
+                                       AltosEepromMega mega = new AltosEepromMega(line);
+                                       if (mega.cmd != AltosLib.AO_LOG_INVALID)
+                                               megas.add(mega);
+                               } catch (Exception e) {
+                                       System.out.printf ("exception\n");
                                }
-                       } catch (NumberFormatException ne) {
-                               cmd = AltosLib.AO_LOG_INVALID;
-                               data = line;
+                       } catch (IOException ie) {
+                               break;
                        }
                }
-       }
 
-       public AltosEepromMega(int in_cmd, int in_tick) {
-               cmd = in_cmd;
-               tick = in_tick;
-               valid = true;
+               return megas;
        }
 }
diff --git a/altoslib/AltosEepromMegaIterable.java b/altoslib/AltosEepromMegaIterable.java
deleted file mode 100644 (file)
index 5736f93..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.io.*;
-import java.util.*;
-import java.text.*;
-
-public class AltosEepromMegaIterable extends AltosRecordIterable {
-
-       static final int        seen_flight = 1;
-       static final int        seen_sensor = 2;
-       static final int        seen_temp_volt = 4;
-       static final int        seen_deploy = 8;
-       static final int        seen_gps_time = 16;
-       static final int        seen_gps_lat = 32;
-       static final int        seen_gps_lon = 64;
-
-       static final int        seen_basic = seen_flight|seen_sensor;
-
-       boolean                 has_accel;
-       boolean                 has_gps;
-       boolean                 has_ignite;
-
-       AltosEepromMega flight_record;
-       AltosEepromMega gps_date_record;
-
-       TreeSet<AltosOrderedMegaRecord> records;
-
-       AltosMs5607             baro;
-
-       LinkedList<AltosRecord> list;
-
-       class EepromState {
-               int     seen;
-               int     n_pad_samples;
-               double  ground_pres;
-               int     gps_tick;
-               int     boost_tick;
-               int     sensor_tick;
-
-               EepromState() {
-                       seen = 0;
-                       n_pad_samples = 0;
-                       ground_pres = 0.0;
-                       gps_tick = 0;
-               }
-       }
-
-       void update_state(AltosRecordMM state, AltosEepromMega record, EepromState eeprom) {
-               state.tick = record.tick;
-               switch (record.cmd) {
-               case AltosLib.AO_LOG_FLIGHT:
-                       eeprom.seen |= seen_flight;
-                       state.ground_accel = record.ground_accel();
-                       state.flight_accel = record.ground_accel();
-                       state.ground_pres = baro.set(record.ground_pres(), record.ground_temp());
-                       state.flight_pres = state.ground_pres;
-                       state.flight = record.data16(0);
-                       eeprom.boost_tick = record.tick;
-                       break;
-               case AltosLib.AO_LOG_SENSOR:
-                       state.accel = record.accel();
-                       baro.set(record.pres(), record.temp());
-                       state.pres = baro.pa;
-                       state.temp = baro.cc;
-                       state.imu = new AltosIMU();
-                       state.imu.accel_x = record.accel_x();
-                       state.imu.accel_y = record.accel_y();
-                       state.imu.accel_z = record.accel_z();
-                       state.imu.gyro_x = record.gyro_x();
-                       state.imu.gyro_y = record.gyro_y();
-                       state.imu.gyro_z = record.gyro_z();
-                       state.mag = new AltosMag();
-                       state.mag.x = record.mag_x();
-                       state.mag.y = record.mag_y();
-                       state.mag.z = record.mag_z();
-                       if (state.state < AltosLib.ao_flight_boost) {
-                               eeprom.n_pad_samples++;
-                               eeprom.ground_pres += state.pres;
-                               state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
-                               state.flight_pres = state.ground_pres;
-                       } else {
-                               state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
-                       }
-                       state.flight_accel = (state.flight_accel * 15 + state.accel) / 16;
-                       if ((eeprom.seen & seen_sensor) == 0)
-                               eeprom.sensor_tick = record.tick - 1;
-                       state.flight_vel += (state.accel_plus_g - state.accel) * (record.tick - eeprom.sensor_tick);
-                       eeprom.seen |= seen_sensor;
-                       eeprom.sensor_tick = record.tick;
-                       has_accel = true;
-                       break;
-               case AltosLib.AO_LOG_TEMP_VOLT:
-                       state.v_batt = record.v_batt();
-                       state.v_pyro = record.v_pbatt();
-                       for (int i = 0; i < record.nsense(); i++)
-                               state.sense[i] = record.sense(i);
-                       eeprom.seen |= seen_temp_volt;
-                       break;
-               case AltosLib.AO_LOG_STATE:
-                       state.state = record.state();
-                       break;
-               case AltosLib.AO_LOG_GPS_TIME:
-                       eeprom.gps_tick = state.tick;
-                       state.gps = new AltosGPS();
-
-                       state.gps.lat = record.latitude() / 1e7;
-                       state.gps.lon = record.longitude() / 1e7;
-                       state.gps.alt = record.altitude();
-                       state.gps.year = record.year() + 2000;
-                       state.gps.month = record.month();
-                       state.gps.day = record.day();
-
-                       state.gps.hour = record.hour();
-                       state.gps.minute = record.minute();
-                       state.gps.second = record.second();
-
-                       int flags = record.flags();
-                       state.gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
-                       state.gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
-                       state.gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
-                               AltosLib.AO_GPS_NUM_SAT_SHIFT;
-                       state.gps_sequence++;
-                       has_gps = true;
-                       eeprom.seen |= seen_gps_time | seen_gps_lat | seen_gps_lon;
-                       break;
-               case AltosLib.AO_LOG_GPS_SAT:
-                       if (state.tick == eeprom.gps_tick) {
-                               int nsat = record.nsat();
-                               for (int i = 0; i < nsat; i++)
-                                       state.gps.add_sat(record.svid(i), record.c_n(i));
-                       }
-                       break;
-               case AltosLib.AO_LOG_CONFIG_VERSION:
-                       break;
-               case AltosLib.AO_LOG_MAIN_DEPLOY:
-                       break;
-               case AltosLib.AO_LOG_APOGEE_DELAY:
-                       break;
-               case AltosLib.AO_LOG_RADIO_CHANNEL:
-                       break;
-               case AltosLib.AO_LOG_CALLSIGN:
-                       state.callsign = record.data;
-                       break;
-               case AltosLib.AO_LOG_ACCEL_CAL:
-                       state.accel_plus_g = record.config_a;
-                       state.accel_minus_g = record.config_b;
-                       break;
-               case AltosLib.AO_LOG_RADIO_CAL:
-                       break;
-               case AltosLib.AO_LOG_MANUFACTURER:
-                       break;
-               case AltosLib.AO_LOG_PRODUCT:
-                       break;
-               case AltosLib.AO_LOG_SERIAL_NUMBER:
-                       state.serial = record.config_a;
-                       break;
-               case AltosLib.AO_LOG_SOFTWARE_VERSION:
-                       break;
-               case AltosLib.AO_LOG_BARO_RESERVED:
-                       baro.reserved = record.config_a;
-                       break;
-               case AltosLib.AO_LOG_BARO_SENS:
-                       baro.sens =record.config_a;
-                       break;
-               case AltosLib.AO_LOG_BARO_OFF:
-                       baro.off =record.config_a;
-                       break;
-               case AltosLib.AO_LOG_BARO_TCS:
-                       baro.tcs =record.config_a;
-                       break;
-               case AltosLib.AO_LOG_BARO_TCO:
-                       baro.tco =record.config_a;
-                       break;
-               case AltosLib.AO_LOG_BARO_TREF:
-                       baro.tref =record.config_a;
-                       break;
-               case AltosLib.AO_LOG_BARO_TEMPSENS:
-                       baro.tempsens =record.config_a;
-                       break;
-               case AltosLib.AO_LOG_BARO_CRC:
-                       baro.crc =record.config_a;
-                       break;
-               }
-               state.seen |= eeprom.seen;
-       }
-
-       LinkedList<AltosRecord> make_list() {
-               LinkedList<AltosRecord>         list = new LinkedList<AltosRecord>();
-               Iterator<AltosOrderedMegaRecord>        iterator = records.iterator();
-               AltosOrderedMegaRecord          record = null;
-               AltosRecordMM                   state = new AltosRecordMM();
-               //boolean                               last_reported = false;
-               EepromState                     eeprom = new EepromState();
-
-               state.state = AltosLib.ao_flight_pad;
-               state.accel_plus_g = 15758;
-               state.accel_minus_g = 16294;
-
-               /* Pull in static data from the flight and gps_date records */
-               if (flight_record != null)
-                       update_state(state, flight_record, eeprom);
-               if (gps_date_record != null)
-                       update_state(state, gps_date_record, eeprom);
-
-               while (iterator.hasNext()) {
-                       record = iterator.next();
-                       if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
-                               AltosRecordMM r = state.clone();
-                               r.time = (r.tick - eeprom.boost_tick) / 100.0;
-                               list.add(r);
-                       }
-                       update_state(state, record, eeprom);
-               }
-               AltosRecordMM r = state.clone();
-               r.time = (r.tick - eeprom.boost_tick) / 100.0;
-               list.add(r);
-               return list;
-       }
-
-       public Iterator<AltosRecord> iterator() {
-               if (list == null)
-                       list = make_list();
-               return list.iterator();
-       }
-
-       public boolean has_gps() { return has_gps; }
-       public boolean has_accel() { return has_accel; }
-       public boolean has_ignite() { return has_ignite; }
-
-       public void write_comments(PrintStream out) {
-               Iterator<AltosOrderedMegaRecord>        iterator = records.iterator();
-               out.printf("# Comments\n");
-               while (iterator.hasNext()) {
-                       AltosOrderedMegaRecord  record = iterator.next();
-                       switch (record.cmd) {
-                       case AltosLib.AO_LOG_CONFIG_VERSION:
-                               out.printf("# Config version: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_MAIN_DEPLOY:
-                               out.printf("# Main deploy: %s\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_APOGEE_DELAY:
-                               out.printf("# Apogee delay: %s\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_RADIO_CHANNEL:
-                               out.printf("# Radio channel: %s\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_CALLSIGN:
-                               out.printf("# Callsign: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_ACCEL_CAL:
-                               out.printf ("# Accel cal: %d %d\n", record.config_a, record.config_b);
-                               break;
-                       case AltosLib.AO_LOG_RADIO_CAL:
-                               out.printf ("# Radio cal: %d\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
-                               out.printf ("# Max flight log: %d\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_MANUFACTURER:
-                               out.printf ("# Manufacturer: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_PRODUCT:
-                               out.printf ("# Product: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_SERIAL_NUMBER:
-                               out.printf ("# Serial number: %d\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_SOFTWARE_VERSION:
-                               out.printf ("# Software version: %s\n", record.data);
-                               break;
-                       case AltosLib.AO_LOG_BARO_RESERVED:
-                               out.printf ("# Baro reserved: %d\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_SENS:
-                               out.printf ("# Baro sens: %d\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_OFF:
-                               out.printf ("# Baro off: %d\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TCS:
-                               out.printf ("# Baro tcs: %d\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TCO:
-                               out.printf ("# Baro tco: %d\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TREF:
-                               out.printf ("# Baro tref: %d\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_TEMPSENS:
-                               out.printf ("# Baro tempsens: %d\n", record.config_a);
-                               break;
-                       case AltosLib.AO_LOG_BARO_CRC:
-                               out.printf ("# Baro crc: %d\n", record.config_a);
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * Read the whole file, dumping records into a RB tree so
-        * we can enumerate them in time order -- the eeprom data
-        * are sometimes out of order with GPS data getting timestamps
-        * matching the first packet out of the GPS unit but not
-        * written until the final GPS packet has been received.
-        */
-       public AltosEepromMegaIterable (FileInputStream input) {
-               records = new TreeSet<AltosOrderedMegaRecord>();
-
-               AltosOrderedMegaRecord last_gps_time = null;
-
-               baro = new AltosMs5607();
-
-               int index = 0;
-               int prev_tick = 0;
-               boolean prev_tick_valid = false;
-               boolean missing_time = false;
-
-               try {
-                       for (;;) {
-                               String line = AltosLib.gets(input);
-                               if (line == null)
-                                       break;
-                               AltosOrderedMegaRecord record = new AltosOrderedMegaRecord(line, index++, prev_tick, prev_tick_valid);
-                               if (record.cmd == AltosLib.AO_LOG_INVALID)
-                                       continue;
-                               prev_tick = record.tick;
-                               if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION)
-                                       prev_tick_valid = true;
-                               if (record.cmd == AltosLib.AO_LOG_FLIGHT) {
-                                       flight_record = record;
-                                       continue;
-                               }
-
-                               records.add(record);
-
-                               /* Bail after reading the 'landed' record; we're all done */
-                               if (record.cmd == AltosLib.AO_LOG_STATE &&
-                                   record.state() == AltosLib.ao_flight_landed)
-                                       break;
-                       }
-               } catch (IOException io) {
-               } catch (ParseException pe) {
-               }
-               try {
-                       input.close();
-               } catch (IOException ie) {
-               }
-       }
-}
diff --git a/altoslib/AltosEepromMetrum2.java b/altoslib/AltosEepromMetrum2.java
new file mode 100644 (file)
index 0000000..c1d62c0
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromMetrum2 extends AltosEeprom {
+       public static final int record_length = 16;
+
+       public int record_length() { return record_length; }
+
+       /* AO_LOG_FLIGHT elements */
+       public int flight() { return data16(0); }
+       public int ground_accel() { return data16(2); }
+       public int ground_pres() { return data32(4); }
+       public int ground_temp() { return data32(8); }
+
+       /* AO_LOG_STATE elements */
+       public int state() { return data16(0); }
+       public int reason() { return data16(2); }
+
+       /* AO_LOG_SENSOR elements */
+       public int pres() { return data32(0); }
+       public int temp() { return data32(4); }
+       public int accel() { return data16(8); }
+
+       /* AO_LOG_TEMP_VOLT elements */
+       public int v_batt() { return data16(0); }
+       public int sense_a() { return data16(2); }
+       public int sense_m() { return data16(4); }
+
+       /* AO_LOG_GPS_POS elements */
+       public int latitude() { return data32(0); }
+       public int longitude() { return data32(4); }
+       public int altitude() { return data16(8); }
+
+       /* AO_LOG_GPS_TIME elements */
+       public int hour() { return data8(0); }
+       public int minute() { return data8(1); }
+       public int second() { return data8(2); }
+       public int flags() { return data8(3); }
+       public int year() { return data8(4); }
+       public int month() { return data8(5); }
+       public int day() { return data8(6); }
+       
+       /* AO_LOG_GPS_SAT elements */
+       public int nsat() { return data8(0); }
+       public int more() { return data8(1); }
+       public int svid(int n) { return data8(2 + n * 2); }
+       public int c_n(int n) { return data8(2 + n * 2 + 1); }
+
+       public AltosEepromMetrum2 (AltosEepromChunk chunk, int start) throws ParseException {
+               parse_chunk(chunk, start);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               AltosGPS        gps;
+
+               /* Flush any pending GPS changes */
+               if (state.gps_pending) {
+                       switch (cmd) {
+                       case AltosLib.AO_LOG_GPS_POS:
+                       case AltosLib.AO_LOG_GPS_LAT:
+                       case AltosLib.AO_LOG_GPS_LON:
+                       case AltosLib.AO_LOG_GPS_ALT:
+                       case AltosLib.AO_LOG_GPS_SAT:
+                       case AltosLib.AO_LOG_GPS_DATE:
+                               break;
+                       default:
+                               state.set_temp_gps();
+                               break;
+                       }
+               }
+
+               switch (cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       state.set_flight(flight());
+                       state.set_ground_accel(ground_accel());
+                       state.set_ground_pressure(ground_pres());
+//                     state.set_temperature(ground_temp() / 100.0);
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.set_state(state());
+                       break;
+               case AltosLib.AO_LOG_SENSOR:
+                       state.set_ms5607(pres(), temp());
+                       state.set_accel(accel());
+
+                       break;
+               case AltosLib.AO_LOG_TEMP_VOLT:
+                       state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt()));
+
+                       state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense_a()));
+                       state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense_m()));
+
+                       break;
+               case AltosLib.AO_LOG_GPS_POS:
+                       gps = state.make_temp_gps(false);
+                       gps.lat = latitude() / 1e7;
+                       gps.lon = longitude() / 1e7;
+                       gps.alt = altitude();
+                       break;
+               case AltosLib.AO_LOG_GPS_TIME:
+                       gps = state.make_temp_gps(false);
+
+                       gps.hour = hour();
+                       gps.minute = minute();
+                       gps.second = second();
+
+                       int flags = flags();
+
+                       gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
+                       gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
+                       gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
+                               AltosLib.AO_GPS_NUM_SAT_SHIFT;
+
+                       gps.year = 2000 + year();
+                       gps.month = month();
+                       gps.day = day();
+                       break;
+               case AltosLib.AO_LOG_GPS_SAT:
+                       gps = state.make_temp_gps(true);
+
+                       int n = nsat();
+                       for (int i = 0; i < n; i++)
+                               gps.add_sat(svid(i), c_n(i));
+                       break;
+               }
+       }
+
+       public AltosEepromMetrum2 (String line) {
+               parse_string(line);
+       }
+
+       static public LinkedList<AltosEeprom> read(FileInputStream input) {
+               LinkedList<AltosEeprom> metrums = new LinkedList<AltosEeprom>();
+
+               for (;;) {
+                       try {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               try {
+                                       AltosEepromMetrum2 metrum = new AltosEepromMetrum2(line);
+                                       
+                                       if (metrum.cmd != AltosLib.AO_LOG_INVALID)
+                                               metrums.add(metrum);
+                               } catch (Exception e) {
+                                       System.out.printf ("exception\n");
+                               }
+                       } catch (IOException ie) {
+                               break;
+                       }
+               }
+
+               return metrums;
+       }
+}
diff --git a/altoslib/AltosEepromMini.java b/altoslib/AltosEepromMini.java
new file mode 100644 (file)
index 0000000..a09a62c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromMini extends AltosEeprom {
+       public static final int record_length = 16;
+
+       public int record_length() { return record_length; }
+
+       /* AO_LOG_FLIGHT elements */
+       public int flight() { return data16(0); }
+       public int ground_pres() { return data32(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 data24(0); }
+       public int temp() { return data24(3); }
+       public int sense_a() { return data16(6); }
+       public int sense_m() { return data16(8); }
+       public int v_batt() { return data16(10); }
+
+       double voltage(AltosState state, int sensor) {
+               if (state.log_format == AltosLib.AO_LOG_FORMAT_EASYMINI)
+                       return AltosConvert.easy_mini_voltage(sensor);
+               else
+                       return AltosConvert.tele_mini_voltage(sensor);
+       }
+
+       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(ground_pres());
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.set_state(state());
+                       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()));
+                       break;
+               }
+       }
+
+       public AltosEepromMini (AltosEepromChunk chunk, int start) throws ParseException {
+               parse_chunk(chunk, start);
+       }
+
+       public AltosEepromMini (String line) {
+               parse_string(line);
+       }
+
+       public AltosEepromMini(int in_cmd, int in_tick) {
+               cmd = in_cmd;
+               tick = in_tick;
+               valid = true;
+       }
+
+       static public LinkedList<AltosEeprom> read(FileInputStream input) {
+               LinkedList<AltosEeprom> minis = new LinkedList<AltosEeprom>();
+
+               for (;;) {
+                       try {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               AltosEepromMini mini = new AltosEepromMini(line);
+                               minis.add(mini);
+                       } catch (IOException ie) {
+                               break;
+                       }
+               }
+
+               return minis;
+       }
+}
diff --git a/altoslib/AltosEepromMonitor.java b/altoslib/AltosEepromMonitor.java
new file mode 100644 (file)
index 0000000..eeef067
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public interface AltosEepromMonitor {
+
+       public void set_states(int min_state, int max_state);
+
+       public void set_value(String in_state_name, int in_state, int in_state_block, int in_block);
+
+       public void set_serial(int in_serial);
+
+       public void set_flight(int in_flight);
+
+       public void set_filename(String in_file);
+
+       public void set_thread(Thread eeprom_thread);
+
+       final static int INFO_MESSAGE = 0;
+       final static int WARNING_MESSAGE = 1;
+       final static int ERROR_MESSAGE = 2;
+
+       public void show_message(String message, String title, int message_type);
+
+       public void start();
+
+       public void done(boolean success);
+
+       public void reset();
+}
diff --git a/altoslib/AltosEepromRecord.java b/altoslib/AltosEepromRecord.java
deleted file mode 100644 (file)
index 70ac111..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.*;
-
-public class AltosEepromRecord {
-       public int      cmd;
-       public int      tick;
-       public int      a;
-       public int      b;
-       public String   data;
-       public boolean  tick_valid;
-
-       public static final int record_length = 8;
-
-       public AltosEepromRecord (AltosEepromChunk chunk, int start) throws ParseException {
-
-               cmd = chunk.data(start);
-               tick_valid = true;
-
-               tick_valid = !chunk.erased(start, record_length);
-               if (tick_valid) {
-                       if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
-                               throw new ParseException(String.format("invalid checksum at 0x%x",
-                                                                      chunk.address + start), 0);
-               } else {
-                       cmd = AltosLib.AO_LOG_INVALID;
-               }
-
-               tick = chunk.data16(start + 2);
-               a = chunk.data16(start + 4);
-               b = chunk.data16(start + 6);
-
-               data = null;
-       }
-
-       public AltosEepromRecord (String line) {
-               tick_valid = false;
-               tick = 0;
-               a = 0;
-               b = 0;
-               data = null;
-               if (line == null) {
-                       cmd = AltosLib.AO_LOG_INVALID;
-                       data = "";
-               } else {
-                       try {
-                               String[] tokens = line.split("\\s+");
-
-                               if (tokens[0].length() == 1) {
-                                       if (tokens.length != 4) {
-                                               cmd = AltosLib.AO_LOG_INVALID;
-                                               data = line;
-                                       } else {
-                                               cmd = tokens[0].codePointAt(0);
-                                               tick = Integer.parseInt(tokens[1],16);
-                                               tick_valid = true;
-                                               a = Integer.parseInt(tokens[2],16);
-                                               b = Integer.parseInt(tokens[3],16);
-                                       }
-                               } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
-                                       cmd = AltosLib.AO_LOG_CONFIG_VERSION;
-                                       data = tokens[2];
-                               } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
-                                       cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
-                                       a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
-                                       cmd = AltosLib.AO_LOG_APOGEE_DELAY;
-                                       a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
-                                       cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
-                                       a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Callsign:")) {
-                                       cmd = AltosLib.AO_LOG_CALLSIGN;
-                                       data = tokens[1].replaceAll("\"","");
-                               } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
-                                       cmd = AltosLib.AO_LOG_ACCEL_CAL;
-                                       a = Integer.parseInt(tokens[3]);
-                                       b = Integer.parseInt(tokens[5]);
-                               } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
-                                       cmd = AltosLib.AO_LOG_RADIO_CAL;
-                                       a = Integer.parseInt(tokens[2]);
-                               } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
-                                       cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
-                                       a = Integer.parseInt(tokens[3]);
-                               } else if (tokens[0].equals("manufacturer")) {
-                                       cmd = AltosLib.AO_LOG_MANUFACTURER;
-                                       data = tokens[1];
-                               } else if (tokens[0].equals("product")) {
-                                       cmd = AltosLib.AO_LOG_PRODUCT;
-                                       data = tokens[1];
-                               } else if (tokens[0].equals("serial-number")) {
-                                       cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
-                                       a = Integer.parseInt(tokens[1]);
-                               } else if (tokens[0].equals("log-format")) {
-                                       cmd = AltosLib.AO_LOG_LOG_FORMAT;
-                                       a = Integer.parseInt(tokens[1]);
-                               } else if (tokens[0].equals("software-version")) {
-                                       cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
-                                       data = tokens[1];
-                               } else {
-                                       cmd = AltosLib.AO_LOG_INVALID;
-                                       data = line;
-                               }
-                       } catch (NumberFormatException ne) {
-                               cmd = AltosLib.AO_LOG_INVALID;
-                               data = line;
-                       }
-               }
-       }
-
-       public AltosEepromRecord(int in_cmd, int in_tick, int in_a, int in_b) {
-               tick_valid = true;
-               cmd = in_cmd;
-               tick = in_tick;
-               a = in_a;
-               b = in_b;
-       }
-}
diff --git a/altoslib/AltosEepromTM.java b/altoslib/AltosEepromTM.java
new file mode 100644 (file)
index 0000000..3680391
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * 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; 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromTM extends AltosEeprom {
+       public int      a;
+       public int      b;
+
+       public static final int record_length = 8;
+
+       public void write(PrintStream out) {
+               out.printf("%c %4x %4x %4x\n", cmd, tick, a, b);
+       }
+
+       public int record_length() { return record_length; }
+
+       public String string() {
+               return String.format("%c %4x %4x %4x\n", cmd, tick, a, b);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               AltosGPS        gps;
+
+               /* Flush any pending GPS changes */
+               if (state.gps_pending) {
+                       switch (cmd) {
+                       case AltosLib.AO_LOG_GPS_LAT:
+                       case AltosLib.AO_LOG_GPS_LON:
+                       case AltosLib.AO_LOG_GPS_ALT:
+                       case AltosLib.AO_LOG_GPS_SAT:
+                       case AltosLib.AO_LOG_GPS_DATE:
+                               break;
+                       default:
+                               state.set_temp_gps();
+                               break;
+                       }
+               }
+
+               switch (cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       state.set_state(AltosLib.ao_flight_pad);
+                       state.set_ground_accel(a);
+                       state.set_flight(b);
+                       state.set_boost_tick(tick);
+                       break;
+               case AltosLib.AO_LOG_SENSOR:
+                       state.set_accel(a);
+                       state.set_pressure(AltosConvert.barometer_to_pressure(b));
+                       break;
+               case AltosLib.AO_LOG_PRESSURE:
+                       state.set_pressure(AltosConvert.barometer_to_pressure(b));
+                       break;
+               case AltosLib.AO_LOG_TEMP_VOLT:
+                       state.set_temperature(AltosConvert.thermometer_to_temperature(a));
+                       state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(b));
+                       break;
+               case AltosLib.AO_LOG_DEPLOY:
+                       state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(a));
+                       state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(b));
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.set_state(a);
+                       break;
+               case AltosLib.AO_LOG_GPS_TIME:
+                       gps = state.make_temp_gps(false);
+
+                       gps.hour = (a & 0xff);
+                       gps.minute = (a >> 8);
+                       gps.second = (b & 0xff);
+
+                       int flags = (b >> 8);
+
+                       gps.connected = (flags & AltosLib.AO_GPS_RUNNING) != 0;
+                       gps.locked = (flags & AltosLib.AO_GPS_VALID) != 0;
+                       gps.nsat = (flags & AltosLib.AO_GPS_NUM_SAT_MASK) >>
+                               AltosLib.AO_GPS_NUM_SAT_SHIFT;
+                       break;
+               case AltosLib.AO_LOG_GPS_LAT:
+                       gps = state.make_temp_gps(false);
+
+                       int lat32 = a | (b << 16);
+                       gps.lat = (double) lat32 / 1e7;
+                       break;
+               case AltosLib.AO_LOG_GPS_LON:
+                       gps = state.make_temp_gps(false);
+
+                       int lon32 = a | (b << 16);
+                       gps.lon = (double) lon32 / 1e7;
+                       break;
+               case AltosLib.AO_LOG_GPS_ALT:
+                       gps = state.make_temp_gps(false);
+                       gps.alt = a;
+                       break;
+               case AltosLib.AO_LOG_GPS_SAT:
+                       gps = state.make_temp_gps(true);
+                       int svid = a;
+                       int c_n0 = b >> 8;
+                       gps.add_sat(svid, c_n0);
+                       break;
+               case AltosLib.AO_LOG_GPS_DATE:
+                       gps = state.make_temp_gps(false);
+                       gps.year = (a & 0xff) + 2000;
+                       gps.month = a >> 8;
+                       gps.day = b & 0xff;
+                       break;
+               }
+       }
+
+       public AltosEepromTM (AltosEepromChunk chunk, int start) throws ParseException {
+
+               cmd = chunk.data(start);
+               valid = true;
+
+               valid = !chunk.erased(start, record_length);
+               if (valid) {
+                       if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
+                               throw new ParseException(String.format("invalid checksum at 0x%x",
+                                                                      chunk.address + start), 0);
+               } else {
+                       cmd = AltosLib.AO_LOG_INVALID;
+               }
+
+               tick = chunk.data16(start + 2);
+               a = chunk.data16(start + 4);
+               b = chunk.data16(start + 6);
+       }
+
+       public AltosEepromTM (String line) {
+               valid = false;
+               tick = 0;
+               a = 0;
+               b = 0;
+               if (line == null) {
+                       cmd = AltosLib.AO_LOG_INVALID;
+               } else {
+                       try {
+                               String[] tokens = line.split("\\s+");
+
+                               if (tokens[0].length() == 1) {
+                                       if (tokens.length != 4) {
+                                               cmd = AltosLib.AO_LOG_INVALID;
+                                       } else {
+                                               cmd = tokens[0].codePointAt(0);
+                                               tick = Integer.parseInt(tokens[1],16);
+                                               valid = true;
+                                               a = Integer.parseInt(tokens[2],16);
+                                               b = Integer.parseInt(tokens[3],16);
+                                       }
+                               } else {
+                                       cmd = AltosLib.AO_LOG_INVALID;
+                               }
+                       } catch (NumberFormatException ne) {
+                               cmd = AltosLib.AO_LOG_INVALID;
+                       }
+               }
+       }
+
+       public AltosEepromTM(int in_cmd, int in_tick, int in_a, int in_b) {
+               valid = true;
+               cmd = in_cmd;
+               tick = in_tick;
+               a = in_a;
+               b = in_b;
+       }
+
+       static public LinkedList<AltosEeprom> read(FileInputStream input) {
+               LinkedList<AltosEeprom> tms = new LinkedList<AltosEeprom>();
+
+               for (;;) {
+                       try {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               AltosEepromTM tm = new AltosEepromTM(line);
+                               tms.add(tm);
+                       } catch (IOException ie) {
+                               break;
+                       }
+               }
+
+               return tms;
+       }
+
+}
diff --git a/altoslib/AltosEepromTeleScience.java b/altoslib/AltosEepromTeleScience.java
deleted file mode 100644 (file)
index 2a828cf..0000000
+++ /dev/null
@@ -1,55 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.*;
-
-public class AltosEepromTeleScience {
-       public int      type;
-       public int      tick;
-       public int      tm_state;
-       public int      tm_tick;
-       public int[]    data;
-       public boolean  valid;
-
-       public static final int AO_LOG_TELESCIENCE_START = 's';
-       public static final int AO_LOG_TELESCIENCE_DATA = 'd';
-
-       static final int        max_data = 12;
-       public static final int record_length = 32;
-
-       public AltosEepromTeleScience (AltosEepromChunk chunk, int start) throws ParseException {
-               type = chunk.data(start);
-
-               valid = !chunk.erased(start, record_length);
-               if (valid) {
-                       if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
-                               throw new ParseException(String.format("invalid checksum at 0x%x",
-                                                                      chunk.address + start), 0);
-               } else {
-                       type = AltosLib.AO_LOG_INVALID;
-               }
-
-               tick = chunk.data16(start+2);
-               tm_tick = chunk.data16(start+4);
-               tm_state = chunk.data(start+6);
-               data = new int[max_data];
-               for (int i = 0; i < max_data; i++)
-                       data[i] = chunk.data16(start + 8 + i * 2);
-       }
-}
diff --git a/altoslib/AltosEepromTm.java b/altoslib/AltosEepromTm.java
new file mode 100644 (file)
index 0000000..b891413
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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; 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromTm extends AltosEeprom {
+       public int      i;
+       public int      a;
+       public int      b;
+
+       public static final int record_length = 2;
+
+       public void write(PrintStream out) {
+               out.printf("%c %4x %4x %4x\n", cmd, tick, a, b);
+       }
+
+       public int record_length() { return record_length; }
+
+       public String string() {
+               return String.format("%c %4x %4x %4x\n", cmd, tick, a, b);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               switch (cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       state.set_state(AltosLib.ao_flight_boost);
+                       state.set_flight(b);
+                       break;
+               case AltosLib.AO_LOG_PRESSURE:
+                       if (tick == 0)
+                               state.set_ground_pressure(AltosConvert.barometer_to_pressure(b));
+                       else
+                               state.set_pressure(AltosConvert.barometer_to_pressure(b));
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.set_state(a);
+                       break;
+               }
+       }
+
+       public AltosEepromTm (AltosEepromChunk chunk, int start, AltosState state) throws ParseException {
+               int     value = chunk.data16(start);
+
+               int     i = (chunk.address + start) / record_length;
+
+               cmd = chunk.data(start);
+               valid = true;
+
+               valid = !chunk.erased(start, record_length);
+
+               switch (i) {
+               case 0:
+                       cmd = AltosLib.AO_LOG_FLIGHT;
+                       tick = 0;
+                       a = 0;
+                       b = value;
+                       break;
+               case 1:
+                       cmd = AltosLib.AO_LOG_PRESSURE;
+                       tick = 0;
+                       a = 0;
+                       b = value;
+                       break;
+               default:
+                       if ((value & 0x8000) != 0) {
+                               cmd = AltosLib.AO_LOG_STATE;
+                               tick = state.tick;
+                               a = value & 0x7fff;
+                               b = 0;
+                       } else {
+                               if (state.ascent)
+                                       tick = state.tick + 10;
+                               else
+                                       tick = state.tick + 100;
+                               cmd = AltosLib.AO_LOG_PRESSURE;
+                               a = 0;
+                               b = value;
+                       }
+                       break;
+               }
+       }
+
+       public AltosEepromTm (String line) {
+               valid = false;
+               tick = 0;
+               a = 0;
+               b = 0;
+               if (line == null) {
+                       cmd = AltosLib.AO_LOG_INVALID;
+               } else {
+                       try {
+                               String[] tokens = line.split("\\s+");
+
+                               if (tokens[0].length() == 1) {
+                                       if (tokens.length != 4) {
+                                               cmd = AltosLib.AO_LOG_INVALID;
+                                       } else {
+                                               cmd = tokens[0].codePointAt(0);
+                                               tick = Integer.parseInt(tokens[1],16);
+                                               valid = true;
+                                               a = Integer.parseInt(tokens[2],16);
+                                               b = Integer.parseInt(tokens[3],16);
+                                       }
+                               } else {
+                                       cmd = AltosLib.AO_LOG_INVALID;
+                               }
+                       } catch (NumberFormatException ne) {
+                               cmd = AltosLib.AO_LOG_INVALID;
+                       }
+               }
+       }
+
+       public AltosEepromTm(int in_cmd, int in_tick, int in_a, int in_b) {
+               valid = true;
+               cmd = in_cmd;
+               tick = in_tick;
+               a = in_a;
+               b = in_b;
+       }
+
+       static public LinkedList<AltosEeprom> read(FileInputStream input) {
+               LinkedList<AltosEeprom> tms = new LinkedList<AltosEeprom>();
+
+               for (;;) {
+                       try {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               AltosEepromTm tm = new AltosEepromTm(line);
+                               tms.add(tm);
+                       } catch (IOException ie) {
+                               break;
+                       }
+               }
+
+               return tms;
+       }
+
+}
index 90dbc6dbea8ecf069dbedbf530b88e33ee865ea3..f39c3962a3f42b7e56dd2510a9c05dee871ff2b6 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1
+package org.altusmetrum.altoslib_2
 
 import java.io.File;
 import java.util.*;
 
 public class AltosFile extends File {
 
-       public AltosFile(int year, int month, int day, int serial, int flight, String extension) {
+       static String number(int n) {
+               if (n == AltosLib.MISSING)
+                       return "unkn";
+               else
+                       return String.format("%04d", n);
+       }
+
+       static String receiver(int receiver) {
+               if (receiver == AltosLib.MISSING)
+                       return "";
+               return String.format("-via-%04d", receiver);
+       }
+
+       public AltosFile(int year, int month, int day, int serial, int flight, int receiver, String extension) {
                super (AltosPreferences.logdir(),
-                      String.format("%04d-%02d-%02d-serial-%03d-flight-%03d.%s",
-                                    year, month, day, serial, flight, extension));
+                      String.format("%04d-%02d-%02d-serial-%s-flight-%s%s.%s",
+                                    year, month, day, number(serial), number(flight), receiver(receiver), extension));
+       }
+
+       public AltosFile(int year, int month, int day, int serial, int flight, String extension) {
+               this(year, month, day, serial, flight, AltosLib.MISSING, extension);
+       }
+
+       public AltosFile(int serial, int flight, int receiver, String extension) {
+               this(Calendar.getInstance().get(Calendar.YEAR),
+                    Calendar.getInstance().get(Calendar.MONTH) + 1,
+                    Calendar.getInstance().get(Calendar.DAY_OF_MONTH),
+                    serial,
+                    flight,
+                    receiver,
+                    extension);
        }
 
        public AltosFile(int serial, int flight, String extension) {
@@ -34,10 +61,11 @@ public class AltosFile extends File {
                     Calendar.getInstance().get(Calendar.DAY_OF_MONTH),
                     serial,
                     flight,
+                    AltosLib.MISSING,
                     extension);
        }
 
-       public AltosFile(AltosRecord telem) {
-               this(telem.serial, telem.flight, "telem");
+       public AltosFile(AltosState state) {
+               this(state.serial, state.flight, state.receiver_serial, "telem");
        }
 }
index 010274b944884ecf1e3339aad5f72a3e3221d18d..0977070e2a2883adba4a49b772712c5c6dd436b0 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 
-public class AltosFlash {
+public class AltosFlash extends AltosProgrammer {
        File                    file;
        FileInputStream         input;
        AltosHexfile            image;
@@ -318,7 +318,7 @@ public class AltosFlash {
                close();
        }
 
-       public boolean check_rom_config() {
+       public boolean check_rom_config() throws InterruptedException {
                if (debug == null)
                        return true;
                if (rom_config == null)
@@ -330,7 +330,7 @@ public class AltosFlash {
                rom_config = romconfig;
        }
 
-       public AltosRomconfig romconfig() {
+       public AltosRomconfig romconfig() throws InterruptedException {
                if (!check_rom_config())
                        return null;
                return rom_config;
index ab50b74a6093799f9322071cf9dc1475fe32b8c4..777ae635bf3ec24475ec3bda2b80d44df98fd941 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public interface AltosFlashListener {
        public void position(String label, int percent);
index 345266588f5b16e75ff5d73b9b93761ececbf9d5..b251e7ccdd53ad37394d11f16251408b611c0813 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.text.*;
 import java.io.*;
@@ -28,7 +28,7 @@ public class AltosFlightReader {
 
        public void init() { }
 
-       public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; }
+       public AltosState read() throws InterruptedException, ParseException, AltosCRCException, IOException { return null; }
 
        public void close(boolean interrupted) { }
 
@@ -46,7 +46,7 @@ public class AltosFlightReader {
 
        public File backing_file() { return null; }
 
-       public boolean has_monitor_battery() { return false; }
+       public boolean has_monitor_battery() throws InterruptedException { return false; }
 
-       public double monitor_battery() { return AltosRecord.MISSING; }
+       public double monitor_battery() throws InterruptedException { return AltosLib.MISSING; }
 }
index 484a2fd9d56e084f99c130185bf33fb2ad21711a..ece7525ad848d78408d432c328dac7235c6d3ece 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosFrequency {
        public double   frequency;
index f23842f3d947c09b135bbfabef197111a1ab9a71..f5162225ac200c08edb3359f8865545e5024075d 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.text.*;
+import java.util.concurrent.*;
 
-public class AltosGPS {
+public class AltosGPS implements Cloneable {
 
-       public final static int MISSING = AltosRecord.MISSING;
+       public final static int MISSING = AltosLib.MISSING;
 
        public int      nsat;
        public boolean  locked;
        public boolean  connected;
        public double   lat;            /* degrees (+N -S) */
        public double   lon;            /* degrees (+E -W) */
-       public int      alt;            /* m */
+       public double   alt;            /* m */
        public int      year;
        public int      month;
        public int      day;
@@ -65,40 +66,40 @@ public class AltosGPS {
        }
 
        public void ClearGPSTime() {
-               year = month = day = 0;
-               hour = minute = second = 0;
+               year = month = day = AltosLib.MISSING;
+               hour = minute = second = AltosLib.MISSING;
        }
 
        public AltosGPS(AltosTelemetryMap map) throws ParseException {
-               String  state = map.get_string(AltosTelemetry.AO_TELEM_GPS_STATE,
-                                              AltosTelemetry.AO_TELEM_GPS_STATE_ERROR);
+               String  state = map.get_string(AltosTelemetryLegacy.AO_TELEM_GPS_STATE,
+                                              AltosTelemetryLegacy.AO_TELEM_GPS_STATE_ERROR);
 
-               nsat = map.get_int(AltosTelemetry.AO_TELEM_GPS_NUM_SAT, 0);
-               if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_LOCKED)) {
+               nsat = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_NUM_SAT, 0);
+               if (state.equals(AltosTelemetryLegacy.AO_TELEM_GPS_STATE_LOCKED)) {
                        connected = true;
                        locked = true;
-                       lat = map.get_double(AltosTelemetry.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7);
-                       lon = map.get_double(AltosTelemetry.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7);
-                       alt = map.get_int(AltosTelemetry.AO_TELEM_GPS_ALTITUDE, MISSING);
-                       year = map.get_int(AltosTelemetry.AO_TELEM_GPS_YEAR, MISSING);
+                       lat = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LATITUDE, MISSING, 1.0e-7);
+                       lon = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_LONGITUDE, MISSING, 1.0e-7);
+                       alt = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_ALTITUDE, MISSING);
+                       year = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_YEAR, MISSING);
                        if (year != MISSING)
                                year += 2000;
-                       month = map.get_int(AltosTelemetry.AO_TELEM_GPS_MONTH, MISSING);
-                       day = map.get_int(AltosTelemetry.AO_TELEM_GPS_DAY, MISSING);
-
-                       hour = map.get_int(AltosTelemetry.AO_TELEM_GPS_HOUR, 0);
-                       minute = map.get_int(AltosTelemetry.AO_TELEM_GPS_MINUTE, 0);
-                       second = map.get_int(AltosTelemetry.AO_TELEM_GPS_SECOND, 0);
-
-                       ground_speed = map.get_double(AltosTelemetry.AO_TELEM_GPS_HORIZONTAL_SPEED,
-                                                     AltosRecord.MISSING, 1/100.0);
-                       course = map.get_int(AltosTelemetry.AO_TELEM_GPS_COURSE,
-                                            AltosRecord.MISSING);
-                       hdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_HDOP, MISSING, 1.0);
-                       vdop = map.get_double(AltosTelemetry.AO_TELEM_GPS_VDOP, MISSING, 1.0);
-                       h_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_HERROR, MISSING);
-                       v_error = map.get_int(AltosTelemetry.AO_TELEM_GPS_VERROR, MISSING);
-               } else if (state.equals(AltosTelemetry.AO_TELEM_GPS_STATE_UNLOCKED)) {
+                       month = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MONTH, MISSING);
+                       day = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_DAY, MISSING);
+
+                       hour = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HOUR, 0);
+                       minute = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_MINUTE, 0);
+                       second = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_SECOND, 0);
+
+                       ground_speed = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HORIZONTAL_SPEED,
+                                                     AltosLib.MISSING, 1/100.0);
+                       course = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_COURSE,
+                                            AltosLib.MISSING);
+                       hdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_HDOP, MISSING, 1.0);
+                       vdop = map.get_double(AltosTelemetryLegacy.AO_TELEM_GPS_VDOP, MISSING, 1.0);
+                       h_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_HERROR, MISSING);
+                       v_error = map.get_int(AltosTelemetryLegacy.AO_TELEM_GPS_VERROR, MISSING);
+               } else if (state.equals(AltosTelemetryLegacy.AO_TELEM_GPS_STATE_UNLOCKED)) {
                        connected = true;
                        locked = false;
                } else {
@@ -107,6 +108,62 @@ public class AltosGPS {
                }
        }
 
+       public boolean parse_string (String line, boolean says_done) {
+               String[] bits = line.split("\\s+");
+               if (bits.length == 0)
+                       return false;
+               if (line.startsWith("Date:")) {
+                       if (bits.length < 2)
+                               return false;
+                       String[] d = bits[1].split("/");
+                       if (d.length < 3)
+                               return false;
+                       year = Integer.parseInt(d[0]) + 2000;
+                       month = Integer.parseInt(d[1]);
+                       day = Integer.parseInt(d[2]);
+               } else if (line.startsWith("Time:")) {
+                       if (bits.length < 2)
+                               return false;
+                       String[] d = bits[1].split(":");
+                       if (d.length < 3)
+                               return false;
+                       hour = Integer.parseInt(d[0]);
+                       minute = Integer.parseInt(d[1]);
+                       second = Integer.parseInt(d[2]);
+               } else if (line.startsWith("Lat/Lon:")) {
+                       if (bits.length < 3)
+                               return false;
+                       lat = Integer.parseInt(bits[1]) * 1.0e-7;
+                       lon = Integer.parseInt(bits[2]) * 1.0e-7;
+               } else if (line.startsWith("Alt:")) {
+                       if (bits.length < 2)
+                               return false;
+                       alt = Integer.parseInt(bits[1]);
+               } else if (line.startsWith("Flags:")) {
+                       if (bits.length < 2)
+                               return false;
+                       int status = Integer.decode(bits[1]);
+                       connected = (status & AltosLib.AO_GPS_RUNNING) != 0;
+                       locked = (status & AltosLib.AO_GPS_VALID) != 0;
+                       if (!says_done)
+                               return false;
+               } else if (line.startsWith("Sats:")) {
+                       if (bits.length < 2)
+                               return false;
+                       nsat = Integer.parseInt(bits[1]);
+                       cc_gps_sat = new AltosGPSSat[nsat];
+                       for (int i = 0; i < nsat; i++) {
+                               int     svid = Integer.parseInt(bits[2+i*2]);
+                               int     cc_n0 = Integer.parseInt(bits[3+i*2]);
+                               cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0);
+                       }
+               } else if (line.startsWith("done")) {
+                       return false;
+               } else
+                       return false;
+               return true;
+       }
+
        public AltosGPS(String[] words, int i, int version) throws ParseException {
                AltosParse.word(words[i++], "GPS");
                nsat = AltosParse.parse_int(words[i++]);
@@ -212,10 +269,46 @@ public class AltosGPS {
        }
 
        public AltosGPS() {
+               lat = AltosLib.MISSING;
+               lon = AltosLib.MISSING;
+               alt = AltosLib.MISSING;
                ClearGPSTime();
                cc_gps_sat = null;
        }
 
+       public AltosGPS clone() {
+               AltosGPS        g = new AltosGPS();
+
+               g.nsat = nsat;
+               g.locked = locked;
+               g.connected = connected;
+               g.lat = lat;            /* degrees (+N -S) */
+               g.lon = lon;            /* degrees (+E -W) */
+               g.alt = alt;            /* m */
+               g.year = year;
+               g.month = month;
+               g.day = day;
+               g.hour = hour;
+               g.minute = minute;
+               g.second = second;
+
+               g.ground_speed = ground_speed;  /* m/s */
+               g.course = course;              /* degrees */
+               g.climb_rate = climb_rate;      /* m/s */
+               g.hdop = hdop;          /* unitless? */
+               g.h_error = h_error;    /* m */
+               g.v_error = v_error;    /* m */
+
+               if (cc_gps_sat != null) {
+                       g.cc_gps_sat = new AltosGPSSat[cc_gps_sat.length];
+                       for (int i = 0; i < cc_gps_sat.length; i++) {
+                               g.cc_gps_sat[i] = new AltosGPSSat(cc_gps_sat[i].svid,
+                                                                 cc_gps_sat[i].c_n0);
+                       }
+               }
+               return g;
+       }
+
        public AltosGPS(AltosGPS old) {
                if (old != null) {
                        nsat = old.nsat;
@@ -247,8 +340,36 @@ public class AltosGPS {
                                }
                        }
                } else {
+                       lat = AltosLib.MISSING;
+                       lon = AltosLib.MISSING;
+                       alt = AltosLib.MISSING;
                        ClearGPSTime();
                        cc_gps_sat = null;
                }
        }
+
+       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+               try {
+                       AltosGPS        gps = new AltosGPS(link, config_data);
+
+                       if (gps != null) {
+                               state.set_gps(gps, state.gps_sequence++);
+                               return;
+                       }
+               } catch (TimeoutException te) {
+               }
+               state.set_gps(null, 0);
+       }
+
+       public AltosGPS (AltosLink link, AltosConfigData config_data) throws TimeoutException, InterruptedException {
+               boolean says_done = config_data.compare_version("1.0") >= 0;
+               link.printf("g\n");
+               for (;;) {
+                       String line = link.get_reply_no_dialog(5000);
+                       if (line == null)
+                               throw new TimeoutException();
+                       if (!parse_string(line, says_done))
+                               break;
+               }
+       }
 }
diff --git a/altoslib/AltosGPSQuery.java b/altoslib/AltosGPSQuery.java
deleted file mode 100644 (file)
index deb9d20..0000000
+++ /dev/null
@@ -1,97 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.util.concurrent.*;
-
-class AltosGPSQuery extends AltosGPS {
-       public AltosGPSQuery (AltosLink link, AltosConfigData config_data)
-               throws TimeoutException, InterruptedException {
-               boolean says_done = config_data.compare_version("1.0") >= 0;
-               link.printf("g\n");
-               for (;;) {
-                       String line = link.get_reply_no_dialog(5000);
-                       if (line == null)
-                               throw new TimeoutException();
-                       String[] bits = line.split("\\s+");
-                       if (bits.length == 0)
-                               continue;
-                       if (line.startsWith("Date:")) {
-                               if (bits.length < 2)
-                                       continue;
-                               String[] d = bits[1].split(":");
-                               if (d.length < 3)
-                                       continue;
-                               year = Integer.parseInt(d[0]) + 2000;
-                               month = Integer.parseInt(d[1]);
-                               day = Integer.parseInt(d[2]);
-                               continue;
-                       }
-                       if (line.startsWith("Time:")) {
-                               if (bits.length < 2)
-                                       continue;
-                               String[] d = bits[1].split("/");
-                               if (d.length < 3)
-                                       continue;
-                               hour = Integer.parseInt(d[0]);
-                               minute = Integer.parseInt(d[1]);
-                               second = Integer.parseInt(d[2]);
-                               continue;
-                       }
-                       if (line.startsWith("Lat/Lon:")) {
-                               if (bits.length < 3)
-                                       continue;
-                               lat = Integer.parseInt(bits[1]) * 1.0e-7;
-                               lon = Integer.parseInt(bits[2]) * 1.0e-7;
-                               continue;
-                       }
-                       if (line.startsWith("Alt:")) {
-                               if (bits.length < 2)
-                                       continue;
-                               alt = Integer.parseInt(bits[1]);
-                               continue;
-                       }
-                       if (line.startsWith("Flags:")) {
-                               if (bits.length < 2)
-                                       continue;
-                               int status = Integer.decode(bits[1]);
-                               connected = (status & AltosLib.AO_GPS_RUNNING) != 0;
-                               locked = (status & AltosLib.AO_GPS_VALID) != 0;
-                               if (!says_done)
-                                       break;
-                               continue;
-                       }
-                       if (line.startsWith("Sats:")) {
-                               if (bits.length < 2)
-                                       continue;
-                               nsat = Integer.parseInt(bits[1]);
-                               cc_gps_sat = new AltosGPSSat[nsat];
-                               for (int i = 0; i < nsat; i++) {
-                                       int     svid = Integer.parseInt(bits[2+i*2]);
-                                       int     cc_n0 = Integer.parseInt(bits[3+i*2]);
-                                       cc_gps_sat[i] = new AltosGPSSat(svid, cc_n0);
-                               }
-                       }
-                       if (line.startsWith("done"))
-                               break;
-                       if (line.startsWith("Syntax error"))
-                               break;
-               }
-       }
-}
-
index 8714dd8aa42f98e217764fc80c3c8718f8be9e05..0e17d7f24d9eca661543f1ce3eeb56f17f8fd129 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosGPSSat {
        public int      svid;
index f1cf0ae9089173de180b9b0e39108379ed807a53..2c84bf4a27534c607f0c517215e41f354fc0000d 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.lang.Math;
 
-public class AltosGreatCircle {
+public class AltosGreatCircle implements Cloneable {
        public double   distance;
        public double   bearing;
        public double   range;
@@ -95,6 +95,16 @@ public class AltosGreatCircle {
                elevation = Math.atan2(height_diff, distance) * 180 / Math.PI;
        }
 
+       public AltosGreatCircle clone() {
+               AltosGreatCircle n = new AltosGreatCircle();
+
+               n.distance = distance;
+               n.bearing = bearing;
+               n.range = range;
+               n.elevation = elevation;
+               return n;
+       }
+
        public AltosGreatCircle (double start_lat, double start_lon,
                                 double end_lat, double end_lon) {
                this(start_lat, start_lon, 0, end_lat, end_lon, 0);
index ed590812c5245b7076955b7e583d0337ffc47d4a..84bd42d91589e1324bf1cb5dc825e5f9ca488269 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosHeight extends AltosUnits {
 
-       public double value(double v) {
-               if (AltosConvert.imperial_units)
+       public double value(double v, boolean imperial_units) {
+               if (imperial_units)
                        return AltosConvert.meters_to_feet(v);
                return v;
        }
 
-       public String show_units() {
-               if (AltosConvert.imperial_units)
+       public double inverse(double v, boolean imperial_units) {
+               if (imperial_units)
+                       return AltosConvert.feet_to_meters(v);
+               return v;
+       }
+
+       public String show_units(boolean imperial_units) {
+               if (imperial_units)
                        return "ft";
                return "m";
        }
 
-       public String say_units() {
-               if (AltosConvert.imperial_units)
+       public String say_units(boolean imperial_units) {
+               if (imperial_units)
                        return "feet";
                return "meters";
        }
 
-       public int show_fraction(int width) {
+       public int show_fraction(int width, boolean imperial_units) {
                return width / 9;
        }
 }
\ No newline at end of file
index 2140228a179f44acf126c5f3288a438a9bd6464f..717c1c5d813778ba73ed6d5755527c83d86f6f53 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 import java.util.LinkedList;
@@ -116,7 +116,7 @@ class HexRecord implements Comparable<Object> {
                return String.format("%04x: %02x (%d)", address, type, data.length);
        }
 
-       public HexRecord(HexFileInputStream input) throws IOException {
+       public HexRecord(HexFileInputStream input) throws IOException, EOFException {
                read_state      state = read_state.marker;
                int             nhexbytes = 0;
                int             hex = 0;
@@ -125,14 +125,16 @@ class HexRecord implements Comparable<Object> {
 
                while (state != read_state.done) {
                        int c = input.read();
-                       if (c < 0 && state != read_state.white)
+                       if (c < 0 && state != read_state.white && state != read_state.marker)
                                throw new IOException(String.format("%d: Unexpected EOF", input.line));
                        if (c == ' ')
                                continue;
                        switch (state) {
                        case marker:
+                               if (c == EOF || c == -1)
+                                       throw new EOFException();
                                if (c != ':')
-                                       throw new IOException("Missing ':'");
+                                       throw new IOException(String.format ("Missing ':' (got %x)", c));
                                state = read_state.length;
                                nhexbytes = 2;
                                hex = 0;
@@ -208,25 +210,82 @@ class HexRecord implements Comparable<Object> {
 }
 
 public class AltosHexfile {
-       public int      address;
-       public byte[]   data;
+       public int              address;
+       public byte[]           data;
+       LinkedList<AltosHexsym> symlist = new LinkedList<AltosHexsym>();
 
        public byte get_byte(int a) {
                return data[a - address];
        }
 
+       /* CC1111-based products have the romconfig stuff located
+        * at a fixed address; when the file we load has no symbols,
+        * assume it is one of those and set the symbols appropriately
+        */
+       final static int ao_romconfig_version_addr = 0xa0;
+       final static int ao_romconfig_check_addr = 0xa2;
+       final static int ao_serial_number_addr = 0xa4;
+       final static int ao_radio_cal_addr = 0xa6;
+       final static int ao_usb_descriptors_addr = 0xaa;
+
+       static AltosHexsym[] cc_symbols = {
+               new AltosHexsym("ao_romconfig_version", ao_romconfig_version_addr),
+               new AltosHexsym("ao_romconfig_check", ao_romconfig_check_addr),
+               new AltosHexsym("ao_serial_number", ao_serial_number_addr),
+               new AltosHexsym("ao_radio_cal", ao_radio_cal_addr),
+               new AltosHexsym("ao_usb_descriptors", ao_usb_descriptors_addr)
+       };
+
+       private void add_cc_symbols() {
+               for (int i = 0; i < cc_symbols.length; i++)
+                       symlist.add(cc_symbols[i]);
+       }
+
+       public void add_symbol(AltosHexsym symbol) {
+               symlist.add(symbol);
+       }
+
+       /* Take symbols from another hexfile and duplicate them here */
+       public void add_symbols(AltosHexfile other) {
+               for (AltosHexsym symbol : other.symlist)
+                       symlist.add(symbol);
+       }
+
+       public AltosHexsym lookup_symbol(String name) {
+               if (symlist.isEmpty())
+                       add_cc_symbols();
+
+               for (AltosHexsym symbol : symlist)
+                       if (name.equals(symbol.name))
+                               return symbol;
+               return null;
+       }
+
+       private String make_string(byte[] data, int start, int length) {
+               String s = "";
+               for (int i = 0; i < length; i++)
+                       s += (char) data[start + i];
+               return s;
+       }
+
+       public AltosHexfile(byte[] bytes, int offset) {
+               data = bytes;
+               address = offset;
+       }
+
        public AltosHexfile(FileInputStream file) throws IOException {
                HexFileInputStream      input = new HexFileInputStream(file);
                LinkedList<HexRecord>   record_list = new LinkedList<HexRecord>();
                boolean                 done = false;
 
                while (!done) {
-                       HexRecord       record = new HexRecord(input);
+                       try {
+                               HexRecord       record = new HexRecord(input);
 
-                       if (record.type == HexRecord.EOF)
-                               done = true;
-                       else
                                record_list.add(record);
+                       } catch (EOFException eof) {
+                               done = true;
+                       }
                }
 
                long    extended_addr = 0;
@@ -234,9 +293,10 @@ public class AltosHexfile {
                long    bound = 0;
                boolean set = false;
                for (HexRecord record : record_list) {
+                       long addr;
                        switch (record.type) {
                        case 0:
-                               long addr = extended_addr + record.address;
+                               addr = extended_addr + record.address;
                                long r_bound = addr + record.data.length;
                                if (!set || addr < base)
                                        base = addr;
@@ -256,6 +316,12 @@ public class AltosHexfile {
                                        throw new IOException("invalid extended segment address record");
                                extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16;
                                break;
+                       case 0xfe:
+                               String name = make_string(record.data, 0, record.data.length);
+                               addr = extended_addr + record.address;
+                               AltosHexsym s = new AltosHexsym(name, addr);
+                               symlist.add(s);
+                               break;
                        default:
                                throw new IOException ("invalid hex record type");
                        }
@@ -292,6 +358,8 @@ public class AltosHexfile {
                                        throw new IOException("invalid extended segment address record");
                                extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16;
                                break;
+                       case 0xfe:
+                               break;
                        default:
                                throw new IOException ("invalid hex record type");
                        }
diff --git a/altoslib/AltosHexsym.java b/altoslib/AltosHexsym.java
new file mode 100644 (file)
index 0000000..810a480
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosHexsym {
+       String  name;
+       long    address;
+
+       final static long invalid_addr = 0xffffffff;
+
+       public AltosHexsym(String name, long address) {
+               this.name = name;
+               this.address = address;
+       }
+}
\ No newline at end of file
index 8f6731faa5a9bebbbbf1712d0502a4bf4d471042..6d88ccae9a45f6a45926444528db9debc04993b4 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
-public class AltosIMU {
+import java.util.concurrent.*;
+
+public class AltosIMU implements Cloneable {
        public int              accel_x;
        public int              accel_y;
        public int              accel_z;
@@ -25,5 +27,67 @@ public class AltosIMU {
        public int              gyro_x;
        public int              gyro_y;
        public int              gyro_z;
+
+       public boolean parse_string(String line) {
+               if (!line.startsWith("Accel:"))
+                       return false;
+
+               String[] items = line.split("\\s+");
+
+               if (items.length >= 8) {
+                       accel_x = Integer.parseInt(items[1]);
+                       accel_y = Integer.parseInt(items[2]);
+                       accel_z = Integer.parseInt(items[3]);
+                       gyro_x = Integer.parseInt(items[5]);
+                       gyro_y = Integer.parseInt(items[6]);
+                       gyro_z = Integer.parseInt(items[7]);
+               }
+               return true;
+       }
+
+       public AltosIMU clone() {
+               AltosIMU        n = new AltosIMU();
+
+               n.accel_x = accel_x;
+               n.accel_y = accel_y;
+               n.accel_z = accel_z;
+
+               n.gyro_x = gyro_x;
+               n.gyro_y = gyro_y;
+               n.gyro_z = gyro_z;
+               return n;
+       }
+
+       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+               try {
+                       AltosIMU        imu = new AltosIMU(link);
+
+                       if (imu != null)
+                               state.set_imu(imu);
+               } catch (TimeoutException te) {
+               }
+       }
+
+       public AltosIMU() {
+               accel_x = AltosLib.MISSING;
+               accel_y = AltosLib.MISSING;
+               accel_z = AltosLib.MISSING;
+
+               gyro_x = AltosLib.MISSING;
+               gyro_y = AltosLib.MISSING;
+               gyro_z = AltosLib.MISSING;
+       }
+
+       public AltosIMU(AltosLink link) throws InterruptedException, TimeoutException {
+               this();
+               link.printf("I\n");
+               for (;;) {
+                       String line = link.get_reply_no_dialog(5000);
+                       if (line == null) {
+                               throw new TimeoutException();
+                       }
+                       if (parse_string(line))
+                               break;
+               }
+       }
 }
-       
\ No newline at end of file
diff --git a/altoslib/AltosIMUQuery.java b/altoslib/AltosIMUQuery.java
deleted file mode 100644 (file)
index 4ea5d96..0000000
+++ /dev/null
@@ -1,46 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.util.concurrent.TimeoutException;
-
-class AltosIMUQuery extends AltosIMU {
-
-       public AltosIMUQuery (AltosLink link) throws InterruptedException, TimeoutException {
-               link.printf("I\n");
-               for (;;) {
-                       String line = link.get_reply_no_dialog(5000);
-                       if (line == null) {
-                               throw new TimeoutException();
-                       }
-                       if (!line.startsWith("Accel:"))
-                               continue;
-                       String[] items = line.split("\\s+");
-                       if (items.length >= 8) {
-                               accel_x = Integer.parseInt(items[1]);
-                               accel_y = Integer.parseInt(items[2]);
-                               accel_z = Integer.parseInt(items[3]);
-                               gyro_x = Integer.parseInt(items[5]);
-                               gyro_y = Integer.parseInt(items[6]);
-                               gyro_z = Integer.parseInt(items[7]);
-                       }
-                       break;
-               }
-       }
-}
-
diff --git a/altoslib/AltosIdle.java b/altoslib/AltosIdle.java
new file mode 100644 (file)
index 0000000..456a924
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.concurrent.*;
+
+public abstract class AltosIdle {
+       AltosLink       link;
+       AltosConfigData config_data;
+
+       public void printf(String format, Object ... arguments) {
+               link.printf(format, arguments);
+       }
+
+       public abstract void update_state(AltosState state) throws InterruptedException, TimeoutException;
+
+       public AltosIdle(AltosLink link, AltosConfigData config_data) {
+               this.link = link;
+               this.config_data = config_data;
+       }
+}
diff --git a/altoslib/AltosIdleFetch.java b/altoslib/AltosIdleFetch.java
new file mode 100644 (file)
index 0000000..4adc6c4
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.concurrent.*;
+
+class AltosIdler {
+       String  prefix;
+       int[]   idlers;
+
+       static final int        idle_gps = 0;
+       static final int        idle_imu = 1;
+       static final int        idle_mag = 2;
+       static final int        idle_ms5607 = 3;
+       static final int        idle_mma655x = 4;
+
+
+       static final int        idle_sensor_tm = 10;
+       static final int        idle_sensor_metrum = 11;
+       static final int        idle_sensor_mega = 12;
+       static final int        idle_sensor_emini = 13;
+       static final int        idle_sensor_tmini = 14;
+
+       public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException {
+               for (int idler : idlers) {
+                       AltosIdle idle = null;
+                       switch (idler) {
+                       case idle_gps:
+                               AltosGPS.update_state(state, link, config_data);
+                               break;
+                       case idle_imu:
+                               AltosIMU.update_state(state, link, config_data);
+                               break;
+                       case idle_mag:
+                               AltosMag.update_state(state, link, config_data);
+                               break;
+                       case idle_ms5607:
+                               AltosMs5607.update_state(state, link, config_data);
+                               break;
+                       case idle_mma655x:
+                               AltosMma655x.update_state(state, link, config_data);
+                               break;
+                       case idle_sensor_tm:
+                               AltosSensorTM.update_state(state, link, config_data);
+                               break;
+                       case idle_sensor_metrum:
+                               AltosSensorMetrum.update_state(state, link, config_data);
+                               break;
+                       case idle_sensor_mega:
+                               AltosSensorMega.update_state(state, link, config_data);
+                               break;
+                       case idle_sensor_emini:
+                               AltosSensorEMini.update_state(state, link, config_data);
+                               break;
+                       case idle_sensor_tmini:
+                               AltosSensorTMini.update_state(state, link, config_data);
+                       }
+                       if (idle != null)
+                               idle.update_state(state);
+               }
+       }
+
+       public boolean matches(AltosConfigData config_data) {
+               return config_data.product.startsWith(prefix);
+       }
+
+       public AltosIdler(String prefix, int ... idlers) {
+               this.prefix = prefix;
+               this.idlers = idlers;
+       }
+}
+
+
+public class AltosIdleFetch implements AltosStateUpdate {
+
+       static final AltosIdler[] idlers = {
+
+               new AltosIdler("EasyMini",
+                              AltosIdler.idle_ms5607,
+                              AltosIdler.idle_sensor_emini),
+
+               new AltosIdler("TeleMini-v1",
+                              AltosIdler.idle_sensor_tm),
+
+               new AltosIdler("TeleMini-v2",
+                              AltosIdler.idle_ms5607,
+                              AltosIdler.idle_sensor_tmini),
+
+               new AltosIdler("TeleMetrum-v1",
+                              AltosIdler.idle_gps,
+                              AltosIdler.idle_sensor_tm),
+
+               new AltosIdler("TeleMetrum-v2",
+                              AltosIdler.idle_gps,
+                              AltosIdler.idle_ms5607, AltosIdler.idle_mma655x,
+                              AltosIdler.idle_sensor_metrum),
+
+               new AltosIdler("TeleMega",
+                              AltosIdler.idle_gps,
+                              AltosIdler.idle_ms5607, AltosIdler.idle_mma655x,
+                              AltosIdler.idle_imu, AltosIdler.idle_mag,
+                              AltosIdler.idle_sensor_mega),
+       };
+
+       AltosLink               link;
+
+       double                  frequency;
+       String                  callsign;
+
+       public void update_state(AltosState state) throws InterruptedException {
+               try {
+                       AltosConfigData config_data = new AltosConfigData(link);
+                       state.set_state(AltosLib.ao_flight_startup);
+                       state.set_serial(config_data.serial);
+                       state.set_callsign(config_data.callsign);
+                       state.set_ground_accel(config_data.accel_cal_plus);
+                       state.set_accel_g(config_data.accel_cal_plus, config_data.accel_cal_minus);
+                       for (AltosIdler idler : idlers) {
+                               if (idler.matches(config_data)) {
+                                       idler.update_state(state, link, config_data);
+                                       break;
+                               }
+                       }
+                       state.set_received_time(System.currentTimeMillis());
+               } catch (TimeoutException te) {
+               }
+               
+       }
+
+       public AltosIdleFetch(AltosLink link) {
+               this.link = link;
+       }
+}
index b3ce5b204a8774976f9764fb2d738d37de99fdf1..d9d71143a0f5f4fea10ea535e00498fcc5e2fdd6 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 import java.util.concurrent.*;
@@ -24,11 +24,13 @@ import java.util.concurrent.*;
 public class AltosIdleMonitor extends Thread {
        AltosLink               link;
        AltosIdleMonitorListener        listener;
-       AltosState              state;
+
+       AltosIdleFetch          fetch;
+
        boolean                 remote;
        double                  frequency;
        String                  callsign;
-       AltosState              previous_state;
+
        AltosListenerState      listener_state;
        AltosConfigData         config_data;
        AltosGPS                gps;
@@ -47,86 +49,35 @@ public class AltosIdleMonitor extends Thread {
                return rssi;
        }
 
-       boolean has_sensor_tm(AltosConfigData config_data) {
-               return config_data.product.startsWith("TeleMetrum") || config_data.product.startsWith("TeleMini");
-       }
-
-       boolean has_sensor_mm(AltosConfigData config_data) {
-               return config_data.product.startsWith("TeleMega");
+       void start_link() throws InterruptedException, TimeoutException {
+               if (remote) {
+                       link.set_radio_frequency(frequency);
+                       link.set_callsign(callsign);
+                       link.start_remote();
+               } else
+                       link.flush_input();
        }
 
-       boolean has_gps(AltosConfigData config_data) {
-               return config_data.product.startsWith("TeleMetrum") || config_data.product.startsWith("TeleMega");
-       }
-
-       AltosRecord sensor_mm(AltosConfigData config_data) throws InterruptedException, TimeoutException {
-               AltosRecordMM record_mm = new AltosRecordMM();
-               AltosSensorMM sensor = new AltosSensorMM(link);
-               AltosMs5607 ms5607 = new AltosMs5607Query(link);
-               AltosIMU imu = new AltosIMUQuery(link);
-
-               record_mm.accel_plus_g = config_data.accel_cal_plus;
-               record_mm.accel_minus_g = config_data.accel_cal_minus;
-
-               record_mm.ground_accel = sensor.accel;
-               record_mm.accel = sensor.accel;
-               record_mm.ground_pres = ms5607.pa;
-               record_mm.pres = ms5607.pa;
-               record_mm.temp = ms5607.cc;
-
-               record_mm.v_batt = sensor.v_batt;
-               record_mm.v_pyro = sensor.v_pyro;
-               record_mm.sense = sensor.sense;
-
-               record_mm.imu = imu;
-
-               return record_mm;
+       void stop_link() throws InterruptedException, TimeoutException {
+               if (remote)
+                       link.stop_remote();
        }
 
-       void update_state() throws InterruptedException, TimeoutException {
-               AltosRecord     record = null;
+       void update_state(AltosState state) throws InterruptedException, TimeoutException {
+               boolean         worked = false;
 
                try {
-                       if (remote) {
-                               link.set_radio_frequency(frequency);
-                               link.set_callsign(callsign);
-                               link.start_remote();
-                       } else
-                               link.flush_input();
-                       config_data = new AltosConfigData(link);
-
-                       if (has_sensor_tm(config_data))
-                               record = new AltosSensorTM(link, config_data);
-                       else if (has_sensor_mm(config_data))
-                               record = sensor_mm(config_data);
-                       else
-                               record = new AltosRecordNone();
-
-                       if (has_gps(config_data))
-                               gps = new AltosGPSQuery(link, config_data);
-
-                       record.version = 0;
-                       record.callsign = config_data.callsign;
-                       record.serial = config_data.serial;
-                       record.flight = config_data.log_available() > 0 ? 255 : 0;
-                       record.status = 0;
-                       record.state = AltosLib.ao_flight_idle;
-                       record.gps = gps;
-                       record.gps_sequence++;
-                       state = new AltosState (record, state);
+                       start_link();
+                       fetch.update_state(state);
+                       worked = true;
                } finally {
-                       if (remote) {
-                               link.stop_remote();
-                               if (record != null) {
-                                       record.rssi = link.rssi();
-                                       listener_state.battery = link.monitor_battery();
-                               }
-                       } else {
-                               if (record != null)
-                                       record.rssi = 0;
+                       stop_link();
+                       if (worked) {
+                               if (remote)
+                                       state.set_rssi(link.rssi(), 0);
+                               listener_state.battery = link.monitor_battery();
                        }
                }
-
        }
 
        public void set_frequency(double in_frequency) {
@@ -139,33 +90,32 @@ public class AltosIdleMonitor extends Thread {
                link.abort_reply();
        }
 
-       public void post_state() {
-               listener.update(state, listener_state);
-       }
-
-       public void abort() {
-               if (isAlive()) {
+       public void abort() throws InterruptedException {
+               while (isAlive()) {
                        interrupt();
                        link.abort_reply();
-                       try {
-                               join();
-                       } catch (InterruptedException ie) {
-                       }
+                       Thread.sleep(100);
                }
+               join();
        }
 
        public void run() {
+               AltosState state = new AltosState();
                try {
-                       for (;;) {
+                       while (!link.has_error) {
                                try {
-                                       update_state();
-                                       post_state();
+                                       link.config_data();
+                                       update_state(state);
+                                       listener.update(state, listener_state);
                                } catch (TimeoutException te) {
                                }
                                Thread.sleep(1000);
                        }
                } catch (InterruptedException ie) {
+               }
+               try {
                        link.close();
+               } catch (InterruptedException ie) {
                }
        }
 
@@ -174,7 +124,7 @@ public class AltosIdleMonitor extends Thread {
                listener = in_listener;
                link = in_link;
                remote = in_remote;
-               state = null;
                listener_state = new AltosListenerState();
+               fetch = new AltosIdleFetch(link);
        }
 }
index 27e36dea2ce6b4f673bc47f3623c4e0e0d07810b..0b03b897ae3139ebb27ef7c12a26976e61885aaa 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public interface AltosIdleMonitorListener {
        public void update(AltosState state, AltosListenerState listener_state);
index 859059008cbfd838e8c9ff3aadd0704c8fe230f1..fc9599b65ce4cb8aa44ed66dc31011240d5b5b7f 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 import java.util.concurrent.*;
@@ -141,7 +141,7 @@ public class AltosIgnite {
                }
        }
 
-       public void fire(int igniter) {
+       public void fire(int igniter) throws InterruptedException {
                if (link == null)
                        return;
                try {
@@ -154,21 +154,14 @@ public class AltosIgnite {
                                link.printf("i DoIt drogue\n");
                                break;
                        }
-               } catch (InterruptedException ie) {
                } catch (TimeoutException te) {
                } finally {
-                       try {
-                               stop_link();
-                       } catch (InterruptedException ie) {
-                       }
+                       stop_link();
                }
        }
 
-       public void close() {
-               try {
-                       stop_link();
-               } catch (InterruptedException ie) {
-               }
+       public void close() throws InterruptedException {
+               stop_link();
                link.close();
                link = null;
        }
index 25d17e726bf01727c2720d6aba01c1e6772eb722..efbc3ddbe69c15f57bee5ae272673d2749c14b77 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.util.*;
 import java.io.*;
@@ -28,6 +28,7 @@ public class AltosLib {
        public static final int AO_LOG_TEMP_VOLT = 'T';
        public static final int AO_LOG_DEPLOY = 'D';
        public static final int AO_LOG_STATE = 'S';
+       public static final int AO_LOG_GPS_POS = 'P';
        public static final int AO_LOG_GPS_TIME = 'G';
        public static final int AO_LOG_GPS_LAT = 'N';
        public static final int AO_LOG_GPS_LON = 'W';
@@ -62,6 +63,8 @@ public class AltosLib {
 
        public static final int AO_LOG_SOFTWARE_VERSION = 9999;
 
+       public final static int MISSING = 0x7fffffff;
+
        /* Added to flag invalid records */
        public static final int AO_LOG_INVALID = -1;
 
@@ -92,16 +95,59 @@ public class AltosLib {
        public final static int product_telemega = 0x0023;
        public final static int product_megadongle = 0x0024;
        public final static int product_telegps = 0x0025;
+       public final static int product_easymini = 0x0026;
+       public final static int product_telemini = 0x0027;
        public final static int product_altusmetrum_min = 0x000a;
-       public final static int product_altusmetrum_max = 0x0025;
+       public final static int product_altusmetrum_max = 0x002c;
 
        public final static int product_any = 0x10000;
        public final static int product_basestation = 0x10000 + 1;
        public final static int product_altimeter = 0x10000 + 2;
 
+       private static class Product {
+               final String    name;
+               final int       product;
+
+               Product (String name, int product) {
+                       this.name = name;
+                       this.product = product;
+               }
+       }
+
+       private static Product[] products = {
+               new Product("telemetrum", product_telemetrum),
+               new Product("teleballoon", product_telemetrum),
+               new Product("teledongle", product_teledongle),
+               new Product("teleterra", product_teledongle),
+               new Product("telebt", product_telebt),
+               new Product("telelaunch", product_telelaunch),
+               new Product("telelco", product_telelco),
+               new Product("telescience", product_telescience),
+               new Product("telepyro", product_telepyro),
+               new Product("telemega", product_telemega),
+               new Product("megadongle", product_megadongle),
+               new Product("telegps", product_telegps),
+               new Product("easymini", product_easymini),
+               new Product("telemini", product_telemini)
+       };
+
+       public static int name_to_product(String name) {
+               String low = name.toLowerCase();
+
+               for (int i = 0; i < products.length; i++)
+                       if (low.startsWith(products[i].name))
+                               return products[i].product;
+               return product_any;
+       }
+
        /* Bluetooth "identifier" (bluetooth sucks) */
        public final static String bt_product_telebt = "TeleBT";
 
+       /* "good" voltages */
+
+       public final static double ao_battery_good = 3.8;
+       public final static double ao_igniter_good = 3.5;
+
        /* Telemetry modes */
        public static final int ao_telemetry_off = 0;
        public static final int ao_telemetry_min = 1;
@@ -216,6 +262,9 @@ public class AltosLib {
        public static final int AO_LOG_FORMAT_TELEMETRY = 3;
        public static final int AO_LOG_FORMAT_TELESCIENCE = 4;
        public static final int AO_LOG_FORMAT_TELEMEGA = 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_NONE = 127;
 
        public static boolean isspace(int c) {
@@ -410,4 +459,24 @@ public class AltosLib {
        public static File replace_extension(File input, String extension) {
                return new File(replace_extension(input.getPath(), extension));
        }
+
+       public static String product_name(int product_id) {
+               switch (product_id) {
+               case product_altusmetrum: return "AltusMetrum";
+               case product_telemetrum: return "TeleMetrum";
+               case product_teledongle: return "TeleDongle";
+               case product_teleterra: return "TeleTerra";
+               case product_telebt: return "TeleBT";
+               case product_telelaunch: return "TeleLaunch";
+               case product_telelco: return "TeleLco";
+               case product_telescience: return "Telescience";
+               case product_telepyro: return "TelePyro";
+               case product_telemega: return "TeleMega";
+               case product_megadongle: return "MegaDongle";
+               case product_telegps: return "TeleGPS";
+               case product_easymini: return "EasyMini";
+               case product_telemini: return "TeleMini";
+               default: return "unknown";
+               }
+       }
 }
index b3bd20f97bc71071ddf49d751ae1101012a56afe..e5dd13fc2901c7d582be2c937ea7560409454e75 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosLine {
        public String   line;
index 159ebfe19c234b34b423a6619e56d18f7ca6f433..ee1f9785bb7a111158edceb3cc249afa0f5f3014 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 import java.util.concurrent.*;
@@ -26,23 +26,28 @@ public abstract class AltosLink implements Runnable {
        public final static int ERROR = -1;
        public final static int TIMEOUT = -2;
 
-       public abstract int getchar();
-       public abstract void print(String data);
-       public abstract void close();
+       public abstract int getchar() throws InterruptedException;
+       public abstract void print(String data) throws InterruptedException;
+       public abstract void putchar(byte c);
+       public abstract void close() throws InterruptedException;
 
        public static boolean debug = false;
        public static void set_debug(boolean in_debug) { debug = in_debug; }
+
+       public boolean has_error;
+
        LinkedList<String> pending_output = new LinkedList<String>();
 
        public LinkedList<LinkedBlockingQueue<AltosLine>> monitors = new LinkedList<LinkedBlockingQueue<AltosLine>> ();;
        public LinkedBlockingQueue<AltosLine> reply_queue = new LinkedBlockingQueue<AltosLine>();
+       public LinkedBlockingQueue<byte[]> binary_queue = new LinkedBlockingQueue<byte[]>();
 
-       public void add_monitor(LinkedBlockingQueue<AltosLine> q) {
+       public synchronized void add_monitor(LinkedBlockingQueue<AltosLine> q) {
                set_monitor(true);
                monitors.add(q);
        }
 
-       public void remove_monitor(LinkedBlockingQueue<AltosLine> q) {
+       public synchronized void remove_monitor(LinkedBlockingQueue<AltosLine> q) {
                monitors.remove(q);
                if (monitors.isEmpty())
                        set_monitor(false);
@@ -52,7 +57,11 @@ public abstract class AltosLink implements Runnable {
                String  line = String.format(format, arguments);
                if (debug)
                        pending_output.add(line);
-               print(line);
+               try {
+                       print(line);
+               } catch (InterruptedException ie) {
+
+               }
        }
 
        public String get_reply_no_dialog(int timeout) throws InterruptedException, TimeoutException {
@@ -90,6 +99,7 @@ public abstract class AltosLink implements Runnable {
                }
        }
 
+       private int     len_read = 0;
 
        public void run () {
                int c;
@@ -100,13 +110,12 @@ public abstract class AltosLink implements Runnable {
                        for (;;) {
                                c = getchar();
                                if (Thread.interrupted()) {
-                                       if (debug)
-                                               System.out.printf("INTERRUPTED\n");
                                        break;
                                }
                                if (c == ERROR) {
                                        if (debug)
                                                System.out.printf("ERROR\n");
+                                       has_error = true;
                                        add_telem (new AltosLine());
                                        add_reply (new AltosLine());
                                        break;
@@ -116,10 +125,10 @@ public abstract class AltosLink implements Runnable {
                                                System.out.printf("TIMEOUT\n");
                                        continue;
                                }
-                               if (c == '\r')
+                               if (c == '\r' && len_read == 0)
                                        continue;
                                synchronized(this) {
-                                       if (c == '\n') {
+                                       if (c == '\n' && len_read == 0) {
                                                if (line_count != 0) {
                                                        add_bytes(line_bytes, line_count);
                                                        line_count = 0;
@@ -134,6 +143,11 @@ public abstract class AltosLink implements Runnable {
                                                }
                                                line_bytes[line_count] = (byte) c;
                                                line_count++;
+                                               if (len_read !=0 && line_count == len_read) {
+                                                       add_binary(line_bytes, line_count);
+                                                       line_count = 0;
+                                                       len_read = 0;
+                                               }
                                        }
                                }
                        }
@@ -141,6 +155,7 @@ public abstract class AltosLink implements Runnable {
                }
        }
 
+
        public String get_reply(int timeout) throws InterruptedException {
                boolean can_cancel = can_cancel_reply();
                String  reply = null;
@@ -175,6 +190,38 @@ public abstract class AltosLink implements Runnable {
                return reply;
        }
 
+       public byte[] get_binary_reply(int timeout, int len) throws InterruptedException {
+               boolean can_cancel = can_cancel_reply();
+               byte[] bytes = null;
+
+               synchronized(this) {
+                       len_read = len;
+               }
+               try {
+                       ++in_reply;
+
+                       flush_output();
+
+                       reply_abort = false;
+                       reply_timeout_shown = false;
+                       for (;;) {
+                               bytes = binary_queue.poll(timeout, TimeUnit.MILLISECONDS);
+                               if (bytes != null) {
+                                       cleanup_reply_timeout();
+                                       break;
+                               }
+                               if (!remote || !can_cancel || check_reply_timeout()) {
+                                       bytes = null;
+                                       break;
+                               }
+                       }
+                       
+               } finally {
+                       --in_reply;
+               }
+               return bytes;
+       }
+
        public void add_telem(AltosLine line) throws InterruptedException {
                for (int e = 0; e < monitors.size(); e++) {
                        LinkedBlockingQueue<AltosLine> q = monitors.get(e);
@@ -190,7 +237,7 @@ public abstract class AltosLink implements Runnable {
                try {
                        add_telem (new AltosLine());
                        add_reply (new AltosLine());
-               } catch (InterruptedException e) {
+               } catch (InterruptedException ie) {
                }
        }
 
@@ -216,6 +263,22 @@ public abstract class AltosLink implements Runnable {
                add_string(line);
        }
 
+       public void add_binary(byte[] bytes, int len) throws InterruptedException {
+               byte[] dup = new byte[len];
+
+               if (debug)
+                       System.out.printf ("\t\t\t\t\t%d:", len);
+               for(int i = 0; i < len; i++) {
+                       dup[i] = bytes[i];
+                       if (debug)
+                               System.out.printf(" %02x", dup[i]);
+               }
+               if (debug)
+                       System.out.printf("\n");
+
+               binary_queue.put(dup);
+       }
+
        public void flush_output() {
                for (String s : pending_output)
                        System.out.print(s);
@@ -252,6 +315,8 @@ public abstract class AltosLink implements Runnable {
        public String callsign;
        AltosConfigData config_data;
 
+       private Object config_data_lock = new Object();
+
        private int telemetry_len() {
                return AltosLib.telemetry_len(telemetry);
        }
@@ -325,9 +390,11 @@ public abstract class AltosLink implements Runnable {
        }
 
        public AltosConfigData config_data() throws InterruptedException, TimeoutException {
-               if (config_data == null)
-                       config_data = new AltosConfigData(this);
-               return config_data;
+               synchronized(config_data_lock) {
+                       if (config_data == null)
+                               config_data = new AltosConfigData(this);
+                       return config_data;
+               }
        }
 
        public void set_callsign(String callsign) {
@@ -336,6 +403,29 @@ public abstract class AltosLink implements Runnable {
                flush_output();
        }
 
+       public boolean is_loader() throws InterruptedException {
+               boolean ret = false;
+               printf("v\n");
+               for (;;) {
+                       String line = get_reply();
+
+                       if (line == null)
+                               return false;
+                       if (line.startsWith("software-version"))
+                               break;
+                       if (line.startsWith("altos-loader"))
+                               ret = true;
+               }
+               return ret;
+       }
+
+       public void to_loader() throws InterruptedException {
+               printf("X\n");
+               flush_output();
+               close();
+               Thread.sleep(1000);
+       }
+
        public boolean remote;
        public int serial;
        public String name;
@@ -398,8 +488,8 @@ public abstract class AltosLink implements Runnable {
                return config_data.has_monitor_battery();
        }
 
-       public double monitor_battery() {
-               int monitor_batt = AltosRecord.MISSING;
+       public double monitor_battery() throws InterruptedException {
+               int monitor_batt = AltosLib.MISSING;
 
                if (config_data.has_monitor_battery()) {
                        try {
@@ -412,16 +502,16 @@ public abstract class AltosLink implements Runnable {
                                }
                                i++;
                        }
-                       } catch (InterruptedException ie) {
                        } catch (TimeoutException te) {
                        }
                }
-               if (monitor_batt == AltosRecord.MISSING)
-                       return AltosRecord.MISSING;
+               if (monitor_batt == AltosLib.MISSING)
+                       return AltosLib.MISSING;
                return AltosConvert.cc_battery_to_voltage(monitor_batt);
        }
 
        public AltosLink() {
                callsign = "";
+               has_error = false;
        }
 }
index 2fb4673edcc5c87885f6ae03328959f9f8cd9502..01dd7afb4e6f7b9a6c7e52adec741584d0c1a31c 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosListenerState {
        public int      crc_errors;
@@ -23,6 +23,6 @@ public class AltosListenerState {
 
        public AltosListenerState() {
                crc_errors = 0;
-               battery = AltosRecord.MISSING;
+               battery = AltosLib.MISSING;
        }
 }
index 974c9f0f90ab6c189c1dbb718a6d0e02af809207..d4fbee97bc47e491a326bf33135a6e9424fb7039 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
-import java.text.ParseException;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.text.*;
+import java.util.concurrent.*;
 
 /*
  * This creates a thread to capture telemetry data and write it to
@@ -31,9 +31,11 @@ public class AltosLog implements Runnable {
        LinkedBlockingQueue<String>     pending_queue;
        int                             serial;
        int                             flight;
+       int                             receiver_serial;
        FileWriter                      log_file;
        Thread                          log_thread;
        AltosFile                       file;
+       AltosLink                       link;
 
        private void close_log_file() {
                if (log_file != null) {
@@ -57,18 +59,15 @@ public class AltosLog implements Runnable {
                return file;
        }
 
-       boolean open (AltosRecord telem) throws IOException {
-               AltosFile       a = new AltosFile(telem);
+       boolean open (AltosState state) throws IOException, InterruptedException {
+               AltosFile       a = new AltosFile(state);
 
                log_file = new FileWriter(a, true);
                if (log_file != null) {
                        while (!pending_queue.isEmpty()) {
-                               try {
-                                       String s = pending_queue.take();
-                                       log_file.write(s);
-                                       log_file.write('\n');
-                               } catch (InterruptedException ie) {
-                               }
+                               String s = pending_queue.take();
+                               log_file.write(s);
+                               log_file.write('\n');
                        }
                        log_file.flush();
                        file = a;
@@ -78,22 +77,25 @@ public class AltosLog implements Runnable {
 
        public void run () {
                try {
-                       AltosRecord     previous = null;
+                       AltosState      state = new AltosState();
+                       AltosConfigData receiver_config = link.config_data();
+                       state.set_receiver_serial(receiver_config.serial);
                        for (;;) {
                                AltosLine       line = input_queue.take();
                                if (line.line == null)
                                        continue;
                                try {
-                                       AltosRecord     telem = AltosTelemetry.parse(line.line, previous);
-                                       if ((telem.seen & AltosRecord.seen_flight) != 0 &&
-                                           (telem.serial != serial || telem.flight != flight || log_file == null))
+                                       AltosTelemetry  telem = AltosTelemetry.parse(line.line);
+                                       state = state.clone();
+                                       telem.update_state(state);
+                                       if (state.serial != serial || state.flight != flight || log_file == null)
                                        {
                                                close_log_file();
-                                               serial = telem.serial;
-                                               flight = telem.flight;
-                                               open(telem);
+                                               serial = state.serial;
+                                               flight = state.flight;
+                                               if (state.serial != AltosLib.MISSING && state.flight != AltosLib.MISSING)
+                                                       open(state);
                                        }
-                                       previous = telem;
                                } catch (ParseException pe) {
                                } catch (AltosCRCException ce) {
                                }
@@ -105,6 +107,7 @@ public class AltosLog implements Runnable {
                                        pending_queue.put(line.line);
                        }
                } catch (InterruptedException ie) {
+               } catch (TimeoutException te) {
                } catch (IOException ie) {
                }
                close();
@@ -116,6 +119,7 @@ public class AltosLog implements Runnable {
                link.add_monitor(input_queue);
                serial = -1;
                flight = -1;
+               this.link = link;
                log_file = null;
                log_thread = new Thread(this);
                log_thread.start();
index b3bbd92fa9843acbcbdf633489e7c0c741357af2..89e72bd6e5983153dcacb499011a254369aa946f 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
-public class AltosMag {
+import java.util.concurrent.*;
+
+public class AltosMag implements Cloneable {
        public int              x;
        public int              y;
        public int              z;
+
+       public boolean parse_string(String line) {
+//             if (line.startsWith("Syntax error")) {
+//                     x = y = z = 0;
+//                     return true;
+//             }
+
+               if (!line.startsWith("X:"))
+                       return false;
+
+               String[] items = line.split("\\s+");
+
+               if (items.length >= 6) {
+                       x = Integer.parseInt(items[1]);
+                       y = Integer.parseInt(items[3]);
+                       z = Integer.parseInt(items[5]);
+               }
+               return true;
+       }
+
+       public AltosMag clone() {
+               AltosMag n = new AltosMag();
+
+               n.x = x;
+               n.y = y;
+               n.z = z;
+               return n;
+       }
+
+       public AltosMag() {
+               x = AltosLib.MISSING;
+               y = AltosLib.MISSING;
+               z = AltosLib.MISSING;
+       }
+
+       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+               try {
+                       AltosMag        mag = new AltosMag(link);
+
+                       if (mag != null)
+                               state.set_mag(mag);
+               } catch (TimeoutException te) {
+               }
+       }
+
+       public AltosMag(AltosLink link) throws InterruptedException, TimeoutException {
+               this();
+               link.printf("M\n");
+               for (;;) {
+                       String line = link.get_reply_no_dialog(5000);
+                       if (line == null) {
+                               throw new TimeoutException();
+                       }
+                       if (parse_string(line))
+                               break;
+               }
+       }
 }
        
\ No newline at end of file
diff --git a/altoslib/AltosMma655x.java b/altoslib/AltosMma655x.java
new file mode 100644 (file)
index 0000000..f825619
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.*;
+
+public class AltosMma655x implements Cloneable {
+
+       int     accel;
+
+       public boolean parse_line(String line) {
+               String[] items = line.split("\\s+");
+               if (line.startsWith("MMA655X value:")) {
+                       if (items.length >= 3)
+                               accel = Integer.parseInt(items[1]);
+               } else
+                       return false;
+               return true;
+       }
+
+       public AltosMma655x() {
+               accel = AltosLib.MISSING;
+       }
+
+       public AltosMma655x clone() {
+               AltosMma655x    n = new AltosMma655x();
+
+               n.accel = accel;
+               return n;
+       }
+
+       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+               try {
+                       AltosMma655x    mma655x = new AltosMma655x(link);
+
+                       if (mma655x != null)
+                               state.set_accel(mma655x.accel);
+               } catch (TimeoutException te) {
+               }
+       }
+
+       public AltosMma655x(AltosLink link) throws InterruptedException, TimeoutException {
+               this();
+               link.printf("A\n");
+               for (;;) {
+                       String line = link.get_reply_no_dialog(5000);
+                       if (line == null)
+                               throw new TimeoutException();
+                       if (!parse_line(line))
+                               break;
+               }
+       }
+}
index 606916b7b46ec84f14de302b2d7e2a011056c5f2..2319d5b821b833becd9cd72c37b796caca051aa6 100644 (file)
@@ -15,7 +15,9 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.*;
 
 public class AltosMs5607 {
        public int      reserved;
@@ -85,8 +87,9 @@ public class AltosMs5607 {
        public boolean parse_line(String line) {
                String[] items = line.split("\\s+");
                if (line.startsWith("Pressure:")) {
-                       if (items.length >= 2)
+                       if (items.length >= 2) {
                                raw_pres = Integer.parseInt(items[1]);
+                       }
                } else if (line.startsWith("Temperature:")) {
                        if (items.length >= 2)
                                raw_temp = Integer.parseInt(items[1]);
@@ -94,8 +97,9 @@ public class AltosMs5607 {
                        if (items.length >= 3)
                                reserved = Integer.parseInt(items[2]);
                } else if (line.startsWith("ms5607 sens:")) {
-                       if (items.length >= 3)
+                       if (items.length >= 3) {
                                sens = Integer.parseInt(items[2]);
+                       }
                } else if (line.startsWith("ms5607 off:")) {
                        if (items.length >= 3)
                                off = Integer.parseInt(items[2]);
@@ -114,15 +118,43 @@ public class AltosMs5607 {
                } else if (line.startsWith("ms5607 crc:")) {
                        if (items.length >= 3)
                                crc = Integer.parseInt(items[2]);
-               } else if (line.startsWith("Altitude"))
+               } else if (line.startsWith("Altitude:")) {
                        return false;
+               }
                return true;
        }
 
+       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+               try {
+                       AltosMs5607     ms5607 = new AltosMs5607(link);
+
+                       if (ms5607 != null) {
+                               state.set_ms5607(ms5607);
+                               return;
+                       }
+               } catch (TimeoutException te) {
+               }
+       }
+
        public AltosMs5607() {
-               raw_pres = AltosRecord.MISSING;
-               raw_temp = AltosRecord.MISSING;
-               pa = AltosRecord.MISSING;
-               cc = AltosRecord.MISSING;
+               raw_pres = AltosLib.MISSING;
+               raw_temp = AltosLib.MISSING;
+               pa = AltosLib.MISSING;
+               cc = AltosLib.MISSING;
+       }
+
+       public AltosMs5607 (AltosLink link) throws InterruptedException, TimeoutException {
+               this();
+               link.printf("c s\nB\n");
+               for (;;) {
+                       String line = link.get_reply_no_dialog(5000);
+                       if (line == null) {
+                               throw new TimeoutException();
+                       }
+                       if (!parse_line(line)) {
+                               break;
+                       }
+               }
+               convert();
        }
 }
diff --git a/altoslib/AltosMs5607Query.java b/altoslib/AltosMs5607Query.java
deleted file mode 100644 (file)
index d39dbf2..0000000
+++ /dev/null
@@ -1,36 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.util.concurrent.TimeoutException;
-
-class AltosMs5607Query extends AltosMs5607 {
-       public AltosMs5607Query (AltosLink link) throws InterruptedException, TimeoutException {
-               link.printf("v\nB\n");
-               for (;;) {
-                       String line = link.get_reply_no_dialog(5000);
-                       if (line == null) {
-                               throw new TimeoutException();
-                       }
-                       if (!parse_line(line))
-                               break;
-               }
-               convert();
-       }
-}
-
diff --git a/altoslib/AltosNoSymbol.java b/altoslib/AltosNoSymbol.java
new file mode 100644 (file)
index 0000000..e94687c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosNoSymbol extends Exception {
+       public AltosNoSymbol(String name) {
+               super(String.format("No such symbol \"%s\"", name));
+       }
+}
diff --git a/altoslib/AltosOrderedMegaRecord.java b/altoslib/AltosOrderedMegaRecord.java
deleted file mode 100644 (file)
index b20a5bb..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.ParseException;
-
-/*
- * AltosRecords with an index field so they can be sorted by tick while preserving
- * the original ordering for elements with matching ticks
- */
-class AltosOrderedMegaRecord extends AltosEepromMega implements Comparable<AltosOrderedMegaRecord> {
-
-       public int      index;
-
-       public AltosOrderedMegaRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid)
-               throws ParseException {
-               super(line);
-               if (prev_tick_valid) {
-                       tick |= (prev_tick & ~0xffff);
-                       if (tick < prev_tick) {
-                               if (prev_tick - tick > 0x8000)
-                                       tick += 0x10000;
-                       } else {
-                               if (tick - prev_tick > 0x8000)
-                                       tick -= 0x10000;
-                       }
-               }
-               index = in_index;
-       }
-
-       public int compareTo(AltosOrderedMegaRecord o) {
-               int     tick_diff = tick - o.tick;
-               if (tick_diff != 0)
-                       return tick_diff;
-               return index - o.index;
-       }
-}
diff --git a/altoslib/AltosOrderedRecord.java b/altoslib/AltosOrderedRecord.java
deleted file mode 100644 (file)
index 63507d3..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.ParseException;
-
-/*
- * AltosRecords with an index field so they can be sorted by tick while preserving
- * the original ordering for elements with matching ticks
- */
-class AltosOrderedRecord extends AltosEepromRecord implements Comparable<AltosOrderedRecord> {
-
-       public int      index;
-
-       public AltosOrderedRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid)
-               throws ParseException {
-               super(line);
-               if (prev_tick_valid) {
-                       tick |= (prev_tick & ~0xffff);
-                       if (tick < prev_tick) {
-                               if (prev_tick - tick > 0x8000)
-                                       tick += 0x10000;
-                       } else {
-                               if (tick - prev_tick > 0x8000)
-                                       tick -= 0x10000;
-                       }
-               }
-               index = in_index;
-       }
-
-       public AltosOrderedRecord(int in_cmd, int in_tick, int in_a, int in_b, int in_index) {
-               super(in_cmd, in_tick, in_a, in_b);
-               index = in_index;
-       }
-
-       public String toString() {
-               return String.format("%d.%d %04x %04x %04x",
-                                    cmd, index, tick, a, b);
-       }
-
-       public int compareTo(AltosOrderedRecord o) {
-               int     tick_diff = tick - o.tick;
-               if (tick_diff != 0)
-                       return tick_diff;
-               return index - o.index;
-       }
-}
-
index 66bbeed5eb185f5b101b54a1bfad369d1fb44a0b..ca96a8f94385aeb3877458628b33afb1293d48e0 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.text.*;
 
index 088ca3d7589c7507c1e17afb090158043737a218..c4051f9b58e2155a56a5a81e8ebf7d186d7f87fb 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 import java.util.*;
index fb8a235a8d5ede79f5b13f2019e2a897bc2e2808..1ea28b0131ab11510ea7fe719680036e3fc1cb81 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.File;
 
diff --git a/altoslib/AltosProgrammer.java b/altoslib/AltosProgrammer.java
new file mode 100644 (file)
index 0000000..b010d56
--- /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; 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+
+public abstract class AltosProgrammer {
+
+       abstract public void flash();
+
+       abstract public void close();
+
+       abstract public void abort();
+
+       abstract public AltosRomconfig romconfig() throws InterruptedException;
+
+       abstract public void set_romconfig(AltosRomconfig config);
+}
\ No newline at end of file
index 4dbb42234a346c1806d606b70bad05e5a079ffcd..a219468c7468cfe0c6c11607b14073b167c4deeb 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.util.*;
 import java.text.*;
@@ -28,24 +28,24 @@ public class AltosPyro {
        public static final int pyro_accel_greater              = 0x00000002;
        public static final String pyro_accel_less_string       = "a<";
        public static final String pyro_accel_greater_string    = "a>";
-       public static final String pyro_accel_less_name         = "Acceleration less than (m/s²)";
-       public static final String pyro_accel_greater_name      = "Acceleration greater than (m/s²)";
+       public static final String pyro_accel_less_name         = "Acceleration less than";
+       public static final String pyro_accel_greater_name      = "Acceleration greater than";
        public static final double pyro_accel_scale             = 16.0;
 
        public static final int pyro_speed_less                 = 0x00000004;
        public static final int pyro_speed_greater              = 0x00000008;
        public static final String pyro_speed_less_string       = "s<";
        public static final String pyro_speed_greater_string    = "s>";
-       public static final String pyro_speed_less_name         = "Speed less than (m/s)";
-       public static final String pyro_speed_greater_name      = "Speed greater than (m/s)";
+       public static final String pyro_speed_less_name         = "Speed less than";
+       public static final String pyro_speed_greater_name      = "Speed greater than";
        public static final double pyro_speed_scale             = 16.0;
 
        public static final int pyro_height_less                = 0x00000010;
        public static final int pyro_height_greater             = 0x00000020;
        public static final String pyro_height_less_string      = "h<";
        public static final String pyro_height_greater_string   = "h>";
-       public static final String pyro_height_less_name        = "Height less than (m)";
-       public static final String pyro_height_greater_name     = "Height greater than (m)";
+       public static final String pyro_height_less_name        = "Height less than";
+       public static final String pyro_height_greater_name     = "Height greater than";
        public static final double pyro_height_scale            = 1.0;
 
        public static final int pyro_orient_less                = 0x00000040;
@@ -102,12 +102,16 @@ public class AltosPyro {
 
        private static HashMap<Integer,String> pyro_to_name = new HashMap<Integer,String>();
 
+       private static HashMap<Integer,AltosUnits> pyro_to_units = new HashMap<Integer,AltosUnits>();
+
        private static HashMap<Integer,Double> pyro_to_scale = new HashMap<Integer,Double>();
        
-       private static void insert_map(int flag, String string, String name, double scale) {
+       private static void insert_map(int flag, String string, String name, AltosUnits units, double scale) {
                string_to_pyro.put(string, flag);
                pyro_to_string.put(flag, string);
                pyro_to_name.put(flag, name);
+               if (units != null)
+                       pyro_to_units.put(flag, units);
                pyro_to_scale.put(flag, scale);
        }
        
@@ -124,8 +128,22 @@ public class AltosPyro {
        }
 
        public static String pyro_to_name(int flag) {
-               if (pyro_to_name.containsKey(flag))
-                       return pyro_to_name.get(flag);
+               String          name;
+               AltosUnits      units = null;
+               if (!pyro_to_name.containsKey(flag))
+                       return null;
+
+               name = pyro_to_name.get(flag);
+               if (pyro_to_units.containsKey(flag))
+                       units = pyro_to_units.get(flag);
+               if (units == null)
+                       return name;
+               return String.format ("%s (%s)", name, units.show_units());
+       }
+
+       public static AltosUnits pyro_to_units(int flag) {
+               if (pyro_to_units.containsKey(flag))
+                       return pyro_to_units.get(flag);
                return null;
        }
 
@@ -136,29 +154,29 @@ public class AltosPyro {
        }
 
        private static void initialize_maps() {
-               insert_map(pyro_accel_less, pyro_accel_less_string, pyro_accel_less_name, pyro_accel_scale);
-               insert_map(pyro_accel_greater, pyro_accel_greater_string, pyro_accel_greater_name, pyro_accel_scale);
+               insert_map(pyro_accel_less, pyro_accel_less_string, pyro_accel_less_name, AltosConvert.accel, pyro_accel_scale);
+               insert_map(pyro_accel_greater, pyro_accel_greater_string, pyro_accel_greater_name, AltosConvert.accel, pyro_accel_scale);
 
-               insert_map(pyro_speed_less, pyro_speed_less_string, pyro_speed_less_name, pyro_speed_scale);
-               insert_map(pyro_speed_greater, pyro_speed_greater_string, pyro_speed_greater_name, pyro_speed_scale);
+               insert_map(pyro_speed_less, pyro_speed_less_string, pyro_speed_less_name, AltosConvert.speed, pyro_speed_scale);
+               insert_map(pyro_speed_greater, pyro_speed_greater_string, pyro_speed_greater_name, AltosConvert.speed, pyro_speed_scale);
 
-               insert_map(pyro_height_less, pyro_height_less_string, pyro_height_less_name, pyro_height_scale);
-               insert_map(pyro_height_greater, pyro_height_greater_string, pyro_height_greater_name, pyro_height_scale);
+               insert_map(pyro_height_less, pyro_height_less_string, pyro_height_less_name, AltosConvert.height, pyro_height_scale);
+               insert_map(pyro_height_greater, pyro_height_greater_string, pyro_height_greater_name, AltosConvert.height, pyro_height_scale);
 
-               insert_map(pyro_orient_less, pyro_orient_less_string, pyro_orient_less_name, pyro_orient_scale);
-               insert_map(pyro_orient_greater, pyro_orient_greater_string, pyro_orient_greater_name, pyro_orient_scale);
+               insert_map(pyro_orient_less, pyro_orient_less_string, pyro_orient_less_name, null, pyro_orient_scale);
+               insert_map(pyro_orient_greater, pyro_orient_greater_string, pyro_orient_greater_name, null, pyro_orient_scale);
 
-               insert_map(pyro_time_less, pyro_time_less_string, pyro_time_less_name, pyro_time_scale);
-               insert_map(pyro_time_greater, pyro_time_greater_string, pyro_time_greater_name, pyro_time_scale);
+               insert_map(pyro_time_less, pyro_time_less_string, pyro_time_less_name, null, pyro_time_scale);
+               insert_map(pyro_time_greater, pyro_time_greater_string, pyro_time_greater_name, null, pyro_time_scale);
 
-               insert_map(pyro_ascending, pyro_ascending_string, pyro_ascending_name, 1.0);
-               insert_map(pyro_descending, pyro_descending_string, pyro_descending_name, 1.0);
+               insert_map(pyro_ascending, pyro_ascending_string, pyro_ascending_name, null, 1.0);
+               insert_map(pyro_descending, pyro_descending_string, pyro_descending_name, null, 1.0);
 
-               insert_map(pyro_after_motor, pyro_after_motor_string, pyro_after_motor_name, 1.0);
-               insert_map(pyro_delay, pyro_delay_string, pyro_delay_name, pyro_delay_scale);
+               insert_map(pyro_after_motor, pyro_after_motor_string, pyro_after_motor_name, null, 1.0);
+               insert_map(pyro_delay, pyro_delay_string, pyro_delay_name, null, pyro_delay_scale);
                
-               insert_map(pyro_state_less, pyro_state_less_string, pyro_state_less_name, 1.0);
-               insert_map(pyro_state_greater_or_equal, pyro_state_greater_or_equal_string, pyro_state_greater_or_equal_name, 1.0);
+               insert_map(pyro_state_less, pyro_state_less_string, pyro_state_less_name, null, 1.0);
+               insert_map(pyro_state_greater_or_equal, pyro_state_greater_or_equal_string, pyro_state_greater_or_equal_name, null, 1.0);
        }
 
        {
diff --git a/altoslib/AltosRecord.java b/altoslib/AltosRecord.java
deleted file mode 100644 (file)
index 5e4ed92..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosRecord implements Comparable <AltosRecord>, Cloneable {
-
-       public static final int seen_flight = 1;
-       public static final int seen_sensor = 2;
-       public static final int seen_temp_volt = 4;
-       public static final int seen_deploy = 8;
-       public static final int seen_gps_time = 16;
-       public static final int seen_gps_lat = 32;
-       public static final int seen_gps_lon = 64;
-       public static final int seen_companion = 128;
-
-       public int      seen;
-       
-       public final static int MISSING = 0x7fffffff;
-
-       /* Every AltosRecord implementation provides these fields */
-       
-       public int      version;
-       public String   callsign;
-       public int      serial;
-       public int      flight;
-       public int      rssi;
-       public int      status;
-       public int      state;
-       public int      tick;
-
-       public AltosGPS gps;
-       public int      gps_sequence;
-
-       public double   time;   /* seconds since boost */
-
-       public int      device_type;
-       public int      config_major;
-       public int      config_minor;
-       public int      apogee_delay;
-       public int      main_deploy;
-       public int      flight_log_max;
-       public String   firmware_version;
-
-       public AltosRecordCompanion companion;
-
-       /* Telemetry sources have these values recorded from the flight computer */
-       public double   kalman_height;
-       public double   kalman_speed;
-       public double   kalman_acceleration;
-
-       /*
-        * Abstract methods that convert record data
-        * to standard units:
-        *
-        *      pressure:       Pa
-        *      voltage:        V
-        *      acceleration:   m/s²
-        *      speed:          m/s
-        *      height:         m
-        *      temperature:    °C
-        */
-
-       public double pressure() { return MISSING; }
-       public double ground_pressure() { return MISSING; }
-       public double acceleration() { return MISSING; }
-
-       public double altitude() {
-               double  p = pressure();
-
-               if (p == MISSING)
-                       return MISSING;
-               return AltosConvert.pressure_to_altitude(p);
-       }
-
-       public double ground_altitude() {
-               double  p = ground_pressure();
-
-               if (p == MISSING)
-                       return MISSING;
-               return AltosConvert.pressure_to_altitude(p);
-       }
-
-       public double height() {
-               double  g = ground_altitude();
-               double  a = altitude();
-
-               if (g == MISSING)
-                       return MISSING;
-               if (a == MISSING)
-                       return MISSING;
-               return a - g;
-       }
-
-       public double battery_voltage() { return MISSING; }
-
-       public double main_voltage() { return MISSING; }
-
-       public double drogue_voltage() { return MISSING; }
-
-       public double temperature() { return MISSING; }
-       
-       public AltosIMU imu() { return null; }
-
-       public AltosMag mag() { return null; }
-
-       public String state() {
-               return AltosLib.state_name(state);
-       }
-
-       public int compareTo(AltosRecord o) {
-               return tick - o.tick;
-       }
-
-       public AltosRecord clone() {
-               AltosRecord n = new AltosRecord();
-               n.copy(this);
-               return n;
-       }
-
-       public void copy(AltosRecord old) {
-               seen = old.seen;
-               version = old.version;
-               callsign = old.callsign;
-               serial = old.serial;
-               flight = old.flight;
-               rssi = old.rssi;
-               status = old.status;
-               state = old.state;
-               tick = old.tick;
-               gps = new AltosGPS(old.gps);
-               gps_sequence = old.gps_sequence;
-               companion = old.companion;
-               kalman_acceleration = old.kalman_acceleration;
-               kalman_speed = old.kalman_speed;
-               kalman_height = old.kalman_height;
-       }
-
-       public AltosRecord() {
-               seen = 0;
-               version = 0;
-               callsign = "N0CALL";
-               serial = MISSING;
-               flight = MISSING;
-               rssi = 0;
-               status = 0;
-               state = AltosLib.ao_flight_startup;
-               tick = 0;
-               gps = null;
-               gps_sequence = 0;
-               companion = null;
-
-               kalman_acceleration = MISSING;
-               kalman_speed = MISSING;
-               kalman_height = MISSING;
-       }
-}
diff --git a/altoslib/AltosRecordCompanion.java b/altoslib/AltosRecordCompanion.java
deleted file mode 100644 (file)
index b153fb5..0000000
+++ /dev/null
@@ -1,38 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosRecordCompanion {
-       public final static int board_id_telescience = 0x0a;
-       public final static int MAX_CHANNELS = 12;
-
-       public int      tick;
-       public int      board_id;
-       public int      update_period;
-       public int      channels;
-       public int[]    companion_data;
-
-       public AltosRecordCompanion(int in_channels) {
-               channels = in_channels;
-               if (channels < 0)
-                       channels = 0;
-               if (channels > MAX_CHANNELS)
-                       channels = MAX_CHANNELS;
-               companion_data = new int[channels];
-       }
-}
diff --git a/altoslib/AltosRecordIterable.java b/altoslib/AltosRecordIterable.java
deleted file mode 100644 (file)
index 62dbdfe..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.io.*;
-import java.util.*;
-
-public abstract class AltosRecordIterable implements Iterable<AltosRecord> {
-       public abstract Iterator<AltosRecord> iterator();
-       public void write_comments(PrintStream out) { }
-       public boolean has_accel() { return false; }
-       public boolean has_gps() { return false; }
-       public boolean has_ignite() { return false; };
-}
diff --git a/altoslib/AltosRecordMM.java b/altoslib/AltosRecordMM.java
deleted file mode 100644 (file)
index d697111..0000000
+++ /dev/null
@@ -1,178 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosRecordMM extends AltosRecord {
-
-       /* Sensor values */
-       public int      accel;
-       public int      pres;
-       public int      temp;
-       
-       public int      v_batt;
-       public int      v_pyro;
-       public int      sense[];
-
-       public int      ground_accel;
-       public int      ground_pres;
-       public int      accel_plus_g;
-       public int      accel_minus_g;
-
-       public int      flight_accel;
-       public int      flight_vel;
-       public int      flight_pres;
-
-       public final static int num_sense = 6;
-
-       public AltosIMU imu;
-       public AltosMag mag;
-
-       static double adc(int raw) {
-               return raw / 4095.0;
-       }
-
-       public double pressure() {
-               if (pres != MISSING)
-                       return pres;
-               return MISSING;
-       }
-
-       public double ground_pressure() {
-               if (ground_pres != MISSING)
-                       return ground_pres;
-               return MISSING;
-       }
-
-       public double battery_voltage() {
-               if (v_batt != MISSING)
-                       return 3.3 * adc(v_batt) * (15.0 + 27.0) / 27.0;
-               return MISSING;
-       }
-
-       static double pyro(int raw) {
-               if (raw != MISSING)
-                       return 3.3 * adc(raw) * (100.0 + 27.0) / 27.0;
-               return MISSING;
-       }
-
-       public double main_voltage() {
-               return pyro(sense[5]);
-       }
-
-       public double drogue_voltage() {
-               return pyro(sense[4]);
-       }
-
-       public double temperature() {
-               if (temp != MISSING)
-                       return temp / 100.0;
-               return MISSING;
-       }
-       
-       public AltosIMU imu() { return imu; }
-
-       public AltosMag mag() { return mag; }
-
-       double accel_counts_per_mss() {
-               double  counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2;
-
-               return counts_per_g / 9.80665;
-       }
-
-       public double acceleration() {
-               if (ground_accel == MISSING || accel == MISSING)
-                       return MISSING;
-
-               if (accel_minus_g == MISSING || accel_plus_g == MISSING)
-                       return MISSING;
-
-               return (ground_accel - accel) / accel_counts_per_mss();
-       }
-
-       public void copy (AltosRecordMM old) {
-               super.copy(old);
-
-               accel = old.accel;
-               pres = old.pres;
-               temp = old.temp;
-
-               v_batt = old.v_batt;
-               v_pyro = old.v_pyro;
-               sense = new int[num_sense];
-               
-               for (int i = 0; i < num_sense; i++)
-                       sense[i] = old.sense[i];
-
-               ground_accel = old.ground_accel;
-               ground_pres = old.ground_pres;
-               accel_plus_g = old.accel_plus_g;
-               accel_minus_g = old.accel_minus_g;
-               
-               flight_accel = old.flight_accel;
-               flight_vel = old.flight_vel;
-               flight_pres = old.flight_pres;
-
-               imu = old.imu;
-               mag = old.mag;
-       }
-
-
-
-       public AltosRecordMM clone() {
-               return new AltosRecordMM(this);
-       }
-
-       void make_missing() {
-
-               accel = MISSING;
-               pres = MISSING;
-               temp = MISSING;
-
-               v_batt = MISSING;
-               v_pyro = MISSING;
-               sense = new int[num_sense];
-               for (int i = 0; i < num_sense; i++)
-                       sense[i] = MISSING;
-
-               ground_accel = MISSING;
-               ground_pres = MISSING;
-               accel_plus_g = MISSING;
-               accel_minus_g = MISSING;
-
-               flight_accel = 0;
-               flight_vel = 0;
-               flight_pres = 0;
-
-               imu = new AltosIMU();
-               mag = new AltosMag();
-       }
-
-       public AltosRecordMM(AltosRecord old) {
-               super.copy(old);
-               make_missing();
-       }
-
-       public AltosRecordMM(AltosRecordMM old) {
-               copy(old);
-       }
-
-       public AltosRecordMM() {
-               super();
-               make_missing();
-       }
-}
diff --git a/altoslib/AltosRecordNone.java b/altoslib/AltosRecordNone.java
deleted file mode 100644 (file)
index a95b6a9..0000000
+++ /dev/null
@@ -1,38 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosRecordNone extends AltosRecord {
-
-       public double pressure() { return MISSING; }
-       public double ground_pressure() { return MISSING; }
-       public double temperature() { return MISSING; }
-       public double acceleration() { return MISSING; }
-
-       public AltosRecordNone(AltosRecord old) {
-               super.copy(old);
-       }
-
-       public AltosRecordNone clone() {
-               return new AltosRecordNone(this);
-       }
-
-       public AltosRecordNone() {
-               super();
-       }
-}
diff --git a/altoslib/AltosRecordTM.java b/altoslib/AltosRecordTM.java
deleted file mode 100644 (file)
index c6cf364..0000000
+++ /dev/null
@@ -1,186 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosRecordTM extends AltosRecord {
-
-       /* Sensor values */
-       public int      accel;
-       public int      pres;
-       public int      temp;
-       public int      batt;
-       public int      drogue;
-       public int      main;
-
-       public int      ground_accel;
-       public int      ground_pres;
-       public int      accel_plus_g;
-       public int      accel_minus_g;
-
-       public int      flight_accel;
-       public int      flight_vel;
-       public int      flight_pres;
-
-       /*
-        * Values for our MP3H6115A pressure sensor
-        *
-        * From the data sheet:
-        *
-        * Pressure range: 15-115 kPa
-        * Voltage at 115kPa: 2.82
-        * Output scale: 27mV/kPa
-        *
-        *
-        * 27 mV/kPa * 2047 / 3300 counts/mV = 16.75 counts/kPa
-        * 2.82V * 2047 / 3.3 counts/V = 1749 counts/115 kPa
-        */
-
-       static final double counts_per_kPa = 27 * 2047 / 3300;
-       static final double counts_at_101_3kPa = 1674.0;
-
-       static double
-       barometer_to_pressure(double count)
-       {
-               return ((count / 16.0) / 2047.0 + 0.095) / 0.009 * 1000.0;
-       }
-
-       public double pressure() {
-               if (pres == MISSING)
-                       return MISSING;
-               return barometer_to_pressure(pres);
-       }
-
-       public double ground_pressure() {
-               if (ground_pres == MISSING)
-                       return MISSING;
-               return barometer_to_pressure(ground_pres);
-       }
-
-       public double battery_voltage() {
-               if (batt == MISSING)
-                       return MISSING;
-               return AltosConvert.cc_battery_to_voltage(batt);
-       }
-
-       public double main_voltage() {
-               if (main == MISSING)
-                       return MISSING;
-               return AltosConvert.cc_ignitor_to_voltage(main);
-       }
-
-       public double drogue_voltage() {
-               if (drogue == MISSING)
-                       return MISSING;
-               return AltosConvert.cc_ignitor_to_voltage(drogue);
-       }
-
-       /* Value for the CC1111 built-in temperature sensor
-        * Output voltage at 0°C = 0.755V
-        * Coefficient = 0.00247V/°C
-        * Reference voltage = 1.25V
-        *
-        * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247
-        *      = (value - 19791.268) / 32768 * 1.25 / 0.00247
-        */
-
-       static double
-       thermometer_to_temperature(double thermo)
-       {
-               return (thermo - 19791.268) / 32728.0 * 1.25 / 0.00247;
-       }
-
-       public double temperature() {
-               if (temp == MISSING)
-                       return MISSING;
-               return thermometer_to_temperature(temp);
-       }
-
-       double accel_counts_per_mss() {
-               double  counts_per_g = Math.abs(accel_minus_g - accel_plus_g) / 2;
-
-               return counts_per_g / 9.80665;
-       }
-
-       public double acceleration() {
-               if (ground_accel == MISSING || accel == MISSING)
-                       return MISSING;
-               return (ground_accel - accel) / accel_counts_per_mss();
-       }
-
-       public void copy(AltosRecordTM old) {
-               super.copy(old);
-
-               version = old.version;
-               callsign = old.callsign;
-               serial = old.serial;
-               flight = old.flight;
-               rssi = old.rssi;
-               status = old.status;
-               state = old.state;
-               tick = old.tick;
-               accel = old.accel;
-               pres = old.pres;
-               temp = old.temp;
-               batt = old.batt;
-               drogue = old.drogue;
-               main = old.main;
-               flight_accel = old.flight_accel;
-               ground_accel = old.ground_accel;
-               flight_vel = old.flight_vel;
-               flight_pres = old.flight_pres;
-               ground_pres = old.ground_pres;
-               accel_plus_g = old.accel_plus_g;
-               accel_minus_g = old.accel_minus_g;
-       }
-
-       public AltosRecordTM clone() {
-               return new AltosRecordTM(this);
-       }
-
-       void make_missing() {
-               accel = MISSING;
-               pres = MISSING;
-               temp = MISSING;
-               batt = MISSING;
-               drogue = MISSING;
-               main = MISSING;
-
-               flight_accel = MISSING;
-               flight_vel = MISSING;
-               flight_pres = MISSING;
-
-               ground_accel = MISSING;
-               ground_pres = MISSING;
-               accel_plus_g = MISSING;
-               accel_minus_g = MISSING;
-       }
-
-       public AltosRecordTM(AltosRecord old) {
-               super.copy(old);
-               make_missing();
-       }
-
-       public AltosRecordTM(AltosRecordTM old) {
-               copy(old);
-       }
-       
-       public AltosRecordTM() {
-               super();
-               make_missing();
-       }
-}
index a7e30370d2696da8db29aedbdb461e3808a332ac..19091d3dfd22cea4055948b566e6548f61689c0c 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 import java.util.*;
@@ -25,10 +25,10 @@ import java.util.*;
  */
 
 public class AltosReplayReader extends AltosFlightReader {
-       Iterator<AltosRecord>   iterator;
+       Iterator<AltosState>    iterator;
        File    file;
 
-       public AltosRecord read() {
+       public AltosState read() {
                if (iterator.hasNext())
                        return iterator.next();
                return null;
@@ -41,11 +41,12 @@ public class AltosReplayReader extends AltosFlightReader {
                /* Make it run in realtime after the rocket leaves the pad */
                if (state.state > AltosLib.ao_flight_pad)
                        Thread.sleep((int) (Math.min(state.time_change,10) * 1000));
+               state.set_received_time(System.currentTimeMillis());
        }
 
        public File backing_file() { return file; }
 
-       public AltosReplayReader(Iterator<AltosRecord> in_iterator, File in_file) {
+       public AltosReplayReader(Iterator<AltosState> in_iterator, File in_file) {
                iterator = in_iterator;
                file = in_file;
                name = file.getName();
index 0800a2c4da1e405abad6d9686cfb76514d6355ff..2f106deb8223aca4be55d391d091da5a4ef6ff1a 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 
@@ -26,7 +26,20 @@ public class AltosRomconfig {
        public int      serial_number;
        public int      radio_calibration;
 
-       static int get_int(byte[] bytes, int start, int len) {
+       static private int find_offset(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
+               AltosHexsym symbol = hexfile.lookup_symbol(name);
+               if (symbol == null)
+                       throw new AltosNoSymbol(name);
+               int offset = (int) symbol.address - hexfile.address;
+               if (offset < 0 || hexfile.data.length < offset + len)
+                       throw new AltosNoSymbol(name);
+               return offset;
+       }
+
+       static int get_int(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
+               byte[] bytes = hexfile.data;
+               int start = find_offset(hexfile, name, len);
+
                int     v = 0;
                int     o = 0;
                while (len > 0) {
@@ -38,7 +51,10 @@ public class AltosRomconfig {
                return v;
        }
 
-       static void put_int(int value, byte[] bytes, int start, int len) {
+       static void put_int(int value, AltosHexfile hexfile, String name, int len) throws AltosNoSymbol, IOException {
+               byte[] bytes = hexfile.data;
+               int start = find_offset(hexfile, name, len);
+
                while (len > 0) {
                        bytes[start] = (byte) (value & 0xff);
                        start++;
@@ -47,86 +63,155 @@ public class AltosRomconfig {
                }
        }
 
-       static void put_string(String value, byte[] bytes, int start) {
+       static void put_string(String value, AltosHexfile hexfile, String name) throws AltosNoSymbol {
+               byte[] bytes = hexfile.data;
+               int start = find_offset(hexfile, name, value.length());
+
                for (int i = 0; i < value.length(); i++)
                        bytes[start + i] = (byte) value.charAt(i);
        }
 
        static final int AO_USB_DESC_STRING     = 3;
 
-       static void put_usb_serial(int value, byte[] bytes, int start) {
-               int offset = start + 0xa;
+       static void put_usb_serial(int value, AltosHexfile hexfile, String name) throws AltosNoSymbol {
+               byte[] bytes = hexfile.data;
+               int start = find_offset(hexfile, name, 2);
+
                int string_num = 0;
 
-               while (offset < bytes.length && bytes[offset] != 0) {
-                       if (bytes[offset + 1] == AO_USB_DESC_STRING) {
+               while (start < bytes.length && bytes[start] != 0) {
+                       if (bytes[start + 1] == AO_USB_DESC_STRING) {
                                ++string_num;
                                if (string_num == 4)
                                        break;
                        }
-                       offset += ((int) bytes[offset]) & 0xff;
+                       start += ((int) bytes[start]) & 0xff;
                }
-               if (offset >= bytes.length || bytes[offset] == 0)
-                       return;
-               int len = ((((int) bytes[offset]) & 0xff) - 2) / 2;
+               if (start >= bytes.length || bytes[start] == 0)
+                       throw new AltosNoSymbol(name);
+
+               int len = ((((int) bytes[start]) & 0xff) - 2) / 2;
                String fmt = String.format("%%0%dd", len);
 
                String s = String.format(fmt, value);
-               if (s.length() != len) {
-                       System.out.printf("weird usb length issue %s isn't %d\n",
-                                         s, len);
-                       return;
-               }
+               if (s.length() != len)
+                       throw new AltosNoSymbol(String.format("weird usb length issue %s isn't %d\n", s, len));
+
                for (int i = 0; i < len; i++) {
-                       bytes[offset + 2 + i*2] = (byte) s.charAt(i);
-                       bytes[offset + 2 + i*2+1] = 0;
+                       bytes[start + 2 + i*2] = (byte) s.charAt(i);
+                       bytes[start + 2 + i*2+1] = 0;
                }
        }
 
-       public AltosRomconfig(byte[] bytes, int offset) {
-               version = get_int(bytes, offset + 0, 2);
-               check = get_int(bytes, offset + 2, 2);
-               if (check == (~version & 0xffff)) {
-                       switch (version) {
-                       case 2:
-                       case 1:
-                               serial_number = get_int(bytes, offset + 4, 2);
-                               radio_calibration = get_int(bytes, offset + 6, 4);
-                               valid = true;
-                               break;
+       final static String ao_romconfig_version = "ao_romconfig_version";
+       final static String ao_romconfig_check = "ao_romconfig_check";
+       final static String ao_serial_number = "ao_serial_number";
+       final static String ao_radio_cal = "ao_radio_cal";
+       final static String ao_usb_descriptors = "ao_usb_descriptors";
+
+       public AltosRomconfig(AltosHexfile hexfile) {
+               try {
+                       version = get_int(hexfile, ao_romconfig_version, 2);
+                       check = get_int(hexfile, ao_romconfig_check, 2);
+                       if (check == (~version & 0xffff)) {
+                               switch (version) {
+                               case 2:
+                               case 1:
+                                       serial_number = get_int(hexfile, ao_serial_number, 2);
+                                       try {
+                                               radio_calibration = get_int(hexfile, ao_radio_cal, 4);
+                                       } catch (AltosNoSymbol missing) {
+                                               radio_calibration = 0;
+                                       }
+                                       valid = true;
+                                       break;
+                               }
                        }
+               } catch (AltosNoSymbol missing) {
+                       valid = false;
                }
        }
 
-       public AltosRomconfig(AltosHexfile hexfile) {
-               this(hexfile.data, 0xa0 - hexfile.address);
+       private final static String[] fetch_names = {
+               ao_romconfig_version,
+               ao_romconfig_check,
+               ao_serial_number,
+               ao_radio_cal
+       };
+
+       private final static String[] required_names = {
+               ao_romconfig_version,
+               ao_romconfig_check,
+               ao_serial_number
+       };
+               
+       private static boolean name_required(String name) {
+               for (String required : required_names)
+                       if (name.equals(required))
+                               return true;
+               return false;
        }
 
-       public void write(byte[] bytes, int offset) throws IOException {
+       public static int fetch_base(AltosHexfile hexfile) throws AltosNoSymbol {
+               int     base = 0x7fffffff;
+               for (String name : fetch_names) {
+                       try {
+                               int     addr = find_offset(hexfile, name, 2) + hexfile.address;
+                               if (addr < base)
+                                       base = addr;
+                       } catch (AltosNoSymbol ns) {
+                               if (name_required(name))
+                                       throw (ns);
+                       }
+               }
+               return base;
+       }
+
+       public static int fetch_bounds(AltosHexfile hexfile) throws AltosNoSymbol {
+               int     bounds = 0;
+               for (String name : fetch_names) {
+                       try {
+                               int     addr = find_offset(hexfile, name, 2) + hexfile.address;
+                               if (addr > bounds)
+                                       bounds = addr;
+                       } catch (AltosNoSymbol ns) {
+                               if (name_required(name))
+                                       throw (ns);
+                       }
+               }
+               return bounds + 2;
+       }
+
+       public void write (AltosHexfile hexfile) throws IOException {
                if (!valid)
                        throw new IOException("rom configuration invalid");
 
-               if (offset < 0 || bytes.length < offset + 10)
-                       throw new IOException("image cannot contain rom config");
-
-               AltosRomconfig existing = new AltosRomconfig(bytes, offset);
+               AltosRomconfig existing = new AltosRomconfig(hexfile);
                if (!existing.valid)
                        throw new IOException("image does not contain existing rom config");
 
-               switch (existing.version) {
-               case 2:
-                       put_usb_serial(serial_number, bytes, offset);
-               case 1:
-                       put_int(serial_number, bytes, offset + 4, 2);
-                       put_int(radio_calibration, bytes, offset + 6, 4);
-                       break;
+               try {
+                       switch (existing.version) {
+                       case 2:
+                               try {
+                                       put_usb_serial(serial_number, hexfile, ao_usb_descriptors);
+                               } catch (AltosNoSymbol missing) {
+                               }
+                               /* fall through ... */
+                       case 1:
+                               put_int(serial_number, hexfile, ao_serial_number, 2);
+                               try {
+                                       put_int(radio_calibration, hexfile, ao_radio_cal, 4);
+                               } catch (AltosNoSymbol missing) {
+                               }
+                               break;
+                       }
+               } catch (AltosNoSymbol missing) {
+                       throw new IOException(missing.getMessage());
                }
-       }
 
-       public void write (AltosHexfile hexfile) throws IOException {
-               write(hexfile.data, 0xa0 - hexfile.address);
                AltosRomconfig check = new AltosRomconfig(hexfile);
-               if (!check.valid())
+               if (!check.valid)
                        throw new IOException("writing new rom config failed\n");
        }
 
diff --git a/altoslib/AltosSelfFlash.java b/altoslib/AltosSelfFlash.java
new file mode 100644 (file)
index 0000000..3bf7ce4
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+
+public class AltosSelfFlash extends AltosProgrammer {
+       File                    file;
+       FileInputStream         input;
+       AltosHexfile            image;
+       AltosLink               link;
+       boolean                 aborted;
+       AltosFlashListener      listener;
+       AltosRomconfig          rom_config;
+
+       void action(String s, int percent) {
+               if (listener != null && !aborted)
+                       listener.position(s, percent);
+       }
+
+       void action(int part, int total) {
+               int percent = 100 * part / total;
+               action(String.format("%d/%d (%d%%)",
+                                    part, total, percent),
+                      percent);
+       }
+
+       byte[] read_memory(long addr, int len) throws InterruptedException, IOException {
+               int b;
+               byte[]  data = new byte[len];
+
+               for (int offset = 0; offset < len; offset += 0x100) {
+                       link.printf("R %x\n", addr + offset);
+                       byte[]  reply = link.get_binary_reply(5000, 0x100);
+                       
+                       if (reply == null)
+                               throw new IOException("Read device memory timeout");
+                       for (b = 0; b < len; b++)
+                               data[b+offset] = reply[b];
+               }
+               return data;
+       }
+               
+       void write_memory(long addr, byte[] data, int start, int len) {
+               int b;
+               link.printf("W %x\n", addr);
+               link.flush_output();
+               for (b = 0; b < len; b++)
+                       link.putchar(data[start + b]);
+               for (; b < 0x100; b++)
+                       link.putchar((byte) 0xff);
+       }
+
+       void reboot() {
+               link.printf("a\n");
+               link.flush_output();
+       }
+
+       public void flash() {
+               try {
+                       if (!check_rom_config())
+                               throw new IOException("Invalid rom config settings");
+
+                       /*
+                        * Store desired config values into image
+                        */
+                       rom_config.write(image);
+
+                       int remain = image.data.length;
+                       long flash_addr = image.address;
+                       int image_start = 0;
+
+                       action("start", 0);
+                       action(0, image.data.length);
+                       while (remain > 0 && !aborted) {
+                               int this_time = remain;
+                               if (this_time > 0x100)
+                                       this_time = 0x100;
+
+                               if (link != null) {
+                                       /* write the data */
+                                       write_memory(flash_addr, image.data, image_start, this_time);
+
+                                       byte[] check = read_memory(flash_addr, this_time);
+                                       for (int i = 0; i < this_time; i++)
+                                               if (check[i] != image.data[image_start + i])
+                                                       throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
+                                                                                           image.address + image_start + i,
+                                                                                           check[i], image.data[image_start + i]));
+                               } else {
+                                       Thread.sleep(100);
+                               }
+
+                               remain -= this_time;
+                               flash_addr += this_time;
+                               image_start += this_time;
+
+                               action(image.data.length - remain, image.data.length);
+                       }
+                       if (!aborted) {
+                               action("done", 100);
+                       }
+                       close();
+               } catch (IOException ie) {
+                       action(ie.getMessage(), -1);
+                       abort();
+               } catch (InterruptedException ie) {
+                       abort();
+               }
+       }
+
+       public void close() {
+               if (link != null) {
+                       reboot();
+                       try {
+                               link.close();
+                       } catch (InterruptedException ie) {
+                       }
+                       link = null;
+               }
+       }
+
+       synchronized public void abort() {
+               aborted = true;
+               close();
+       }
+
+       private AltosHexfile get_rom() throws InterruptedException {
+               try {
+                       int base = AltosRomconfig.fetch_base(image);
+                       int bounds = AltosRomconfig.fetch_bounds(image);
+                       byte[] data = read_memory(base, bounds - base);
+                       AltosHexfile hexfile = new AltosHexfile(data, base);
+                       hexfile.add_symbols(image);
+                       return hexfile;
+               } catch (AltosNoSymbol none) {
+                       return null;
+               } catch (IOException ie) {
+                       return null;
+               }
+
+       }
+
+       public boolean check_rom_config() throws InterruptedException {
+               if (link == null) {
+                       return true;
+               }
+               if (rom_config == null) {
+                       AltosHexfile hexfile = get_rom();
+                       if (hexfile != null)
+                               rom_config = new AltosRomconfig(hexfile);
+               }
+               return rom_config != null && rom_config.valid();
+       }
+
+       public void set_romconfig (AltosRomconfig romconfig) {
+               rom_config = romconfig;
+       }
+
+       public AltosRomconfig romconfig() throws InterruptedException {
+               if (!check_rom_config())
+                       return null;
+               return rom_config;
+       }
+
+       public AltosSelfFlash(File file, AltosLink link, AltosFlashListener listener)
+               throws IOException, FileNotFoundException, InterruptedException {
+               this.file = file;
+               this.link = link;
+               this.listener = listener;
+               input = new FileInputStream(file);
+               image = new AltosHexfile(input);
+       }
+}
\ No newline at end of file
diff --git a/altoslib/AltosSensorEMini.java b/altoslib/AltosSensorEMini.java
new file mode 100644 (file)
index 0000000..5f9eed5
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.TimeoutException;
+
+public class AltosSensorEMini {
+       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 {
+                       AltosSensorEMini        sensor_emini = new AltosSensorEMini(link);
+
+                       if (sensor_emini == null)
+                               return;
+                       state.set_battery_voltage(AltosConvert.easy_mini_voltage(sensor_emini.batt));
+                       state.set_apogee_voltage(AltosConvert.easy_mini_voltage(sensor_emini.apogee));
+                       state.set_main_voltage(AltosConvert.easy_mini_voltage(sensor_emini.main));
+                       
+               } catch (TimeoutException te) {
+               }
+       }
+
+       public AltosSensorEMini(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 6d1b61c079fa3d9305a661f871da2122651ffe1d..0ef42cf683e372938d951ddd788ec0dad0c7f4c9 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.util.concurrent.TimeoutException;
 
diff --git a/altoslib/AltosSensorMega.java b/altoslib/AltosSensorMega.java
new file mode 100644 (file)
index 0000000..e715242
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.TimeoutException;
+
+class AltosSensorMega {
+       int             tick;
+       int[]           sense;
+       int             v_batt;
+       int             v_pbatt;
+       int             temp;
+
+       public AltosSensorMega() {
+               sense = new int[6];
+       }
+
+       public AltosSensorMega(AltosLink link) throws InterruptedException, TimeoutException {
+               this();
+               String[] items = link.adc();
+               for (int i = 0; i < items.length;) {
+                       if (items[i].equals("tick:")) {
+                               tick = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("A:")) {
+                               sense[0] = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("B:")) {
+                               sense[1] = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("C:")) {
+                               sense[2] = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("D:")) {
+                               sense[3] = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("drogue:")) {
+                               sense[4] = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("main:")) {
+                               sense[5] = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("batt:")) {
+                               v_batt = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("pbatt:")) {
+                               v_pbatt = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("temp:")) {
+                               temp = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       i++;
+               }
+       }
+
+       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+               try {
+                       AltosSensorMega sensor_mega = new AltosSensorMega(link);
+
+                       state.set_battery_voltage(AltosConvert.mega_battery_voltage(sensor_mega.v_batt));
+                       state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sensor_mega.sense[4]));
+                       state.set_main_voltage(AltosConvert.mega_pyro_voltage(sensor_mega.sense[5]));
+
+                       double[]        ignitor_voltage = new double[4];
+                       for (int i = 0; i < 4; i++)
+                               ignitor_voltage[i] = AltosConvert.mega_pyro_voltage(sensor_mega.sense[i]);
+                       state.set_ignitor_voltage(ignitor_voltage);
+
+               } catch (TimeoutException te) {
+               }
+       }
+}
+
diff --git a/altoslib/AltosSensorMetrum.java b/altoslib/AltosSensorMetrum.java
new file mode 100644 (file)
index 0000000..c30eaeb
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.util.concurrent.TimeoutException;
+
+class AltosSensorMetrum {
+       int             tick;
+       int             sense_a;
+       int             sense_m;
+       int             v_batt;
+
+       public AltosSensorMetrum(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("drogue:")) {
+                               sense_a = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("main:")) {
+                               sense_m = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       if (items[i].equals("batt:")) {
+                               v_batt = Integer.parseInt(items[i+1]);
+                               i += 2;
+                               continue;
+                       }
+                       i++;
+               }
+       }
+
+       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+               try {
+                       AltosSensorMetrum       sensor_metrum = new AltosSensorMetrum(link);
+                       state.set_battery_voltage(AltosConvert.mega_battery_voltage(sensor_metrum.v_batt));
+                       state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sensor_metrum.sense_a));
+                       state.set_main_voltage(AltosConvert.mega_pyro_voltage(sensor_metrum.sense_m));
+               } catch (TimeoutException te) {
+               }
+       }
+}
+
index 754dc5bbbc85cec8d762a5ec8fc5be1da31b9fde..f867de4b8efa5dc0eb0f8b410cdbd1732d382568 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.util.concurrent.TimeoutException;
 
-class AltosSensorTM extends AltosRecordTM {
+public class AltosSensorTM {
+       public int      tick;
+       public int      accel;
+       public int      pres;
+       public int      temp;
+       public int      batt;
+       public int      drogue;
+       public int      main;
 
-       public AltosSensorTM(AltosLink link, AltosConfigData config_data) throws InterruptedException, TimeoutException {
-               super();
+       static public void update_state(AltosState state, AltosLink link, AltosConfigData config_data) throws InterruptedException {
+               try {
+                       AltosSensorTM   sensor_tm = new AltosSensorTM(link);
+
+                       if (sensor_tm == null)
+                               return;
+                       state.set_accel(sensor_tm.accel);
+                       state.set_pressure(AltosConvert.barometer_to_pressure(sensor_tm.pres));
+                       state.set_temperature(AltosConvert.thermometer_to_temperature(sensor_tm.temp));
+                       state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(sensor_tm.batt));
+                       state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(sensor_tm.drogue));
+                       state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(sensor_tm.main));
+                       
+               } catch (TimeoutException te) {
+               }
+       }
+
+       public AltosSensorTM(AltosLink link) throws InterruptedException, TimeoutException {
                String[] items = link.adc();
                for (int i = 0; i < items.length;) {
                        if (items[i].equals("tick:")) {
@@ -62,10 +85,6 @@ class AltosSensorTM extends AltosRecordTM {
                        }
                        i++;
                }
-               ground_accel = config_data.accel_cal_plus;
-               ground_pres = pres;
-               accel_plus_g = config_data.accel_cal_plus;
-               accel_minus_g = config_data.accel_cal_minus;
        }
 }
 
diff --git a/altoslib/AltosSensorTMini.java b/altoslib/AltosSensorTMini.java
new file mode 100644 (file)
index 0000000..ee03091
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+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.easy_mini_voltage(sensor_tmini.batt));
+                       state.set_apogee_voltage(AltosConvert.easy_mini_voltage(sensor_tmini.apogee));
+                       state.set_main_voltage(AltosConvert.easy_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++;
+               }
+       }
+}
+
index 6fb624fb664bbab32511848765e54dccb566f77a..6618c539eed867c3beda5f993b35796c096e15a0 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosSpeed extends AltosUnits {
 
-       public double value(double v) {
-               if (AltosConvert.imperial_units)
+       public double value(double v, boolean imperial_units) {
+               if (imperial_units)
                        return AltosConvert.meters_to_mph(v);
                return v;
        }
 
-       public String show_units() {
-               if (AltosConvert.imperial_units)
+       public double inverse(double v, boolean imperial_units) {
+               if (imperial_units)
+                       return AltosConvert.mph_to_meters(v);
+               return v;
+       }
+
+       public String show_units(boolean imperial_units) {
+               if (imperial_units)
                        return "mph";
                return "m/s";
        }
 
-       public String say_units() {
-               if (AltosConvert.imperial_units)
+       public String say_units(boolean imperial_units) {
+               if (imperial_units)
                        return "miles per hour";
                return "meters per second";
        }
 
-       public int show_fraction(int width) {
+       public int show_fraction(int width, boolean imperial_units) {
                return width / 9;
        }
 }
\ No newline at end of file
index 825306be998559373141bba449553019605fa18c..6d55b833b83a5bf1a8878d10d6e45b539a71b088 100644 (file)
  * Track flight state from telemetry or eeprom data stream
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
-public class AltosState {
-       public AltosRecord data;
+public class AltosState implements Cloneable {
+
+       public static final int set_position = 1;
+       public static final int set_gps = 2;
+       public static final int set_data = 4;
+
+       public int set;
+
+       static final double ascent_filter_len = 0.5;
+       static final double descent_filter_len = 0.5;
 
        /* derived data */
 
-       public long     report_time;
+       public long     received_time;
 
        public double   time;
+       public double   prev_time;
        public double   time_change;
        public int      tick;
+       private int     prev_tick;
+       public int      boost_tick;
+
+       class AltosValue {
+               private double  value;
+               private double  prev_value;
+               private double  max_value;
+               private double  set_time;
+               private double  prev_set_time;
+
+               void set(double new_value, double time) {
+                       if (new_value != AltosLib.MISSING) {
+                               value = new_value;
+                               if (max_value == AltosLib.MISSING || value > max_value) {
+                                       max_value = value;
+                               }
+                               set_time = time;
+                       }
+               }
+
+               void set_filtered(double new_value, double time) {
+                       if (prev_value != AltosLib.MISSING)
+                               new_value = (prev_value * 15.0 + new_value) / 16.0;
+                       set(new_value, time);
+               }
+
+               double value() {
+                       return value;
+               }
+
+               double max() {
+                       return max_value;
+               }
+
+               double prev() {
+                       return prev_value;
+               }
+
+               double change() {
+                       if (value != AltosLib.MISSING && prev_value != AltosLib.MISSING)
+                               return value - prev_value;
+                       return AltosLib.MISSING;
+               }
+
+               double rate() {
+                       double c = change();
+                       double t = set_time - prev_set_time;
+
+                       if (c != AltosLib.MISSING && t != 0)
+                               return c / t;
+                       return AltosLib.MISSING;
+               }
+
+               double integrate() {
+                       if (value == AltosLib.MISSING)
+                               return AltosLib.MISSING;
+                       if (prev_value == AltosLib.MISSING)
+                               return AltosLib.MISSING;
+
+                       return (value + prev_value) / 2 * (set_time - prev_set_time);
+               }
+
+               double time() {
+                       return set_time;
+               }
+
+               void set_derivative(AltosValue in) {
+                       double  n = in.rate();
+                       
+                       if (n == AltosLib.MISSING)
+                               return;
+
+                       double  p = prev_value;
+                       double  pt = prev_set_time;
+
+                       if (p == AltosLib.MISSING) {
+                               p = 0;
+                               pt = in.time() - 0.01;
+                       }
+
+                       /* Clip changes to reduce noise */
+                       double  ddt = in.time() - pt;
+                       double  ddv = (n - p) / ddt;
+                               
+                       final double max = 100000;
+
+                       /* 100gs */
+                       if (Math.abs(ddv) > max) {
+                               if (n > p)
+                                       n = p + ddt * max;
+                               else
+                                       n = p - ddt * max;
+                       }
+
+                       double filter_len;
+
+                       if (ascent)
+                               filter_len = ascent_filter_len;
+                       else
+                               filter_len = descent_filter_len;
+
+                       double f = 1/Math.exp(ddt/ filter_len);
+                       n = p * f + n * (1-f);
+
+                       set(n, in.time());
+               }
+
+               void set_integral(AltosValue in) {
+                       double  change = in.integrate();
+
+                       if (change != AltosLib.MISSING) {
+                               double  prev = prev_value;
+                               if (prev == AltosLib.MISSING)
+                                       prev = 0;
+                               set(prev + change, in.time());
+                       }
+               }
+
+               void copy(AltosValue old) {
+                       value = old.value;
+                       set_time = old.set_time;
+                       prev_value = old.value;
+                       prev_set_time = old.set_time;
+                       max_value = old.max_value;
+               }
+
+               void finish_update() {
+                       prev_value = value;
+                       prev_set_time = set_time;
+               }
+
+               AltosValue() {
+                       value = AltosLib.MISSING;
+                       prev_value = AltosLib.MISSING;
+                       max_value = AltosLib.MISSING;
+               }
+       }
+
+       class AltosCValue {
+               AltosValue      measured;
+               AltosValue      computed;
+
+               double value() {
+                       double v = measured.value();
+                       if (v != AltosLib.MISSING)
+                               return v;
+                       return computed.value();
+               }
+
+               boolean is_measured() {
+                       return measured.value() != AltosLib.MISSING;
+               }
+
+               double max() {
+                       double m = measured.max();
+
+                       if (m != AltosLib.MISSING)
+                               return m;
+                       return computed.max();
+               }
+
+               double prev_value() {
+                       if (measured.value != AltosLib.MISSING && measured.prev_value != AltosLib.MISSING)
+                               return measured.prev_value;
+                       return computed.prev_value;
+               }
+
+               AltosValue altos_value() {
+                       if (measured.value() != AltosLib.MISSING)
+                               return measured;
+                       return computed;
+               }
+
+               double change() {
+                       double c = measured.change();
+                       if (c == AltosLib.MISSING)
+                               c = computed.change();
+                       return c;
+               }
+
+               double rate() {
+                       double r = measured.rate();
+                       if (r == AltosLib.MISSING)
+                               r = computed.rate();
+                       return r;
+               }
+
+               void set_measured(double new_value, double time) {
+                       measured.set(new_value, time);
+               }
+
+               void set_computed(double new_value, double time) {
+                       computed.set(new_value, time);
+               }
+
+               void set_derivative(AltosValue in) {
+                       computed.set_derivative(in);
+               }
+
+               void set_derivative(AltosCValue in) {
+                       set_derivative(in.altos_value());
+               }
+
+               void set_integral(AltosValue in) {
+                       computed.set_integral(in);
+               }
+               
+               void set_integral(AltosCValue in) {
+                       set_integral(in.altos_value());
+               }
+               
+               void copy(AltosCValue old) {
+                       measured.copy(old.measured);
+                       computed.copy(old.computed);
+               }
+
+               void finish_update() {
+                       measured.finish_update();
+                       computed.finish_update();
+               }
+
+               AltosCValue() {
+                       measured = new AltosValue();
+                       computed = new AltosValue();
+               }
+       }
 
        public int      state;
+       public int      flight;
+       public int      serial;
+       public int      receiver_serial;
        public boolean  landed;
        public boolean  ascent; /* going up? */
-       public boolean boost;   /* under power */
+       public boolean  boost;  /* under power */
+       public int      rssi;
+       public int      status;
+       public int      device_type;
+       public int      config_major;
+       public int      config_minor;
+       public int      apogee_delay;
+       public int      main_deploy;
+       public int      flight_log_max;
+
+       private double pressure_to_altitude(double p) {
+               if (p == AltosLib.MISSING)
+                       return AltosLib.MISSING;
+               return AltosConvert.pressure_to_altitude(p);
+       }
+
+       private AltosCValue ground_altitude;
 
-       public double   ground_altitude;
-       public double   altitude;
-       public double   height;
-       public double   acceleration;
-       public double   battery;
+       public double ground_altitude() {
+               return ground_altitude.value();
+       }
+
+       public void set_ground_altitude(double a) {
+               ground_altitude.set_measured(a, time);
+       }
+
+       class AltosGroundPressure extends AltosCValue {
+               void set_filtered(double p, double time) {
+                       computed.set_filtered(p, time);
+                       if (!is_measured())
+                               ground_altitude.set_computed(pressure_to_altitude(computed.value()), time);
+               }
+
+               void set_measured(double p, double time) {
+                       super.set_measured(p, time);
+                       ground_altitude.set_computed(pressure_to_altitude(p), time);
+               }
+       }
+
+       private AltosGroundPressure ground_pressure;
+               
+       public double ground_pressure() {
+               return ground_pressure.value();
+       }
+
+       public void set_ground_pressure (double pressure) {
+               ground_pressure.set_measured(pressure, time);
+       }
+
+       class AltosAltitude extends AltosCValue {
+
+               private void set_speed(AltosValue v) {
+                       if (!acceleration.is_measured() || !ascent)
+                               speed.set_derivative(this);
+               }
+
+               void set_computed(double a, double time) {
+                       super.set_computed(a,time);
+                       set_speed(computed);
+                       set |= set_position;
+               }
+
+               void set_measured(double a, double time) {
+                       super.set_measured(a,time);
+                       set_speed(measured);
+                       set |= set_position;
+               }
+       }
+
+       private AltosAltitude   altitude;
+
+       public double altitude() {
+               double a = altitude.value();
+               if (a != AltosLib.MISSING)
+                       return a;
+               if (gps != null)
+                       return gps.alt;
+               return AltosLib.MISSING;
+       }
+
+       public double max_altitude() {
+               double a = altitude.max();
+               if (a != AltosLib.MISSING)
+                       return a;
+               return AltosLib.MISSING;
+       }
+
+       public void set_altitude(double new_altitude) {
+               altitude.set_measured(new_altitude, time);
+       }
+
+       class AltosPressure extends AltosValue {
+               void set(double p, double time) {
+                       super.set(p, time);
+                       if (state == AltosLib.ao_flight_pad)
+                               ground_pressure.set_filtered(p, time);
+                       double a = pressure_to_altitude(p);
+                       altitude.set_computed(a, time);
+               }
+       }
+
+       private AltosPressure   pressure;
+
+       public double pressure() {
+               return pressure.value();
+       }
+
+       public void set_pressure(double p) {
+               pressure.set(p, time);
+       }
+
+       public double height() {
+               double k = kalman_height.value();
+               if (k != AltosLib.MISSING)
+                       return k;
+
+               double a = altitude();
+               double g = ground_altitude();
+               if (a != AltosLib.MISSING && g != AltosLib.MISSING)
+                       return a - g;
+               return AltosLib.MISSING;
+       }
+
+       public double max_height() {
+               double  k = kalman_height.max();
+               if (k != AltosLib.MISSING)
+                       return k;
+
+               double a = altitude.max();
+               double g = ground_altitude();
+               if (a != AltosLib.MISSING && g != AltosLib.MISSING)
+                       return a - g;
+               return AltosLib.MISSING;
+       }
+
+       class AltosSpeed extends AltosCValue {
+               
+               void set_accel() {
+                       acceleration.set_derivative(this);
+               }
+
+               void set_derivative(AltosCValue in) {
+                       super.set_derivative(in);
+                       set_accel();
+               }
+
+               void set_computed(double new_value, double time) {
+                       super.set_computed(new_value, time);
+                       set_accel();
+               }
+
+               void set_measured(double new_value, double time) {
+                       super.set_measured(new_value, time);
+                       set_accel();
+               }
+       }
+
+       private AltosSpeed speed;
+
+       public double speed() {
+               double v = kalman_speed.value();
+               if (v != AltosLib.MISSING)
+                       return v;
+               return speed.value();
+       }
+
+       public double max_speed() {
+               double v = kalman_speed.max();
+               if (v != AltosLib.MISSING)
+                       return v;
+               return speed.max();
+       }
+
+       class AltosAccel extends AltosCValue {
+               void set_measured(double a, double time) {
+                       super.set_measured(a, time);
+                       if (ascent)
+                               speed.set_integral(this.measured);
+               }
+       }
+
+       AltosAccel acceleration;
+
+       public double acceleration() {
+               return acceleration.value();
+       }
+
+       public double max_acceleration() {
+               return acceleration.max();
+       }
+
+       public AltosValue       kalman_height, kalman_speed, kalman_acceleration;
+
+       public void set_kalman(double height, double speed, double acceleration) {
+               kalman_height.set(height, time);
+               kalman_speed.set(speed, time);
+               kalman_acceleration.set(acceleration, time);
+       }
+
+       public double   battery_voltage;
+       public double   pyro_voltage;
        public double   temperature;
-       public double   main_sense;
-       public double   drogue_sense;
-       public double   accel_speed;
-       public double   baro_speed;
+       public double   apogee_voltage;
+       public double   main_voltage;
 
-       public double   max_height;
-       public double   max_acceleration;
-       public double   max_accel_speed;
-       public double   max_baro_speed;
+       public double   ignitor_voltage[];
 
        public AltosGPS gps;
+       public AltosGPS temp_gps;
+       public int temp_gps_sat_tick;
+       public boolean  gps_pending;
        public int gps_sequence;
 
        public AltosIMU imu;
@@ -62,10 +492,11 @@ public class AltosState {
        public static final int MIN_PAD_SAMPLES = 10;
 
        public int      npad;
-       public int      ngps;
        public int      gps_waiting;
        public boolean  gps_ready;
 
+       public int      ngps;
+
        public AltosGreatCircle from_pad;
        public double   elevation;      /* from pad */
        public double   range;          /* total distance */
@@ -77,202 +508,554 @@ public class AltosState {
        public int      speak_tick;
        public double   speak_altitude;
 
-       public double speed() {
-               if (ascent)
-                       return accel_speed;
-               else
-                       return baro_speed;
+       public String   callsign;
+       public String   firmware_version;
+
+       public double   accel_plus_g;
+       public double   accel_minus_g;
+       public double   accel;
+       public double   ground_accel;
+       public double   ground_accel_avg;
+
+       public int      log_format;
+
+       public AltosMs5607      baro;
+
+       public AltosCompanion   companion;
+
+       public void set_npad(int npad) {
+               this.npad = npad;
+               gps_waiting = MIN_PAD_SAMPLES - npad;
+               if (this.gps_waiting < 0)
+                       gps_waiting = 0;
+               gps_ready = gps_waiting == 0;
        }
 
-       public double max_speed() {
-               if (max_accel_speed != 0)
-                       return max_accel_speed;
-               return max_baro_speed;
-       }
-
-       public void init (AltosRecord cur, AltosState prev_state) {
-               data = cur;
-
-               /* Discard previous state if it was for a different board */
-               if (prev_state != null && prev_state.data.serial != data.serial)
-                       prev_state = null;
-               ground_altitude = data.ground_altitude();
-
-               altitude = data.altitude();
-               if (altitude == AltosRecord.MISSING && data.gps != null)
-                       altitude = data.gps.alt;
-
-               height = AltosRecord.MISSING;
-               if (data.kalman_height != AltosRecord.MISSING)
-                       height = data.kalman_height;
-               else {
-                       if (altitude != AltosRecord.MISSING && ground_altitude != AltosRecord.MISSING) {
-                               double  cur_height = altitude - ground_altitude;
-                               if (prev_state == null || prev_state.height == AltosRecord.MISSING)
-                                       height = cur_height;
-                               else
-                                       height = (prev_state.height * 15 + cur_height) / 16.0;
-                       }
+       public void init() {
+               set = 0;
+
+               received_time = System.currentTimeMillis();
+               time = AltosLib.MISSING;
+               time_change = AltosLib.MISSING;
+               prev_time = AltosLib.MISSING;
+               tick = AltosLib.MISSING;
+               prev_tick = AltosLib.MISSING;
+               boost_tick = AltosLib.MISSING;
+               state = AltosLib.ao_flight_invalid;
+               flight = AltosLib.MISSING;
+               landed = false;
+               boost = false;
+               rssi = AltosLib.MISSING;
+               status = 0;
+               device_type = AltosLib.MISSING;
+               config_major = AltosLib.MISSING;
+               config_minor = AltosLib.MISSING;
+               apogee_delay = AltosLib.MISSING;
+               main_deploy = AltosLib.MISSING;
+               flight_log_max = AltosLib.MISSING;
+
+               ground_altitude = new AltosCValue();
+               ground_pressure = new AltosGroundPressure();
+               altitude = new AltosAltitude();
+               pressure = new AltosPressure();
+               speed = new AltosSpeed();
+               acceleration = new AltosAccel();
+
+               temperature = AltosLib.MISSING;
+               battery_voltage = AltosLib.MISSING;
+               pyro_voltage = AltosLib.MISSING;
+               apogee_voltage = AltosLib.MISSING;
+               main_voltage = AltosLib.MISSING;
+               ignitor_voltage = null;
+
+               kalman_height = new AltosValue();
+               kalman_speed = new AltosValue();
+               kalman_acceleration = new AltosValue();
+
+               gps = null;
+               temp_gps = null;
+               temp_gps_sat_tick = 0;
+               gps_sequence = 0;
+               gps_pending = false;
+
+               imu = null;
+               mag = null;
+
+               set_npad(0);
+               ngps = 0;
+
+               from_pad = null;
+               elevation = AltosLib.MISSING;
+               range = AltosLib.MISSING;
+               gps_height = AltosLib.MISSING;
+
+               pad_lat = AltosLib.MISSING;
+               pad_lon = AltosLib.MISSING;
+               pad_alt = AltosLib.MISSING;
+
+               speak_tick = AltosLib.MISSING;
+               speak_altitude = AltosLib.MISSING;
+
+               callsign = null;
+
+               accel_plus_g = AltosLib.MISSING;
+               accel_minus_g = AltosLib.MISSING;
+               accel = AltosLib.MISSING;
+
+               ground_accel = AltosLib.MISSING;
+               ground_accel_avg = AltosLib.MISSING;
+
+               log_format = AltosLib.MISSING;
+               serial = AltosLib.MISSING;
+               receiver_serial = AltosLib.MISSING;
+
+               baro = null;
+               companion = null;
+       }
+
+       void finish_update() {
+               prev_tick = tick;
+
+               ground_altitude.finish_update();
+               altitude.finish_update();
+               pressure.finish_update();
+               speed.finish_update();
+               acceleration.finish_update();
+
+               kalman_height.finish_update();
+               kalman_speed.finish_update();
+               kalman_acceleration.finish_update();
+       }
+
+       void copy(AltosState old) {
+
+               if (old == null) {
+                       init();
+                       return;
                }
 
-               report_time = System.currentTimeMillis();
+               received_time = old.received_time;
+               time = old.time;
+               time_change = old.time_change;
+               prev_time = old.time;
+               
+               tick = old.tick;
+               prev_tick = old.tick;
+               boost_tick = old.boost_tick;
+
+               state = old.state;
+               flight = old.flight;
+               landed = old.landed;
+               ascent = old.ascent;
+               boost = old.boost;
+               rssi = old.rssi;
+               status = old.status;
+               device_type = old.device_type;
+               config_major = old.config_major;
+               config_minor = old.config_minor;
+               apogee_delay = old.apogee_delay;
+               main_deploy = old.main_deploy;
+               flight_log_max = old.flight_log_max;
+               
+               set = 0;
+
+               ground_pressure.copy(old.ground_pressure);
+               ground_altitude.copy(old.ground_altitude);
+               altitude.copy(old.altitude);
+               pressure.copy(old.pressure);
+               speed.copy(old.speed);
+               acceleration.copy(old.acceleration);
+
+               battery_voltage = old.battery_voltage;
+               pyro_voltage = old.pyro_voltage;
+               temperature = old.temperature;
+               apogee_voltage = old.apogee_voltage;
+               main_voltage = old.main_voltage;
+               ignitor_voltage = old.ignitor_voltage;
+
+               kalman_height.copy(old.kalman_height);
+               kalman_speed.copy(old.kalman_speed);
+               kalman_acceleration.copy(old.kalman_acceleration);
 
-               if (data.kalman_acceleration != AltosRecord.MISSING)
-                       acceleration = data.kalman_acceleration;
+               if (old.gps != null)
+                       gps = old.gps.clone();
                else
-                       acceleration = data.acceleration();
-               temperature = data.temperature();
-               drogue_sense = data.drogue_voltage();
-               main_sense = data.main_voltage();
-               battery = data.battery_voltage();
-               tick = data.tick;
-               state = data.state;
-
-               if (prev_state != null) {
-
-                       /* Preserve any existing gps data */
-                       npad = prev_state.npad;
-                       ngps = prev_state.ngps;
-                       gps = prev_state.gps;
-                       gps_sequence = prev_state.gps_sequence;
-                       pad_lat = prev_state.pad_lat;
-                       pad_lon = prev_state.pad_lon;
-                       pad_alt = prev_state.pad_alt;
-                       max_height = prev_state.max_height;
-                       max_acceleration = prev_state.max_acceleration;
-                       max_accel_speed = prev_state.max_accel_speed;
-                       max_baro_speed = prev_state.max_baro_speed;
-                       imu = prev_state.imu;
-                       mag = prev_state.mag;
-
-                       /* make sure the clock is monotonic */
-                       while (tick < prev_state.tick)
-                               tick += 65536;
-
-                       time_change = (tick - prev_state.tick) / 100.0;
-
-                       if (data.kalman_speed != AltosRecord.MISSING) {
-                               baro_speed = accel_speed = data.kalman_speed;
-                       } else {
-                               /* compute barometric speed */
-
-                               double height_change = height - prev_state.height;
-
-                               double prev_baro_speed = prev_state.baro_speed;
-                               if (prev_baro_speed == AltosRecord.MISSING)
-                                       prev_baro_speed = 0;
-
-                               if (time_change > 0)
-                                       baro_speed = (prev_baro_speed * 3 + (height_change / time_change)) / 4.0;
-                               else
-                                       baro_speed = prev_state.baro_speed;
+                       gps = null;
+               if (old.temp_gps != null)
+                       temp_gps = old.temp_gps.clone();
+               else
+                       temp_gps = null;
+               temp_gps_sat_tick = old.temp_gps_sat_tick;
+               gps_sequence = old.gps_sequence;
+               gps_pending = old.gps_pending;
 
-                               double prev_accel_speed = prev_state.accel_speed;
+               if (old.imu != null)
+                       imu = old.imu.clone();
+               else
+                       imu = null;
 
-                               if (prev_accel_speed == AltosRecord.MISSING)
-                                       prev_accel_speed = 0;
+               if (old.mag != null)
+                       mag = old.mag.clone();
+               else
+                       mag = null;
 
-                               if (acceleration == AltosRecord.MISSING) {
-                                       /* Fill in mising acceleration value */
-                                       accel_speed = baro_speed;
+               npad = old.npad;
+               gps_waiting = old.gps_waiting;
+               gps_ready = old.gps_ready;
+               ngps = old.ngps;
 
-                                       if (time_change > 0 && accel_speed != AltosRecord.MISSING)
-                                               acceleration = (accel_speed - prev_accel_speed) / time_change;
-                                       else
-                                               acceleration = prev_state.acceleration;
-                               } else {
-                                       /* compute accelerometer speed */
-                                       accel_speed = prev_accel_speed + acceleration * time_change;
+               if (old.from_pad != null)
+                       from_pad = old.from_pad.clone();
+               else
+                       from_pad = null;
+
+               elevation = old.elevation;
+               range = old.range;
+
+               gps_height = old.gps_height;
+               pad_lat = old.pad_lat;
+               pad_lon = old.pad_lon;
+               pad_alt = old.pad_alt;
+
+               speak_tick = old.speak_tick;
+               speak_altitude = old.speak_altitude;
+
+               callsign = old.callsign;
+
+               accel_plus_g = old.accel_plus_g;
+               accel_minus_g = old.accel_minus_g;
+               accel = old.accel;
+               ground_accel = old.ground_accel;
+               ground_accel_avg = old.ground_accel_avg;
+
+               log_format = old.log_format;
+               serial = old.serial;
+               receiver_serial = old.receiver_serial;
+
+               baro = old.baro;
+               companion = old.companion;
+       }
+       
+       void update_time() {
+       }
+
+       void update_gps() {
+               elevation = 0;
+               range = -1;
+               gps_height = 0;
+
+               if (gps == null)
+                       return;
+
+               if (gps.locked && gps.nsat >= 4) {
+                       /* Track consecutive 'good' gps reports, waiting for 10 of them */
+                       if (state == AltosLib.ao_flight_pad) {
+                               set_npad(npad+1);
+                               if (pad_lat != AltosLib.MISSING) {
+                                       pad_lat = (pad_lat * 31 + gps.lat) / 32;
+                                       pad_lon = (pad_lon * 31 + gps.lon) / 32;
+                                       pad_alt = (pad_alt * 31 + gps.alt) / 32;
                                }
                        }
-               } else {
-                       npad = 0;
-                       ngps = 0;
-                       gps = null;
-                       gps_sequence = 0;
-                       baro_speed = AltosRecord.MISSING;
-                       accel_speed = AltosRecord.MISSING;
-                       pad_alt = AltosRecord.MISSING;
-                       max_baro_speed = 0;
-                       max_accel_speed = 0;
-                       max_height = 0;
-                       max_acceleration = 0;
-                       time_change = 0;
+                       if (pad_lat == AltosLib.MISSING) {
+                               pad_lat = gps.lat;
+                               pad_lon = gps.lon;
+                               pad_alt = gps.alt;
+                       }
                }
+               if (gps.lat != 0 && gps.lon != 0 &&
+                   pad_lat != AltosLib.MISSING &&
+                   pad_lon != AltosLib.MISSING)
+               {
+                       double h = height();
 
-               time = tick / 100.0;
-
-               if (data.gps != null && data.gps_sequence != gps_sequence && (state < AltosLib.ao_flight_boost)) {
+                       if (h == AltosLib.MISSING)
+                               h = 0;
+                       from_pad = new AltosGreatCircle(pad_lat, pad_lon, 0, gps.lat, gps.lon, h);
+                       elevation = from_pad.elevation;
+                       range = from_pad.range;
+                       gps_height = gps.alt - pad_alt;
+               }
+       }
 
-                       /* Track consecutive 'good' gps reports, waiting for 10 of them */
-                       if (data.gps != null && data.gps.locked && data.gps.nsat >= 4)
-                               npad++;
-                       else
-                               npad = 0;
-
-                       /* Average GPS data while on the pad */
-                       if (data.gps != null && data.gps.locked && data.gps.nsat >= 4) {
-                               if (ngps > 1 && state == AltosLib.ao_flight_pad) {
-                                       /* filter pad position */
-                                       pad_lat = (pad_lat * 31.0 + data.gps.lat) / 32.0;
-                                       pad_lon = (pad_lon * 31.0 + data.gps.lon) / 32.0;
-                                       pad_alt = (pad_alt * 31.0 + data.gps.alt) / 32.0;
-                               } else {
-                                       pad_lat = data.gps.lat;
-                                       pad_lon = data.gps.lon;
-                                       pad_alt = data.gps.alt;
+       public void set_tick(int new_tick) {
+               if (new_tick != AltosLib.MISSING) {
+                       if (prev_tick != AltosLib.MISSING) {
+                               while (new_tick < prev_tick - 1000) {
+                                       new_tick += 65536;
                                }
-                               ngps++;
                        }
-               } else {
-                       if (ngps == 0 && ground_altitude != AltosRecord.MISSING)
-                               pad_alt = ground_altitude;
+                       tick = new_tick;
+                       time = tick / 100.0;
+                       time_change = time - prev_time;
                }
+       }
 
-               gps_sequence = data.gps_sequence;
+       public void set_boost_tick(int boost_tick) {
+               if (boost_tick != AltosLib.MISSING)
+                       this.boost_tick = boost_tick;
+       }
 
-               gps_waiting = MIN_PAD_SAMPLES - npad;
-               if (gps_waiting < 0)
-                       gps_waiting = 0;
+       public String state_name() {
+               return AltosLib.state_name(state);
+       }
 
-               gps_ready = gps_waiting == 0;
+       public void set_state(int state) {
+               if (state != AltosLib.ao_flight_invalid) {
+                       this.state = state;
+                       ascent = (AltosLib.ao_flight_boost <= state &&
+                                 state <= AltosLib.ao_flight_coast);
+                       boost = (AltosLib.ao_flight_boost == state);
+               }
 
-               ascent = (AltosLib.ao_flight_boost <= state &&
-                         state <= AltosLib.ao_flight_coast);
-               boost = (AltosLib.ao_flight_boost == state);
+       }
 
-               /* Only look at accelerometer data under boost */
-               if (boost && acceleration != AltosRecord.MISSING && (max_acceleration == AltosRecord.MISSING || acceleration > max_acceleration))
-                       max_acceleration = acceleration;
-               if (boost && accel_speed != AltosRecord.MISSING && accel_speed > max_accel_speed)
-                       max_accel_speed = accel_speed;
-               if (boost && baro_speed != AltosRecord.MISSING && baro_speed > max_baro_speed)
-                       max_baro_speed = baro_speed;
+       public void set_device_type(int device_type) {
+               this.device_type = device_type;
+       }
 
-               if (height != AltosRecord.MISSING && height > max_height)
-                       max_height = height;
-               elevation = 0;
-               range = -1;
-               gps_height = 0;
-               if (data.gps != null) {
-                       gps = data.gps;
-                       if (ngps > 0 && gps.locked) {
-                               double h = height;
-
-                               if (h == AltosRecord.MISSING) h = 0;
-                               from_pad = new AltosGreatCircle(pad_lat, pad_lon, 0, gps.lat, gps.lon, h);
-                               elevation = from_pad.elevation;
-                               range = from_pad.range;
-                               gps_height = gps.alt - pad_alt;
+       public void set_config(int major, int minor, int apogee_delay, int main_deploy, int flight_log_max) {
+               config_major = major;
+               config_minor = minor;
+               this.apogee_delay = apogee_delay;
+               this.main_deploy = main_deploy;
+               this.flight_log_max = flight_log_max;
+       }
+
+       public void set_callsign(String callsign) {
+               this.callsign = callsign;
+       }
+
+       public void set_firmware_version(String version) {
+               firmware_version = version;
+       }
+
+       public void set_flight(int flight) {
+
+               /* When the flight changes, reset the state */
+               if (flight != AltosLib.MISSING && flight != 0) {
+                       if (this.flight != AltosLib.MISSING &&
+                           this.flight != flight) {
+                               int bt = boost_tick;
+                               init();
+                               boost_tick = bt;
+                       }
+                       this.flight = flight;
+               }
+       }
+
+       public void set_serial(int serial) {
+               /* When the serial changes, reset the state */
+               if (serial != AltosLib.MISSING) {
+                       if (this.serial != AltosLib.MISSING &&
+                           this.serial != serial) {
+                               int bt = boost_tick;
+                               init();
+                               boost_tick = bt;
+                       }
+                       this.serial = serial;
+               }
+       }
+
+       public void set_receiver_serial(int serial) {
+               if (serial != AltosLib.MISSING)
+                       receiver_serial = serial;
+       }
+
+       public int rssi() {
+               if (rssi == AltosLib.MISSING)
+                       return 0;
+               return rssi;
+       }
+
+       public void set_rssi(int rssi, int status) {
+               if (rssi != AltosLib.MISSING) {
+                       this.rssi = rssi;
+                       this.status = status;
+               }
+       }
+
+       public void set_received_time(long ms) {
+               received_time = ms;
+       }
+
+       public void set_gps(AltosGPS gps, int sequence) {
+               if (gps != null) {
+                       this.gps = gps.clone();
+                       gps_sequence = sequence;
+                       update_gps();
+                       set |= set_gps;
+               }
+       }
+
+       public void set_imu(AltosIMU imu) {
+               if (imu != null)
+                       imu = imu.clone();
+               this.imu = imu;
+       }
+
+       public void set_mag(AltosMag mag) {
+               this.mag = mag.clone();
+       }
+
+       public AltosMs5607 make_baro() {
+               if (baro == null)
+                       baro = new AltosMs5607();
+               return baro;
+       }
+
+       public void set_ms5607(AltosMs5607 ms5607) {
+               baro = ms5607;
+
+               if (baro != null) {
+                       set_pressure(baro.pa);
+                       set_temperature(baro.cc / 100.0);
+               }
+       }
+
+       public void set_ms5607(int pres, int temp) {
+               if (baro != null) {
+                       baro.set(pres, temp);
+
+                       set_pressure(baro.pa);
+                       set_temperature(baro.cc / 100.0);
+               }
+       }
+
+       public void make_companion (int nchannels) {
+               if (companion == null)
+                       companion = new AltosCompanion(nchannels);
+       }
+
+       public void set_companion(AltosCompanion companion) {
+               this.companion = companion;
+       }
+
+       void update_accel() {
+               double  ground = ground_accel;
+
+               if (ground == AltosLib.MISSING)
+                       ground = ground_accel_avg;
+               if (accel == AltosLib.MISSING)
+                       return;
+               if (ground == AltosLib.MISSING)
+                       return;
+               if (accel_plus_g == AltosLib.MISSING)
+                       return;
+               if (accel_minus_g == AltosLib.MISSING)
+                       return;
+
+               double counts_per_g = (accel_minus_g - accel_plus_g) / 2.0;
+               double counts_per_mss = counts_per_g / 9.80665;
+               acceleration.set_measured((ground - accel) / counts_per_mss, time);
+       }
+
+       public void set_accel_g(double accel_plus_g, double accel_minus_g) {
+               if (accel_plus_g != AltosLib.MISSING) {
+                       this.accel_plus_g = accel_plus_g;
+                       this.accel_minus_g = accel_minus_g;
+                       update_accel();
+               }
+       }
+
+       public void set_ground_accel(double ground_accel) {
+               if (ground_accel != AltosLib.MISSING) {
+                       this.ground_accel = ground_accel;
+                       update_accel();
+               }
+       }
+
+       public void set_accel(double accel) {
+               if (accel != AltosLib.MISSING) {
+                       this.accel = accel;
+                       if (state == AltosLib.ao_flight_pad) {
+                               if (ground_accel_avg == AltosLib.MISSING)
+                                       ground_accel_avg = accel;
+                               else
+                                       ground_accel_avg = (ground_accel_avg * 7 + accel) / 8;
                        }
                }
+               update_accel();
+       }
+
+       public void set_temperature(double temperature) {
+               if (temperature != AltosLib.MISSING) {
+                       this.temperature = temperature;
+                       set |= set_data;
+               }
+       }
+
+       public void set_battery_voltage(double battery_voltage) {
+               if (battery_voltage != AltosLib.MISSING) {
+                       this.battery_voltage = battery_voltage;
+                       set |= set_data;
+               }
+       }
+
+       public void set_pyro_voltage(double pyro_voltage) {
+               if (pyro_voltage != AltosLib.MISSING) {
+                       this.pyro_voltage = pyro_voltage;
+                       set |= set_data;
+               }
+       }
+
+       public void set_apogee_voltage(double apogee_voltage) {
+               if (apogee_voltage != AltosLib.MISSING) {
+                       this.apogee_voltage = apogee_voltage;
+                       set |= set_data;
+               }
+       }
+
+       public void set_main_voltage(double main_voltage) {
+               if (main_voltage != AltosLib.MISSING) {
+                       this.main_voltage = main_voltage;
+                       set |= set_data;
+               }
+       }
+
+       public void set_ignitor_voltage(double[] voltage) {
+               this.ignitor_voltage = voltage;
+       }
+
+       public double time_since_boost() {
+               if (tick == AltosLib.MISSING)
+                       return 0.0;
+
+               if (boost_tick == AltosLib.MISSING)
+                       return tick / 100.0;
+               return (tick - boost_tick) / 100.0;
+       }
+
+       public boolean valid() {
+               return tick != AltosLib.MISSING && serial != AltosLib.MISSING;
+       }
+
+       public AltosGPS make_temp_gps(boolean sats) {
+               if (temp_gps == null) {
+                       temp_gps = new AltosGPS(gps);
+               }
+               gps_pending = true;
+               if (sats) {
+                       if (tick != temp_gps_sat_tick)
+                               temp_gps.cc_gps_sat = null;
+                       temp_gps_sat_tick = tick;
+               }
+               return temp_gps;
+       }
+
+       public void set_temp_gps() {
+               set_gps(temp_gps, gps_sequence + 1);
+               gps_pending = false;
+               temp_gps = null;
        }
 
-       public AltosState(AltosRecord cur) {
-               init(cur, null);
+       public AltosState clone() {
+               AltosState s = new AltosState();
+               s.copy(this);
+               return s;
        }
 
-       public AltosState (AltosRecord cur, AltosState prev) {
-               init(cur, prev);
+       public AltosState () {
+               init();
        }
 }
diff --git a/altoslib/AltosStateIterable.java b/altoslib/AltosStateIterable.java
new file mode 100644 (file)
index 0000000..6d63741
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+
+public abstract class AltosStateIterable implements Iterable<AltosState> {
+
+       public void write_comments (PrintStream out) {
+       }
+       
+       public abstract void write(PrintStream out);
+}
diff --git a/altoslib/AltosStateUpdate.java b/altoslib/AltosStateUpdate.java
new file mode 100644 (file)
index 0000000..97a5dfe
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public interface AltosStateUpdate {
+       public void     update_state(AltosState state) throws InterruptedException;
+}
\ No newline at end of file
index e73223499a2f42ed91950b0a70e778e3541b3a12..03ca9f80504bafa4b3b418bf43924a6b36686b14 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.text.*;
 
@@ -23,217 +23,114 @@ import java.text.*;
  * Telemetry data contents
  */
 
+public abstract class AltosTelemetry implements AltosStateUpdate {
 
-/*
- * The packet format is a simple hex dump of the raw telemetry frame.
- * It starts with 'TELEM', then contains hex digits with a checksum as the last
- * byte on the line.
- *
- * Version 4 is a replacement with consistent syntax. Each telemetry line
- * contains a sequence of space-separated names and values, the values are
- * either integers or strings. The names are all unique. All values are
- * optional
- *
- * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944
- *   r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764
- *   a_s 0 a_b 26439 g_s u g_n 0 s_n 0
- *
- * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788
- *   r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0
- *
- * General header fields
- *
- *     Name            Value
- *
- *     VERSION         Telemetry version number (4 or more). Must be first.
- *     c               Callsign (string, no spaces allowed)
- *     n               Flight unit serial number (integer)
- *     f               Flight number (integer)
- *     r               Packet RSSI value (integer)
- *     s               Flight computer state (string, no spaces allowed)
- *     t               Flight computer clock (integer in centiseconds)
- *
- * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports
- * in 1/2dB increments while this protocol provides only integers. So,
- * the syntax didn't change just the interpretation of the RSSI
- * values.
- *
- * Version 2 of the telemetry data stream is a bit of a mess, with no
- * consistent formatting. In particular, the GPS data is formatted for
- * viewing instead of parsing.  However, the key feature is that every
- * telemetry line contains all of the information necessary to
- * describe the current rocket state, including the calibration values
- * for accelerometer and barometer.
- *
- * GPS unlocked:
- *
- * VERSION 2 CALL KB0G SERIAL  51 FLIGHT     2 RSSI  -68 STATUS ff STATE     pad  1001 \
- *    a: 16032 p: 21232 t: 20284 v: 25160 d:   204 m:   204 fa: 16038 ga: 16032 fv:       0 \
- *    fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS  0 sat unlocked SAT 1   15  30
- *
- * GPS locked:
- *
- * VERSION 2 CALL KB0G SERIAL  51 FLIGHT     2 RSSI  -71 STATUS ff STATE     pad  2504 \
- *     a: 16028 p: 21220 t: 20360 v: 25004 d:   208 m:   200 fa: 16031 ga: 16032 fv:     330 \
- *     fp: 21231 gp: 21230 a+: 16049 a-: 16304 \
- *     GPS  9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W  1790m  \
- *     0.00m/s(H) 0°     0.00m/s(V) 1.0(hdop)     0(herr)     0(verr) \
- *     SAT 10   29  30  24  28   5  25  21  20  15  33   1  23  30  24  18  26  10  29   2  26
- *
- */
+       /* All telemetry packets have these fields */
+       public int      tick;
+       public int      serial;
+       public int      rssi;
+       public int      status;
+
+       /* Mark when we received the packet */
+       long            received_time;
+
+       static boolean cksum(int[] bytes) {
+               int     sum = 0x5a;
+               for (int i = 1; i < bytes.length - 1; i++)
+                       sum += bytes[i];
+               sum &= 0xff;
+               return sum == bytes[bytes.length - 1];
+       }
+
+       public void update_state(AltosState state) {
+               if (state.state == AltosLib.ao_flight_invalid)
+                       state.set_state(AltosLib.ao_flight_startup);
+               state.set_serial(serial);
+               state.set_tick(tick);
+               state.set_rssi(rssi, status);
+               state.set_received_time(received_time);
+       }
+
+       final static int PKT_APPEND_STATUS_1_CRC_OK             = (1 << 7);
+       final static int PKT_APPEND_STATUS_1_LQI_MASK           = (0x7f);
+       final static int PKT_APPEND_STATUS_1_LQI_SHIFT          = 0;
+
+       final static int packet_type_TM_sensor = 0x01;
+       final static int packet_type_Tm_sensor = 0x02;
+       final static int packet_type_Tn_sensor = 0x03;
+       final static int packet_type_configuration = 0x04;
+       final static int packet_type_location = 0x05;
+       final static int packet_type_satellite = 0x06;
+       final static int packet_type_companion = 0x07;
+       final static int packet_type_mega_sensor = 0x08;
+       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;
+       
+       static AltosTelemetry parse_hex(String hex)  throws ParseException, AltosCRCException {
+               AltosTelemetry  telem = null;
+
+               int[] bytes;
+               try {
+                       bytes = AltosLib.hexbytes(hex);
+               } catch (NumberFormatException ne) {
+                       throw new ParseException(ne.getMessage(), 0);
+               }
+
+               /* one for length, one for checksum */
+               if (bytes[0] != bytes.length - 2)
+                       throw new ParseException(String.format("invalid length %d != %d\n",
+                                                              bytes[0],
+                                                              bytes.length - 2), 0);
+               if (!cksum(bytes))
+                       throw new ParseException(String.format("invalid line \"%s\"", hex), 0);
+
+               int     rssi = AltosLib.int8(bytes, bytes.length - 3) / 2 - 74;
+               int     status = AltosLib.uint8(bytes, bytes.length - 2);
+
+               if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0)
+                       throw new AltosCRCException(rssi);
+
+               /* length, data ..., rssi, status, checksum -- 4 bytes extra */
+               switch (bytes.length) {
+               case AltosLib.ao_telemetry_standard_len + 4:
+                       telem = AltosTelemetryStandard.parse_hex(bytes);
+                       break;
+               case AltosLib.ao_telemetry_0_9_len + 4:
+                       telem = new AltosTelemetryLegacy(bytes);
+                       break;
+               case AltosLib.ao_telemetry_0_8_len + 4:
+                       telem = new AltosTelemetryLegacy(bytes);
+                       break;
+               default:
+                       throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0);
+               }
+               if (telem != null) {
+                       telem.received_time = System.currentTimeMillis();
+                       telem.rssi = rssi;
+                       telem.status = status;
+               }
+               return telem;
+       }
+
+       public static AltosTelemetry parse(String line) throws ParseException, AltosCRCException {
+               String[] word = line.split("\\s+");
+               int i =0;
+
+               if (word[i].equals("CRC") && word[i+1].equals("INVALID")) {
+                       i += 2;
+                       AltosParse.word(word[i++], "RSSI");
+                       throw new AltosCRCException(AltosParse.parse_int(word[i++]));
+               }
+
+               AltosTelemetry telem;
 
-public abstract class AltosTelemetry extends AltosRecord {
-
-       /*
-        * General header fields
-        *
-        *      Name            Value
-        *
-        *      VERSION         Telemetry version number (4 or more). Must be first.
-        *      c               Callsign (string, no spaces allowed)
-        *      n               Flight unit serial number (integer)
-        *      f               Flight number (integer)
-        *      r               Packet RSSI value (integer)
-        *      s               Flight computer state (string, no spaces allowed)
-        *      t               Flight computer clock (integer in centiseconds)
-        */
-
-       final static String AO_TELEM_VERSION    = "VERSION";
-       final static String AO_TELEM_CALL       = "c";
-       final static String AO_TELEM_SERIAL     = "n";
-       final static String AO_TELEM_FLIGHT     = "f";
-       final static String AO_TELEM_RSSI       = "r";
-       final static String AO_TELEM_STATE      = "s";
-       final static String AO_TELEM_TICK       = "t";
-
-       /*
-        * Raw sensor values
-        *
-        *      Name            Value
-        *      r_a             Accelerometer reading (integer)
-        *      r_b             Barometer reading (integer)
-        *      r_t             Thermometer reading (integer)
-        *      r_v             Battery reading (integer)
-        *      r_d             Drogue continuity (integer)
-        *      r_m             Main continuity (integer)
-        */
-
-       final static String AO_TELEM_RAW_ACCEL  = "r_a";
-       final static String AO_TELEM_RAW_BARO   = "r_b";
-       final static String AO_TELEM_RAW_THERMO = "r_t";
-       final static String AO_TELEM_RAW_BATT   = "r_v";
-       final static String AO_TELEM_RAW_DROGUE = "r_d";
-       final static String AO_TELEM_RAW_MAIN   = "r_m";
-
-       /*
-        * Sensor calibration values
-        *
-        *      Name            Value
-        *      c_a             Ground accelerometer reading (integer)
-        *      c_b             Ground barometer reading (integer)
-        *      c_p             Accelerometer reading for +1g
-        *      c_m             Accelerometer reading for -1g
-        */
-
-       final static String AO_TELEM_CAL_ACCEL_GROUND   = "c_a";
-       final static String AO_TELEM_CAL_BARO_GROUND    = "c_b";
-       final static String AO_TELEM_CAL_ACCEL_PLUS     = "c_p";
-       final static String AO_TELEM_CAL_ACCEL_MINUS    = "c_m";
-
-       /*
-        * Kalman state values
-        *
-        *      Name            Value
-        *      k_h             Height above pad (integer, meters)
-        *      k_s             Vertical speeed (integer, m/s * 16)
-        *      k_a             Vertical acceleration (integer, m/s² * 16)
-        */
-
-       final static String AO_TELEM_KALMAN_HEIGHT      = "k_h";
-       final static String AO_TELEM_KALMAN_SPEED       = "k_s";
-       final static String AO_TELEM_KALMAN_ACCEL       = "k_a";
-
-       /*
-        * Ad-hoc flight values
-        *
-        *      Name            Value
-        *      a_a             Acceleration (integer, sensor units)
-        *      a_s             Speed (integer, integrated acceleration value)
-        *      a_b             Barometer reading (integer, sensor units)
-        */
-
-       final static String AO_TELEM_ADHOC_ACCEL        = "a_a";
-       final static String AO_TELEM_ADHOC_SPEED        = "a_s";
-       final static String AO_TELEM_ADHOC_BARO         = "a_b";
-
-       /*
-        * GPS values
-        *
-        *      Name            Value
-        *      g_s             GPS state (string):
-        *                              l       locked
-        *                              u       unlocked
-        *                              e       error (missing or broken)
-        *      g_n             Number of sats used in solution
-        *      g_ns            Latitude (degrees * 10e7)
-        *      g_ew            Longitude (degrees * 10e7)
-        *      g_a             Altitude (integer meters)
-        *      g_Y             GPS year (integer)
-        *      g_M             GPS month (integer - 1-12)
-        *      g_D             GPS day (integer - 1-31)
-        *      g_h             GPS hour (integer - 0-23)
-        *      g_m             GPS minute (integer - 0-59)
-        *      g_s             GPS second (integer - 0-59)
-        *      g_v             GPS vertical speed (integer, cm/sec)
-        *      g_s             GPS horizontal speed (integer, cm/sec)
-        *      g_c             GPS course (integer, 0-359)
-        *      g_hd            GPS hdop (integer * 10)
-        *      g_vd            GPS vdop (integer * 10)
-        *      g_he            GPS h error (integer)
-        *      g_ve            GPS v error (integer)
-        */
-
-       final static String AO_TELEM_GPS_STATE                  = "g";
-       final static String AO_TELEM_GPS_STATE_LOCKED           = "l";
-       final static String AO_TELEM_GPS_STATE_UNLOCKED         = "u";
-       final static String AO_TELEM_GPS_STATE_ERROR            = "e";
-       final static String AO_TELEM_GPS_NUM_SAT                = "g_n";
-       final static String AO_TELEM_GPS_LATITUDE               = "g_ns";
-       final static String AO_TELEM_GPS_LONGITUDE              = "g_ew";
-       final static String AO_TELEM_GPS_ALTITUDE               = "g_a";
-       final static String AO_TELEM_GPS_YEAR                   = "g_Y";
-       final static String AO_TELEM_GPS_MONTH                  = "g_M";
-       final static String AO_TELEM_GPS_DAY                    = "g_D";
-       final static String AO_TELEM_GPS_HOUR                   = "g_h";
-       final static String AO_TELEM_GPS_MINUTE                 = "g_m";
-       final static String AO_TELEM_GPS_SECOND                 = "g_s";
-       final static String AO_TELEM_GPS_VERTICAL_SPEED         = "g_v";
-       final static String AO_TELEM_GPS_HORIZONTAL_SPEED       = "g_g";
-       final static String AO_TELEM_GPS_COURSE                 = "g_c";
-       final static String AO_TELEM_GPS_HDOP                   = "g_hd";
-       final static String AO_TELEM_GPS_VDOP                   = "g_vd";
-       final static String AO_TELEM_GPS_HERROR                 = "g_he";
-       final static String AO_TELEM_GPS_VERROR                 = "g_ve";
-
-       /*
-        * GPS satellite values
-        *
-        *      Name            Value
-        *      s_n             Number of satellites reported (integer)
-        *      s_v0            Space vehicle ID (integer) for report 0
-        *      s_c0            C/N0 number (integer) for report 0
-        *      s_v1            Space vehicle ID (integer) for report 1
-        *      s_c1            C/N0 number (integer) for report 1
-        *      ...
-        */
-
-       final static String AO_TELEM_SAT_NUM    = "s_n";
-       final static String AO_TELEM_SAT_SVID   = "s_v";
-       final static String AO_TELEM_SAT_C_N_0  = "s_c";
-
-       static public AltosRecord parse(String line, AltosRecord previous) throws ParseException, AltosCRCException {
-               AltosTelemetryRecord    r = AltosTelemetryRecord.parse(line);
-
-               return r.update_state(previous);
+               if (word[i].equals("TELEM")) {
+                       telem = parse_hex(word[i+1]);
+               } else {
+                       telem = new AltosTelemetryLegacy(line);
+               }
+               return telem;
        }
 }
diff --git a/altoslib/AltosTelemetryConfiguration.java b/altoslib/AltosTelemetryConfiguration.java
new file mode 100644 (file)
index 0000000..e5d444d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetryConfiguration extends AltosTelemetryStandard {
+       int     device_type;
+       int     flight;
+       int     config_major;
+       int     config_minor;
+       int     apogee_delay;
+       int     main_deploy;
+       int     flight_log_max;
+       String  callsign;
+       String  version;
+
+       public AltosTelemetryConfiguration(int[] bytes) {
+               super(bytes);
+
+               device_type    = uint8(5);
+               flight         = uint16(6);
+               config_major   = uint8(8);
+               config_minor   = uint8(9);
+               apogee_delay   = uint16(10);
+               main_deploy    = uint16(12);
+               flight_log_max = uint16(14);
+               callsign       = string(16, 8);
+               version        = string(24, 8);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+               state.set_device_type(device_type);
+               state.set_flight(flight);
+               state.set_config(config_major, config_minor, apogee_delay, main_deploy, flight_log_max);
+
+               state.set_callsign(callsign);
+               state.set_firmware_version(version);
+       }
+}
diff --git a/altoslib/AltosTelemetryFile.java b/altoslib/AltosTelemetryFile.java
new file mode 100644 (file)
index 0000000..7566d94
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+class AltosTelemetryIterator implements Iterator<AltosState> {
+       AltosState                      state;
+       Iterator<AltosTelemetry>        telems;
+       AltosTelemetry                  next;
+       boolean                         seen;
+
+       public boolean hasNext() {
+               return !seen || telems.hasNext();
+       }
+
+       public AltosState next() {
+               if (seen) {
+                       AltosState      n = state.clone();
+                       AltosTelemetry  t = telems.next();
+
+                       t.update_state(n);
+                       state = n;
+               }
+               seen = true;
+               return state;
+       }
+
+       public void remove () {
+       }
+
+       public AltosTelemetryIterator(AltosState start, Iterator<AltosTelemetry> telems) {
+               this.state = start;
+               this.telems = telems;
+               this.seen = false;
+       }
+}
+
+public class AltosTelemetryFile extends AltosStateIterable {
+
+       AltosTelemetryIterable  telems;
+       AltosState              start;
+
+       public void write_comments(PrintStream out) {
+       }
+
+       public void write(PrintStream out) {
+               
+       }
+
+       public AltosTelemetryFile(FileInputStream input) {
+               telems = new AltosTelemetryIterable(input);
+               start = new AltosState();
+
+               /* Find boost tick */
+               AltosState      state = start.clone();
+
+               for (AltosTelemetry telem : telems) {
+                       telem.update_state(state);
+                       state.finish_update();
+                       if (state.state != AltosLib.ao_flight_invalid && state.state >= AltosLib.ao_flight_boost) {
+                               start.set_boost_tick(state.tick);
+                               break;
+                       }
+               }
+       }
+
+       public Iterator<AltosState> iterator() {
+               AltosState                      state = start.clone();
+               Iterator<AltosTelemetry>        i = telems.iterator();
+
+               while (i.hasNext() && !state.valid()) {
+                       AltosTelemetry  t = i.next();
+                       t.update_state(state);
+                       state.finish_update();
+               }
+               return new AltosTelemetryIterator(state, i);
+       }
+}
\ No newline at end of file
index 570336387640c1ae77560e4dcf038967e3c08465..bf30b4c88b0906cb948684be2d52a27b2c3c8c65 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.io.*;
 import java.util.*;
 import java.text.*;
 
-public class AltosTelemetryIterable extends AltosRecordIterable {
-       TreeSet<AltosRecord>    records;
+class AltosTelemetryOrdered implements Comparable<AltosTelemetryOrdered> {
+       AltosTelemetry  telem;
+       int             index;
+       int             tick;
 
-       public Iterator<AltosRecord> iterator () {
-               return records.iterator();
+       public int compareTo(AltosTelemetryOrdered o) {
+               int     tick_diff = tick - o.tick;
+
+               if (tick_diff != 0)
+                       return tick_diff;
+               return index - o.index;
        }
 
-       boolean has_gps = false;
-       boolean has_accel = false;
-       boolean has_ignite = false;
-       public boolean has_gps() { return has_gps; }
-       public boolean has_accel() { return has_accel; }
-       public boolean has_ignite() { return has_ignite; };
+       AltosTelemetryOrdered (AltosTelemetry telem, int index, int tick) {
+               this.telem = telem;
+               this.index = index;
+               this.tick = tick;
+       }
+}
 
-       public AltosTelemetryIterable (FileInputStream input) {
-               boolean saw_boost = false;
-               int     current_tick = 0;
-               int     boost_tick = 0;
+class AltosTelemetryOrderedIterator implements Iterator<AltosTelemetry> {
+       Iterator<AltosTelemetryOrdered> iterator;
+
+       public AltosTelemetryOrderedIterator(TreeSet<AltosTelemetryOrdered> telems) {
+               iterator = telems.iterator();
+       }
+
+       public boolean hasNext() {
+               return iterator.hasNext();
+       }
 
-               AltosRecord     previous = null;
-               records = new TreeSet<AltosRecord> ();
+       public AltosTelemetry next() {
+               return iterator.next().telem;
+       }
+
+       public void remove () {
+       }
+}
+
+public class AltosTelemetryIterable implements Iterable<AltosTelemetry> {
+       TreeSet<AltosTelemetryOrdered>  telems;
+       int tick;
+       int index;
+
+       public void add (AltosTelemetry telem) {
+               int     t = telem.tick;
+               if (!telems.isEmpty()) {
+                       while (t < tick - 1000)
+                               t += 65536;
+               }
+               tick = t;
+               telems.add(new AltosTelemetryOrdered(telem, index++, tick));
+       }
+
+       public Iterator<AltosTelemetry> iterator () {
+               return new AltosTelemetryOrderedIterator(telems);
+       }
+
+       public AltosTelemetryIterable (FileInputStream input) {
+               telems = new TreeSet<AltosTelemetryOrdered> ();
+               tick = 0;
+               index = 0;
 
                try {
                        for (;;) {
@@ -50,32 +91,10 @@ public class AltosTelemetryIterable extends AltosRecordIterable {
                                        break;
                                }
                                try {
-                                       AltosRecord record = AltosTelemetry.parse(line, previous);
-                                       if (record == null)
+                                       AltosTelemetry telem = AltosTelemetry.parse(line);
+                                       if (telem == null)
                                                break;
-                                       if (records.isEmpty()) {
-                                               current_tick = record.tick;
-                                       } else {
-                                               int tick = record.tick;
-                                               while (tick < current_tick - 0x1000)
-                                                       tick += 0x10000;
-                                               current_tick = tick;
-                                               record.tick = current_tick;
-                                       }
-                                       if (!saw_boost && record.state >= AltosLib.ao_flight_boost)
-                                       {
-                                               saw_boost = true;
-                                               boost_tick = record.tick;
-                                       }
-                                       if (record.acceleration() != AltosRecord.MISSING)
-                                               has_accel = true;
-                                       if (record.gps != null)
-                                               has_gps = true;
-                                       if (record.main_voltage() != AltosRecord.MISSING)
-                                               has_ignite = true;
-                                       if (previous != null && previous.tick != record.tick)
-                                               records.add(previous);
-                                       previous = record;
+                                       add(telem);
                                } catch (ParseException pe) {
                                        System.out.printf("parse exception %s\n", pe.getMessage());
                                } catch (AltosCRCException ce) {
@@ -84,26 +103,5 @@ public class AltosTelemetryIterable extends AltosRecordIterable {
                } catch (IOException io) {
                        System.out.printf("io exception\n");
                }
-
-               if (previous != null)
-                       records.add(previous);
-
-               /* Adjust all tick counts to match expected eeprom values,
-                * which starts with a 16-bit tick count 16 samples before boost
-                */
-
-               int tick_adjust = (boost_tick - 16) & 0xffff0000;
-               for (AltosRecord r : this)
-                       r.tick -= tick_adjust;
-               boost_tick -= tick_adjust;
-
-               /* adjust all tick counts to be relative to boost time */
-               for (AltosRecord r : this)
-                       r.time = (r.tick - boost_tick) / 100.0;
-
-               try {
-                       input.close();
-               } catch (IOException ie) {
-               }
        }
 }
diff --git a/altoslib/AltosTelemetryLegacy.java b/altoslib/AltosTelemetryLegacy.java
new file mode 100644 (file)
index 0000000..132b9e8
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * 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; 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+import java.text.*;
+
+/*
+ * Telemetry data contents
+ */
+
+
+/*
+ * The packet format is a simple hex dump of the raw telemetry frame.
+ * It starts with 'TELEM', then contains hex digits with a checksum as the last
+ * byte on the line.
+ *
+ * Version 4 is a replacement with consistent syntax. Each telemetry line
+ * contains a sequence of space-separated names and values, the values are
+ * either integers or strings. The names are all unique. All values are
+ * optional
+ *
+ * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944
+ *   r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764
+ *   a_s 0 a_b 26439 g_s u g_n 0 s_n 0
+ *
+ * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788
+ *   r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0
+ *
+ * General header fields
+ *
+ *     Name            Value
+ *
+ *     VERSION         Telemetry version number (4 or more). Must be first.
+ *     c               Callsign (string, no spaces allowed)
+ *     n               Flight unit serial number (integer)
+ *     f               Flight number (integer)
+ *     r               Packet RSSI value (integer)
+ *     s               Flight computer state (string, no spaces allowed)
+ *     t               Flight computer clock (integer in centiseconds)
+ *
+ * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports
+ * in 1/2dB increments while this protocol provides only integers. So,
+ * the syntax didn't change just the interpretation of the RSSI
+ * values.
+ *
+ * Version 2 of the telemetry data stream is a bit of a mess, with no
+ * consistent formatting. In particular, the GPS data is formatted for
+ * viewing instead of parsing.  However, the key feature is that every
+ * telemetry line contains all of the information necessary to
+ * describe the current rocket state, including the calibration values
+ * for accelerometer and barometer.
+ *
+ * GPS unlocked:
+ *
+ * VERSION 2 CALL KB0G SERIAL  51 FLIGHT     2 RSSI  -68 STATUS ff STATE     pad  1001 \
+ *    a: 16032 p: 21232 t: 20284 v: 25160 d:   204 m:   204 fa: 16038 ga: 16032 fv:       0 \
+ *    fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS  0 sat unlocked SAT 1   15  30
+ *
+ * GPS locked:
+ *
+ * VERSION 2 CALL KB0G SERIAL  51 FLIGHT     2 RSSI  -71 STATUS ff STATE     pad  2504 \
+ *     a: 16028 p: 21220 t: 20360 v: 25004 d:   208 m:   200 fa: 16031 ga: 16032 fv:     330 \
+ *     fp: 21231 gp: 21230 a+: 16049 a-: 16304 \
+ *     GPS  9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W  1790m  \
+ *     0.00m/s(H) 0°     0.00m/s(V) 1.0(hdop)     0(herr)     0(verr) \
+ *     SAT 10   29  30  24  28   5  25  21  20  15  33   1  23  30  24  18  26  10  29   2  26
+ *
+ */
+
+public class AltosTelemetryLegacy extends AltosTelemetry {
+       /*
+        * General header fields
+        *
+        *      Name            Value
+        *
+        *      VERSION         Telemetry version number (4 or more). Must be first.
+        *      c               Callsign (string, no spaces allowed)
+        *      n               Flight unit serial number (integer)
+        *      f               Flight number (integer)
+        *      r               Packet RSSI value (integer)
+        *      s               Flight computer state (string, no spaces allowed)
+        *      t               Flight computer clock (integer in centiseconds)
+        */
+
+       final static String AO_TELEM_VERSION    = "VERSION";
+       final static String AO_TELEM_CALL       = "c";
+       final static String AO_TELEM_SERIAL     = "n";
+       final static String AO_TELEM_FLIGHT     = "f";
+       final static String AO_TELEM_RSSI       = "r";
+       final static String AO_TELEM_STATE      = "s";
+       final static String AO_TELEM_TICK       = "t";
+
+       /*
+        * Raw sensor values
+        *
+        *      Name            Value
+        *      r_a             Accelerometer reading (integer)
+        *      r_b             Barometer reading (integer)
+        *      r_t             Thermometer reading (integer)
+        *      r_v             Battery reading (integer)
+        *      r_d             Drogue continuity (integer)
+        *      r_m             Main continuity (integer)
+        */
+
+       final static String AO_TELEM_RAW_ACCEL  = "r_a";
+       final static String AO_TELEM_RAW_BARO   = "r_b";
+       final static String AO_TELEM_RAW_THERMO = "r_t";
+       final static String AO_TELEM_RAW_BATT   = "r_v";
+       final static String AO_TELEM_RAW_DROGUE = "r_d";
+       final static String AO_TELEM_RAW_MAIN   = "r_m";
+
+       /*
+        * Sensor calibration values
+        *
+        *      Name            Value
+        *      c_a             Ground accelerometer reading (integer)
+        *      c_b             Ground barometer reading (integer)
+        *      c_p             Accelerometer reading for +1g
+        *      c_m             Accelerometer reading for -1g
+        */
+
+       final static String AO_TELEM_CAL_ACCEL_GROUND   = "c_a";
+       final static String AO_TELEM_CAL_BARO_GROUND    = "c_b";
+       final static String AO_TELEM_CAL_ACCEL_PLUS     = "c_p";
+       final static String AO_TELEM_CAL_ACCEL_MINUS    = "c_m";
+
+       /*
+        * Kalman state values
+        *
+        *      Name            Value
+        *      k_h             Height above pad (integer, meters)
+        *      k_s             Vertical speeed (integer, m/s * 16)
+        *      k_a             Vertical acceleration (integer, m/s² * 16)
+        */
+
+       final static String AO_TELEM_KALMAN_HEIGHT      = "k_h";
+       final static String AO_TELEM_KALMAN_SPEED       = "k_s";
+       final static String AO_TELEM_KALMAN_ACCEL       = "k_a";
+
+       /*
+        * Ad-hoc flight values
+        *
+        *      Name            Value
+        *      a_a             Acceleration (integer, sensor units)
+        *      a_s             Speed (integer, integrated acceleration value)
+        *      a_b             Barometer reading (integer, sensor units)
+        */
+
+       final static String AO_TELEM_ADHOC_ACCEL        = "a_a";
+       final static String AO_TELEM_ADHOC_SPEED        = "a_s";
+       final static String AO_TELEM_ADHOC_BARO         = "a_b";
+
+       /*
+        * GPS values
+        *
+        *      Name            Value
+        *      g_s             GPS state (string):
+        *                              l       locked
+        *                              u       unlocked
+        *                              e       error (missing or broken)
+        *      g_n             Number of sats used in solution
+        *      g_ns            Latitude (degrees * 10e7)
+        *      g_ew            Longitude (degrees * 10e7)
+        *      g_a             Altitude (integer meters)
+        *      g_Y             GPS year (integer)
+        *      g_M             GPS month (integer - 1-12)
+        *      g_D             GPS day (integer - 1-31)
+        *      g_h             GPS hour (integer - 0-23)
+        *      g_m             GPS minute (integer - 0-59)
+        *      g_s             GPS second (integer - 0-59)
+        *      g_v             GPS vertical speed (integer, cm/sec)
+        *      g_s             GPS horizontal speed (integer, cm/sec)
+        *      g_c             GPS course (integer, 0-359)
+        *      g_hd            GPS hdop (integer * 10)
+        *      g_vd            GPS vdop (integer * 10)
+        *      g_he            GPS h error (integer)
+        *      g_ve            GPS v error (integer)
+        */
+
+       final static String AO_TELEM_GPS_STATE                  = "g";
+       final static String AO_TELEM_GPS_STATE_LOCKED           = "l";
+       final static String AO_TELEM_GPS_STATE_UNLOCKED         = "u";
+       final static String AO_TELEM_GPS_STATE_ERROR            = "e";
+       final static String AO_TELEM_GPS_NUM_SAT                = "g_n";
+       final static String AO_TELEM_GPS_LATITUDE               = "g_ns";
+       final static String AO_TELEM_GPS_LONGITUDE              = "g_ew";
+       final static String AO_TELEM_GPS_ALTITUDE               = "g_a";
+       final static String AO_TELEM_GPS_YEAR                   = "g_Y";
+       final static String AO_TELEM_GPS_MONTH                  = "g_M";
+       final static String AO_TELEM_GPS_DAY                    = "g_D";
+       final static String AO_TELEM_GPS_HOUR                   = "g_h";
+       final static String AO_TELEM_GPS_MINUTE                 = "g_m";
+       final static String AO_TELEM_GPS_SECOND                 = "g_s";
+       final static String AO_TELEM_GPS_VERTICAL_SPEED         = "g_v";
+       final static String AO_TELEM_GPS_HORIZONTAL_SPEED       = "g_g";
+       final static String AO_TELEM_GPS_COURSE                 = "g_c";
+       final static String AO_TELEM_GPS_HDOP                   = "g_hd";
+       final static String AO_TELEM_GPS_VDOP                   = "g_vd";
+       final static String AO_TELEM_GPS_HERROR                 = "g_he";
+       final static String AO_TELEM_GPS_VERROR                 = "g_ve";
+
+       /*
+        * GPS satellite values
+        *
+        *      Name            Value
+        *      s_n             Number of satellites reported (integer)
+        *      s_v0            Space vehicle ID (integer) for report 0
+        *      s_c0            C/N0 number (integer) for report 0
+        *      s_v1            Space vehicle ID (integer) for report 1
+        *      s_c1            C/N0 number (integer) for report 1
+        *      ...
+        */
+
+       final static String AO_TELEM_SAT_NUM    = "s_n";
+       final static String AO_TELEM_SAT_SVID   = "s_v";
+       final static String AO_TELEM_SAT_C_N_0  = "s_c";
+
+       public int      version;
+       public String   callsign;
+       public int      flight;
+       public int      state;
+
+       public AltosGPS gps;
+       public int      gps_sequence;
+
+       /* Telemetry sources have these values recorded from the flight computer */
+       public double   kalman_height;
+       public double   kalman_speed;
+       public double   kalman_acceleration;
+
+       /* Sensor values */
+       public int      accel;
+       public int      pres;
+       public int      temp;
+       public int      batt;
+       public int      apogee;
+       public int      main;
+
+       public int      ground_accel;
+       public int      ground_pres;
+       public int      accel_plus_g;
+       public int      accel_minus_g;
+
+       public int      flight_accel;
+       public int      flight_vel;
+       public int      flight_pres;
+
+       private void parse_v4(String[] words, int i) throws ParseException {
+               AltosTelemetryMap       map = new AltosTelemetryMap(words, i);
+
+               callsign = map.get_string(AO_TELEM_CALL, "N0CALL");
+               serial = map.get_int(AO_TELEM_SERIAL, AltosLib.MISSING);
+               flight = map.get_int(AO_TELEM_FLIGHT, AltosLib.MISSING);
+               rssi = map.get_int(AO_TELEM_RSSI, AltosLib.MISSING);
+               state = AltosLib.state(map.get_string(AO_TELEM_STATE, "invalid"));
+               tick = map.get_int(AO_TELEM_TICK, 0);
+
+               /* raw sensor values */
+               accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosLib.MISSING);
+               pres = map.get_int(AO_TELEM_RAW_BARO, AltosLib.MISSING);
+               temp = map.get_int(AO_TELEM_RAW_THERMO, AltosLib.MISSING);
+               batt = map.get_int(AO_TELEM_RAW_BATT, AltosLib.MISSING);
+               apogee = map.get_int(AO_TELEM_RAW_DROGUE, AltosLib.MISSING);
+               main = map.get_int(AO_TELEM_RAW_MAIN, AltosLib.MISSING);
+
+               /* sensor calibration information */
+               ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosLib.MISSING);
+               ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosLib.MISSING);
+               accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosLib.MISSING);
+               accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosLib.MISSING);
+
+               /* flight computer values */
+               kalman_acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosLib.MISSING, 1/16.0);
+               kalman_speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosLib.MISSING, 1/16.0);
+               kalman_height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosLib.MISSING);
+
+               flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosLib.MISSING);
+               flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosLib.MISSING);
+               flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosLib.MISSING);
+
+               if (map.has(AO_TELEM_GPS_STATE))
+                       gps = new AltosGPS(map);
+               else
+                       gps = null;
+       }
+
+       private void parse_legacy(String[] words, int i) throws ParseException {
+
+               AltosParse.word (words[i++], "CALL");
+               callsign = words[i++];
+
+               AltosParse.word (words[i++], "SERIAL");
+               serial = AltosParse.parse_int(words[i++]);
+
+               if (version >= 2) {
+                       AltosParse.word (words[i++], "FLIGHT");
+                       flight = AltosParse.parse_int(words[i++]);
+               } else
+                       flight = 0;
+
+               AltosParse.word(words[i++], "RSSI");
+               rssi = AltosParse.parse_int(words[i++]);
+
+               /* Older telemetry data had mis-computed RSSI value */
+               if (version <= 2)
+                       rssi = (rssi + 74) / 2 - 74;
+
+               AltosParse.word(words[i++], "STATUS");
+               status = AltosParse.parse_hex(words[i++]);
+
+               AltosParse.word(words[i++], "STATE");
+               state = AltosLib.state(words[i++]);
+
+               tick = AltosParse.parse_int(words[i++]);
+
+               AltosParse.word(words[i++], "a:");
+               accel = AltosParse.parse_int(words[i++]);
+
+               AltosParse.word(words[i++], "p:");
+               pres = AltosParse.parse_int(words[i++]);
+
+               AltosParse.word(words[i++], "t:");
+               temp = AltosParse.parse_int(words[i++]);
+
+               AltosParse.word(words[i++], "v:");
+               batt = AltosParse.parse_int(words[i++]);
+
+               AltosParse.word(words[i++], "d:");
+               apogee = AltosParse.parse_int(words[i++]);
+
+               AltosParse.word(words[i++], "m:");
+               main = AltosParse.parse_int(words[i++]);
+
+               AltosParse.word(words[i++], "fa:");
+               flight_accel = AltosParse.parse_int(words[i++]);
+
+               AltosParse.word(words[i++], "ga:");
+               ground_accel = AltosParse.parse_int(words[i++]);
+
+               AltosParse.word(words[i++], "fv:");
+               flight_vel = AltosParse.parse_int(words[i++]);
+
+               AltosParse.word(words[i++], "fp:");
+               flight_pres = AltosParse.parse_int(words[i++]);
+
+               /* Old TeleDongle code with kalman-reporting TeleMetrum code */
+               if ((flight_vel & 0xffff0000) == 0x80000000) {
+                       kalman_speed = ((short) flight_vel) / 16.0;
+                       kalman_acceleration = flight_accel / 16.0;
+                       kalman_height = flight_pres;
+                       flight_vel = AltosLib.MISSING;
+                       flight_pres = AltosLib.MISSING;
+                       flight_accel = AltosLib.MISSING;
+               } else {
+                       kalman_speed = AltosLib.MISSING;
+                       kalman_acceleration = AltosLib.MISSING;
+                       kalman_height = AltosLib.MISSING;
+               }
+
+               AltosParse.word(words[i++], "gp:");
+               ground_pres = AltosParse.parse_int(words[i++]);
+
+               if (version >= 1) {
+                       AltosParse.word(words[i++], "a+:");
+                       accel_plus_g = AltosParse.parse_int(words[i++]);
+
+                       AltosParse.word(words[i++], "a-:");
+                       accel_minus_g = AltosParse.parse_int(words[i++]);
+               } else {
+                       accel_plus_g = ground_accel;
+                       accel_minus_g = ground_accel + 530;
+               }
+
+               gps = new AltosGPS(words, i, version);
+               gps_sequence++;
+       }
+
+       public AltosTelemetryLegacy(String line) throws ParseException, AltosCRCException {
+               String[] words = line.split("\\s+");
+               int     i = 0;
+
+               if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
+                       i += 2;
+                       AltosParse.word(words[i++], "RSSI");
+                       rssi = AltosParse.parse_int(words[i++]);
+                       throw new AltosCRCException(rssi);
+               }
+               if (words[i].equals("CALL")) {
+                       version = 0;
+               } else {
+                       AltosParse.word (words[i++], "VERSION");
+                       version = AltosParse.parse_int(words[i++]);
+               }
+
+               if (version < 4)
+                       parse_legacy(words, i);
+               else
+                       parse_v4(words, i);
+       }
+
+       /*
+        * Given a hex dump of a legacy telemetry line, construct an AltosRecordTM from that
+        */
+
+       int[]   bytes;
+       int     adjust;
+
+       /*
+       private int int8(int i) {
+               return AltosLib.int8(bytes, i + 1 + adjust);
+       }
+       */
+       private int uint8(int i) {
+               return AltosLib.uint8(bytes, i + 1 + adjust);
+       }
+       private int int16(int i) {
+               return AltosLib.int16(bytes, i + 1 + adjust);
+       }
+       private int uint16(int i) {
+               return AltosLib.uint16(bytes, i + 1 + adjust);
+       }
+       private int uint32(int i) {
+               return AltosLib.uint32(bytes, i + 1 + adjust);
+       }
+       private String string(int i, int l) {
+               return AltosLib.string(bytes, i + 1 + adjust, l);
+       }
+
+       static final int AO_GPS_NUM_SAT_MASK    = (0xf << 0);
+       static final int AO_GPS_NUM_SAT_SHIFT   = (0);
+
+       static final int AO_GPS_VALID           = (1 << 4);
+       static final int AO_GPS_RUNNING         = (1 << 5);
+       static final int AO_GPS_DATE_VALID      = (1 << 6);
+       static final int AO_GPS_COURSE_VALID    = (1 << 7);
+
+       public AltosTelemetryLegacy(int[] in_bytes) {
+               bytes = in_bytes;
+               version = 4;
+               adjust = 0;
+
+               if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) {
+                       serial = uint8(0);
+                       adjust = -1;
+               } else
+                       serial = uint16(0);
+
+               callsign = string(62, 8);
+               flight = uint16(2);
+               state = uint8(4);
+               tick = uint16(21);
+               accel = int16(23);
+               pres = int16(25);
+               temp = int16(27);
+               batt = int16(29);
+               apogee = int16(31);
+               main = int16(33);
+               
+               ground_accel = int16(7);
+               ground_pres = int16(15);
+               accel_plus_g = int16(17);
+               accel_minus_g = int16(19);
+
+               if (uint16(11) == 0x8000) {
+                       kalman_acceleration = int16(5);
+                       kalman_speed = int16(9);
+                       kalman_height = int16(13);
+                       flight_accel = AltosLib.MISSING;
+                       flight_vel = AltosLib.MISSING;
+                       flight_pres = AltosLib.MISSING;
+               } else {
+                       flight_accel = int16(5);
+                       flight_vel = uint32(9);
+                       flight_pres = int16(13);
+                       kalman_acceleration = AltosLib.MISSING;
+                       kalman_speed = AltosLib.MISSING;
+                       kalman_height = AltosLib.MISSING;
+               }
+
+               gps = null;
+
+               int gps_flags = uint8(41);
+
+               if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) {
+                       gps = new AltosGPS();
+                       gps_sequence++;
+
+                       gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK);
+                       gps.locked = (gps_flags & AO_GPS_VALID) != 0;
+                       gps.connected = true;
+                       gps.lat = uint32(42) / 1.0e7;
+                       gps.lon = uint32(46) / 1.0e7;
+                       gps.alt = int16(50);
+                       gps.ground_speed = uint16(52) / 100.0;
+                       gps.course = uint8(54) * 2;
+                       gps.hdop = uint8(55) / 5.0;
+                       gps.h_error = uint16(58);
+                       gps.v_error = uint16(60);
+
+                       int     n_tracking_reported = uint8(70);
+                       if (n_tracking_reported > 12)
+                               n_tracking_reported = 12;
+                       int     n_tracking_actual = 0;
+                       for (int i = 0; i < n_tracking_reported; i++) {
+                               if (uint8(71 + i*2) != 0)
+                                       n_tracking_actual++;
+                       }
+                       if (n_tracking_actual > 0) {
+                               gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual];
+
+                               n_tracking_actual = 0;
+                               for (int i = 0; i < n_tracking_reported; i++) {
+                                       int     svid = uint8(71 + i*2);
+                                       int     c_n0 = uint8(72 + i*2);
+                                       if (svid != 0)
+                                               gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0);
+                               }
+                       }
+               }
+       }
+
+       public void update_state(AltosState state) {
+               state.set_tick(tick);
+               state.set_state(this.state);
+               state.set_flight(flight);
+               state.set_serial(serial);
+               state.set_rssi(rssi, status);
+
+               state.set_pressure(AltosConvert.barometer_to_pressure(pres));
+               state.set_accel_g(accel_plus_g, accel_minus_g);
+               state.set_accel(accel);
+               if (kalman_height != AltosLib.MISSING)
+                       state.set_kalman(kalman_height, kalman_speed, kalman_acceleration);
+               state.set_temperature(AltosConvert.thermometer_to_temperature(temp));
+               state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(batt));
+               state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(apogee));
+               state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(main));
+               if (gps != null)
+                       state.set_gps(gps, gps_sequence);
+       }
+}
diff --git a/altoslib/AltosTelemetryLocation.java b/altoslib/AltosTelemetryLocation.java
new file mode 100644 (file)
index 0000000..6e88091
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetryLocation extends AltosTelemetryStandard {
+       int     flags;
+       int     altitude;
+       int     latitude;
+       int     longitude;
+       int     year;
+       int     month;
+       int     day;
+       int     hour;
+       int     minute;
+       int     second;
+       int     pdop;
+       int     hdop;
+       int     vdop;
+       int     mode;
+       int     ground_speed;
+       int     climb_rate;
+       int     course;
+
+       public AltosTelemetryLocation(int[] bytes) {
+               super(bytes);
+
+               flags          = uint8(5);
+               altitude       = int16(6);
+               latitude       = uint32(8);
+               longitude      = uint32(12);
+               year           = uint8(16);
+               month          = uint8(17);
+               day            = uint8(18);
+               hour           = uint8(19);
+               minute         = uint8(20);
+               second         = uint8(21);
+               pdop           = uint8(22);
+               hdop           = uint8(23);
+               vdop           = uint8(24);
+               mode           = uint8(25);
+               ground_speed   = uint16(26);
+               climb_rate     = int16(28);
+               course         = uint8(30);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+               AltosGPS        gps = state.make_temp_gps(false);
+
+               gps.nsat = flags & 0xf;
+               gps.locked = (flags & (1 << 4)) != 0;
+               gps.connected = (flags & (1 << 5)) != 0;
+
+               if (gps.locked) {
+                       gps.lat = latitude * 1.0e-7;
+                       gps.lon = longitude * 1.0e-7;
+                       gps.alt = altitude;
+                       gps.year = 2000 + year;
+                       gps.month = month;
+                       gps.day = day;
+                       gps.hour = hour;
+                       gps.minute = minute;
+                       gps.second = second;
+                       gps.ground_speed = ground_speed * 1.0e-2;
+                       gps.course = course * 2;
+                       gps.climb_rate = climb_rate * 1.0e-2;
+                       gps.hdop = hdop;
+                       gps.vdop = vdop;
+               }
+               state.set_temp_gps();
+       }
+}
index 7cca98b09acc39e46c9cf0091434c679541bbcb6..37883a1c47e838b19cf5e562eed21e220142edef 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 import java.text.*;
 import java.util.HashMap;
 
diff --git a/altoslib/AltosTelemetryMegaData.java b/altoslib/AltosTelemetryMegaData.java
new file mode 100644 (file)
index 0000000..f5cc01d
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosTelemetryMegaData extends AltosTelemetryStandard {
+       int     state;
+       
+       int     v_batt;
+       int     v_pyro;
+       int     sense[];
+
+       int     ground_pres;
+       int     ground_accel;
+       int     accel_plus_g;
+       int     accel_minus_g;
+
+       int     acceleration;
+       int     speed;
+       int     height;
+
+       public AltosTelemetryMegaData(int[] bytes) {
+               super(bytes);
+
+               state = int8(5);
+
+               v_batt = int16(6);
+               v_pyro = int16(8);
+
+               sense = new int[6];     
+
+               for (int i = 0; i < 6; i++) {
+                       sense[i] = int8(10 + i) << 4;
+                       sense[i] |= sense[i] >> 8;
+               }
+
+               ground_pres = int32(16);
+               ground_accel = int16(20);
+               accel_plus_g = int16(22);
+               accel_minus_g = int16(24);
+
+               acceleration = int16(26);
+               speed = int16(28);
+               height = int16(30);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               state.set_state(this.state);
+                       
+               state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt));
+               state.set_pyro_voltage(AltosConvert.mega_pyro_voltage(v_pyro));
+
+               state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense[4]));
+               state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense[5]));
+
+               double voltages[] = new double[4];
+               for (int i = 0; i < 4; i++)
+                       voltages[i] = AltosConvert.mega_pyro_voltage(sense[i]);
+
+               state.set_ignitor_voltage(voltages);
+
+               state.set_ground_accel(ground_accel);
+               state.set_ground_pressure(ground_pres);
+               state.set_accel_g(accel_plus_g, accel_minus_g);
+
+               state.set_kalman(height, speed/16.0, acceleration / 16.0);
+       }
+}
+
diff --git a/altoslib/AltosTelemetryMegaSensor.java b/altoslib/AltosTelemetryMegaSensor.java
new file mode 100644 (file)
index 0000000..23b67af
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosTelemetryMegaSensor extends AltosTelemetryStandard {
+       int     accel;
+       int     pres;
+       int     temp;
+
+       int     accel_x;
+       int     accel_y;
+       int     accel_z;
+
+       int     gyro_x;
+       int     gyro_y;
+       int     gyro_z;
+
+       int     mag_x;
+       int     mag_y;
+       int     mag_z;
+
+       public AltosTelemetryMegaSensor(int[] bytes) {
+               super(bytes);
+
+               accel         = int16(6);
+               pres          = int32(8);
+               temp          = int16(12);
+
+               accel_x       = int16(14);
+               accel_y       = int16(16);
+               accel_z       = int16(18);
+
+               gyro_x        = int16(20);
+               gyro_y        = int16(22);
+               gyro_z        = int16(24);
+
+               mag_x         = int16(26);
+               mag_y         = int16(28);
+               mag_z         = int16(30);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               state.set_accel(accel);
+               state.set_pressure(pres);
+               state.set_temperature(temp / 100.0);
+
+               AltosIMU imu = new AltosIMU();
+               
+               imu.accel_x = accel_x;
+               imu.accel_y = accel_y;
+               imu.accel_z = accel_z;
+
+               imu.gyro_x = gyro_x;
+               imu.gyro_y = gyro_y;
+               imu.gyro_z = gyro_z;
+
+               state.imu = imu;
+
+               AltosMag mag = new AltosMag();
+
+               mag.x = mag_x;
+               mag.y = mag_y;
+               mag.z = mag_z;
+
+               state.mag = mag;
+       }
+}
diff --git a/altoslib/AltosTelemetryMetrumData.java b/altoslib/AltosTelemetryMetrumData.java
new file mode 100644 (file)
index 0000000..b623997
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetryMetrumData extends AltosTelemetryStandard {
+
+       int     ground_pres;
+       int     ground_accel;
+       int     accel_plus_g;
+       int     accel_minus_g;
+
+       public AltosTelemetryMetrumData(int[] bytes) {
+               super(bytes);
+
+               ground_pres = int32(8);
+               ground_accel = int16(12);
+               accel_plus_g = int16(14);
+               accel_minus_g = int16(16);
+       }
+
+       public void update_state(AltosState state) {
+               state.set_ground_accel(ground_accel);
+               state.set_accel_g(accel_plus_g, accel_minus_g);
+               state.set_ground_pressure(ground_pres);
+       }
+}
diff --git a/altoslib/AltosTelemetryMetrumSensor.java b/altoslib/AltosTelemetryMetrumSensor.java
new file mode 100644 (file)
index 0000000..fc047af
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetryMetrumSensor extends AltosTelemetryStandard {
+       int     state;
+
+       int     accel;
+       int     pres;
+       int     temp;
+
+       int     acceleration;
+       int     speed;
+       int     height;
+
+       int     v_batt;
+       int     sense_a;
+       int     sense_m;
+
+       public AltosTelemetryMetrumSensor(int[] bytes) {
+               super(bytes);
+
+               state         = int8(5);
+               accel         = int16(6);
+               pres          = int32(8);
+               temp          = int16(12);
+
+               acceleration  = int16(14);
+               speed         = int16(16);
+               height        = int16(18);
+
+               v_batt        = int16(20);
+               sense_a       = int16(22);
+               sense_m       = int16(24);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               state.set_state(this.state);
+
+               state.set_accel(accel);
+               state.set_pressure(pres);
+               state.set_temperature(temp/100.0);
+
+               state.set_kalman(height, speed/16.0, acceleration/16.0);
+
+               state.set_battery_voltage(AltosConvert.mega_battery_voltage(v_batt));
+
+               state.set_apogee_voltage(AltosConvert.mega_pyro_voltage(sense_a));
+               state.set_main_voltage(AltosConvert.mega_pyro_voltage(sense_m));
+       }
+}
diff --git a/altoslib/AltosTelemetryMini.java b/altoslib/AltosTelemetryMini.java
new file mode 100644 (file)
index 0000000..e710946
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+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/AltosTelemetryRaw.java b/altoslib/AltosTelemetryRaw.java
new file mode 100644 (file)
index 0000000..dbe70fe
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosTelemetryRaw extends AltosTelemetryStandard {
+       public AltosTelemetryRaw(int[] bytes) {
+               super(bytes);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+       }
+}
index b4293c7349d2d9fda70bd03942aa91c37e0ac031..eeb35cb51c6579e141678d4c2cce352b9d3eb6d2 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 import java.text.*;
 import java.io.*;
@@ -24,19 +24,23 @@ import java.util.concurrent.*;
 public class AltosTelemetryReader extends AltosFlightReader {
        AltosLink       link;
        AltosLog        log;
-       AltosRecord     previous;
        double          frequency;
        int             telemetry;
+       AltosState      state = null;
 
        LinkedBlockingQueue<AltosLine> telem;
 
-       public AltosRecord read() throws InterruptedException, ParseException, AltosCRCException, IOException {
+       public AltosState read() throws InterruptedException, ParseException, AltosCRCException, IOException {
                AltosLine l = telem.take();
                if (l.line == null)
                        throw new IOException("IO error");
-               AltosRecord     next = AltosTelemetry.parse(l.line, previous);
-               previous = next;
-               return next;
+               AltosTelemetry  telem = AltosTelemetry.parse(l.line);
+               if (state == null)
+                       state = new AltosState();
+               else
+                       state = state.clone();
+               telem.update_state(state);
+               return state;
        }
 
        public void flush() {
@@ -44,14 +48,16 @@ public class AltosTelemetryReader extends AltosFlightReader {
        }
 
        public void reset() {
-               previous = null;
                flush();
        }
 
        public void close(boolean interrupted) {
                link.remove_monitor(telem);
                log.close();
-               link.close();
+               try {
+                       link.close();
+               } catch (InterruptedException ie) {
+               }
        }
 
        public void set_frequency(double in_frequency) throws InterruptedException, TimeoutException {
@@ -80,7 +86,7 @@ public class AltosTelemetryReader extends AltosFlightReader {
                        else
                                return false;
                } catch (InterruptedException ie) {
-                       return true;
+                       return false;
                } catch (TimeoutException te) {
                        return true;
                }
@@ -111,29 +117,27 @@ public class AltosTelemetryReader extends AltosFlightReader {
                return link.has_monitor_battery();
        }
 
-       public double monitor_battery() {
+       public double monitor_battery() throws InterruptedException {
                return link.monitor_battery();
        }
 
        public AltosTelemetryReader (AltosLink in_link)
                throws IOException, InterruptedException, TimeoutException {
                link = in_link;
+               boolean success = false;
                try {
                        log = new AltosLog(link);
                        name = link.name;
-                       previous = null;
                        telem = new LinkedBlockingQueue<AltosLine>();
                        frequency = AltosPreferences.frequency(link.serial);
                        set_frequency(frequency);
                        telemetry = AltosPreferences.telemetry(link.serial);
                        set_telemetry(telemetry);
                        link.add_monitor(telem);
-               } catch (TimeoutException e) {
-                       close(true);
-                       throw(e);
-               } catch (InterruptedException e) {
-                       close(true);
-                       throw(e);
+                       success = true;
+               } finally {
+                       if (!success)
+                               close(true);
                }
        }
 }
diff --git a/altoslib/AltosTelemetryRecord.java b/altoslib/AltosTelemetryRecord.java
deleted file mode 100644 (file)
index fdc3c88..0000000
+++ /dev/null
@@ -1,135 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-import java.text.*;
-
-public abstract class AltosTelemetryRecord {
-
-       long    received_time;
-       abstract public AltosRecord update_state(AltosRecord previous);
-
-       static boolean cksum(int[] bytes) {
-               int     sum = 0x5a;
-               for (int i = 1; i < bytes.length - 1; i++)
-                       sum += bytes[i];
-               sum &= 0xff;
-               return sum == bytes[bytes.length - 1];
-       }
-
-       final static int PKT_APPEND_STATUS_1_CRC_OK             = (1 << 7);
-       final static int PKT_APPEND_STATUS_1_LQI_MASK           = (0x7f);
-       final static int PKT_APPEND_STATUS_1_LQI_SHIFT          = 0;
-
-       final static int packet_type_TM_sensor = 0x01;
-       final static int packet_type_Tm_sensor = 0x02;
-       final static int packet_type_Tn_sensor = 0x03;
-       final static int packet_type_configuration = 0x04;
-       final static int packet_type_location = 0x05;
-       final static int packet_type_satellite = 0x06;
-       final static int packet_type_companion = 0x07;
-       final static int packet_type_MM_sensor = 0x08;
-       final static int packet_type_MM_data = 0x09;
-       
-       static AltosTelemetryRecord parse_hex(String hex)  throws ParseException, AltosCRCException {
-               AltosTelemetryRecord    r;
-
-               int[] bytes;
-               try {
-                       bytes = AltosLib.hexbytes(hex);
-               } catch (NumberFormatException ne) {
-                       throw new ParseException(ne.getMessage(), 0);
-               }
-
-               /* one for length, one for checksum */
-               if (bytes[0] != bytes.length - 2)
-                       throw new ParseException(String.format("invalid length %d != %d\n",
-                                                              bytes[0],
-                                                              bytes.length - 2), 0);
-               if (!cksum(bytes))
-                       throw new ParseException(String.format("invalid line \"%s\"", hex), 0);
-
-               int     rssi = AltosLib.int8(bytes, bytes.length - 3) / 2 - 74;
-               int     status = AltosLib.uint8(bytes, bytes.length - 2);
-
-               if ((status & PKT_APPEND_STATUS_1_CRC_OK) == 0)
-                       throw new AltosCRCException(rssi);
-
-               /* length, data ..., rssi, status, checksum -- 4 bytes extra */
-               switch (bytes.length) {
-               case AltosLib.ao_telemetry_standard_len + 4:
-                       int     type = AltosLib.uint8(bytes, 4 + 1);
-                       switch (type) {
-                       case packet_type_TM_sensor:
-                       case packet_type_Tm_sensor:
-                       case packet_type_Tn_sensor:
-                               r = new AltosTelemetryRecordSensor(bytes, rssi);
-                               break;
-                       case packet_type_configuration:
-                               r = new AltosTelemetryRecordConfiguration(bytes, rssi);
-                               break;
-                       case packet_type_location:
-                               r = new AltosTelemetryRecordLocation(bytes, rssi);
-                               break;
-                       case packet_type_satellite:
-                               r = new AltosTelemetryRecordSatellite(bytes, rssi);
-                               break;
-                       case packet_type_companion:
-                               r = new AltosTelemetryRecordCompanion(bytes, rssi);
-                               break;
-                       case packet_type_MM_sensor:
-                               r = new AltosTelemetryRecordMegaSensor(bytes, rssi);
-                               break;
-                       case packet_type_MM_data:
-                               r = new AltosTelemetryRecordMegaData(bytes, rssi);
-                               break;
-                       default:
-                               r = new AltosTelemetryRecordRaw(bytes, rssi);
-                               break;
-                       }
-                       break;
-               case AltosLib.ao_telemetry_0_9_len + 4:
-                       r = new AltosTelemetryRecordLegacy(bytes, rssi, status);
-                       break;
-               case AltosLib.ao_telemetry_0_8_len + 4:
-                       r = new AltosTelemetryRecordLegacy(bytes, rssi, status);
-                       break;
-               default:
-                       throw new ParseException(String.format("Invalid packet length %d", bytes.length), 0);
-               }
-               r.received_time = System.currentTimeMillis();
-               return r;
-       }
-
-       public static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException {
-               AltosTelemetryRecord    r;
-
-               String[] word = line.split("\\s+");
-               int i =0;
-               if (word[i].equals("CRC") && word[i+1].equals("INVALID")) {
-                       i += 2;
-                       AltosParse.word(word[i++], "RSSI");
-                       throw new AltosCRCException(AltosParse.parse_int(word[i++]));
-               }
-
-               if (word[i].equals("TELEM"))
-                       r = parse_hex(word[i+1]);
-               else
-                       r = new AltosTelemetryRecordLegacy(line);
-               return r;
-       }
-}
diff --git a/altoslib/AltosTelemetryRecordCompanion.java b/altoslib/AltosTelemetryRecordCompanion.java
deleted file mode 100644 (file)
index 2231df1..0000000
+++ /dev/null
@@ -1,52 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosTelemetryRecordCompanion extends AltosTelemetryRecordRaw {
-
-       AltosRecordCompanion    companion;
-
-       public AltosTelemetryRecordCompanion(int[] in_bytes, int rssi) {
-               super(in_bytes, rssi);
-
-               int     off = 0;
-               if (uint8(6) == 0)
-                       off = 1;
-               int channels = uint8(7+off);
-
-               if (off != 0 && channels >= 12)
-                       channels = 11;
-
-               companion = new AltosRecordCompanion(channels);
-               companion.tick          = tick;
-               companion.board_id      = uint8(5);
-               companion.update_period = uint8(6+off);
-               for (int i = 0; i < companion.companion_data.length; i++)
-                       companion.companion_data[i] = uint16(8 + off + i * 2);
-       }
-
-       public AltosRecord update_state(AltosRecord previous) {
-               AltosRecord     next = super.update_state(previous);
-
-               next.companion = companion;
-               next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt;
-
-               companion.tick = tick;
-               return next;
-       }
-}
diff --git a/altoslib/AltosTelemetryRecordConfiguration.java b/altoslib/AltosTelemetryRecordConfiguration.java
deleted file mode 100644 (file)
index 47fc348..0000000
+++ /dev/null
@@ -1,64 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-
-public class AltosTelemetryRecordConfiguration extends AltosTelemetryRecordRaw {
-       int     device_type;
-       int     flight;
-       int     config_major;
-       int     config_minor;
-       int     apogee_delay;
-       int     main_deploy;
-       int     flight_log_max;
-       String  callsign;
-       String  version;
-
-       public AltosTelemetryRecordConfiguration(int[] in_bytes, int rssi) {
-               super(in_bytes, rssi);
-
-               device_type    = uint8(5);
-               flight         = uint16(6);
-               config_major   = uint8(8);
-               config_minor   = uint8(9);
-               apogee_delay   = uint16(10);
-               main_deploy    = uint16(12);
-               flight_log_max = uint16(14);
-               callsign       = string(16, 8);
-               version        = string(24, 8);
-       }
-
-       public AltosRecord update_state(AltosRecord previous) {
-               AltosRecord     next = super.update_state(previous);
-
-               next.device_type = device_type;
-               next.flight = flight;
-               next.config_major = config_major;
-               next.config_minor = config_minor;
-               next.apogee_delay = apogee_delay;
-               next.main_deploy = main_deploy;
-               next.flight_log_max = flight_log_max;
-
-               next.callsign = callsign;
-               next.firmware_version = version;
-
-               next.seen |= AltosRecord.seen_deploy | AltosRecord.seen_flight;
-
-               return next;
-       }
-}
diff --git a/altoslib/AltosTelemetryRecordGeneral.java b/altoslib/AltosTelemetryRecordGeneral.java
deleted file mode 100644 (file)
index 08cd606..0000000
+++ /dev/null
@@ -1,41 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.*;
-
-public class AltosTelemetryRecordGeneral {
-
-       static AltosTelemetryRecord parse(String line) throws ParseException, AltosCRCException {
-               AltosTelemetryRecord    r;
-
-               String[] word = line.split("\\s+");
-               int i =0;
-               if (word[i].equals("CRC") && word[i+1].equals("INVALID")) {
-                       i += 2;
-                       AltosParse.word(word[i++], "RSSI");
-                       throw new AltosCRCException(AltosParse.parse_int(word[i++]));
-               }
-
-               if (word[i].equals("TELEM"))
-                       r = AltosTelemetryRecordRaw.parse(word[i+1]);
-               else
-                       r = new AltosTelemetryRecordLegacy(line);
-               return r;
-       }
-}
diff --git a/altoslib/AltosTelemetryRecordLegacy.java b/altoslib/AltosTelemetryRecordLegacy.java
deleted file mode 100644 (file)
index f2d3f86..0000000
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * 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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-import java.text.*;
-
-/*
- * Telemetry data contents
- */
-
-
-/*
- * The packet format is a simple hex dump of the raw telemetry frame.
- * It starts with 'TELEM', then contains hex digits with a checksum as the last
- * byte on the line.
- *
- * Version 4 is a replacement with consistent syntax. Each telemetry line
- * contains a sequence of space-separated names and values, the values are
- * either integers or strings. The names are all unique. All values are
- * optional
- *
- * VERSION 4 c KD7SQG n 236 f 18 r -25 s pad t 513 r_a 15756 r_b 26444 r_t 20944
- *   r_v 26640 r_d 512 r_m 208 c_a 15775 c_b 26439 c_p 15749 c_m 16281 a_a 15764
- *   a_s 0 a_b 26439 g_s u g_n 0 s_n 0
- *
- * VERSION 4 c KD7SQG n 19 f 0 r -23 s pad t 513 r_b 26372 r_t 21292 r_v 26788
- *   r_d 136 r_m 140 c_b 26370 k_h 0 k_s 0 k_a 0
- *
- * General header fields
- *
- *     Name            Value
- *
- *     VERSION         Telemetry version number (4 or more). Must be first.
- *     c               Callsign (string, no spaces allowed)
- *     n               Flight unit serial number (integer)
- *     f               Flight number (integer)
- *     r               Packet RSSI value (integer)
- *     s               Flight computer state (string, no spaces allowed)
- *     t               Flight computer clock (integer in centiseconds)
- *
- * Version 3 is Version 2 with fixed RSSI numbers -- the radio reports
- * in 1/2dB increments while this protocol provides only integers. So,
- * the syntax didn't change just the interpretation of the RSSI
- * values.
- *
- * Version 2 of the telemetry data stream is a bit of a mess, with no
- * consistent formatting. In particular, the GPS data is formatted for
- * viewing instead of parsing.  However, the key feature is that every
- * telemetry line contains all of the information necessary to
- * describe the current rocket state, including the calibration values
- * for accelerometer and barometer.
- *
- * GPS unlocked:
- *
- * VERSION 2 CALL KB0G SERIAL  51 FLIGHT     2 RSSI  -68 STATUS ff STATE     pad  1001 \
- *    a: 16032 p: 21232 t: 20284 v: 25160 d:   204 m:   204 fa: 16038 ga: 16032 fv:       0 \
- *    fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS  0 sat unlocked SAT 1   15  30
- *
- * GPS locked:
- *
- * VERSION 2 CALL KB0G SERIAL  51 FLIGHT     2 RSSI  -71 STATUS ff STATE     pad  2504 \
- *     a: 16028 p: 21220 t: 20360 v: 25004 d:   208 m:   200 fa: 16031 ga: 16032 fv:     330 \
- *     fp: 21231 gp: 21230 a+: 16049 a-: 16304 \
- *     GPS  9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W  1790m  \
- *     0.00m/s(H) 0°     0.00m/s(V) 1.0(hdop)     0(herr)     0(verr) \
- *     SAT 10   29  30  24  28   5  25  21  20  15  33   1  23  30  24  18  26  10  29   2  26
- *
- */
-
-public class AltosTelemetryRecordLegacy extends AltosTelemetryRecord {
-       /*
-        * General header fields
-        *
-        *      Name            Value
-        *
-        *      VERSION         Telemetry version number (4 or more). Must be first.
-        *      c               Callsign (string, no spaces allowed)
-        *      n               Flight unit serial number (integer)
-        *      f               Flight number (integer)
-        *      r               Packet RSSI value (integer)
-        *      s               Flight computer state (string, no spaces allowed)
-        *      t               Flight computer clock (integer in centiseconds)
-        */
-
-       final static String AO_TELEM_VERSION    = "VERSION";
-       final static String AO_TELEM_CALL       = "c";
-       final static String AO_TELEM_SERIAL     = "n";
-       final static String AO_TELEM_FLIGHT     = "f";
-       final static String AO_TELEM_RSSI       = "r";
-       final static String AO_TELEM_STATE      = "s";
-       final static String AO_TELEM_TICK       = "t";
-
-       /*
-        * Raw sensor values
-        *
-        *      Name            Value
-        *      r_a             Accelerometer reading (integer)
-        *      r_b             Barometer reading (integer)
-        *      r_t             Thermometer reading (integer)
-        *      r_v             Battery reading (integer)
-        *      r_d             Drogue continuity (integer)
-        *      r_m             Main continuity (integer)
-        */
-
-       final static String AO_TELEM_RAW_ACCEL  = "r_a";
-       final static String AO_TELEM_RAW_BARO   = "r_b";
-       final static String AO_TELEM_RAW_THERMO = "r_t";
-       final static String AO_TELEM_RAW_BATT   = "r_v";
-       final static String AO_TELEM_RAW_DROGUE = "r_d";
-       final static String AO_TELEM_RAW_MAIN   = "r_m";
-
-       /*
-        * Sensor calibration values
-        *
-        *      Name            Value
-        *      c_a             Ground accelerometer reading (integer)
-        *      c_b             Ground barometer reading (integer)
-        *      c_p             Accelerometer reading for +1g
-        *      c_m             Accelerometer reading for -1g
-        */
-
-       final static String AO_TELEM_CAL_ACCEL_GROUND   = "c_a";
-       final static String AO_TELEM_CAL_BARO_GROUND    = "c_b";
-       final static String AO_TELEM_CAL_ACCEL_PLUS     = "c_p";
-       final static String AO_TELEM_CAL_ACCEL_MINUS    = "c_m";
-
-       /*
-        * Kalman state values
-        *
-        *      Name            Value
-        *      k_h             Height above pad (integer, meters)
-        *      k_s             Vertical speeed (integer, m/s * 16)
-        *      k_a             Vertical acceleration (integer, m/s² * 16)
-        */
-
-       final static String AO_TELEM_KALMAN_HEIGHT      = "k_h";
-       final static String AO_TELEM_KALMAN_SPEED       = "k_s";
-       final static String AO_TELEM_KALMAN_ACCEL       = "k_a";
-
-       /*
-        * Ad-hoc flight values
-        *
-        *      Name            Value
-        *      a_a             Acceleration (integer, sensor units)
-        *      a_s             Speed (integer, integrated acceleration value)
-        *      a_b             Barometer reading (integer, sensor units)
-        */
-
-       final static String AO_TELEM_ADHOC_ACCEL        = "a_a";
-       final static String AO_TELEM_ADHOC_SPEED        = "a_s";
-       final static String AO_TELEM_ADHOC_BARO         = "a_b";
-
-       /*
-        * GPS values
-        *
-        *      Name            Value
-        *      g_s             GPS state (string):
-        *                              l       locked
-        *                              u       unlocked
-        *                              e       error (missing or broken)
-        *      g_n             Number of sats used in solution
-        *      g_ns            Latitude (degrees * 10e7)
-        *      g_ew            Longitude (degrees * 10e7)
-        *      g_a             Altitude (integer meters)
-        *      g_Y             GPS year (integer)
-        *      g_M             GPS month (integer - 1-12)
-        *      g_D             GPS day (integer - 1-31)
-        *      g_h             GPS hour (integer - 0-23)
-        *      g_m             GPS minute (integer - 0-59)
-        *      g_s             GPS second (integer - 0-59)
-        *      g_v             GPS vertical speed (integer, cm/sec)
-        *      g_s             GPS horizontal speed (integer, cm/sec)
-        *      g_c             GPS course (integer, 0-359)
-        *      g_hd            GPS hdop (integer * 10)
-        *      g_vd            GPS vdop (integer * 10)
-        *      g_he            GPS h error (integer)
-        *      g_ve            GPS v error (integer)
-        */
-
-       final static String AO_TELEM_GPS_STATE                  = "g";
-       final static String AO_TELEM_GPS_STATE_LOCKED           = "l";
-       final static String AO_TELEM_GPS_STATE_UNLOCKED         = "u";
-       final static String AO_TELEM_GPS_STATE_ERROR            = "e";
-       final static String AO_TELEM_GPS_NUM_SAT                = "g_n";
-       final static String AO_TELEM_GPS_LATITUDE               = "g_ns";
-       final static String AO_TELEM_GPS_LONGITUDE              = "g_ew";
-       final static String AO_TELEM_GPS_ALTITUDE               = "g_a";
-       final static String AO_TELEM_GPS_YEAR                   = "g_Y";
-       final static String AO_TELEM_GPS_MONTH                  = "g_M";
-       final static String AO_TELEM_GPS_DAY                    = "g_D";
-       final static String AO_TELEM_GPS_HOUR                   = "g_h";
-       final static String AO_TELEM_GPS_MINUTE                 = "g_m";
-       final static String AO_TELEM_GPS_SECOND                 = "g_s";
-       final static String AO_TELEM_GPS_VERTICAL_SPEED         = "g_v";
-       final static String AO_TELEM_GPS_HORIZONTAL_SPEED       = "g_g";
-       final static String AO_TELEM_GPS_COURSE                 = "g_c";
-       final static String AO_TELEM_GPS_HDOP                   = "g_hd";
-       final static String AO_TELEM_GPS_VDOP                   = "g_vd";
-       final static String AO_TELEM_GPS_HERROR                 = "g_he";
-       final static String AO_TELEM_GPS_VERROR                 = "g_ve";
-
-       /*
-        * GPS satellite values
-        *
-        *      Name            Value
-        *      s_n             Number of satellites reported (integer)
-        *      s_v0            Space vehicle ID (integer) for report 0
-        *      s_c0            C/N0 number (integer) for report 0
-        *      s_v1            Space vehicle ID (integer) for report 1
-        *      s_c1            C/N0 number (integer) for report 1
-        *      ...
-        */
-
-       final static String AO_TELEM_SAT_NUM    = "s_n";
-       final static String AO_TELEM_SAT_SVID   = "s_v";
-       final static String AO_TELEM_SAT_C_N_0  = "s_c";
-
-       AltosRecordTM   record;
-
-       private void parse_v4(String[] words, int i) throws ParseException {
-               AltosTelemetryMap       map = new AltosTelemetryMap(words, i);
-
-               record.callsign = map.get_string(AO_TELEM_CALL, "N0CALL");
-               record.serial = map.get_int(AO_TELEM_SERIAL, AltosRecord.MISSING);
-               record.flight = map.get_int(AO_TELEM_FLIGHT, AltosRecord.MISSING);
-               record.rssi = map.get_int(AO_TELEM_RSSI, AltosRecord.MISSING);
-               record.state = AltosLib.state(map.get_string(AO_TELEM_STATE, "invalid"));
-               record.tick = map.get_int(AO_TELEM_TICK, 0);
-
-               /* raw sensor values */
-               record.accel = map.get_int(AO_TELEM_RAW_ACCEL, AltosRecord.MISSING);
-               record.pres = map.get_int(AO_TELEM_RAW_BARO, AltosRecord.MISSING);
-               record.temp = map.get_int(AO_TELEM_RAW_THERMO, AltosRecord.MISSING);
-               record.batt = map.get_int(AO_TELEM_RAW_BATT, AltosRecord.MISSING);
-               record.drogue = map.get_int(AO_TELEM_RAW_DROGUE, AltosRecord.MISSING);
-               record.main = map.get_int(AO_TELEM_RAW_MAIN, AltosRecord.MISSING);
-
-               /* sensor calibration information */
-               record.ground_accel = map.get_int(AO_TELEM_CAL_ACCEL_GROUND, AltosRecord.MISSING);
-               record.ground_pres = map.get_int(AO_TELEM_CAL_BARO_GROUND, AltosRecord.MISSING);
-               record.accel_plus_g = map.get_int(AO_TELEM_CAL_ACCEL_PLUS, AltosRecord.MISSING);
-               record.accel_minus_g = map.get_int(AO_TELEM_CAL_ACCEL_MINUS, AltosRecord.MISSING);
-
-               /* flight computer values */
-               record.kalman_acceleration = map.get_double(AO_TELEM_KALMAN_ACCEL, AltosRecord.MISSING, 1/16.0);
-               record.kalman_speed = map.get_double(AO_TELEM_KALMAN_SPEED, AltosRecord.MISSING, 1/16.0);
-               record.kalman_height = map.get_int(AO_TELEM_KALMAN_HEIGHT, AltosRecord.MISSING);
-
-               record.flight_accel = map.get_int(AO_TELEM_ADHOC_ACCEL, AltosRecord.MISSING);
-               record.flight_vel = map.get_int(AO_TELEM_ADHOC_SPEED, AltosRecord.MISSING);
-               record.flight_pres = map.get_int(AO_TELEM_ADHOC_BARO, AltosRecord.MISSING);
-
-               if (map.has(AO_TELEM_GPS_STATE)) {
-               record.gps = new AltosGPS(map);
-               record.gps_sequence++;
-               }
-               else
-               record.gps = null;
-       }
-
-       private void parse_legacy(String[] words, int i) throws ParseException {
-
-               AltosParse.word (words[i++], "CALL");
-               record.callsign = words[i++];
-
-               AltosParse.word (words[i++], "SERIAL");
-               record.serial = AltosParse.parse_int(words[i++]);
-
-               if (record.version >= 2) {
-                       AltosParse.word (words[i++], "FLIGHT");
-                       record.flight = AltosParse.parse_int(words[i++]);
-               } else
-                       record.flight = 0;
-
-               AltosParse.word(words[i++], "RSSI");
-               record.rssi = AltosParse.parse_int(words[i++]);
-
-               /* Older telemetry data had mis-computed RSSI value */
-               if (record.version <= 2)
-                       record.rssi = (record.rssi + 74) / 2 - 74;
-
-               AltosParse.word(words[i++], "STATUS");
-               record.status = AltosParse.parse_hex(words[i++]);
-
-               AltosParse.word(words[i++], "STATE");
-               record.state = AltosLib.state(words[i++]);
-
-               record.tick = AltosParse.parse_int(words[i++]);
-
-               AltosParse.word(words[i++], "a:");
-               record.accel = AltosParse.parse_int(words[i++]);
-
-               AltosParse.word(words[i++], "p:");
-               record.pres = AltosParse.parse_int(words[i++]);
-
-               AltosParse.word(words[i++], "t:");
-               record.temp = AltosParse.parse_int(words[i++]);
-
-               AltosParse.word(words[i++], "v:");
-               record.batt = AltosParse.parse_int(words[i++]);
-
-               AltosParse.word(words[i++], "d:");
-               record.drogue = AltosParse.parse_int(words[i++]);
-
-               AltosParse.word(words[i++], "m:");
-               record.main = AltosParse.parse_int(words[i++]);
-
-               AltosParse.word(words[i++], "fa:");
-               record.flight_accel = AltosParse.parse_int(words[i++]);
-
-               AltosParse.word(words[i++], "ga:");
-               record.ground_accel = AltosParse.parse_int(words[i++]);
-
-               AltosParse.word(words[i++], "fv:");
-               record.flight_vel = AltosParse.parse_int(words[i++]);
-
-               AltosParse.word(words[i++], "fp:");
-               record.flight_pres = AltosParse.parse_int(words[i++]);
-
-               /* Old TeleDongle code with kalman-reporting TeleMetrum code */
-               if ((record.flight_vel & 0xffff0000) == 0x80000000) {
-                       record.kalman_speed = ((short) record.flight_vel) / 16.0;
-                       record.kalman_acceleration = record.flight_accel / 16.0;
-                       record.kalman_height = record.flight_pres;
-                       record.flight_vel = AltosRecord.MISSING;
-                       record.flight_pres = AltosRecord.MISSING;
-                       record.flight_accel = AltosRecord.MISSING;
-               }
-
-               AltosParse.word(words[i++], "gp:");
-               record.ground_pres = AltosParse.parse_int(words[i++]);
-
-               if (record.version >= 1) {
-                       AltosParse.word(words[i++], "a+:");
-                       record.accel_plus_g = AltosParse.parse_int(words[i++]);
-
-                       AltosParse.word(words[i++], "a-:");
-                       record.accel_minus_g = AltosParse.parse_int(words[i++]);
-               } else {
-                       record.accel_plus_g = record.ground_accel;
-                       record.accel_minus_g = record.ground_accel + 530;
-               }
-
-               record.gps = new AltosGPS(words, i, record.version);
-               record.gps_sequence++;
-       }
-
-       public AltosTelemetryRecordLegacy(String line) throws ParseException, AltosCRCException {
-               String[] words = line.split("\\s+");
-               int     i = 0;
-
-               record = new AltosRecordTM();
-
-               if (words[i].equals("CRC") && words[i+1].equals("INVALID")) {
-                       i += 2;
-                       AltosParse.word(words[i++], "RSSI");
-                       record.rssi = AltosParse.parse_int(words[i++]);
-                       throw new AltosCRCException(record.rssi);
-               }
-               if (words[i].equals("CALL")) {
-                       record.version = 0;
-               } else {
-                       AltosParse.word (words[i++], "VERSION");
-                       record.version = AltosParse.parse_int(words[i++]);
-               }
-
-               if (record.version < 4)
-                       parse_legacy(words, i);
-               else
-                       parse_v4(words, i);
-       }
-
-       /*
-        * Given a hex dump of a legacy telemetry line, construct an AltosRecordTM from that
-        */
-
-       int[]   bytes;
-       int     adjust;
-
-       /*
-       private int int8(int i) {
-               return AltosLib.int8(bytes, i + 1 + adjust);
-       }
-       */
-       private int uint8(int i) {
-               return AltosLib.uint8(bytes, i + 1 + adjust);
-       }
-       private int int16(int i) {
-               return AltosLib.int16(bytes, i + 1 + adjust);
-       }
-       private int uint16(int i) {
-               return AltosLib.uint16(bytes, i + 1 + adjust);
-       }
-       private int uint32(int i) {
-               return AltosLib.uint32(bytes, i + 1 + adjust);
-       }
-       private String string(int i, int l) {
-               return AltosLib.string(bytes, i + 1 + adjust, l);
-       }
-
-       static final int AO_GPS_NUM_SAT_MASK    = (0xf << 0);
-       static final int AO_GPS_NUM_SAT_SHIFT   = (0);
-
-       static final int AO_GPS_VALID           = (1 << 4);
-       static final int AO_GPS_RUNNING         = (1 << 5);
-       static final int AO_GPS_DATE_VALID      = (1 << 6);
-       static final int AO_GPS_COURSE_VALID    = (1 << 7);
-
-       public AltosTelemetryRecordLegacy(int[] in_bytes, int in_rssi, int in_status) {
-               record = new AltosRecordTM();
-
-               bytes = in_bytes;
-               record.version = 4;
-               adjust = 0;
-
-               if (bytes.length == AltosLib.ao_telemetry_0_8_len + 4) {
-                       record.serial = uint8(0);
-                       adjust = -1;
-               } else
-                       record.serial = uint16(0);
-
-               record.seen = AltosRecord.seen_flight | AltosRecord.seen_sensor | AltosRecord.seen_temp_volt | AltosRecord.seen_deploy;
-
-               record.callsign = string(62, 8);
-               record.flight = uint16(2);
-               record.rssi = in_rssi;
-               record.status = in_status;
-               record.state = uint8(4);
-               record.tick = uint16(21);
-               record.accel = int16(23);
-               record.pres = int16(25);
-               record.temp = int16(27);
-               record.batt = int16(29);
-               record.drogue = int16(31);
-               record.main = int16(33);
-               
-               record.ground_accel = int16(7);
-               record.ground_pres = int16(15);
-               record.accel_plus_g = int16(17);
-               record.accel_minus_g = int16(19);
-
-               if (uint16(11) == 0x8000) {
-                       record.kalman_acceleration = int16(5);
-                       record.kalman_speed = int16(9);
-                       record.kalman_height = int16(13);
-                       record.flight_accel = AltosRecord.MISSING;
-                       record.flight_vel = AltosRecord.MISSING;
-                       record.flight_pres = AltosRecord.MISSING;
-               } else {
-                       record.flight_accel = int16(5);
-                       record.flight_vel = uint32(9);
-                       record.flight_pres = int16(13);
-                       record.kalman_acceleration = AltosRecord.MISSING;
-                       record.kalman_speed = AltosRecord.MISSING;
-                       record.kalman_height = AltosRecord.MISSING;
-               }
-
-               record.gps = null;
-
-               int gps_flags = uint8(41);
-
-               if ((gps_flags & (AO_GPS_VALID|AO_GPS_RUNNING)) != 0) {
-                       record.gps = new AltosGPS();
-                       record.gps_sequence++;
-
-                       record.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon;
-                       record.gps.nsat = (gps_flags & AO_GPS_NUM_SAT_MASK);
-                       record.gps.locked = (gps_flags & AO_GPS_VALID) != 0;
-                       record.gps.connected = true;
-                       record.gps.lat = uint32(42) / 1.0e7;
-                       record.gps.lon = uint32(46) / 1.0e7;
-                       record.gps.alt = int16(50);
-                       record.gps.ground_speed = uint16(52) / 100.0;
-                       record.gps.course = uint8(54) * 2;
-                       record.gps.hdop = uint8(55) / 5.0;
-                       record.gps.h_error = uint16(58);
-                       record.gps.v_error = uint16(60);
-
-                       int     n_tracking_reported = uint8(70);
-                       if (n_tracking_reported > 12)
-                               n_tracking_reported = 12;
-                       int     n_tracking_actual = 0;
-                       for (int i = 0; i < n_tracking_reported; i++) {
-                               if (uint8(71 + i*2) != 0)
-                                       n_tracking_actual++;
-                       }
-                       if (n_tracking_actual > 0) {
-                               record.gps.cc_gps_sat = new AltosGPSSat[n_tracking_actual];
-
-                               n_tracking_actual = 0;
-                               for (int i = 0; i < n_tracking_reported; i++) {
-                                       int     svid = uint8(71 + i*2);
-                                       int     c_n0 = uint8(72 + i*2);
-                                       if (svid != 0)
-                                               record.gps.cc_gps_sat[n_tracking_actual++] = new AltosGPSSat(svid, c_n0);
-                               }
-                       }
-               }
-
-               record.time = 0.0;
-       }
-
-       public AltosRecord update_state(AltosRecord previous) {
-               return record;
-       }
-}
diff --git a/altoslib/AltosTelemetryRecordLocation.java b/altoslib/AltosTelemetryRecordLocation.java
deleted file mode 100644 (file)
index 0236d29..0000000
+++ /dev/null
@@ -1,93 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-
-public class AltosTelemetryRecordLocation extends AltosTelemetryRecordRaw {
-       int     flags;
-       int     altitude;
-       int     latitude;
-       int     longitude;
-       int     year;
-       int     month;
-       int     day;
-       int     hour;
-       int     minute;
-       int     second;
-       int     pdop;
-       int     hdop;
-       int     vdop;
-       int     mode;
-       int     ground_speed;
-       int     climb_rate;
-       int     course;
-
-       public AltosTelemetryRecordLocation(int[] in_bytes, int rssi) {
-               super(in_bytes, rssi);
-
-               flags          = uint8(5);
-               altitude       = int16(6);
-               latitude       = uint32(8);
-               longitude      = uint32(12);
-               year           = uint8(16);
-               month          = uint8(17);
-               day            = uint8(18);
-               hour           = uint8(19);
-               minute         = uint8(20);
-               second         = uint8(21);
-               pdop           = uint8(22);
-               hdop           = uint8(23);
-               vdop           = uint8(24);
-               mode           = uint8(25);
-               ground_speed   = uint16(26);
-               climb_rate     = int16(28);
-               course         = uint8(30);
-       }
-
-       public AltosRecord update_state(AltosRecord previous) {
-               AltosRecord     next = super.update_state(previous);
-
-               if (next.gps == null)
-                       next.gps = new AltosGPS();
-
-               next.gps.nsat = flags & 0xf;
-               next.gps.locked = (flags & (1 << 4)) != 0;
-               next.gps.connected = (flags & (1 << 5)) != 0;
-
-               if (next.gps.locked) {
-                       next.gps.lat = latitude * 1.0e-7;
-                       next.gps.lon = longitude * 1.0e-7;
-                       next.gps.alt = altitude;
-                       next.gps.year = 2000 + year;
-                       next.gps.month = month;
-                       next.gps.day = day;
-                       next.gps.hour = hour;
-                       next.gps.minute = minute;
-                       next.gps.second = second;
-                       next.gps.ground_speed = ground_speed * 1.0e-2;
-                       next.gps.course = course * 2;
-                       next.gps.climb_rate = climb_rate * 1.0e-2;
-                       next.gps.hdop = hdop;
-                       next.gps.vdop = vdop;
-                       next.seen |= AltosRecord.seen_gps_time | AltosRecord.seen_gps_lat | AltosRecord.seen_gps_lon;
-                       next.gps_sequence++;
-               }
-
-               return next;
-       }
-}
diff --git a/altoslib/AltosTelemetryRecordMegaData.java b/altoslib/AltosTelemetryRecordMegaData.java
deleted file mode 100644 (file)
index a484ef4..0000000
+++ /dev/null
@@ -1,94 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-
-public class AltosTelemetryRecordMegaData extends AltosTelemetryRecordRaw {
-
-       int     state;
-       
-       int     v_batt;
-       int     v_pyro;
-       int     sense[];
-
-       int     ground_pres;
-       int     ground_accel;
-       int     accel_plus_g;
-       int     accel_minus_g;
-
-       int     acceleration;
-       int     speed;
-       int     height;
-
-       public AltosTelemetryRecordMegaData(int[] in_bytes, int rssi) {
-               super(in_bytes, rssi);
-
-               state = int8(5);
-
-               v_batt = int16(6);
-               v_pyro = int16(8);
-
-               sense = new int[6];     
-
-               for (int i = 0; i < 6; i++) {
-                       sense[i] = int8(10 + i) << 4;
-                       sense[i] |= sense[i] >> 8;
-               }
-
-               ground_pres = int32(16);
-               ground_accel = int16(20);
-               accel_plus_g = int16(22);
-               accel_minus_g = int16(24);
-
-               acceleration = int16(26);
-               speed = int16(28);
-               height = int16(30);
-       }
-
-       public AltosRecord update_state(AltosRecord previous) {
-               AltosRecord     n = super.update_state(previous);
-
-               AltosRecordMM   next;
-               if (!(n instanceof AltosRecordMM)) {
-                       next = new AltosRecordMM(n);
-               } else {
-                       next = (AltosRecordMM) n;
-               }
-
-               next.state = state;
-
-               next.v_batt = v_batt;
-               next.v_pyro = v_pyro;
-
-               for (int i = 0; i < 6; i++)
-                       next.sense[i] = sense[i];
-
-               next.ground_accel = ground_accel;
-               next.ground_pres = ground_pres;
-               next.accel_plus_g = accel_plus_g;
-               next.accel_minus_g = accel_minus_g;
-
-               next.kalman_acceleration = acceleration / 16.0;
-               next.kalman_speed = speed / 16.0;
-               next.kalman_height = height;
-
-               next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt;
-
-               return next;
-       }
-}
diff --git a/altoslib/AltosTelemetryRecordMegaSensor.java b/altoslib/AltosTelemetryRecordMegaSensor.java
deleted file mode 100644 (file)
index 2a4b17a..0000000
+++ /dev/null
@@ -1,88 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-
-public class AltosTelemetryRecordMegaSensor extends AltosTelemetryRecordRaw {
-       int     accel;
-       int     pres;
-       int     temp;
-
-       int     accel_x;
-       int     accel_y;
-       int     accel_z;
-
-       int     gyro_x;
-       int     gyro_y;
-       int     gyro_z;
-
-       int     mag_x;
-       int     mag_y;
-       int     mag_z;
-
-       public AltosTelemetryRecordMegaSensor(int[] in_bytes, int rssi) {
-               super(in_bytes, rssi);
-
-               accel         = int16(6);
-               pres          = int32(8);
-               temp          = int16(12);
-
-               accel_x       = int16(14);
-               accel_y       = int16(16);
-               accel_z       = int16(18);
-
-               gyro_x        = int16(20);
-               gyro_y        = int16(22);
-               gyro_z        = int16(24);
-
-               mag_x         = int16(26);
-               mag_y         = int16(28);
-               mag_z         = int16(30);
-       }
-
-       public AltosRecord update_state(AltosRecord previous) {
-               AltosRecord     n = super.update_state(previous);
-
-               AltosRecordMM   next;
-               if (!(n instanceof AltosRecordMM)) {
-                       next = new AltosRecordMM(n);
-               } else {
-                       next = (AltosRecordMM) n;
-               }
-
-               next.accel = accel;
-               next.pres = pres;
-               next.temp = temp;
-
-               next.imu.accel_x = accel_x;
-               next.imu.accel_y = accel_y;
-               next.imu.accel_z = accel_z;
-
-               next.imu.gyro_x = gyro_x;
-               next.imu.gyro_y = gyro_y;
-               next.imu.gyro_z = gyro_z;
-
-               next.mag.x = mag_x;
-               next.mag.y = mag_y;
-               next.mag.z = mag_z;
-
-               next.seen |= AltosRecord.seen_sensor;
-
-               return next;
-       }
-}
diff --git a/altoslib/AltosTelemetryRecordRaw.java b/altoslib/AltosTelemetryRecordRaw.java
deleted file mode 100644 (file)
index f94789b..0000000
+++ /dev/null
@@ -1,81 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosTelemetryRecordRaw extends AltosTelemetryRecord {
-       int[]   bytes;
-       int     serial;
-       int     tick;
-       int     type;
-       int     rssi;
-
-       long    received_time;
-
-       public int int8(int off) {
-               return AltosLib.int8(bytes, off + 1);
-       }
-
-       public int uint8(int off) {
-               return AltosLib.uint8(bytes, off + 1);
-       }
-
-       public int int16(int off) {
-               return AltosLib.int16(bytes, off + 1);
-       }
-
-       public int uint16(int off) {
-               return AltosLib.uint16(bytes, off + 1);
-       }
-
-       public int uint32(int off) {
-               return AltosLib.uint32(bytes, off + 1);
-       }
-
-       public int int32(int off) {
-               return AltosLib.int32(bytes, off + 1);
-       }
-
-       public String string(int off, int l) {
-               return AltosLib.string(bytes, off + 1, l);
-       }
-
-       public AltosTelemetryRecordRaw(int[] in_bytes, int in_rssi) {
-               bytes = in_bytes;
-               serial = uint16(0);
-               tick   = uint16(2);
-               type   = uint8(4);
-               rssi   = in_rssi;
-       }
-
-       public AltosRecord update_state(AltosRecord previous) {
-               AltosRecord     next;
-
-               if (previous != null && previous.serial == serial)
-                       next = previous.clone();
-               else
-                       next = new AltosRecordNone();
-               next.serial = serial;
-               next.tick = tick;
-               next.rssi = rssi;
-               return next;
-       }
-
-       public long received_time() {
-               return received_time;
-       }
-}
diff --git a/altoslib/AltosTelemetryRecordSatellite.java b/altoslib/AltosTelemetryRecordSatellite.java
deleted file mode 100644 (file)
index 9835389..0000000
+++ /dev/null
@@ -1,52 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-public class AltosTelemetryRecordSatellite extends AltosTelemetryRecordRaw {
-       int             channels;
-       AltosGPSSat[]   sats;
-
-       public AltosTelemetryRecordSatellite(int[] in_bytes, int rssi) {
-               super(in_bytes, rssi);
-
-               channels = uint8(5);
-               if (channels > 12)
-                       channels = 12;
-               if (channels == 0)
-                       sats = null;
-               else {
-                       sats = new AltosGPSSat[channels];
-                       for (int i = 0; i < channels; i++) {
-                               int     svid =  uint8(6 + i * 2 + 0);
-                               int     c_n_1 = uint8(6 + i * 2 + 1);
-                               sats[i] = new AltosGPSSat(svid, c_n_1);
-                       }
-               }
-       }
-
-       public AltosRecord update_state(AltosRecord previous) {
-               AltosRecord     next = super.update_state(previous);
-
-               if (next.gps == null)
-                       next.gps = new AltosGPS();
-
-               next.gps.cc_gps_sat = sats;
-
-               return next;
-       }
-}
diff --git a/altoslib/AltosTelemetryRecordSensor.java b/altoslib/AltosTelemetryRecordSensor.java
deleted file mode 100644 (file)
index e0e92c1..0000000
+++ /dev/null
@@ -1,104 +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; 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.
- */
-
-package org.altusmetrum.altoslib_1;
-
-
-public class AltosTelemetryRecordSensor extends AltosTelemetryRecordRaw {
-       int     state;
-       int     accel;
-       int     pres;
-       int     temp;
-       int     v_batt;
-       int     sense_d;
-       int     sense_m;
-
-       int     acceleration;
-       int     speed;
-       int     height;
-
-       int     ground_accel;
-       int     ground_pres;
-       int     accel_plus_g;
-       int     accel_minus_g;
-
-       public AltosTelemetryRecordSensor(int[] in_bytes, int rssi) {
-               super(in_bytes, rssi);
-               state         = uint8(5);
-
-               accel         = int16(6);
-               pres          = int16(8);
-               temp          = int16(10);
-               v_batt        = int16(12);
-               sense_d       = int16(14);
-               sense_m       = int16(16);
-
-               acceleration  = int16(18);
-               speed         = int16(20);
-               height        = int16(22);
-
-               ground_pres   = int16(24);
-               ground_accel  = int16(26);
-               accel_plus_g  = int16(28);
-               accel_minus_g = int16(30);
-       }
-
-       public AltosRecord update_state(AltosRecord prev) {
-               AltosRecord     n = super.update_state(prev);
-
-               AltosRecordTM   next;
-               if (!(n instanceof AltosRecordTM))
-                       next = new AltosRecordTM(n);
-               else
-                       next = (AltosRecordTM) n;
-
-               next.state = state;
-               if (type == packet_type_TM_sensor)
-                       next.accel = accel;
-               else
-                       next.accel = AltosRecord.MISSING;
-               next.pres = pres;
-               next.temp = temp;
-               next.batt = v_batt;
-               if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) {
-                       next.drogue = sense_d;
-                       next.main = sense_m;
-               } else {
-                       next.drogue = AltosRecord.MISSING;
-                       next.main = AltosRecord.MISSING;
-               }
-
-               next.kalman_acceleration = acceleration / 16.0;
-               next.kalman_speed = speed / 16.0;
-               next.kalman_height = height;
-
-               next.ground_pres = ground_pres;
-               if (type == packet_type_TM_sensor) {
-                       next.ground_accel = ground_accel;
-                       next.accel_plus_g = accel_plus_g;
-                       next.accel_minus_g = accel_minus_g;
-               } else {
-                       next.ground_accel = AltosRecord.MISSING;
-                       next.accel_plus_g = AltosRecord.MISSING;
-                       next.accel_minus_g = AltosRecord.MISSING;
-               }
-
-               next.seen |= AltosRecord.seen_sensor | AltosRecord.seen_temp_volt;
-
-               return next;
-       }
-}
diff --git a/altoslib/AltosTelemetrySatellite.java b/altoslib/AltosTelemetrySatellite.java
new file mode 100644 (file)
index 0000000..fde3d86
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public class AltosTelemetrySatellite extends AltosTelemetryStandard {
+       int             channels;
+       AltosGPSSat[]   sats;
+
+       public AltosTelemetrySatellite(int[] bytes) {
+               super(bytes);
+
+               channels = uint8(5);
+               if (channels > 12)
+                       channels = 12;
+               if (channels == 0)
+                       sats = null;
+               else {
+                       sats = new AltosGPSSat[channels];
+                       for (int i = 0; i < channels; i++) {
+                               int     svid =  uint8(6 + i * 2 + 0);
+                               int     c_n_1 = uint8(6 + i * 2 + 1);
+                               sats[i] = new AltosGPSSat(svid, c_n_1);
+                       }
+               }
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               AltosGPS        gps = state.make_temp_gps(true);
+               
+               gps.cc_gps_sat = sats;
+               state.set_temp_gps();
+       }
+}
diff --git a/altoslib/AltosTelemetrySensor.java b/altoslib/AltosTelemetrySensor.java
new file mode 100644 (file)
index 0000000..e110644
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+
+public class AltosTelemetrySensor extends AltosTelemetryStandard {
+       int     state;
+       int     accel;
+       int     pres;
+       int     temp;
+       int     v_batt;
+       int     sense_d;
+       int     sense_m;
+
+       int     acceleration;
+       int     speed;
+       int     height;
+
+       int     ground_accel;
+       int     ground_pres;
+       int     accel_plus_g;
+       int     accel_minus_g;
+
+       public AltosTelemetrySensor(int[] bytes) {
+               super(bytes);
+               state         = uint8(5);
+
+               accel         = int16(6);
+               pres          = int16(8);
+               temp          = int16(10);
+               v_batt        = int16(12);
+               sense_d       = int16(14);
+               sense_m       = int16(16);
+
+               acceleration  = int16(18);
+               speed         = int16(20);
+               height        = int16(22);
+
+               ground_pres   = int16(24);
+               ground_accel  = int16(26);
+               accel_plus_g  = int16(28);
+               accel_minus_g = int16(30);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+
+               state.set_state(this.state);
+               if (type == packet_type_TM_sensor) {
+                       state.set_ground_accel(ground_accel);
+                       state.set_accel_g(accel_plus_g, accel_minus_g);
+                       state.set_accel(accel);
+               }
+               state.set_ground_pressure(AltosConvert.barometer_to_pressure(ground_pres));
+               state.set_pressure(AltosConvert.barometer_to_pressure(pres));
+               state.set_temperature(AltosConvert.thermometer_to_temperature(temp));
+               state.set_battery_voltage(AltosConvert.cc_battery_to_voltage(v_batt));
+               if (type == packet_type_TM_sensor || type == packet_type_Tm_sensor) {
+                       state.set_apogee_voltage(AltosConvert.cc_ignitor_to_voltage(sense_d));
+                       state.set_main_voltage(AltosConvert.cc_ignitor_to_voltage(sense_m));
+               }
+
+               state.set_kalman(height, speed/16.0, acceleration / 16.0);
+       }
+}
diff --git a/altoslib/AltosTelemetryStandard.java b/altoslib/AltosTelemetryStandard.java
new file mode 100644 (file)
index 0000000..3186ae0
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_2;
+
+public abstract class AltosTelemetryStandard extends AltosTelemetry {
+       int[]   bytes;
+       int     type;
+
+       public int int8(int off) {
+               return AltosLib.int8(bytes, off + 1);
+       }
+
+       public int uint8(int off) {
+               return AltosLib.uint8(bytes, off + 1);
+       }
+
+       public int int16(int off) {
+               return AltosLib.int16(bytes, off + 1);
+       }
+
+       public int uint16(int off) {
+               return AltosLib.uint16(bytes, off + 1);
+       }
+
+       public int uint32(int off) {
+               return AltosLib.uint32(bytes, off + 1);
+       }
+
+       public int int32(int off) {
+               return AltosLib.int32(bytes, off + 1);
+       }
+
+       public String string(int off, int l) {
+               return AltosLib.string(bytes, off + 1, l);
+       }
+
+       public static AltosTelemetry parse_hex(int[] bytes) {
+               int     type = AltosLib.uint8(bytes, 4 + 1);
+
+               AltosTelemetry  telem;
+               switch (type) {
+               case packet_type_TM_sensor:
+               case packet_type_Tm_sensor:
+               case packet_type_Tn_sensor:
+                       telem = new AltosTelemetrySensor(bytes);
+                       break;
+               case packet_type_configuration:
+                       telem = new AltosTelemetryConfiguration(bytes);
+                       break;
+               case packet_type_location:
+                       telem = new AltosTelemetryLocation(bytes);
+                       break;
+               case packet_type_satellite:
+                       telem = new AltosTelemetrySatellite(bytes);
+                       break;
+/*
+               case packet_type_companion:
+                       telem = new AltosTelemetryCompanion(bytes);
+                       break;
+*/
+               case packet_type_mega_sensor:
+                       telem = new AltosTelemetryMegaSensor(bytes);
+                       break;
+               case packet_type_mega_data:
+                       telem = new AltosTelemetryMegaData(bytes);
+                       break;
+               case packet_type_metrum_sensor:
+                       telem = new AltosTelemetryMetrumSensor(bytes);
+                       break;
+               case packet_type_metrum_data:
+                       telem = new AltosTelemetryMetrumData(bytes);
+                       break;
+               case packet_type_mini:
+                       telem = new AltosTelemetryMini(bytes);
+                       break;
+               default:
+                       telem = new AltosTelemetryRaw(bytes);
+                       break;
+               }
+               return telem;
+       }
+
+       public AltosTelemetryStandard(int[] bytes) {
+               this.bytes = bytes;
+
+               serial = uint16(0);
+               tick   = uint16(2);
+               type   = uint8(4);
+       }
+
+       public void update_state(AltosState state) {
+               super.update_state(state);
+       }
+}
index 2749eac09dfdbd08ffc538be1097e1247b821fec..a636533f5e7c95c5cc639906c5d50bb0cbb19ba2 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public class AltosTemperature extends AltosUnits {
 
-       public double value(double v) {
-               if (AltosConvert.imperial_units)
+       public double value(double v, boolean imperial_units) {
+               if (imperial_units)
                        return AltosConvert.c_to_f(v);
                return v;
        }
 
-       public String show_units() {
-               if (AltosConvert.imperial_units)
+       public double inverse(double v, boolean imperial_units) {
+               if (imperial_units)
+                       return AltosConvert.f_to_c(v);
+               return v;
+       }
+
+       public String show_units(boolean imperial_units) {
+               if (imperial_units)
                        return "°F";
                return "°C";
        }
 
-       public String say_units() {
-               if (AltosConvert.imperial_units)
+       public String say_units(boolean imperial_units) {
+               if (imperial_units)
                        return "degrees farenheit";
                return "degrees celsius";
        }
 
-       public int show_fraction(int width) {
+       public int show_fraction(int width, boolean imperial_units) {
                return width / 3;
        }
 }
index b8b3254cc4e80394e6a996d51f622bf46b58ddda..8f9ccded5f4e8659c93085d30c57b709f5ec6150 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public abstract class AltosUnits {
 
-       public abstract double value(double v);
+       public abstract double value(double v, boolean imperial_units);
 
-       public abstract String show_units();
+       public abstract double inverse(double v, boolean imperial_units);
 
-       public abstract String say_units();
+       public abstract String show_units(boolean imperial_units);
 
-       public abstract int show_fraction(int width);
+       public abstract String say_units(boolean imperial_units);
 
-       int say_fraction() {
+       public abstract int show_fraction(int width, boolean imperial_units);
+
+       public double parse(String s, boolean imperial_units) throws NumberFormatException {
+               double v = Double.parseDouble(s);
+               return inverse(v, imperial_units);
+       }
+
+       public double parse(String s) throws NumberFormatException {
+               return parse(s, AltosConvert.imperial_units);
+       }
+
+       public double value(double v) {
+               return value(v, AltosConvert.imperial_units);
+       }
+               
+       public double inverse(double v) {
+               return inverse(v, AltosConvert.imperial_units);
+       }
+
+       public String show_units() {
+               return show_units(AltosConvert.imperial_units);
+       }
+               
+       public String say_units() {
+               return say_units(AltosConvert.imperial_units);
+       }
+               
+       public int show_fraction(int width) {
+               return show_fraction(width, AltosConvert.imperial_units);
+       }
+               
+       int say_fraction(boolean imperial_units) {
                return 0;
        }
 
-       private String show_format(int width) {
-               return String.format("%%%d.%df %s", width, show_fraction(width), show_units());
+       private String show_format(int width, boolean imperial_units) {
+               return String.format("%%%d.%df %s", width, show_fraction(width, imperial_units), show_units(imperial_units));
+       }
+
+       private String say_format(boolean imperial_units) {
+               return String.format("%%1.%df", say_fraction(imperial_units));
        }
 
-       private String say_format() {
-               return String.format("%%1.%df", say_fraction());
+       private String say_units_format(boolean imperial_units) {
+               return String.format("%%1.%df %s", say_fraction(imperial_units), say_units(imperial_units));
        }
 
-       private String say_units_format() {
-               return String.format("%%1.%df %s", say_fraction(), say_units());
+       public String graph_format(int width, boolean imperial_units) {
+               return String.format(String.format("%%%d.%df", width, show_fraction(width, imperial_units)), 0.0);
        }
 
        public String graph_format(int width) {
-               return String.format(String.format("%%%d.%df", width, show_fraction(width)), 0.0);
+               return graph_format(width, AltosConvert.imperial_units);
+       }
+
+       public String show(int width, double v, boolean imperial_units) {
+               return String.format(show_format(width, imperial_units), value(v, imperial_units));
        }
 
        public String show(int width, double v) {
-               return String.format(show_format(width), value(v));
+               return show(width, v, AltosConvert.imperial_units);
+       }
+
+       public String say(double v, boolean imperial_units) {
+               return String.format(say_format(imperial_units), value(v, imperial_units));
        }
 
        public String say(double v) {
-               return String.format(say_format(), value(v));
+               return say(v, AltosConvert.imperial_units);
+       }
+
+       public String say_units(double v, boolean imperial_units) {
+               return String.format(say_units_format(imperial_units), value(v, imperial_units));
        }
 
        public String say_units(double v) {
-               return String.format(say_units_format(), value(v));
+               return say_units(v, AltosConvert.imperial_units);
        }
 }
\ No newline at end of file
index 61a181a4da7853b9d9e80767ff8841b6fe381342..1e3ad6556888b4881c6a6bcbc32aa9066aa14ea0 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_1;
+package org.altusmetrum.altoslib_2;
 
 public interface AltosUnitsListener {
        public void units_changed(boolean imperial_units);
index 18b028d628776652ef2243e30ba8eb50ce22fc80..6d396635905ab2e6bbacb0d48485442940797290 100644 (file)
@@ -1,4 +1,4 @@
-AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
 
 JAVAROOT=bin
 
@@ -9,73 +9,100 @@ CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="bin:$(FREETTS)/*:/usr/share/java/
 SRC=.
 
 altoslibdir = $(datadir)/java
+record_files = \
+       AltosEepromRecord.java \
+       AltosEepromTeleScience.java \
+       AltosRecordCompanion.java \
+       AltosRecordIterable.java \
+       AltosOrderedRecord.java \
+       AltosOrderedMegaRecord.java \
+       AltosOrderedMiniRecord.java \
+       AltosRecord.java \
+       AltosRecordNone.java \
+       AltosRecordTM.java \
+       AltosRecordMM.java \
+       AltosRecordMini.java
+
 
 altoslib_JAVA = \
        AltosLib.java \
+       AltosCompanion.java \
        AltosConfigData.java \
        AltosConfigValues.java \
        AltosConvert.java \
        AltosCRCException.java \
        AltosDebug.java \
+       AltosEeprom.java \
        AltosEepromChunk.java \
+       AltosEepromDownload.java \
+       AltosEepromFile.java \
+       AltosEepromTM.java \
+       AltosEepromTm.java \
+       AltosEepromHeader.java \
        AltosEepromIterable.java \
+       AltosEepromList.java \
        AltosEepromLog.java \
        AltosEepromMega.java \
-       AltosEepromMegaIterable.java \
-       AltosEepromRecord.java \
-       AltosEepromTeleScience.java \
+       AltosEepromMetrum2.java \
+       AltosEepromMini.java \
+       AltosEepromMonitor.java \
        AltosFile.java \
        AltosFlash.java \
        AltosFlashListener.java \
        AltosFlightReader.java \
        AltosFrequency.java \
        AltosGPS.java \
-       AltosGPSQuery.java \
        AltosGPSSat.java \
        AltosGreatCircle.java \
        AltosHexfile.java \
+       AltosHexsym.java \
+       AltosIdle.java \
+       AltosIdleFetch.java \
        AltosIdleMonitor.java \
        AltosIdleMonitorListener.java \
        AltosIgnite.java \
        AltosIMU.java \
-       AltosIMUQuery.java \
        AltosLine.java \
        AltosLink.java \
        AltosListenerState.java \
        AltosLog.java \
+       AltosMag.java \
+       AltosMma655x.java \
        AltosMs5607.java \
-       AltosMs5607Query.java \
-       AltosOrderedRecord.java \
-       AltosOrderedMegaRecord.java \
+       AltosNoSymbol.java \
        AltosParse.java \
        AltosPreferences.java \
        AltosPreferencesBackend.java \
-       AltosRecordCompanion.java \
-       AltosRecordIterable.java \
-       AltosRecord.java \
-       AltosRecordNone.java \
-       AltosRecordTM.java \
-       AltosRecordMM.java \
+       AltosProgrammer.java \
        AltosReplayReader.java \
        AltosRomconfig.java \
+       AltosSelfFlash.java \
        AltosSensorMM.java \
+       AltosSensorEMini.java \
        AltosSensorTM.java \
+       AltosSensorTMini.java \
+       AltosSensorMega.java \
+       AltosSensorMetrum.java \
        AltosState.java \
+       AltosStateIterable.java \
+       AltosStateUpdate.java \
        AltosTelemetry.java \
+       AltosTelemetryConfiguration.java \
+       AltosTelemetryFile.java \
        AltosTelemetryIterable.java \
+       AltosTelemetryLegacy.java \
+       AltosTelemetryLocation.java \
        AltosTelemetryMap.java \
+       AltosTelemetryMegaSensor.java \
+       AltosTelemetryMegaData.java \
+       AltosTelemetryMini.java \
+       AltosTelemetryMetrumSensor.java \
+       AltosTelemetryMetrumData.java \
        AltosTelemetryReader.java \
-       AltosTelemetryRecordCompanion.java \
-       AltosTelemetryRecordConfiguration.java \
-       AltosTelemetryRecordGeneral.java \
-       AltosTelemetryRecord.java \
-       AltosTelemetryRecordLegacy.java \
-       AltosTelemetryRecordLocation.java \
-       AltosTelemetryRecordRaw.java \
-       AltosTelemetryRecordSatellite.java \
-       AltosTelemetryRecordSensor.java \
-       AltosTelemetryRecordMegaSensor.java \
-       AltosTelemetryRecordMegaData.java \
+       AltosTelemetryRaw.java \
+       AltosTelemetrySensor.java \
+       AltosTelemetrySatellite.java \
+       AltosTelemetryStandard.java \
        AltosUnitsListener.java \
        AltosMs5607.java \
        AltosIMU.java \
index f8554c6a2292cc50db18204037e533d541aa8870..4ee3f4ade928def48d503681b8ac5c49dc8beecf 100644 (file)
@@ -21,3 +21,4 @@ Altos-Windows-*.exe
 *.so
 *.jar
 *.class
+*.dmg
index d25736bf36da3d77134663a27ce6fe6d8d6744dc..07280b4ae1c5af8e776c6a288aef54b42294b8da 100644 (file)
@@ -20,7 +20,7 @@ package altosui;
 import java.awt.*;
 import libaltosJNI.*;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class Altos extends AltosUILib {
index 4da4d591d70edaf06a2921a734cb9af616d8b40f..ba4fc614bfc70646ddbbcda8e3a7eebf05459964 100644 (file)
@@ -19,7 +19,7 @@ package altosui;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosAscent extends JComponent implements AltosFlightDisplay {
        GridBagLayout   layout;
@@ -179,7 +179,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
                void reset() {
                        value.setText("");
                        max_value.setText("");
-                       max = AltosRecord.MISSING;
+                       max = AltosLib.MISSING;
                }
 
                void set_font() {
@@ -189,12 +189,12 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
                }
 
                void show(AltosUnits units, double v) {
-                       if (v == AltosRecord.MISSING) {
+                       if (v == AltosLib.MISSING) {
                                value.setText("Missing");
                                max_value.setText("Missing");
                        } else {
                                value.setText(units.show(8, v));
-                               if (v > max || max == AltosRecord.MISSING) {
+                               if (v > max || max == AltosLib.MISSING) {
                                        max_value.setText(units.show(8, v));
                                        max = v;
                                }
@@ -240,7 +240,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
 
        class Height extends AscentValueHold {
                void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.height, state.height);
+                       show(AltosConvert.height, state.height());
                }
                public Height (GridBagLayout layout, int y) {
                        super (layout, y, "Height");
@@ -251,10 +251,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
 
        class Speed extends AscentValueHold {
                void show (AltosState state, AltosListenerState listener_state) {
-                       double speed = state.accel_speed;
-                       if (!state.ascent)
-                               speed = state.baro_speed;
-                       show(AltosConvert.speed, speed);
+                       show(AltosConvert.speed, state.speed());
                }
                public Speed (GridBagLayout layout, int y) {
                        super (layout, y, "Speed");
@@ -265,7 +262,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
 
        class Accel extends AscentValueHold {
                void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.accel, state.acceleration);
+                       show(AltosConvert.accel, state.acceleration());
                }
                public Accel (GridBagLayout layout, int y) {
                        super (layout, y, "Acceleration");
@@ -287,8 +284,8 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
 
        class Apogee extends AscentStatus {
                void show (AltosState state, AltosListenerState listener_state) {
-                       show("%4.2f V", state.drogue_sense);
-                       lights.set(state.drogue_sense > 3.2);
+                       show("%4.2f V", state.apogee_voltage);
+                       lights.set(state.apogee_voltage >= AltosLib.ao_igniter_good);
                }
                public Apogee (GridBagLayout layout, int y) {
                        super(layout, y, "Apogee Igniter Voltage");
@@ -299,8 +296,8 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
 
        class Main extends AscentStatus {
                void show (AltosState state, AltosListenerState listener_state) {
-                       show("%4.2f V", state.main_sense);
-                       lights.set(state.main_sense > 3.2);
+                       show("%4.2f V", state.main_voltage);
+                       lights.set(state.main_voltage >= AltosLib.ao_igniter_good);
                }
                public Main (GridBagLayout layout, int y) {
                        super(layout, y, "Main Igniter Voltage");
@@ -311,7 +308,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
 
        class Lat extends AscentValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state.gps != null)
+                       if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
                                show(pos(state.gps.lat,"N", "S"));
                        else
                                show("???");
@@ -325,7 +322,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
 
        class Lon extends AscentValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state.gps != null)
+                       if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
                                show(pos(state.gps.lon,"E", "W"));
                        else
                                show("???");
@@ -368,11 +365,11 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
                        lon.hide();
                }
                height.show(state, listener_state);
-               if (state.main_sense != AltosRecord.MISSING)
+               if (state.main_voltage != AltosLib.MISSING)
                        main.show(state, listener_state);
                else
                        main.hide();
-               if (state.drogue_sense != AltosRecord.MISSING)
+               if (state.apogee_voltage != AltosLib.MISSING)
                        apogee.show(state, listener_state);
                else
                        apogee.hide();
index 1d42365ba858281e82ca43eb2914cd33a962a046..a1652ec4e0a6a893d53b96a4009fc20ea5f5c04b 100644 (file)
@@ -17,7 +17,7 @@
 
 package altosui;
 import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosBTKnown implements Iterable<AltosBTDevice> {
index 4c9b7a6c405f5f827968dd95715b3a71ae50a1f3..1015f7c323774db278413bb61364c831c1f90f00 100644 (file)
@@ -85,7 +85,7 @@ public class AltosBTManage extends AltosUIDialog implements ActionListener, Iter
                        return devices.iterator();
                }
 
-               public java.util.List<AltosBTDevice> selected_list() {
+               public java.util.List<AltosBTDevice> selected_list() throws InterruptedException {
                        java.util.LinkedList<AltosBTDevice> l = new java.util.LinkedList<AltosBTDevice>();
                        Object[] a = getSelectedValues();
                        for (int i = 0; i < a.length; i++)
@@ -117,16 +117,22 @@ public class AltosBTManage extends AltosUIDialog implements ActionListener, Iter
        }
 
        public void add_known() {
-               for (AltosBTDevice device : visible_devices.selected_list()) {
-                       known_devices.add(device);
-                       visible_devices.remove(device);
+               try {
+                       for (AltosBTDevice device : visible_devices.selected_list()) {
+                               known_devices.add(device);
+                               visible_devices.remove(device);
+                       }
+               } catch (InterruptedException ie) {
                }
        }
 
        public void remove_known() {
-               for (AltosBTDevice device : known_devices.selected_list()) {
-                       known_devices.remove(device);
-                       visible_devices.add(device);
+               try {
+                       for (AltosBTDevice device : known_devices.selected_list()) {
+                               known_devices.remove(device);
+                               visible_devices.add(device);
+                       }
+               } catch (InterruptedException ie) {
                }
        }
 
index 0676f99d38fb63478f4da9c32f5a9535e02743d1..7598eca00ffce570a58fcb30e8103228fb626e48 100644 (file)
@@ -19,7 +19,7 @@ package altosui;
 
 import java.io.*;
 import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosCSV implements AltosWriter {
        File                    name;
@@ -27,7 +27,7 @@ public class AltosCSV implements AltosWriter {
        boolean                 header_written;
        boolean                 seen_boost;
        int                     boost_tick;
-       LinkedList<AltosRecord> pad_records;
+       LinkedList<AltosState>  pad_states;
        AltosState              state;
 
        static final int ALTOS_CSV_VERSION = 5;
@@ -105,47 +105,47 @@ public class AltosCSV implements AltosWriter {
                out.printf("version,serial,flight,call,time,clock,rssi,lqi");
        }
 
-       void write_general(AltosRecord record) {
+       void write_general(AltosState state) {
                out.printf("%s, %d, %d, %s, %8.2f, %8.2f, %4d, %3d",
-                          ALTOS_CSV_VERSION, record.serial, record.flight, record.callsign,
-                          (double) record.time, (double) record.tick / 100.0,
-                          record.rssi,
-                          record.status & 0x7f);
+                          ALTOS_CSV_VERSION, state.serial, state.flight, state.callsign,
+                          (double) state.time, (double) state.tick / 100.0,
+                          state.rssi,
+                          state.status & 0x7f);
        }
 
        void write_flight_header() {
                out.printf("state,state_name");
        }
 
-       void write_flight(AltosRecord record) {
-               out.printf("%d,%8s", record.state, record.state());
+       void write_flight(AltosState state) {
+               out.printf("%d,%8s", state.state, state.state_name());
        }
 
        void write_basic_header() {
                out.printf("acceleration,pressure,altitude,height,accel_speed,baro_speed,temperature,battery_voltage,drogue_voltage,main_voltage");
        }
 
-       void write_basic(AltosRecord record) {
+       void write_basic(AltosState state) {
                out.printf("%8.2f,%10.2f,%8.2f,%8.2f,%8.2f,%8.2f,%5.1f,%5.2f,%5.2f,%5.2f",
-                          record.acceleration(),
-                          record.pressure(),
-                          record.altitude(),
-                          record.height(),
-                          state.accel_speed,
-                          state.baro_speed,
-                          record.temperature(),
-                          record.battery_voltage(),
-                          record.drogue_voltage(),
-                          record.main_voltage());
+                          state.acceleration(),
+                          state.pressure(),
+                          state.altitude(),
+                          state.height(),
+                          state.speed(),
+                          state.speed(),
+                          state.temperature,
+                          state.battery_voltage,
+                          state.apogee_voltage,
+                          state.main_voltage);
        }
 
        void write_advanced_header() {
                out.printf("accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z");
        }
 
-       void write_advanced(AltosRecord record) {
-               AltosIMU        imu = record.imu();
-               AltosMag        mag = record.mag();
+       void write_advanced(AltosState state) {
+               AltosIMU        imu = state.imu;
+               AltosMag        mag = state.mag;
 
                if (imu == null)
                        imu = new AltosIMU();
@@ -161,8 +161,8 @@ public class AltosCSV implements AltosWriter {
                out.printf("connected,locked,nsat,latitude,longitude,altitude,year,month,day,hour,minute,second,pad_dist,pad_range,pad_az,pad_el,hdop");
        }
 
-       void write_gps(AltosRecord record) {
-               AltosGPS        gps = record.gps;
+       void write_gps(AltosState state) {
+               AltosGPS        gps = state.gps;
                if (gps == null)
                        gps = new AltosGPS();
 
@@ -170,7 +170,7 @@ public class AltosCSV implements AltosWriter {
                if (from_pad == null)
                        from_pad = new AltosGreatCircle();
 
-               out.printf("%2d,%2d,%3d,%12.7f,%12.7f,%6d,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f,%6.1f",
+               out.printf("%2d,%2d,%3d,%12.7f,%12.7f,%8.1f,%5d,%3d,%3d,%3d,%3d,%3d,%9.0f,%9.0f,%4.0f,%4.0f,%6.1f",
                           gps.connected?1:0,
                           gps.locked?1:0,
                           gps.nsat,
@@ -198,8 +198,8 @@ public class AltosCSV implements AltosWriter {
                }
        }
 
-       void write_gps_sat(AltosRecord record) {
-               AltosGPS        gps = record.gps;
+       void write_gps_sat(AltosState state) {
+               AltosGPS        gps = state.gps;
                for(int i = 1; i <= 32; i++) {
                        int     c_n0 = 0;
                        if (gps != null && gps.cc_gps_sat != null) {
@@ -221,8 +221,8 @@ public class AltosCSV implements AltosWriter {
                        out.printf(",companion_%02d", i);
        }
 
-       void write_companion(AltosRecord record) {
-               AltosRecordCompanion companion = record.companion;
+       void write_companion(AltosState state) {
+               AltosCompanion companion = state.companion;
 
                int     channels_written = 0;
                if (companion == null) {
@@ -256,50 +256,49 @@ public class AltosCSV implements AltosWriter {
                out.printf ("\n");
        }
 
-       void write_one(AltosRecord record) {
-               state = new AltosState(record, state);
-               write_general(record); out.printf(",");
-               write_flight(record); out.printf(",");
-               write_basic(record); out.printf(",");
-               if (record.imu() != null || record.mag() != null)
-                       write_advanced(record);
-               if (record.gps != null) {
+       void write_one(AltosState state) {
+               write_general(state); out.printf(",");
+               write_flight(state); out.printf(",");
+               write_basic(state); out.printf(",");
+               if (state.imu != null || state.mag != null)
+                       write_advanced(state);
+               if (state.gps != null) {
                        out.printf(",");
-                       write_gps(record); out.printf(",");
-                       write_gps_sat(record);
+                       write_gps(state); out.printf(",");
+                       write_gps_sat(state);
                }
-               if (record.companion != null) {
+               if (state.companion != null) {
                        out.printf(",");
-                       write_companion(record);
+                       write_companion(state);
                }
                out.printf ("\n");
        }
 
        void flush_pad() {
-               while (!pad_records.isEmpty()) {
-                       write_one (pad_records.remove());
+               while (!pad_states.isEmpty()) {
+                       write_one (pad_states.remove());
                }
        }
 
-       public void write(AltosRecord record) {
-               if (record.state == Altos.ao_flight_startup)
+       public void write(AltosState state) {
+               if (state.state == Altos.ao_flight_startup)
                        return;
                if (!header_written) {
-                       write_header(record.imu() != null || record.mag() != null,
-                                    record.gps != null, record.companion != null);
+                       write_header(state.imu != null || state.mag != null,
+                                    state.gps != null, state.companion != null);
                        header_written = true;
                }
                if (!seen_boost) {
-                       if (record.state >= Altos.ao_flight_boost) {
+                       if (state.state >= Altos.ao_flight_boost) {
                                seen_boost = true;
-                               boost_tick = record.tick;
+                               boost_tick = state.tick;
                                flush_pad();
                        }
                }
                if (seen_boost)
-                       write_one(record);
+                       write_one(state);
                else
-                       pad_records.add(record);
+                       pad_states.add(state);
        }
 
        public PrintStream out() {
@@ -307,23 +306,23 @@ public class AltosCSV implements AltosWriter {
        }
 
        public void close() {
-               if (!pad_records.isEmpty()) {
-                       boost_tick = pad_records.element().tick;
+               if (!pad_states.isEmpty()) {
+                       boost_tick = pad_states.element().tick;
                        flush_pad();
                }
                out.close();
        }
 
-       public void write(AltosRecordIterable iterable) {
-               iterable.write_comments(out());
-               for (AltosRecord r : iterable)
-                       write(r);
+       public void write(AltosStateIterable states) {
+               states.write_comments(out());
+               for (AltosState state : states)
+                       write(state);
        }
 
        public AltosCSV(PrintStream in_out, File in_name) {
                name = in_name;
                out = in_out;
-               pad_records = new LinkedList<AltosRecord>();
+               pad_states = new LinkedList<AltosState>();
        }
 
        public AltosCSV(File in_name) throws FileNotFoundException {
index 4250834691755ad725dd948d98deedb7b6030a38..c41ea74b5190dba3a7c5868db374cfec20db9613 100644 (file)
@@ -21,7 +21,7 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosCSVUI
@@ -31,7 +31,7 @@ public class AltosCSVUI
        JFileChooser            csv_chooser;
        JPanel                  accessory;
        JComboBox               combo_box;
-       AltosRecordIterable     iterable;
+       Iterable<AltosState>    states;
        AltosWriter             writer;
 
        static String[]         combo_box_items = { "Comma Separated Values (.CSV)", "Googleearth Data (.KML)" };
@@ -55,8 +55,8 @@ public class AltosCSVUI
                        set_default_file();
        }
 
-       public AltosCSVUI(JFrame frame, AltosRecordIterable in_iterable, File source_file) {
-               iterable = in_iterable;
+       public AltosCSVUI(JFrame frame, AltosStateIterable states, File source_file) {
+               this.states = states;
                csv_chooser = new JFileChooser(source_file);
 
                accessory = new JPanel();
@@ -91,7 +91,7 @@ public class AltosCSVUI
                                        writer = new AltosCSV(file);
                                else
                                        writer = new AltosKML(file);
-                               writer.write(iterable);
+                               writer.write(states);
                                writer.close();
                        } catch (FileNotFoundException ee) {
                                JOptionPane.showMessageDialog(frame,
index ebe1d1f9826612cf004d23d224010da50d515aef..1f446700218827c64ff1ff6673df8cf1654f2156 100644 (file)
@@ -19,7 +19,7 @@ package altosui;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosCompanionInfo extends JTable {
        private AltosFlightInfoTableModel model;
@@ -70,13 +70,13 @@ public class AltosCompanionInfo extends JTable {
                model.clear();
        }
 
-       AltosRecordCompanion    companion;
+       AltosCompanion  companion;
 
        public String board_name() {
                if (companion == null)
                        return "None";
                switch (companion.board_id) {
-               case AltosRecordCompanion.board_id_telescience:
+               case AltosCompanion.board_id_telescience:
                        return "TeleScience";
                default:
                        return String.format("%02x\n", companion.board_id);
@@ -86,8 +86,8 @@ public class AltosCompanionInfo extends JTable {
        public void show(AltosState state, AltosListenerState listener_state) {
                if (state == null)
                        return;
-               if (state.data.companion != null)
-                       companion = state.data.companion;
+               if (state.companion != null)
+                       companion = state.companion;
                info_reset();
                info_add_row(0, "Companion board", "%s", board_name());
                if (companion != null) {
index 4927d3f822e0ad9b73fc2cf6c1fab9c9137eb456..206cbee3e57bf2fd718d124f09da374ad2b167fd 100644 (file)
@@ -22,7 +22,7 @@ import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.text.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosConfig implements ActionListener {
@@ -161,9 +161,9 @@ public class AltosConfig implements ActionListener {
                        } finally {
                                try {
                                        stop_serial();
+                                       serial_line.close();
                                } catch (InterruptedException ie) {
                                }
-                               serial_line.close();
                        }
                }
 
index c90b168f3359ff236f368d08564f0d97e83f6dcd..555af3b6b69ffdc8c12abd03f4dcbd8de98a384e 100644 (file)
@@ -21,7 +21,7 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 class AltosEditFreqUI extends AltosUIDialog implements ActionListener {
index 3cac56c3a576425f2d826c43bf9e3e91aebe21fc..81d121119acce8c580343078132213a95f9a9bd5 100644 (file)
@@ -21,12 +21,12 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.event.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosConfigPyroUI
        extends AltosUIDialog
-       implements ItemListener, DocumentListener
+       implements ItemListener, DocumentListener, AltosUnitsListener
 {
        AltosConfigUI   owner;
        Container       pane;
@@ -45,13 +45,14 @@ public class AltosConfigPyroUI
                }
        }
 
-       class PyroItem implements ItemListener, DocumentListener
+       class PyroItem implements ItemListener, DocumentListener, AltosUnitsListener
        {
                public int              flag;
                public JRadioButton     enable;
                public JTextField       value;
                public JComboBox        combo;
                AltosConfigPyroUI       ui;
+               boolean                 setting;
 
                public void set_enable(boolean enable) {
                        if (value != null)
@@ -62,36 +63,59 @@ public class AltosConfigPyroUI
 
                public void itemStateChanged(ItemEvent e) {
                        set_enable(enable.isSelected());
-                       ui.set_dirty();
+                       if (!setting) 
+                               ui.set_dirty();
                }
 
                public void changedUpdate(DocumentEvent e) {
-                       ui.set_dirty();
+                       if (!setting) 
+                               ui.set_dirty();
                }
 
                public void insertUpdate(DocumentEvent e) {
-                       ui.set_dirty();
+                       if (!setting) 
+                               ui.set_dirty();
                }
 
                public void removeUpdate(DocumentEvent e) {
-                       ui.set_dirty();
+                       if (!setting) 
+                               ui.set_dirty();
+               }
+
+               public void units_changed(boolean imperial_units) {
+                       AltosUnits units = AltosPyro.pyro_to_units(flag);
+
+                       if (units != null) {
+                               try {
+                                       double v = units.parse(value.getText(), !imperial_units);
+                                       set(enabled(), v);
+                               } catch (NumberFormatException ne) {
+                                       set(enabled(), 0.0);
+                               }
+                       }
                }
 
                public void set(boolean new_enable, double new_value) {
+                       setting = true;
                        enable.setSelected(new_enable);
                        set_enable(new_enable);
                        if (value != null) {
                                double  scale = AltosPyro.pyro_to_scale(flag);
+                               double  unit_value = new_value;
+                               AltosUnits units = AltosPyro.pyro_to_units(flag);
+                               if (units != null)
+                                       unit_value = units.value(new_value);
                                String  format = "%6.0f";
                                if (scale >= 10)
                                        format = "%6.1f";
                                else if (scale >= 100)
                                        format = "%6.2f";
-                               value.setText(String.format(format, new_value));
+                               value.setText(String.format(format, unit_value));
                        }
                        if (combo != null)
                                if (new_value >= AltosLib.ao_flight_boost && new_value <= AltosLib.ao_flight_landed)
                                        combo.setSelectedIndex((int) new_value - AltosLib.ao_flight_boost);
+                       setting = false;
                }
 
                public boolean enabled() {
@@ -99,8 +123,12 @@ public class AltosConfigPyroUI
                }
 
                public double value() {
-                       if (value != null)
+                       if (value != null) {
+                               AltosUnits units = AltosPyro.pyro_to_units(flag);
+                               if (units != null)
+                                       return units.parse(value.getText());
                                return Double.parseDouble(value.getText());
+                       }
                        if (combo != null)
                                return combo.getSelectedIndex() + AltosLib.ao_flight_boost;
                        return 0;
@@ -143,7 +171,7 @@ public class AltosConfigPyroUI
                }
        }
 
-       class PyroColumn {
+       class PyroColumn implements AltosUnitsListener {
                public PyroItem[]       items;
                public JLabel           label;
                int                     channel;
@@ -166,17 +194,25 @@ public class AltosConfigPyroUI
                        for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
                                if ((AltosPyro.pyro_all & flag) != 0) {
                                        if (items[row].enabled()) {
-                                               System.out.printf ("Flag %x enabled\n", flag);
                                                p.flags |= flag;
                                                p.set_value(flag, items[row].value());
                                        }
                                        row++;
                                }
                        }
-                       System.out.printf ("Pyro %x %s\n", p.flags, p.toString());
                        return p;
                }
 
+               public void units_changed(boolean imperial_units) {
+                       int row = 0;
+                       for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
+                               if ((AltosPyro.pyro_all & flag) != 0) {
+                                       items[row].units_changed(imperial_units);
+                                       row++;
+                               }
+                       }
+               }
+
                public PyroColumn(AltosConfigPyroUI ui, int x, int y, int in_channel) {
 
                        channel = in_channel;
@@ -209,6 +245,7 @@ public class AltosConfigPyroUI
        }
 
        PyroColumn[]    columns;
+       JLabel[]        labels;
 
        public void set_pyros(AltosPyro[] pyros) {
                for (int i = 0; i < pyros.length; i++) {
@@ -244,6 +281,34 @@ public class AltosConfigPyroUI
                owner.set_dirty();
        }
 
+       public void units_changed(boolean imperial_units) {
+               for (int c = 0; c < columns.length; c++)
+                       columns[c].units_changed(imperial_units);
+               int r = 0;
+               for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {
+                       String n = AltosPyro.pyro_to_name(flag);
+                       if (n != null) {
+                               labels[r].setText(n);
+                               r++;
+                       }
+               }
+       }
+
+       /* A window listener to catch closing events and tell the config code */
+       class ConfigListener extends WindowAdapter {
+               AltosConfigPyroUI       ui;
+               AltosConfigUI           owner;
+
+               public ConfigListener(AltosConfigPyroUI this_ui, AltosConfigUI this_owner) {
+                       ui = this_ui;
+                       owner = this_owner;
+               }
+
+               public void windowClosing(WindowEvent e) {
+                       ui.setVisible(false);
+               }
+       }
+
        public AltosConfigPyroUI(AltosConfigUI in_owner, AltosPyro[] pyros) {
 
                super(in_owner, "Configure Pyro Channels", false);
@@ -255,6 +320,13 @@ public class AltosConfigPyroUI
                pane = getContentPane();
                pane.setLayout(new GridBagLayout());
 
+               int     nrow = 0;
+               for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
+                       if ((flag & AltosPyro.pyro_all) != 0)
+                               nrow++;
+
+               labels = new JLabel[nrow];
+
                int     row = 1;
 
                for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {
@@ -270,6 +342,7 @@ public class AltosConfigPyroUI
                                c.insets = il;
                                JLabel label = new JLabel(n);
                                pane.add(label, c);
+                               labels[row-1] = label;
                                row++;
                        }
                }
@@ -280,6 +353,13 @@ public class AltosConfigPyroUI
                        columns[i] = new PyroColumn(this, i*2 + 1, 0, i);
                        columns[i].set(pyros[i]);
                }
+               addWindowListener(new ConfigListener(this, owner));
+               AltosPreferences.register_units_listener(this);
+       }
+
+       public void dispose() {
+               AltosPreferences.unregister_units_listener(this);
+               super.dispose();
        }
 
        public void make_visible() {
index 16c9e357134c58ded5f2a8e545c3f902781669ac..f879ff88bcdef1324db4714e8e16a7a0c9487cd1 100644 (file)
@@ -21,7 +21,7 @@ import java.awt.event.*;
 import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosConfigTD implements ActionListener {
index 125780a99f9813c723677080e4802c8b383eb36e..b5a6cd7c3fdd8ee6a355bb3d5daeea882722ac98 100644 (file)
@@ -21,7 +21,7 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.event.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosConfigTDUI
index 11f405938ba385118eed7bbf57c6665f20d93b55..a7d95903ae25d828dc14c214419ed492fdcf3e38 100644 (file)
@@ -21,12 +21,12 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.event.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosConfigUI
        extends AltosUIDialog
-       implements ActionListener, ItemListener, DocumentListener, AltosConfigValues
+       implements ActionListener, ItemListener, DocumentListener, AltosConfigValues, AltosUnitsListener
 {
 
        Container       pane;
@@ -75,11 +75,16 @@ public class AltosConfigUI
 
        ActionListener  listener;
 
-       static String[] main_deploy_values = {
+       static String[] main_deploy_values_m = {
                "100", "150", "200", "250", "300", "350",
                "400", "450", "500"
        };
 
+       static String[] main_deploy_values_ft = {
+               "250", "500", "750", "1000", "1250", "1500",
+               "1750", "2000"
+       };
+
        static String[] apogee_delay_values = {
                "0", "1", "2", "3", "4", "5"
        };
@@ -180,7 +185,7 @@ public class AltosConfigUI
 
        void set_pad_orientation_tool_tip() {
                if (pad_orientation_value.isEnabled())
-                       pad_orientation_value.setToolTipText("How will TeleMetrum be mounted in the airframe");
+                       pad_orientation_value.setToolTipText("How will the computer be mounted in the airframe");
                else {
                        if (is_telemetrum())
                                pad_orientation_value.setToolTipText("Older TeleMetrum firmware must fly antenna forward");
@@ -193,7 +198,7 @@ public class AltosConfigUI
 
        /* Build the UI using a grid bag */
        public AltosConfigUI(JFrame in_owner, boolean remote) {
-               super (in_owner, "Configure TeleMetrum", false);
+               super (in_owner, "Configure Flight Computer", false);
 
                owner = in_owner;
                GridBagConstraints c;
@@ -280,7 +285,7 @@ public class AltosConfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = il;
                c.ipady = 5;
-               main_deploy_label = new JLabel("Main Deploy Altitude(m):");
+               main_deploy_label = new JLabel(get_main_deploy_label());
                pane.add(main_deploy_label, c);
 
                c = new GridBagConstraints();
@@ -291,7 +296,7 @@ public class AltosConfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = ir;
                c.ipady = 5;
-               main_deploy_value = new JComboBox(main_deploy_values);
+               main_deploy_value = new JComboBox(main_deploy_values());
                main_deploy_value.setEditable(true);
                main_deploy_value.addItemListener(this);
                pane.add(main_deploy_value, c);
@@ -616,6 +621,7 @@ public class AltosConfigUI
                close.setActionCommand("Close");
 
                addWindowListener(new ConfigListener(this));
+               AltosPreferences.register_units_listener(this);
        }
 
        /* Once the initial values are set, the config code will show the dialog */
@@ -654,15 +660,22 @@ public class AltosConfigUI
 
        AltosConfigPyroUI       pyro_ui;
 
+       public void dispose() {
+               if (pyro_ui != null)
+                       pyro_ui.dispose();
+               AltosPreferences.unregister_units_listener(this);
+               super.dispose();
+       }
+
        /* Listen for events from our buttons */
        public void actionPerformed(ActionEvent e) {
                String  cmd = e.getActionCommand();
 
                if (cmd.equals("Pyro")) {
-                       if (pyro_ui == null && pyros != null) {
+                       if (pyro_ui == null && pyros != null)
                                pyro_ui = new AltosConfigPyroUI(this, pyros);
+                       if (pyro_ui != null)
                                pyro_ui.make_visible();
-                       }
                        return;
                }
 
@@ -718,12 +731,40 @@ public class AltosConfigUI
        }
 
        public void set_main_deploy(int new_main_deploy) {
-               main_deploy_value.setSelectedItem(Integer.toString(new_main_deploy));
+               main_deploy_value.setSelectedItem(AltosConvert.height.say(new_main_deploy));
                main_deploy_value.setEnabled(new_main_deploy >= 0);
        }
 
        public int main_deploy() {
-               return Integer.parseInt(main_deploy_value.getSelectedItem().toString());
+               return (int) (AltosConvert.height.parse(main_deploy_value.getSelectedItem().toString()) + 0.5);
+       }
+
+       String get_main_deploy_label() {
+               return String.format("Main Deploy Altitude(%s):", AltosConvert.height.show_units());
+       }
+       
+       String[] main_deploy_values() {
+               if (AltosConvert.imperial_units)
+                       return main_deploy_values_ft;
+               else
+                       return main_deploy_values_m;
+       }
+                       
+       void set_main_deploy_values() {
+               String[]        v = main_deploy_values();
+               while (main_deploy_value.getItemCount() > 0)
+                       main_deploy_value.removeItemAt(0);
+               for (int i = 0; i < v.length; i++)
+                       main_deploy_value.addItem(v[i]);
+               main_deploy_value.setMaximumRowCount(v.length);
+       }
+       
+       public void units_changed(boolean imperial_units) {
+               String v = main_deploy_value.getSelectedItem().toString();
+               main_deploy_label.setText(get_main_deploy_label());
+               set_main_deploy_values();
+               int m = (int) (AltosConvert.height.parse(v, !imperial_units) + 0.5);
+               set_main_deploy(m);
        }
 
        public void set_apogee_delay(int new_apogee_delay) {
@@ -745,28 +786,7 @@ public class AltosConfigUI
        }
 
        public void set_radio_frequency(double new_radio_frequency) {
-               int i;
-               for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
-                       AltosFrequency  f = (AltosFrequency) radio_frequency_value.getItemAt(i);
-                       
-                       if (f.close(new_radio_frequency)) {
-                               radio_frequency_value.setSelectedIndex(i);
-                               return;
-                       }
-               }
-               for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
-                       AltosFrequency  f = (AltosFrequency) radio_frequency_value.getItemAt(i);
-                       
-                       if (new_radio_frequency < f.frequency)
-                               break;
-               }
-               String  description = String.format("%s serial %s",
-                                                   product_value.getText(),
-                                                   serial_value.getText());
-               AltosFrequency  new_frequency = new AltosFrequency(new_radio_frequency, description);
-               AltosUIPreferences.add_common_frequency(new_frequency);
-               radio_frequency_value.insertItemAt(new_frequency, i);
-               radio_frequency_value.setSelectedIndex(i);
+               radio_frequency_value.set_frequency(new_radio_frequency);
        }
 
        public double radio_frequency() {
@@ -774,7 +794,11 @@ public class AltosConfigUI
        }
 
        public void set_radio_calibration(int new_radio_calibration) {
-               radio_calibration_value.setText(String.format("%d", new_radio_calibration));
+               radio_calibration_value.setVisible(new_radio_calibration >= 0);
+               if (new_radio_calibration < 0)
+                       radio_calibration_value.setText("Disabled");
+               else
+                       radio_calibration_value.setText(String.format("%d", new_radio_calibration));
        }
 
        public int radio_calibration() {
@@ -787,6 +811,7 @@ public class AltosConfigUI
                        radio_enable_value.setEnabled(true);
                } else {
                        radio_enable_value.setSelected(true);
+                       radio_enable_value.setVisible(radio_frequency() > 0);
                        radio_enable_value.setEnabled(false);
                }
                set_radio_enable_tool_tip();
@@ -800,6 +825,7 @@ public class AltosConfigUI
        }
 
        public void set_callsign(String new_callsign) {
+               callsign_value.setVisible(new_callsign != null);
                callsign_value.setText(new_callsign);
        }
 
@@ -859,10 +885,10 @@ public class AltosConfigUI
                if (new_pad_orientation >= pad_orientation_values.length)
                        new_pad_orientation = 0;
                if (new_pad_orientation < 0) {
-                       pad_orientation_value.setEnabled(false);
+                       pad_orientation_value.setVisible(false);
                        new_pad_orientation = 0;
                } else {
-                       pad_orientation_value.setEnabled(true);
+                       pad_orientation_value.setVisible(true);
                }
                pad_orientation_value.setSelectedIndex(new_pad_orientation);
                set_pad_orientation_tool_tip();
@@ -877,7 +903,7 @@ public class AltosConfigUI
 
        public void set_pyros(AltosPyro[] new_pyros) {
                pyros = new_pyros;
-               pyro.setEnabled(pyros != null);
+               pyro.setVisible(pyros != null);
                if (pyros != null && pyro_ui != null)
                        pyro_ui.set_pyros(pyros);
        }
@@ -896,7 +922,7 @@ public class AltosConfigUI
                else
                        s = Integer.toString(new_aprs_interval);
                aprs_interval_value.setSelectedItem(s);
-               aprs_interval_value.setEnabled(new_aprs_interval >= 0);
+               aprs_interval_value.setVisible(new_aprs_interval >= 0);
                set_aprs_interval_tool_tip();
        }
 
index f914f138f2fe7d2e2d116744a343910283ad8cc9..c0d6668279574e051dfafdf0dce2e097b12016f4 100644 (file)
@@ -20,7 +20,7 @@ package altosui;
 import javax.swing.*;
 import javax.swing.filechooser.FileNameExtensionFilter;
 import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosDataChooser extends JFileChooser {
@@ -36,7 +36,7 @@ public class AltosDataChooser extends JFileChooser {
                return file;
        }
 
-       public AltosRecordIterable runDialog() {
+       public AltosStateIterable runDialog() {
                int     ret;
 
                ret = showOpenDialog(frame);
@@ -48,13 +48,10 @@ public class AltosDataChooser extends JFileChooser {
                        try {
                                if (filename.endsWith("eeprom")) {
                                        FileInputStream in = new FileInputStream(file);
-                                       return new AltosEepromIterable(in);
+                                       return new AltosEepromFile(in);
                                } else if (filename.endsWith("telem")) {
                                        FileInputStream in = new FileInputStream(file);
-                                       return new AltosTelemetryIterable(in);
-                               } else if (filename.endsWith("mega")) {
-                                       FileInputStream in = new FileInputStream(file);
-                                       return new AltosEepromMegaIterable(in);
+                                       return new AltosTelemetryFile(in);
                                } else {
                                        throw new FileNotFoundException();
                                }
@@ -77,8 +74,10 @@ public class AltosDataChooser extends JFileChooser {
                                                          "telem"));
                setFileFilter(new FileNameExtensionFilter("TeleMega eeprom file",
                                                          "mega"));
+               setFileFilter(new FileNameExtensionFilter("EasyMini eeprom file",
+                                                         "mini"));
                setFileFilter(new FileNameExtensionFilter("Flight data file",
-                                                         "telem", "eeprom", "mega"));
+                                                         "telem", "eeprom", "mega", "mini"));
                setCurrentDirectory(AltosUIPreferences.logdir());
        }
 }
index 29d33ddc9afac6085b9426bb8b37928274892987..e73d990cb5ccde177ee73e818ae5514b30195c6a 100644 (file)
@@ -19,7 +19,7 @@ package altosui;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosDescent extends JComponent implements AltosFlightDisplay {
        GridBagLayout   layout;
@@ -245,7 +245,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
 
        class Height extends DescentValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.height, state.height);
+                       show(AltosConvert.height, state.height());
                }
                public Height (GridBagLayout layout, int x, int y) {
                        super (layout, x, y, "Height");
@@ -256,10 +256,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
 
        class Speed extends DescentValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       double speed = state.accel_speed;
-                       if (!state.ascent)
-                               speed = state.baro_speed;
-                       show(AltosConvert.speed, speed);
+                       show(AltosConvert.speed, state.speed());
                }
                public Speed (GridBagLayout layout, int x, int y) {
                        super (layout, x, y, "Speed");
@@ -281,7 +278,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
 
        class Lat extends DescentValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state.gps != null && state.gps.connected)
+                       if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
                                show(pos(state.gps.lat,"N", "S"));
                        else
                                show("???");
@@ -295,7 +292,7 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
 
        class Lon extends DescentValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state.gps != null && state.gps.connected)
+                       if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
                                show(pos(state.gps.lon,"W", "E"));
                        else
                                show("???");
@@ -325,8 +322,8 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
 
        class Apogee extends DescentStatus {
                void show (AltosState state, AltosListenerState listener_state) {
-                       show("%4.2f V", state.drogue_sense);
-                       lights.set(state.drogue_sense > 3.2);
+                       show("%4.2f V", state.apogee_voltage);
+                       lights.set(state.apogee_voltage >= AltosLib.ao_igniter_good);
                }
                public Apogee (GridBagLayout layout, int y) {
                        super(layout, y, "Apogee Igniter Voltage");
@@ -337,8 +334,8 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
 
        class Main extends DescentStatus {
                void show (AltosState state, AltosListenerState listener_state) {
-                       show("%4.2f V", state.main_sense);
-                       lights.set(state.main_sense > 3.2);
+                       show("%4.2f V", state.main_voltage);
+                       lights.set(state.main_voltage >= AltosLib.ao_igniter_good);
                }
                public Main (GridBagLayout layout, int y) {
                        super(layout, y, "Main Igniter Voltage");
@@ -430,11 +427,11 @@ public class AltosDescent extends JComponent implements AltosFlightDisplay {
                        lat.hide();
                        lon.hide();
                }
-               if (state.main_sense != AltosRecord.MISSING)
+               if (state.main_voltage != AltosLib.MISSING)
                        main.show(state, listener_state);
                else
                        main.hide();
-               if (state.drogue_sense != AltosRecord.MISSING)
+               if (state.apogee_voltage != AltosLib.MISSING)
                        apogee.show(state, listener_state);
                else
                        apogee.hide();
index 095bed992c08c524d5718e21066ece2b20ad5df6..4b4cc3b9ac2aee901b5e633228eb2142b15ad4e9 100644 (file)
@@ -21,7 +21,7 @@ import java.awt.*;
 import javax.swing.*;
 import java.io.*;
 import java.text.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosDisplayThread extends Thread {
 
@@ -89,17 +89,18 @@ public class AltosDisplayThread extends Thread {
                        /* If the rocket isn't on the pad, then report height */
                        if (Altos.ao_flight_drogue <= state.state &&
                            state.state < Altos.ao_flight_landed &&
+                           state.from_pad != null &&
                            state.range >= 0)
                        {
                                voice.speak("Height %s, bearing %s %d, elevation %d, range %s.\n",
-                                           AltosConvert.height.say(state.height),
+                                           AltosConvert.height.say(state.height()),
                                            state.from_pad.bearing_words(
                                                    AltosGreatCircle.BEARING_VOICE),
                                            (int) (state.from_pad.bearing + 0.5),
                                            (int) (state.elevation + 0.5),
                                            AltosConvert.distance.say(state.range));
                        } else if (state.state > Altos.ao_flight_pad) {
-                               voice.speak(AltosConvert.height.say_units(state.height));
+                               voice.speak(AltosConvert.height.say_units(state.height()));
                        } else {
                                reported_landing = 0;
                        }
@@ -110,10 +111,10 @@ public class AltosDisplayThread extends Thread {
                         */
                        if (state.state >= Altos.ao_flight_drogue &&
                            (last ||
-                            System.currentTimeMillis() - state.report_time >= 15000 ||
+                            System.currentTimeMillis() - state.received_time >= 15000 ||
                             state.state == Altos.ao_flight_landed))
                        {
-                               if (Math.abs(state.baro_speed) < 20 && state.height < 100)
+                               if (Math.abs(state.speed()) < 20 && state.height() < 100)
                                        voice.speak("rocket landed safely");
                                else
                                        voice.speak("rocket may have crashed");
@@ -181,16 +182,16 @@ public class AltosDisplayThread extends Thread {
        synchronized boolean tell() {
                boolean ret = false;
                if (old_state == null || old_state.state != state.state) {
-                       voice.speak(state.data.state());
+                       voice.speak(state.state_name());
                        if ((old_state == null || old_state.state <= Altos.ao_flight_boost) &&
                            state.state > Altos.ao_flight_boost) {
                                voice.speak("max speed: %s.",
-                                           AltosConvert.speed.say_units(state.max_accel_speed + 0.5));
+                                           AltosConvert.speed.say_units(state.max_speed() + 0.5));
                                ret = true;
                        } else if ((old_state == null || old_state.state < Altos.ao_flight_drogue) &&
                                   state.state >= Altos.ao_flight_drogue) {
                                voice.speak("max height: %s.",
-                                           AltosConvert.height.say_units(state.max_height + 0.5));
+                                           AltosConvert.height.say_units(state.max_height() + 0.5));
                                ret = true;
                        }
                }
@@ -218,11 +219,9 @@ public class AltosDisplayThread extends Thread {
                try {
                        for (;;) {
                                try {
-                                       AltosRecord record = reader.read();
-                                       if (record == null)
+                                       state = reader.read();
+                                       if (state == null)
                                                break;
-                                       old_state = state;
-                                       state = new AltosState(record, state);
                                        reader.update(state);
                                        show_safely();
                                        told = tell();
index e81a35d1133fd0249581fced0298b2780f18dc0b..9984d1a2420d37fe247688ab0c735e853967b26b 100644 (file)
@@ -21,7 +21,7 @@ import java.awt.event.*;
 import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosEepromDelete implements Runnable {
        AltosEepromList         flights;
diff --git a/altosui/AltosEepromDownload.java b/altosui/AltosEepromDownload.java
deleted file mode 100644 (file)
index a0523b5..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- * 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; 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.
- */
-
-package altosui;
-
-import java.awt.event.*;
-import javax.swing.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
-
-public class AltosEepromDownload implements Runnable {
-
-       JFrame                  frame;
-       AltosSerial             serial_line;
-       boolean                 remote;
-       Thread                  eeprom_thread;
-       AltosEepromMonitor      monitor;
-
-       int                     flight;
-       int                     serial;
-       int                     year, month, day;
-       boolean                 want_file;
-       FileWriter              eeprom_file;
-       LinkedList<String>      eeprom_pending;
-
-       AltosEepromList         flights;
-       ActionListener          listener;
-       boolean                 success;
-       ParseException          parse_exception;
-       String                  extension;
-
-       private void FlushPending() throws IOException {
-               for (String s : flights.config_data) {
-                       eeprom_file.write(s);
-                       eeprom_file.write('\n');
-               }
-
-               for (String s : eeprom_pending)
-                       eeprom_file.write(s);
-       }
-
-       private void CheckFile(boolean force) throws IOException {
-               if (eeprom_file != null)
-                       return;
-               if (force || (flight != 0 && want_file)) {
-                       AltosFile               eeprom_name;
-
-                       if (extension == null)
-                               extension = "data";
-                       if (year != 0 && month != 0 && day != 0)
-                               eeprom_name = new AltosFile(year, month, day, serial, flight, extension);
-                       else
-                               eeprom_name = new AltosFile(serial, flight, extension);
-
-                       eeprom_file = new FileWriter(eeprom_name);
-                       if (eeprom_file != null) {
-                               monitor.set_file(eeprom_name.getName());
-                               FlushPending();
-                               eeprom_pending = null;
-                       }
-               }
-       }
-
-       void Log(AltosEepromRecord r) throws IOException {
-               if (r.cmd != Altos.AO_LOG_INVALID) {
-                       String log_line = String.format("%c %4x %4x %4x\n",
-                                                       r.cmd, r.tick, r.a, r.b);
-                       if (eeprom_file != null)
-                               eeprom_file.write(log_line);
-                       else
-                               eeprom_pending.add(log_line);
-               }
-       }
-
-       void set_serial(int in_serial) {
-               serial = in_serial;
-               monitor.set_serial(serial);
-       }
-
-       void set_flight(int in_flight) {
-               flight = in_flight;
-               monitor.set_flight(flight);
-       }
-               
-       boolean                 done;
-       int                     state;
-
-       void CaptureFull(AltosEepromChunk eechunk) throws IOException {
-               boolean any_valid = false;
-
-               extension = "eeprom";
-               set_serial(flights.config_data.serial);
-               for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += AltosEepromRecord.record_length) {
-                       try {
-                               AltosEepromRecord r = new AltosEepromRecord(eechunk, i);
-                               if (r.cmd == Altos.AO_LOG_FLIGHT)
-                                       set_flight(r.b);
-
-                               /* Monitor state transitions to update display */
-                               if (r.cmd == Altos.AO_LOG_STATE && r.a <= Altos.ao_flight_landed) {
-                                       state = r.a;
-                                       if (state > Altos.ao_flight_pad)
-                                               want_file = true;
-                               }
-
-                               if (r.cmd == Altos.AO_LOG_GPS_DATE) {
-                                       year = 2000 + (r.a & 0xff);
-                                       month = (r.a >> 8) & 0xff;
-                                       day = (r.b & 0xff);
-                                       want_file = true;
-                               }
-                               if (r.cmd == Altos.AO_LOG_STATE && r.a == Altos.ao_flight_landed)
-                                       done = true;
-                               if (r.cmd != AltosLib.AO_LOG_INVALID)
-                                       any_valid = true;
-                               Log(r);
-                       } catch (ParseException pe) {
-                               if (parse_exception == null)
-                                       parse_exception = pe;
-                       }
-               }
-
-               if (!any_valid)
-                       done = true;
-
-               CheckFile(false);
-       }
-
-       boolean start;
-       int     tiny_tick;
-
-       void CaptureTiny (AltosEepromChunk eechunk) throws IOException {
-               boolean any_valid = false;
-
-               extension = "eeprom";
-               set_serial(flights.config_data.serial);
-               for (int i = 0; i < eechunk.data.length && !done; i += 2) {
-                       int                     v = eechunk.data16(i);
-                       AltosEepromRecord       r;
-
-                       if (i == 0 && start) {
-                               tiny_tick = 0;
-                               start = false;
-                               set_flight(v);
-                               r = new AltosEepromRecord(Altos.AO_LOG_FLIGHT, tiny_tick, 0, v);
-                               any_valid = true;
-                       } else {
-                               int     s = v ^ 0x8000;
-
-                               if (Altos.ao_flight_startup <= s && s <= Altos.ao_flight_invalid) {
-                                       state = s;
-                                       r = new AltosEepromRecord(Altos.AO_LOG_STATE, tiny_tick, state, 0);
-                                       if (state == Altos.ao_flight_landed)
-                                               done = true;
-                                       state = s;
-                                       any_valid = true;
-                               } else {
-                                       if (v != 0xffff)
-                                               any_valid = true;
-
-                                       r = new AltosEepromRecord(Altos.AO_LOG_PRESSURE, tiny_tick, 0, v);
-
-                                       /*
-                                        * The flight software records ascent data every 100ms, and descent
-                                        * data every 1s.
-                                        */
-                                       if (state < Altos.ao_flight_drogue)
-                                               tiny_tick += 10;
-                                       else
-                                               tiny_tick += 100;
-                               }
-                       }
-                       Log(r);
-               }
-               CheckFile(false);
-               if (!any_valid)
-                       done = true;
-       }
-
-       void LogTeleScience(AltosEepromTeleScience r) throws IOException {
-               if (r.type != Altos.AO_LOG_INVALID) {
-                       String log_line = String.format("%c %4x %4x %d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n",
-                                                       r.type, r.tick, r.tm_tick, r.tm_state,
-                                                       r.data[0], r.data[1], r.data[2], r.data[3], 
-                                                       r.data[4], r.data[5], r.data[6], r.data[7], 
-                                                       r.data[8], r.data[9], r.data[10], r.data[11]);
-                       if (eeprom_file != null)
-                               eeprom_file.write(log_line);
-                       else
-                               eeprom_pending.add(log_line);
-               }
-       }
-       
-       boolean telescience_start;
-
-       void CaptureTeleScience (AltosEepromChunk eechunk) throws IOException {
-               boolean any_valid = false;
-
-               extension = "science";
-               for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += AltosEepromTeleScience.record_length) {
-                       try {
-                               AltosEepromTeleScience r = new AltosEepromTeleScience(eechunk, i);
-                               if (r.type == AltosEepromTeleScience.AO_LOG_TELESCIENCE_START) {
-                                       if (telescience_start) {
-                                               done = true;
-                                               break;
-                                       }
-                                       set_serial(r.data[0]);
-                                       set_flight(r.data[1]);
-                                       telescience_start = true;
-                               } else {
-                                       if (!telescience_start)
-                                               break;
-                               }
-                               state = r.tm_state;
-                               want_file =true;
-                               any_valid = true;
-                               LogTeleScience(r);
-                       } catch (ParseException pe) {
-                               if (parse_exception == null)
-                                       parse_exception = pe;
-                       }
-               }
-
-               CheckFile(false);
-               if (!any_valid)
-                       done = true;
-       }
-
-       void LogMega(AltosEepromMega r) throws IOException {
-               if (r.cmd != Altos.AO_LOG_INVALID) {
-                       String log_line = String.format("%c %4x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
-                                                       r.cmd, r.tick,
-                                                       r.data8[0], r.data8[1], r.data8[2], r.data8[3],
-                                                       r.data8[4], r.data8[5], r.data8[6], r.data8[7],
-                                                       r.data8[8], r.data8[9], r.data8[10], r.data8[11],
-                                                       r.data8[12], r.data8[13], r.data8[14], r.data8[15],
-                                                       r.data8[16], r.data8[17], r.data8[18], r.data8[19],
-                                                       r.data8[20], r.data8[21], r.data8[22], r.data8[23],
-                                                       r.data8[24], r.data8[25], r.data8[26], r.data8[27]);
-                       if (eeprom_file != null)
-                               eeprom_file.write(log_line);
-                       else
-                               eeprom_pending.add(log_line);
-               }
-       }
-
-       void CaptureMega(AltosEepromChunk eechunk) throws IOException {
-               boolean any_valid = false;
-
-               extension = "mega";
-               set_serial(flights.config_data.serial);
-               for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += AltosEepromMega.record_length) {
-                       try {
-                               AltosEepromMega r = new AltosEepromMega(eechunk, i);
-                               if (r.cmd == Altos.AO_LOG_FLIGHT)
-                                       set_flight(r.data16(0));
-
-                               /* Monitor state transitions to update display */
-                               if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) <= Altos.ao_flight_landed) {
-                                       state = r.data16(0);
-                                       if (state > Altos.ao_flight_pad)
-                                               want_file = true;
-                               }
-
-                               if (r.cmd == Altos.AO_LOG_GPS_TIME) {
-                                       year = 2000 + r.data8(14);
-                                       month = r.data8(15);
-                                       day = r.data8(16);
-                                       want_file = true;
-                               }
-
-                               if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) == Altos.ao_flight_landed)
-                                       done = true;
-                               any_valid = true;
-                               LogMega(r);
-                       } catch (ParseException pe) {
-                               if (parse_exception == null)
-                                       parse_exception = pe;
-                       }
-               }
-               if (!any_valid)
-                       done = true;
-
-               CheckFile(false);
-       }
-       
-       void CaptureTelemetry(AltosEepromChunk eechunk) throws IOException {
-               
-       }
-
-       void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException {
-               int                     block, state_block = 0;
-               int                     log_format = flights.config_data.log_format;
-
-               state = 0;
-               done = false;
-               start = true;
-
-               if (flights.config_data.serial < 0)
-                       throw new IOException("no serial number found");
-
-               /* Reset per-capture variables */
-               flight = 0;
-               year = 0;
-               month = 0;
-               day = 0;
-               want_file = false;
-               eeprom_file = null;
-               eeprom_pending = new LinkedList<String>();
-
-               /* Set serial number in the monitor dialog window */
-               /* Now scan the eeprom, reading blocks of data and converting to .eeprom file form */
-
-               state = 0; state_block = log.start_block;
-               for (block = log.start_block; !done && block < log.end_block; block++) {
-                       monitor.set_value(AltosLib.state_name(state), state, block - state_block, block - log.start_block);
-
-                       AltosEepromChunk        eechunk = new AltosEepromChunk(serial_line, block, block == log.start_block);
-
-                       /*
-                        * Guess what kind of data is there if the device
-                        * didn't tell us
-                        */
-
-                       if (log_format == Altos.AO_LOG_FORMAT_UNKNOWN) {
-                               if (block == log.start_block) {
-                                       if (eechunk.data(0) == Altos.AO_LOG_FLIGHT)
-                                               log_format = Altos.AO_LOG_FORMAT_FULL;
-                                       else
-                                               log_format = Altos.AO_LOG_FORMAT_TINY;
-                               }
-                       }
-
-                       switch (log_format) {
-                       case AltosLib.AO_LOG_FORMAT_FULL:
-                               extension = "eeprom";
-                               CaptureFull(eechunk);
-                               break;
-                       case AltosLib.AO_LOG_FORMAT_TINY:
-                               extension = "eeprom";
-                               CaptureTiny(eechunk);
-                               break;
-                       case AltosLib.AO_LOG_FORMAT_TELEMETRY:
-                               extension = "telem";
-                               CaptureTelemetry(eechunk);
-                               break;
-                       case AltosLib.AO_LOG_FORMAT_TELESCIENCE:
-                               extension = "science";
-                               CaptureTeleScience(eechunk);
-                               break;
-                       case AltosLib.AO_LOG_FORMAT_TELEMEGA:
-                               extension = "mega";
-                               CaptureMega(eechunk);
-                       }
-               }
-               CheckFile(true);
-               if (eeprom_file != null) {
-                       eeprom_file.flush();
-                       eeprom_file.close();
-               }
-       }
-
-       private void show_message_internal(String message, String title, int message_type) {
-               JOptionPane.showMessageDialog(frame,
-                                             message,
-                                             title,
-                                             message_type);
-       }
-
-       private void show_message(String in_message, String in_title, int in_message_type) {
-               final String message = in_message;
-               final String title = in_title;
-               final int message_type = in_message_type;
-               Runnable r = new Runnable() {
-                               public void run() {
-                                       try {
-                                               show_message_internal(message, title, message_type);
-                                       } catch (Exception ex) {
-                                       }
-                               }
-                       };
-               SwingUtilities.invokeLater(r);
-       }
-
-       public void run () {
-               try {
-                       boolean failed = false;
-                       if (remote)
-                               serial_line.start_remote();
-
-                       for (AltosEepromLog log : flights) {
-                               parse_exception = null;
-                               if (log.selected) {
-                                       monitor.reset();
-                                       CaptureLog(log);
-                               }
-                               if (parse_exception != null) {
-                                       failed = true;
-                                       show_message(String.format("Flight %d download error\n%s\nValid log data saved",
-                                                                  log.flight,
-                                                                  parse_exception.getMessage()),
-                                                    serial_line.device.toShortString(),
-                                                    JOptionPane.WARNING_MESSAGE);
-                               }
-                       }
-                       success = !failed;
-               } catch (IOException ee) {
-                       show_message(ee.getLocalizedMessage(),
-                                    serial_line.device.toShortString(),
-                                    JOptionPane.ERROR_MESSAGE);
-               } catch (InterruptedException ie) {
-                       System.out.printf("download interrupted\n");
-               } catch (TimeoutException te) {
-                       show_message(String.format("Connection to \"%s\" failed",
-                                                  serial_line.device.toShortString()),
-                                    "Connection Failed",
-                                    JOptionPane.ERROR_MESSAGE);
-               } finally {
-                       if (remote) {
-                               try {
-                                       serial_line.stop_remote();
-                               } catch (InterruptedException ie) {
-                               }
-                       }
-                       serial_line.flush_output();
-               }
-               monitor.done();
-               if (listener != null) {
-                       Runnable r = new Runnable() {
-                                       public void run() {
-                                               try {
-                                                       listener.actionPerformed(new ActionEvent(this,
-                                                                                                success ? 1 : 0,
-                                                                                                "download"));
-                                               } catch (Exception ex) {
-                                               }
-                                       }
-                               };
-                       SwingUtilities.invokeLater(r);
-               }
-       }
-
-       public void start() {
-               eeprom_thread = new Thread(this);
-               eeprom_thread.start();
-       }
-
-       public void addActionListener(ActionListener l) {
-               listener = l;
-       }
-
-       public AltosEepromDownload(JFrame given_frame,
-                                  AltosSerial given_serial_line,
-                                  boolean given_remote,
-                                  AltosEepromList given_flights) {
-
-               frame = given_frame;
-               serial_line = given_serial_line;
-               serial_line.set_frame(frame);
-               remote = given_remote;
-               flights = given_flights;
-               success = false;
-
-               monitor = new AltosEepromMonitor(frame, Altos.ao_flight_boost, Altos.ao_flight_landed);
-               monitor.addActionListener(new ActionListener() {
-                               public void actionPerformed(ActionEvent e) {
-                                       if (eeprom_thread != null)
-                                               eeprom_thread.interrupt();
-                               }
-                       });
-       }
-}
diff --git a/altosui/AltosEepromList.java b/altosui/AltosEepromList.java
deleted file mode 100644 (file)
index a63d173..0000000
+++ /dev/null
@@ -1,118 +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; 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.
- */
-
-package altosui;
-
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
-
-/*
- * Temporary structure to hold the list of stored flights;
- * each of these will be queried in turn to generate more
- * complete information
- */
-
-class AltosEepromFlight {
-       int     flight;
-       int     start;
-       int     end;
-
-       public AltosEepromFlight(int in_flight, int in_start, int in_end) {
-               flight = in_flight;
-               start = in_start;
-               end = in_end;
-       }
-}
-
-/*
- * Construct a list of flights available in a connected device
- */
-
-public class AltosEepromList extends ArrayList<AltosEepromLog> {
-       AltosConfigData config_data;
-
-       public AltosEepromList (AltosSerial serial_line, boolean remote)
-               throws IOException, InterruptedException, TimeoutException
-       {
-               try {
-                       if (remote)
-                               serial_line.start_remote();
-                       config_data = new AltosConfigData (serial_line);
-//                     if (config_data.serial == 0)
-//                             throw new IOException("no serial number found");
-
-                       ArrayList<AltosEepromFlight> flights = new ArrayList<AltosEepromFlight>();
-
-                       if (config_data.flight_log_max != 0 || config_data.log_format != 0) {
-
-                               /* Devices with newer firmware will support the 'l'
-                                * command which will list the region of storage
-                                * occupied by each available flight
-                                */
-                               serial_line.printf("l\n");
-                               for (;;) {
-                                       String line = serial_line.get_reply(5000);
-                                       if (line == null)
-                                               throw new TimeoutException();
-                                       if (line.contains("done"))
-                                               break;
-                                       if (line.contains("Syntax"))
-                                               continue;
-                                       String[] tokens = line.split("\\s+");
-                                       if (tokens.length < 6)
-                                               break;
-
-                                       int     flight = -1, start = -1, end = -1;
-                                       try {
-                                               if (tokens[0].equals("flight"))
-                                                       flight = AltosParse.parse_int(tokens[1]);
-                                               if (tokens[2].equals("start"))
-                                                       start = AltosParse.parse_hex(tokens[3]);
-                                               if (tokens[4].equals("end"))
-                                                       end = AltosParse.parse_hex(tokens[5]);
-                                               if (flight > 0 && start >= 0 && end > 0)
-                                                       flights.add(new AltosEepromFlight(flight, start, end));
-                                       } catch (ParseException pe) { System.out.printf("Parse error %s\n", pe.toString()); }
-                               }
-                       } else {
-
-                               /* Older devices will hold only a single
-                                * flight. This also assumes that any older
-                                * device will have a 1MB flash device
-                                */
-                               flights.add(new AltosEepromFlight(0, 0, 0xfff));
-                       }
-
-                       /* With the list of flights collected, collect more complete
-                        * information on them by reading the first block or two of
-                        * data. This will add GPS coordinates and a date. For older
-                        * firmware, this will also extract the flight number.
-                        */
-                       for (AltosEepromFlight flight : flights) {
-                               add(new AltosEepromLog(config_data, serial_line,
-                                                      flight.flight, flight.start, flight.end));
-                       }
-               } finally {
-                       if (remote)
-                               serial_line.stop_remote();
-                       serial_line.flush_output();
-               }
-       }
-}
\ No newline at end of file
index 7a7211960b02545b197b238ebb9229a4c20f2df4..da0a977733083696bacd66870a42f5118ddb6646 100644 (file)
@@ -21,7 +21,7 @@ import java.awt.event.*;
 import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosEepromManage implements ActionListener {
@@ -133,11 +133,13 @@ public class AltosEepromManage implements ActionListener {
                                        for (AltosEepromLog flight : flights)
                                                any_selected = any_selected || flight.selected;
                                        if (any_selected) {
-                                               download = new AltosEepromDownload(frame,
+                                               AltosEepromMonitorUI monitor = new AltosEepromMonitorUI(frame);
+                                               monitor.addActionListener(this);
+                                               serial_line.set_frame(frame);
+                                               download = new AltosEepromDownload(monitor,
                                                                                   serial_line,
                                                                                   remote,
                                                                                   flights);
-                                               download.addActionListener(this);
                                                /*
                                                 * Start flight log download
                                                 */
diff --git a/altosui/AltosEepromMonitorUI.java b/altosui/AltosEepromMonitorUI.java
new file mode 100644 (file)
index 0000000..6ad4ca5
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * 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; 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.
+ */
+
+package altosui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_2.*;
+
+public class AltosEepromMonitorUI extends AltosUIDialog implements AltosEepromMonitor {
+       JFrame          owner;
+       Container       pane;
+       Box             box;
+       JLabel          serial_label;
+       JLabel          flight_label;
+       JLabel          file_label;
+       JLabel          serial_value;
+       JLabel          flight_value;
+       JLabel          file_value;
+       JButton         cancel;
+       JProgressBar    pbar;
+       int             min_state, max_state;
+       ActionListener  listener;
+
+       public AltosEepromMonitorUI(JFrame owner) {
+               super (owner, "Download Flight Data", false);
+
+               this.owner = owner;
+
+               GridBagConstraints c;
+               Insets il = new Insets(4,4,4,4);
+               Insets ir = new Insets(4,4,4,4);
+
+               pane = getContentPane();
+               pane.setLayout(new GridBagLayout());
+
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 0;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               serial_label = new JLabel("Serial:");
+               pane.add(serial_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 1; c.gridy = 0;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               serial_value = new JLabel("");
+               pane.add(serial_value, c);
+
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.NONE;
+               c.gridx = 0; c.gridy = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               flight_label = new JLabel("Flight:");
+               pane.add(flight_label, c);
+
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.gridx = 1; c.gridy = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               flight_value = new JLabel("");
+               pane.add(flight_value, c);
+
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.NONE;
+               c.gridx = 0; c.gridy = 2;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               file_label = new JLabel("File:");
+               pane.add(file_label, c);
+
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.gridx = 1; c.gridy = 2;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               file_value = new JLabel("");
+               pane.add(file_value, c);
+
+               pbar = new JProgressBar();
+               pbar.setMinimum(0);
+               pbar.setMaximum(1000);
+               pbar.setValue(0);
+               pbar.setString("startup");
+               pbar.setStringPainted(true);
+               pbar.setPreferredSize(new Dimension(600, 20));
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 0; c.gridy = 3;
+               c.gridwidth = GridBagConstraints.REMAINDER;
+               Insets ib = new Insets(4,4,4,4);
+               c.insets = ib;
+               pane.add(pbar, c);
+
+
+               cancel = new JButton("Cancel");
+               c = new GridBagConstraints();
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 0; c.gridy = 4;
+               c.gridwidth = GridBagConstraints.REMAINDER;
+               Insets ic = new Insets(4,4,4,4);
+               c.insets = ic;
+               pane.add(cancel, c);
+
+               pack();
+               setLocationRelativeTo(owner);
+       }
+
+       public void addActionListener(ActionListener l) {
+               listener = l;
+       }
+
+       public void set_states(int min_state, int max_state) {
+               this.min_state = min_state;
+               this.max_state = max_state;
+       }
+
+       public void set_thread(Thread in_eeprom_thread) {
+               final Thread eeprom_thread = in_eeprom_thread;
+               cancel.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       if (eeprom_thread != null)
+                                               eeprom_thread.interrupt();
+                               }
+                       });
+       }
+
+       public void start() {
+               setVisible(true);
+       }
+
+       private void set_value_internal(String state_name, int state, int state_block, int block) {
+               if (state_block > 100)
+                       state_block = 100;
+               if (state < min_state) state = min_state;
+               if (state >= max_state) state = max_state - 1;
+               state -= min_state;
+
+               int pos = state * 100 + state_block;
+
+               pbar.setString(String.format("block %d state %s", block, state_name));
+               pbar.setValue(pos);
+       }
+
+       public void set_value(String in_state_name, int in_state, int in_state_block, int in_block) {
+               final String state_name = in_state_name;
+               final int state = in_state;
+               final int state_block = in_state_block;
+               final int block = in_block;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               set_value_internal(state_name, state, state_block, block);
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       private void set_serial_internal(int serial) {
+               serial_value.setText(String.format("%d", serial));
+       }
+
+       public void set_serial(int in_serial) {
+               final int serial = in_serial;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               set_serial_internal(serial);
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       private void set_flight_internal(int flight) {
+               flight_value.setText(String.format("%d", flight));
+       }
+
+       public void set_flight(int in_flight) {
+               final int flight = in_flight;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               set_flight_internal(flight);
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       private void set_filename_internal(String filename) {
+               file_value.setText(String.format("%s", filename));
+       }
+
+       public void set_filename(String in_filename) {
+               final String filename = in_filename;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               set_filename_internal(filename);
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       private void done_internal(boolean success) {
+               listener.actionPerformed(new ActionEvent(this,
+                                                        success ? 1 : 0,
+                                                        "download"));
+               setVisible(false);
+               dispose();
+       }
+
+       public void done(boolean in_success) {
+               final boolean success = in_success;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               done_internal(success);
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       private void reset_internal() {
+               set_value_internal("startup",min_state,0, 0);
+               set_flight_internal(0);
+               set_filename_internal("");
+       }
+
+       public void reset() {
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               reset_internal();
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       private void show_message_internal(String message, String title, int message_type) {
+               int joption_message_type = JOptionPane.ERROR_MESSAGE;
+
+               switch (message_type) {
+               case INFO_MESSAGE:
+                       joption_message_type = JOptionPane.INFORMATION_MESSAGE;
+                       break;
+               case WARNING_MESSAGE:
+                       joption_message_type = JOptionPane.WARNING_MESSAGE;
+                       break;
+               case ERROR_MESSAGE:
+                       joption_message_type = JOptionPane.ERROR_MESSAGE;
+                       break;
+               }
+               JOptionPane.showMessageDialog(owner,
+                                             message,
+                                             title,
+                                             joption_message_type);
+       }
+
+       public void show_message(String in_message, String in_title, int in_message_type) {
+               final String message = in_message;
+               final String title = in_title;
+               final int message_type = in_message_type;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               show_message_internal(message, title, message_type);
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+}
index a451aa3afbbe8b88793f77675e15dc1ed8b1cbe9..8f86eebff55436ec04e8cf7bfbb4349af0b2bf07 100644 (file)
@@ -21,7 +21,7 @@ import javax.swing.*;
 import javax.swing.border.*;
 import java.awt.*;
 import java.awt.event.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 class AltosEepromItem implements ActionListener {
index f4e522181b8f95419d0094f0881cb84a72b22f02..296ad8ef9d761997aebf142704e1d4c6b5adde0a 100644 (file)
@@ -23,7 +23,7 @@ import javax.swing.*;
 import javax.swing.filechooser.FileNameExtensionFilter;
 import java.io.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosFlashUI
@@ -45,18 +45,51 @@ public class AltosFlashUI
        File            file;
 
        // Debug connection
-       AltosDevice     debug_dongle;
+       AltosDevice     device;
+
+       AltosLink       link;
 
        // Desired Rom configuration
        AltosRomconfig  rom_config;
 
        // Flash controller
-       AltosFlash      flash;
+       AltosProgrammer programmer;
+
+       private static String[] pair_programmed = {
+               "teleballoon",
+               "telebt",
+               "teledongle",
+               "telefire",
+               "telemetrum-v0",
+               "telemetrum-v1",
+               "telemini",
+               "telenano",
+               "teleshield",
+               "teleterra"
+       };
+
+       private boolean is_pair_programmed() {
+
+               if (file != null) {
+                       String  name = file.getName();
+                       for (int i = 0; i < pair_programmed.length; i++) {
+                               if (name.startsWith(pair_programmed[i]))
+                                       return true;
+                       }
+               }
+               if (device != null) {
+                       if (!device.matchProduct(AltosLib.product_altusmetrum) &&
+                           (device.matchProduct(AltosLib.product_teledongle) ||
+                            device.matchProduct(AltosLib.product_telebt)))
+                               return true;
+               }
+               return false;
+       }
 
        public void actionPerformed(ActionEvent e) {
                if (e.getSource() == cancel) {
-                       if (flash != null)
-                               flash.abort();
+                       if (programmer != null)
+                               programmer.abort();
                        setVisible(false);
                        dispose();
                } else {
@@ -156,6 +189,33 @@ public class AltosFlashUI
                serial_value.setText(String.format("%d", serial_number));
        }
 
+       static class AltosHexfileFilter extends javax.swing.filechooser.FileFilter {
+               int product;
+               String head;
+               String description;
+
+               public AltosHexfileFilter(int product, String head, String description) {
+                       this.product = product;
+                       this.head = head;
+                       this.description = description;
+               }
+
+               public boolean accept(File file) {
+                       return !file.isFile() || (file.getName().startsWith(head) && file.getName().endsWith(".ihx"));
+               }
+
+               public String getDescription() {
+                       return description;
+               }
+       }
+
+       static AltosHexfileFilter[] filters = {
+               new AltosHexfileFilter(AltosLib.product_telemetrum, "telemetrum", "TeleMetrum Image"),
+               new AltosHexfileFilter(AltosLib.product_teledongle, "teledongle", "TeleDongle Image"),
+               new AltosHexfileFilter(AltosLib.product_telemega, "telemega", "TeleMega Image"),
+               new AltosHexfileFilter(AltosLib.product_easymini, "easymini", "EasyMini Image"),
+       };
+
        boolean select_source_file() {
                JFileChooser    hexfile_chooser = new JFileChooser();
 
@@ -164,7 +224,21 @@ public class AltosFlashUI
                        hexfile_chooser.setCurrentDirectory(firmwaredir);
 
                hexfile_chooser.setDialogTitle("Select Flash Image");
-               hexfile_chooser.setFileFilter(new FileNameExtensionFilter("Flash Image", "ihx"));
+
+               for (int i = 0; i < filters.length; i++) {
+                       hexfile_chooser.addChoosableFileFilter(filters[i]);
+               }
+               javax.swing.filechooser.FileFilter ihx_filter = new FileNameExtensionFilter("Flash Image", "ihx");
+               hexfile_chooser.addChoosableFileFilter(ihx_filter);
+               hexfile_chooser.setFileFilter(ihx_filter);
+               
+               if (!is_pair_programmed() && !device.matchProduct(AltosLib.product_altusmetrum)) {
+                       for (int i = 0; i < filters.length; i++) {
+                               if (device != null && device.matchProduct(filters[i].product))
+                                       hexfile_chooser.setFileFilter(filters[i]);
+                       }
+               }
+
                int returnVal = hexfile_chooser.showOpenDialog(frame);
 
                if (returnVal != JFileChooser.APPROVE_OPTION)
@@ -173,13 +247,16 @@ public class AltosFlashUI
                if (file == null)
                        return false;
                AltosUIPreferences.set_firmwaredir(file.getParentFile());
+               
                return true;
        }
 
-       boolean select_debug_dongle() {
-               debug_dongle = AltosDeviceUIDialog.show(frame, Altos.product_any);
+       boolean select_device() {
+               int     product = Altos.product_any;
 
-               if (debug_dongle == null)
+               device = AltosDeviceUIDialog.show(frame, Altos.product_any);
+
+               if (device == null)
                        return false;
                return true;
        }
@@ -204,7 +281,7 @@ public class AltosFlashUI
                } else if (e instanceof AltosSerialInUseException) {
                        JOptionPane.showMessageDialog(frame,
                                                      String.format("Device \"%s\" already in use",
-                                                                   debug_dongle.toShortString()),
+                                                                   device.toShortString()),
                                                      "Device in use",
                                                      JOptionPane.ERROR_MESSAGE);
                } else if (e instanceof IOException) {
@@ -218,7 +295,7 @@ public class AltosFlashUI
        class flash_task implements Runnable, AltosFlashListener {
                AltosFlashUI    ui;
                Thread          t;
-               AltosFlash      flash;
+               AltosProgrammer programmer;
 
                public void position(String in_s, int in_percent) {
                        final String s = in_s;
@@ -238,14 +315,17 @@ public class AltosFlashUI
 
                public void run () {
                        try {
-                               flash = new AltosFlash(ui.file, new AltosSerial(ui.debug_dongle), this);
+                               if (ui.is_pair_programmed())
+                                       programmer = new AltosFlash(ui.file, link, this);
+                               else
+                                       programmer = new AltosSelfFlash(ui.file, link, this);
 
-                               final AltosRomconfig    current_config = flash.romconfig();
+                               final AltosRomconfig    current_config = programmer.romconfig();
 
                                final Semaphore await_rom_config = new Semaphore(0);
                                SwingUtilities.invokeLater(new Runnable() {
                                                public void run() {
-                                                       ui.flash = flash;
+                                                       ui.programmer = programmer;
                                                        ui.update_rom_config_info(current_config);
                                                        await_rom_config.release();
                                                }
@@ -253,8 +333,8 @@ public class AltosFlashUI
                                await_rom_config.acquire();
 
                                if (ui.rom_config != null) {
-                                       flash.set_romconfig(ui.rom_config);
-                                       flash.flash();
+                                       programmer.set_romconfig(ui.rom_config);
+                                       programmer.flash();
                                }
                        } catch (InterruptedException ee) {
                                final Exception e = ee;
@@ -270,16 +350,9 @@ public class AltosFlashUI
                                                        ui.exception(e);
                                                }
                                        });
-                       } catch (AltosSerialInUseException ee) {
-                               final Exception e = ee;
-                               SwingUtilities.invokeLater(new Runnable() {
-                                               public void run() {
-                                                       ui.exception(e);
-                                               }
-                                       });
                        } finally {
-                               if (flash != null)
-                                       flash.close();
+                               if (programmer != null)
+                                       programmer.close();
                        }
                }
 
@@ -292,16 +365,55 @@ public class AltosFlashUI
 
        flash_task      flasher;
 
+       private boolean open_device() throws InterruptedException {
+               try {
+                       link = new AltosSerial(device);
+                       if (is_pair_programmed())
+                               return true;
+
+                       if (link == null)
+                               throw new IOException(String.format("%s: open failed", device.toShortString()));
+
+                       while (!link.is_loader()) {
+                               link.to_loader();
+
+                               java.util.List<AltosDevice> devices = AltosUSBDevice.list(AltosLib.product_altusmetrum);
+                               if (devices.size() == 1)
+                                       device = devices.get(0);
+                               else {
+                                       device = AltosDeviceUIDialog.show(frame, AltosLib.product_altusmetrum);
+                                       if (device == null)
+                                               return false;
+                               }
+                               link = new AltosSerial(device);
+                       }
+                       return true;
+               } catch (AltosSerialInUseException ee) {
+                       exception(ee);
+               } catch (FileNotFoundException fe) {
+                       exception(fe);
+               } catch (IOException ie) {
+                       exception (ie);
+               }
+               return false;
+       }
+
        /*
         * Execute the steps for flashing
         * a device. Note that this returns immediately;
         * this dialog is not modal
         */
        void showDialog() {
-               if (!select_debug_dongle())
+               if (!select_device())
                        return;
                if (!select_source_file())
                        return;
+               try {
+                       if (!open_device())
+                               return;
+               } catch (InterruptedException ie) {
+                       return;
+               }
                build_dialog();
                flash_task      f = new flash_task(this);
        }
index 4f4c158e8e08aad3105165ca36b5865cde53163a..289ddd01b66ac9a87bd4d351c638f38e2c59bfb3 100644 (file)
@@ -17,7 +17,7 @@
 
 package altosui;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public interface AltosFlightDisplay {
        void reset();
index dee31a8d3bcf6f8d3005803b110ead9cb6595236..552210c36adac61f13cc1c4c617903a208b9d8ba 100644 (file)
 package altosui;
 
 import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosFlightStats {
        double          max_height;
        double          max_speed;
        double          max_acceleration;
-       double[]        state_accel_speed = new double[Altos.ao_flight_invalid + 1];
-       double[]        state_baro_speed = new double[Altos.ao_flight_invalid + 1];
+       double[]        state_speed = new double[Altos.ao_flight_invalid + 1];
        double[]        state_accel = new double[Altos.ao_flight_invalid + 1];
        int[]           state_count = new int[Altos.ao_flight_invalid + 1];
        double[]        state_start = new double[Altos.ao_flight_invalid + 1];
@@ -40,16 +39,19 @@ public class AltosFlightStats {
        boolean         has_other_adc;
        boolean         has_rssi;
 
-       double landed_time(AltosRecordIterable iterable) {
-               AltosState      state = null;
-               for (AltosRecord record : iterable) {
-                       state = new AltosState(record, state);
+       double landed_time(AltosStateIterable states) {
+               AltosState state = null;
 
+               for (AltosState s : states) {
+                       state = s;
                        if (state.state == Altos.ao_flight_landed)
                                break;
                }
 
-               double  landed_height = state.height;
+               if (state == null)
+                       return 0;
+
+               double  landed_height = state.height();
 
                state = null;
 
@@ -57,13 +59,13 @@ public class AltosFlightStats {
 
                double  landed_time = -1000;
 
-               for (AltosRecord record : iterable) {
-                       state = new AltosState(record, state);
+               for (AltosState s : states) {
+                       state = s;
 
-                       if (state.height > landed_height + 10) {
+                       if (state.height() > landed_height + 10) {
                                above = true;
                        } else {
-                               if (above && state.height < landed_height + 2) {
+                               if (above && state.height() < landed_height + 2) {
                                        above = false;
                                        landed_time = state.time;
                                }
@@ -74,84 +76,80 @@ public class AltosFlightStats {
                return landed_time;
        }
 
-       double boost_time(AltosRecordIterable iterable) {
-               double boost_time = -1000;
-
-               AltosState state = null;
+       double boost_time(AltosStateIterable states) {
+               double boost_time = AltosLib.MISSING;
+               AltosState      state = null;
 
-               for (AltosRecord record : iterable) {
-                       state = new AltosState(record, state);
-                       
-                       if (state.acceleration < 1)
+               for (AltosState s : states) {
+                       state = s;
+                       if (state.acceleration() < 1)
                                boost_time = state.time;
-                       if (state.state >= Altos.ao_flight_boost)
+                       if (state.state >= AltosLib.ao_flight_boost && state.state <= AltosLib.ao_flight_landed)
                                break;
                }
-               if (boost_time == -1000)
+               if (state == null)
+                       return 0;
+
+               if (boost_time == AltosLib.MISSING)
                        boost_time = state.time;
                return boost_time;
        }
 
 
-       public AltosFlightStats(AltosRecordIterable iterable) throws InterruptedException, IOException {
-               AltosState      state = null;
-               AltosState      new_state = null;
-               double          boost_time = boost_time(iterable);
+       public AltosFlightStats(AltosStateIterable states) throws InterruptedException, IOException {
+               double          boost_time = boost_time(states);
                double          end_time = 0;
-               double          landed_time = landed_time(iterable);
+               double          landed_time = landed_time(states);
 
-               year = month = day = -1;
-               hour = minute = second = -1;
-               serial = flight = -1;
-               lat = lon = -1;
+               year = month = day = AltosLib.MISSING;
+               hour = minute = second = AltosLib.MISSING;
+               serial = flight = AltosLib.MISSING;
+               lat = lon = AltosLib.MISSING;
                has_gps = false;
                has_other_adc = false;
                has_rssi = false;
-               for (AltosRecord record : iterable) {
-                       if (serial < 0)
-                               serial = record.serial;
-                       if ((record.seen & AltosRecord.seen_flight) != 0 && flight < 0)
-                               flight = record.flight;
-                       if ((record.seen & AltosRecord.seen_temp_volt) != 0)
+               for (AltosState state : states) {
+                       if (serial == AltosLib.MISSING && state.serial != AltosLib.MISSING)
+                               serial = state.serial;
+                       if (flight == AltosLib.MISSING && state.flight != AltosLib.MISSING)
+                               flight = state.flight;
+                       if (state.battery_voltage != AltosLib.MISSING)
                                has_other_adc = true;
-                       if (record.rssi != 0)
+                       if (state.rssi != AltosLib.MISSING)
                                has_rssi = true;
-                       new_state = new AltosState(record, state);
-                       end_time = new_state.time;
-                       state = new_state;
-                       if (state.time >= boost_time && state.state < Altos.ao_flight_boost)
-                               state.state = Altos.ao_flight_boost;
-                       if (state.time >= landed_time && state.state < Altos.ao_flight_landed)
-                               state.state = Altos.ao_flight_landed;
-                       if (0 <= state.state && state.state < Altos.ao_flight_invalid) {
-                               if (state.state >= Altos.ao_flight_boost) {
-                                       if (state.gps != null && state.gps.locked &&
-                                           year < 0) {
-                                               year = state.gps.year;
-                                               month = state.gps.month;
-                                               day = state.gps.day;
-                                               hour = state.gps.hour;
-                                               minute = state.gps.minute;
-                                               second = state.gps.second;
-                                       }
+                       end_time = state.time;
+
+                       int state_id = state.state;
+                       if (state.time >= boost_time && state_id < Altos.ao_flight_boost)
+                               state_id = Altos.ao_flight_boost;
+                       if (state.time >= landed_time && state_id < Altos.ao_flight_landed)
+                               state_id = Altos.ao_flight_landed;
+                       if (state.gps != null && state.gps.locked) {
+                               year = state.gps.year;
+                               month = state.gps.month;
+                               day = state.gps.day;
+                               hour = state.gps.hour;
+                               minute = state.gps.minute;
+                               second = state.gps.second;
+                       }
+                       if (0 <= state_id && state_id < Altos.ao_flight_invalid) {
+                               double acceleration = state.acceleration();
+                               double speed = state.speed();
+                               if (acceleration != AltosLib.MISSING && speed != AltosLib.MISSING) {
+                                       state_accel[state_id] += acceleration;
+                                       state_speed[state_id] += speed;
+                                       state_count[state_id]++;
                                }
-                               state_accel[state.state] += state.acceleration;
-                               state_accel_speed[state.state] += state.accel_speed;
-                               state_baro_speed[state.state] += state.baro_speed;
-                               state_count[state.state]++;
-                               if (state_start[state.state] == 0.0)
-                                       state_start[state.state] = state.time;
-                               if (state_end[state.state] < state.time)
-                                       state_end[state.state] = state.time;
-                               max_height = state.max_height;
-                               if (state.max_accel_speed != 0)
-                                       max_speed = state.max_accel_speed;
-                               else
-                                       max_speed = state.max_baro_speed;
-                               max_acceleration = state.max_acceleration;
+                               if (state_start[state_id] == 0.0)
+                                       state_start[state_id] = state.time;
+                               if (state_end[state_id] < state.time)
+                                       state_end[state_id] = state.time;
+                               max_height = state.max_height();
+                               max_speed = state.max_speed();
+                               max_acceleration = state.max_acceleration();
                        }
                        if (state.gps != null && state.gps.locked && state.gps.nsat >= 4) {
-                               if (state.state <= Altos.ao_flight_pad) {
+                               if (state_id <= Altos.ao_flight_pad) {
                                        pad_lat = state.gps.lat;
                                        pad_lon = state.gps.lon;
                                }
@@ -162,8 +160,7 @@ public class AltosFlightStats {
                }
                for (int s = Altos.ao_flight_startup; s <= Altos.ao_flight_landed; s++) {
                        if (state_count[s] > 0) {
-                               state_accel_speed[s] /= state_count[s];
-                               state_baro_speed[s] /= state_count[s];
+                               state_speed[s] /= state_count[s];
                                state_accel[s] /= state_count[s];
                        }
                        if (state_start[s] == 0)
index a35b5f637e71e1daf269d824d2a4bd5673ef1867..db875b3bb70fac4bc9cc10a8e14fedfa24725fe9 100644 (file)
@@ -19,7 +19,7 @@ package altosui;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosFlightStatsTable extends JComponent {
        GridBagLayout   layout;
@@ -76,15 +76,15 @@ public class AltosFlightStatsTable extends JComponent {
                int y = 0;
                new FlightStat(layout, y++, "Serial", String.format("%d", stats.serial));
                new FlightStat(layout, y++, "Flight", String.format("%d", stats.flight));
-               if (stats.year > 0 && stats.hour > 0)
+               if (stats.year != AltosLib.MISSING && stats.hour != AltosLib.MISSING)
                        new FlightStat(layout, y++, "Date/Time",
                                       String.format("%04d-%02d-%02d", stats.year, stats.month, stats.day),
                                       String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
                else {
-                       if (stats.year > 0)
+                       if (stats.year != AltosLib.MISSING)
                                new FlightStat(layout, y++, "Date",
                                               String.format("%04d-%02d-%02d", stats.year, stats.month, stats.day));
-                       if (stats.hour > 0)
+                       if (stats.hour != AltosLib.MISSING)
                                new FlightStat(layout, y++, "Time",
                                               String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
                }
@@ -95,7 +95,7 @@ public class AltosFlightStatsTable extends JComponent {
                               String.format("%5.0f m/s", stats.max_speed),
                               String.format("%5.0f mph", AltosConvert.meters_to_mph(stats.max_speed)),
                               String.format("Mach %4.1f", AltosConvert.meters_to_mach(stats.max_speed)));
-               if (stats.max_acceleration != AltosRecord.MISSING) {
+               if (stats.max_acceleration != AltosLib.MISSING) {
                        new FlightStat(layout, y++, "Maximum boost acceleration",
                                       String.format("%5.0f m/s²", stats.max_acceleration),
                                       String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.max_acceleration)),
@@ -106,11 +106,11 @@ public class AltosFlightStatsTable extends JComponent {
                                       String.format("%5.0f G", AltosConvert.meters_to_g(stats.state_accel[Altos.ao_flight_boost])));
                }
                new FlightStat(layout, y++, "Drogue descent rate",
-                              String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_drogue]),
-                              String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_drogue])));
+                              String.format("%5.0f m/s", stats.state_speed[Altos.ao_flight_drogue]),
+                              String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_speed[Altos.ao_flight_drogue])));
                new FlightStat(layout, y++, "Main descent rate",
-                              String.format("%5.0f m/s", stats.state_baro_speed[Altos.ao_flight_main]),
-                              String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main])));
+                              String.format("%5.0f m/s", stats.state_speed[Altos.ao_flight_main]),
+                              String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_speed[Altos.ao_flight_main])));
                new FlightStat(layout, y++, "Ascent time",
                               String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_boost] - stats.state_start[AltosLib.ao_flight_boost],
                                             AltosLib.state_name(Altos.ao_flight_boost)),
index d2910414dec132af46e4fecb4e168052068073af..9d575e4c8897ebb8c14e651ca94e5c64712348d7 100644 (file)
@@ -19,7 +19,7 @@ package altosui;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosFlightStatus extends JComponent implements AltosFlightDisplay {
        GridBagLayout   layout;
@@ -65,7 +65,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
 
        class Call extends FlightValue {
                void show(AltosState state, AltosListenerState listener_state) {
-                       value.setText(state.data.callsign);
+                       value.setText(state.callsign);
                }
                public Call (GridBagLayout layout, int x) {
                        super (layout, x, "Callsign");
@@ -76,10 +76,10 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
 
        class Serial extends FlightValue {
                void show(AltosState state, AltosListenerState listener_state) {
-                       if (state.data.serial == AltosRecord.MISSING)
+                       if (state.serial == AltosLib.MISSING)
                                value.setText("none");
                        else
-                               value.setText(String.format("%d", state.data.serial));
+                               value.setText(String.format("%d", state.serial));
                }
                public Serial (GridBagLayout layout, int x) {
                        super (layout, x, "Serial");
@@ -90,10 +90,10 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
 
        class Flight extends FlightValue {
                void show(AltosState state, AltosListenerState listener_state) {
-                       if (state.data.flight == AltosRecord.MISSING)
+                       if (state.flight == AltosLib.MISSING)
                                value.setText("none");
                        else
-                               value.setText(String.format("%d", state.data.flight));
+                               value.setText(String.format("%d", state.flight));
                }
                public Flight (GridBagLayout layout, int x) {
                        super (layout, x, "Flight");
@@ -104,7 +104,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
 
        class FlightState extends FlightValue {
                void show(AltosState state, AltosListenerState listener_state) {
-                       value.setText(state.data.state());
+                       value.setText(state.state_name());
                }
                public FlightState (GridBagLayout layout, int x) {
                        super (layout, x, "State");
@@ -115,7 +115,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
 
        class RSSI extends FlightValue {
                void show(AltosState state, AltosListenerState listener_state) {
-                       value.setText(String.format("%d", state.data.rssi));
+                       value.setText(String.format("%d", state.rssi()));
                }
                public RSSI (GridBagLayout layout, int x) {
                        super (layout, x, "RSSI");
@@ -126,7 +126,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
 
        class LastPacket extends FlightValue {
                void show(AltosState state, AltosListenerState listener_state) {
-                       long secs = (System.currentTimeMillis() - state.report_time + 500) / 1000;
+                       long secs = (System.currentTimeMillis() - state.received_time + 500) / 1000;
                        value.setText(String.format("%d", secs));
                }
                public LastPacket(GridBagLayout layout, int x) {
index 6a327841bf10553b63e8ecaab258a3af83394580..08154fdadd1cc76cd052dd4b52a04fe4ecebda70 100644 (file)
@@ -27,7 +27,7 @@ import java.util.*;
 import java.text.*;
 import java.util.prefs.*;
 import java.util.concurrent.LinkedBlockingQueue;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosFlightStatusTableModel extends AbstractTableModel {
        private String[] columnNames = {
index 962a08f7821d3b88df57130eebd4679983ef9d6e..7821a77709a90fd32b9f58621998334fd5ceb947 100644 (file)
@@ -18,7 +18,7 @@
 package altosui;
 
 import java.awt.event.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosFlightStatusUpdate implements ActionListener {
 
index 6d010d23c14129ae53bc42ddc5149757d51e8db7..c151177e73e1915fae355b66fc9939ff33507b56 100644 (file)
@@ -21,7 +21,7 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, AltosFontListener {
@@ -102,7 +102,7 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
                status_update.saved_state = state;
 
                if (state == null)
-                       state = new AltosState(new AltosRecord());
+                       state = new AltosState();
 
                pad.show(state, listener_state);
 
@@ -130,7 +130,7 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
                flightStatus.show(state, listener_state);
                flightInfo.show(state, listener_state);
 
-               if (state.data.companion != null) {
+               if (state.companion != null) {
                        if (!has_companion) {
                                pane.add("Companion", companion);
                                has_companion= true;
index 7464ac3ee5f244c67e7fec24ca535a2231ea8c5c..17a995d41c0b8fa5b3bc5f482551f7bc048b9e7d 100644 (file)
@@ -18,7 +18,7 @@
 package altosui;
 
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosFreqList extends JComboBox {
@@ -29,6 +29,12 @@ public class AltosFreqList extends JComboBox {
 
        public void set_frequency(double new_frequency) {
                int i;
+
+               if (new_frequency < 0) {
+                       setVisible(false);
+                       return;
+               }
+
                for (i = 0; i < getItemCount(); i++) {
                        AltosFrequency  f = (AltosFrequency) getItemAt(i);
                        
index defe69a0082cdca7a061331cd5086bf3404e772a..c505d2d8c5dc41771b9cc1d07bd03e8afece8f0e 100644 (file)
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 import org.jfree.ui.*;
@@ -37,57 +37,92 @@ import org.jfree.data.*;
 
 class AltosVoltage extends AltosUnits {
 
-       public double value(double v) {
+       public double value(double v, boolean imperial_units) {
                return v;
        }
 
-       public String show_units() {
+       public double inverse(double v, boolean imperial_units) {
+               return v;
+       }
+
+       public String show_units(boolean imperial_units) {
                return "V";
        }
 
-       public String say_units() {
+       public String say_units(boolean imperial_units) {
                return "volts";
        }
 
-       public int show_fraction(int width) {
+       public int show_fraction(int width, boolean imperial_units) {
                return width / 2;
        }
 }
 
 class AltosNsat extends AltosUnits {
 
-       public double value(double v) {
+       public double value(double v, boolean imperial_units) {
+               return v;
+       }
+
+       public double inverse(double v, boolean imperial_units) {
                return v;
        }
 
-       public String show_units() {
+       public String show_units(boolean imperial_units) {
                return "Sats";
        }
 
-       public String say_units() {
+       public String say_units(boolean imperial_units) {
                return "Satellites";
        }
 
-       public int show_fraction(int width) {
+       public int show_fraction(int width, boolean imperial_units) {
+               return 0;
+       }
+}
+
+class AltosPressure extends AltosUnits {
+
+       public double value(double p, boolean imperial_units) {
+               return p;
+       }
+
+       public double inverse(double p, boolean imperial_units) {
+               return p;
+       }
+
+       public String show_units(boolean imperial_units) {
+               return "Pa";
+       }
+
+       public String say_units(boolean imperial_units) {
+               return "pascals";
+       }
+
+       public int show_fraction(int width, boolean imperial_units) {
                return 0;
        }
 }
 
 class AltosDbm extends AltosUnits {
 
-       public double value(double v) {
-               return v;
+       public double value(double d, boolean imperial_units) {
+               return d;
+       }
+
+       public double inverse(double d, boolean imperial_units) {
+               return d;
        }
 
-       public String show_units() {
+       public String show_units(boolean imperial_units) {
                return "dBm";
        }
 
-       public String say_units() {
-               return "d b m";
+       public String say_units(boolean imperial_units) {
+               return "D B M";
        }
 
-       public int show_fraction(int width) {
+       public int show_fraction(int width, boolean imperial_units) {
                return 0;
        }
 }
@@ -96,6 +131,7 @@ public class AltosGraph extends AltosUIGraph {
 
        static final private Color height_color = new Color(194,31,31);
        static final private Color gps_height_color = new Color(150,31,31);
+       static final private Color pressure_color = new Color (225,31,31);
        static final private Color range_color = new Color(100, 31, 31);
        static final private Color distance_color = new Color(100, 31, 194);
        static final private Color speed_color = new Color(31,194,31);
@@ -112,16 +148,18 @@ public class AltosGraph extends AltosUIGraph {
        static final private Color state_color = new Color(0,0,0);
 
        static AltosVoltage voltage_units = new AltosVoltage();
+       static AltosPressure pressure_units = new AltosPressure();
        static AltosNsat nsat_units = new AltosNsat();
        static AltosDbm dbm_units = new AltosDbm();
 
        AltosUIAxis     height_axis, speed_axis, accel_axis, voltage_axis, temperature_axis, nsat_axis, dbm_axis;
-       AltosUIAxis     distance_axis;
+       AltosUIAxis     distance_axis, pressure_axis;
 
        public AltosGraph(AltosUIEnable enable, AltosFlightStats stats, AltosGraphDataSet dataSet) {
                super(enable);
 
                height_axis = newAxis("Height", AltosConvert.height, height_color);
+               pressure_axis = newAxis("Pressure", pressure_units, pressure_color, 0);
                speed_axis = newAxis("Speed", AltosConvert.speed, speed_color);
                accel_axis = newAxis("Acceleration", AltosConvert.accel, accel_color);
                voltage_axis = newAxis("Voltage", voltage_units, voltage_color);
@@ -138,6 +176,12 @@ public class AltosGraph extends AltosUIGraph {
                          height_color,
                          true,
                          height_axis);
+               addSeries("Pressure",
+                         AltosGraphDataPoint.data_pressure,
+                         pressure_units,
+                         pressure_color,
+                         false,
+                         pressure_axis);
                addSeries("Speed",
                          AltosGraphDataPoint.data_speed,
                          AltosConvert.speed,
index 8e6d6923327feb670f339a9bd0f8af3b19cfc4fd..d8191f5d35199ab378188c5e071885031db2d47e 100644 (file)
@@ -18,7 +18,7 @@
 package altosui;
 
 import org.altusmetrum.altosuilib_1.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosGraphDataPoint implements AltosUIDataPoint {
 
@@ -39,39 +39,41 @@ public class AltosGraphDataPoint implements AltosUIDataPoint {
        public static final int data_temperature = 12;
        public static final int data_range = 13;
        public static final int data_distance = 14;
+       public static final int data_pressure = 15;
 
        public double x() throws AltosUIDataMissing {
-               if (state.data.time < -2)
+               double  time = state.time_since_boost();
+               if (time < -2)
                        throw new AltosUIDataMissing(-1);
-               return state.data.time;
+               return time;
        }
 
        public double y(int index) throws AltosUIDataMissing {
-               double y = AltosRecord.MISSING;
+               double y = AltosLib.MISSING;
                switch (index) {
                case data_height:
-                       y = state.height;
+                       y = state.height();
                        break;
                case data_speed:
                        y = state.speed();
                        break;
                case data_accel:
-                       y = state.acceleration;
+                       y = state.acceleration();
                        break;
                case data_temp:
                        y = state.temperature;
                        break;
                case data_battery_voltage:
-                       y = state.battery;
+                       y = state.battery_voltage;
                        break;
                case data_drogue_voltage:
-                       y = state.drogue_sense;
+                       y = state.apogee_voltage;
                        break;
                case data_main_voltage:
-                       y = state.main_sense;
+                       y = state.main_voltage;
                        break;
                case data_rssi:
-                       y = state.data.rssi;
+                       y = state.rssi;
                        break;
                case data_gps_height:
                        y = state.gps_height;
@@ -94,15 +96,18 @@ public class AltosGraphDataPoint implements AltosUIDataPoint {
                        if (state.from_pad != null)
                                y = state.from_pad.distance;
                        break;
+               case data_pressure:
+                       y = state.pressure();
+                       break;
                }
-               if (y == AltosRecord.MISSING)
+               if (y == AltosLib.MISSING)
                        throw new AltosUIDataMissing(index);
                return y;
        }
 
        public int id(int index) {
                if (index == data_state) {
-                       int s = state.data.state;
+                       int s = state.state;
                        if (s < Altos.ao_flight_boost || s > Altos.ao_flight_landed)
                                return -1;
                        return s;
@@ -112,7 +117,7 @@ public class AltosGraphDataPoint implements AltosUIDataPoint {
 
        public String id_name(int index) {
                if (index == data_state)
-                       return state.data.state();
+                       return state.state_name();
                return "";
        }
 
index dc047e9aeebb5a0bd4c8fdb9ba2c89bf5103908d..4e6c46d1605a3d2bd840792a6cc447c4b10adae3 100644 (file)
@@ -20,39 +20,36 @@ package altosui;
 import java.lang.*;
 import java.io.*;
 import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 class AltosGraphIterator implements Iterator<AltosUIDataPoint> {
        AltosGraphDataSet       dataSet;
-       Iterator<AltosRecord>   iterator;
-
-       AltosState      state;
+       Iterator<AltosState>    iterator;
 
        public boolean hasNext() {
                return iterator.hasNext();
        }
 
        public AltosUIDataPoint next() {
-               state = new AltosState(iterator.next(), state);
+               AltosState      state = iterator.next();
 
-               if ((state.data.seen & AltosRecord.seen_flight) != 0) {
-                       if (dataSet.callsign == null && state.data.callsign != null)
-                               dataSet.callsign = state.data.callsign;
+               if (state.flight != AltosLib.MISSING) {
+                       if (dataSet.callsign == null && state.callsign != null)
+                               dataSet.callsign = state.callsign;
 
-                       if (dataSet.serial == 0 && state.data.serial != 0)
-                               dataSet.serial = state.data.serial;
+                       if (dataSet.serial == 0 && state.serial != 0)
+                               dataSet.serial = state.serial;
 
-                       if (dataSet.flight == 0 && state.data.flight != 0)
-                               dataSet.flight = state.data.flight;
+                       if (dataSet.flight == 0 && state.flight != 0)
+                               dataSet.flight = state.flight;
                }
 
                return new AltosGraphDataPoint(state);
        }
 
-       public AltosGraphIterator (Iterator<AltosRecord> iterator, AltosGraphDataSet dataSet) {
+       public AltosGraphIterator (Iterator<AltosState> iterator, AltosGraphDataSet dataSet) {
                this.iterator = iterator;
-               this.state = null;
                this.dataSet = dataSet;
        }
 
@@ -64,7 +61,7 @@ class AltosGraphIterable implements Iterable<AltosUIDataPoint> {
        AltosGraphDataSet       dataSet;
 
        public Iterator<AltosUIDataPoint> iterator() {
-               return new AltosGraphIterator(dataSet.records.iterator(), dataSet);
+               return new AltosGraphIterator(dataSet.states.iterator(), dataSet);
        }
 
        public AltosGraphIterable(AltosGraphDataSet dataSet) {
@@ -76,7 +73,7 @@ public class AltosGraphDataSet implements AltosUIDataSet {
        String                  callsign;
        int                     serial;
        int                     flight;
-       AltosRecordIterable     records;
+       AltosStateIterable      states;
 
        public String name() {
                if (callsign != null)
@@ -89,8 +86,8 @@ public class AltosGraphDataSet implements AltosUIDataSet {
                return new AltosGraphIterable(this);
        }
 
-       public AltosGraphDataSet (AltosRecordIterable records) {
-               this.records = records;
+       public AltosGraphDataSet (AltosStateIterable states) {
+               this.states = states;
                this.callsign = null;
                this.serial = 0;
                this.flight = 0;
index d8b8f6dd282d41b1bbce8b4724f7dac3212714a5..c42f7b5f89d4f346517fad948c5b3ec6a86229d4 100644 (file)
@@ -9,7 +9,7 @@ import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 import org.jfree.chart.ChartPanel;
@@ -28,10 +28,9 @@ public class AltosGraphUI extends AltosUIFrame
        AltosFlightStatsTable   statsTable;
        boolean                 has_gps;
 
-       void fill_map(AltosRecordIterable records) {
+       void fill_map(AltosStateIterable states) {
                boolean         any_gps = false;
-               for (AltosRecord record : records) {
-                       state = new AltosState(record, state);
+               for (AltosState state : states) {
                        if (state.gps != null && state.gps.locked && state.gps.nsat >= 4) {
                                if (map == null)
                                        map = new AltosSiteMap();
@@ -41,7 +40,7 @@ public class AltosGraphUI extends AltosUIFrame
                }
        }
 
-       AltosGraphUI(AltosRecordIterable records, File file) throws InterruptedException, IOException {
+       AltosGraphUI(AltosStateIterable states, File file) throws InterruptedException, IOException {
                super(file.getName());
                state = null;
 
@@ -49,8 +48,8 @@ public class AltosGraphUI extends AltosUIFrame
 
                enable = new AltosUIEnable();
 
-               stats = new AltosFlightStats(records);
-               graphDataSet = new AltosGraphDataSet(records);
+               stats = new AltosFlightStats(states);
+               graphDataSet = new AltosGraphDataSet(states);
 
                graph = new AltosGraph(enable, stats, graphDataSet);
 
@@ -61,7 +60,7 @@ public class AltosGraphUI extends AltosUIFrame
                pane.add("Flight Statistics", statsTable);
 
                has_gps = false;
-               fill_map(records);
+               fill_map(states);
                if (has_gps)
                        pane.add("Map", map);
 
index bbab017f1c525779c622e1623f1db541c8d72fba..6a79604efff6b33f894ebaba09e111c652befb9d 100644 (file)
@@ -23,7 +23,8 @@ import javax.swing.*;
 import javax.swing.event.*;
 import java.io.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import java.util.Arrays;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDisplay, AltosFontListener, AltosIdleMonitorListener, DocumentListener {
@@ -38,7 +39,10 @@ public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDispl
 
        void stop_display() {
                if (thread != null) {
-                       thread.abort();
+                       try {
+                               thread.abort();
+                       } catch (InterruptedException ie) {
+                       }
                }
                thread = null;
        }
@@ -65,13 +69,13 @@ public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDispl
 
        public void show(AltosState state, AltosListenerState listener_state) {
                status_update.saved_state = state;
-               try {
+//             try {
                        pad.show(state, listener_state);
                        flightStatus.show(state, listener_state);
                        flightInfo.show(state, listener_state);
-               } catch (Exception e) {
-                       System.out.print("Show exception" + e);
-               }
+//             } catch (Exception e) {
+//                     System.out.print("Show exception " + e);
+//             }
        }
 
        public void update(final AltosState state, final AltosListenerState listener_state) {
@@ -191,7 +195,11 @@ public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDispl
                addWindowListener(new WindowAdapter() {
                                @Override
                                public void windowClosing(WindowEvent e) {
-                                       disconnect();
+                                       try {
+                                               disconnect();
+                                       } catch (Exception ex) {
+                                               System.out.println(Arrays.toString(ex.getStackTrace()));
+                                       }
                                        setVisible(false);
                                        dispose();
                                        AltosUIPreferences.unregister_font_listener(AltosIdleMonitorUI.this);
index 14d4eebcbaf210013215e704ae3b7849613a2161..c8024aaedacf2773338179443abdd98b6c753008 100644 (file)
@@ -23,7 +23,7 @@ import javax.swing.*;
 import java.io.*;
 import java.text.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosIgniteUI
index 3d16faf2cbf369f368563f8ce64dbd006015ccb5..feafed21f32a852e0ecf3d8cec954fe65a97ed21 100644 (file)
@@ -20,7 +20,7 @@ package altosui;
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.table.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosInfoTable extends JTable {
        private AltosFlightInfoTableModel model;
@@ -107,35 +107,37 @@ public class AltosInfoTable extends JTable {
        public void show(AltosState state, AltosListenerState listener_state) {
                info_reset();
                if (state != null) {
-                       if (state.altitude != AltosRecord.MISSING)
-                               info_add_row(0, "Altitude", "%6.0f    m", state.altitude);
-                       if (state.ground_altitude != AltosRecord.MISSING)
-                               info_add_row(0, "Pad altitude", "%6.0f    m", state.ground_altitude);
-                       if (state.height != AltosRecord.MISSING)
-                               info_add_row(0, "Height", "%6.0f    m", state.height);
-                       if (state.height != AltosRecord.MISSING)
-                               info_add_row(0, "Max height", "%6.0f    m", state.max_height);
-                       if (state.acceleration != AltosRecord.MISSING)
-                               info_add_row(0, "Acceleration", "%8.1f  m/s²", state.acceleration);
-                       if (state.acceleration != AltosRecord.MISSING)
-                               info_add_row(0, "Max acceleration", "%8.1f  m/s²", state.max_acceleration);
-                       if (state.speed() != AltosRecord.MISSING)
+                       if (state.device_type != AltosLib.MISSING)
+                               info_add_row(0, "Device", "%s", AltosLib.product_name(state.device_type));
+                       if (state.altitude() != AltosLib.MISSING)
+                               info_add_row(0, "Altitude", "%6.0f    m", state.altitude());
+                       if (state.ground_altitude() != AltosLib.MISSING)
+                               info_add_row(0, "Pad altitude", "%6.0f    m", state.ground_altitude());
+                       if (state.height() != AltosLib.MISSING)
+                               info_add_row(0, "Height", "%6.0f    m", state.height());
+                       if (state.max_height() != AltosLib.MISSING)
+                               info_add_row(0, "Max height", "%6.0f    m", state.max_height());
+                       if (state.acceleration() != AltosLib.MISSING)
+                               info_add_row(0, "Acceleration", "%8.1f  m/s²", state.acceleration());
+                       if (state.max_acceleration() != AltosLib.MISSING)
+                               info_add_row(0, "Max acceleration", "%8.1f  m/s²", state.max_acceleration());
+                       if (state.speed() != AltosLib.MISSING)
                                info_add_row(0, "Speed", "%8.1f  m/s", state.speed());
-                       if (state.speed() != AltosRecord.MISSING)
-                               info_add_row(0, "Max Speed", "%8.1f  m/s", state.max_accel_speed);
-                       if (state.temperature != AltosRecord.MISSING)
+                       if (state.max_speed() != AltosLib.MISSING)
+                               info_add_row(0, "Max Speed", "%8.1f  m/s", state.max_speed());
+                       if (state.temperature != AltosLib.MISSING)
                                info_add_row(0, "Temperature", "%9.2f °C", state.temperature);
-                       if (state.battery != AltosRecord.MISSING)
-                               info_add_row(0, "Battery", "%9.2f V", state.battery);
-                       if (state.drogue_sense != AltosRecord.MISSING)
-                               info_add_row(0, "Drogue", "%9.2f V", state.drogue_sense);
-                       if (state.main_sense != AltosRecord.MISSING)
-                               info_add_row(0, "Main", "%9.2f V", state.main_sense);
+                       if (state.battery_voltage != AltosLib.MISSING)
+                               info_add_row(0, "Battery", "%9.2f V", state.battery_voltage);
+                       if (state.apogee_voltage != AltosLib.MISSING)
+                               info_add_row(0, "Drogue", "%9.2f V", state.apogee_voltage);
+                       if (state.main_voltage != AltosLib.MISSING)
+                               info_add_row(0, "Main", "%9.2f V", state.main_voltage);
                }
                if (listener_state != null) {
                        info_add_row(0, "CRC Errors", "%6d", listener_state.crc_errors);
 
-                       if (listener_state.battery != AltosRecord.MISSING)
+                       if (listener_state.battery != AltosLib.MISSING)
                                info_add_row(0, "Receiver Battery", "%9.2f", listener_state.battery);
                }
 
@@ -148,17 +150,21 @@ public class AltosInfoTable extends JTable {
                                else
                                        info_add_row(1, "GPS state", "wait (%d)",
                                                     state.gps_waiting);
-                               if (state.data.gps.locked)
+                               if (state.gps.locked)
                                        info_add_row(1, "GPS", "   locked");
-                               else if (state.data.gps.connected)
+                               else if (state.gps.connected)
                                        info_add_row(1, "GPS", " unlocked");
                                else
                                        info_add_row(1, "GPS", "  missing");
-                               info_add_row(1, "Satellites", "%6d", state.data.gps.nsat);
-                               info_add_deg(1, "Latitude", state.gps.lat, 'N', 'S');
-                               info_add_deg(1, "Longitude", state.gps.lon, 'E', 'W');
-                               info_add_row(1, "GPS altitude", "%6d", state.gps.alt);
-                               info_add_row(1, "GPS height", "%6.0f", state.gps_height);
+                               info_add_row(1, "Satellites", "%6d", state.gps.nsat);
+                               if (state.gps.lat != AltosLib.MISSING)
+                                       info_add_deg(1, "Latitude", state.gps.lat, 'N', 'S');
+                               if (state.gps.lon != AltosLib.MISSING)
+                                       info_add_deg(1, "Longitude", state.gps.lon, 'E', 'W');
+                               if (state.gps.alt != AltosLib.MISSING)
+                                       info_add_row(1, "GPS altitude", "%8.1f", state.gps.alt);
+                               if (state.gps_height != AltosLib.MISSING)
+                                       info_add_row(1, "GPS height", "%8.1f", state.gps_height);
 
                                /* The SkyTraq GPS doesn't report these values */
                                /*
@@ -195,14 +201,16 @@ public class AltosInfoTable extends JTable {
                                        info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W');
                                        info_add_row(1, "Pad GPS alt", "%6.0f m", state.pad_alt);
                                }
-                               info_add_row(1, "GPS date", "%04d-%02d-%02d",
-                                            state.gps.year,
-                                            state.gps.month,
-                                            state.gps.day);
-                               info_add_row(1, "GPS time", "  %02d:%02d:%02d",
-                                            state.gps.hour,
-                                            state.gps.minute,
-                                            state.gps.second);
+                               if (state.gps.year != AltosLib.MISSING) 
+                                       info_add_row(1, "GPS date", "%04d-%02d-%02d",
+                                                    state.gps.year,
+                                                    state.gps.month,
+                                                    state.gps.day);
+                               if (state.gps.hour != AltosLib.MISSING)
+                                       info_add_row(1, "GPS time", "  %02d:%02d:%02d",
+                                                    state.gps.hour,
+                                                    state.gps.minute,
+                                                    state.gps.second);
                                //int   nsat_vis = 0;
                                int     c;
 
index 140f3f0766b9bdb792a733c02d48dbf68f3fc869..fbb0ece41867319c95f15a3b5cf38fff9d2350f6 100644 (file)
 package altosui;
 
 import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosKML implements AltosWriter {
 
        File                    name;
        PrintStream             out;
-       int                     state = -1;
-       AltosRecord             prev = null;
+       int                     flight_state = -1;
+       AltosState              prev = null;
        double                  gps_start_altitude;
 
        static final String[] kml_state_colors = {
@@ -83,7 +83,7 @@ public class AltosKML implements AltosWriter {
                "</Document>\n" +
                "</kml>\n";
 
-       void start (AltosRecord record) {
+       void start (AltosState record) {
                out.printf(kml_header_start, record.flight, record.serial);
                out.printf("Date:   %04d-%02d-%02d\n",
                           record.gps.year, record.gps.month, record.gps.day);
@@ -94,30 +94,30 @@ public class AltosKML implements AltosWriter {
 
        boolean started = false;
 
-       void state_start(AltosRecord record) {
-               String  state_name = Altos.state_name(record.state);
-               out.printf(kml_style_start, state_name, kml_state_colors[record.state]);
+       void state_start(AltosState state) {
+               String  state_name = Altos.state_name(state.state);
+               out.printf(kml_style_start, state_name, kml_state_colors[state.state]);
                out.printf("\tState: %s\n", state_name);
                out.printf("%s", kml_style_end);
                out.printf(kml_placemark_start, state_name, state_name);
        }
 
-       void state_end(AltosRecord record) {
+       void state_end(AltosState state) {
                out.printf("%s", kml_placemark_end);
        }
 
-       void coord(AltosRecord record) {
-               AltosGPS        gps = record.gps;
+       void coord(AltosState state) {
+               AltosGPS        gps = state.gps;
                double          altitude;
 
-               if (record.height() != AltosRecord.MISSING)
-                       altitude = record.height() + gps_start_altitude;
+               if (state.height() != AltosLib.MISSING)
+                       altitude = state.height() + gps_start_altitude;
                else
                        altitude = gps.alt;
                out.printf(kml_coord_fmt,
                           gps.lon, gps.lat,
                           altitude, (double) gps.alt,
-                          record.time, gps.nsat);
+                          state.time, gps.nsat);
        }
 
        void end() {
@@ -132,38 +132,40 @@ public class AltosKML implements AltosWriter {
                }
        }
 
-       public void write(AltosRecord record) {
-               AltosGPS        gps = record.gps;
+       public void write(AltosState state) {
+               AltosGPS        gps = state.gps;
 
                if (gps == null)
                        return;
 
-               if ((record.seen & (AltosRecord.seen_gps_lat)) == 0)
+               if (gps.lat == AltosLib.MISSING)
                        return;
-               if ((record.seen & (AltosRecord.seen_gps_lon)) == 0)
+               if (gps.lon == AltosLib.MISSING)
                        return;
                if (!started) {
-                       start(record);
+                       start(state);
                        started = true;
                        gps_start_altitude = gps.alt;
                }
-               if (prev != null && prev.gps_sequence == record.gps_sequence)
+               if (prev != null && prev.gps_sequence == state.gps_sequence)
                        return;
-               if (record.state != state) {
-                       state = record.state;
+               if (state.state != flight_state) {
+                       flight_state = state.state;
                        if (prev != null) {
-                               coord(record);
+                               coord(state);
                                state_end(prev);
                        }
-                       state_start(record);
+                       state_start(state);
                }
-               coord(record);
-               prev = record;
+               coord(state);
+               prev = state;
        }
 
-       public void write(AltosRecordIterable iterable) {
-               for (AltosRecord record : iterable)
-                       write(record);
+       public void write(AltosStateIterable states) {
+               for (AltosState state : states) {
+                       if ((state.set & AltosState.set_gps) != 0)
+                               write(state);
+               }
        }
 
        public AltosKML(File in_name) throws FileNotFoundException {
index 1d209bda8ccaa493371d104126efb2d1c6ca21c2..cc2053e0ca5fe7896557241f31e9dc0bb2854424 100644 (file)
@@ -21,7 +21,7 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosLanded extends JComponent implements AltosFlightDisplay, ActionListener {
        GridBagLayout   layout;
@@ -103,7 +103,8 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
 
        class Lat extends LandedValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state.gps != null && state.gps.connected)
+                       show();
+                       if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
                                show(pos(state.gps.lat,"N", "S"));
                        else
                                show("???");
@@ -118,7 +119,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
        class Lon extends LandedValue {
                void show (AltosState state, AltosListenerState listener_state) {
                        show();
-                       if (state.gps != null && state.gps.connected)
+                       if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
                                show(pos(state.gps.lon,"E", "W"));
                        else
                                show("???");
@@ -162,7 +163,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
 
        class Height extends LandedValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.height, state.max_height);
+                       show(AltosConvert.height, state.max_height());
                }
                public Height (GridBagLayout layout, int y) {
                        super (layout, y, "Maximum Height");
@@ -184,7 +185,7 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
 
        class Accel extends LandedValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.accel, state.max_acceleration);
+                       show(AltosConvert.accel, state.max_acceleration());
                }
                public Accel (GridBagLayout layout, int y) {
                        super (layout, y, "Maximum Acceleration");
@@ -243,21 +244,18 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
                        if (file != null) {
                                String  filename = file.getName();
                                try {
-                                       AltosRecordIterable records = null;
+                                       AltosStateIterable states = null;
                                        if (filename.endsWith("eeprom")) {
                                                FileInputStream in = new FileInputStream(file);
-                                               records = new AltosEepromIterable(in);
+                                               states = new AltosEepromFile(in);
                                        } else if (filename.endsWith("telem")) {
                                                FileInputStream in = new FileInputStream(file);
-                                               records = new AltosTelemetryIterable(in);
-                                       } else if (filename.endsWith("mega")) {
-                                               FileInputStream in = new FileInputStream(file);
-                                               records = new AltosEepromMegaIterable(in);
+                                               states = new AltosTelemetryFile(in);
                                        } else {
                                                throw new FileNotFoundException(filename);
                                        }
                                        try {
-                                               new AltosGraphUI(records, file);
+                                               new AltosGraphUI(states, file);
                                        } catch (InterruptedException ie) {
                                        } catch (IOException ie) {
                                        }
index e2316a13c813a26fd248f5bb0737040391dbde0e..06a0f1efa2bc9c3855c2760bbfb3b71ff9a2b0e3 100644 (file)
@@ -19,7 +19,7 @@ package altosui;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosPad extends JComponent implements AltosFlightDisplay {
        GridBagLayout   layout;
@@ -176,11 +176,11 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class Battery extends LaunchStatus {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state == null || state.battery == AltosRecord.MISSING)
+                       if (state == null || state.battery_voltage == AltosLib.MISSING)
                                hide();
                        else {
-                               show("%4.2f V", state.battery);
-                               lights.set(state.battery > 3.7);
+                               show("%4.2f V", state.battery_voltage);
+                               lights.set(state.battery_voltage >= AltosLib.ao_battery_good);
                        }
                }
                public Battery (GridBagLayout layout, int y) {
@@ -192,11 +192,11 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class Apogee extends LaunchStatus {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state == null || state.drogue_sense == AltosRecord.MISSING)
+                       if (state == null || state.apogee_voltage == AltosLib.MISSING)
                                hide();
                        else {
-                               show("%4.2f V", state.drogue_sense);
-                               lights.set(state.drogue_sense > 3.2);
+                               show("%4.2f V", state.apogee_voltage);
+                               lights.set(state.apogee_voltage >= AltosLib.ao_igniter_good);
                        }
                }
                public Apogee (GridBagLayout layout, int y) {
@@ -208,11 +208,11 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class Main extends LaunchStatus {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state == null || state.main_sense == AltosRecord.MISSING)
+                       if (state == null || state.main_voltage == AltosLib.MISSING)
                                hide();
                        else {
-                               show("%4.2f V", state.main_sense);
-                               lights.set(state.main_sense > 3.2);
+                               show("%4.2f V", state.main_voltage);
+                               lights.set(state.main_voltage >= AltosLib.ao_igniter_good);
                        }
                }
                public Main (GridBagLayout layout, int y) {
@@ -224,19 +224,19 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class LoggingReady extends LaunchStatus {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state == null || state.data.flight == AltosRecord.MISSING) {
+                       if (state == null || state.flight == AltosLib.MISSING) {
                                hide();
                        } else {
-                               if (state.data.flight != 0) {
-                                       if (state.data.state <= Altos.ao_flight_pad)
+                               if (state.flight != 0) {
+                                       if (state.state <= Altos.ao_flight_pad)
                                                show("Ready to record");
-                                       else if (state.data.state < Altos.ao_flight_landed)
+                                       else if (state.state < Altos.ao_flight_landed)
                                                show("Recording data");
                                        else
                                                show("Recorded data");
                                } else
                                        show("Storage full");
-                               lights.set(state.data.flight != 0);
+                               lights.set(state.flight != 0);
                        }
                }
                public LoggingReady (GridBagLayout layout, int y) {
@@ -283,11 +283,11 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class ReceiverBattery extends LaunchStatus {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (listener_state == null || listener_state.battery == AltosRecord.MISSING)
+                       if (listener_state == null || listener_state.battery == AltosLib.MISSING)
                                hide();
                        else {
                                show("%4.2f V", listener_state.battery);
-                               lights.set(listener_state.battery > 3.7);
+                               lights.set(listener_state.battery > AltosLib.ao_battery_good);
                        }
                }
                public ReceiverBattery (GridBagLayout layout, int y) {
@@ -310,17 +310,23 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class PadLat extends LaunchValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state == null || state.gps == null) {
-                               hide();
-                       } else {
-                               if (state.state < AltosLib.ao_flight_pad) {
-                                       show(pos(state.gps.lat,"N", "S"));
-                                       set_label("Latitude");
-                               } else { 
-                                       show(pos(state.pad_lat,"N", "S"));
-                                       set_label("Pad Latitude");
+                       double lat = AltosLib.MISSING;
+                       String label = null;
+
+                       if (state != null) {
+                               if (state.state < AltosLib.ao_flight_pad && state.gps != null && state.gps.lat != AltosLib.MISSING) {
+                                       lat = state.gps.lat;
+                                       label = "Latitude";
+                               } else {
+                                       lat = state.pad_lat;
+                                       label = "Pad Latitude";
                                }
                        }
+                       if (lat != AltosLib.MISSING) {
+                               show(pos(lat,"N", "S"));
+                               set_label(label);
+                       } else
+                               hide();
                }
                public PadLat (GridBagLayout layout, int y) {
                        super (layout, y, "Pad Latitude");
@@ -331,17 +337,23 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class PadLon extends LaunchValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state == null || state.gps == null) {
-                               hide();
-                       } else {
-                               if (state.state < AltosLib.ao_flight_pad) {
-                                       show(pos(state.gps.lon,"E", "W"));
-                                       set_label("Longitude");
-                               } else { 
-                                       show(pos(state.pad_lon,"E", "W"));
-                                       set_label("Pad Longitude");
+                       double lon = AltosLib.MISSING;
+                       String label = null;
+
+                       if (state != null) {
+                               if (state.state < AltosLib.ao_flight_pad && state.gps != null && state.gps.lon != AltosLib.MISSING) {
+                                       lon = state.gps.lon;
+                                       label = "Longitude";
+                               } else {
+                                       lon = state.pad_lon;
+                                       label = "Pad Longitude";
                                }
                        }
+                       if (lon != AltosLib.MISSING) {
+                               show(pos(lon,"E", "W"));
+                               set_label(label);
+                       } else
+                               hide();
                }
                public PadLon (GridBagLayout layout, int y) {
                        super (layout, y, "Pad Longitude");
@@ -352,21 +364,23 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
 
        class PadAlt extends LaunchValue {
                void show (AltosState state, AltosListenerState listener_state) {
-                       if (state == null)
-                               hide();
-                       else {
-                               if (state.state < AltosLib.ao_flight_pad && state.gps != null) {
-                                       show("%4.0f m", state.gps.alt);
-                                       set_label("Altitude");
+                       double alt = AltosLib.MISSING;
+                       String label = null;
+
+                       if (state != null) {
+                               if (state.state < AltosLib.ao_flight_pad && state.gps != null && state.gps.alt != AltosLib.MISSING) {
+                                       alt = state.gps.alt;
+                                       label = "Altitude";
                                } else {
-                                       if (state.pad_alt == AltosRecord.MISSING)
-                                               hide();
-                                       else {
-                                               show("%4.0f m", state.pad_alt);
-                                               set_label("Pad Altitude");
-                                       }
+                                       alt = state.pad_alt;
+                                       label = "Pad Altitude";
                                }
                        }
+                       if (alt != AltosLib.MISSING) {
+                               show("%4.0f m", state.gps.alt);
+                               set_label(label);
+                       } else
+                               hide();
                }
                public PadAlt (GridBagLayout layout, int y) {
                        super (layout, y, "Pad Altitude");
index 909e72a013af68eb735297f9de2cd73fd2d02a6e..fa7801257289c2f7577449b54a6bcfecacaeb29b 100644 (file)
@@ -20,7 +20,7 @@ package altosui;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosRomconfigUI
@@ -91,7 +91,7 @@ public class AltosRomconfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = ir;
                c.ipady = 5;
-               radio_calibration_value = new JTextField("1186611");
+               radio_calibration_value = new JTextField("0");
                pane.add(radio_calibration_value, c);
 
                /* Buttons */
index 0c903873b45fd69a9a8268e4ac9dc7cfd6814737..a5ccb15aac379a6d6cb82dc8a0a4850b8eb567f0 100644 (file)
@@ -25,7 +25,7 @@ import java.io.*;
 import java.util.*;
 import java.text.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 class AltosScanResult {
@@ -184,13 +184,13 @@ public class AltosScanUI
                        try {
                                for (;;) {
                                        try {
-                                               AltosRecord     record = reader.read();
-                                               if (record == null)
+                                               AltosState      state = reader.read();
+                                               if (state == null)
                                                        continue;
-                                               if ((record.seen & AltosRecord.seen_flight) != 0) {
-                                                       final AltosScanResult   result = new AltosScanResult(record.callsign,
-                                                                                                    record.serial,
-                                                                                                    record.flight,
+                                               if (state.flight != AltosLib.MISSING) {
+                                                       final AltosScanResult   result = new AltosScanResult(state.callsign,
+                                                                                                    state.serial,
+                                                                                                    state.flight,
                                                                                                     frequencies[frequency_index],
                                                                                                     telemetry);
                                                        Runnable r = new Runnable() {
index e869f1ab1ac3688a9eaa6c964c6cd64729af2e0b..5e9322e598a5a143c8fda318d2635613dbcc76ac 100644 (file)
@@ -25,7 +25,7 @@ import java.io.*;
 import java.util.*;
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 import libaltosJNI.*;
@@ -57,11 +57,8 @@ public class AltosSerial extends AltosLink  {
        public void flush_output() {
                super.flush_output();
                if (altos != null) {
-                       if (libaltos.altos_flush(altos) != 0) {
-                               libaltos.altos_close(altos);
-                               altos = null;
-                               abort_reply();
-                       }
+                       if (libaltos.altos_flush(altos) != 0)
+                               close_serial();
                }
        }
 
@@ -122,6 +119,17 @@ public class AltosSerial extends AltosLink  {
                SwingUtilities.invokeLater(r);
        }
 
+       private void close_serial() {
+               synchronized (devices_opened) {
+                       devices_opened.remove(device.getPath());
+               }
+               if (altos != null) {
+                       libaltos.altos_free(altos);
+                       altos = null;
+               }
+               abort_reply();
+       }
+
        public void close() {
                if (remote) {
                        try {
@@ -132,35 +140,33 @@ public class AltosSerial extends AltosLink  {
                if (in_reply != 0)
                        System.out.printf("Uh-oh. Closing active serial device\n");
 
-               if (altos != null) {
-                       libaltos.altos_close(altos);
-               }
+               close_serial();
+
                if (input_thread != null) {
                        try {
                                input_thread.interrupt();
                                input_thread.join();
-                       } catch (InterruptedException e) {
+                       } catch (InterruptedException ie) {
                        }
                        input_thread = null;
                }
-               if (altos != null) {
-                       libaltos.altos_free(altos);
-                       altos = null;
-               }
-               synchronized (devices_opened) {
-                       devices_opened.remove(device.getPath());
-               }
                if (debug)
                        System.out.printf("Closing %s\n", device.getPath());
        }
 
        private void putc(char c) {
                if (altos != null)
-                       if (libaltos.altos_putchar(altos, c) != 0) {
-                               libaltos.altos_close(altos);
-                               altos = null;
-                               abort_reply();
-                       }
+                       if (libaltos.altos_putchar(altos, c) != 0)
+                               close_serial();
+       }
+
+       public void putchar(byte c) {
+               if (altos != null) {
+                       if (debug)
+                               System.out.printf(" %02x", (int) c & 0xff);
+                       if (libaltos.altos_putchar(altos, (char) c) != 0)
+                               close_serial();
+               }
        }
 
        public void print(String data) {
index 23085f3ec5e270645b8c44760c34fb9202d61271..9491ce2be4b95c4ddf5f400beda942a23a1294bf 100644 (file)
@@ -23,7 +23,7 @@ import java.io.*;
 import java.lang.Math;
 import java.awt.geom.Point2D;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
@@ -271,27 +271,34 @@ public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
        int last_state = -1;
 
        public void show(double lat, double lon) {
-               initMaps(lat, lon);
-               scrollRocketToVisible(pt(lat, lon));
+               System.out.printf ("show %g %g\n", lat, lon);
+               return;
+//             initMaps(lat, lon);
+//             scrollRocketToVisible(pt(lat, lon));
        }
        public void show(final AltosState state, final AltosListenerState listener_state) {
                // if insufficient gps data, nothing to update
-               if (!state.gps.locked && state.gps.nsat < 4)
+               AltosGPS        gps = state.gps;
+
+               if (gps == null)
+                       return;
+
+               if (!gps.locked && gps.nsat < 4)
                        return;
 
                if (!initialised) {
-                       if (state.pad_lat != 0 || state.pad_lon != 0) {
+                       if (state.pad_lat != AltosLib.MISSING && state.pad_lon != AltosLib.MISSING) {
                                initMaps(state.pad_lat, state.pad_lon);
                                initialised = true;
-                       } else if (state.gps.lat != 0 || state.gps.lon != 0) {
-                               initMaps(state.gps.lat, state.gps.lon);
+                       } else if (gps.lat != AltosLib.MISSING && gps.lon != AltosLib.MISSING) {
+                               initMaps(gps.lat, gps.lon);
                                initialised = true;
                        } else {
                                return;
                        }
                }
 
-               final Point2D.Double pt = pt(state.gps.lat, state.gps.lon);
+               final Point2D.Double pt = pt(gps.lat, gps.lon);
                if (last_pt == pt && last_state == state.state)
                        return;
 
index 365e4b6c3c36846a96e9fdc91ffed0fec6e072af..172e6397c6fe9875d193940932e6037c7f10e0f0 100644 (file)
@@ -22,7 +22,7 @@ import java.awt.image.*;
 import javax.swing.*;
 import java.awt.geom.Point2D;
 import java.awt.geom.Line2D;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosSiteMapTile extends JLayeredPane {
        JLabel mapLabel;
index 9f8f6ddac4285a0bee154d6267b52e429ec01d54..9dad8718507dd384c07a59c5506fb4d8234b2cc4 100644 (file)
@@ -22,7 +22,7 @@ import java.awt.event.*;
 import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class AltosUI extends AltosUIFrame {
@@ -290,9 +290,9 @@ public class AltosUI extends AltosUIFrame {
                AltosDataChooser chooser = new AltosDataChooser(
                        AltosUI.this);
 
-               AltosRecordIterable iterable = chooser.runDialog();
-               if (iterable != null) {
-                       AltosFlightReader reader = new AltosReplayReader(iterable.iterator(),
+               Iterable<AltosState> states = chooser.runDialog();
+               if (states != null) {
+                       AltosFlightReader reader = new AltosReplayReader(states.iterator(),
                                                                         chooser.file());
                        new AltosFlightUI(voice, reader);
                }
@@ -312,10 +312,10 @@ public class AltosUI extends AltosUIFrame {
        private void ExportData() {
                AltosDataChooser chooser;
                chooser = new AltosDataChooser(this);
-               AltosRecordIterable record_reader = chooser.runDialog();
-               if (record_reader == null)
+               AltosStateIterable states = chooser.runDialog();
+               if (states == null)
                        return;
-               new AltosCSVUI(AltosUI.this, record_reader, chooser.file());
+               new AltosCSVUI(AltosUI.this, states, chooser.file());
        }
 
        /* Load a flight log CSV file and display a pretty graph.
@@ -324,11 +324,11 @@ public class AltosUI extends AltosUIFrame {
        private void GraphData() {
                AltosDataChooser chooser;
                chooser = new AltosDataChooser(this);
-               AltosRecordIterable record_reader = chooser.runDialog();
-               if (record_reader == null)
+               AltosStateIterable states = chooser.runDialog();
+               if (states == null)
                        return;
                try {
-                       new AltosGraphUI(record_reader, chooser.file());
+                       new AltosGraphUI(states, chooser.file());
                } catch (InterruptedException ie) {
                } catch (IOException ie) {
                }
@@ -345,17 +345,15 @@ public class AltosUI extends AltosUIFrame {
                }
        }
 
-       static AltosRecordIterable open_logfile(File file) {
+       static AltosStateIterable open_logfile(File file) {
                try {
                        FileInputStream in;
 
                        in = new FileInputStream(file);
-                       if (file.getName().endsWith("eeprom"))
-                               return new AltosEepromIterable(in);
-                       else if (file.getName().endsWith("mega"))
-                               return new AltosEepromMegaIterable(in);
+                       if (file.getName().endsWith("telem"))
+                               return new AltosTelemetryFile(in);
                        else
-                               return new AltosTelemetryIterable(in);
+                               return new AltosEepromFile(in);
                } catch (FileNotFoundException fe) {
                        System.out.printf("%s\n", fe.getMessage());
                        return null;
@@ -386,10 +384,11 @@ public class AltosUI extends AltosUIFrame {
        static final int process_graph = 3;
        static final int process_replay = 4;
        static final int process_summary = 5;
+       static final int process_cat = 6;
 
        static boolean process_csv(File input) {
-               AltosRecordIterable iterable = open_logfile(input);
-               if (iterable == null)
+               AltosStateIterable states = open_logfile(input);
+               if (states == null)
                        return false;
 
                File output = Altos.replace_extension(input,".csv");
@@ -401,15 +400,15 @@ public class AltosUI extends AltosUIFrame {
                        AltosWriter writer = open_csv(output);
                        if (writer == null)
                                return false;
-                       writer.write(iterable);
+                       writer.write(states);
                        writer.close();
                }
                return true;
        }
 
        static boolean process_kml(File input) {
-               AltosRecordIterable iterable = open_logfile(input);
-               if (iterable == null)
+               AltosStateIterable states = open_logfile(input);
+               if (states == null)
                        return false;
 
                File output = Altos.replace_extension(input,".kml");
@@ -421,13 +420,13 @@ public class AltosUI extends AltosUIFrame {
                        AltosWriter writer = open_kml(output);
                        if (writer == null)
                                return false;
-                       writer.write(iterable);
+                       writer.write(states);
                        writer.close();
                        return true;
                }
        }
 
-       static AltosRecordIterable record_iterable(File file) {
+       static AltosStateIterable record_iterable(File file) {
                FileInputStream in;
                try {
                        in = new FileInputStream(file);
@@ -435,23 +434,17 @@ public class AltosUI extends AltosUIFrame {
                        System.out.printf("Failed to open file '%s'\n", file);
                        return null;
                }
-               AltosRecordIterable recs;
-               //AltosReplayReader reader;
-               if (file.getName().endsWith("eeprom")) {
-                       recs = new AltosEepromIterable(in);
-               } else if (file.getName().endsWith("mega")) {
-                       recs = new AltosEepromMegaIterable(in);
-               } else {
-                       recs = new AltosTelemetryIterable(in);
-               }
-               return recs;
+               if (file.getName().endsWith("telem"))
+                       return new AltosTelemetryFile(in);
+               else
+                       return new AltosEepromFile(in);
        }
 
        static AltosReplayReader replay_file(File file) {
-               AltosRecordIterable recs = record_iterable(file);
-               if (recs == null)
+               AltosStateIterable states = record_iterable(file);
+               if (states == null)
                        return null;
-               return new AltosReplayReader(recs.iterator(), file);
+               return new AltosReplayReader(states.iterator(), file);
        }
 
        static boolean process_replay(File file) {
@@ -464,11 +457,11 @@ public class AltosUI extends AltosUIFrame {
        }
 
        static boolean process_graph(File file) {
-               AltosRecordIterable recs = record_iterable(file);
-               if (recs == null)
+               AltosStateIterable states = record_iterable(file);
+               if (states == null)
                        return false;
                try {
-                       new AltosGraphUI(recs, file);
+                       new AltosGraphUI(states, file);
                        return true;
                } catch (InterruptedException ie) {
                } catch (IOException ie) {
@@ -477,11 +470,11 @@ public class AltosUI extends AltosUIFrame {
        }
        
        static boolean process_summary(File file) {
-               AltosRecordIterable iterable = record_iterable(file);
-               if (iterable == null)
+               AltosStateIterable states = record_iterable(file);
+               if (states == null)
                        return false;
                try {
-                       AltosFlightStats stats = new AltosFlightStats(iterable);
+                       AltosFlightStats stats = new AltosFlightStats(states);
                        if (stats.serial > 0)
                                System.out.printf("Serial:       %5d\n", stats.serial);
                        if (stats.flight > 0)
@@ -499,18 +492,18 @@ public class AltosUI extends AltosUIFrame {
                                          stats.max_speed,
                                          AltosConvert.meters_to_feet(stats.max_speed),
                                          AltosConvert.meters_to_mach(stats.max_speed));
-                       if (stats.max_acceleration != AltosRecord.MISSING) {
+                       if (stats.max_acceleration != AltosLib.MISSING) {
                                System.out.printf("Max accel:   %6.0f m/s² %6.0f ft/s² %6.2f g\n",
                                                  stats.max_acceleration,
                                                  AltosConvert.meters_to_feet(stats.max_acceleration),
                                                  AltosConvert.meters_to_g(stats.max_acceleration));
                        }
                        System.out.printf("Drogue rate: %6.0f m/s  %6.0f ft/s\n",
-                                         stats.state_baro_speed[Altos.ao_flight_drogue],
-                                         AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_drogue]));
+                                         stats.state_speed[Altos.ao_flight_drogue],
+                                         AltosConvert.meters_to_feet(stats.state_speed[Altos.ao_flight_drogue]));
                        System.out.printf("Main rate:   %6.0f m/s  %6.0f ft/s\n",
-                                         stats.state_baro_speed[Altos.ao_flight_main],
-                                         AltosConvert.meters_to_feet(stats.state_baro_speed[Altos.ao_flight_main]));
+                                         stats.state_speed[Altos.ao_flight_main],
+                                         AltosConvert.meters_to_feet(stats.state_speed[Altos.ao_flight_main]));
                        System.out.printf("Flight time: %6.0f s\n",
                                          stats.state_end[Altos.ao_flight_main] -
                                          stats.state_start[Altos.ao_flight_boost]);
@@ -521,6 +514,29 @@ public class AltosUI extends AltosUIFrame {
                return false;
        }
 
+       static boolean process_cat(File file) {
+               try {
+                       AltosStateIterable eef = record_iterable(file);
+
+                       System.out.printf ("process cat\n");
+                       for (AltosState state : eef) {
+                               System.out.printf ("tick %d state %d height %g\n",
+                                                  state.tick, state.state, state.height());
+                               if ((state.set & AltosState.set_gps) != 0)
+                                       System.out.printf ("time %g lat %g lon %g alt %g\n",
+                                                          state.time_since_boost(),
+                                                          state.gps.lat,
+                                                          state.gps.lon,
+                                                          state.gps.alt);
+                       }
+
+               } catch (Exception e) {
+                       System.out.printf("Failed to open file '%s'\n", file);
+                       return false;
+               }
+               return true;
+       }
+
        public static void help(int code) {
                System.out.printf("Usage: altosui [OPTION]... [FILE]...\n");
                System.out.printf("  Options:\n");
@@ -570,6 +586,8 @@ public class AltosUI extends AltosUIFrame {
                                        process = process_graph;
                                else if (args[i].equals("--summary"))
                                        process = process_summary;
+                               else if (args[i].equals("--cat"))
+                                       process = process_cat;
                                else if (args[i].startsWith("--"))
                                        help(1);
                                else {
@@ -596,6 +614,9 @@ public class AltosUI extends AltosUIFrame {
                                                if (!process_summary(file))
                                                        ++errors;
                                                break;
+                                       case process_cat:
+                                               if (!process_cat(file))
+                                                       ++errors;
                                        }
                                }
                        }
index 0dac9fc74f3dc3dad4c222824eeb10b0fd1be77f..fb5f8520a2c5039d2f8eef6f31b88009ecb79299 100644 (file)
@@ -19,7 +19,7 @@ package altosui;
 
 import java.io.File;
 import java.util.prefs.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import javax.swing.filechooser.FileSystemView;
 
 public class AltosUIPreferencesBackend implements AltosPreferencesBackend {
index 2f70b472b8906a2030873a01c0f5f512851dca70..d664d6e825fe28c556a9b0725952f18fd8686b70 100644 (file)
 
 package altosui;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 
 public interface AltosWriter {
 
-       public void write(AltosRecord record);
+       public void write(AltosState state);
 
-       public void write(AltosRecordIterable iterable);
+       public void write(AltosStateIterable states);
 
        public void close();
 }
index 78e29cd8242fc33d1dd525b6341cfdddd399cf15..824ec9e103019a3aa46d7a7fe2fe24b485e8c9ff 100644 (file)
@@ -1,6 +1,6 @@
 
 JAVAROOT=classes
-AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
 
 man_MANS=altosui.1
 
@@ -34,10 +34,8 @@ altosui_JAVA = \
        AltosDeviceUIDialog.java \
        AltosDisplayThread.java \
        AltosEepromDelete.java \
-       AltosEepromDownload.java \
-       AltosEepromList.java \
        AltosEepromManage.java \
-       AltosEepromMonitor.java \
+       AltosEepromMonitorUI.java \
        AltosEepromSelect.java \
        AltosFlashUI.java \
        AltosFlightDisplay.java \
@@ -137,26 +135,35 @@ ICONJAR= -C $(ICONDIR) altus-metrum-16.png \
 WINDOWS_ICON=$(ICONDIR)/altus-metrum.ico
 
 # Firmware
-FIRMWARE_TD_0_2=$(top_srcdir)/src/teledongle-v0.2-$(VERSION).ihx
+FIRMWARE_TD_0_2=$(top_srcdir)/src/teledongle-v0.2/teledongle-v0.2-$(VERSION).ihx
 FIRMWARE_TD=$(FIRMWARE_TD_0_2)
 
-FIRMWARE_TM_1_0=$(top_srcdir)/src/telemetrum-v1.0-$(VERSION).ihx
-FIRMWARE_TM_1_1=$(top_srcdir)/src/telemetrum-v1.1-$(VERSION).ihx
-FIRMWARE_TM_1_2=$(top_srcdir)/src/telemetrum-v1.2-$(VERSION).ihx
+FIRMWARE_TM_1_0=$(top_srcdir)/src/telemetrum-v1.0/telemetrum-v1.0-$(VERSION).ihx
+FIRMWARE_TM_1_1=$(top_srcdir)/src/telemetrum-v1.1/telemetrum-v1.1-$(VERSION).ihx
+FIRMWARE_TM_1_2=$(top_srcdir)/src/telemetrum-v1.2/telemetrum-v1.2-$(VERSION).ihx
 FIRMWARE_TM=$(FIRMWARE_TM_1_0) $(FIRMWARE_TM_1_1) $(FIRMWARE_TM_1_2)
 
-FIRMWARE_TELEMINI_1_0=$(top_srcdir)/src/telemini-v1.0-$(VERSION).ihx
+FIRMWARE_TELEMINI_1_0=$(top_srcdir)/src/telemini-v1.0/telemini-v1.0-$(VERSION).ihx
 FIRMWARE_TELEMINI=$(FIRMWARE_TELEMINI_1_0)
 
-FIRMWARE_TBT_1_0=$(top_srcdir)/src/telebt-v1.0-$(VERSION).ihx
+FIRMWARE_TBT_1_0=$(top_srcdir)/src/telebt-v1.0/telebt-v1.0-$(VERSION).ihx
 FIRMWARE_TBT=$(FIRMWARE_TBT_1_0)
 
-FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT)
+FIRMWARE_TMEGA_1_0=$(top_srcdir)/src/telemega-v1.0/telemega-v1.0-$(VERSION).ihx
+FIRMWARE_TMEGA=$(FIRMWARE_TMEGA_1_0)
+
+FIRMWARE_EMINI_1_0=$(top_srcdir)/src/easymini-v1.0/easymini-v1.0-$(VERSION).ihx
+
+FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT) $(FIRMWARE_TMEGA) $(FIRMWARE_EMINI)
 
 ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf
 ALTOS_DOC=$(top_srcdir)/doc/altos.pdf
 TELEMETRY_DOC=$(top_srcdir)/doc/telemetry.pdf
-TEMPLATE_DOC=$(top_srcdir)/doc/telemetrum-outline.pdf $(top_srcdir)/doc/telemega-outline.pdf
+TEMPLATE_DOC=\
+       $(top_srcdir)/doc/telemetrum-outline.pdf \
+       $(top_srcdir)/doc/easymini-outline.pdf \
+       $(top_srcdir)/doc/telemega-outline.pdf \
+       $(top_srcdir)/doc/easymini-outline.pdf
 
 DOC=$(ALTUSMETRUM_DOC) $(ALTOS_DOC) $(TELEMETRY_DOC) $(TEMPLATE_DOC)
 
@@ -171,7 +178,7 @@ LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) $(DOC)
 LINUX_EXTRA=altosui-fat
 
 MACOSX_INFO_PLIST=Info.plist
-MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) ReadMe-Mac.rtf
+MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(DOC) ReadMe-Mac.rtf
 MACOSX_EXTRA=$(FIRMWARE)
 
 WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON)
@@ -322,6 +329,8 @@ $(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) Makefile
        mkdir macosx
        cp -a AltosUI.app macosx/
        cp -a ReadMe-Mac.rtf macosx/ReadMe.rtf
+       mkdir -p macosx/Doc
+       cp -a $(DOC) macosx/Doc
        cp -p Info.plist macosx/AltosUI.app/Contents
        mkdir -p macosx/AltOS-$(VERSION) macosx/AltosUI.app/Contents/Resources/Java
        cp -p $(FATJAR) macosx/AltosUI.app/Contents/Resources/Java/altosui.jar
index 81506bb0cfb331ffb8e6c0fe7dafe8fa291eb4af..779b0c1279cf6c1b98daa4c6d69393e66bf9e26f 100644 (file)
@@ -121,6 +121,8 @@ Section "TeleMetrum, TeleDongle and TeleBT Firmware"
        File "../src/telemini-v1.0/telemini-v1.0-${VERSION}.ihx"
        File "../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx"
        File "../src/telebt-v1.0/telebt-v1.0-${VERSION}.ihx"
+       File "../src/telemega-v1.0/telemega-v1.0-${VERSION}.ihx"
+       File "../src/easymini-v1.0/easymini-v1.0-${VERSION}.ihx"
 
 SectionEnd
 
@@ -133,6 +135,7 @@ Section "Documentation"
        File "../doc/telemetry.pdf"
        File "../doc/telemetrum-outline.pdf"
        File "../doc/telemega-outline.pdf"
+       File "../doc/easymini-outline.pdf"
 SectionEnd
 
 Section "Uninstaller"
index 867b03841bb4100cfaf4298377cb55fd52a990e4..a38cba63e0f7913ce52e7cab49ca1cb4bb88d45e 100644 (file)
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
index 55486dea1214a064c5a1d013c2d639bd361fce71..84803c0e916770af06b0fc627e040806f826cfe5 100644 (file)
@@ -23,7 +23,7 @@ import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
index 5f3a2eef30a8064936f4abc763160cd4298124e6..ef0cc6772daa8e80e8f06d216ddfdabed136c5fe 100644 (file)
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
index 8f0ce8011d6595d7812d9b9888cfd8f2f7cc3fb1..d826072fee0eacd24c07e320a52663c2fbd7781d 100644 (file)
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
index 1b1214052f8f9598f46b8895456d6a3f95a23b76..9fcaf6d4d636979ef4272b1171ff0a982f75a758 100644 (file)
@@ -20,7 +20,7 @@ package org.altusmetrum.altosuilib_1;
 import java.awt.*;
 import libaltosJNI.*;
 
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosUILib extends AltosLib {
 
index 0949be6f94af3122ed0b31d2643eb16754b40c9f..e4262abd3c77c47818301bdae7e6cce3e07ad0a8 100644 (file)
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
index 49321bcec358500809bb9edd1ccfbd2f4871d71a..fc14f24b5a3417190ad4445d36f50cb861e386d8 100644 (file)
@@ -21,7 +21,7 @@ import java.io.*;
 import java.util.*;
 import java.awt.Component;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 public class AltosUIPreferences extends AltosPreferences {
 
index 8a5386c3328c0dd0bd3e9c66f811cf2ad2b5801c..55da8d480c6af10fab511dcbb378e760b4d09b1f 100644 (file)
@@ -19,7 +19,7 @@ package org.altusmetrum.altosuilib_1;
 
 import java.io.File;
 import java.util.prefs.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import javax.swing.filechooser.FileSystemView;
 
 public class AltosUIPreferencesBackend implements AltosPreferencesBackend {
index ac09a3cc04c9b6541eb3d95e18684c0d7bca3013..441eba2b33587c47790f4e21870629f06e7b6b05 100644 (file)
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
@@ -34,6 +34,24 @@ import org.jfree.chart.labels.*;
 import org.jfree.data.xy.*;
 import org.jfree.data.*;
 
+class AltosUITime extends AltosUnits {
+       public double value(double v, boolean imperial_units) { return v; }
+
+       public double inverse(double v, boolean imperial_unis) { return v; }
+       
+       public String show_units(boolean imperial_units) { return "s"; }
+
+       public String say_units(boolean imperial_units) { return "seconds"; }
+
+       public int show_fraction(int width, boolean imperial_units) {
+               if (width < 5)
+                       return 0;
+               return width - 5;
+       }
+
+       public int say_fraction(boolean imperial_units) { return 0; }
+}
+
 public class AltosUISeries extends XYSeries implements AltosUIGrapher {
        AltosUIAxis     axis;
        String          label;
@@ -47,11 +65,12 @@ public class AltosUISeries extends XYSeries implements AltosUIGrapher {
                axis.set_units();
                StandardXYToolTipGenerator      ttg;
 
-               String  example = units.graph_format(4);
+               String  time_example = (new AltosUITime()).graph_format(7);
+               String  example = units.graph_format(7);
 
                ttg = new StandardXYToolTipGenerator(String.format("{1}s: {2}%s ({0})",
                                                                   units.show_units()),
-                                                    new java.text.DecimalFormat(example),
+                                                    new java.text.DecimalFormat(time_example),
                                                     new java.text.DecimalFormat(example));
                renderer.setBaseToolTipGenerator(ttg);
        }
index a06b686911423c1ad4aa1416f37124f8f6dbe665..4f329840bdbe88aba6b33305ee43a9e808b8e405 100644 (file)
@@ -68,18 +68,20 @@ public class AltosUSBDevice  extends altos_device implements AltosDevice {
                if (want_product == AltosUILib.product_any)
                        return true;
 
+               int have_product = getProduct();
+
                if (want_product == AltosUILib.product_basestation)
-                       return matchProduct(AltosUILib.product_teledongle) ||
-                               matchProduct(AltosUILib.product_teleterra) ||
-                               matchProduct(AltosUILib.product_telebt) ||
-                               matchProduct(AltosUILib.product_megadongle);
+                       return have_product == AltosUILib.product_teledongle ||
+                               have_product == AltosUILib.product_teleterra ||
+                               have_product == AltosUILib.product_telebt ||
+                               have_product == AltosUILib.product_megadongle;
 
                if (want_product == AltosUILib.product_altimeter)
-                       return matchProduct(AltosUILib.product_telemetrum) ||
-                               matchProduct(AltosUILib.product_telemega) ||
-                               matchProduct(AltosUILib.product_telegps);
-
-               int have_product = getProduct();
+                       return have_product == AltosUILib.product_telemetrum ||
+                               have_product == AltosUILib.product_telemega ||
+                               have_product == AltosUILib.product_telegps ||
+                               have_product == AltosUILib.product_easymini ||
+                               have_product == AltosUILib.product_telemini;
 
                if (have_product == AltosUILib.product_altusmetrum)     /* old devices match any request */
                        return true;
index 0cd2aaea5eb36d027a828ef3f0bac905ae870fc3..4b22af1f8eda6fab2ed14cc710c7ce16db3cbfee 100644 (file)
@@ -1,4 +1,4 @@
-AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
 
 JAVAROOT=bin
 
diff --git a/ao-bringup/cal-accel b/ao-bringup/cal-accel
new file mode 100755 (executable)
index 0000000..96e51e6
--- /dev/null
@@ -0,0 +1,120 @@
+#!/usr/bin/nickle
+
+import File;
+
+string timed_read(file f, int timeout) {
+       thread reader = fork func() {
+               try {
+                       return fgets(f);
+               } catch Thread::signal(int i) {
+                       return "";
+               }
+       }();
+
+       thread killer = fork func() {
+               try {
+                       sleep (timeout);
+                       Thread::send_signal(reader, 1);
+               } catch Thread::signal(int i) {
+                       return;
+               }
+       }();
+
+       poly v = Thread::join(reader);
+       Thread::send_signal(killer, 1);
+       Thread::join(killer);
+       if (is_string(v))
+               return v;
+       return "";
+}
+
+void flush_input(file f) {
+       for (;;) {
+               string s = timed_read(f, 200);
+               if (s == "")
+                       break;
+       }
+}
+
+string[*] settings(file f) {
+       string[...] x = {};
+
+       flush_input(f);
+       fprintf (f, "c s\nv\n");
+       flush(f);
+       for (;;) {
+               string l = File::fgets(f);
+               x[dim(x)] = l;
+               if (String::index(l, "software-version") == 0)
+                       break;
+       }
+       return x;
+}
+
+string[*] find_setting(string[*] s, string match) {
+       for (int i = 0; i < dim(s); i++)
+               if (String::index(s[i], match) == 0)
+                       return String::split(s[i], " ");
+       return (string[*]) {};
+}
+
+bool
+do_cal(file f) {
+       flush_input(f);
+       fprintf(f, "E 1\nc a 0\n");
+       flush(f);
+       string s = "";
+       bool worked = true;
+       bool running = false;
+
+       thread put = fork func() {
+               try {
+                       for (;;) {
+                               putc(getchar(), f);
+                               flush(f);
+                       }
+               } catch Thread::signal(int i) {
+                       return;
+               }
+       }();
+
+       for (;;) {
+               int c = getc(f);
+               if (c == '\n')
+                       s = "";
+               else
+                       s = s + String::new(c);
+               putchar(c); flush(stdout);
+               if (String::index(s, "press a key...") >= 0)
+                       running = true;
+               if (String::index(s, "Invalid") >= 0)
+                       worked = false;
+               if (running && String::index(s, ">") >= 0)
+                       break;
+       }
+       fprintf (f, "E 0\n");
+       if (worked)
+               fprintf (f, "c w\n");
+       sleep(200);
+       Thread::send_signal(put, 1);
+       Thread::join(put);
+
+       return worked;
+}
+
+void main () {
+       string  name = argv[1];
+       file    f = open(name, "r+");
+
+       if (do_cal(f)) {
+               string[*] s = settings(f);
+               string[*] ac = find_setting(s, "Accel cal");
+               printf ("Calibration value +1g %s -1g %s saved\n", ac[3], ac[5]);
+               exit (0);
+       } else {
+               printf ("Calibration failed\n");
+               exit (1);
+       }
+}
+
+main();
diff --git a/ao-bringup/cal-freq b/ao-bringup/cal-freq
new file mode 100755 (executable)
index 0000000..dc2f221
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+case $# in
+1)
+       dev="$1"
+       ;;
+*)
+       echo "Usage: $0 <device>"
+       exit 1;
+       ;;
+esac
+
+while true; do
+       echo 'C 1' > $dev
+
+       echo -n "Generating RF carrier. Please enter measured frequency [enter for done]: "
+
+       read FREQ
+
+       echo 'C 0' > $dev
+
+       case "$FREQ" in
+       "")
+               exit 0
+               ;;
+       *)
+               calline=`./get-radio-cal $dev`
+               CURRENT_CAL=`echo $calline | awk '{print $2}'`
+               CURRENT_FREQ=`echo $calline | awk '{print $4}'`
+
+               echo "Current radio calibration "$CURRENT_CAL
+               echo "Current radio frequency "$CURRENT_FREQ
+
+               CAL_VALUE=`nickle -e "floor($CURRENT_FREQ / $FREQ * $CURRENT_CAL + 0.5)"`
+
+               echo "Programming flash with cal value " $CAL_VALUE
+
+               cat << EOF > $dev
+c f $CAL_VALUE
+c w
+EOF
+
+               echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
+               ;;
+       esac
+done
diff --git a/ao-bringup/get-radio-cal b/ao-bringup/get-radio-cal
new file mode 100755 (executable)
index 0000000..8f975fe
--- /dev/null
@@ -0,0 +1,66 @@
+#!/usr/bin/nickle
+
+import File;
+
+string timed_read(file f, int timeout) {
+       thread reader = fork func() { try { return fgets(f); } catch Thread::signal(int i) { return ""; } }();
+       thread killer = fork func() { sleep (timeout); Thread::send_signal(reader, 1); }();
+       poly v = Thread::join(reader);
+       if (is_string(v))
+               return v;
+       return "";
+}
+
+void flush_input(file f) {
+       for (;;) {
+               string s = timed_read(f, 100);
+               if (s == "")
+                       break;
+       }
+}
+
+string[*] settings(file f) {
+       string[...] x = {};
+
+       flush_input(f);
+       fprintf (f, "c s\nv\n");
+       flush(f);
+       for (;;) {
+               string l = File::fgets(f);
+               x[dim(x)] = l;
+               if (String::index(l, "software-version") == 0)
+                       break;
+       }
+       return x;
+}
+
+string[*] find_setting(string[*] s, string match) {
+       for (int i = 0; i < dim(s); i++)
+               if (String::index(s[i], match) == 0)
+                       return String::split(s[i], " ");
+       return (string[*]) {};
+}
+
+int[*]
+get_radio (file f) {
+       string[*] s = settings(f);
+
+       string[*] cal = find_setting(s, "Radio cal:");
+       string[*] freq = find_setting(s, "Frequency:");
+       if (dim(cal) == 0 || dim(freq) == 0)
+               return (int[2]) { 0, 0 };
+
+       int cal_val = string_to_integer(cal[2]);
+       int freq_val = string_to_integer(freq[1]);
+       return (int[2]) { cal_val, freq_val };
+}
+
+void main () {
+       string  name = argv[1];
+       file    f = open(name, "r+");
+
+       int[*] vals = get_radio(f);
+       printf ("cal %d freq %f\n", vals[0], vals[1] / 1000);
+}
+
+main();
index 6c52721c8e3a765ec4d999a634c8161eb1fe6356..ef20e915f863ec1494bf624595b3e3b3bd898263 100755 (executable)
@@ -1,5 +1,8 @@
 #!/bin/sh
 
+# serial number of the TeleDongle being used as the flash programmer
+DONGLE=612
+
 if [ -x ../ao-tools/ao-load/ao-load ]; then
        AOLOAD=../ao-tools/ao-load/ao-load
 elif [ -x /usr/bin/ao-load ]; then
@@ -18,12 +21,12 @@ else
        exit 1
 fi
 
-echo "TeleBT v0.1 Turn-On and Calibration Program"
-echo "Copyright 2011 by Bdale Garbee.  Released under GPL v2"
+echo "TeleBT v1.1 Turn-On and Calibration Program"
+echo "Copyright 2013 by Bdale Garbee.  Released under GPL v2"
 echo
 echo "Expectations:"
-echo "\tTeleBT v0.1 powered from USB"
-echo "\t\twith TeleDonle (on /dev/ttyACM0) cabled to debug header"
+echo "\tTeleBT v1.1 powered from USB"
+echo "\t\twith TeleDonlge (on /dev/ttyACM0) cabled to debug header"
 echo "\t\twith coax from SMA to frequency counter"
 echo
 echo -n "TeleBT serial number: "
@@ -31,18 +34,18 @@ read SERIAL
 
 echo $RAWLOAD
 
-$RAWLOAD -D 100 -r ao_led_blink.ihx
+$RAWLOAD -D $DONGLE -r ao_led_blink.ihx
 echo "LEDs should be blinking"
 sleep 5
 
-$RAWLOAD -D 100 -r ao_radio_xmit.ihx
+$RAWLOAD -D $DONGLE -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 -D 100 --cal $CAL_VALUE /usr/share/altos/telebt-v0.1*.ihx $SERIAL
+$AOLOAD -D $DONGLE --cal $CAL_VALUE /usr/share/altos/stable/telebt-v1.0*.ihx $SERIAL
 
 echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
 echo "Unplug debug cable, power cycle, cu to the board, confirm freq and record power"
diff --git a/ao-bringup/turnon_telemega b/ao-bringup/turnon_telemega
new file mode 100755 (executable)
index 0000000..a8bf869
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+if [ -x ../ao-tools/ao-stmload/ao-stmload ]; then
+       STMLOAD=../ao-tools/ao-stmload/ao-stmload
+elif [ -x /usr/bin/ao-stmload ]; then
+       STMLOAD=/usr/bin/ao-stmload
+else
+       echo "Can't find ao-stmload!  Aborting."
+       exit 1
+fi
+
+if [ -x ../ao-tools/ao-usbload/ao-usbload ]; then
+       USBLOAD=../ao-tools/ao-usbload/ao-usbload
+elif [ -x /usr/bin/ao-usbload ]; then
+       USBLOAD=/usr/bin/ao-usbload
+else
+       echo "Can't find ao-usbload!  Aborting."
+       exit 1
+fi
+
+VERSION=1.0
+#VERSION=0.1
+
+echo "TeleMega v$VERSION Turn-On and Calibration Program"
+echo "Copyright 2010 by Bdale Garbee.  Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\tTeleMega 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 "TeleMega-$VERSION serial number: "
+read SERIAL
+
+echo $STMLOAD
+
+$STMLOAD --raw ../src/telemega-v$VERSION/flash-loader/*.elf || exit 1
+
+sleep 2
+
+$USBLOAD --serial=$SERIAL ../src/telemega-v$VERSION/*.ihx || exit 1
+
+sleep 2
+
+dev=`ao-list | awk '/TeleMega-v'"$VERSION"'/ { print $3; exit(0); }'`
+
+case "$dev" in
+/dev/tty*)
+       echo "TeleMega found on $dev"
+       ;;
+*)
+       echo 'No TeleMega-v'"$VERSION"' found'
+       exit 1
+       ;;
+esac
+
+echo 'E 0' > $dev
+
+SERIAL=$SERIAL ./cal-freq $dev
+
+./cal-accel $dev
diff --git a/ao-bringup/turnon_teleminiv2 b/ao-bringup/turnon_teleminiv2
new file mode 100755 (executable)
index 0000000..0ce73cb
--- /dev/null
@@ -0,0 +1,53 @@
+#!/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 "TeleMini v2.0 Turn-On and Calibration Program"
+echo "Copyright 2011 by Bdale Garbee.  Released under GPL v2"
+echo "Copyright 2013 by Keith Packard.  Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\tTeleMini v2.0 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
+echo -n "TeleMini serial number: "
+read SERIAL
+
+echo $RAWLOAD
+
+#TTY=/dev/ttyACM0
+PROGRAMMER="-D 186"
+BIN=../src/telemini-v2.0*.ihx
+
+$RAWLOAD $PROGRAMMER -r ao_led_blink.ihx
+echo "LEDs should be blinking"
+sleep 5
+
+$RAWLOAD $PROGRAMMER -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 $PROGRAMMER --cal=$CAL_VALUE $BIN $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 4600f1d62221bf73ffe348ce532b6423d99aa4a4..a42988d6c22f57a45ded73084b1cf8f59f60c9c8 100644 (file)
@@ -1,3 +1,7 @@
 SUBDIRS=lib ao-rawload ao-dbg ao-bitbang ao-eeprom ao-list \
-       ao-load ao-telem ao-stmload ao-send-telem ao-sky-flash \
-       ao-dumpflash ao-edit-telem ao-dump-up
+       ao-load ao-telem ao-send-telem ao-sky-flash \
+       ao-dumpflash ao-edit-telem ao-dump-up ao-elftohex \
+       ao-flash ao-usbload
+if LIBSTLINK
+SUBDIRS += ao-stmload
+endif
index ad2cb28081a4811cec5cc4dbb252a054d36b9521..2c33cf0677cee345151df0716a580971c4454be2 100644 (file)
@@ -7,6 +7,6 @@ man_MANS = ao-dbg.1
 
 ao_dbg_DEPENDENCIES = $(AO_DBG_LIBS)
 
-ao_dbg_LDADD=$(AO_DBG_LIBS) $(LIBUSB_LIBS)  -lreadline
+ao_dbg_LDADD=$(AO_DBG_LIBS) $(LIBUSB_LIBS) $(LIBREADLINE)
 
 ao_dbg_SOURCES = ao-dbg-parse.c ao-dbg-command.c ao-dbg-main.c
index eab7bc689d7502f5832f61957ac06e22e8556fb2..11c521e88d5a47614137a651f4ac6a02a7a252fa 100644 (file)
@@ -202,8 +202,8 @@ command_dump (int argc, char **argv)
 enum command_result
 command_file (int argc, char **argv)
 {
-       struct hex_file *hex;
-       struct hex_image *image;
+       struct ao_hex_file *hex;
+       struct ao_hex_image *image;
        FILE *file;
 
        if (argc != 2)
@@ -211,16 +211,16 @@ command_file (int argc, char **argv)
        file = fopen (argv[1], "r");
        if (!file)
                return command_error;
-       hex = ccdbg_hex_file_read(file, argv[1]);
+       hex = ao_hex_file_read(file, argv[1]);
        fclose(file);
        if (!hex)
                return command_error;
        if (hex->nrecord == 0) {
-               ccdbg_hex_file_free(hex);
+               ao_hex_file_free(hex);
                return command_error;
        }
-       image = ccdbg_hex_image_create(hex);
-       ccdbg_hex_file_free(hex);
+       image = ao_hex_image_create(hex);
+       ao_hex_file_free(hex);
        start_address = image->address;
        ccdbg_set_rom(s51_dbg, image);
        return command_success;
@@ -495,8 +495,8 @@ command_load (int argc, char **argv)
 {
        char *filename = argv[1];
        FILE *file;
-       struct hex_file *hex;
-       struct hex_image *image;
+       struct ao_hex_file      *hex;
+       struct ao_hex_image *image;
 
        if (!filename)
                return command_error;
@@ -505,13 +505,13 @@ command_load (int argc, char **argv)
                perror(filename);
                return command_error;
        }
-       hex = ccdbg_hex_file_read(file, filename);
+       hex = ao_hex_file_read(file, filename);
        fclose(file);
        if (!hex) {
                return command_error;
        }
-       image = ccdbg_hex_image_create(hex);
-       ccdbg_hex_file_free(hex);
+       image = ao_hex_image_create(hex);
+       ao_hex_file_free(hex);
        if (!image) {
                fprintf(stderr, "image create failed\n");
                return command_error;
@@ -523,7 +523,7 @@ command_load (int argc, char **argv)
        } else {
                fprintf(stderr, "Can only load to RAM\n");
        }
-       ccdbg_hex_image_free(image);
+       ao_hex_image_free(image);
        return command_success;
 }
 
index 21b83a3dbc2b6c01327f05fe1e72ae59111b400a..25eca54b149cb7dae8ec654721ddd4ca043cbfd9 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include "ao-dbg.h"
 #include <unistd.h>
 #include <sys/types.h>
@@ -204,13 +208,16 @@ s51_putc(int c)
        putc(c, s51_output);
 }
 
+#if HAVE_LIBREADLINE
 #include <readline/readline.h>
 #include <readline/history.h>
+#endif
 
 int
 s51_read_line(char *line, int len)
 {
        int ret;
+#if HAVE_LIBREADLINE
        if (s51_output == stdout && s51_input == stdin && s51_prompt) {
                char *r;
 
@@ -221,7 +228,9 @@ s51_read_line(char *line, int len)
                line[len-1] = '\0';
                add_history(r);
                return 1;
-       } else {
+       } else
+#endif
+       {
                if (s51_prompt)
                        s51_printf("%s", s51_prompt);
                else
index dcb9099df8cbe8d1742a2f877b9584bc5fa9c3a8..ba69183431c823f508bb318afff89c291ee77abc 100644 (file)
@@ -198,7 +198,7 @@ command_read (void)
        if (!s51_tty) {
                if (!s51_device)
                        s51_device = getenv("AO_DBG_DEVICE");
-               s51_tty = cc_usbdevs_find_by_arg(s51_device, "TIDongle");
+               s51_tty = cc_usbdevs_find_by_arg(s51_device, "TeleDongle");
        }
        s51_dbg = ccdbg_open (s51_tty);
        if (!s51_dbg)
diff --git a/ao-tools/ao-elftohex/Makefile.am b/ao-tools/ao-elftohex/Makefile.am
new file mode 100644 (file)
index 0000000..dd0046d
--- /dev/null
@@ -0,0 +1,12 @@
+bin_PROGRAMS=ao-elftohex
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_ELFTOHEX_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_elftohex_DEPENDENCIES = $(AO_ELFTOHEX_LIBS)
+
+ao_elftohex_LDADD=$(AO_ELFTOHEX_LIBS) -lelf
+
+ao_elftohex_SOURCES=ao-elftohex.c
+
+man_MANS = ao-elftohex.1
diff --git a/ao-tools/ao-elftohex/ao-elftohex.1 b/ao-tools/ao-elftohex/ao-elftohex.1
new file mode 100644 (file)
index 0000000..e52e6f5
--- /dev/null
@@ -0,0 +1,38 @@
+.\"
+.\" 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.
+.\"
+.\"
+.TH AO-LOAD 1 "ao-elftohex" ""
+.SH NAME
+ao-elftohex \- convert a program to IHX format
+.SH SYNOPSIS
+.B "ao-elftohex"
+[\--output-\fIoutput.ihx\fP]
+[\--verbose]
+\fIinput.elf\fP
+.SH DESCRIPTION
+.I ao-elftohex
+reads the specified .elf file and writes out a .ihx version.
+.SH OPTIONS
+.TP
+\--output=\fIoutput.ihx\fP
+This specifies the output file (default is stdout)
+.TP
+\--verbose
+Dumps some debug information.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-elftohex/ao-elftohex.c b/ao-tools/ao-elftohex/ao-elftohex.c
new file mode 100644 (file)
index 0000000..db8f86f
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ao-hex.h"
+#include "ao-elf.h"
+#include "ao-verbose.h"
+
+static const struct option options[] = {
+       { .name = "verbose", .has_arg = 1, .val = 'v' },
+       { .name = "output", .has_arg = 1, .val = 'o' },
+       { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+       fprintf(stderr, "usage: %s [--verbose=<level>] [--output=<output.ihx>] <input.elf>\n", program);
+       exit(1);
+}
+
+static int
+ends_with(char *whole, char *suffix)
+{
+       int whole_len = strlen(whole);
+       int suffix_len = strlen(suffix);
+
+       if (suffix_len > whole_len)
+               return 0;
+       return strcmp(whole + whole_len - suffix_len, suffix) == 0;
+}
+
+int
+main (int argc, char **argv)
+{
+       char                    *input = NULL;
+       char                    *output = NULL;
+       struct ao_hex_image     *image;
+       struct ao_sym           *file_symbols;
+       int                     num_file_symbols;
+       FILE                    *file;
+       int                     c;
+
+       while ((c = getopt_long(argc, argv, "v:o:", options, NULL)) != -1) {
+               switch (c) {
+               case 'o':
+                       output = optarg;
+                       break;
+               case 'v':
+                       ao_verbose = (int) strtol(optarg, NULL, 0);
+                       break;
+               default:
+                       usage(argv[0]);
+                       break;
+               }
+       }
+
+       input = argv[optind];
+       if (input == NULL)
+               usage(argv[0]);
+
+       if (ends_with (input, ".ihx"))
+               image = ao_hex_load(input, &file_symbols, &num_file_symbols);
+       else
+               image = ao_load_elf(input, &file_symbols, &num_file_symbols);
+
+       if (!image)
+               usage(argv[0]);
+
+       if (!output)
+               file = stdout;
+       else {
+               file = fopen(output, "w");
+               if (!file) {
+                       perror(output);
+                       exit(1);
+               }
+       }
+
+       if (!ao_hex_save(file, image, file_symbols, num_file_symbols)) {
+               fprintf(stderr, "%s: failed to write hex file\n", output ? output : "<stdout>");
+               if (output)
+                       unlink(output);
+               exit(1);
+       }
+       exit(0);
+}
diff --git a/ao-tools/ao-flash/Makefile.am b/ao-tools/ao-flash/Makefile.am
new file mode 100644 (file)
index 0000000..6b7ea6b
--- /dev/null
@@ -0,0 +1,3 @@
+bin_SCRIPTS=ao-flash-stm ao-flash-lpc
+
+man_MANS = ao-flash-stm.1 ao-flash-lpc.1
\ No newline at end of file
diff --git a/ao-tools/ao-flash/ao-flash-lpc b/ao-tools/ao-flash/ao-flash-lpc
new file mode 100644 (file)
index 0000000..57f632b
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+case "$#" in
+0)
+       echo "usage: $0 <filename> ..."
+       exit 1
+       ;;
+esac
+cmds=/tmp/flash$$
+trap "rm $cmds" 0 1 15
+for file in "$@"; do
+       echo "flash write_image $file"
+done > $cmds
+openocd \
+       -f interface/stlink-v2.cfg \
+       -f target/lpc11u14.cfg \
+       -c init \
+       -c 'reset halt' \
+       -f $cmds \
+       -c 'reset init' \
+        -c 'reset run' \
+       -c shutdown
diff --git a/ao-tools/ao-flash/ao-flash-lpc.1 b/ao-tools/ao-flash/ao-flash-lpc.1
new file mode 100644 (file)
index 0000000..4631203
--- /dev/null
@@ -0,0 +1,36 @@
+.\"
+.\" Copyright © 2013 Keith Packard <keithp@keithp.com>
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+.\"
+.\"
+.TH AO-FLASH-LPC 1 "ao-flash-lpc" ""
+.SH NAME
+ao-flash-lpc \- flash a program to an LPC11U14-based AltOS device using openocd
+.SH SYNOPSIS
+.B "ao-flash-lpc"
+\fIfile.elf\fP
+.SH DESCRIPTION
+.I ao-flash-lpc
+loads the specified .elf file into the target device flash memory.
+.SH USAGE
+.I ao-flash-lpc
+is a simple script that passes the correct arguments to openocd to
+load a file into the target device via a connected STlink
+debugging dongle.
+.SH "SEE ALSO"
+openocd(1)
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-flash/ao-flash-stm b/ao-tools/ao-flash/ao-flash-stm
new file mode 100644 (file)
index 0000000..9eebf5d
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh
+case "$#" in
+0)
+       echo "usage: $0 <filename> ..."
+       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
diff --git a/ao-tools/ao-flash/ao-flash-stm.1 b/ao-tools/ao-flash/ao-flash-stm.1
new file mode 100644 (file)
index 0000000..81aa592
--- /dev/null
@@ -0,0 +1,38 @@
+.\"
+.\" 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.
+.\"
+.\"
+.TH AO-FLASH-STM 1 "ao-flash-stm" ""
+.SH NAME
+ao-flash-stm \- flash a program to an STM32-based AltOS device using st-flash
+.SH SYNOPSIS
+.B "ao-flash-stm"
+\fIfile.elf\fP
+.SH DESCRIPTION
+.I ao-flash-stm
+loads the specified .elf file into the target device flash memory.
+.SH USAGE
+.I ao-flash-stm
+converts the specified .elf file into a raw binary file and then uses
+st-flash to load it into the target device via a connected STlink
+debugging dongle. If st-flash is not available,
+.I ao-flash-stm
+will emit an error message and terminate.
+.SH "SEE ALSO"
+st-flash(1)
+.SH AUTHOR
+Keith Packard
index e3cef4a5664f61c8d06959482dc48db8a342a08d..c1f551499ceac969b76072f417bb3f66f49e3e31 100644 (file)
@@ -80,7 +80,7 @@ find_symbols(FILE *map)
 }
 
 static int
-rewrite(struct hex_image *image, unsigned addr, char *data, int len)
+rewrite(struct ao_hex_image *image, unsigned addr, char *data, int len)
 {
        int i;
        if (addr < image->address || image->address + image->length < addr + len)
@@ -114,8 +114,8 @@ main (int argc, char **argv)
        struct ccdbg    *dbg;
        uint8_t         status;
        uint16_t        pc;
-       struct hex_file *hex;
-       struct hex_image *image;
+       struct ao_hex_file      *hex;
+       struct ao_hex_image *image;
        char            *filename;
        FILE            *file;
        FILE            *map;
@@ -182,18 +182,18 @@ main (int argc, char **argv)
        }
        fclose(map);
 
-       hex = ccdbg_hex_file_read(file, filename);
+       hex = ao_hex_file_read(file, filename);
        fclose(file);
        if (!hex) {
                perror(filename);
                exit (1);
        }
-       image = ccdbg_hex_image_create(hex);
+       image = ao_hex_image_create(hex);
        if (!image) {
                fprintf(stderr, "image create failed\n");
                exit (1);
        }
-       ccdbg_hex_file_free(hex);
+       ao_hex_file_free(hex);
 
        serial = strtoul(serial_string, NULL, 0);
        if (!serial)
@@ -276,7 +276,7 @@ main (int argc, char **argv)
        } else {
                printf("Cannot load code to 0x%04x\n",
                       image->address);
-               ccdbg_hex_image_free(image);
+               ao_hex_image_free(image);
                ccdbg_close(dbg);
                exit(1);
        }
diff --git a/ao-tools/ao-mega/.gitignore b/ao-tools/ao-mega/.gitignore
new file mode 100644 (file)
index 0000000..7bb3739
--- /dev/null
@@ -0,0 +1 @@
+ao-mega
diff --git a/ao-tools/ao-mega/Makefile.am b/ao-tools/ao-mega/Makefile.am
new file mode 100644 (file)
index 0000000..22b6260
--- /dev/null
@@ -0,0 +1,12 @@
+bin_PROGRAMS=ao-mega
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_POSTFLIGHT_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_mega_DEPENDENCIES = $(AO_POSTFLIGHT_LIBS)
+
+ao_mega_LDADD=$(AO_POSTFLIGHT_LIBS) $(LIBUSB_LIBS)
+
+ao_mega_SOURCES = ao-mega.c
+
+man_MANS = ao-mega.1
diff --git a/ao-tools/ao-mega/ao-mega.1 b/ao-tools/ao-mega/ao-mega.1
new file mode 100644 (file)
index 0000000..0f96bdc
--- /dev/null
@@ -0,0 +1,30 @@
+.\"
+.\" Copyright © 2009 Keith Packard <keithp@keithp.com>
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; 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.
+.\"
+.\"
+.TH AO-TELEM 1 "ao-mega" ""
+.SH NAME
+ao-mega \- Dump a mega flight log (eeprom only)
+.SH SYNOPSIS
+.B "ao-mega"
+{flight.mega}
+.SH DESCRIPTION
+.I ao-mega
+reads the specified flight log and dumps it in human readable format.
+output.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-mega/ao-mega.c b/ao-tools/ao-mega/ao-mega.c
new file mode 100644 (file)
index 0000000..523229e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include "cc.h"
+
+static const struct option options[] = {
+       { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+       fprintf(stderr, "usage: %s\n"
+               "\t{flight.mega} ...\n", program);
+       exit(1);
+}
+
+#define bool(b)        ((b) ? "true" : "false")
+
+static const char *state_names[] = {
+       "startup",
+       "idle",
+       "pad",
+       "boost",
+       "fast",
+       "coast",
+       "drogue",
+       "main",
+       "landed",
+       "invalid"
+};
+
+
+#define NUM_STATE      (sizeof state_names/sizeof state_names[0])
+
+int
+main (int argc, char **argv)
+{
+       char    line[256];
+       int c, i, ret, j;
+       char *s;
+       FILE *file;
+       int serial;
+       const char *state;
+       while ((c = getopt_long(argc, argv, "", options, NULL)) != -1) {
+               switch (c) {
+               default:
+                       usage(argv[0]);
+                       break;
+               }
+       }
+       for (i = optind; i < argc; i++) {
+               file = fopen(argv[i], "r");
+               if (!file) {
+                       perror(argv[i]);
+                       ret++;
+                       continue;
+               }
+               s = strstr(argv[i], "-serial-");
+               if (s)
+                       serial = atoi(s + 8);
+               else
+                       serial = 0;
+               while (fgets(line, sizeof (line), file)) {
+                       struct ao_log_mega      log;
+
+                       if (cc_mega_parse(line, &log)) {
+                               if (log.is_config) {
+                                       printf ("kind %d\n", log.u.config_int.kind);
+                               } else {
+                                       printf ("tick %5d ", log.tick);
+                                       switch (log.type) {
+                                       case AO_LOG_FLIGHT:
+                                               printf ("flight %5u ground_accel %d ground_pres %u\n",
+                                                       log.u.flight.flight,
+                                                       log.u.flight.ground_accel,
+                                                       log.u.flight.ground_pres);
+                                               break;
+                                       case AO_LOG_STATE:
+                                               if (log.u.state.state < NUM_STATE)
+                                                       state = state_names[log.u.state.state];
+                                               else
+                                                       state = "invalid";
+                                               printf ("state %d (%s)\n", log.u.state.state, state);
+                                               break;
+                                       case AO_LOG_SENSOR:
+                                               printf ("p %9u t %9u ax %6d ay %6d az %6d gx %6d gy %6d gz %6d mx %6d my %6d mz %6d a %6d\n",
+                                                       log.u.sensor.pres,
+                                                       log.u.sensor.temp,
+                                                       log.u.sensor.accel_x,
+                                                       log.u.sensor.accel_y,
+                                                       log.u.sensor.accel_z,
+                                                       log.u.sensor.gyro_x,
+                                                       log.u.sensor.gyro_y,
+                                                       log.u.sensor.gyro_z,
+                                                       log.u.sensor.mag_x,
+                                                       log.u.sensor.mag_y,
+                                                       log.u.sensor.mag_z,
+                                                       log.u.sensor.accel);
+                                               break;
+                                       case AO_LOG_TEMP_VOLT:
+                                               printf ("batt %6d pbatt %6d n_sense %d",
+                                                       log.u.volt.v_batt,
+                                                       log.u.volt.v_pbatt,
+                                                       log.u.volt.n_sense);
+                                               for (j = 0; j < log.u.volt.n_sense; j++) {
+                                                       printf (" s%d %6d",
+                                                               j, log.u.volt.sense[j]);
+                                               }
+                                               printf ("pyro %04x\n", log.u.volt.pyro);
+                                               printf ("\n");
+                                               break;
+                                       default:
+                                               printf ("type %c\n", log.type, log.tick);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               fclose (file);
+
+       }
+       return ret;
+}
index a4746b195411ac8d73bb237774f12cea3020b808..17ed73cae20e5ac58a7176ba8583459da22b7e07 100644 (file)
@@ -40,8 +40,8 @@ main (int argc, char **argv)
        struct ccdbg    *dbg;
        uint8_t         status;
        uint16_t        pc;
-       struct hex_file *hex;
-       struct hex_image *image;
+       struct ao_hex_file      *hex;
+       struct ao_hex_image *image;
        char            *filename;
        FILE            *file;
        char            *tty = NULL;
@@ -75,17 +75,17 @@ main (int argc, char **argv)
                perror(filename);
                exit(1);
        }
-       hex = ccdbg_hex_file_read(file, filename);
+       hex = ao_hex_file_read(file, filename);
        fclose(file);
        if (!hex)
                exit (1);
-       image = ccdbg_hex_image_create(hex);
+       image = ao_hex_image_create(hex);
        if (!image) {
                fprintf(stderr, "image create failed\n");
                exit (1);
        }
 
-       ccdbg_hex_file_free(hex);
+       ao_hex_file_free(hex);
        if (!tty)
                tty = cc_usbdevs_find_by_arg(device, "TIDongle");
        dbg = ccdbg_open(tty);
@@ -107,7 +107,7 @@ main (int argc, char **argv)
        } else {
                printf("Cannot load code to 0x%04x\n",
                       image->address);
-               ccdbg_hex_image_free(image);
+               ao_hex_image_free(image);
                ccdbg_close(dbg);
                exit(1);
        }
index 4eaf699cac02de404eec0ac1114452683ee7eeb6..45eb6216787f5afe2d50e68f497eb9b34744c914 100644 (file)
@@ -2,16 +2,14 @@ if LIBSTLINK
 
 bin_PROGRAMS=ao-stmload
 
-LIBSTLINKDIR=/local/src/stlink
-
-AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBSTLINK_CFLAGS) $(LIBUSB_CFLAGS)
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(STLINK_CFLAGS) $(LIBUSB_CFLAGS)
 AO_STMLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
 
 ao_stmload_DEPENDENCIES = $(AO_STMLOAD_LIBS)
 
-ao_stmload_LDADD=$(AO_STMLOAD_LIBS) $(LIBSTLINK_LIBS) $(LIBUSB_LIBS) -lelf
+ao_stmload_LDADD=$(AO_STMLOAD_LIBS) $(STLINK_LIBS) $(LIBUSB_LIBS) -lelf
 
-ao_stmload_SOURCES=ao-stmload.c ao-elf.c ao-stmload.h ao-selfload.c
+ao_stmload_SOURCES=ao-stmload.c ao-stmload.h
 
 man_MANS = ao-stmload.1
 
diff --git a/ao-tools/ao-stmload/ao-elf.c b/ao-tools/ao-stmload/ao-elf.c
deleted file mode 100644 (file)
index dad8fb8..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright © 2013 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include "ao-elf.h"
-#include <err.h>
-#include <gelf.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include "ccdbg.h"
-#include "ao-stmload.h"
-
-/*
- * Look through the Elf file for the AltOS symbols
- * that can be adjusted before the image is written
- * to the device
- */
-static int
-find_symbols (Elf *e)
-{
-       Elf_Scn         *scn;
-       Elf_Data        *symbol_data = NULL;
-       GElf_Shdr       shdr;
-       GElf_Sym        sym;
-       int             i, symbol_count, s;
-       int             required = 0;
-       char            *symbol_name;
-       char            *section_name;
-       size_t          shstrndx;
-
-       if (elf_getshdrstrndx(e, &shstrndx) < 0)
-               return 0;
-
-       /*
-        * Find the symbols
-        */
-
-       scn = NULL;
-       while ((scn = elf_nextscn(e, scn)) != NULL) {
-
-               if (gelf_getshdr(scn, &shdr) != &shdr)
-                       return 0;
-
-               if (shdr.sh_type == SHT_SYMTAB) {
-                       symbol_data = elf_getdata(scn, NULL);
-                       symbol_count = shdr.sh_size / shdr.sh_entsize;
-                       break;
-               }
-       }
-
-       if (!symbol_data)
-               return 0;
-
-       for (i = 0; i < symbol_count; i++) {
-               gelf_getsym(symbol_data, i, &sym);
-
-               symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name);
-
-               for (s = 0; s < ao_num_symbols; s++)
-                       if (!strcmp (ao_symbols[s].name, symbol_name)) {
-                               int     t;
-                               ao_symbols[s].addr = sym.st_value;
-                               if (ao_symbols[s].required)
-                                       ++required;
-                       }
-       }
-
-       return required >= ao_num_required_symbols;
-}
-
-uint32_t round4(uint32_t a) {
-       return (a + 3) & ~3;
-}
-
-struct hex_image *
-new_load (uint32_t addr, uint32_t len)
-{
-       struct hex_image *new;
-
-       len = round4(len);
-       new = calloc (1, sizeof (struct hex_image) + len);
-       if (!new)
-               abort();
-
-       new->address = addr;
-       new->length = len;
-       return new;
-}
-
-void
-load_paste(struct hex_image *into, struct hex_image *from)
-{
-       if (from->address < into->address || into->address + into->length < from->address + from->length)
-               abort();
-
-       memcpy(into->data + from->address - into->address, from->data, from->length);
-}
-
-/*
- * Make a new load structure large enough to hold the old one and
- * the new data
- */
-struct hex_image *
-expand_load(struct hex_image *from, uint32_t address, uint32_t length)
-{
-       struct hex_image        *new;
-
-       if (from) {
-               uint32_t        from_last = from->address + from->length;
-               uint32_t        last = address + length;
-
-               if (address > from->address)
-                       address = from->address;
-               if (last < from_last)
-                       last = from_last;
-
-               length = last - address;
-
-               if (address == from->address && length == from->length)
-                       return from;
-       }
-       new = new_load(address, length);
-       if (from) {
-               load_paste(new, from);
-               free (from);
-       }
-       return new;
-}
-
-/*
- * Create a new load structure with data from the existing one
- * and the new data
- */
-struct hex_image *
-load_write(struct hex_image *from, uint32_t address, uint32_t length, void *data)
-{
-       struct hex_image        *new;
-
-       new = expand_load(from, address, length);
-       memcpy(new->data + address - new->address, data, length);
-       return new;
-}
-
-/*
- * Construct a large in-memory block for all
- * of the loaded sections of the program
- */
-static struct hex_image *
-get_load(Elf *e)
-{
-       Elf_Scn         *scn;
-       size_t          shstrndx;
-       GElf_Shdr       shdr;
-       Elf_Data        *data;
-       char            *got_name;
-       size_t          nphdr;
-       size_t          p;
-       GElf_Phdr       phdr;
-       GElf_Addr       p_paddr;
-       GElf_Off        p_offset;
-       GElf_Addr       sh_paddr;
-       struct hex_image        *load = NULL;
-       char            *section_name;
-       size_t          nshdr;
-       size_t          s;
-       
-       if (elf_getshdrstrndx(e, &shstrndx) < 0)
-               return 0;
-
-       if (elf_getphdrnum(e, &nphdr) < 0)
-               return 0;
-
-       if (elf_getshdrnum(e, &nshdr) < 0)
-               return 0;
-
-       /*
-        * As far as I can tell, all of the phdr sections should
-        * be flashed to memory
-        */
-       for (p = 0; p < nphdr; p++) {
-
-               /* Find this phdr */
-               gelf_getphdr(e, p, &phdr);
-
-               if (phdr.p_type != PT_LOAD)
-                       continue;
-
-               p_offset = phdr.p_offset;
-               /* Get the associated file section */
-
-#if 0
-               printf ("offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n",
-                       (uint32_t) phdr.p_offset,
-                       (uint32_t) phdr.p_vaddr,
-                       (uint32_t) phdr.p_paddr,
-                       (uint32_t) phdr.p_filesz,
-                       (uint32_t) phdr.p_memsz);
-#endif
-               
-               for (s = 0; s < nshdr; s++) {
-                       scn = elf_getscn(e, s);
-
-                       if (!scn) {
-                               printf ("getscn failed\n");
-                               abort();
-                       }
-                       if (gelf_getshdr(scn, &shdr) != &shdr) {
-                               printf ("gelf_getshdr failed\n");
-                               abort();
-                       }
-
-                       section_name = elf_strptr(e, shstrndx, shdr.sh_name);
-
-                       if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) {
-                                       
-                               if (shdr.sh_size == 0)
-                                       continue;
-
-                               sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset;
-
-                               printf ("\tsize %08x rom %08x exec %08x %s\n",
-                                       (uint32_t) shdr.sh_size,
-                                       (uint32_t) sh_paddr,
-                                       (uint32_t) shdr.sh_addr,
-                                       section_name);
-
-                               data = elf_getdata(scn, NULL);
-
-                               /* Write the section data into the memory block */
-                               load = load_write(load, sh_paddr, shdr.sh_size, data->d_buf);
-                       }
-               }
-       }
-       return load;
-}
-
-/*
- * Open the specified ELF file and
- * check for the symbols we need
- */
-
-struct hex_image *
-ao_load_elf(char *name)
-{
-       int             fd;
-       Elf             *e;
-       Elf_Scn         *scn;
-       Elf_Data        *symbol_data = NULL;
-       GElf_Shdr       shdr;
-       GElf_Sym        sym;
-       size_t          n, shstrndx, sz;
-       int             i, symbol_count, s;
-       int             required = 0;
-       struct hex_image        *image;
-
-       if (elf_version(EV_CURRENT) == EV_NONE)
-               return NULL;
-
-       fd = open(name, O_RDONLY, 0);
-
-       if (fd < 0)
-               return NULL;
-
-       e = elf_begin(fd, ELF_C_READ, NULL);
-
-       if (!e)
-               return NULL;
-
-       if (elf_kind(e) != ELF_K_ELF)
-               return NULL;
-
-       if (elf_getshdrstrndx(e, &shstrndx) != 0)
-               return NULL;
-
-       if (!find_symbols(e)) {
-               fprintf (stderr, "Cannot find required symbols\n");
-               return NULL;
-       }
-
-       image = get_load(e);
-       if (!image) {
-               fprintf (stderr, "Cannot create memory image from file\n");
-               return NULL;
-       }
-
-       return image;
-}
diff --git a/ao-tools/ao-stmload/ao-elf.h b/ao-tools/ao-stmload/ao-elf.h
deleted file mode 100644 (file)
index 4303d5c..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _AO_ELF_H_
-#define _AO_ELF_H_
-
-struct hex_image *
-ao_load_elf(char *name);
-
-#endif
diff --git a/ao-tools/ao-stmload/ao-selfload.c b/ao-tools/ao-stmload/ao-selfload.c
deleted file mode 100644 (file)
index 95667dc..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright © 2013 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sysexits.h>
-#include <unistd.h>
-#include <string.h>
-#include "cc.h"
-#include "cc-usb.h"
-#include "ccdbg.h"
-#include "ao-stmload.h"
-
-int    ao_self_verbose;
-
-#define TRACE(...) if (ao_self_verbose) printf (__VA_ARGS__)
-
-void
-ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256])
-{
-       int                     byte;
-       cc_usb_sync(cc);
-       cc_usb_printf(cc, "R %x\n", address);
-       for (byte = 0; byte < 0x100; byte++) {
-               block[byte] = cc_usb_getchar(cc);
-       }
-       TRACE ("\nread %08x\n", address);
-       for (byte = 0; byte < 0x100; byte++) {
-               TRACE (" %02x", block[byte]);
-               if ((byte & 0xf) == 0xf)
-                       TRACE ("\n");
-       }
-}
-
-void
-ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256])
-{
-       int                     byte;
-       cc_usb_sync(cc);
-       cc_usb_printf(cc, "W %x\n", address);
-       TRACE ("write %08x\n", address);
-       for (byte = 0; byte < 0x100; byte++) {
-               TRACE (" %02x", block[byte]);
-               if ((byte & 0xf) == 0xf)
-                       TRACE ("\n");
-       }
-       for (byte = 0; byte < 0x100; byte++) {
-               cc_usb_printf(cc, "%c", block[byte]);
-       }
-}
-
-struct hex_image *
-ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length)
-{
-       struct hex_image        *image;
-       int                     pages;
-       int                     page;
-       uint32_t                base = address & ~0xff;
-       uint32_t                bound = (address + length + 0xff) & ~0xff;
-
-       image = calloc(sizeof (struct hex_image) + (bound - base), 1);
-       image->address = base;
-       image->length = bound - base;
-       pages = image->length / 0x100;
-       for (page = 0; page < pages; page++)
-               ao_self_block_read(cc, image->address + page * 0x100, image->data + page * 0x100);
-       return image;
-}
-
-int
-ao_self_write(struct cc_usb *cc, struct hex_image *image)
-{
-       uint8_t         block[256];
-       uint8_t         check[256];
-       uint32_t        base, bound, length, address;
-       uint32_t        pages;
-       uint32_t        page;
-
-       base = image->address & ~0xff;
-       bound = (image->address + image->length + 0xff) & ~0xff;
-
-       address = base;
-       length = bound - base;
-
-       pages = length / 0x100;
-       printf ("Write %08x %d pages: ", address, length/0x100); fflush(stdout);
-       for (page = 0; page < pages; page++) {
-               uint32_t        start, stop;
-               address = base + page * 0x100;
-
-               if (address < image->address || address + 0x100 > image->address + image->length) {
-                       ao_self_block_read(cc, address, block);
-               }
-               start = address;
-               stop = address + 0x100;
-               if (start < image->address)
-                       start = image->address;
-               if (stop > image->address + image->length)
-                       stop = image->address + image->length;
-               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);
-               if (memcmp(block, check, 0x100) != 0) {
-                       fprintf(stderr, "Block at 0x%08x doesn't match\n", address);
-                       return 0;
-               }
-               putchar('.'); fflush(stdout);
-       }
-       printf("done\n");
-       cc_usb_printf(cc,"a\n");
-       return 1;
-}
index dd25f07f8e0cb6f2d355a15a72c1e09931a1c92e..4210a11150419c0f25bc0028ca123dcc2de5c2c5 100644 (file)
 #include <unistd.h>
 #include <getopt.h>
 #include <string.h>
+#include <stdbool.h>
 #include "stlink-common.h"
 #include "ao-elf.h"
 #include "ccdbg.h"
-#include "cc-usb.h"
 #include "cc.h"
 #include "ao-stmload.h"
+#include "ao-selfload.h"
+#include "ao-verbose.h"
+#include "ao-editaltos.h"
 
-#define AO_USB_DESC_STRING             3
-
-struct sym ao_symbols[] = {
-
-       { 0, AO_BOOT_APPLICATION_BASE + 0x100,  "ao_romconfig_version", 1 },
-#define AO_ROMCONFIG_VERSION   (ao_symbols[0].addr)
-
-       { 0, AO_BOOT_APPLICATION_BASE + 0x102,  "ao_romconfig_check",   1 },
-#define AO_ROMCONFIG_CHECK     (ao_symbols[1].addr)
-
-       { 0, AO_BOOT_APPLICATION_BASE + 0x104,  "ao_serial_number", 1 },
-#define AO_SERIAL_NUMBER       (ao_symbols[2].addr)
-
-       { 0, AO_BOOT_APPLICATION_BASE + 0x108,  "ao_radio_cal", 0 },
-#define AO_RADIO_CAL           (ao_symbols[3].addr)
-
-       { 0, AO_BOOT_APPLICATION_BASE + 0x10c,  "ao_usb_descriptors", 0 },
-#define AO_USB_DESCRIPTORS     (ao_symbols[4].addr)
-};
-
-#define NUM_SYMBOLS            5
-#define NUM_REQUIRED_SYMBOLS   3
-
-int ao_num_symbols = NUM_SYMBOLS;
-int ao_num_required_symbols = NUM_REQUIRED_SYMBOLS;
-
-/*
- * Edit the to-be-written memory block
- */
-static int
-rewrite(struct hex_image *load, unsigned address, uint8_t *data, int length)
-{
-       int             i;
-
-       if (address < load->address || load->address + load->length < address + length)
-               return 0;
-
-       printf("rewrite %04x:", address);
-       for (i = 0; i < length; i++)
-               printf (" %02x", load->data[address - load->address + i]);
-       printf(" ->");
-       for (i = 0; i < length; i++)
-               printf (" %02x", data[i]);
-       printf("\n");
-       memcpy(load->data + address - load->address, data, length);
-}
-
-/*
- * Read a 16-bit value from the USB target
- */
-
-static uint16_t
-get_uint16_cc(struct cc_usb *cc, uint32_t addr)
-{
-       struct hex_image        *hex = ao_self_read(cc, addr, 2);
-       uint16_t                v;
-       uint8_t                 *data;
-
-       if (!hex)
-               return 0;
-       data = hex->data + addr - hex->address;
-       v = data[0] | (data[1] << 8);
-       free(hex);
-       return v;
-}
-
-static uint32_t
-get_uint32_cc(struct cc_usb *cc, uint32_t addr)
-{
-       struct hex_image        *hex = ao_self_read(cc, addr, 4);
-       uint32_t                v;
-       uint8_t                 *data;
-
-       if (!hex)
-               return 0;
-       data = hex->data + addr - hex->address;
-       v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
-       free(hex);
-       return v;
-}
 
 /*
  * Read a 16-bit value from the target device with arbitrary
@@ -141,13 +64,10 @@ get_uint16_sl(stlink_t *sl, uint32_t addr)
 }
 
 static uint16_t
-get_uint16(stlink_t *sl, struct cc_usb *cc, uint32_t addr)
+get_uint16(stlink_t *sl, uint32_t addr)
 {
        uint16_t        result;
-       if (cc)
-               result = get_uint16_cc(cc, addr);
-       else
-               result = get_uint16_sl(sl, addr);
+       result = get_uint16_sl(sl, addr);
        printf ("read 0x%08x = 0x%04x\n", addr, result);
        return result;
 }
@@ -185,14 +105,11 @@ get_uint32_sl(stlink_t *sl, uint32_t addr)
  * alignment
  */
 static uint32_t
-get_uint32(stlink_t *sl, struct cc_usb *cc, uint32_t addr)
+get_uint32(stlink_t *sl, uint32_t addr)
 {
        uint32_t        result;
 
-       if (cc)
-               result = get_uint32_cc(cc, addr);
-       else
-               result = get_uint32_sl(sl, addr);
+       result = get_uint32_sl(sl, addr);
        printf ("read 0x%08x = 0x%08x\n", addr, result);
        return result;
 }
@@ -206,10 +123,10 @@ get_uint32(stlink_t *sl, struct cc_usb *cc, uint32_t addr)
  * places this at 0x100 from the start of the rom section
  */
 static int
-check_flashed(stlink_t *sl, struct cc_usb *cc)
+check_flashed(stlink_t *sl)
 {
-       uint16_t        romconfig_version = get_uint16(sl, cc, AO_ROMCONFIG_VERSION);
-       uint16_t        romconfig_check = get_uint16(sl, cc, AO_ROMCONFIG_CHECK);
+       uint16_t        romconfig_version = get_uint16(sl, AO_ROMCONFIG_VERSION);
+       uint16_t        romconfig_check = get_uint16(sl, AO_ROMCONFIG_CHECK);
 
        if (romconfig_version != (uint16_t) ~romconfig_check) {
                fprintf (stderr, "Device has not been flashed before\n");
@@ -219,34 +136,27 @@ check_flashed(stlink_t *sl, struct cc_usb *cc)
 }
 
 static const struct option options[] = {
-       { .name = "stlink", .has_arg = 0, .val = 'S' },
-       { .name = "tty", .has_arg = 1, .val = 'T' },
-       { .name = "device", .has_arg = 1, .val = 'D' },
+       { .name = "v1", .has_arg = 0, .val = '1' },
+       { .name = "raw", .has_arg = 0, .val = 'r' },
        { .name = "cal", .has_arg = 1, .val = 'c' },
        { .name = "serial", .has_arg = 1, .val = 's' },
-       { .name = "verbose", .has_arg = 0, .val = 'v' },
+       { .name = "verbose", .has_arg = 1, .val = 'v' },
        { 0, 0, 0, 0},
 };
 
 static void usage(char *program)
 {
-       fprintf(stderr, "usage: %s [--stlink] [--verbose] [--device=<device>] [-tty=<tty>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
+       fprintf(stderr, "usage: %s [--v1] [--raw] [--verbose=<verbose>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
        exit(1);
 }
 
 void
-done(stlink_t *sl, struct cc_usb *cc, int code)
+done(stlink_t *sl, int code)
 {
-       if (cc) {
-/*             cc_usb_printf(cc, "a\n"); */
-               cc_usb_close(cc);
-       }
-       if (sl) {
-               stlink_reset(sl);
-               stlink_run(sl);
-               stlink_exit_debug_mode(sl);
-               stlink_close(sl);
-       }
+       stlink_reset(sl);
+       stlink_run(sl);
+       stlink_exit_debug_mode(sl);
+       stlink_close(sl);
        exit (code);
 }
 
@@ -264,7 +174,8 @@ ends_with(char *whole, char *suffix)
 int
 main (int argc, char **argv)
 {
-       char                    *device = NULL;
+       int                     stlink_v1 = 0;
+       int                     raw = 0;
        char                    *filename;
        Elf                     *e;
        char                    *serial_end;
@@ -281,21 +192,20 @@ main (int argc, char **argv)
        int                     c;
        stlink_t                *sl = NULL;
        int                     was_flashed = 0;
-       struct hex_image        *load;
+       struct ao_hex_image     *load;
        int                     tries;
-       struct cc_usb           *cc = NULL;
-       int                     use_stlink = 0;
-       char                    *tty = NULL;
        int                     success;
        int                     verbose = 0;
+       struct ao_sym           *file_symbols;
+       int                     num_file_symbols;
 
-       while ((c = getopt_long(argc, argv, "T:D:c:s:Sv", options, NULL)) != -1) {
+       while ((c = getopt_long(argc, argv, "1rc:s:v:", options, NULL)) != -1) {
                switch (c) {
-               case 'T':
-                       tty = optarg;
+               case '1':
+                       stlink_v1 = 1;
                        break;
-               case 'D':
-                       device = optarg;
+               case 'r':
+                       raw = 1;
                        break;
                case 'c':
                        cal = strtoul(optarg, &cal_end, 10);
@@ -307,9 +217,6 @@ main (int argc, char **argv)
                        if (serial_end == optarg || *serial_end != '\0')
                                usage(argv[0]);
                        break;
-               case 'S':
-                       use_stlink = 1;
-                       break;
                case 'v':
                        verbose++;
                        break;
@@ -319,7 +226,7 @@ main (int argc, char **argv)
                }
        }
 
-       ao_self_verbose = verbose;
+       ao_verbose = verbose;
 
        if (verbose > 1)
                ccdbg_add_debug(CC_DEBUG_BITBANG);
@@ -329,219 +236,102 @@ main (int argc, char **argv)
                usage(argv[0]);
 
        if (ends_with (filename, ".elf")) {
-               load = ao_load_elf(filename);
+               load = ao_load_elf(filename, &file_symbols, &num_file_symbols);
        } else if (ends_with (filename, ".ihx")) {
-               int     i;
-               load = ccdbg_hex_load(filename);
-               for (i = 0; i < ao_num_symbols; i++)
-                       ao_symbols[i].addr = ao_symbols[i].default_addr;
+               load = ao_hex_load(filename, &file_symbols, &num_file_symbols);
        } else
                usage(argv[0]);
 
-       if (use_stlink) {
-               /* Connect to the programming dongle
-                */
+       if (!raw) {
+               if (!ao_editaltos_find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols)) {
+                       fprintf(stderr, "Cannot find required symbols\n");
+                       usage(argv[0]);
+               }
+       }
+
+       /* Connect to the programming dongle
+        */
        
-               for (tries = 0; tries < 3; tries++) {
-                       if (device) {
-                               sl = stlink_v1_open(50);
-                       } else {
-                               sl = stlink_open_usb(50);
+       for (tries = 0; tries < 3; tries++) {
+               if (stlink_v1) {
+                       sl = stlink_v1_open(50);
+               } else {
+                       sl = stlink_open_usb(50);
                
-                       }
-                       if (!sl) {
-                               fprintf (stderr, "No STLink devices present\n");
-                               done (sl, NULL, 1);
-                       }
-
-                       if (sl->chip_id != 0)
-                               break;
-                       stlink_reset(sl);
-                       stlink_close(sl);
-                       sl = NULL;
                }
                if (!sl) {
-                       fprintf (stderr, "Debugger connection failed\n");
-                       exit(1);
+                       fprintf (stderr, "No STLink devices present\n");
+                       done (sl, 1);
                }
 
-               /* Verify that the loaded image fits entirely within device flash
-                */
-               if (load->address < sl->flash_base ||
-                   sl->flash_base + sl->flash_size < load->address + load->length) {
-                       fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename,
-                                load->address, load->address + load->length);
-                       done(sl, NULL, 1);
-               }
-
-               /* Enter debugging mode
-                */
-               if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
-                       stlink_exit_dfu_mode(sl);
-
-               if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
-                       stlink_enter_swd_mode(sl);
-       } else {
-               int     is_loader;
-               int     tries;
-
-               for (tries = 0; tries < 3; tries++) {
-                       char    *this_tty = tty;
-                       if (!this_tty)
-                               this_tty = cc_usbdevs_find_by_arg(device, "AltosFlash");
-                       if (!this_tty)
-                               this_tty = cc_usbdevs_find_by_arg(device, "MegaMetrum");
-                       if (!this_tty)
-                               this_tty = getenv("ALTOS_TTY");
-                       if (!this_tty)
-                               this_tty="/dev/ttyACM0";
-
-                       cc = cc_usb_open(this_tty);
-
-                       if (!cc)
-                               exit(1);
-                       cc_usb_printf(cc, "v\n");
-                       is_loader = 0;
-                       for (;;) {
-                               char    line[256];
-                               cc_usb_getline(cc, line, sizeof(line));
-                               if (!strncmp(line, "altos-loader", 12))
-                                       is_loader = 1;
-                               if (!strncmp(line, "software-version", 16))
-                                       break;
-                       }
-                       if (is_loader)
-                               break;
-                       printf ("rebooting to loader\n");
-                       cc_usb_printf(cc, "X\n");
-                       cc_usb_close(cc);
-                       sleep(1);
-                       cc = NULL;
-               }
-               if (!is_loader) {
-                       fprintf(stderr, "Cannot switch to boot loader\n");
-                       exit(1);
-               }
-#if 0
-               {
-                       uint8_t check[256];
-                       int     i = 0;
-
-                       ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, check);
-                       for (;;) {
-                               uint8_t block[256];
-                               putchar ('.');
-                               if (++i == 40) {
-                                       putchar('\n');
-                                       i = 0;
-                               }
-                               fflush(stdout);
-                               ao_self_block_write(cc, AO_BOOT_APPLICATION_BASE, block);
-                               ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, block);
-                               if (memcmp(block, check, 256) != 0) {
-                                       fprintf (stderr, "read differed\n");
-                                       exit(1);
-                               }
-                       }
-               }
-#endif
+               if (sl->chip_id != 0)
+                       break;
+               stlink_reset(sl);
+               stlink_close(sl);
+               sl = NULL;
        }
-
-       /* Go fetch existing config values
-        * if available
-        */
-       was_flashed = check_flashed(sl, cc);
-
-       if (!serial) {
-               if (!was_flashed) {
-                       fprintf (stderr, "Must provide serial number\n");
-                       done(sl, cc, 1);
-               }
-               serial = get_uint16(sl, cc, AO_SERIAL_NUMBER);
-               if (!serial || serial == 0xffff) {
-                       fprintf (stderr, "Invalid existing serial %d\n", serial);
-                       done(sl, cc, 1);
-               }
+       if (!sl) {
+               fprintf (stderr, "Debugger connection failed\n");
+               exit(1);
        }
 
-       if (!cal && AO_RADIO_CAL && was_flashed) {
-               cal = get_uint32(sl, cc, AO_RADIO_CAL);
-               if (!cal || cal == 0xffffffff) {
-                       fprintf (stderr, "Invalid existing rf cal %d\n", cal);
-                       done(sl, cc, 1);
-               }
+       /* Verify that the loaded image fits entirely within device flash
+        */
+       if (load->address < sl->flash_base ||
+           sl->flash_base + sl->flash_size < load->address + load->length) {
+               fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename,
+                        load->address, load->address + load->length);
+               done(sl, 1);
        }
 
-       /* Write the config values into the flash image
+       /* Enter debugging mode
         */
+       if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
+               stlink_exit_dfu_mode(sl);
 
-       serial_int[0] = serial & 0xff;
-       serial_int[1] = (serial >> 8) & 0xff;
+       if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
+               stlink_enter_swd_mode(sl);
 
-       if (!rewrite(load, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {
-               fprintf(stderr, "Cannot rewrite serial integer at %08x\n",
-                       AO_SERIAL_NUMBER);
-               done(sl, cc, 1);
-       }
 
-       if (AO_USB_DESCRIPTORS) {
-               uint32_t        usb_descriptors = AO_USB_DESCRIPTORS - load->address;
-               string_num = 0;
+       if (!raw) {
+               /* Go fetch existing config values
+                * if available
+                */
+               was_flashed = check_flashed(sl);
 
-               while (load->data[usb_descriptors] != 0 && usb_descriptors < load->length) {
-                       if (load->data[usb_descriptors+1] == AO_USB_DESC_STRING) {
-                               ++string_num;
-                               if (string_num == 4)
-                                       break;
+               if (!serial) {
+                       if (!was_flashed) {
+                               fprintf (stderr, "Must provide serial number\n");
+                               done(sl, 1);
+                       }
+                       serial = get_uint16(sl, AO_SERIAL_NUMBER);
+                       if (!serial || serial == 0xffff) {
+                               fprintf (stderr, "Invalid existing serial %d\n", serial);
+                               done(sl, 1);
                        }
-                       usb_descriptors += load->data[usb_descriptors];
-               }
-               if (usb_descriptors >= load->length || load->data[usb_descriptors] == 0 ) {
-                       fprintf(stderr, "Cannot rewrite serial string at %08x\n", AO_USB_DESCRIPTORS);
-                       done(sl, cc, 1);
                }
 
-               serial_ucs2_len = load->data[usb_descriptors] - 2;
-               serial_ucs2 = malloc(serial_ucs2_len);
-               if (!serial_ucs2) {
-                       fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len);
-                       done(sl, cc, 1);
-               }
-               s = serial;
-               for (i = serial_ucs2_len / 2; i; i--) {
-                       serial_ucs2[i * 2 - 1] = 0;
-                       serial_ucs2[i * 2 - 2] = (s % 10) + '0';
-                       s /= 10;
-               }
-               if (!rewrite(load, usb_descriptors + 2 + load->address, serial_ucs2, serial_ucs2_len)) {
-                       fprintf (stderr, "Cannot rewrite USB descriptor at %08x\n", AO_USB_DESCRIPTORS);
-                       done(sl, cc, 1);
+               if (!cal && AO_RADIO_CAL && was_flashed) {
+                       cal = get_uint32(sl, AO_RADIO_CAL);
+                       if (!cal || cal == 0xffffffff) {
+                               fprintf (stderr, "Invalid existing rf cal %d\n", cal);
+                               done(sl, 1);
+                       }
                }
-       }
-
-       if (cal && AO_RADIO_CAL) {
-               cal_int[0] = cal & 0xff;
-               cal_int[1] = (cal >> 8) & 0xff;
-               cal_int[2] = (cal >> 16) & 0xff;
-               cal_int[3] = (cal >> 24) & 0xff;
 
-               if (!rewrite(load, AO_RADIO_CAL, cal_int, sizeof (cal_int))) {
-                       fprintf(stderr, "Cannot rewrite radio calibration at %08x\n", AO_RADIO_CAL);
-                       exit(1);
-               }
+               if (!ao_editaltos(load, serial, cal))
+                       done(sl, 1);
        }
 
        /* And flash the resulting image to the device
         */
-       if (cc)
-               success = ao_self_write(cc, load);
-       else
-               success = (stlink_write_flash(sl, load->address, load->data, load->length) >= 0);
+
+       success = (stlink_write_flash(sl, load->address, load->data, load->length) >= 0);
                
        if (!success) {
                fprintf (stderr, "\"%s\": Write failed\n", filename);
-               done(sl, cc, 1);
+               done(sl, 1);
        }
 
-       done(sl, cc, 0);
+       done(sl, 0);
 }
index 98884535f6ecaf4926685d4d99e70a807b31d00b..1ba9a9775143e1c675de12521efd840c11757946 100644 (file)
 #ifndef _AO_STMLOAD_H_
 #define _AO_STMLOAD_H_
 
-struct sym {
-       unsigned        addr;
-       unsigned        default_addr;
-       char            *name;
-       int             required;
-};
+#include "ao-elf.h"
 
 #define AO_BOOT_APPLICATION_BASE       0x08001000
 
-extern struct sym ao_symbols[];
+extern struct ao_sym ao_symbols[];
 
 extern int ao_num_symbols;
 extern int ao_num_required_symbols;
@@ -38,12 +33,4 @@ ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256]);
 void
 ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256]);
 
-struct hex_image *
-ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length);
-
-int
-ao_self_write(struct cc_usb *cc, struct hex_image *image);
-
-extern int ao_self_verbose;
-
 #endif /* _AO_STMLOAD_H_ */
index d2dae5a7a14068cbdcc5e21552bc64e61f79b31e..f1755b824f82ef233a89d6ec9312bdea623700c9 100644 (file)
@@ -194,6 +194,39 @@ main (int argc, char **argv)
                                                telem.mega_data.height);
 
                                        break;
+                               case AO_TELEMETRY_METRUM_SENSOR:
+                                       printf ("state %1d accel %5d pres %9d temp %6.2f acceleration %6.2f speed %6.2f height %5d v_batt %5d sense_a %5d sense_m %5d\n",
+                                               telem.metrum_sensor.state,
+                                               telem.metrum_sensor.accel,
+                                               telem.metrum_sensor.pres,
+                                               telem.metrum_sensor.temp / 100.0,
+                                               telem.metrum_sensor.acceleration / 16.0,
+                                               telem.metrum_sensor.speed / 16.0,
+                                               telem.metrum_sensor.height,
+                                               telem.metrum_sensor.v_batt,
+                                               telem.metrum_sensor.sense_a,
+                                               telem.metrum_sensor.sense_m);
+                                       break;
+                               case AO_TELEMETRY_METRUM_DATA:
+                                       printf ("ground_pres %9d ground_accel %5d accel_plus %5d accel_minus %5d\n",
+                                               telem.metrum_data.ground_pres,
+                                               telem.metrum_data.ground_accel,
+                                               telem.metrum_data.accel_plus_g,
+                                               telem.metrum_data.accel_minus_g);
+                                       break;
+                               case AO_TELEMETRY_MINI:
+                                       printf ("state %1d v_batt %5d sense_a %5d sense_m %5d pres %9d temp %6.2f acceleration %6.2f speed %6.2f height %5d ground_pres %9d\n",
+                                               telem.mini.state,
+                                               telem.mini.v_batt,
+                                               telem.mini.sense_a,
+                                               telem.mini.sense_m,
+                                               telem.mini.pres,
+                                               telem.mini.temp / 100.0,
+                                               telem.mini.acceleration / 16.0,
+                                               telem.mini.speed / 16.0,
+                                               telem.mini.height,
+                                               telem.mini.ground_pres);
+                                       break;
                                default:
                                        printf("\n");
                                }
diff --git a/ao-tools/ao-usbload/Makefile.am b/ao-tools/ao-usbload/Makefile.am
new file mode 100644 (file)
index 0000000..e3b63a8
--- /dev/null
@@ -0,0 +1,12 @@
+bin_PROGRAMS=ao-usbload
+
+AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBUSB_CFLAGS)
+AO_STMLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a
+
+ao_usbload_DEPENDENCIES = $(AO_STMLOAD_LIBS)
+
+ao_usbload_LDADD=$(AO_STMLOAD_LIBS) $(LIBUSB_LIBS) -lelf
+
+ao_usbload_SOURCES=ao-usbload.c ao-usbload.h
+
+man_MANS = ao-usbload.1
diff --git a/ao-tools/ao-usbload/ao-usbload.1 b/ao-tools/ao-usbload/ao-usbload.1
new file mode 100644 (file)
index 0000000..4816592
--- /dev/null
@@ -0,0 +1,81 @@
+.\"
+.\" Copyright © 2009 Keith Packard <keithp@keithp.com>
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; 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.
+.\"
+.\"
+.TH AO-LOAD 1 "ao-usbload" ""
+.SH NAME
+ao-usbload \- flash a program to an ARM-based AltOS device
+.SH SYNOPSIS
+.B "ao-usbload"
+[\-T \fItty-device\fP]
+[\--tty \fItty-device\fP]
+[\-D \fIaltos-device\fP]
+[\--device \fIaltos-device\fP]
+[\--cal \fIradio-calibration\fP]
+[\--serial \fserial-number\fP]
+\fIfile.elf\fP or \fIfile.ihx\fP
+.SH DESCRIPTION
+.I ao-usbload
+loads the specified .elf or .ihx file into the target device flash
+memory via the AltOS boot loader, using either existing serial number
+and radio calibration values or taking either of those from the
+command line.
+.SH OPTIONS
+.TP
+\-T tty-device | --tty tty-device
+This selects which tty device the debugger uses to communicate with
+the target device. The special name 'BITBANG' directs ao-dbg to use
+the cp2103 connection, otherwise this should be a usb serial port
+connected to a suitable cc1111 debug node.
+.TP
+\-D AltOS-device | --device AltOS-device
+Search for a connected device. This requires an argument of one of the
+following forms:
+.IP
+TeleMega:2
+.br
+TeleMega
+.br
+2
+.IP
+Leaving out the product name will cause the tool to select a suitable
+product, leaving out the serial number will cause the tool to match
+one of the available devices.
+.TP
+\-s serial-number | --serial serial-number
+This programs the device serial number into the image. If no serial
+number is specified, then the existing serial number, if any, will be
+read from the device.
+.TP
+\-c radio-calibration | --cal radio-calibration This programs the
+radio calibration value into the image for hardware which doesn't have
+any eeprom storage for this value. If no calibration value is
+specified, an existing calibration value will be used. The value here
+can be computed given the current radio calibration value, the
+measured frequency and the desired frequency:
+.IP
+       cal' = cal * (desired/measured)
+.IP
+The default calibration value is 7119667.
+.SH USAGE
+.I ao-usbload
+reads the specified .elf file into memory, edits the image to
+customize it using the specified serial number and radio calibration
+values. It then connects to the debug dongle and writes the program to
+the target device flash memory.
+.SH AUTHOR
+Keith Packard
diff --git a/ao-tools/ao-usbload/ao-usbload.c b/ao-tools/ao-usbload/ao-usbload.c
new file mode 100644 (file)
index 0000000..0c8a23d
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * 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 <err.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdbool.h>
+#include "ao-elf.h"
+#include "ccdbg.h"
+#include "cc-usb.h"
+#include "cc.h"
+#include "ao-usbload.h"
+#include "ao-selfload.h"
+#include "ao-verbose.h"
+#include "ao-editaltos.h"
+
+static uint16_t
+get_uint16(struct cc_usb *cc, uint32_t addr)
+{
+       uint16_t        result;
+       result = ao_self_get_uint16(cc, addr);
+       printf ("read 0x%08x = 0x%04x\n", addr, result);
+       return result;
+}
+
+/*
+ * Read a 32-bit value from the target device with arbitrary
+ * alignment
+ */
+static uint32_t
+get_uint32(struct cc_usb *cc, uint32_t addr)
+{
+       uint32_t        result;
+
+       result = ao_self_get_uint32(cc, addr);
+       printf ("read 0x%08x = 0x%08x\n", addr, result);
+       return result;
+}
+
+/*
+ * Check to see if the target device has been
+ * flashed with a similar firmware image before
+ *
+ * This is done by looking for the same romconfig version,
+ * which should be at the same location as the linker script
+ * places this at 0x100 from the start of the rom section
+ */
+static int
+check_flashed(struct cc_usb *cc)
+{
+       uint16_t        romconfig_version = get_uint16(cc, AO_ROMCONFIG_VERSION);
+       uint16_t        romconfig_check = get_uint16(cc, AO_ROMCONFIG_CHECK);
+
+       if (romconfig_version != (uint16_t) ~romconfig_check) {
+               fprintf (stderr, "Device has not been flashed before\n");
+               return 0;
+       }
+       return 1;
+}
+
+static const struct option options[] = {
+       { .name = "tty", .has_arg = 1, .val = 'T' },
+       { .name = "device", .has_arg = 1, .val = 'D' },
+       { .name = "raw", .has_arg = 0, .val = 'r' },
+       { .name = "cal", .has_arg = 1, .val = 'c' },
+       { .name = "serial", .has_arg = 1, .val = 's' },
+       { .name = "verbose", .has_arg = 1, .val = 'v' },
+       { 0, 0, 0, 0},
+};
+
+static void usage(char *program)
+{
+       fprintf(stderr, "usage: %s [--raw] [--verbose=<verbose>] [--device=<device>] [-tty=<tty>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
+       exit(1);
+}
+
+void
+done(struct cc_usb *cc, int code)
+{
+/*     cc_usb_printf(cc, "a\n"); */
+       cc_usb_close(cc);
+       exit (code);
+}
+
+static int
+ends_with(char *whole, char *suffix)
+{
+       int whole_len = strlen(whole);
+       int suffix_len = strlen(suffix);
+
+       if (suffix_len > whole_len)
+               return 0;
+       return strcmp(whole + whole_len - suffix_len, suffix) == 0;
+}
+
+int
+main (int argc, char **argv)
+{
+       char                    *device = NULL;
+       char                    *filename;
+       Elf                     *e;
+       int                     raw = 0;
+       char                    *serial_end;
+       unsigned int            serial = 0;
+       char                    *serial_ucs2;
+       int                     serial_ucs2_len;
+       char                    serial_int[2];
+       unsigned int            s;
+       int                     i;
+       int                     string_num;
+       uint32_t                cal = 0;
+       char                    cal_int[4];
+       char                    *cal_end;
+       int                     c;
+       int                     was_flashed = 0;
+       struct ao_hex_image     *load;
+       int                     tries;
+       struct cc_usb           *cc = NULL;
+       char                    *tty = NULL;
+       int                     success;
+       int                     verbose = 0;
+       struct ao_sym           *file_symbols;
+       int                     num_file_symbols;
+
+       while ((c = getopt_long(argc, argv, "rT:D:c:s:v:", options, NULL)) != -1) {
+               switch (c) {
+               case 'T':
+                       tty = optarg;
+                       break;
+               case 'D':
+                       device = optarg;
+                       break;
+               case 'r':
+                       raw = 1;
+                       break;
+               case 'c':
+                       cal = strtoul(optarg, &cal_end, 10);
+                       if (cal_end == optarg || *cal_end != '\0')
+                               usage(argv[0]);
+                       break;
+               case 's':
+                       serial = strtoul(optarg, &serial_end, 10);
+                       if (serial_end == optarg || *serial_end != '\0')
+                               usage(argv[0]);
+                       break;
+               case 'v':
+                       verbose++;
+                       break;
+               default:
+                       usage(argv[0]);
+                       break;
+               }
+       }
+
+       ao_verbose = verbose;
+
+       if (verbose > 1)
+               ccdbg_add_debug(CC_DEBUG_BITBANG);
+
+       filename = argv[optind];
+       if (filename == NULL)
+               usage(argv[0]);
+
+       if (ends_with (filename, ".elf")) {
+               load = ao_load_elf(filename, &file_symbols, &num_file_symbols);
+       } else if (ends_with (filename, ".ihx")) {
+               load = ao_hex_load(filename, &file_symbols, &num_file_symbols);
+       } else
+               usage(argv[0]);
+
+       if (!raw) {
+               if (!ao_editaltos_find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols)) {
+                       fprintf(stderr, "Cannot find required symbols\n");
+                       usage(argv[0]);
+               }
+       }
+
+       {
+               int     is_loader;
+               int     tries;
+
+               for (tries = 0; tries < 3; tries++) {
+                       char    *this_tty = tty;
+                       if (!this_tty)
+                               this_tty = cc_usbdevs_find_by_arg(device, "AltosFlash");
+                       if (!this_tty)
+                               this_tty = cc_usbdevs_find_by_arg(device, "TeleMega");
+                       if (!this_tty)
+                               this_tty = getenv("ALTOS_TTY");
+                       if (!this_tty)
+                               this_tty="/dev/ttyACM0";
+
+                       cc = cc_usb_open(this_tty);
+
+                       if (!cc)
+                               exit(1);
+                       cc_usb_printf(cc, "v\n");
+                       is_loader = 0;
+                       for (;;) {
+                               char    line[256];
+                               cc_usb_getline(cc, line, sizeof(line));
+                               if (!strncmp(line, "altos-loader", 12))
+                                       is_loader = 1;
+                               if (!strncmp(line, "software-version", 16))
+                                       break;
+                       }
+                       if (is_loader)
+                               break;
+                       printf ("rebooting to loader\n");
+                       cc_usb_printf(cc, "X\n");
+                       cc_usb_close(cc);
+                       sleep(1);
+                       cc = NULL;
+               }
+               if (!is_loader) {
+                       fprintf(stderr, "Cannot switch to boot loader\n");
+                       exit(1);
+               }
+#if 0
+               {
+                       uint8_t check[256];
+                       int     i = 0;
+
+                       ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, check);
+                       for (;;) {
+                               uint8_t block[256];
+                               putchar ('.');
+                               if (++i == 40) {
+                                       putchar('\n');
+                                       i = 0;
+                               }
+                               fflush(stdout);
+                               ao_self_block_write(cc, AO_BOOT_APPLICATION_BASE, block);
+                               ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, block);
+                               if (memcmp(block, check, 256) != 0) {
+                                       fprintf (stderr, "read differed\n");
+                                       exit(1);
+                               }
+                       }
+               }
+#endif
+       }
+
+       if (!raw) {
+               /* Go fetch existing config values
+                * if available
+                */
+               was_flashed = check_flashed(cc);
+
+               if (!serial) {
+                       if (!was_flashed) {
+                               fprintf (stderr, "Must provide serial number\n");
+                               done(cc, 1);
+                       }
+                       serial = get_uint16(cc, AO_SERIAL_NUMBER);
+                       if (!serial || serial == 0xffff) {
+                               fprintf (stderr, "Invalid existing serial %d\n", serial);
+                               done(cc, 1);
+                       }
+               }
+
+               if (!cal && AO_RADIO_CAL && was_flashed) {
+                       cal = get_uint32(cc, AO_RADIO_CAL);
+                       if (!cal || cal == 0xffffffff) {
+                               fprintf (stderr, "Invalid existing rf cal %d\n", cal);
+                               done(cc, 1);
+                       }
+               }
+
+               if (!ao_editaltos(load, serial, cal))
+                       done(cc, 1);
+       }
+
+       /* And flash the resulting image to the device
+        */
+       success = ao_self_write(cc, load);
+               
+       if (!success) {
+               fprintf (stderr, "\"%s\": Write failed\n", filename);
+               done(cc, 1);
+       }
+
+       done(cc, 0);
+}
diff --git a/ao-tools/ao-usbload/ao-usbload.h b/ao-tools/ao-usbload/ao-usbload.h
new file mode 100644 (file)
index 0000000..1ba9a97
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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_STMLOAD_H_
+#define _AO_STMLOAD_H_
+
+#include "ao-elf.h"
+
+#define AO_BOOT_APPLICATION_BASE       0x08001000
+
+extern struct ao_sym ao_symbols[];
+
+extern int ao_num_symbols;
+extern int ao_num_required_symbols;
+
+void
+ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256]);
+
+void
+ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256]);
+
+#endif /* _AO_STMLOAD_H_ */
index 1f8f2e42f33eb7d1098bbcc0aab5dff1842acd74..a03a976cd59b3f397790965ee338524975aef925 100644 (file)
@@ -11,7 +11,6 @@ libao_tools_a_SOURCES = \
        ccdbg-debug.h \
        ccdbg-flash.c \
        ccdbg.h \
-       ccdbg-hex.c \
        ccdbg-io.c \
        ccdbg-manual.c \
        ccdbg-memory.c \
@@ -21,6 +20,7 @@ libao_tools_a_SOURCES = \
        cc-convert.c \
        cc-dsp.c \
        cc-integrate.c \
+       cc-mega.c \
        cc-period.c \
        cc-process.c \
        cc-usb.c \
@@ -39,4 +39,14 @@ libao_tools_a_SOURCES = \
        i0.c \
        chbevl.c \
        mconf.h \
-       cephes.h
+       cephes.h \
+       ao-hex.c \
+       ao-hex.h \
+       ao-editaltos.c \
+       ao-editaltos.h \
+       ao-elf.c \
+       ao-elf.h \
+       ao-selfload.c \
+       ao-selfload.h \
+       ao-verbose.c \
+       ao-verbose.h
diff --git a/ao-tools/lib/ao-editaltos.c b/ao-tools/lib/ao-editaltos.c
new file mode 100644 (file)
index 0000000..a8b6409
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "ao-editaltos.h"
+
+struct ao_sym ao_symbols[] = {
+
+       { 0, 0, "ao_romconfig_version", 1 },
+       { 0, 0, "ao_romconfig_check",   1 },
+       { 0, 0, "ao_serial_number", 1 },
+       { 0, 0, "ao_radio_cal", 0 },
+       { 0, 0, "ao_usb_descriptors", 0 },
+};
+
+#define NUM_SYMBOLS            5
+
+int ao_num_symbols = NUM_SYMBOLS;
+
+/*
+ * Edit the to-be-written memory block
+ */
+static bool
+rewrite(struct ao_hex_image *load, unsigned address, uint8_t *data, int length)
+{
+       int             i;
+
+       if (address < load->address || load->address + load->length < address + length)
+               return false;
+
+       printf("rewrite %04x:", address);
+       for (i = 0; i < length; i++)
+               printf (" %02x", load->data[address - load->address + i]);
+       printf(" ->");
+       for (i = 0; i < length; i++)
+               printf (" %02x", data[i]);
+       printf("\n");
+       memcpy(load->data + address - load->address, data, length);
+       return true;
+}
+
+/*
+ * Find the symbols needed to correctly load the program
+ */
+
+bool
+ao_editaltos_find_symbols(struct ao_sym *file_symbols, int num_file_symbols,
+                         struct ao_sym *symbols, int num_symbols)
+{
+       int     f, s;
+
+       for (f = 0; f < num_file_symbols; f++) {
+               for (s = 0; s < num_symbols; s++) {
+                       if (strcmp(symbols[s].name, file_symbols[f].name) == 0) {
+                               symbols[s].addr = file_symbols[f].addr;
+                               symbols[s].found = true;
+                       }
+               }
+       }
+       for (s = 0; s < num_symbols; s++)
+               if (!symbols[s].found && symbols[s].required)
+                       return false;
+       return true;
+}
+
+bool
+ao_editaltos(struct ao_hex_image *image,
+            uint16_t serial,
+            uint32_t cal)
+{
+       uint8_t                 *serial_ucs2;
+       int                     serial_ucs2_len;
+       uint8_t                 serial_int[2];
+       unsigned int            s;
+       int                     i;
+       int                     string_num;
+       uint8_t                 cal_int[4];
+
+       /* Write the config values into the flash image
+        */
+
+       serial_int[0] = serial & 0xff;
+       serial_int[1] = (serial >> 8) & 0xff;
+
+       if (!rewrite(image, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {
+               fprintf(stderr, "Cannot rewrite serial integer at %08x\n",
+                       AO_SERIAL_NUMBER);
+               return false;
+       }
+
+       if (AO_USB_DESCRIPTORS) {
+               uint32_t        usb_descriptors = AO_USB_DESCRIPTORS - image->address;
+               string_num = 0;
+
+               while (image->data[usb_descriptors] != 0 && usb_descriptors < image->length) {
+                       if (image->data[usb_descriptors+1] == AO_USB_DESC_STRING) {
+                               ++string_num;
+                               if (string_num == 4)
+                                       break;
+                       }
+                       usb_descriptors += image->data[usb_descriptors];
+               }
+               if (usb_descriptors >= image->length || image->data[usb_descriptors] == 0 ) {
+                       fprintf(stderr, "Cannot rewrite serial string at %08x\n", AO_USB_DESCRIPTORS);
+                       return false;
+               }
+
+               serial_ucs2_len = image->data[usb_descriptors] - 2;
+               serial_ucs2 = malloc(serial_ucs2_len);
+               if (!serial_ucs2) {
+                       fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len);
+                       return false;
+               }
+               s = serial;
+               for (i = serial_ucs2_len / 2; i; i--) {
+                       serial_ucs2[i * 2 - 1] = 0;
+                       serial_ucs2[i * 2 - 2] = (s % 10) + '0';
+                       s /= 10;
+               }
+               if (!rewrite(image, usb_descriptors + 2 + image->address, serial_ucs2, serial_ucs2_len)) {
+                       fprintf (stderr, "Cannot rewrite USB descriptor at %08x\n", AO_USB_DESCRIPTORS);
+                       return false;
+               }
+       }
+
+       if (cal && AO_RADIO_CAL) {
+               cal_int[0] = cal & 0xff;
+               cal_int[1] = (cal >> 8) & 0xff;
+               cal_int[2] = (cal >> 16) & 0xff;
+               cal_int[3] = (cal >> 24) & 0xff;
+
+               if (!rewrite(image, AO_RADIO_CAL, cal_int, sizeof (cal_int))) {
+                       fprintf(stderr, "Cannot rewrite radio calibration at %08x\n", AO_RADIO_CAL);
+                       return false;
+               }
+       }
+       return true;
+}
diff --git a/ao-tools/lib/ao-editaltos.h b/ao-tools/lib/ao-editaltos.h
new file mode 100644 (file)
index 0000000..7453043
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_EDITALTOS_H_
+#define _AO_EDITALTOS_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ao-hex.h"
+
+extern struct ao_sym ao_symbols[];
+extern int ao_num_symbols;
+
+#define AO_USB_DESC_STRING             3
+
+#define AO_ROMCONFIG_VERSION   (ao_symbols[0].addr)
+#define AO_ROMCONFIG_CHECK     (ao_symbols[1].addr)
+#define AO_SERIAL_NUMBER       (ao_symbols[2].addr)
+#define AO_RADIO_CAL           (ao_symbols[3].addr)
+#define AO_USB_DESCRIPTORS     (ao_symbols[4].addr)
+
+struct ao_editaltos_funcs {
+       uint16_t        (*get_uint16)(void *closure, uint32_t addr);
+       uint32_t        (*get_uint32)(void *closure, uint32_t addr);
+};
+
+bool
+ao_editaltos_find_symbols(struct ao_sym *file_symbols, int num_file_symbols,
+                         struct ao_sym *symbols, int num_symbols);
+
+bool
+ao_editaltos(struct ao_hex_image *image,
+            uint16_t serial,
+            uint32_t radio_cal);
+
+#endif /* _AO_EDITALTOS_H_ */
diff --git a/ao-tools/lib/ao-elf.c b/ao-tools/lib/ao-elf.c
new file mode 100644 (file)
index 0000000..99b3721
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "ao-elf.h"
+#include "ao-hex.h"
+#include "ao-verbose.h"
+
+/*
+ * Look through the Elf file for symbols that can be adjusted before
+ * the image is written to the device
+ */
+static struct ao_sym *
+load_symbols (Elf *e, int *num_symbolsp)
+{
+       Elf_Scn         *scn;
+       Elf_Data        *symbol_data = NULL;
+       GElf_Shdr       shdr;
+       GElf_Sym        sym;
+       int             i, symbol_count;
+       char            *symbol_name;
+       size_t          shstrndx;
+       struct ao_sym   *symbols = NULL;
+       struct ao_sym   *symbol;
+       int             num_symbols = 0;
+       int             size_symbols = 0;
+
+       if (elf_getshdrstrndx(e, &shstrndx) < 0)
+               return false;
+
+       /*
+        * Find the symbols
+        */
+
+       scn = NULL;
+       while ((scn = elf_nextscn(e, scn)) != NULL) {
+
+               if (gelf_getshdr(scn, &shdr) != &shdr)
+                       return false;
+
+               if (shdr.sh_type == SHT_SYMTAB) {
+                       symbol_data = elf_getdata(scn, NULL);
+                       symbol_count = shdr.sh_size / shdr.sh_entsize;
+                       break;
+               }
+       }
+
+       if (!symbol_data)
+               return NULL;
+
+       for (i = 0; i < symbol_count; i++) {
+               gelf_getsym(symbol_data, i, &sym);
+
+               symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name);
+               if (!symbol_name[0])
+                       continue;
+
+               if (num_symbols == size_symbols) {
+                       struct ao_sym   *new_symbols;
+                       int             new_size;
+
+                       if (!size_symbols)
+                               new_size = 16;
+                       else
+                               new_size = size_symbols * 2;
+                       new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym));
+                       if (!new_symbols)
+                               goto bail;
+
+                       symbols = new_symbols;
+                       size_symbols = new_size;
+               }
+               symbol = &symbols[num_symbols];
+               memset(symbol, 0, sizeof (struct ao_sym));
+               symbol->name = strdup(symbol_name);
+               if (!symbol->name)
+                       goto bail;
+               symbol->addr = sym.st_value;
+               ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr);
+               num_symbols++;
+       }
+       *num_symbolsp = num_symbols;
+       return symbols;
+bail:
+       for (i = 0; i < num_symbols; i++)
+               free(symbols[i].name);
+       free(symbols);
+       return NULL;
+}
+
+static uint32_t
+round4(uint32_t a) {
+       return (a + 3) & ~3;
+}
+
+static struct ao_hex_image *
+new_load (uint32_t addr, uint32_t len)
+{
+       struct ao_hex_image *new;
+
+       len = round4(len);
+       new = calloc (1, sizeof (struct ao_hex_image) + len);
+       if (!new)
+               abort();
+
+       new->address = addr;
+       new->length = len;
+       return new;
+}
+
+static void
+load_paste(struct ao_hex_image *into, struct ao_hex_image *from)
+{
+       if (from->address < into->address || into->address + into->length < from->address + from->length)
+               abort();
+
+       memcpy(into->data + from->address - into->address, from->data, from->length);
+}
+
+/*
+ * Make a new load structure large enough to hold the old one and
+ * the new data
+ */
+static struct ao_hex_image *
+expand_load(struct ao_hex_image *from, uint32_t address, uint32_t length)
+{
+       struct ao_hex_image     *new;
+
+       if (from) {
+               uint32_t        from_last = from->address + from->length;
+               uint32_t        last = address + length;
+
+               if (address > from->address)
+                       address = from->address;
+               if (last < from_last)
+                       last = from_last;
+
+               length = last - address;
+
+               if (address == from->address && length == from->length)
+                       return from;
+       }
+       new = new_load(address, length);
+       if (from) {
+               load_paste(new, from);
+               free (from);
+       }
+       return new;
+}
+
+/*
+ * Create a new load structure with data from the existing one
+ * and the new data
+ */
+static struct ao_hex_image *
+load_write(struct ao_hex_image *from, uint32_t address, uint32_t length, void *data)
+{
+       struct ao_hex_image     *new;
+
+       new = expand_load(from, address, length);
+       memcpy(new->data + address - new->address, data, length);
+       return new;
+}
+
+/*
+ * Construct a large in-memory block for all
+ * of the loaded sections of the program
+ */
+static struct ao_hex_image *
+get_load(Elf *e)
+{
+       Elf_Scn         *scn;
+       size_t          shstrndx;
+       GElf_Shdr       shdr;
+       Elf_Data        *data;
+       size_t          nphdr;
+       size_t          p;
+       GElf_Phdr       phdr;
+       GElf_Addr       sh_paddr;
+       struct ao_hex_image     *load = NULL;
+#if 0
+       char            *section_name;
+#endif
+       size_t          nshdr;
+       size_t          s;
+       
+       if (elf_getshdrstrndx(e, &shstrndx) < 0)
+               return 0;
+
+       if (elf_getphdrnum(e, &nphdr) < 0)
+               return 0;
+
+       if (elf_getshdrnum(e, &nshdr) < 0)
+               return 0;
+
+       /*
+        * As far as I can tell, all of the phdr sections should
+        * be flashed to memory
+        */
+       for (p = 0; p < nphdr; p++) {
+
+               /* Find this phdr */
+               gelf_getphdr(e, p, &phdr);
+
+               if (phdr.p_type != PT_LOAD)
+                       continue;
+
+               /* Get the associated file section */
+
+#if 0
+               fprintf (stderr, "offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n",
+                        (uint32_t) phdr.p_offset,
+                        (uint32_t) phdr.p_vaddr,
+                        (uint32_t) phdr.p_paddr,
+                        (uint32_t) phdr.p_filesz,
+                        (uint32_t) phdr.p_memsz);
+#endif
+               
+               for (s = 0; s < nshdr; s++) {
+                       scn = elf_getscn(e, s);
+
+                       if (!scn) {
+                               fprintf (stderr, "getscn failed\n");
+                               abort();
+                       }
+                       if (gelf_getshdr(scn, &shdr) != &shdr) {
+                               fprintf (stderr, "gelf_getshdr failed\n");
+                               abort();
+                       }
+
+#if 0
+                       section_name = elf_strptr(e, shstrndx, shdr.sh_name);
+#endif
+
+                       if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) {
+                                       
+                               if (shdr.sh_size == 0)
+                                       continue;
+
+                               sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset;
+
+#if 0
+                               fprintf (stderr, "\tsize %08x rom %08x exec %08x %s\n",
+                                        (uint32_t) shdr.sh_size,
+                                        (uint32_t) sh_paddr,
+                                        (uint32_t) shdr.sh_addr,
+                                        section_name);
+#endif
+
+                               data = elf_getdata(scn, NULL);
+
+                               /* Write the section data into the memory block */
+                               load = load_write(load, sh_paddr, shdr.sh_size, data->d_buf);
+                       }
+               }
+       }
+       return load;
+}
+
+/*
+ * Open the specified ELF file and
+ * check for the symbols we need
+ */
+
+struct ao_hex_image *
+ao_load_elf(char *name, struct ao_sym **symbols, int *num_symbols)
+{
+       int             fd;
+       Elf             *e;
+       size_t          shstrndx;
+       struct ao_hex_image     *image;
+
+       if (elf_version(EV_CURRENT) == EV_NONE)
+               return NULL;
+
+       fd = open(name, O_RDONLY, 0);
+
+       if (fd < 0)
+               return NULL;
+
+       e = elf_begin(fd, ELF_C_READ, NULL);
+
+       if (!e)
+               return NULL;
+
+       if (elf_kind(e) != ELF_K_ELF)
+               return NULL;
+
+       if (elf_getshdrstrndx(e, &shstrndx) != 0)
+               return NULL;
+
+       if (symbols)
+               *symbols = load_symbols(e, num_symbols);
+
+       image = get_load(e);
+       if (!image) {
+               fprintf (stderr, "Cannot create memory image from file\n");
+               return NULL;
+       }
+
+       return image;
+}
diff --git a/ao-tools/lib/ao-elf.h b/ao-tools/lib/ao-elf.h
new file mode 100644 (file)
index 0000000..0f79d14
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_ELF_H_
+#define _AO_ELF_H_
+
+#include <stdbool.h>
+#include <gelf.h>
+#include "ao-hex.h"
+
+struct ao_hex_image *
+ao_load_elf(char *name, struct ao_sym **symbols, int *num_symbols);
+
+#endif /* _AO_ELF_H_ */
diff --git a/ao-tools/lib/ao-hex.c b/ao-tools/lib/ao-hex.c
new file mode 100644 (file)
index 0000000..5cfc63c
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * Copyright © 2008 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 <stdarg.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "ao-hex.h"
+#include "ao-verbose.h"
+
+struct ao_hex_input {
+       FILE    *file;
+       int     line;
+       char    *name;
+};
+
+enum ao_hex_read_state {
+       read_marker,
+       read_length,
+       read_address,
+       read_type,
+       read_data,
+       read_checksum,
+       read_newline,
+       read_white,
+       read_done,
+};
+
+
+static void
+ao_hex_error(struct ao_hex_input *input, char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+       fprintf(stderr, "Hex error %s:%d: ", input->name, input->line);
+       vfprintf(stderr, format, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+}
+
+static void
+ao_hex_free(struct ao_hex_record *record)
+{
+       if (!record) return;
+       free(record);
+}
+
+static struct ao_hex_record *
+ao_hex_alloc(uint8_t length)
+{
+       struct ao_hex_record *record;
+
+       record = calloc(1, sizeof(struct ao_hex_record) + length);
+       record->length = length;
+       return record;
+}
+
+static int
+ishex(char c)
+{
+       return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+}
+
+static int
+fromhex(char c)
+{
+       if (isdigit(c))
+               return c - '0';
+       if ('a' <= c && c <= 'f')
+               return c - 'a' + 10;
+       if ('A' <= c && c <= 'F')
+               return c - 'A' + 10;
+       abort();
+       return 0;
+}
+
+static uint8_t
+ao_hex_checksum(struct ao_hex_record *record)
+{
+       uint8_t checksum = 0;
+       int i;
+
+       checksum += record->length;
+       checksum += record->address >> 8;
+       checksum += record->address & 0xff;
+       checksum += record->type;
+       for (i = 0; i < record->length; i++)
+               checksum += record->data[i];
+       return -checksum;
+}
+
+static struct ao_hex_record *
+ao_hex_read_record(struct ao_hex_input *input)
+{
+       struct ao_hex_record *record = NULL;
+       enum ao_hex_read_state state = read_marker;
+       char c;
+       int nhexbytes;
+       uint32_t hex;
+       uint32_t ndata;
+       uint8_t checksum;
+
+       while (state != read_done) {
+               c = getc(input->file);
+               if (c == EOF && state != read_white && state != read_marker) {
+                       ao_hex_error(input, "Unexpected EOF");
+                       goto bail;
+               }
+               if (c == ' ')
+                       continue;
+               if (c == '\n')
+                       input->line++;
+               switch (state) {
+               case read_marker:
+                       if (c == EOF)
+                               return NULL;
+                       if (c != ':') {
+                               ao_hex_error(input, "Missing ':'");
+                               goto bail;
+                       }
+                       state = read_length;
+                       nhexbytes = 2;
+                       hex = 0;
+                       break;
+               case read_length:
+               case read_address:
+               case read_type:
+               case read_data:
+               case read_checksum:
+                       if (!ishex(c)) {
+                               ao_hex_error(input, "Non-hex char '%c'",
+                                               c);
+                               goto bail;
+                       }
+                       hex = hex << 4 | fromhex(c);
+                       --nhexbytes;
+                       if (nhexbytes != 0)
+                               break;
+
+                       switch (state) {
+                       case read_length:
+                               record = ao_hex_alloc(hex);
+                               if (!record) {
+                                       ao_hex_error(input, "Out of memory");
+                                       goto bail;
+                               }
+                               state = read_address;
+                               nhexbytes = 4;
+                               break;
+                       case read_address:
+                               record->address = hex;
+                               state = read_type;
+                               nhexbytes = 2;
+                               break;
+                       case read_type:
+                               record->type = hex;
+                               state = read_data;
+                               nhexbytes = 2;
+                               ndata = 0;
+                               break;
+                       case read_data:
+                               record->data[ndata] = hex;
+                               ndata++;
+                               nhexbytes = 2;
+                               break;
+                       case read_checksum:
+                               record->checksum = hex;
+                               state = read_newline;
+                               break;
+                       default:
+                               break;
+                       }
+                       if (state == read_data)
+                               if (ndata == record->length) {
+                                       nhexbytes = 2;
+                                       state = read_checksum;
+                               }
+                       hex = 0;
+                       break;
+               case read_newline:
+                       if (c != '\n' && c != '\r') {
+                               ao_hex_error(input, "Missing newline");
+                               goto bail;
+                       }
+                       state = read_white;
+                       break;
+               case read_white:
+                       if (!isspace(c)) {
+                               if (c == '\n')
+                                       input->line--;
+                               if (c != EOF)
+                                       ungetc(c, input->file);
+                               state = read_done;
+                       }
+                       break;
+               case read_done:
+                       break;
+               }
+       }
+       checksum = ao_hex_checksum(record);
+       if (checksum != record->checksum) {
+               ao_hex_error(input, "Invalid checksum (read 0x%02x computed 0x%02x)\n",
+                               record->checksum, checksum);
+               goto bail;
+       }
+       return record;
+
+bail:
+       ao_hex_free(record);
+       return NULL;
+}
+
+void
+ao_hex_file_free(struct ao_hex_file *hex)
+{
+       int     i;
+
+       if (!hex)
+               return;
+       for (i = 0; i < hex->nrecord; i++)
+               ao_hex_free(hex->records[i]);
+       free(hex);
+}
+
+struct ao_hex_file *
+ao_hex_file_read(FILE *file, char *name)
+{
+       struct ao_hex_input input;
+       struct ao_hex_file      *hex = NULL, *newhex;
+       struct ao_hex_record *record;
+       int srecord = 1;
+       int done = 0;
+
+       hex = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *), 1);
+       if (!hex)
+               return NULL;
+       input.name = name;
+       input.line = 1;
+       input.file = file;
+       while (!done) {
+               record = ao_hex_read_record(&input);
+               if (!record) {
+                       if (feof(input.file)) {
+                               done = 1;
+                               break;
+                       } else
+                               goto bail;
+               }
+               if (hex->nrecord == srecord) {
+                       srecord *= 2;
+                       newhex = realloc(hex,
+                                        sizeof (struct ao_hex_file) +
+                                        srecord * sizeof (struct ao_hex_record *));
+                       if (!newhex)
+                               goto bail;
+                       hex = newhex;
+               }
+               hex->records[hex->nrecord++] = record;
+       }
+       return hex;
+
+bail:
+       ao_hex_file_free(hex);
+       return NULL;
+}
+
+static struct ao_sym *
+load_symbols(struct ao_hex_file *hex,
+            int *num_symbolsp)
+{
+       uint32_t                extended_addr;
+       uint32_t                addr;
+       int                     i;
+       struct ao_hex_record    *record;
+       struct ao_sym           *symbols = NULL;
+       struct ao_sym           *symbol;
+       int                     num_symbols = 0;
+       int                     size_symbols = 0;
+       
+       extended_addr = 0;
+       for (i = 0; i < hex->nrecord; i++) {
+               record = hex->records[i];
+               switch (record->type) {
+               case AO_HEX_RECORD_NORMAL:
+                       addr = extended_addr + record->address;
+                       break;
+               case AO_HEX_RECORD_EOF:
+                       break;
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
+                       if (record->length != 2)
+                               goto bail;
+                       extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
+                       break;
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
+                       if (record->length != 2)
+                               goto bail;
+                       extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
+                       break;
+               case AO_HEX_RECORD_SYMBOL:
+                       addr = extended_addr + record->address;
+                       if (num_symbols == size_symbols) {
+                               struct ao_sym   *new_symbols;
+                               int             new_size;
+
+                               if (!size_symbols)
+                                       new_size = 16;
+                               else
+                                       new_size = size_symbols * 2;
+                               new_symbols = realloc(symbols, new_size * sizeof (struct ao_sym));
+                               if (!new_symbols)
+                                       goto bail;
+
+                               symbols = new_symbols;
+                               size_symbols = new_size;
+                       }
+                       symbol = &symbols[num_symbols];
+                       memset(symbol, 0, sizeof (struct ao_sym));
+                       symbol->name = calloc(record->length + 1, 1);
+                       if (!symbol->name)
+                               goto bail;
+                       memcpy(symbol->name, record->data, record->length);
+                       symbol->addr = addr;
+                       ao_printf(AO_VERBOSE_EXE, "Add symbol %s: %08x\n", symbol->name, symbol->addr);
+                       num_symbols++;
+                       break;
+               }
+       }
+       *num_symbolsp = num_symbols;
+       return symbols;
+bail:
+       for (i = 0; i < num_symbols; i++)
+               free(symbols[i].name);
+       free(symbols);
+       return NULL;
+}
+
+static void
+ao_hex_record_set_checksum(struct ao_hex_record *record)
+{
+       uint8_t cksum = 0;
+       int i;
+
+       cksum += record->length;
+       cksum += record->address >> 8;
+       cksum += record->address;
+       cksum += record->type;
+       for (i = 0; i < record->length; i++)
+               cksum += record->data[i];
+
+       record->checksum = -cksum;
+}
+
+struct ao_hex_image *
+ao_hex_image_create(struct ao_hex_file *hex)
+{
+       struct ao_hex_image *image;
+       struct ao_hex_record *record;
+       int i;
+       uint32_t addr;
+       uint32_t base, bound;
+       uint32_t offset;
+       uint32_t extended_addr;
+
+       int length;
+
+       /* Find the address bounds of the file
+        */
+       base = 0xffffffff;
+       bound = 0x0;
+       extended_addr = 0;
+       for (i = 0; i < hex->nrecord; i++) {
+               uint32_t r_bound;
+               record = hex->records[i];
+               switch (record->type) {
+               case AO_HEX_RECORD_NORMAL:
+                       addr = extended_addr + record->address;
+                       r_bound = addr + record->length;
+                       if (addr < base)
+                               base = addr;
+                       if (r_bound > bound)
+                               bound = r_bound;
+                       break;
+               case AO_HEX_RECORD_EOF:
+                       break;
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
+                       if (record->length != 2)
+                               return NULL;
+                       extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
+                       break;
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
+                       if (record->length != 2)
+                               return NULL;
+                       extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
+                       break;
+               case AO_HEX_RECORD_SYMBOL:
+                       break;
+               }
+       }
+       length = bound - base;
+       image = calloc(sizeof(struct ao_hex_image) + length, 1);
+       if (!image)
+               return NULL;
+       image->address = base;
+       image->length = length;
+       memset(image->data, 0xff, length);
+       extended_addr = 0;
+       for (i = 0; i < hex->nrecord; i++) {
+               record = hex->records[i];
+               switch (record->type) {
+               case AO_HEX_RECORD_NORMAL:
+                       addr = extended_addr + record->address;
+                       offset = addr - base;
+                       memcpy(image->data + offset, record->data, record->length);
+                       break;
+               case AO_HEX_RECORD_EOF:
+                       break;
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_4:
+                       extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
+                       break;
+               case AO_HEX_RECORD_EXTENDED_ADDRESS_8:
+                       extended_addr = (record->data[0] << 24) | (record->data[1] << 16);
+                       break;
+               case AO_HEX_RECORD_SYMBOL:
+                       break;
+               }
+       }
+       return image;
+}
+
+void
+ao_hex_image_free(struct ao_hex_image *image)
+{
+       free(image);
+}
+
+int
+ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b)
+{
+       if (a->length != b->length)
+               return 0;
+       if (memcmp(a->data, b->data, a->length) != 0)
+               return 0;
+       return 1;
+}
+
+struct ao_hex_image *
+ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbolsp)
+{
+       FILE                    *file;
+       struct ao_hex_file      *hex_file;
+       struct ao_hex_image     *hex_image;
+
+       file = fopen (filename, "r");
+       if (!file)
+               return NULL;
+       
+       hex_file = ao_hex_file_read(file, filename);
+       fclose(file);
+       if (!hex_file)
+               return NULL;
+       hex_image = ao_hex_image_create(hex_file);
+       if (!hex_image)
+               return NULL;
+
+       if (symbols)
+               *symbols = load_symbols(hex_file, num_symbolsp);
+
+       ao_hex_file_free(hex_file);
+       return hex_image;
+}
+
+#define BYTES_PER_RECORD       32
+
+static struct ao_hex_file *
+ao_hex_file_create(struct ao_hex_image *image, struct ao_sym *symbols, int num_symbols)
+{
+       /* split data into n-byte-sized chunks */
+       uint32_t                data_records = (image->length + BYTES_PER_RECORD-1) / BYTES_PER_RECORD;
+       /* extended address and data for each block, EOF, address and data for each symbol */
+       uint32_t                total_records = data_records * 2 + 1 + num_symbols * 2;
+       uint32_t                offset;
+       uint32_t                address;
+       uint32_t                length;
+       char                    *name;
+       struct ao_hex_file      *hex_file;
+       int                     nrecord = 0;
+       int                     s;
+       struct ao_hex_record    *record;
+
+       hex_file = calloc(sizeof (struct ao_hex_file) + sizeof (struct ao_hex_record *) * total_records, 1);
+       if (!hex_file)
+               return NULL;
+
+       /* Add the data
+        */
+       for (offset = 0; offset < image->length; offset += BYTES_PER_RECORD) {
+               uint32_t                address = image->address + offset;
+               uint32_t                length = image->length - offset;
+
+               if (length > BYTES_PER_RECORD)
+                       length = BYTES_PER_RECORD;
+
+               record = calloc(sizeof (struct ao_hex_record) + 2, 1);
+               record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8;
+               record->address = 0;
+               record->length = 2;
+               record->data[0] = address >> 24;
+               record->data[1] = address >> 16;
+               ao_hex_record_set_checksum(record);
+
+               hex_file->records[nrecord++] = record;
+
+               record = calloc(sizeof (struct ao_hex_record) + length, 1);
+               record->type = AO_HEX_RECORD_NORMAL;
+               record->address = address;
+               record->length = length;
+               memcpy(record->data, image->data + offset, length);
+               ao_hex_record_set_checksum(record);
+
+               hex_file->records[nrecord++] = record;
+       }
+
+       /* Stick an EOF after the data
+        */
+       record = calloc(sizeof (struct ao_hex_record), 1);
+       record->type = AO_HEX_RECORD_EOF;
+       record->address = 0;
+       record->length = 0;
+       record->data[0] = 0;
+       record->data[1] = 0;
+       ao_hex_record_set_checksum(record);
+
+       hex_file->records[nrecord++] = record;
+       
+       /* Add the symbols
+        */
+
+       for (s = 0; s < num_symbols; s++) {
+
+               name = symbols[s].name;
+               address = symbols[s].addr;
+               length = strlen (name);
+
+               record = calloc(sizeof (struct ao_hex_record) + 2, 1);
+               record->type = AO_HEX_RECORD_EXTENDED_ADDRESS_8;
+               record->address = 0;
+               record->length = 2;
+               record->data[0] = address >> 24;
+               record->data[1] = address >> 16;
+               ao_hex_record_set_checksum(record);
+
+               hex_file->records[nrecord++] = record;
+
+               record = calloc(sizeof (struct ao_hex_record) + length, 1);
+               record->type = AO_HEX_RECORD_SYMBOL;
+               record->address = address;
+               record->length = length;
+               memcpy(record->data, name, length);
+               ao_hex_record_set_checksum(record);
+
+               hex_file->records[nrecord++] = record;
+       }
+
+       hex_file->nrecord = nrecord;
+       return hex_file;
+}
+
+static bool
+ao_hex_write_record(FILE *file, struct ao_hex_record *record)
+{
+       int     i;
+
+       fputc(':', file);
+       fprintf(file, "%02x", record->length);
+       fprintf(file, "%04x", record->address);
+       fprintf(file, "%02x", record->type);
+       for (i = 0; i < record->length; i++)
+               fprintf(file, "%02x", record->data[i]);
+       fprintf(file, "%02x", record->checksum);
+       fputc('\n', file);
+       return true;
+}
+
+bool
+ao_hex_save(FILE *file, struct ao_hex_image *image,
+           struct ao_sym *symbols, int num_symbols)
+{
+       struct ao_hex_file      *hex_file;
+       int                     i;
+       bool                    ret = false;
+
+       hex_file = ao_hex_file_create(image, symbols, num_symbols);
+       if (!hex_file)
+               goto create_failed;
+
+       for (i = 0; i < hex_file->nrecord; i++) {
+               if (!ao_hex_write_record(file, hex_file->records[i]))
+                       goto write_failed;
+       }
+       ret = true;
+       
+       if (fflush(file) != 0)
+               ret = false;
+write_failed:
+       ao_hex_file_free(hex_file);
+create_failed:
+       return ret;
+}
diff --git a/ao-tools/lib/ao-hex.h b/ao-tools/lib/ao-hex.h
new file mode 100644 (file)
index 0000000..9849746
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_HEX_H_
+#define _AO_HEX_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#define AO_HEX_RECORD_NORMAL                   0x00
+#define AO_HEX_RECORD_EOF                      0x01
+#define AO_HEX_RECORD_EXTENDED_ADDRESS_4       0x02
+#define AO_HEX_RECORD_EXTENDED_ADDRESS_8       0x04
+#define AO_HEX_RECORD_SYMBOL                   0xfe
+
+/* Intel hex file format data
+ */
+struct ao_hex_record {
+       uint8_t length;
+       uint16_t address;
+       uint8_t type;
+       uint8_t checksum;
+       uint8_t data[0];
+};
+
+struct ao_hex_file {
+       int                     nrecord;
+       struct ao_hex_record    *records[0];
+};
+
+struct ao_hex_image {
+       uint32_t        address;
+       uint32_t        length;
+       uint8_t         data[0];
+};
+
+struct ao_sym {
+       unsigned        addr;
+       unsigned        default_addr;
+       char            *name;
+       bool            required;
+       bool            found;
+};
+
+struct ao_hex_file *
+ao_hex_file_read(FILE *file, char *name);
+
+void
+ao_hex_file_free(struct ao_hex_file *hex);
+
+struct ao_hex_image *
+ao_hex_image_create(struct ao_hex_file *hex);
+
+void
+ao_hex_image_free(struct ao_hex_image *image);
+
+struct ao_hex_image *
+ao_hex_load(char *filename, struct ao_sym **symbols, int *num_symbols);
+
+int
+ao_hex_image_equal(struct ao_hex_image *a, struct ao_hex_image *b);
+
+bool
+ao_hex_save(FILE *file, struct ao_hex_image *image,
+           struct ao_sym *symbols, int num_symbols);
+
+#endif /* _AO_HEX_H_ */
diff --git a/ao-tools/lib/ao-selfload.c b/ao-tools/lib/ao-selfload.c
new file mode 100644 (file)
index 0000000..41e45ad
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <string.h>
+#include "ao-hex.h"
+#include "ao-selfload.h"
+#include "ao-verbose.h"
+
+#define TRACE(...) ao_printf(AO_VERBOSE_SELF, __VA_ARGS__)
+
+static void
+ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256])
+{
+       int                     byte;
+       cc_usb_sync(cc);
+       cc_usb_printf(cc, "R %x\n", address);
+       for (byte = 0; byte < 0x100; byte++) {
+               block[byte] = cc_usb_getchar(cc);
+       }
+       TRACE ("\nread %08x\n", address);
+       for (byte = 0; byte < 0x100; byte++) {
+               TRACE (" %02x", block[byte]);
+               if ((byte & 0xf) == 0xf)
+                       TRACE ("\n");
+       }
+}
+
+static void
+ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256])
+{
+       int                     byte;
+       cc_usb_sync(cc);
+       cc_usb_printf(cc, "W %x\n", address);
+       TRACE ("write %08x\n", address);
+       for (byte = 0; byte < 0x100; byte++) {
+               TRACE (" %02x", block[byte]);
+               if ((byte & 0xf) == 0xf)
+                       TRACE ("\n");
+       }
+       for (byte = 0; byte < 0x100; byte++) {
+               cc_usb_printf(cc, "%c", block[byte]);
+       }
+}
+
+struct ao_hex_image *
+ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length)
+{
+       struct ao_hex_image     *image;
+       int                     pages;
+       int                     page;
+       uint32_t                base = address & ~0xff;
+       uint32_t                bound = (address + length + 0xff) & ~0xff;
+
+       image = calloc(sizeof (struct ao_hex_image) + (bound - base), 1);
+       image->address = base;
+       image->length = bound - base;
+       pages = image->length / 0x100;
+       for (page = 0; page < pages; page++)
+               ao_self_block_read(cc, image->address + page * 0x100, image->data + page * 0x100);
+       return image;
+}
+
+bool
+ao_self_write(struct cc_usb *cc, struct ao_hex_image *image)
+{
+       uint8_t         block[256];
+       uint8_t         check[256];
+       uint32_t        base, bound, length, address;
+       uint32_t        pages;
+       uint32_t        page;
+
+       base = image->address & ~0xff;
+       bound = (image->address + image->length + 0xff) & ~0xff;
+
+       address = base;
+       length = bound - base;
+
+       pages = length / 0x100;
+       printf ("Write %08x %d pages: ", address, length/0x100); fflush(stdout);
+       for (page = 0; page < pages; page++) {
+               uint32_t        start, stop;
+               address = base + page * 0x100;
+
+               if (address < image->address || address + 0x100 > image->address + image->length) {
+                       ao_self_block_read(cc, address, block);
+               }
+               start = address;
+               stop = address + 0x100;
+               if (start < image->address)
+                       start = image->address;
+               if (stop > image->address + image->length)
+                       stop = image->address + image->length;
+               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);
+               if (memcmp(block, check, 0x100) != 0) {
+                       fprintf(stderr, "Block at 0x%08x doesn't match\n", address);
+                       return 0;
+               }
+               putchar('.'); fflush(stdout);
+       }
+       printf("done\n");
+       cc_usb_printf(cc,"a\n");
+       return 1;
+}
+
+/*
+ * Read a 16-bit value from the USB target
+ */
+
+uint16_t
+ao_self_get_uint16(struct cc_usb *cc, uint32_t addr)
+{
+       struct ao_hex_image     *hex = ao_self_read(cc, addr, 2);
+       uint16_t                v;
+       uint8_t                 *data;
+
+       if (!hex)
+               return 0;
+       data = hex->data + addr - hex->address;
+       v = data[0] | (data[1] << 8);
+       free(hex);
+       return v;
+}
+
+uint32_t
+ao_self_get_uint32(struct cc_usb *cc, uint32_t addr)
+{
+       struct ao_hex_image     *hex = ao_self_read(cc, addr, 4);
+       uint32_t                v;
+       uint8_t                 *data;
+
+       if (!hex)
+               return 0;
+       data = hex->data + addr - hex->address;
+       v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+       free(hex);
+       return v;
+}
diff --git a/ao-tools/lib/ao-selfload.h b/ao-tools/lib/ao-selfload.h
new file mode 100644 (file)
index 0000000..a001a40
--- /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; 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_SELFLOAD_H_
+#define _AO_SELFLOAD_H_
+
+#include <stdbool.h>
+#include "ao-hex.h"
+#include "cc-usb.h"
+
+struct ao_hex_image *
+ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length);
+
+bool
+ao_self_write(struct cc_usb *cc, struct ao_hex_image *image);
+
+uint16_t
+ao_self_get_uint16(struct cc_usb *cc, uint32_t addr);
+
+uint32_t
+ao_self_get_uint32(struct cc_usb *cc, uint32_t addr);
+
+#endif /* _AO_SELFLOAD_H_ */
diff --git a/ao-tools/lib/ao-verbose.c b/ao-tools/lib/ao-verbose.c
new file mode 100644 (file)
index 0000000..a1678ed
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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-verbose.h"
+#include <stdio.h>
+
+uint32_t       ao_verbose;
+
+void
+ao_printf(uint32_t verbose, const char *format, ...)
+{
+       va_list args;
+
+       if (!(ao_verbose & verbose))
+               return;
+
+       va_start(args, format);
+       vprintf(format, args);
+       va_end(args);
+}
+
+
diff --git a/ao-tools/lib/ao-verbose.h b/ao-tools/lib/ao-verbose.h
new file mode 100644 (file)
index 0000000..26c2fe4
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_VERBOSE_H_
+#define _AO_VERBOSE_H_
+
+#include <stdint.h>
+#include <stdarg.h>
+
+uint32_t       ao_verbose;
+
+#define AO_VERBOSE_EXE 1
+#define AO_VERBOSE_SELF        2
+
+void
+ao_printf(uint32_t verbose, const char *format, ...);
+
+#endif /* _AO_VERBOSE_H_ */
diff --git a/ao-tools/lib/cc-mega.c b/ao-tools/lib/cc-mega.c
new file mode 100644 (file)
index 0000000..3aa24a6
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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 "cc.h"
+#include <string.h>
+#include <ctype.h>
+
+static const char *
+parse_hex(const char *data, int *result)
+{
+       char    d[12];
+       int     x;
+       int     i;
+
+       while (isspace (*data))
+               data++;
+       for (i = 0; i < sizeof (d) - 1 && isxdigit(*data); i++)
+               d[i] = *data++;
+       d[i] = '\0';
+       if (sscanf(d, "%x", &x) != 1)
+               return NULL;
+       *result = x;
+       return data;
+}
+
+static const char *
+parse_uint16(const char *data, uint16_t *result)
+{
+       int     x;
+       data = parse_hex(data, &x);
+       *result =x;
+       return data;
+}
+
+static const char *
+parse_uint8(const char *data, uint8_t *result)
+{
+       int     x;
+       data = parse_hex(data, &x);
+       *result =x;
+       return data;
+}
+
+static int
+parse_eeprom(const char *input_line, struct ao_log_mega *l) {
+       const char      *line;
+       int     b;
+
+       if (input_line[1] != ' ')
+               return 0;
+       if (!isupper(input_line[0]))
+               return 0;
+
+       l->type = input_line[0];
+       l->is_config = 0;
+       line = input_line + 2;
+
+       line = parse_uint16(line, &l->tick);
+       for (b = 0; b < 28; b++) {
+               if (!line)
+                       return 0;
+               line = parse_uint8(line, &l->u.bytes[b]);
+       }
+       return 1;
+}
+
+#define YUP(t) do {                            \
+               l->u.config_int.kind = (t);     \
+               l->is_config = 1;               \
+               return 1;                       \
+       } while (0);
+
+static int
+parse_config(const char *input_line, struct ao_log_mega *l) {
+       if (sscanf (input_line, "Config version: %d.%d",
+                   &l->u.config_int.data[0],
+                   &l->u.config_int.data[1]))
+               YUP(AO_CONFIG_CONFIG);
+       if (sscanf (input_line, "Main deploy: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_MAIN);
+       if (sscanf (input_line, "Apogee delay: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_APOGEE);
+       if (sscanf (input_line, "Apogee lockout: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_LOCKOUT);
+       if (sscanf (input_line, "Frequency: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_FREQUENCY);
+       if (sscanf (input_line, "Radio enable:  %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_RADIO_ENABLE);
+       if (sscanf (input_line, "Accel cal +1g: %d -1g: %d",
+                   &l->u.config_int.data[0],
+                   &l->u.config_int.data[1]))
+               YUP(AO_CONFIG_ACCEL_CAL);
+       if (sscanf (input_line, "Radio cal: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_RADIO_CAL);
+       if (sscanf (input_line, "Max flight log: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_MAX_LOG);
+       if (sscanf (input_line, "Ignite mode: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_IGNITE_MODE);
+       if (sscanf (input_line, "Pad orientation: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_PAD_ORIENTATION);
+       if (sscanf (input_line, "serial-number %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_SERIAL_NUMBER);
+       if (sscanf (input_line, "log-format %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_LOG_FORMAT);
+       if (sscanf (input_line, "ms5607 reserved: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_MS5607_RESERVED);
+       if (sscanf (input_line, "ms5607 sens: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_MS5607_SENS);
+       if (sscanf (input_line, "ms5607 off: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_MS5607_OFF);
+       if (sscanf (input_line, "ms5607 tcs: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_MS5607_TCS);
+       if (sscanf (input_line, "ms5607 tco: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_MS5607_TCO);
+       if (sscanf (input_line, "ms5607 tref: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_MS5607_TREF);
+       if (sscanf (input_line, "ms5607 tempsens: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_MS5607_TEMPSENS);
+       if (sscanf (input_line, "ms5607 crc: %d",
+                   &l->u.config_int.data[0]))
+               YUP(AO_CONFIG_MS5607_CRC);
+       return 0;
+}
+
+int
+cc_mega_parse(const char *input_line, struct ao_log_mega *l) {
+       return parse_eeprom(input_line, l) || parse_config(input_line, l);
+}
index 9a5be49f9a76d2e9cd2122e951838cf9d5e2eed7..c28aceb895d2385eef28bceb8a0ae1514398a2d3 100644 (file)
@@ -201,6 +201,72 @@ struct ao_telemetry_mega_data {
        /* 32 */
 };
 
+#define AO_TELEMETRY_METRUM_SENSOR     0x0A
+
+struct ao_telemetry_metrum_sensor {
+       uint16_t        serial;         /*  0 */
+       uint16_t        tick;           /*  2 */
+       uint8_t         type;           /*  4 */
+
+       uint8_t         state;          /*  5 flight state */
+       int16_t         accel;          /*  6 Z axis */
+
+       int32_t         pres;           /*  8 Pa * 10 */
+       int16_t         temp;           /* 12 °C * 100 */
+
+       int16_t         acceleration;   /* 14 m/s² * 16 */
+       int16_t         speed;          /* 16 m/s * 16 */
+       int16_t         height;         /* 18 m */
+
+       int16_t         v_batt;         /* 20 battery voltage */
+       int16_t         sense_a;        /* 22 apogee continuity sense */
+       int16_t         sense_m;        /* 24 main continuity sense */
+
+       uint8_t         pad[6];         /* 26 */
+       /* 32 */
+};
+       
+#define AO_TELEMETRY_METRUM_DATA       0x0B
+
+struct ao_telemetry_metrum_data {
+       uint16_t        serial;         /*  0 */
+       uint16_t        tick;           /*  2 */
+       uint8_t         type;           /*  4 */
+
+       int32_t         ground_pres;    /* 8 average pres on pad */
+       int16_t         ground_accel;   /* 12 average accel on pad */
+       int16_t         accel_plus_g;   /* 14 accel calibration at +1g */
+       int16_t         accel_minus_g;  /* 16 accel calibration at -1g */
+
+       uint8_t         pad[14];        /* 18 */
+       /* 32 */
+};
+
+#define AO_TELEMETRY_MINI              0x10
+
+struct ao_telemetry_mini {
+       uint16_t        serial;         /*  0 */
+       uint16_t        tick;           /*  2 */
+       uint8_t         type;           /*  4 */
+
+       uint8_t         state;          /*  5 flight state */
+       int16_t         v_batt;         /*  6 battery voltage */
+       int16_t         sense_a;        /*  8 apogee continuity */
+       int16_t         sense_m;        /* 10 main continuity */
+
+       int32_t         pres;           /* 12 Pa * 10 */
+       int16_t         temp;           /* 16 °C * 100 */
+
+       int16_t         acceleration;   /* 18 m/s² * 16 */
+       int16_t         speed;          /* 20 m/s * 16 */
+       int16_t         height;         /* 22 m */
+
+       int32_t         ground_pres;    /* 24 average pres on pad */
+
+       int32_t         pad28;          /* 28 */
+       /* 32 */
+};
+
 /* #define AO_SEND_ALL_BARO */
 
 #define AO_TELEMETRY_BARO              0x80
@@ -234,6 +300,9 @@ union ao_telemetry_all {
        struct ao_telemetry_companion           companion;
        struct ao_telemetry_mega_sensor         mega_sensor;
        struct ao_telemetry_mega_data           mega_data;
+       struct ao_telemetry_metrum_sensor       metrum_sensor;
+       struct ao_telemetry_metrum_data         metrum_data;
+       struct ao_telemetry_mini                mini;
        struct ao_telemetry_baro                baro;
 };
 
index 625540bbe07e5cb5923a73075c82de48bc1f2cbe..c07f8cd07350f56db32e423d658eae6b315485c1 100644 (file)
@@ -306,7 +306,8 @@ struct ao_log_mega {
                        int16_t         v_pbatt;        /* 6 */
                        int16_t         n_sense;        /* 8 */
                        int16_t         sense[10];      /* 10 */
-               } volt;                                 /* 30 */
+                       uint16_t        pyro;           /* 30 */
+               } volt;                                 /* 32 */
                /* AO_LOG_GPS_TIME */
                struct {
                        int32_t         latitude;       /* 4 */
index a1002879f815b178630face7a11ff8e365440350..55c912b295a003162972f73c588abfa35e89733c 100644 (file)
@@ -157,7 +157,7 @@ ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc)
 }
 
 uint8_t
-ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image)
+ccdbg_execute_hex_image(struct ccdbg *dbg, struct ao_hex_image *image)
 {
        uint16_t pc;
        uint8_t status;
index 1b46870b86d96de483ea59b72be2443eb1ddb39d..44eb952baaa1236400cb3f8c690cc793989941cb 100644 (file)
@@ -238,7 +238,7 @@ ccdbg_flash_lock(struct ccdbg *dbg, uint8_t lock)
 #endif
 
 uint8_t
-ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image)
+ccdbg_flash_hex_image(struct ccdbg *dbg, struct ao_hex_image *image)
 {
        uint16_t flash_prog;
        uint16_t flash_len;
diff --git a/ao-tools/lib/ccdbg-hex.c b/ao-tools/lib/ccdbg-hex.c
deleted file mode 100644 (file)
index 184b4e3..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright © 2008 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 "ccdbg.h"
-#include <stdarg.h>
-#include <ctype.h>
-
-struct hex_input {
-       FILE    *file;
-       int     line;
-       char    *name;
-};
-
-enum hex_read_state {
-       read_marker,
-       read_length,
-       read_address,
-       read_type,
-       read_data,
-       read_checksum,
-       read_newline,
-       read_white,
-       read_done,
-};
-
-
-static void
-ccdbg_hex_error(struct hex_input *input, char *format, ...)
-{
-       va_list ap;
-
-       va_start(ap, format);
-       fprintf(stderr, "Hex error %s:%d: ", input->name, input->line);
-       vfprintf(stderr, format, ap);
-       fprintf(stderr, "\n");
-       va_end(ap);
-}
-
-static void
-ccdbg_hex_free(struct hex_record *record)
-{
-       if (!record) return;
-       free(record);
-}
-
-static struct hex_record *
-ccdbg_hex_alloc(uint8_t length)
-{
-       struct hex_record *record;
-
-       record = calloc(1, sizeof(struct hex_record) + length);
-       record->length = length;
-       return record;
-}
-
-static int
-ishex(char c)
-{
-       return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
-}
-
-static int
-fromhex(char c)
-{
-       if (isdigit(c))
-               return c - '0';
-       if ('a' <= c && c <= 'f')
-               return c - 'a' + 10;
-       if ('A' <= c && c <= 'F')
-               return c - 'A' + 10;
-       abort();
-       return 0;
-}
-
-static uint8_t
-ccdbg_hex_checksum(struct hex_record *record)
-{
-       uint8_t checksum = 0;
-       int i;
-
-       checksum += record->length;
-       checksum += record->address >> 8;
-       checksum += record->address & 0xff;
-       checksum += record->type;
-       for (i = 0; i < record->length; i++)
-               checksum += record->data[i];
-       return -checksum;
-}
-
-static struct hex_record *
-ccdbg_hex_read_record(struct hex_input *input)
-{
-       struct hex_record *record = NULL;
-       enum hex_read_state state = read_marker;
-       char c;
-       int nhexbytes;
-       uint32_t hex;
-       uint32_t ndata;
-       uint8_t checksum;
-
-       while (state != read_done) {
-               c = getc(input->file);
-               if (c == EOF && state != read_white) {
-                       ccdbg_hex_error(input, "Unexpected EOF");
-                       goto bail;
-               }
-               if (c == ' ')
-                       continue;
-               if (c == '\n')
-                       input->line++;
-               switch (state) {
-               case read_marker:
-                       if (c != ':') {
-                               ccdbg_hex_error(input, "Missing ':'");
-                               goto bail;
-                       }
-                       state = read_length;
-                       nhexbytes = 2;
-                       hex = 0;
-                       break;
-               case read_length:
-               case read_address:
-               case read_type:
-               case read_data:
-               case read_checksum:
-                       if (!ishex(c)) {
-                               ccdbg_hex_error(input, "Non-hex char '%c'",
-                                               c);
-                               goto bail;
-                       }
-                       hex = hex << 4 | fromhex(c);
-                       --nhexbytes;
-                       if (nhexbytes != 0)
-                               break;
-
-                       switch (state) {
-                       case read_length:
-                               record = ccdbg_hex_alloc(hex);
-                               if (!record) {
-                                       ccdbg_hex_error(input, "Out of memory");
-                                       goto bail;
-                               }
-                               state = read_address;
-                               nhexbytes = 4;
-                               break;
-                       case read_address:
-                               record->address = hex;
-                               state = read_type;
-                               nhexbytes = 2;
-                               break;
-                       case read_type:
-                               record->type = hex;
-                               state = read_data;
-                               nhexbytes = 2;
-                               ndata = 0;
-                               break;
-                       case read_data:
-                               record->data[ndata] = hex;
-                               ndata++;
-                               nhexbytes = 2;
-                               break;
-                       case read_checksum:
-                               record->checksum = hex;
-                               state = read_newline;
-                               break;
-                       default:
-                               break;
-                       }
-                       if (state == read_data)
-                               if (ndata == record->length) {
-                                       nhexbytes = 2;
-                                       state = read_checksum;
-                               }
-                       hex = 0;
-                       break;
-               case read_newline:
-                       if (c != '\n' && c != '\r') {
-                               ccdbg_hex_error(input, "Missing newline");
-                               goto bail;
-                       }
-                       state = read_white;
-                       break;
-               case read_white:
-                       if (!isspace(c)) {
-                               if (c == '\n')
-                                       input->line--;
-                               if (c != EOF)
-                                       ungetc(c, input->file);
-                               state = read_done;
-                       }
-                       break;
-               case read_done:
-                       break;
-               }
-       }
-       checksum = ccdbg_hex_checksum(record);
-       if (checksum != record->checksum) {
-               ccdbg_hex_error(input, "Invalid checksum (read 0x%02x computed 0x%02x)\n",
-                               record->checksum, checksum);
-               goto bail;
-       }
-       return record;
-
-bail:
-       ccdbg_hex_free(record);
-       return NULL;
-}
-
-void
-ccdbg_hex_file_free(struct hex_file *hex)
-{
-       int     i;
-
-       if (!hex)
-               return;
-       for (i = 0; i < hex->nrecord; i++)
-               ccdbg_hex_free(hex->records[i]);
-       free(hex);
-}
-
-struct hex_file *
-ccdbg_hex_file_read(FILE *file, char *name)
-{
-       struct hex_input input;
-       struct hex_file *hex = NULL, *newhex;
-       struct hex_record *record;
-       int srecord = 1;
-       int done = 0;
-
-       hex = calloc(sizeof (struct hex_file) + sizeof (struct hex_record *), 1);
-       input.name = name;
-       input.line = 1;
-       input.file = file;
-       while (!done) {
-               record = ccdbg_hex_read_record(&input);
-               if (!record)
-                       goto bail;
-               if (hex->nrecord == srecord) {
-                       srecord *= 2;
-                       newhex = realloc(hex,
-                                        sizeof (struct hex_file) +
-                                        srecord * sizeof (struct hex_record *));
-                       if (!newhex)
-                               goto bail;
-                       hex = newhex;
-               }
-               hex->records[hex->nrecord++] = record;
-               if (record->type == HEX_RECORD_EOF)
-                       done = 1;
-       }
-       return hex;
-
-bail:
-       ccdbg_hex_file_free(hex);
-       return NULL;
-}
-
-struct hex_image *
-ccdbg_hex_image_create(struct hex_file *hex)
-{
-       struct hex_image *image;
-       struct hex_record *record;
-       int i;
-       uint32_t addr;
-       uint32_t base, bound;
-       uint32_t offset;
-       uint32_t extended_addr;
-
-       int length;
-
-       base = 0xffffffff;
-       bound = 0x0;
-       extended_addr = 0;
-       for (i = 0; i < hex->nrecord; i++) {
-               uint32_t r_bound;
-               record = hex->records[i];
-               switch (record->type) {
-               case 0:
-                       addr = extended_addr + record->address;
-                       r_bound = addr + record->length;
-                       if (addr < base)
-                               base = addr;
-                       if (r_bound > bound)
-                               bound = r_bound;
-                       break;
-               case 1:
-                       break;
-               case 2:
-                       if (record->length != 2)
-                               return NULL;
-                       extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
-                       break;
-               case 4:
-                       if (record->length != 2)
-                               return NULL;
-                       extended_addr = ((record->data[0] << 8) | record->data[1]) << 16;
-                       break;
-               }
-
-       }
-       length = bound - base;
-       image = calloc(sizeof(struct hex_image) + length, 1);
-       if (!image)
-               return NULL;
-       image->address = base;
-       image->length = length;
-       memset(image->data, 0xff, length);
-       extended_addr = 0;
-       for (i = 0; i < hex->nrecord; i++) {
-               record = hex->records[i];
-               switch (record->type) {
-               case 0:
-                       addr = extended_addr + record->address;
-                       offset = addr - base;
-                       memcpy(image->data + offset, record->data, record->length);
-                       break;
-               case 1:
-                       break;
-               case 2:
-                       extended_addr = ((record->data[0] << 8) | record->data[1]) << 4;
-                       break;
-               case 4:
-                       extended_addr = ((record->data[0] << 8) | record->data[1]) << 16;
-                       break;
-               }
-       }
-       return image;
-}
-
-void
-ccdbg_hex_image_free(struct hex_image *image)
-{
-       free(image);
-}
-
-int
-ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b)
-{
-       if (a->length != b->length)
-               return 0;
-       if (memcmp(a->data, b->data, a->length) != 0)
-               return 0;
-       return 1;
-}
-
-struct hex_image *
-ccdbg_hex_load(char *filename)
-{
-       FILE *file;
-       struct hex_file *hex_file;
-       struct hex_image *hex_image;
-
-       file = fopen (filename, "r");
-       if (!file)
-               return 0;
-       
-       hex_file = ccdbg_hex_file_read(file, filename);
-       fclose(file);
-       if (!hex_file)
-               return 0;
-       hex_image = ccdbg_hex_image_create(hex_file);
-       if (!hex_image)
-               return 0;
-       ccdbg_hex_file_free(hex_file);
-       return hex_image;
-}
index 554ac637c6911491e61005ba76ca7932d8d06686..04059e2eeddacf373bf2bf6437321ef72663acbb 100644 (file)
@@ -117,18 +117,18 @@ ccdbg_write_uint8(struct ccdbg *dbg, uint16_t addr, uint8_t byte)
 }
 
 uint8_t
-ccdbg_write_hex_image(struct ccdbg *dbg, struct hex_image *image, uint16_t offset)
+ccdbg_write_hex_image(struct ccdbg *dbg, struct ao_hex_image *image, uint16_t offset)
 {
        ccdbg_write_memory(dbg, image->address + offset, image->data, image->length);
        return 0;
 }
 
-struct hex_image *
+struct ao_hex_image *
 ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length)
 {
-       struct hex_image *image;
+       struct ao_hex_image *image;
 
-       image = calloc(sizeof(struct hex_image) + length, 1);
+       image = calloc(sizeof(struct ao_hex_image) + length, 1);
        image->address = address;
        image->length = length;
        memset(image->data, 0xff, length);
index 71bed2200478b2f9b56a199f2a8e7a8ee87d523f..6e8e7378ef1a38f3c899e346b7fe851cb6b1e2be 100644 (file)
 #include "ccdbg.h"
 
 uint8_t
-ccdbg_set_rom(struct ccdbg *dbg, struct hex_image *rom)
+ccdbg_set_rom(struct ccdbg *dbg, struct ao_hex_image *rom)
 {
        if (dbg->rom)
-               ccdbg_hex_image_free(dbg->rom);
+               ao_hex_image_free(dbg->rom);
        dbg->rom = rom;
        return 0;
 }
@@ -30,7 +30,7 @@ ccdbg_set_rom(struct ccdbg *dbg, struct hex_image *rom)
 uint8_t
 ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes)
 {
-       struct hex_image *rom = dbg->rom;
+       struct ao_hex_image *rom = dbg->rom;
        if (!rom)
                return 0;
        if (addr < rom->address || rom->address + rom->length < addr + nbytes)
@@ -42,7 +42,7 @@ uint8_t
 ccdbg_rom_replace_xmem(struct ccdbg *dbg,
                       uint16_t addr, uint8_t *bytes, int nbytes)
 {
-       struct hex_image *rom = dbg->rom;
+       struct ao_hex_image *rom = dbg->rom;
        if (!rom)
                return 0;
 
index a27ff5d1c9c664368b3f12a0cf3128389339ca4e..b17f289d59894d0f72d532ed0b331373ceae21ff 100644 (file)
@@ -33,6 +33,7 @@
 #include "ccdbg-debug.h"
 #include "cc-bitbang.h"
 #include "cc-usb.h"
+#include "ao-hex.h"
 
 /* 8051 instructions
  */
 struct ccdbg {
        struct cc_bitbang       *bb;
        struct cc_usb           *usb;
-       struct hex_image        *rom;
+       struct ao_hex_image     *rom;
 };
 
-/* Intel hex file format data
- */
-struct hex_record {
-       uint8_t length;
-       uint16_t address;
-       uint8_t type;
-       uint8_t checksum;
-       uint8_t data[0];
-};
-
-struct hex_file {
-       int                     nrecord;
-       struct hex_record       *records[0];
-};
-
-struct hex_image {
-       uint32_t        address;
-       uint32_t        length;
-       uint8_t         data[0];
-};
 
 #define CC_STATE_ACC   0x1
 #define CC_STATE_PSW   0x2
@@ -139,10 +120,6 @@ struct ccstate {
        uint8_t         sfr[CC_STATE_NSFR];
 };
 
-#define HEX_RECORD_NORMAL              0x00
-#define HEX_RECORD_EOF                 0x01
-#define HEX_RECORD_EXTENDED_ADDRESS    0x02
-
 /* CC1111 debug port commands
  */
 #define CC_CHIP_ERASE          0x14
@@ -234,30 +211,11 @@ uint8_t
 ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc);
 
 uint8_t
-ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image);
+ccdbg_execute_hex_image(struct ccdbg *dbg, struct ao_hex_image *image);
 
 /* ccdbg-flash.c */
 uint8_t
-ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image);
-
-/* ccdbg-hex.c */
-struct hex_file *
-ccdbg_hex_file_read(FILE *file, char *name);
-
-void
-ccdbg_hex_file_free(struct hex_file *hex);
-
-struct hex_image *
-ccdbg_hex_image_create(struct hex_file *hex);
-
-void
-ccdbg_hex_image_free(struct hex_image *image);
-
-struct hex_image *
-ccdbg_hex_load(char *filename);
-
-int
-ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b);
+ccdbg_flash_hex_image(struct ccdbg *dbg, struct ao_hex_image *image);
 
 /* ccdbg-io.c */
 struct ccdbg *
@@ -304,9 +262,9 @@ uint8_t
 ccdbg_write_uint8(struct ccdbg *dbg, uint16_t addr, uint8_t byte);
 
 uint8_t
-ccdbg_write_hex_image(struct ccdbg *dbg, struct hex_image *image, uint16_t offset);
+ccdbg_write_hex_image(struct ccdbg *dbg, struct ao_hex_image *image, uint16_t offset);
 
-struct hex_image *
+struct ao_hex_image *
 ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length);
 
 uint8_t
@@ -317,7 +275,7 @@ ccdbg_write_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes);
 
 /* ccdbg-rom.c */
 uint8_t
-ccdbg_set_rom(struct ccdbg *dbg, struct hex_image *rom);
+ccdbg_set_rom(struct ccdbg *dbg, struct ao_hex_image *rom);
 
 uint8_t
 ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes);
index c838c5b38c48421564bd1f3cafe08d09897caae8..4e8b11ba9abd526410e44eb3a6264969e5657f5a 100755 (executable)
@@ -9,5 +9,4 @@ cd $srcdir
 autoreconf --force -v --install || exit 1
 cd $ORIGDIR || exit $?
 
-PKG_CONFIG_PATH=/opt/cortex/lib/pkgconfig \
-       $srcdir/configure --enable-maintainer-mode "$@"
+$srcdir/configure --enable-maintainer-mode "$@"
index fb095d5b38a92420ad531a47731c29a9ff623996..0b2960ce5fc0dd9a44481d4f21ac062b8d111399 100644 (file)
@@ -18,7 +18,11 @@ dnl
 dnl Process this file with autoconf to create configure.
 
 AC_PREREQ(2.57)
+<<<<<<< HEAD
 AC_INIT([altos], 1.2.1)
+=======
+AC_INIT([altos], 1.3)
+>>>>>>> branch-1.3
 AC_CONFIG_SRCDIR([src/core/ao.h])
 AM_INIT_AUTOMAKE([foreign dist-bzip2])
 AM_MAINTAINER_MODE
@@ -26,12 +30,11 @@ AM_MAINTAINER_MODE
 VERSION_DASH=`echo $VERSION | sed 's/\./-/g'`
 AC_SUBST(VERSION_DASH)
 
-
 dnl ==========================================================================
 dnl Java library versions
 
 ALTOSUILIB_VERSION=1
-ALTOSLIB_VERSION=1
+ALTOSLIB_VERSION=2
 
 AC_SUBST(ALTOSLIB_VERSION)
 AC_DEFINE(ALTOSLIB_VERSION,$ALTOSLIB_VERSION,[Version of the AltosLib package])
@@ -180,34 +183,262 @@ if test "x$GCC" = "xyes"; then
 fi
 AC_SUBST(WARN_CFLAGS)
 
-AC_CHECK_PROG([HAVE_SDCC], [sdcc], yes, no)
+#
+# Configure SDCC
+#
+
+AC_ARG_WITH([sdcc],
+           [AS_HELP_STRING([--with-sdcc],
+                           [Name of SDCC])],
+           [],
+           [with_sdcc=auto])
+
+if test "x$with_sdcc" != "xno"; then       
+       if test "x$with_sdcc" = "xauto"; then
+               with_sdcc="sdcc"
+               AC_CHECK_PROG([HAVE_SDCC],[$with_sdcc], yes, no)
+       else
+               HAVE_SDCC=yes
+       fi
+else
+       HAVE_SDCC=no
+fi
+
 if test "x$HAVE_SDCC" = "xno"; then
-       AC_MSG_WARN([No sdcc found, cc1111 binaries will not be built])
+       AC_MSG_WARN([SDCC not found, cc1111 binaries will not be built])
+else
+       SDCC=$with_sdcc
+fi
+
+AC_SUBST(SDCC)
+AC_SUBST(HAVE_SDCC)
+
+#
+# Configure ARM compiler for STM32L and LPC11U14
+#
+
+AC_ARG_WITH([arm-cc],
+           [AS_HELP_STRING([--with-arm-cc],
+                           [Name of ARM C compiler])],
+           [],
+           [with_arm_cc=auto])
+
+if test "x$with_arm_cc" != "xno"; then     
+       if test "x$with_arm_cc" = "xauto"; then
+               with_arm_cc="arm-none-eabi-gcc"
+               AC_CHECK_PROG([HAVE_ARM_CC],[$with_arm_cc], yes, no)
+       else
+               HAVE_ARM_CC=yes
+       fi
+else
+       HAVE_ARM_CC=no
+fi
+
+if test "x$HAVE_ARM_CC" = "xno"; then
+       AC_MSG_WARN([Arm compiler not found, ARM binaries will not be built])
+else
+       ARM_CC=$with_arm_cc
+fi
+AC_SUBST(HAVE_ARM_CC)
+AC_SUBST(ARM_CC)
+
+if test -d pdclib -a x"$HAVE_ARM_CC" = xyes; then
+       PDCLIB_ROOT='$(TOPDIR)/../pdclib-root'
+       PDCLIB_INCLUDES='-I$(TOPDIR)/../pdclib-root/include'
+       PDCLIB_LIBS_M0='-L$(TOPDIR)/../pdclib-root/lib -lpdclib-cortex-m0'
+       PDCLIB_LIBS_M3='-L$(TOPDIR)/../pdclib-root/lib -lpdclib-cortex-m3'
+       HAVE_PDCLIB=yes
+else
+       PDCLIB_INCLUDES=''
+       PDCLIB_LIBS_M0='-lpdclib-cortex-m0'
+       PDCLIB_LIBS_M3='-lpdclib-cortex-m3'
+       HAVE_PDCLIB=no
+fi
+
+AM_CONDITIONAL(PDCLIB, [test x$HAVE_PDCLIB = xyes])
+
+AC_SUBST(PDCLIB_INCLUDES)
+AC_SUBST(PDCLIB_LIBS_M0)
+AC_SUBST(PDCLIB_LIBS_M3)
+AC_SUBST(PDCLIB_ROOT)
+AC_SUBST(HAVE_PDCLIB)
+
+if test "x$HAVE_ARM_CC" = "xyes"; then
+       save_CC="$CC"
+       save_CFLAGS="$CFLAGS"
+       save_LIBS="$LIBS"
+       CC="$ARM_CC"
+       CFLAGS="-mthumb -mcpu=cortex-m0"
+       LIBS="-ffreestanding -nostdlib"
+       AC_LANG_PUSH([C])
+
+       AC_MSG_CHECKING([if ]$ARM_CC[ supports cortex-m0])
+       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int i;])],
+                         [HAVE_ARM_M0_CC=yes],
+                         [HAVE_ARM_M0_CC=no])
+        AC_MSG_RESULT([$HAVE_ARM_M0_CC])
+
+       CFLAGS="-mthumb -mcpu=cortex-m3"
+       AC_MSG_CHECKING([if ]$ARM_CC[ supports cortex-m3])
+       AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int i;])],
+                         [HAVE_ARM_M3_CC=yes],
+                         [HAVE_ARM_M3_CC=no])
+        AC_MSG_RESULT([$HAVE_ARM_M3_CC])
+
+       if test x$HAVE_PDCLIB != xyes; then
+               AC_CHECK_LIB(pdclib-cortex-m0,memcpy,
+                            [],
+                            [HAVE_ARM_M0_CC=no])
+
+               AC_CHECK_LIB(pdclib-cortex-m3,memcpy,
+                            [],
+                            [HAVE_ARM_M3_CC=no])
+        fi
+
+       AC_LANG_POP([C])
+       LIBS="$save_LIBS"
+       CFLAGS="$save_CFLAGS"
+       CC="$save_CC"
+else
+       HAVE_ARM_M3_CC=no
+       HAVE_ARM_M0_CC=no
+fi
+AC_SUBST(HAVE_ARM_M3_CC)
+AC_SUBST(HAVE_ARM_M0_CC)
+       
+if test "x$HAVE_ARM_M3_CC" = "xno"; then
+       AC_MSG_WARN([No cortex-m3 arm compiler found, STM32L binaries will not be built])
 fi
 
-AC_CHECK_PROG([HAVE_ARM_GCC], [arm-none-eabi-gcc], yes, no)
-if test "x$HAVE_ARM_GCC" = "xno"; then
-       AC_MSG_WARN([No arm compiler found, STM32L and LPC11U14 binaries will not be built])
+if test "x$HAVE_ARM_M0_CC" = "xno"; then
+       AC_MSG_WARN([No cortex-m0 arm compiler found, LPC11U14 binaries will not be built])
 fi
 
+#
+# Configure AVR compiler
+#
+
+AC_ARG_WITH([avr-cc],
+           [AS_HELP_STRING([--with-avr-cc],
+                           [Name of AVR C compiler])],
+           [],
+           [with_avr_cc=auto])
+
+if test "x$with_avr_cc" != "xno"; then     
+       if test "x$with_avr_cc" = "xauto"; then
+               with_avr_cc="avr-gcc"
+               AC_CHECK_PROG([HAVE_AVR_CC],[$with_avr_cc], yes, no)
+       else
+               HAVE_AVR_CC=yes
+       fi
+else
+       HAVE_AVR_CC=no
+fi
+
+AC_ARG_WITH([avr-objcopy],
+           [AS_HELP_STRING([--with-avr-objcopy],
+                           [Name of AVR objcopy])],
+           [],
+           [with_avr_objcopy=auto])
+
+if test "x$with_avr_objcopy" != "xno"; then        
+       if test "x$with_avr_objcopy" = "xauto"; then
+               with_avr_objcopy="avr-objcopy"
+               AC_CHECK_PROG([HAVE_AVR_OBJCOPY],[$with_avr_objcopy], yes, no)
+       else
+               HAVE_AVR_OBJCOPY=yes
+       fi
+else
+       HAVE_AVR_OBJCOPY=no
+fi
+
+if test "x$HAVE_AVR_CC" = "xno" -o "x$HAVE_AVR_OBJCOPY" = "xno"; then
+       AC_MSG_WARN([AVR compiler and objcopy not found, atmel binaries will not be built])
+       HAVE_AVR_CC=no
+else
+       save_CC="$CC"
+       save_CFLAGS="$CFLAGS"
+       save_LIBS="$LIBS"
+
+       CC="$with_avr_cc"
+       CFLAGS="-mmcu=attiny85"
+       AC_LANG_PUSH([C])
+       AC_MSG_CHECKING([if ]$with_avr_cc[ can link programs])
+       AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
+                         [AVR_LINK=yes],
+                         [AVR_LINK=no])
+        AC_MSG_RESULT([$AVR_LINK])
+       AC_LANG_POP([C])
+
+       LIBS="$save_LIBS"
+       CFLAGS="$save_CFLAGS"
+       CC="$save_CC"
+
+       if test "x$AVR_LINK" = xyes; then
+               AVR_CC=$with_avr_cc
+               AVR_OBJCOPY=$with_avr_objcopy
+       else
+               HAVE_AVR_CC=no;
+       fi
+fi
+
+AC_SUBST(AVR_CC)
+AC_SUBST(AVR_OBJCOPY)
+AC_SUBST(HAVE_AVR_CC)
+
 AC_CHECK_PROG([HAVE_NICKLE], [nickle], yes, no)
 if test "x$HAVE_NICKLE" = "xno"; then
        AC_MSG_ERROR([Please install nickle to build AltOs])
 fi
 
-AC_CHECK_LIB(readline, readline)
+AC_ARG_WITH([readline],
+           [AS_HELP_STRING([--with-readline],
+                             [enable readline functionality in ao-dbg @<:@default=auto@:>@])],
+             [],
+             [with_readline=auto])
+                             
+LIBREADLINE_LIBS=
+
+if test x"$with_readline" != "xno"; then
+       AC_CHECK_LIB([readline], [main],
+                      [AC_SUBST([LIBREADLINE], ["-lreadline -lncurses"])
+                      AC_DEFINE([HAVE_LIBREADLINE], [1],
+                         [Define if you have libreadline])],
+                     [if test "x$with_readline" != xauto; then
+                        AC_MSG_ERROR([--with-readline was given, but test for readline failed])
+                      fi],
+                      -lncurses)
+fi
 
 PKG_CHECK_MODULES([LIBUSB], [libusb-1.0])
 
 AC_CHECK_HEADERS(libelf.h libelf/libelf.h, [break])
 AC_CHECK_HEADERS(gelf.h libelf/gelf.h, [break])
 
-PKG_CHECK_MODULES([LIBSTLINK], [stlink], [HAVE_STLINK=yes], [HAVE_STLINK=no])
+AC_ARG_WITH([stlink],
+           [AS_HELP_STRING([--with-stlink],
+                           [Build tools that use the stlink library (default: auto)])],
+           [],
+           [with_stlink=auto])
+
+if test x"$with_stlink" != "xno"; then
+       PKG_CHECK_MODULES([STLINK], [stlink], [HAVE_STLINK=yes], [HAVE_STLINK=no])
+       if test x"$HAVE_STLINK" = "xno" -a x"$with_stlink" != "xauto"; then
+               AC_MSG_ERROR([--with-stlink was given, but stlink was not found])
+       fi
+else
+       HAVE_STLINK=no
+fi
+
+if test x"$HAVE_STLINK" = "xyes"; then
+       AC_DEFINE(HAVE_STLINK,1,[Using STlink library])
+fi
 
-AM_CONDITIONAL([LIBSTLINK], [test x$HAVE_STLINK != xno])
+AM_CONDITIONAL([LIBSTLINK], [test x$HAVE_STLINK == xyes])
 
 AC_OUTPUT([
 Makefile
+src/Makedefs
 altoslib/Makefile
 altosuilib/Makefile
 altosuilib/AltosUIVersion.java
@@ -235,6 +466,9 @@ ao-tools/ao-sky-flash/Makefile
 ao-tools/ao-dumpflash/Makefile
 ao-tools/ao-edit-telem/Makefile
 ao-tools/ao-dump-up/Makefile
+ao-tools/ao-elftohex/Makefile
+ao-tools/ao-usbload/Makefile
+ao-tools/ao-flash/Makefile
 ao-utils/Makefile
 src/Version
 ])
@@ -243,10 +477,16 @@ echo ""
 echo "  Package: ${PACKAGE_NAME} ${PACKAGE_VERSION}"
 echo ""
 echo "  Configuration"
-echo "    STM32L/LPC11U14 support.....: ${HAVE_ARM_GCC}"
+echo "    Arm compiler................: ${ARM_CC}"
+echo "    STM32L support..............: ${HAVE_ARM_M3_CC}"
+echo "    LPC11U14 support............: ${HAVE_ARM_M0_CC}"
+echo "    SDCC........................: ${SDCC}"
 echo "    CC1111 support..............: ${HAVE_SDCC}"
+echo "    AVR compiler................: ${AVR_CC} ${AVR_OBJCOPY}"
+echo "    AVR support.................: ${HAVE_AVR_CC}"
 echo "    Android support.............: ${HAVE_ANDROID_SDK}"
 echo "    STlink support..............: ${HAVE_STLINK}"
+echo "    Local pdclib................: ${HAVE_PDCLIB}"
 echo ""
 echo "  Java paths"
 echo "    freetts.....................: ${FREETTS}"
index 884fdaa71ccd439d23293a92b789befdf1d3b2bd..05f0eec5627eeba39f26b8b8193340ac08e475e0 100644 (file)
@@ -1,7 +1,7 @@
 debian/altos.desktop   usr/share/applications
 debian/altusmetrum.xpm usr/share/pixmaps
-src/*.ihx              usr/share/altos
-src/*.map              usr/share/altos
+src/*/*.ihx            usr/share/altos
+src/*/*.map            usr/share/altos
 themes/background.png          usr/share/altos/themes
 themes/slim/panel.png          usr/share/slim/themes/altusmetrum
 themes/slim/slim.theme         usr/share/slim/themes/altusmetrum
index 0375c23778920508b77094c92e6a4a4a72c13298..f23a841a313241ce0d2c3bc5de1eb04a093d33cf 100644 (file)
@@ -3,8 +3,8 @@ Section: electronics
 Priority: optional
 Maintainer: Bdale Garbee <bdale@gag.com>
 Uploaders: Keith Packard <keithp@keithp.com>
-Build-Depends: debhelper (>= 7), autoconf, automake, gawk, libreadline-dev, libusb-1.0-0-dev, nickle, cc1111, xsltproc, fop, docbook-xml, docbook-xsl, swig, default-jdk, freetts, libtool, libjfreechart-java, libbluetooth-dev, pkg-config, libelf-dev, libbluetooth-dev, libssl-dev, sox
-Standards-Version: 3.9.4
+Build-Depends: debhelper (>= 7), autoconf, automake, gawk, libreadline-dev, libusb-1.0-0-dev, nickle, cc1111, xsltproc, fop, xmlto, docbook-xml, docbook-xsl, swig, default-jdk, freetts, libtool, libjfreechart-java, libbluetooth-dev, pkg-config, libelf-dev, libbluetooth-dev, libssl-dev, gcc-arm-none-eabi
+Standards-Version: 3.9.5
 Homepage: http://altusmetrum.org/AltOS
 Vcs-Git: git://git.gag.com/fw/altos
 Vcs-Browser: http://git.gag.com/?p=fw/altos
index 4e927977fe8a9f55481cd355f669409bf240e569..57c7e7426e9af07f360d9109e26bfefb0f09beac 100755 (executable)
@@ -11,7 +11,7 @@ prebuild:
 configure: configure-stamp
 configure-stamp:
        dh_testdir
-       ./autogen.sh --prefix=/usr
+       PKG_CONFIG_PATH=/opt/stlink/lib/pkgconfig ./autogen.sh --prefix=/usr
        touch configure-stamp
 
 build: build-arch build-indep
index 06346a2d5d5c2358e015bcd66e93d9fefbbefca0..bc8dc2a2f408315267f6a10251ccf6b06c6c110c 100644 (file)
@@ -11,29 +11,58 @@ RELNOTES=\
        release-notes-1.1.html \
        release-notes-1.1.1.html \
        release-notes-1.2.html \
-       release-notes-1.2.1.html
+       release-notes-1.2.1.html \
+       release-notes-1.3.html
+
+PICTURES=\
+       altosui.png \
+       ascent.png \
+       configure-altimeter.png \
+       configure-altosui.png \
+       configure-groundstation.png \
+       configure-pyro.png \
+       descent.png \
+       device-selection.png \
+       easymini-top.jpg \
+       fire-igniter.png \
+       graph-configure.png \
+       graph-map.png \
+       graph.png \
+       graph-stats.png \
+       landed.png \
+       launch-pad.png \
+       load-maps.png \
+       scan-channels.png \
+       site-map.png \
+       table.png \
+       telemega-v1.0-top.jpg \
+       telemetrum-v1.1-thside.jpg \
+       telemini-v1-top.jpg \
+       telemini-v2-top.jpg
+SVG=\
+       easymini-outline.svg \
+       telemega-outline.svg \
+       telemetrum.svg \
+       telemini.svg
 
 RELNOTES_XSL=$(RELNOTES:.html=.xsl)
 HTML=altusmetrum.html altos.html telemetry.html companion.html micropeak.html $(RELNOTES)
 PDF=altusmetrum.pdf altos.pdf telemetry.pdf companion.pdf micropeak.pdf
-DOC=$(HTML) $(PDF)
 HTMLSTYLE=/usr/share/xml/docbook/stylesheet/docbook-xsl/html/docbook.xsl
-FOSTYLE=/usr/share/xml/docbook/stylesheet/docbook-xsl/fo/docbook.xsl
+FOSTYLE=xorg-fo.xsl
 PDFSTYLE=
-IMAGES=telemetrum.svg telemini.svg
+IMAGES=$(PICTURES) $(SVG)
+DOC=$(HTML) $(PDF) $(PICTURES)
 
-.SUFFIXES: .xsl .html .fo .pdf
+.SUFFIXES: .xsl .html .pdf
 
 XSLTFLAGS=--stringparam section.autolabel 1 --xinclude
 
 .xsl.html:
        xsltproc $(XSLTFLAGS) -o $@ $(HTMLSTYLE) $*.xsl
 
-.xsl.fo:
-       xsltproc $(XSLTFLAGS) -o $@ $(FOSTYLE) $*.xsl
-
-.fo.pdf:
-       fop -fo $*.fo -pdf $@
+.xsl.pdf:
+       xmlto -x $(FOSTYLE) --with-fop pdf $*.xsl
 
 all:   $(HTML) $(PDF)
 
@@ -48,13 +77,15 @@ publish:    $(DOC)
         git push)
 
 clean:
-       rm -f $(HTML) $(PDF) *.fo
+       rm -f $(HTML) $(PDF)
 
 distclean:
-       rm -f $(HTML) $(PDF) *.fo
+       rm -f $(HTML) $(PDF)
 
 altusmetrum.html: $(RELNOTES_XSL) $(IMAGES)
-altusmetrum.fo: $(RELNOTES_XSL) $(IMAGES)
+altusmetrum.pdf: $(RELNOTES_XSL) $(IMAGES)
+
+$(PDF): $(FOSTYLE)
 
 indent:                altusmetrum.xsl
        xmlindent -i 2 < altusmetrum.xsl > altusmetrum.new
index 5af94725603705ccc429beac72dadf272a40fe88..5b9e12e8fa4b84d63f24558d9f54d9113e6e98b8 100644 (file)
            will fail to compile.
            <itemizedlist>
              <listitem>
+<para>
                AO_EXTI_MODE_PULL_UP. Apply a pull-up to the pin; a
                disconnected pin will read as 1.
+</para>
              </listitem>
              <listitem>
+<para>
                AO_EXTI_MODE_PULL_DOWN. Apply a pull-down to the pin;
                a disconnected pin will read as 0.
+</para>
              </listitem>
              <listitem>
+<para>
                0. Don't apply either a pull-up or pull-down. A
                disconnected pin will read an undetermined value.
+</para>
              </listitem>
            </itemizedlist>
          </para>
        variable with one of the following values:
        <variablelist>
          <varlistentry>
-           <title>ao_cmd_success</title>
+           <term>ao_cmd_success</term>
            <listitem>
              <para>
                The command was parsed successfully. There is no
            </listitem>
          </varlistentry>
          <varlistentry>
-           <title>ao_cmd_lex_error</title>
+           <term>ao_cmd_lex_error</term>
            <listitem>
              <para>
                A token in the line was invalid, such as a number
            </listitem>
          </varlistentry>
          <varlistentry>
-           <title>ao_syntax_error</title>
+           <term>ao_syntax_error</term>
            <listitem>
              <para>
                The command line is invalid for some reason other
   </chapter>
   <chapter>
     <title>CC1111 Radio peripheral</title>
-    <para>
-      The CC1111 radio transceiver sends and receives digital packets
-      with forward error correction and detection. The AltOS driver is
-      fairly specific to the needs of the TeleMetrum and TeleDongle
-      devices, using it for other tasks may require customization of
-      the driver itself. There are three basic modes of operation:
-      <orderedlist>
-       <listitem>
-         <para>
-           Telemetry mode. In this mode, TeleMetrum transmits telemetry
-           frames at a fixed rate. The frames are of fixed size. This
-           is strictly a one-way communication from TeleMetrum to
-           TeleDongle.
-         </para>
-       </listitem>
-       <listitem>
-         <para>
-           Packet mode. In this mode, the radio is used to create a
-           reliable duplex byte stream between TeleDongle and
-           TeleMetrum. This is an asymmetrical protocol with
-           TeleMetrum only transmitting in response to a packet sent
-           from TeleDongle. Thus getting data from TeleMetrum to
-           TeleDongle requires polling. The polling rate is adaptive,
-           when no data has been received for a while, the rate slows
-           down. The packets are checked at both ends and invalid
-           data are ignored.
-         </para>
-         <para>
-           On the TeleMetrum side, the packet link is hooked into the
-           stdio mechanism, providing an alternate data path for the
-           command processor. It is enabled when the unit boots up in
-           'idle' mode.
-         </para>
-         <para>
-           On the TeleDongle side, the packet link is enabled with a
-           command; data from the stdio package is forwarded over the
-           packet link providing a connection from the USB command
-           stream to the remote TeleMetrum device.
-         </para>
-       </listitem>
-       <listitem>
-         <para>
-           Radio Direction Finding mode. In this mode, TeleMetrum
-           constructs a special packet that sounds like an audio tone
-           when received by a conventional narrow-band FM
-           receiver. This is designed to provide a beacon to track
-           the device when other location mechanisms fail.
-         </para>
-       </listitem>
-      </orderedlist>
-    </para>
+    <section>
+      <title>Radio Introduction</title>
+      <para>
+       The CC1111 radio transceiver sends and receives digital packets
+       with forward error correction and detection. The AltOS driver is
+       fairly specific to the needs of the TeleMetrum and TeleDongle
+       devices, using it for other tasks may require customization of
+       the driver itself. There are three basic modes of operation:
+       <orderedlist>
+         <listitem>
+           <para>
+             Telemetry mode. In this mode, TeleMetrum transmits telemetry
+             frames at a fixed rate. The frames are of fixed size. This
+             is strictly a one-way communication from TeleMetrum to
+             TeleDongle.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             Packet mode. In this mode, the radio is used to create a
+             reliable duplex byte stream between TeleDongle and
+             TeleMetrum. This is an asymmetrical protocol with
+             TeleMetrum only transmitting in response to a packet sent
+             from TeleDongle. Thus getting data from TeleMetrum to
+             TeleDongle requires polling. The polling rate is adaptive,
+             when no data has been received for a while, the rate slows
+             down. The packets are checked at both ends and invalid
+             data are ignored.
+           </para>
+           <para>
+             On the TeleMetrum side, the packet link is hooked into the
+             stdio mechanism, providing an alternate data path for the
+             command processor. It is enabled when the unit boots up in
+             'idle' mode.
+           </para>
+           <para>
+             On the TeleDongle side, the packet link is enabled with a
+             command; data from the stdio package is forwarded over the
+             packet link providing a connection from the USB command
+             stream to the remote TeleMetrum device.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             Radio Direction Finding mode. In this mode, TeleMetrum
+             constructs a special packet that sounds like an audio tone
+             when received by a conventional narrow-band FM
+             receiver. This is designed to provide a beacon to track
+             the device when other location mechanisms fail.
+           </para>
+         </listitem>
+       </orderedlist>
+      </para>
+    </section>
     <section>
       <title>ao_radio_set_telemetry</title>
        <programlisting>
          the radio operation.
        </para>
     </section>
-    <para>
-      In telemetry mode, you can send or receive a telemetry
-      packet. The data from receiving a packet also includes the RSSI
-      and status values supplied by the receiver. These are added
-      after the telemetry data.
-    </para>
     <section>
-      <title>ao_radio_send</title>
+      <title>Radio Telemetry</title>
+      <para>
+       In telemetry mode, you can send or receive a telemetry
+       packet. The data from receiving a packet also includes the RSSI
+       and status values supplied by the receiver. These are added
+       after the telemetry data.
+      </para>
+      <section>
+       <title>ao_radio_send</title>
        <programlisting>
          void
          ao_radio_send(__xdata struct ao_telemetry *telemetry);
          sending, and ao_radio_put() afterwards, to correctly
          serialize access to the radio device.
        </para>
-    </section>
-    <section>
-      <title>ao_radio_recv</title>
+      </section>
+      <section>
+       <title>ao_radio_recv</title>
        <programlisting>
          void
          ao_radio_recv(__xdata struct ao_radio_recv *radio);
          received, or zero if the operation was aborted (from some
          other task calling ao_radio_abort()).
        </para>
+      </section>
     </section>
-    <para>
-      In radio direction finding mode, there's just one function to
-      use
-    </para>
     <section>
-      <title>ao_radio_rdf</title>
+      <title>Radio Direction Finding</title>
+      <para>
+       In radio direction finding mode, there's just one function to
+       use
+      </para>
+      <section>
+       <title>ao_radio_rdf</title>
        <programlisting>
          void
          ao_radio_rdf(int ms);
          This sends an RDF packet lasting for the specified amount
          of time. The maximum length is 1020 ms.
        </para>
+      </section>
     </section>
-    <para>
-      Packet mode is asymmetrical and is configured at compile time
-      for either master or slave mode (but not both). The basic I/O
-      functions look the same at both ends, but the internals are
-      different, along with the initialization steps.
-    </para>
     <section>
-      <title>ao_packet_putchar</title>
+      <title>Radio Packet Mode</title>
+      <para>
+       Packet mode is asymmetrical and is configured at compile time
+       for either master or slave mode (but not both). The basic I/O
+       functions look the same at both ends, but the internals are
+       different, along with the initialization steps.
+      </para>
+      <section>
+       <title>ao_packet_putchar</title>
        <programlisting>
          void
          ao_packet_putchar(char c);
          slave side, any pending data will be sent the next time
          the master polls for data.
        </para>
-    </section>
-    <section>
-      <title>ao_packet_pollchar</title>
+      </section>
+      <section>
+       <title>ao_packet_pollchar</title>
        <programlisting>
          char
          ao_packet_pollchar(void);
          otherwise returns AO_READ_AGAIN. On the master side, if
          this empties the buffer, it triggers a poll for more data.
        </para>
-    </section>
-    <section>
-      <title>ao_packet_slave_start</title>
+      </section>
+      <section>
+       <title>ao_packet_slave_start</title>
        <programlisting>
          void
          ao_packet_slave_start(void);
          This is available only on the slave side and starts a task
          to listen for packet data.
        </para>
-    </section>
-    <section>
-      <title>ao_packet_slave_stop</title>
+      </section>
+      <section>
+       <title>ao_packet_slave_stop</title>
        <programlisting>
          void
          ao_packet_slave_stop(void);
        <para>
          Disables the packet slave task, stopping the radio receiver.
        </para>
-    </section>
-    <section>
-      <title>ao_packet_slave_init</title>
+      </section>
+      <section>
+       <title>ao_packet_slave_init</title>
        <programlisting>
          void
          ao_packet_slave_init(void);
          that when packet slave mode is enabled, characters will
          get send and received through the stdio functions.
        </para>
-    </section>
-    <section>
-      <title>ao_packet_master_init</title>
+      </section>
+      <section>
+       <title>ao_packet_master_init</title>
        <programlisting>
          void
          ao_packet_master_init(void);
        <para>
          Adds the 'p' packet forward command to start packet mode.
        </para>
+      </section>
     </section>
   </chapter>
 </book>
diff --git a/doc/altosui.png b/doc/altosui.png
new file mode 100644 (file)
index 0000000..3dd28de
Binary files /dev/null and b/doc/altosui.png differ
index dfd72ab46f99f8fd425ece356f0fe149b01771b5..c71e08a7dc2ddec4530fd9dc7909019675bda403 100644 (file)
@@ -1,9 +1,9 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
 <book>
   <title>The Altus Metrum System</title>
-  <subtitle>An Owner's Manual for TeleMetrum, TeleMini, TeleDongle and TeleBT Devices</subtitle>
+  <subtitle>An Owner's Manual for Altus Metrum Rocketry Electronics</subtitle>
   <bookinfo>
     <author>
       <firstname>Bdale</firstname>
       </para>
     </legalnotice>
     <revhistory>
+      <revision>
+       <revnumber>1.3</revnumber>
+       <date>12 November 2013</date>
+       <revremark>
+         Updated for software version 1.3. Version 1.3 adds support
+         for TeleMega, TeleMetrum v2.0, TeleMini v2.0 and EasyMini
+         and fixes bugs in AltosUI and the AltOS firmware.
+       </revremark>
+      </revision>
       <revision>
        <revnumber>1.2.1</revnumber>
        <date>21 May 2013</date>
       </revision>
     </revhistory>
   </bookinfo>
-  <acknowledgements>
+  <dedication>
+    <title>Acknowledgments</title>
     <para>
-      Thanks to Bob Finch, W9YA, NAR 12965, TRA 12350 for writing "The
+      Thanks to Bob Finch, W9YA, NAR 12965, TRA 12350 for writing The
       Mere-Mortals Quick Start/Usage Guide to the Altus Metrum Starter
-      Kit" which formed the basis of the original Getting Started chapter 
+      Kit which formed the basis of the original Getting Started chapter 
       in this manual.  Bob was one of our first customers for a production
       TeleMetrum, and his continued enthusiasm and contributions
       are immensely gratifying and highly appreciated!
@@ -121,7 +131,7 @@ Keith Packard, KD7SQG
 NAR #88757, TRA #12200
       </literallayout>
     </para>
-  </acknowledgements>
+  </dedication>
   <chapter>
     <title>Introduction and Overview</title>
     <para>
@@ -135,14 +145,28 @@ NAR #88757, TRA #12200
     <para>
       The first device created for our community was TeleMetrum, a dual
       deploy altimeter with fully integrated GPS and radio telemetry
-      as standard features, and a "companion interface" that will
-      support optional capabilities in the future.
+      as standard features, and a “companion interface” that will
+      support optional capabilities in the future. The latest version
+      of TeleMetrum, v2.0, has all of the same features but with
+      improved sensors and radio to offer increased performance.
     </para>
     <para>
       Our second device was TeleMini, a dual deploy altimeter with
-      radio telemetry and radio direction finding. This device is only
-      13mm by 38mm (½ inch by 1½ inches) and can fit easily in an 18mm 
-      air-frame.
+      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.
+    </para>
+    <para>
+      TeleMega is our most sophisticated device, including six pyro
+      channels (four of which are fully programmable), integrated GPS,
+      integrated gyroscopes for staging/air-start inhibit and high
+      performance telemetry.
+    </para>
+    <para>
+      EasyMini is a dual-deploy altimeter with logging and built-in
+      USB data download.
     </para>
     <para>
       TeleDongle was our first ground station, providing a USB to RF
@@ -156,8 +180,8 @@ NAR #88757, TRA #12200
     <para>
       For a slightly more portable ground station experience that also
       provides direct rocket recovery support, TeleBT offers flight
-      monitoring and data logging using a Bluetooth connection between
-      the receiver and an Android device that has the Altos Droid
+      monitoring and data logging using a  Bluetooth™ connection between
+      the receiver and an Android device that has the AltosDroid
       application installed from the Google Play store.
     </para>
     <para>
@@ -170,61 +194,77 @@ NAR #88757, TRA #12200
     <title>Getting Started</title>
     <para>
       The first thing to do after you check the inventory of parts in your
-      "starter kit" is to charge the battery.
+      “starter kit” is to charge the battery.
     </para>
     <para>
-      The TeleMetrum battery can be charged by plugging it into the
-      corresponding socket of the TeleMetrum and then using the USB A to
-      mini B
-      cable to plug the TeleMetrum into your computer's USB socket. The
-      TeleMetrum circuitry will charge the battery whenever it is plugged
-      in, because the TeleMetrum's on-off switch does NOT control the
+      For TeleMetrum and TeleMega, the battery can be charged by plugging it into the
+      corresponding socket of the device and then using the USB
+      cable to plug the flight computer into your computer's USB socket. The
+      on-board circuitry will charge the battery whenever it is plugged
+      in, because the on-off switch does NOT control the
       charging circuitry.
     </para>
     <para>
-      When the GPS chip is initially searching for
-      satellites, TeleMetrum will consume more current than it can pull
-      from the USB port, so the battery must be attached in order to get
-      satellite lock.  Once GPS is locked, the current consumption goes back
-      down enough to enable charging while
-      running. So it's a good idea to fully charge the battery as your
-      first item of business so there is no issue getting and maintaining
-      satellite lock.  The yellow charge indicator led will go out when the
-      battery is nearly full and the charger goes to trickle charge. It
-      can take several hours to fully recharge a deeply discharged battery.
+      On TeleMetrum v1 boards, when the GPS chip is initially
+      searching for satellites, TeleMetrum will consume more current
+      than it pulls from the USB port, so the battery must be
+      attached in order to get satellite lock.  Once GPS is locked,
+      the current consumption goes back down enough to enable charging
+      while running. So it's a good idea to fully charge the battery
+      as your first item of business so there is no issue getting and
+      maintaining satellite lock.  The yellow charge indicator led
+      will go out when the battery is nearly full and the charger goes
+      to trickle charge. It can take several hours to fully recharge a
+      deeply discharged battery.
+    </para>
+    <para>
+      TeleMetrum v2.0 and TeleMega use a higher power battery charger,
+      allowing them to charge the battery while running the board at
+      maximum power. When the battery is charging, or when the board
+      is consuming a lot of power, the red LED will be lit. When the
+      battery is fully charged, the green LED will be lit. When the
+      battery is damaged or missing, both LEDs will be lit, which
+      appears yellow.
+    </para>
+    <para>
+      The Lithium Polymer TeleMini and EasyMini battery can be charged by
+      disconnecting it from the board and plugging it into a
+      standalone battery charger such as the LipoCharger product
+      included in TeleMini Starter Kits, and connecting that via a USB
+      cable to a laptop or other USB power source.
     </para>
     <para>
-      The TeleMini battery can be charged by disconnecting it from the
-      TeleMini board and plugging it into a standalone battery charger 
-      such as the LipoCharger product included in TeleMini Starter Kits, 
-      and connecting that via a USB cable to a laptop or other USB
-      power source.  
+      You can also choose to use another battery with TeleMini v2.0
+      and EasyMini, anything supplying between 4 and 12 volts should
+      work fine (like a standard 9V battery), but if you are planning
+      to fire pyro charges, ground testing is required to verify that
+      the battery supplies enough current to fire your chosen e-matches.
     </para>
     <para>
       The other active device in the starter kit is the TeleDongle USB to
       RF interface.  If you plug it in to your Mac or Linux computer it should
-      "just work", showing up as a serial port device.  Windows systems need
+      “just work”, showing up as a serial port device.  Windows systems need
       driver information that is part of the AltOS download to know that the
       existing USB modem driver will work.  We therefore recommend installing
       our software before plugging in TeleDongle if you are using a Windows
-      computer.  If you are using Linux and are having problems, try moving 
-      to a fresher kernel (2.6.33 or newer), as the USB serial driver had 
-      ugly bugs in some earlier versions.
+      computer.  If you are using an older version of Linux and are having 
+      problems, try moving to a fresher kernel (2.6.33 or newer). 
     </para>
     <para>
-      Next you should obtain and install the AltOS software.  These include
-      the AltosUI ground station program, current firmware images for
-      TeleMetrum, TeleMini and TeleDongle, and a number of standalone 
-      utilities that are rarely needed.  Pre-built binary packages are 
-      available for Linux, Microsoft Windows, and recent MacOSX versions.  
-      Full source code and build instructions are also available.
-      The latest version may always be downloaded from
+      Next you should obtain and install the AltOS software.  The AltOS
+      distribution includes the AltosUI ground station program, current 
+      firmware
+      images for all of the hardware, and a number of standalone
+      utilities that are rarely needed.  Pre-built binary packages are
+      available for Linux, Microsoft Windows, and recent MacOSX
+      versions.  Full source code and build instructions are also
+      available.  The latest version may always be downloaded from
       <ulink url="http://altusmetrum.org/AltOS"/>.
     </para>
     <para>
-      If you're using a TeleBT instead of the TeleDongle, you'll want
-      to go install the Altos Droid application from the Google Play
-      store. You don't need a data plan to use Altos Droid, but
+      If you're using a TeleBT instead of the TeleDongle, you'll want to 
+      install the AltosDroid application from the Google Play store on an 
+      Android device. You don't need a data plan to use AltosDroid, but 
       without network access, the Map view will be less useful as it
       won't contain any map data. You can also use TeleBT connected
       over USB with your laptop computer; it acts exactly like a
@@ -253,22 +293,22 @@ NAR #88757, TRA #12200
       strapping them down, for example.
     </para>
     <para>
-      The barometric sensors used on both TeleMetrum and TeleMini are 
-      sensitive to sunlight.  In normal TeleMetrum mounting situations, it 
+      The barometric sensors used on all of our flight computers are 
+      sensitive to sunlight.  In normal mounting situations, the baro sensor
       and all of the other surface mount components
-      are "down" towards whatever the underlying mounting surface is, so
-      this is not normally a problem.  Please consider this, though, when
-      designing an installation, for example, in an air-frame with a
-      see-through plastic payload bay.  It is particularly important to
-      consider this with TeleMini, both because the baro sensor is on the
-      "top" of the board, and because many model rockets with payload bays
+      are “down” towards whatever the underlying mounting surface is, so
+      this is not normally a problem.  Please consider this when designing an 
+      installation in an air-frame with a see-through plastic payload bay.  It
+      is particularly important to
+      consider this with TeleMini v1.0, both because the baro sensor is on the
+      “top” of the board, and because many model rockets with payload bays
       use clear plastic for the payload bay!  Replacing these with an opaque
       cardboard tube, painting them, or wrapping them with a layer of masking
       tape are all reasonable approaches to keep the sensor out of direct
       sunlight.
     </para>
     <para>
-      The barometric sensor sampling port must be able to "breathe",
+      The barometric sensor sampling port must be able to “breathe”,
       both by not being covered by foam or tape or other materials that might
       directly block the hole on the top of the sensor, and also by having a
       suitable static vent to outside air.
@@ -280,81 +320,492 @@ NAR #88757, TRA #12200
     </para>
   </chapter>
   <chapter>
-    <title>Hardware Overview</title>
-    <para>
-      TeleMetrum is a 1 inch by 2.75 inch circuit board.  It was designed to
-      fit inside coupler for 29mm air-frame tubing, but using it in a tube that
-      small in diameter may require some creativity in mounting and wiring
-      to succeed!  The presence of an accelerometer means TeleMetrum should
-      be aligned along the flight axis of the airframe, and by default the 1/4
-      wave UHF wire antenna should be on the nose-cone end of the board.  The
-      antenna wire is about 7 inches long, and wiring for a power switch and
-      the e-matches for apogee and main ejection charges depart from the
-      fin can end of the board, meaning an ideal "simple" avionics
-      bay for TeleMetrum should have at least 10 inches of interior length.
-    </para>
-    <para>
-      TeleMini is a 0.5 inch by 1.5 inch circuit board.   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 1/4
-      wave UHF wire antenna attached to the center of one end of
-      the board is about 7 inches long, and wiring for a power switch and
-      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.
-    </para>
-    <para>
-      A typical TeleMetrum or TeleMini installation involves attaching 
-      only a suitable Lithium Polymer battery, a single pole switch for 
-      power on/off, and two pairs of wires connecting e-matches for the 
-      apogee and main ejection charges.  All Altus Metrum products are 
-      designed for use with single-cell batteries with 3.7 volts nominal.
-    </para>
-    <para>
-      The battery connectors are a standard 2-pin JST connector and
-      match batteries sold by Spark Fun. These batteries are
-      single-cell Lithium Polymer batteries that nominally provide 3.7
-      volts.  Other vendors sell similar batteries for RC aircraft
-      using mating connectors, however the polarity for those is
-      generally reversed from the batteries used by Altus Metrum
-      products. In particular, the Tenergy batteries supplied for use
-      in Featherweight flight computers are not compatible with Altus
-      Metrum flight computers or battery chargers. <emphasis>Check
-      polarity and voltage before connecting any battery not purchased
-      from Altus Metrum or Spark Fun.</emphasis>
-    </para>
-    <para>
-      By default, we use the unregulated output of the Li-Po battery directly
-      to fire ejection charges.  This works marvelously with standard
-      low-current e-matches like the J-Tek from MJG Technologies, and with
-      Quest Q2G2 igniters.  However, if you want or need to use a separate 
-      pyro battery, check out the "External Pyro Battery" section in this 
-      manual for instructions on how to wire that up. The altimeters are 
-      designed to work with an external pyro battery of no more than 15 volts.
-    </para>
-    <para>
-      Ejection charges are wired directly to the screw terminal block
-      at the aft end of the altimeter.  You'll need a very small straight 
-      blade screwdriver for these screws, such as you might find in a 
-      jeweler's screwdriver set.
-    </para>
-    <para>
-      TeleMetrum also uses the screw terminal block for the power
-      switch leads. On TeleMini, the power switch leads are soldered
-      directly to the board and can be connected directly to a switch.
-    </para>
-    <para>
-      For most air-frames, the integrated antennas are more than
-      adequate.   However, if you are installing in a carbon-fiber or
-      metal electronics bay which is opaque to RF signals, you may need to
-      use off-board external antennas instead.  In this case, you can
-      order an altimeter with an SMA connector for the UHF antenna
-      connection, and, on TeleMetrum, you can unplug the integrated GPS
-      antenna and select an appropriate off-board GPS antenna with
-      cable terminating in a U.FL connector.
-    </para>
+    <title>Altus Metrum Hardware</title>
+    <section>
+      <title>Overview</title>
+      <para>
+       Here's the full set of Altus Metrum products, both in
+       production and retired.
+      </para>
+      <table frame='all'>
+       <title>Altus Metrum Electronics</title>
+       <?dbfo keep-together="always"?>
+       <tgroup cols='8' align='center' colsep='1' rowsep='1'>
+         <colspec align='center' colwidth='*' colname='Device'/>
+         <colspec align='center' colwidth='*' colname='Barometer'/>
+         <colspec align='center' colwidth='*' colname='Z-axis accelerometer'/>
+         <colspec align='center' colwidth='*' colname='GPS'/>
+         <colspec align='center' colwidth='*' colname='3D sensors'/>
+         <colspec align='center' colwidth='*' colname='Storage'/>
+         <colspec align='center' colwidth='*' colname='RF'/>
+         <colspec align='center' colwidth='*' colname='Battery'/>
+         <thead>
+           <row>
+             <entry align='center'>Device</entry>
+             <entry align='center'>Barometer</entry>
+             <entry align='center'>Z-axis accelerometer</entry>
+             <entry align='center'>GPS</entry>
+             <entry align='center'>3D sensors</entry>
+             <entry align='center'>Storage</entry>
+             <entry align='center'>RF Output</entry>
+             <entry align='center'>Battery</entry>
+           </row>
+         </thead>
+         <tbody>
+           <row>
+             <entry>TeleMetrum v1.0</entry>
+             <entry><para>MP3H6115 10km (33k')</para></entry>
+             <entry><para>MMA2202 50g</para></entry>
+             <entry>SkyTraq</entry>
+             <entry>-</entry>
+             <entry>1MB</entry>
+             <entry>10mW</entry>
+             <entry>3.7V</entry>
+           </row>
+           <row>
+             <entry>TeleMetrum v1.1</entry>
+             <entry><para>MP3H6115 10km (33k')</para></entry>
+             <entry><para>MMA2202 50g</para></entry>
+             <entry>SkyTraq</entry>
+             <entry>-</entry>
+             <entry>2MB</entry>
+             <entry>10mW</entry>
+             <entry>3.7V</entry>
+           </row>
+           <row>
+             <entry>TeleMetrum v1.2</entry>
+             <entry><para>MP3H6115 10km (33k')</para></entry>
+             <entry><para>ADXL78 70g</para></entry>
+             <entry>SkyTraq</entry>
+             <entry>-</entry>
+             <entry>2MB</entry>
+             <entry>10mW</entry>
+             <entry>3.7V</entry>
+           </row>
+           <row>
+             <entry>TeleMetrum v2.0</entry>
+             <entry><para>MS5607 30km (100k')</para></entry>
+             <entry><para>MMA6555 102g</para></entry>
+             <entry>uBlox Max-7Q</entry>
+             <entry>-</entry>
+             <entry>8MB</entry>
+             <entry>40mW</entry>
+             <entry>3.7V</entry>
+           </row>
+           <row>
+             <entry><para>TeleMini <?linebreak?>v1.0</para></entry>
+             <entry><para>MP3H6115 10km (33k')</para></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>5kB</entry>
+             <entry>10mW</entry>
+             <entry>3.7V</entry>
+           </row>
+           <row>
+             <entry>TeleMini <?linebreak?>v2.0</entry>
+             <entry><para>MS5607 30km (100k')</para></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>1MB</entry>
+             <entry>10mW</entry>
+             <entry>3.7-12V</entry>
+           </row>
+           <row>
+             <entry>EasyMini <?linebreak?>v1.0</entry>
+             <entry><para>MS5607 30km (100k')</para></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>1MB</entry>
+             <entry>-</entry>
+             <entry>3.7-12V</entry>
+           </row>
+           <row>
+             <entry>TeleMega <?linebreak?>v1.0</entry>
+             <entry><para>MS5607 30km (100k')</para></entry>
+             <entry><para>MMA6555 102g</para></entry>
+             <entry>uBlox Max-7Q</entry>
+             <entry><para>MPU6000 HMC5883</para></entry>
+             <entry>8MB</entry>
+             <entry>40mW</entry>
+             <entry>3.7V</entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+      <table frame='all'>
+       <title>Altus Metrum Boards</title>
+       <?dbfo keep-together="always"?>
+       <tgroup cols='6' align='center' colsep='1' rowsep='1'>
+         <colspec align='center' colwidth='*' colname='Device'/>
+         <colspec align='center' colwidth='*' colname='Connectors'/>
+         <colspec align='center' colwidth='*' colname='Screw Terminals'/>
+         <colspec align='center' colwidth='*' colname='Width'/>
+         <colspec align='center' colwidth='*' colname='Length'/>
+         <colspec align='center' colwidth='*' colname='Tube Size'/>
+         <thead>
+           <row>
+             <entry align='center'>Device</entry>
+             <entry align='center'>Connectors</entry>
+             <entry align='center'>Screw Terminals</entry>
+             <entry align='center'>Width</entry>
+             <entry align='center'>Length</entry>
+             <entry align='center'>Tube Size</entry>
+           </row>
+         </thead>
+         <tbody>
+           <row>
+             <entry>TeleMetrum</entry>
+             <entry><para>
+               Antenna<?linebreak?>
+               Debug<?linebreak?>
+               Companion<?linebreak?>
+               USB<?linebreak?>
+               Battery
+             </para></entry>
+             <entry><para>Apogee pyro <?linebreak?>Main pyro <?linebreak?>Switch</para></entry>
+             <entry>1 inch (2.54cm)</entry>
+             <entry>2 ¾ inch (6.99cm)</entry>
+             <entry>29mm coupler</entry>
+           </row>
+           <row>
+             <entry><para>TeleMini <?linebreak?>v1.0</para></entry>
+             <entry><para>
+               Antenna<?linebreak?>
+               Debug<?linebreak?>
+               Battery
+             </para></entry>
+             <entry><para>
+               Apogee pyro <?linebreak?>
+               Main pyro
+             </para></entry>
+             <entry>½ inch (1.27cm)</entry>
+             <entry>1½ inch (3.81cm)</entry>
+             <entry>18mm coupler</entry>
+           </row>
+           <row>
+             <entry>TeleMini <?linebreak?>v2.0</entry>
+             <entry><para>
+               Antenna<?linebreak?>
+               Debug<?linebreak?>
+               USB<?linebreak?>
+               Battery
+             </para></entry>
+             <entry><para>
+               Apogee pyro <?linebreak?>
+               Main pyro <?linebreak?>
+               Battery <?linebreak?>
+               Switch
+               </para></entry>
+             <entry>0.8 inch (2.03cm)</entry>
+             <entry>1½ inch (3.81cm)</entry>
+             <entry>24mm coupler</entry>
+           </row>
+           <row>
+             <entry>EasyMini</entry>
+             <entry><para>
+               Debug<?linebreak?>
+               USB<?linebreak?>
+               Battery
+             </para></entry>
+             <entry><para>
+               Apogee pyro <?linebreak?>
+               Main pyro <?linebreak?>
+               Battery <?linebreak?>
+               Switch
+               </para></entry>
+             <entry>0.8 inch (2.03cm)</entry>
+             <entry>1½ inch (3.81cm)</entry>
+             <entry>24mm coupler</entry>
+           </row>
+           <row>
+             <entry>TeleMega</entry>
+             <entry><para>
+               Antenna<?linebreak?>
+               Debug<?linebreak?>
+               Companion<?linebreak?>
+               USB<?linebreak?>
+               Battery
+             </para></entry>
+             <entry><para>
+               Apogee pyro <?linebreak?>
+               Main pyro<?linebreak?>
+               Pyro A-D<?linebreak?>
+               Switch<?linebreak?>
+               Pyro battery
+             </para></entry>
+             <entry>1¼ inch (3.18cm)</entry>
+             <entry>3¼ inch (8.26cm)</entry>
+             <entry>38mm coupler</entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
+    <section>
+      <title>TeleMetrum</title>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="telemetrum-v1.1-thside.jpg" width="5.5in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
+      <para>
+       TeleMetrum is a 1 inch by 2¾ inch circuit board.  It was designed to
+       fit inside coupler for 29mm air-frame tubing, but using it in a tube that
+       small in diameter may require some creativity in mounting and wiring
+       to succeed!  The presence of an accelerometer means TeleMetrum should
+       be aligned along the flight axis of the airframe, and by default the ¼
+       wave UHF wire antenna should be on the nose-cone end of the board.  The
+       antenna wire is about 7 inches long, and wiring for a power switch and
+       the e-matches for apogee and main ejection charges depart from the
+       fin can end of the board, meaning an ideal “simple” avionics
+       bay for TeleMetrum should have at least 10 inches of interior length.
+      </para>
+    </section>
+    <section>
+      <title>TeleMini</title>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="telemini-v1-top.jpg" width="5.5in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
+      <para>
+       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.
+      </para>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="telemini-v2-top.jpg" width="5.5in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
+      <para>
+       TeleMini v2.0 is 0.8 inches by 1½ inches. It adds more
+       on-board data logging memory, a built-in USB connector and
+       screw terminals for the battery and power switch. The larger
+       board fits in a 24mm coupler. There's also a battery connector
+       for a LiPo battery if you want to use one of those.
+      </para>
+    </section>
+    <section>
+      <title>EasyMini</title>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="easymini-top.jpg" width="5.5in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
+      <para>
+       EasyMini is built on a 0.8 inch by 1½ inch circuit board. It's
+       designed to fit in a 24mm coupler tube. The connectors and
+       screw terminals match TeleMini v2.0, so you can easily swap between
+       EasyMini and TeleMini.
+      </para>
+    </section>
+    <section>
+      <title>TeleMega</title>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="telemega-v1.0-top.jpg" width="5.5in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
+      <para>
+       TeleMega is a 1¼ inch by 3¼ inch circuit board. It was
+       designed to easily fit in a 38mm coupler. Like TeleMetrum,
+       TeleMega has an accelerometer and so it must be mounted so that
+       the board is aligned with the flight axis. It can be mounted
+       either antenna up or down.
+      </para>
+    </section>
+    <section>
+      <title>Flight Data Recording</title>
+      <para>
+       Each flight computer logs data at 100 samples per second
+       during ascent and 10 samples per second during descent, except
+       for TeleMini v1.0, which records ascent at 10 samples per
+       second and descent at 1 sample per second. Data are logged to
+       an on-board flash memory part, which can be partitioned into
+       several equal-sized blocks, one for each flight.
+      </para>
+      <table frame='all'>
+       <title>Data Storage on Altus Metrum altimeters</title>
+       <?dbfo keep-together="always"?>
+       <tgroup cols='4' align='center' colsep='1' rowsep='1'>
+         <colspec align='center' colwidth='*' colname='Device'/>
+         <colspec align='center' colwidth='*' colname='Bytes per sample'/>
+         <colspec align='center' colwidth='*' colname='Total storage'/>
+         <colspec align='center' colwidth='*' colname='Minutes of
+                                                       full-rate'/>
+         <thead>
+           <row>
+             <entry align='center'>Device</entry>
+             <entry align='center'>Bytes per Sample</entry>
+             <entry align='center'>Total Storage</entry>
+             <entry align='center'>Minutes at Full Rate</entry>
+           </row>
+         </thead>
+         <tbody>
+           <row>
+             <entry>TeleMetrum v1.0</entry>
+             <entry>8</entry>
+             <entry>1MB</entry>
+             <entry>20</entry>
+           </row>
+           <row>
+             <entry>TeleMetrum v1.1 v1.2</entry>
+             <entry>8</entry>
+             <entry>2MB</entry>
+             <entry>40</entry>
+           </row>
+           <row>
+             <entry>TeleMetrum v2.0</entry>
+             <entry>16</entry>
+             <entry>8MB</entry>
+             <entry>80</entry>
+           </row>
+           <row>
+             <entry>TeleMini v1.0</entry>
+             <entry>2</entry>
+             <entry>5kB</entry>
+             <entry>4</entry>
+           </row>
+           <row>
+             <entry>TeleMini v2.0</entry>
+             <entry>16</entry>
+             <entry>1MB</entry>
+             <entry>10</entry>
+           </row>
+           <row>
+             <entry>EasyMini</entry>
+             <entry>16</entry>
+             <entry>1MB</entry>
+             <entry>10</entry>
+           </row>
+           <row>
+             <entry>TeleMega</entry>
+             <entry>32</entry>
+             <entry>8MB</entry>
+             <entry>40</entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+      <para>
+       The on-board flash is partitioned into separate flight logs,
+       each of a fixed maximum size. Increase the maximum size of
+       each log and you reduce the number of flights that can be
+       stored. Decrease the size and you can store more flights.
+      </para>
+      <para>
+       Configuration data is also stored in the flash memory on
+       TeleMetrum v1.x, TeleMini and EasyMini. This consumes 64kB
+       of flash space.  This configuration space is not available
+       for storing flight log data. TeleMetrum v2.0 and TeleMega
+       store configuration data in a bit of eeprom available within
+       the processor chip, leaving that space available in flash for
+       more flight data.
+      </para>
+      <para>
+       To compute the amount of space needed for a single flight, you
+       can multiply the expected ascent time (in seconds) by 100
+       times bytes-per-sample, multiply the expected descent time (in
+       seconds) by 10 times the bytes per sample and add the two
+       together. That will slightly under-estimate the storage (in
+       bytes) needed for the flight. For instance, a TeleMetrum v2.0 flight spending
+       20 seconds in ascent and 150 seconds in descent will take
+       about (20 * 1600) + (150 * 160) = 56000 bytes of storage. You
+       could store dozens of these flights in the on-board flash.
+      </para>
+      <para>
+       The default size allows for several flights on each flight
+       computer, except for TeleMini v1.0, which only holds data for a
+       single flight. You can adjust the size.
+      </para>
+      <para>
+       Altus Metrum flight computers will not overwrite existing
+       flight data, so be sure to download flight data and erase it
+       from the flight computer before it fills up. The flight
+       computer will still successfully control the flight even if it
+       cannot log data, so the only thing you will lose is the data.
+      </para>
+    </section>
+    <section>
+      <title>Installation</title>
+      <para>
+       A typical installation involves attaching 
+       only a suitable battery, a single pole switch for 
+       power on/off, and two pairs of wires connecting e-matches for the 
+       apogee and main ejection charges.  All Altus Metrum products are 
+       designed for use with single-cell batteries with 3.7 volts
+       nominal. TeleMini v2.0 and EasyMini may also be used with other
+       batteries as long as they supply between 4 and 12 volts. 
+      </para>
+      <para>
+       The battery connectors are a standard 2-pin JST connector and
+       match batteries sold by Spark Fun. These batteries are
+       single-cell Lithium Polymer batteries that nominally provide 3.7
+       volts.  Other vendors sell similar batteries for RC aircraft
+       using mating connectors, however the polarity for those is
+       generally reversed from the batteries used by Altus Metrum
+       products. In particular, the Tenergy batteries supplied for use
+       in Featherweight flight computers are not compatible with Altus
+       Metrum flight computers or battery chargers. <emphasis>Check
+       polarity and voltage before connecting any battery not purchased
+       from Altus Metrum or Spark Fun.</emphasis>
+      </para>
+      <para>
+       By default, we use the unregulated output of the battery directly
+       to fire ejection charges.  This works marvelously with standard
+       low-current e-matches like the J-Tek from MJG Technologies, and with
+       Quest Q2G2 igniters.  However, if you want or need to use a separate 
+       pyro battery, check out the “External Pyro Battery” section in this 
+       manual for instructions on how to wire that up. The altimeters are 
+       designed to work with an external pyro battery of no more than 15 volts.
+
+      </para>
+      <para>
+       Ejection charges are wired directly to the screw terminal block
+       at the aft end of the altimeter.  You'll need a very small straight 
+       blade screwdriver for these screws, such as you might find in a 
+       jeweler's screwdriver set.
+      </para>
+      <para>
+       Except for TeleMini v1.0, the flight computers also use the
+       screw terminal block for the power switch leads. On TeleMini v1.0,
+       the power switch leads are soldered directly to the board and
+       can be connected directly to a switch.
+      </para>
+      <para>
+       For most air-frames, the integrated antennas are more than
+       adequate.   However, if you are installing in a carbon-fiber or
+       metal electronics bay which is opaque to RF signals, you may need to
+       use off-board external antennas instead.  In this case, you can
+       replace the stock UHF antenna wire with an edge-launched SMA connector,
+       and, on TeleMetrum v1, you can unplug the integrated GPS
+       antenna and select an appropriate off-board GPS antenna with
+       cable terminating in a U.FL connector.
+      </para>
+    </section>
   </chapter>
   <chapter>
     <title>System Operation</title>
@@ -362,55 +813,271 @@ NAR #88757, TRA #12200
       <title>Firmware Modes </title>
       <para>
         The AltOS firmware build for the altimeters has two
-        fundamental modes, "idle" and "flight".  Which of these modes
+        fundamental modes, “idle” and “flight”.  Which of these modes
         the firmware operates in is determined at start up time. For
-        TeleMetrum, the mode is controlled by the orientation of the
+        TeleMetrum and TeleMega, which have accelerometers, the mode is 
+       controlled by the orientation of the
         rocket (well, actually the board, of course...) at the time
-        power is switched on.  If the rocket is "nose up", then
-        TeleMetrum assumes it's on a rail or rod being prepared for
+        power is switched on.  If the rocket is “nose up”, then
+        the flight computer assumes it's on a rail or rod being prepared for
         launch, so the firmware chooses flight mode.  However, if the
         rocket is more or less horizontal, the firmware instead enters
-        idle mode.  Since TeleMini doesn't have an accelerometer we can
-        use to determine orientation, "idle" mode is selected when the
-        board receives a command packet within the first five seconds
-        of operation; if no packet is received, the board enters
-        "flight" mode.
+        idle mode.  Since TeleMini v2.0 and EasyMini don't have an
+        accelerometer we can use to determine orientation, “idle” mode
+        is selected if the board is connected via USB to a computer,
+        otherwise the board enters “flight” mode. TeleMini v1.0
+        selects “idle” mode if it receives a command packet within the
+        first five seconds of operation.
       </para>
       <para>
         At power on, you will hear three beeps or see three flashes
-        ("S" in Morse code for start up) and then a pause while
+        (“S” in Morse code for start up) and then a pause while
         the altimeter completes initialization and self test, and decides 
        which mode to enter next.
       </para>
       <para>
-        In flight or "pad" mode, the altimeter engages the flight
-        state machine, goes into transmit-only mode to
-        send telemetry, and waits for launch to be detected.
-        Flight mode is indicated by an "di-dah-dah-dit" ("P" for pad)
-        on the beeper or lights, followed by beeps or flashes
-        indicating the state of the pyrotechnic igniter continuity.
-        One beep/flash indicates apogee continuity, two beeps/flashes
-        indicate main continuity, three beeps/flashes indicate both
-        apogee and main continuity, and one longer "brap" sound or
-        rapidly alternating lights indicates no continuity.  For a
+       Here's a short summary of all of the modes and the beeping (or
+       flashing, in the case of TeleMini v1) that accompanies each
+       mode. In the description of the beeping pattern, “dit” means a
+       short beep while "dah" means a long beep (three times as
+       long). “Brap” means a long dissonant tone.
+       <table frame='all'>
+         <title>AltOS Modes</title>
+         <?dbfo keep-together="always"?>
+         <tgroup cols='4' align='center' colsep='1' rowsep='1'>
+           <colspec align='center' colwidth='*' colname='Mode Name'/>
+           <colspec align='center' colwidth='*' colname='Letter'/>
+           <colspec align='center' colwidth='*' colname='Beeps'/>
+           <colspec align='center' colwidth='*' colname='Description'/>
+           <thead>
+             <row>
+               <entry>Mode Name</entry>
+               <entry>Abbreviation</entry>
+               <entry>Beeps</entry>
+               <entry>Description</entry>
+             </row>
+           </thead>
+           <tbody>
+             <row>
+               <entry>Startup</entry>
+               <entry>S</entry>
+               <entry>dit dit dit</entry>
+               <entry>
+                 <para>
+                   Calibrating sensors, detecting orientation.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Idle</entry>
+               <entry>I</entry>
+               <entry>dit dit</entry>
+               <entry>
+                 <para>
+                   Ready to accept commands over USB or radio link.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Pad</entry>
+               <entry>P</entry>
+               <entry>dit dah dah dit</entry>
+               <entry>
+                 <para>
+                   Waiting for launch. Not listening for commands.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Boost</entry>
+               <entry>B</entry>
+               <entry>dah dit dit dit</entry>
+               <entry>
+                 <para>
+                   Accelerating upwards.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Fast</entry>
+               <entry>F</entry>
+               <entry>dit dit dah dit</entry>
+               <entry>
+                 <para>
+                   Decellerating, but moving faster than 200m/s.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Coast</entry>
+               <entry>C</entry>
+               <entry>dah dit dah dit</entry>
+               <entry>
+                 <para>
+                   Decellerating, moving slower than 200m/s
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Drogue</entry>
+               <entry>D</entry>
+               <entry>dah dit dit</entry>
+               <entry>
+                 <para>
+                   Descending after apogee. Above main height.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Main</entry>
+               <entry>M</entry>
+               <entry>dah dah</entry>
+               <entry>
+                 <para>
+                   Descending. Below main height.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Landed</entry>
+               <entry>L</entry>
+               <entry>dit dah dit dit</entry>
+               <entry>
+                 <para>
+                   Stable altitude for at least ten seconds.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Sensor error</entry>
+               <entry>X</entry>
+               <entry>dah dit dit dah</entry>
+               <entry>
+                 <para>
+                   Error detected during sensor calibration.
+                 </para>
+               </entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </table>
+      </para>
+      <para>
+        In flight or “pad” mode, the altimeter engages the flight
+        state machine, goes into transmit-only mode to send telemetry,
+        and waits for launch to be detected.  Flight mode is indicated
+        by an “di-dah-dah-dit” (“P” for pad) on the beeper or lights,
+        followed by beeps or flashes indicating the state of the
+        pyrotechnic igniter continuity.  One beep/flash indicates
+        apogee continuity, two beeps/flashes indicate main continuity,
+        three beeps/flashes indicate both apogee and main continuity,
+        and one longer “brap” sound which is made by rapidly
+        alternating between two tones indicates no continuity.  For a
         dual deploy flight, make sure you're getting three beeps or
         flashes before launching!  For apogee-only or motor eject
         flights, do what makes sense.
       </para>
       <para>
-        If idle mode is entered, you will hear an audible "di-dit" or
-        see two short flashes ("I" for idle), and the flight state
+        If idle mode is entered, you will hear an audible “di-dit” or
+        see two short flashes (“I” for idle), and the flight state
         machine is disengaged, thus no ejection charges will fire.
         The altimeters also listen for the radio link when in idle
         mode for requests sent via TeleDongle.  Commands can be issued
-        to a TeleMetrum in idle mode over either USB or the radio link
-        equivalently. TeleMini only has the radio link.  Idle mode is
-        useful for configuring the altimeter, for extracting data from
-        the on-board storage chip after flight, and for ground testing
-        pyro charges.
+        in idle mode over either USB or the radio link
+        equivalently. TeleMini v1.0 only has the radio link.  Idle
+        mode is useful for configuring the altimeter, for extracting
+        data from the on-board storage chip after flight, and for
+        ground testing pyro charges.
+      </para>
+      <para>
+       In “Idle” and “Pad” modes, once the mode indication
+       beeps/flashes and continuity indication has been sent, if
+       there is no space available to log the flight in on-board
+       memory, the flight computer will emit a warbling tone (much
+       slower than the “no continuity tone”)
+      </para>
+      <para>
+       Here's a summary of all of the “pad” and “idle” mode indications.
+       <table frame='all'>
+         <title>Pad/Idle Indications</title>
+         <?dbfo keep-together="always"?>
+         <tgroup cols='3' align='center' colsep='1' rowsep='1'>
+           <colspec align='center' colwidth='*' colname='Name'/>
+           <colspec align='center' colwidth='*' colname='Beeps'/>
+           <colspec align='center' colwidth='*' colname='Description'/>
+           <thead>
+             <row>
+               <entry>Name</entry>
+               <entry>Beeps</entry>
+               <entry>Description</entry>
+             </row>
+           </thead>
+           <tbody>
+             <row>
+               <entry>Neither</entry>
+               <entry>brap</entry>
+               <entry>
+                 <para>
+                   No continuity detected on either apogee or main
+                   igniters.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Apogee</entry>
+               <entry>dit</entry>
+               <entry>
+                 <para>
+                   Continuity detected only on apogee igniter.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Main</entry>
+               <entry>dit dit</entry>
+               <entry>
+                 <para>
+                   Continuity detected only on main igniter.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Both</entry>
+               <entry>dit dit dit</entry>
+               <entry>
+                 <para>
+                   Continuity detected on both igniters.
+                 </para>
+               </entry>
+             </row>
+             <row>
+               <entry>Storage Full</entry>
+               <entry>warble</entry>
+               <entry>
+                 <para>
+                   On-board data logging storage is full. This will
+                   not prevent the flight computer from safely
+                   controlling the flight or transmitting telemetry
+                   signals, but no record of the flight will be
+                   stored in on-board flash.
+                 </para>
+               </entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </table>
+      </para>
+      <para>
+       Once landed, the flight computer will signal that by emitting
+       the “Landed” sound described above, after which it will beep
+       out the apogee height (in meters). Each digit is represented
+       by a sequence of short “dit” beeps, with a pause between
+       digits. A zero digit is represented with one long “dah”
+       beep. The flight computer will continue to report landed mode
+       and beep out the maximum height until turned off.
       </para>
       <para>
-        One "neat trick" of particular value when TeleMetrum is used with 
+        One “neat trick” of particular value when TeleMetrum or TeleMega are used with 
         very large air-frames, is that you can power the board up while the 
         rocket is horizontal, such that it comes up in idle mode.  Then you can
         raise the air-frame to launch position, and issue a 'reset' command 
@@ -421,24 +1088,32 @@ NAR #88757, TRA #12200
         installing igniters!
       </para>
       <para>
-       TeleMini is configured via the radio link. Of course, that
+       TeleMini v1.0 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
+       when you don't have the radio configuration values, TeleMini v1.0
        offers an 'emergency recovery' mode. In this mode, TeleMini is
        configured as follows:
        <itemizedlist>
          <listitem>
+           <para>
            Sets the radio frequency to 434.550MHz
+           </para>
          </listitem>
          <listitem>
+           <para>
            Sets the radio calibration back to the factory value.
+           </para>
          </listitem>
          <listitem>
+           <para>
            Sets the callsign to N0CALL
+           </para>
          </listitem>
          <listitem>
+           <para>
            Does not go to 'pad' mode after five seconds.
+           </para>
          </listitem>
        </itemizedlist>
       </para>
@@ -454,17 +1129,17 @@ NAR #88757, TRA #12200
     <section>
       <title>GPS </title>
       <para>
-        TeleMetrum includes a complete GPS receiver.  A complete explanation 
-        of how GPS works is beyond the scope of this manual, but the bottom 
-        line is that the TeleMetrum GPS receiver needs to lock onto at least 
-        four satellites to obtain a solid 3 dimensional position fix and know
-        what time it is.
+        TeleMetrum and TeleMega include a complete GPS receiver.  A
+        complete explanation of how GPS works is beyond the scope of
+        this manual, but the bottom line is that the GPS receiver
+        needs to lock onto at least four satellites to obtain a solid
+        3 dimensional position fix and know what time it is.
       </para>
       <para>
-        TeleMetrum provides backup power to the GPS chip any time a 
-        battery is connected.  This allows the receiver to "warm start" on
+        The flight computers provide backup power to the GPS chip any time a 
+        battery is connected.  This allows the receiver to “warm start” on
         the launch rail much faster than if every power-on were a GPS 
-       "cold start".  In typical operations, powering up TeleMetrum
+       “cold start”.  In typical operations, powering up
         on the flight line in idle mode while performing final air-frame
         preparation will be sufficient to allow the GPS receiver to cold
         start and acquire lock.  Then the board can be powered down during
@@ -485,10 +1160,10 @@ NAR #88757, TRA #12200
         computer.
       </para>
       <para>
-        Any operation which can be performed with TeleMetrum can
-        either be done with TeleMetrum directly connected to the
+        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 doesn't provide a USB connector and so it is
+        link. TeleMini v1.0 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.
@@ -514,10 +1189,11 @@ NAR #88757, TRA #12200
         </listitem>
         <listitem>
           <para>
-            Configure altimeter apogee delays or main deploy heights
+            Configure altimeter apogee delays, main deploy heights
+           and additional pyro event conditions
             to respond to changing launch conditions. You can also
             'reboot' the altimeter. Use this to remotely enable the
-            flight computer by turning TeleMetrum on in "idle" mode,
+            flight computer by turning TeleMetrum or TeleMega on in “idle” mode,
             then once the air-frame is oriented for launch, you can
             reboot the altimeter and have it restart in pad mode
             without having to climb the scary ladder.
@@ -526,7 +1202,7 @@ NAR #88757, TRA #12200
         <listitem>
           <para>
             Fire Igniters—Test your deployment charges without snaking
-            wires out through holes in the air-frame. Simply assembly the
+            wires out through holes in the air-frame. Simply assemble the
             rocket as if for flight with the apogee and main charges
             loaded, then remotely command the altimeter to fire the
             igniters.
@@ -541,9 +1217,10 @@ NAR #88757, TRA #12200
         close the window before performing other desired radio operations.
       </para>
       <para>
-        TeleMetrum only enables radio commanding in 'idle' mode, so
-        make sure you have TeleMetrum lying horizontally when you turn
-        it on. Otherwise, TeleMetrum will start in 'pad' mode ready for
+        The flight computers only enable radio commanding in 'idle' mode.
+       TeleMetrum and TeleMega use the accelerometer to detect which orientation they
+       start up in, so make sure you have the flight computer lying horizontally when you turn
+        it on. Otherwise, it will start in 'pad' mode ready for
         flight, and will not be listening for command packets from TeleDongle.
       </para>
       <para>
@@ -570,15 +1247,15 @@ NAR #88757, TRA #12200
         An important aspect of preparing a rocket using electronic deployment
         for flight is ground testing the recovery system.  Thanks
         to the bi-directional radio link central to the Altus Metrum system,
-        this can be accomplished in a TeleMetrum or TeleMini equipped rocket 
+        this can be accomplished in a TeleMega, TeleMetrum or TeleMini equipped rocket 
         with less work than you may be accustomed to with other systems.  It 
         can even be fun!
       </para>
       <para>
         Just prep the rocket for flight, then power up the altimeter
-        in "idle" mode (placing air-frame horizontal for TeleMetrum or
-        selected the Configure Altimeter tab for TeleMini).  This will cause 
-        the firmware to go into "idle" mode, in which the normal flight
+        in “idle” mode (placing air-frame horizontal for TeleMetrum or TeleMega, or
+        selecting the Configure Altimeter tab for TeleMini).  This will cause 
+        the firmware to go into “idle” mode, in which the normal flight
         state machine is disabled and charges will not fire without
         manual command.  You can now command the altimeter to fire the apogee
         or main charges from a safe distance using your computer and 
@@ -588,18 +1265,18 @@ NAR #88757, TRA #12200
     <section>
       <title>Radio Link </title>
       <para>
-        The chip our boards are based on incorporates an RF transceiver, but
+        Our flight computers all incorporate an RF transceiver, but
         it's not a full duplex system... each end can only be transmitting or
         receiving at any given moment.  So we had to decide how to manage the
         link.
       </para>
       <para>
         By design, the altimeter firmware listens for the radio link when
-        it's in "idle mode", which
+        it's in “idle mode”, which
         allows us to use the radio link to configure the rocket, do things like
         ejection tests, and extract data after a flight without having to
-        crack open the air-frame.  However, when the board is in "flight
-        mode", the altimeter only
+        crack open the air-frame.  However, when the board is in flight
+        mode, the altimeter only
         transmits and doesn't listen at all.  That's because we want to put
         ultimate priority on event detection and getting telemetry out of
         the rocket through
@@ -607,27 +1284,36 @@ NAR #88757, TRA #12200
         data later...
       </para>
       <para>
-        We don't use a 'normal packet radio' mode like APRS because they're 
-        just too inefficient.  The GFSK modulation we use is FSK with the
-        base-band pulses passed through a
-        Gaussian filter before they go into the modulator to limit the
-        transmitted bandwidth.  When combined with the hardware forward error
-        correction support in the cc1111 chip, this allows us to have a very
-        robust 38.4 kilobit data link with only 10 milliwatts of transmit 
-        power, a whip antenna in the rocket, and a hand-held Yagi on the 
-        ground.  We've had flights to above 21k feet AGL with great reception, 
-        and calculations suggest we should be good to well over 40k feet AGL 
-        with a 5-element yagi on the ground.  We hope to fly boards to higher 
-        altitudes over time, and would of course appreciate customer feedback 
-        on performance in higher altitude flights!
+        We don't generally use a 'normal packet radio' mode like APRS
+        because they're just too inefficient.  The GFSK modulation we
+        use is FSK with the base-band pulses passed through a Gaussian
+        filter before they go into the modulator to limit the
+        transmitted bandwidth.  When combined with forward error
+        correction and interleaving, this allows us to have a very
+        robust 19.2 kilobit data link with only 10-40 milliwatts of
+        transmit power, a whip antenna in the rocket, and a hand-held
+        Yagi on the ground.  We've had flights to above 21k feet AGL
+        with great reception, and calculations suggest we should be
+        good to well over 40k feet AGL with a 5-element yagi on the
+        ground with our 10mW units and over 100k feet AGL with the
+        40mW devices.  We hope to fly boards to higher altitudes over
+        time, and would of course appreciate customer feedback on
+        performance in higher altitude flights!
+      </para>
+      <para>
+       TeleMetrum v2.0 and TeleMega can send APRS if desired, and the
+       interval between APRS packets can be configured. As each APRS
+       packet takes a full second to transmit, we recommend an
+       interval of at least 5 seconds to avoid consuming too much
+       battery power or radio channel bandwidth.
       </para>
     </section>
     <section>
       <title>Configurable Parameters</title>
       <para>
         Configuring an Altus Metrum altimeter for flight is very
-        simple.  Even on our baro-only TeleMini board, the use of a Kalman 
-        filter means there is no need to set a "mach delay".  The few 
+        simple.  Even on our baro-only TeleMini and EasyMini boards, the use of a Kalman 
+        filter means there is no need to set a “mach delay”.  The few 
         configurable parameters can all be set using AltosUI over USB or
         or radio link via TeleDongle.
       </para>
@@ -636,7 +1322,7 @@ NAR #88757, TRA #12200
         <para>
          Altus Metrum boards support radio frequencies in the 70cm
          band. By default, the configuration interface provides a
-         list of 10 "standard" frequencies in 100kHz channels starting at
+         list of 10 “standard” frequencies in 100kHz channels starting at
          434.550MHz.  However, the firmware supports use of
          any 50kHz multiple within the 70cm band. At any given
          launch, we highly recommend coordinating when and by whom each
@@ -682,54 +1368,18 @@ NAR #88757, TRA #12200
       <section>
        <title>Maximum Flight Log</title>
        <para>
-         TeleMetrum version 1.1 and 1.2 have 2MB of on-board flash storage,
-         enough to hold over 40 minutes of data at full data rate
-         (100 samples/second). TeleMetrum 1.0 has 1MB of on-board
-         storage. As data are stored at a reduced rate during descent
-         (10 samples/second), there's plenty of space to store many
-         flights worth of data.
-       </para>
-       <para>
-         The on-board flash is partitioned into separate flight logs,
-         each of a fixed maximum size. Increase the maximum size of
-         each log and you reduce the number of flights that can be
-         stored. Decrease the size and TeleMetrum can store more
-         flights.
-       </para>
-       <para>
-         All of the configuration data is also stored in the flash
-         memory, which consumes 64kB on TeleMetrum v1.1/v1.2 and 256B on
-         TeleMetrum v1.0. This configuration space is not available
-         for storing flight log data.
-       </para>
-       <para>
-         To compute the amount of space needed for a single flight,
-         you can multiply the expected ascent time (in seconds) by
-         800, multiply the expected descent time (in seconds) by 80
-         and add the two together. That will slightly under-estimate
-         the storage (in bytes) needed for the flight. For instance,
-         a flight spending 20 seconds in ascent and 150 seconds in
-         descent will take about (20 * 800) + (150 * 80) = 28000
-         bytes of storage. You could store dozens of these flights in
-         the on-board flash.
+         Changing this value will set the maximum amount of flight
+         log storage that an individual flight will use. The
+         available storage is divided into as many flights of the
+         specified size as can fit in the available space. You can
+         download and erase individual flight logs. If you fill up
+         the available storage, future flights will not get logged
+         until you erase some of the stored ones.
        </para>
        <para>
-         The default size, 192kB, allows for 10 flights of storage on
-         TeleMetrum v1.1/v1.2 and 5 flights on TeleMetrum v1.0. This
-         ensures that you won't need to erase the memory before
-         flying each time while still allowing more than sufficient
-         storage for each flight.
-       </para>
-       <para>
-         As TeleMini does not contain an accelerometer, it stores
-         data at 10 samples per second during ascent and one sample
-         per second during descent. Each sample is a two byte reading
-         from the barometer. These are stored in 5kB of
-         on-chip flash memory which can hold 256 seconds at the
-         ascent rate or 2560 seconds at the descent rate. Because of
-         the limited storage, TeleMini cannot hold data for more than
-         one flight, and so must be erased after each flight or it
-         will not capture data for subsequent flights.
+         Even though our flight computers (except TeleMini v1.0) can store
+         multiple flights, we strongly recommend downloading and saving
+         flight data after each flight.
        </para>
       </section>
       <section>
@@ -738,9 +1388,8 @@ NAR #88757, TRA #12200
          Instead of firing one charge at apogee and another charge at
          a fixed height above the ground, you can configure the
          altimeter to fire both at apogee or both during
-         descent. This was added to support an airframe that has two
-         TeleMetrum computers, one in the fin can and one in the
-         nose.
+         descent. This was added to support an airframe Bdale designed that 
+         had two altimeters, one in the fin can and one in the nose.
        </para>
        <para>
          Providing the ability to use both igniters for apogee or
@@ -752,31 +1401,194 @@ NAR #88757, TRA #12200
       <section>
        <title>Pad Orientation</title>
        <para>
-         TeleMetrum measures acceleration along the axis of the
-         board. Which way the board is oriented affects the sign of
-         the acceleration value. Instead of trying to guess which way
-         the board is mounted in the air frame, TeleMetrum must be
-         explicitly configured for either Antenna Up or Antenna
-         Down. The default, Antenna Up, expects the end of the
-         TeleMetrum board connected to the 70cm antenna to be nearest
-         the nose of the rocket, with the end containing the screw
+         TeleMetrum and TeleMega measure acceleration along the axis
+         of the board. Which way the board is oriented affects the
+         sign of the acceleration value. Instead of trying to guess
+         which way the board is mounted in the air frame, the
+         altimeter must be explicitly configured for either Antenna
+         Up or Antenna Down. The default, Antenna Up, expects the end
+         of the board connected to the 70cm antenna to be nearest the
+         nose of the rocket, with the end containing the screw
          terminals nearest the tail.
        </para>
       </section>
+      <section>
+       <title>Configurable Pyro Channels</title>
+       <para>
+         In addition to the usual Apogee and Main pyro channels,
+         TeleMega has four additional channels that can be configured
+         to activate when various flight conditions are
+         satisfied. You can select as many conditions as necessary;
+         all of them must be met in order to activate the
+         channel. The conditions available are:
+       </para>
+       <itemizedlist>
+         <listitem>
+           <para>
+             Acceleration away from the ground. Select a value, and
+             then choose whether acceleration should be above or
+             below that value. Acceleration is positive upwards, so
+             accelerating towards the ground would produce negative
+             numbers. Acceleration during descent is noisy and
+             inaccurate, so be careful when using it during these
+             phases of the flight.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             Vertical speed.  Select a value, and then choose whether
+             vertical speed should be above or below that
+             value. Speed is positive upwards, so moving towards the
+             ground would produce negative numbers. Speed during
+             descent is a bit noisy and so be careful when using it
+             during these phases of the flight.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             Height. Select a value, and then choose whether the
+             height above the launch pad should be above or below
+             that value.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             Orientation. TeleMega contains a 3-axis gyroscope and
+             accelerometer which is used to measure the current
+             angle. Note that this angle is not the change in angle
+             from the launch pad, but rather absolute relative to
+             gravity; the 3-axis accelerometer is used to compute the
+             angle of the rocket on the launch pad and initialize the
+             system. Because this value is computed by integrating
+             rate gyros, it gets progressively less accurate as the
+             flight goes on. It should have an accumulated error of
+             less than 0.2°/second (after 10 seconds of flight, the
+             error should be less than 2°).
+           </para>
+           <para>
+             The usual use of the orientation configuration is to
+             ensure that the rocket is traveling mostly upwards when
+             deciding whether to ignite air starts or additional
+             stages. For that, choose a reasonable maximum angle
+             (like 20°) and set the motor igniter to require an angle
+             of less than that value.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             Flight Time. Time since boost was detected. Select a
+             value and choose whether to activate the pyro channel
+             before or after that amount of time.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             Ascending. A simple test saying whether the rocket is
+             going up or not. This is exactly equivalent to testing
+             whether the speed is &gt; 0.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             Descending. A simple test saying whether the rocket is
+             going down or not. This is exactly equivalent to testing
+             whether the speed is &lt; 0.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             After Motor. The flight software counts each time the
+             rocket starts accelerating (presumably due to a motor or
+             motors igniting). Use this value to count ignitions for
+             multi-staged or multi-airstart launches.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             Delay. This value doesn't perform any checks, instead it
+             inserts a delay between the time when the other
+             parameters become true and when the pyro channel is
+             activated.
+           </para>
+         </listitem>
+         <listitem>
+           <para>
+             Flight State. The flight software tracks the flight
+             through a sequence of states:
+             <orderedlist>
+               <listitem>
+                 <para>
+                   Boost. The motor has lit and the rocket is
+                   accelerating upwards.
+                 </para>
+               </listitem>
+               <listitem>
+                 <para>
+                   Fast. The motor has burned out and the rocket is
+                   descellerating, but it is going faster than 200m/s.
+                 </para>
+               </listitem>
+               <listitem>
+                 <para>
+                   Coast. The rocket is still moving upwards and
+                   decelerating, but the speed is less than 200m/s.
+                 </para>
+               </listitem>
+               <listitem>
+                 <para>
+                   Drogue. The rocket has reached apogee and is heading
+                   back down, but is above the configured Main
+                   altitude.
+                 </para>
+               </listitem>
+               <listitem>
+                 <para>
+                   Main. The rocket is still descending, and is below
+                   the Main altitude
+                 </para>
+               </listitem>
+               <listitem>
+                 <para>
+                   Landed. The rocket is no longer moving.
+                 </para>
+               </listitem>
+             </orderedlist>
+           </para>
+           <para>
+             You can select a state to limit when the pyro channel
+             may activate; note that the check is based on when the
+             rocket transitions <emphasis>into</emphasis> the state, and so checking for
+             “greater than Boost” means that the rocket is currently
+             in boost or some later state.
+           </para>
+           <para>
+             When a motor burns out, the rocket enters either Fast or
+             Coast state (depending on how fast it is moving). If the
+             computer detects upwards acceleration again, it will
+             move back to Boost state.
+           </para>
+         </listitem>
+       </itemizedlist>
+      </section>
     </section>
 
   </chapter>
   <chapter>
-
     <title>AltosUI</title>
+    <informalfigure>
+      <mediaobject>
+       <imageobject>
+         <imagedata fileref="altosui.png" width="5.5in"/>
+       </imageobject>
+      </mediaobject>
+    </informalfigure>
     <para>
       The AltosUI program provides a graphical user interface for
-      interacting with the Altus Metrum product family, including
-      TeleMetrum, TeleMini and TeleDongle. AltosUI can monitor telemetry data,
-      configure TeleMetrum, TeleMini and TeleDongle devices and many other
+      interacting with the Altus Metrum product family. AltosUI can
+      monitor telemetry data, configure devices and many other
       tasks. The primary interface window provides a selection of
-      buttons, one for each major activity in the system.  This manual
-      is split into chapters, each of which documents one of the tasks
+      buttons, one for each major activity in the system.  This chapter
+      is split into sections, each of which documents one of the tasks
       provided from the top-level toolbar.
     </para>
     <section>
@@ -788,6 +1600,13 @@ NAR #88757, TRA #12200
         AltosUI will create a window to display telemetry data as
         received by the selected TeleDongle device.
       </para>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="device-selection.png" width="3.5in"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
       <para>
         All telemetry data received are automatically recorded in
         suitable log files. The name of the files includes the current
@@ -856,78 +1675,112 @@ NAR #88757, TRA #12200
       </para>
       <section>
         <title>Launch Pad</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="launch-pad.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
         <para>
           The 'Launch Pad' tab shows information used to decide when the
           rocket is ready for flight. The first elements include red/green
           indicators, if any of these is red, you'll want to evaluate
           whether the rocket is ready to launch:
-          <itemizedlist>
-            <listitem>
-              <para>
-                Battery Voltage. This indicates whether the Li-Po battery
-                powering the TeleMetrum has sufficient charge to last for
-                the duration of the flight. A value of more than
-                3.7V is required for a 'GO' status.
-              </para>
-            </listitem>
-            <listitem>
-              <para>
-                Apogee Igniter Voltage. This indicates whether the apogee
-                igniter has continuity. If the igniter has a low
-                resistance, then the voltage measured here will be close
-                to the Li-Po battery voltage. A value greater than 3.2V is
-                required for a 'GO' status.
-              </para>
-            </listitem>
-            <listitem>
-              <para>
-                Main Igniter Voltage. This indicates whether the main
-                igniter has continuity. If the igniter has a low
-                resistance, then the voltage measured here will be close
-                to the Li-Po battery voltage. A value greater than 3.2V is
-                required for a 'GO' status.
-              </para>
-            </listitem>
-           <listitem>
-             <para>
-               On-board Data Logging. This indicates whether there is
-               space remaining on-board to store flight data for the
-               upcoming flight. If you've downloaded data, but failed
-               to erase flights, there may not be any space
-               left. TeleMetrum can store multiple flights, depending
-               on the configured maximum flight log size. TeleMini
-               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 transmit telemetry and fire
-               ejection charges at the proper times.
-             </para>
-           </listitem>
-            <listitem>
-              <para>
-                GPS Locked. For a TeleMetrum device, this indicates whether the GPS receiver is
-                currently able to compute position information. GPS requires
-                at least 4 satellites to compute an accurate position.
-              </para>
-            </listitem>
-            <listitem>
-              <para>
-                GPS Ready. For a TeleMetrum device, this indicates whether GPS has reported at least
-                10 consecutive positions without losing lock. This ensures
-                that the GPS receiver has reliable reception from the
-                satellites.
-              </para>
-            </listitem>
-          </itemizedlist>
-          <para>
-            The Launchpad tab also shows the computed launch pad position
-            and altitude, averaging many reported positions to improve the
-            accuracy of the fix.
-          </para>
+          <variablelist>
+           <varlistentry>
+             <term>Battery Voltage</term>
+             <listitem>
+               <para>
+                 This indicates whether the Li-Po battery powering the 
+                 flight computer has sufficient charge to last for
+                 the duration of the flight. A value of more than
+                 3.8V is required for a 'GO' status.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>Apogee Igniter Voltage</term>
+             <listitem>
+               <para>
+                 This indicates whether the apogee
+                 igniter has continuity. If the igniter has a low
+                 resistance, then the voltage measured here will be close
+                 to the Li-Po battery voltage. A value greater than 3.2V is
+                 required for a 'GO' status.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>Main Igniter Voltage</term>
+             <listitem>
+               <para>
+                 This indicates whether the main
+                 igniter has continuity. If the igniter has a low
+                 resistance, then the voltage measured here will be close
+                 to the Li-Po battery voltage. A value greater than 3.2V is
+                 required for a 'GO' status.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>On-board Data Logging</term>
+             <listitem>
+               <para>
+                 This indicates whether there is
+                 space remaining on-board to store flight data for the
+                 upcoming flight. If you've downloaded data, but failed
+                 to erase flights, there may not be any space
+                 left. Most of our flight computers can store multiple 
+                 flights, depending on the configured maximum flight log 
+                 size. 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 transmit telemetry and fire
+                 ejection charges at the proper times even if the flight
+                 data storage is full.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>GPS Locked</term>
+             <listitem>
+               <para>
+                 For a TeleMetrum or TeleMega device, this indicates whether the GPS receiver is
+                 currently able to compute position information. GPS requires
+                 at least 4 satellites to compute an accurate position.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>GPS Ready</term>
+             <listitem>
+               <para>
+                 For a TeleMetrum or TeleMega device, this indicates whether GPS has reported at least
+                 10 consecutive positions without losing lock. This ensures
+                 that the GPS receiver has reliable reception from the
+                 satellites.
+               </para>
+             </listitem>
+           </varlistentry>
+          </variablelist>
         </para>
+       <para>
+         The Launchpad tab also shows the computed launch pad position
+         and altitude, averaging many reported positions to improve the
+         accuracy of the fix.
+       </para>
       </section>
       <section>
         <title>Ascent</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="ascent.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
         <para>
           This tab is shown during Boost, Fast and Coast
           phases. The information displayed here helps monitor the
@@ -940,7 +1793,7 @@ NAR #88757, TRA #12200
           flight.
         </para>
         <para>
-          The current latitude and longitude reported by the TeleMetrum GPS are
+          The current latitude and longitude reported by the GPS are
           also shown. Note that under high acceleration, these values
           may not get updated as the GPS receiver loses position
           fix. Once the rocket starts coasting, the receiver should
@@ -954,6 +1807,13 @@ NAR #88757, TRA #12200
       </section>
       <section>
         <title>Descent</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="descent.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
         <para>
           Once the rocket has reached apogee and (we hope) activated the
           apogee charge, attention switches to tracking the rocket on
@@ -968,7 +1828,7 @@ NAR #88757, TRA #12200
          be below 10m/s when under the main parachute in a dual-deploy flight.
         </para>
         <para>
-          For TeleMetrum altimeters, you can locate the rocket in the
+          With GPS-equipped flight computers, you can locate the rocket in the
           sky using the elevation and bearing information to figure
           out where to look. Elevation is in degrees above the
           horizon. Bearing is reported in degrees relative to true
@@ -990,6 +1850,13 @@ NAR #88757, TRA #12200
       </section>
       <section>
         <title>Landed</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="landed.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
         <para>
           Once the rocket is on the ground, attention switches to
           recovery. While the radio signal is often lost once the
@@ -1005,7 +1872,7 @@ NAR #88757, TRA #12200
           unit and have that compute a track to the landing location.
         </para>
        <para>
-         Both TeleMini and TeleMetrum will continue to transmit RDF
+         Our flight computers will continue to transmit RDF
          tones after landing, allowing you to locate the rocket by
          following the radio signal if necessary. You may need to get 
          away from the clutter of the flight line, or even get up on 
@@ -1016,7 +1883,7 @@ NAR #88757, TRA #12200
           during the flight are displayed for your admiring observers.
          The accuracy of these immediate values depends on the quality
          of your radio link and how many packets were received.  
-         Recovering the on-board data after flight will likely yield
+         Recovering the on-board data after flight may yield
          more precise results.
         </para>
        <para>
@@ -1025,8 +1892,32 @@ NAR #88757, TRA #12200
          graph window for the current flight.
        </para>
       </section>
+      <section>
+       <title>Table</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="table.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+       <para>
+         The table view shows all of the data available from the
+         flight computer. Probably the most useful data on
+         this tab is the detailed GPS information, which includes
+         horizontal dilution of precision information, and
+         information about the signal being received from the satellites.
+       </para>
+      </section>
       <section>
         <title>Site Map</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="site-map.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
         <para>
           When the TeleMetrum has a GPS fix, the Site Map tab will map
           the rocket's position to make it easier for you to locate the
@@ -1060,16 +1951,14 @@ NAR #88757, TRA #12200
         system can handle, and is not subject to radio drop-outs. As
         such, it provides a more complete and precise record of the
         flight. The 'Save Flight Data' button allows you to read the
-        flash memory and write it to disk. As TeleMini has only a barometer, it
-       records data at the same rate as the telemetry signal, but there will be
-       no data lost due to telemetry drop-outs.
+        flash memory and write it to disk. 
       </para>
       <para>
         Clicking on the 'Save Flight Data' button brings up a list of
-        connected TeleMetrum and TeleDongle devices. If you select a
-        TeleMetrum device, the flight data will be downloaded from that
+        connected flight computers and TeleDongle devices. If you select a
+        flight computer, the flight data will be downloaded from that
         device directly. If you select a TeleDongle device, flight data
-        will be downloaded from an altimeter over radio link via the 
+        will be downloaded from a flight computer over radio link via the 
        specified TeleDongle. See the chapter on Controlling An Altimeter 
        Over The Radio Link for more information.
       </para>
@@ -1113,16 +2002,27 @@ NAR #88757, TRA #12200
         flash memory.
       </para>
       <para>
-        Once a flight record is selected, a window with four tabs is
-        opened. The first tab contains a graph with acceleration
-        (blue), velocity (green) and altitude (red) of the flight,
-        measured in metric units. The apogee(yellow) and main(magenta)
-        igniter voltages are also displayed; high voltages indicate
-        continuity, low voltages indicate open circuits. The second
-        tab lets you configure which data to show in the graph.  The
-        third contains some basic flight statistics while the fourth
-        has a map with the ground track of the flight displayed.
+        Note that telemetry files will generally produce poor graphs
+        due to the lower sampling rate and missed telemetry packets.
+        Use saved flight data in .eeprom files for graphing where possible.
+      </para>
+      <para>
+        Once a flight record is selected, a window with multiple tabs is
+        opened.
       </para>
+      <section>
+       <title>Flight Graph</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="graph.png" width="5.5in" scalefit="1"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+       <para>
+         By default, the graph contains acceleration (blue),
+         velocity (green) and altitude (red).
+       </para>
       <para>
         The graph can be zoomed into a particular area by clicking and
         dragging down and to the right. Once zoomed, the graph can be
@@ -1131,21 +2031,61 @@ NAR #88757, TRA #12200
         The right mouse button causes a pop-up menu to be displayed, giving
         you the option save or print the plot.
       </para>
-      <para>
-        Note that telemetry files will generally produce poor graphs
-        due to the lower sampling rate and missed telemetry packets.
-        Use saved flight data in .eeprom files for graphing where possible.
-      </para>
+      </section>
+      <section>
+       <title>Configure Graph</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="graph-configure.png" width="5.5in" scalefit="1"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+       <para>
+         This selects which graph elements to show, and, at the
+         very bottom, lets you switch between metric and
+         imperial units
+       </para>
+      </section>
+      <section>
+       <title>Flight Statistics</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="graph-stats.png" width="5.5in" scalefit="1"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+       <para>
+         Shows overall data computed from the flight.
+       </para>
+      </section>
+      <section>
+       <title>Map</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="graph-map.png" width="5.5in" scalefit="1"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+       <para>
+         Shows a satellite image of the flight area overlaid
+         with the path of the flight. The red concentric
+         circles mark the launch pad, the black concentric
+         circles mark the landing location.
+       </para>
+      </section>
     </section>
     <section>
       <title>Export Data</title>
       <para>
         This tool takes the raw data files and makes them available for
         external analysis. When you select this button, you are prompted to 
-       select a flight
-        data file (either .eeprom or .telem will do, remember that
-        .eeprom files contain higher resolution and more continuous
-        data). Next, a second dialog appears which is used to select
+       select a flight data file, which can be either a .eeprom or .telem.
+       The .eeprom files contain higher resolution and more continuous data, 
+       while .telem files contain receiver signal strength information.  
+       Next, a second dialog appears which is used to select
         where to write the resulting file. It has a selector to choose
         between CSV and KML file formats.
       </para>
@@ -1179,8 +2119,15 @@ NAR #88757, TRA #12200
     </section>
     <section>
       <title>Configure Altimeter</title>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="configure-altimeter.png" width="3in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
       <para>
-        Select this button and then select either a TeleMetrum or
+        Select this button and then select either an altimeter or
         TeleDongle Device from the list provided. Selecting a TeleDongle
         device will use the radio link to configure a remote altimeter. 
       </para>
@@ -1193,35 +2140,47 @@ NAR #88757, TRA #12200
       <para>
         At the bottom of the dialog, there are four buttons:
       </para>
-      <itemizedlist>
-        <listitem>
-          <para>
-            Save. This writes any changes to the
-            configuration parameter block in flash memory. If you don't
-            press this button, any changes you make will be lost.
-          </para>
-        </listitem>
-        <listitem>
-          <para>
-            Reset. This resets the dialog to the most recently saved values,
-            erasing any changes you have made.
-          </para>
-        </listitem>
-        <listitem>
-          <para>
-            Reboot. This reboots the device. Use this to
-            switch from idle to pad mode by rebooting once the rocket is
-            oriented for flight, or to confirm changes you think you saved 
-           are really saved.
-          </para>
-        </listitem>
-        <listitem>
-          <para>
-            Close. This closes the dialog. Any unsaved changes will be
-            lost.
-          </para>
-        </listitem>
-      </itemizedlist>
+      <variablelist>
+       <varlistentry>
+         <term>Save</term>
+         <listitem>
+           <para>
+             This writes any changes to the
+             configuration parameter block in flash memory. If you don't
+             press this button, any changes you make will be lost.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>Reset</term>
+         <listitem>
+           <para>
+             This resets the dialog to the most recently saved values,
+             erasing any changes you have made.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>Reboot</term>
+         <listitem>
+           <para>
+             This reboots the device. Use this to
+             switch from idle to pad mode by rebooting once the rocket is
+             oriented for flight, or to confirm changes you think you saved 
+             are really saved.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>Close</term>
+         <listitem>
+           <para>
+             This closes the dialog. Any unsaved changes will be
+             lost.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
       <para>
         The rest of the dialog contains the parameters to be configured.
       </para>
@@ -1251,15 +2210,15 @@ NAR #88757, TRA #12200
       <section>
         <title>Radio Frequency</title>
         <para>
-          This configures which of the configured frequencies to use for both
+          This configures which of the frequencies to use for both
           telemetry and packet command mode. Note that if you set this
-          value via packet command mode, you will have to reconfigure
-          the TeleDongle frequency before you will be able to use packet
-          command mode again.
+          value via packet command mode, the TeleDongle frequency will
+          also be automatically reconfigured to match so that
+          communication will continue afterwards.
         </para>
       </section>
       <section>
-        <title>Radio Calibration</title>
+        <title>RF Calibration</title>
         <para>
           The radios in every Altus Metrum device are calibrated at the
           factory to ensure that they transmit and receive on the
@@ -1271,12 +2230,31 @@ NAR #88757, TRA #12200
         </para>
       </section>
       <section>
-        <title>Callsign</title>
-        <para>
-          This sets the call sign included in each telemetry packet. Set this
-          as needed to conform to your local radio regulations.
-        </para>
-      </section>
+       <title>Telemetry/RDF/APRS Enable</title>
+       <para>
+         Enables the radio for transmission during flight. When
+         disabled, the radio will not transmit anything during flight
+         at all.
+       </para>
+      </section>
+      <section>
+       <title>APRS Interval</title>
+       <para>
+         How often to transmit GPS information via APRS. This option
+         is available on TeleMetrum v2 and TeleMega
+         boards. TeleMetrum v1 boards cannot transmit APRS
+         packets. Note that a single APRS packet takes nearly a full
+         second to transmit, so enabling this option will prevent
+         sending any other telemetry during that time.
+       </para>
+      </section>
+      <section>
+        <title>Callsign</title>
+        <para>
+          This sets the call sign included in each telemetry packet. Set this
+          as needed to conform to your local radio regulations.
+        </para>
+      </section>
       <section>
         <title>Maximum Flight Log Size</title>
         <para>
@@ -1294,62 +2272,117 @@ NAR #88757, TRA #12200
          computers. This configuration parameter allows the two
          channels to be used in different configurations.
        </para>
-       <itemizedlist>
-         <listitem>
-           <para>
-             Dual Deploy. This is the usual mode of operation; the
-             'apogee' channel is fired at apogee and the 'main'
-             channel at the height above ground specified by the
-             'Main Deploy Altitude' during descent.
-           </para>
-         </listitem>
-         <listitem>
-           <para>
-             Redundant Apogee. This fires both channels at
-             apogee, the 'apogee' channel first followed after a two second
-             delay by the 'main' channel.
-           </para>
-         </listitem>
-         <listitem>
-           <para>
-             Redundant Main. This fires both channels at the
-             height above ground specified by the Main Deploy
-             Altitude setting during descent. The 'apogee'
-             channel is fired first, followed after a two second
-             delay by the 'main' channel.
-           </para>
-         </listitem>
-       </itemizedlist>
+          <variablelist>
+           <varlistentry>
+             <term>Dual Deploy</term>
+             <listitem>
+               <para>
+                 This is the usual mode of operation; the
+                 'apogee' channel is fired at apogee and the 'main'
+                 channel at the height above ground specified by the
+                 'Main Deploy Altitude' during descent.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>Redundant Apogee</term>
+             <listitem>
+               <para>
+                 This fires both channels at
+                 apogee, the 'apogee' channel first followed after a two second
+                 delay by the 'main' channel.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>Redundant Main</term>
+             <listitem>
+               <para>
+                 This fires both channels at the
+                 height above ground specified by the Main Deploy
+                 Altitude setting during descent. The 'apogee'
+                 channel is fired first, followed after a two second
+                 delay by the 'main' channel.
+               </para>
+             </listitem>
+           </varlistentry>
+       </variablelist>
       </section>
       <section>
         <title>Pad Orientation</title>
        <para>
-         Because it includes an accelerometer, TeleMetrum is
-         sensitive to the orientation of the board. By default, it
-         expects the antenna end to point forward. This parameter
-         allows that default to be changed, permitting the board to
-         be mounted with the antenna pointing aft instead.
+         Because they include accelerometers, TeleMetrum and
+         TeleMega are sensitive to the orientation of the board. By
+         default, they expect the antenna end to point forward. This
+         parameter allows that default to be changed, permitting the
+         board to be mounted with the antenna pointing aft instead.
+       </para>
+       <variablelist>
+         <varlistentry>
+           <term>Antenna Up</term>
+           <listitem>
+             <para>
+               In this mode, the antenna end of the
+               flight computer must point forward, in line with the
+               expected flight path.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Antenna Down</term>
+           <listitem>
+             <para>
+               In this mode, the antenna end of the
+               flight computer must point aft, in line with the
+               expected flight path.
+             </para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </section>
+      <section>
+       <title>Configure Pyro Channels</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="configure-pyro.png" width="6in" scalefit="1"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+       <para>
+         This opens a separate window to configure the additional
+         pyro channels available on TeleMega.  One column is
+         presented for each channel. Each row represents a single
+         parameter, if enabled the parameter must meet the specified
+         test for the pyro channel to be fired. See the Pyro Channels
+         section in the System Operation chapter above for a
+         description of these parameters.
+       </para>
+       <para>
+         Select conditions and set the related value; the pyro
+         channel will be activated when <emphasis>all</emphasis> of the
+         conditions are met. Each pyro channel has a separate set of
+         configuration values, so you can use different values for
+         the same condition with different channels.
+       </para>
+       <para>
+         Once you have selected the appropriate configuration for all
+         of the necessary pyro channels, you can save the pyro
+         configuration along with the rest of the flight computer
+         configuration by pressing the 'Save' button in the main
+         Configure Flight Computer window.
        </para>
-       <itemizedlist>
-         <listitem>
-           <para>
-             Antenna Up. In this mode, the antenna end of the
-             TeleMetrum board must point forward, in line with the
-             expected flight path.
-           </para>
-         </listitem>
-         <listitem>
-           <para>
-             Antenna Down. In this mode, the antenna end of the
-             TeleMetrum board must point aft, in line with the
-             expected flight path.
-           </para>
-         </listitem>
-       </itemizedlist>
       </section>
     </section>
     <section>
       <title>Configure AltosUI</title>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="configure-altosui.png" width="2.5in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
       <para>
         This button presents a dialog so that you can configure the AltosUI global settings.
       </para>
@@ -1361,18 +2394,24 @@ NAR #88757, TRA #12200
           the current flight status. However, sometimes you don't want
           to hear them.
         </para>
-        <itemizedlist>
-          <listitem>
-            <para>Enable—turns all voice announcements on and off</para>
-          </listitem>
-          <listitem>
-            <para>
-              Test Voice—Plays a short message allowing you to verify
-              that the audio system is working and the volume settings
-              are reasonable
-            </para>
-          </listitem>
-        </itemizedlist>
+        <variablelist>
+         <varlistentry>
+           <term>Enable</term>
+           <listitem>
+             <para>Turns all voice announcements on and off</para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Test Voice</term>
+           <listitem>
+             <para>
+               Plays a short message allowing you to verify
+               that the audio system is working and the volume settings
+               are reasonable
+             </para>
+           </listitem>
+         </varlistentry>
+        </variablelist>
       </section>
       <section>
         <title>Log Directory</title>
@@ -1397,15 +2436,23 @@ NAR #88757, TRA #12200
           with the AltosUI operators call sign as needed to comply with
           your local radio regulations.
         </para>
+        <para>
+         Note that to successfully command a flight computer over the radio
+         (to configure the altimeter, monitor idle, or fire pyro charges), 
+         the callsign configured here must exactly match the callsign
+         configured in the flight computer.  This matching is case 
+         sensitive.
+        </para>
       </section>
       <section>
        <title>Imperial Units</title>
        <para>
          This switches between metric units (meters) and imperial
          units (feet and miles). This affects the display of values
-         use during flight monitoring, data graphing and all of the
-         voice announcements. It does not change the units used when
-         exporting to CSV files, those are always produced in metric units.
+         use during flight monitoring, configuration, data graphing
+         and all of the voice announcements. It does not change the
+         units used when exporting to CSV files, those are always
+         produced in metric units.
        </para>
       </section>
       <section>
@@ -1439,6 +2486,13 @@ NAR #88757, TRA #12200
     </section>
     <section>
       <title>Configure Groundstation</title>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="configure-groundstation.png" width="3in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
       <para>
         Select this button and then select a TeleDongle Device from the list provided.
       </para>
@@ -1458,27 +2512,36 @@ NAR #88757, TRA #12200
       <para>
         At the bottom of the dialog, there are three buttons:
       </para>
-      <itemizedlist>
-        <listitem>
-          <para>
-            Save. This writes any changes to the
-            local Java preferences file. If you don't
-            press this button, any changes you make will be lost.
-          </para>
-        </listitem>
-        <listitem>
-          <para>
-            Reset. This resets the dialog to the most recently saved values,
-            erasing any changes you have made.
-          </para>
-        </listitem>
-        <listitem>
-          <para>
-            Close. This closes the dialog. Any unsaved changes will be
-            lost.
-          </para>
-        </listitem>
-      </itemizedlist>
+      <variablelist>
+       <varlistentry>
+         <term>Save</term>
+         <listitem>
+           <para>
+             This writes any changes to the
+             local Java preferences file. If you don't
+             press this button, any changes you make will be lost.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>Reset</term>
+         <listitem>
+           <para>
+             This resets the dialog to the most recently saved values,
+             erasing any changes you have made.
+           </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>Close</term>
+         <listitem>
+           <para>
+             This closes the dialog. Any unsaved changes will be
+             lost.
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
       <para>
         The rest of the dialog contains the parameters to be configured.
       </para>
@@ -1507,56 +2570,36 @@ NAR #88757, TRA #12200
     <section>
       <title>Flash Image</title>
       <para>
-        This reprograms any Altus Metrum device by using a TeleMetrum
-        or TeleDongle as a programming dongle. Please read the
-        directions for flashing devices in the Updating Device
-        Firmware chapter below.
-      </para>
-      <para>
-        Once you have the programmer and target devices connected,
-        push the 'Flash Image' button. That will present a dialog box
-        listing all of the connected devices. Carefully select the
-        programmer device, not the device to be programmed.
-      </para>
-      <para>
-        Next, select the image to flash to the device. These are named
-        with the product name and firmware version. The file selector
-        will start in the directory containing the firmware included
-        with the AltosUI package. Navigate to the directory containing
-        the desired firmware if it isn't there.
-      </para>
-      <para>
-        Next, a small dialog containing the device serial number and
-        RF calibration values should appear. If these values are
-        incorrect (possibly due to a corrupted image in the device),
-        enter the correct values here.
-      </para>
-      <para>
-        Finally, a dialog containing a progress bar will follow the
-        programming process.
-      </para>
-      <para>
-        When programming is complete, the target device will
-        reboot. Note that if the target device is connected via USB, you
-        will have to unplug it and then plug it back in for the USB
-        connection to reset so that you can communicate with the device
-        again.
+        This reprograms Altus Metrum devices with new
+        firmware. TeleMetrum v1.x, TeleDongle, TeleMini and TeleBT are
+        all reprogrammed by using another similar unit as a
+        programming dongle (pair programming). TeleMega, TeleMetrum v2
+        and EasyMini are all programmed directly over their USB ports
+        (self programming).  Please read the directions for flashing
+        devices in the Updating Device Firmware chapter below.
       </para>
     </section>
     <section>
       <title>Fire Igniter</title>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="fire-igniter.png" width="1in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
       <para>
-       This activates the igniter circuits in TeleMetrum to help test
-       recovery systems deployment. Because this command can operate
+       This activates the igniter circuits in the flight computer to help 
+       test recovery systems deployment. Because this command can operate
        over the Packet Command Link, you can prepare the rocket as
        for flight and then test the recovery system without needing
        to snake wires inside the air-frame.
       </para>
       <para>
        Selecting the 'Fire Igniter' button brings up the usual device
-       selection dialog. Pick the desired TeleDongle or TeleMetrum
-       device. This brings up another window which shows the current
-       continuity test status for both apogee and main charges.
+       selection dialog. Pick the desired device. This brings up another 
+       window which shows the current continuity test status for both 
+       apogee and main charges.
       </para>
       <para>
        Next, select the desired igniter to fire. This will enable the
@@ -1572,6 +2615,13 @@ NAR #88757, TRA #12200
     </section>
     <section>
       <title>Scan Channels</title>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="scan-channels.png" width="2.75in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
       <para>
        This listens for telemetry packets on all of the configured
        frequencies, displaying information about each device it
@@ -1583,6 +2633,13 @@ NAR #88757, TRA #12200
     </section>
     <section>
       <title>Load Maps</title>
+      <informalfigure>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="load-maps.png" width="5.5in" scalefit="1"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
       <para>
        Before heading out to a new launch site, you can use this to
        load satellite images in case you don't have internet
@@ -1593,8 +2650,8 @@ NAR #88757, TRA #12200
        There's a drop-down menu of launch sites we know about; if
        your favorites aren't there, please let us know the lat/lon
        and name of the site. The contents of this list are actually
-       downloaded at run-time, so as new sites are sent in, they'll
-       get automatically added to this list.
+       downloaded from our server at run-time, so as new sites are sent 
+       in, they'll get automatically added to this list.
       </para>
       <para>
        If the launch site isn't in the list, you can manually enter the lat/lon values
@@ -1611,9 +2668,13 @@ NAR #88757, TRA #12200
       <title>Monitor Idle</title>
       <para>
        This brings up a dialog similar to the Monitor Flight UI,
-       except it works with the altimeter in "idle" mode by sending
+       except it works with the altimeter in “idle” mode by sending
        query commands to discover the current state rather than
-       listening for telemetry packets.
+       listening for telemetry packets. Because this uses command
+       mode, it needs to have the TeleDongle and flight computer
+       callsigns match exactly. If you can receive telemetry, but
+       cannot manage to run Monitor Idle, then it's very likely that
+       your callsigns are different in some way.
       </para>
     </section>
   </chapter>
@@ -1622,7 +2683,7 @@ NAR #88757, TRA #12200
     <para>
       AltosDroid provides the same flight monitoring capabilities as
       AltosUI, but runs on Android devices and is designed to connect
-      to a TeleBT receiver over Bluetooth™. Altos Droid monitors
+      to a TeleBT receiver over Bluetooth™. AltosDroid monitors
       telemetry data, logging it to internal storage in the Android
       device, and presents that data in a UI the same way the 'Monitor
       Flight' window does in AltosUI.
@@ -1635,10 +2696,10 @@ NAR #88757, TRA #12200
     <section>
       <title>Installing AltosDroid</title>
       <para>
-       AltosDroid is included in the Google Play store. To install
-       it on your Android device, open open the Google Play Store
-       application and search for "altosdroid". Make sure you don't
-       have a space between "altos" and "droid" or you probably won't
+       AltosDroid is available from the Google Play store. To install
+       it on your Android device, open the Google Play Store
+       application and search for “altosdroid”. Make sure you don't
+       have a space between “altos” and “droid” or you probably won't
        find what you want. That should bring you to the right page
        from which you can download and install the application.
       </para>
@@ -1669,9 +2730,9 @@ NAR #88757, TRA #12200
       </para>
     </section>
     <section>
-      <title>Altos Droid Flight Monitoring</title>
+      <title>AltosDroid Flight Monitoring</title>
       <para>
-       Altos Droid is designed to mimic the AltosUI flight monitoring
+       AltosDroid is designed to mimic the AltosUI flight monitoring
        display, providing separate tabs for each stage of your rocket
        flight along with a tab containing a map of the local area
        with icons marking the current location of the altimeter and
@@ -1684,76 +2745,94 @@ NAR #88757, TRA #12200
           rocket is ready for flight. The first elements include red/green
           indicators, if any of these is red, you'll want to evaluate
           whether the rocket is ready to launch:
-          <itemizedlist>
-            <listitem>
-              <para>
-                Battery Voltage. This indicates whether the Li-Po battery
-                powering the TeleMetrum has sufficient charge to last for
-                the duration of the flight. A value of more than
-                3.7V is required for a 'GO' status.
-              </para>
-            </listitem>
-            <listitem>
-              <para>
-                Apogee Igniter Voltage. This indicates whether the apogee
-                igniter has continuity. If the igniter has a low
-                resistance, then the voltage measured here will be close
-                to the Li-Po battery voltage. A value greater than 3.2V is
-                required for a 'GO' status.
-              </para>
-            </listitem>
-            <listitem>
-              <para>
-                Main Igniter Voltage. This indicates whether the main
-                igniter has continuity. If the igniter has a low
-                resistance, then the voltage measured here will be close
-                to the Li-Po battery voltage. A value greater than 3.2V is
-                required for a 'GO' status.
-              </para>
-            </listitem>
-           <listitem>
-             <para>
-               On-board Data Logging. This indicates whether there is
-               space remaining on-board to store flight data for the
-               upcoming flight. If you've downloaded data, but failed
-               to erase flights, there may not be any space
-               left. TeleMetrum can store multiple flights, depending
-               on the configured maximum flight log size. TeleMini
-               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 transmit telemetry and fire
-               ejection charges at the proper times.
-             </para>
-           </listitem>
-            <listitem>
-              <para>
-                GPS Locked. For a TeleMetrum device, this indicates whether the GPS receiver is
-                currently able to compute position information. GPS requires
-                at least 4 satellites to compute an accurate position.
-              </para>
-            </listitem>
-            <listitem>
-              <para>
-                GPS Ready. For a TeleMetrum device, this indicates whether GPS has reported at least
-                10 consecutive positions without losing lock. This ensures
-                that the GPS receiver has reliable reception from the
-                satellites.
-              </para>
-            </listitem>
-          </itemizedlist>
-          <para>
-            The Launchpad tab also shows the computed launch pad position
-            and altitude, averaging many reported positions to improve the
-            accuracy of the fix.
-          </para>
-        </para>
+          <variablelist>
+           <varlistentry>
+             <term>Battery Voltage</term>
+             <listitem>
+               <para>
+                 This indicates whether the Li-Po battery
+                 powering the TeleMetrum has sufficient charge to last for
+                 the duration of the flight. A value of more than
+                 3.8V is required for a 'GO' status.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>Apogee Igniter Voltage</term>
+             <listitem>
+               <para>
+                 This indicates whether the apogee
+                 igniter has continuity. If the igniter has a low
+                 resistance, then the voltage measured here will be close
+                 to the Li-Po battery voltage. A value greater than 3.2V is
+                 required for a 'GO' status.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>Main Igniter Voltage</term>
+             <listitem>
+               <para>
+                 This indicates whether the main
+                 igniter has continuity. If the igniter has a low
+                 resistance, then the voltage measured here will be close
+                 to the Li-Po battery voltage. A value greater than 3.2V is
+                 required for a 'GO' status.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>On-board Data Logging</term>
+             <listitem>
+               <para>
+                 This indicates whether there is
+                 space remaining on-board to store flight data for the
+                 upcoming flight. If you've downloaded data, but failed
+                 to erase flights, there may not be any space
+                 left. TeleMetrum can store multiple flights, depending
+                 on the configured maximum flight log size. TeleMini
+                 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 transmit telemetry and fire
+                 ejection charges at the proper times.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>GPS Locked</term>
+             <listitem>
+               <para>
+                 For a TeleMetrum or TeleMega device, this indicates whether the GPS receiver is
+                 currently able to compute position information. GPS requires
+                 at least 4 satellites to compute an accurate position.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>GPS Ready</term>
+             <listitem>
+               <para>
+                 For a TeleMetrum or TeleMega device, this indicates whether GPS has reported at least
+                 10 consecutive positions without losing lock. This ensures
+                 that the GPS receiver has reliable reception from the
+                 satellites.
+               </para>
+             </listitem>
+           </varlistentry>
+          </variablelist>
+       </para>
+       <para>
+         The Launchpad tab also shows the computed launch pad position
+         and altitude, averaging many reported positions to improve the
+         accuracy of the fix.
+       </para>
       </section>
     </section>
     <section>
       <title>Downloading Flight Logs</title>
       <para>
-       Altos Droid always saves every bit of telemetry data it
+       AltosDroid always saves every bit of telemetry data it
        receives. To download that to a computer for use with AltosUI,
        simply remove the SD card from your Android device, or connect
        your device to your computer's USB port and browse the files
@@ -1775,20 +2854,22 @@ NAR #88757, TRA #12200
       <section>
         <title>In the Rocket</title>
         <para>
-          In the rocket itself, you just need a <ulink url="http://www.altusmetrum.org/TeleMetrum/">TeleMetrum</ulink> or
-         <ulink url="http://www.altusmetrum.org/TeleMini/">TeleMini</ulink> board and
+          In the rocket itself, you just need a flight computer and
           a single-cell, 3.7 volt nominal Li-Po rechargeable battery.  An 
          850mAh battery weighs less than a 9V alkaline battery, and will 
-         run a TeleMetrum for hours.
-         A 110mAh battery weighs less than a triple A battery and will run a TeleMetrum for
-         a few hours, or a TeleMini for much (much) longer.
+         run a TeleMetrum or TeleMega for hours.
+         A 110mAh battery weighs less than a triple A battery and is a good
+         choice for use with TeleMini.
         </para>
         <para>
-          By default, we ship the altimeters with a simple wire antenna.  If your
-          electronics bay or the air-frame it resides within is made of carbon fiber,
-          which is opaque to RF signals, you may choose to have an SMA connector
-          installed so that you can run a coaxial cable to an antenna mounted
-          elsewhere in the rocket.
+          By default, we ship flight computers with a simple wire antenna.  
+         If your electronics bay or the air-frame it resides within is made 
+         of carbon fiber, which is opaque to RF signals, you may prefer to 
+         install an SMA connector so that you can run a coaxial cable to an 
+         antenna mounted elsewhere in the rocket.  However, note that the 
+         GPS antenna is fixed on all current products, so you really want
+         to install the flight computer in a bay made of RF-transparent
+         materials if at all possible.
         </para>
       </section>
       <section>
@@ -1807,6 +2888,11 @@ NAR #88757, TRA #12200
          Linux, Mac OS and Windows. There's also a suite of C tools
          for Linux which can perform most of the same tasks.
         </para>
+        <para>
+         Alternatively, a TeleBT attached with an SMA to BNC adapter at the
+         feed point of a hand-held yagi used in conjunction with an Android
+         device running AltosDroid makes an outstanding ground station.
+        </para>
         <para>
           After the flight, you can use the radio link to extract the more detailed data
           logged in either TeleMetrum or TeleMini devices, or you can use a mini USB cable to plug into the
@@ -1816,37 +2902,50 @@ NAR #88757, TRA #12200
           of digital cameras and other modern electronic stuff will work fine.
         </para>
         <para>
-          If your TeleMetrum-equipped rocket lands out of sight, you may enjoy having a hand-held GPS
-          receiver, so that you can put in a way-point for the last reported rocket
-          position before touch-down.  This makes looking for your rocket a lot like
-          Geo-Caching... just go to the way-point and look around starting from there.
+          If your rocket lands out of sight, you may enjoy having a hand-held 
+         GPS receiver, so that you can put in a way-point for the last 
+         reported rocket position before touch-down.  This makes looking for 
+         your rocket a lot like Geo-Caching... just go to the way-point and 
+         look around starting from there.  AltosDroid on an Android device
+         with GPS receiver works great for this, too!
         </para>
         <para>
-          You may also enjoy having a ham radio "HT" that covers the 70cm band... you
+          You may also enjoy having a ham radio “HT” that covers the 70cm band... you
           can use that with your antenna to direction-find the rocket on the ground
           the same way you can use a Walston or Beeline tracker.  This can be handy
           if the rocket is hiding in sage brush or a tree, or if the last GPS position
           doesn't get you close enough because the rocket dropped into a canyon, or
           the wind is blowing it across a dry lake bed, or something like that...  Keith
-          and Bdale both currently own and use the Yaesu VX-7R at launches.
+          currently uses a Yaesu VX-7R, Bdale has a Baofung UV-5R
+         which isn't as nice, but was a whole lot cheaper.
         </para>
         <para>
           So, to recap, on the ground the hardware you'll need includes:
           <orderedlist inheritnum='inherit' numeration='arabic'>
             <listitem>
-              an antenna and feed-line or adapter
+              <para>
+             an antenna and feed-line or adapter
+             </para>
             </listitem>
             <listitem>
-              a TeleDongle
+              <para>
+             a TeleDongle
+             </para>
             </listitem>
             <listitem>
-              a notebook computer
+              <para>
+             a notebook computer
+             </para>
             </listitem>
             <listitem>
-              optionally, a hand-held GPS receiver
+              <para>
+             optionally, a hand-held GPS receiver
+             </para>
             </listitem>
             <listitem>
-              optionally, an HT or receiver covering 435 MHz
+              <para>
+             optionally, an HT or receiver covering 435 MHz
+             </para>
             </listitem>
           </orderedlist>
         </para>
@@ -1884,25 +2983,20 @@ NAR #88757, TRA #12200
       </section>
       <section>
         <title>Future Plans</title>
+       <para>
+         We've designed a simple GPS based radio tracker called TeleGPS.  
+         If all goes well, we hope to introduce this in the first
+         half of 2014.
+       </para>
         <para>
-          In the future, we intend to offer "companion boards" for the rocket 
-         that will plug in to TeleMetrum to collect additional data, provide 
-         more pyro channels, and so forth.  
-        </para>
-        <para>
-         Also under design is a new flight computer with more sensors, more
-         pyro channels, and a more powerful radio system designed for use
-         in multi-stage, complex, and extreme altitude projects.
-        </para>
-        <para>
-          We are also working on alternatives to TeleDongle.  One is a
-         a stand-alone, hand-held ground terminal that will allow monitoring 
-         the rocket's status, collecting data during flight, and logging data 
-         after flight without the need for a notebook computer on the
-          flight line.  Particularly since it is so difficult to read most 
-         notebook screens in direct sunlight, we think this will be a great 
-         thing to have.  We are also working on a TeleDongle variant with
-         Bluetooth that will work with Android phones and tablets.
+          We have designed and prototyped several “companion boards” that 
+         can attach to the companion connector on TeleMetrum and TeleMega
+         flight computers to collect more data, provide more pyro channels, 
+         and so forth.  We do not yet know if or when any of these boards
+         will be produced in enough quantity to sell.  If you have specific
+         interests for data collection or control of events in your rockets
+         beyond the capabilities of our existing productions, please let 
+         us know!
         </para>
         <para>
           Because all of our work is open, both the hardware designs and the 
@@ -1923,33 +3017,40 @@ NAR #88757, TRA #12200
     <para>
       Building high-power rockets that fly safely is hard enough. Mix
       in some sophisticated electronics and a bunch of radio energy
-      and oftentimes you find few perfect solutions. This chapter
+      and some creativity and/or compromise may be required. This chapter
       contains some suggestions about how to install Altus Metrum
-      products into the rocket air-frame, including how to safely and
+      products into a rocket air-frame, including how to safely and
       reliably mix a variety of electronics into the same air-frame.
     </para>
     <section>
       <title>Mounting the Altimeter</title>
       <para>
        The first consideration is to ensure that the altimeter is
-       securely fastened to the air-frame. For TeleMetrum, we use
-       nylon standoffs and nylon screws; they're good to at least 50G
-       and cannot cause any electrical issues on the board. For
-       TeleMini, we usually cut small pieces of 1/16" balsa to fit
+       securely fastened to the air-frame. For most of our products, we 
+       prefer nylon standoffs and nylon screws; they're good to at least 50G
+       and cannot cause any electrical issues on the board.  Metal screws
+       and standoffs are fine, too, just be careful to avoid electrical
+       shorts!  For TeleMini v1.0, we usually cut small pieces of 1/16 inch 
+       balsa to fit
        under the screw holes, and then take 2x56 nylon screws and
        screw them through the TeleMini mounting holes, through the
        balsa and into the underlying material.
       </para>
       <orderedlist inheritnum='inherit' numeration='arabic'>
        <listitem>
-         Make sure TeleMetrum is aligned precisely along the axis of
-         acceleration so that the accelerometer can accurately
-         capture data during the flight.
+         <para>
+           Make sure accelerometer-equipped products like TeleMetrum and
+           TeleMega are aligned precisely along the axis of
+           acceleration so that the accelerometer can accurately
+           capture data during the flight.
+         </para>
        </listitem>
        <listitem>
-         Watch for any metal touching components on the
-         board. Shorting out connections on the bottom of the board
-         can cause the altimeter to fail during flight.
+         <para>
+           Watch for any metal touching components on the
+           board. Shorting out connections on the bottom of the board
+           can cause the altimeter to fail during flight.
+         </para>
        </listitem>
       </orderedlist>
     </section>
@@ -1977,7 +3078,7 @@ NAR #88757, TRA #12200
        culprit here -- CF is a good conductor and will effectively
        shield the antenna, dramatically reducing signal strength and
        range. Metallic flake paint is another effective shielding
-       material which is to be avoided around any antennas.
+       material which should be avoided around any antennas.
       </para>
       <para>
        If the ebay is large enough, it can be convenient to simply
@@ -1998,7 +3099,7 @@ NAR #88757, TRA #12200
        consuming very little space.
       </para>
       <para>
-       If you need to place the antenna at a distance from the
+       If you need to place the UHF antenna at a distance from the
        altimeter, you can replace the antenna with an edge-mounted
        SMA connector, and then run 50Ω coax from the board to the
        antenna. Building a remote antenna is beyond the scope of this
@@ -2008,25 +3109,29 @@ NAR #88757, TRA #12200
     <section>
       <title>Preserving GPS Reception</title>
       <para>
-       The GPS antenna and receiver in TeleMetrum are highly
-       sensitive and normally have no trouble tracking enough
+       The GPS antenna and receiver used in TeleMetrum and TeleMega is 
+       highly sensitive and normally have no trouble tracking enough
        satellites to provide accurate position information for
-       recovering the rocket. However, there are many ways to
-       attenuate the GPS signal.
+       recovering the rocket. However, there are many ways the GPS signal
+       can end up attenuated, negatively affecting GPS performance. 
       <orderedlist inheritnum='inherit' numeration='arabic'>
        <listitem>
-         Conductive tubing or coatings. Carbon fiber and metal
-         tubing, or metallic paint will all dramatically attenuate the
-         GPS signal. We've never heard of anyone successfully
-         receiving GPS from inside these materials.
+         <para>
+           Conductive tubing or coatings. Carbon fiber and metal
+           tubing, or metallic paint will all dramatically attenuate the
+           GPS signal. We've never heard of anyone successfully
+           receiving GPS from inside these materials.
+         </para>
        </listitem>
        <listitem>
-         Metal components near the GPS patch antenna. These will
-         de-tune the patch antenna, changing the resonant frequency
-         away from the L1 carrier and reduce the effectiveness of the
-         antenna. You can place as much stuff as you like beneath the
-         antenna as that's covered with a ground plane. But, keep
-         wires and metal out from above the patch antenna.
+         <para>
+           Metal components near the GPS patch antenna. These will
+           de-tune the patch antenna, changing the resonant frequency
+           away from the L1 carrier and reduce the effectiveness of the
+           antenna. You can place as much stuff as you like beneath the
+           antenna as that's covered with a ground plane. But, keep
+           wires and metal out from above the patch antenna.
+         </para>
        </listitem>
       </orderedlist>
       </para>
@@ -2053,16 +3158,21 @@ NAR #88757, TRA #12200
       </para>
       <itemizedlist>
        <listitem>
-         Keep wires from different circuits apart. Moving circuits
-         further apart will reduce RFI.
+         <para>
+           Keep wires from different circuits apart. Moving circuits
+           further apart will reduce RFI.
+         </para>
        </listitem>
        <listitem>
+         <para>
          Avoid parallel wires from different circuits. The longer two
          wires run parallel to one another, the larger the amount of
          transferred energy. Cross wires at right angles to reduce
          RFI.
+         </para>
        </listitem>
        <listitem>
+         <para>
          Twist wires from the same circuits. Two wires the same
          distance from the transmitter will get the same amount of
          induced energy which will then cancel out. Any time you have
@@ -2070,14 +3180,17 @@ NAR #88757, TRA #12200
          even out distances and reduce RFI. For altimeters, this
          includes battery leads, switch hookups and igniter
          circuits.
+         </para>
        </listitem>
        <listitem>
+         <para>
          Avoid resonant lengths. Know what frequencies are present
          in the environment and avoid having wire lengths near a
-         natural resonant length. Altusmetrum products transmit on the
+         natural resonant length. Altus Metrum products transmit on the
          70cm amateur band, so you should avoid lengths that are a
-         simple ratio of that length; essentially any multiple of 1/4
+         simple ratio of that length; essentially any multiple of ¼
          of the wavelength (17.5cm).
+         </para>
        </listitem>
       </itemizedlist>
     </section>
@@ -2099,10 +3212,10 @@ NAR #88757, TRA #12200
        decreasing pressure.
       </para>
       <para>
-       The barometric sensor in the altimeter is quite sensitive to
-       chemical damage from the products of APCP or BP combustion, so
-       make sure the ebay is carefully sealed from any compartment
-       which contains ejection charges or motors.
+       All barometric sensors are quite sensitive to chemical damage from 
+       the products of APCP or BP combustion, so make sure the ebay is 
+       carefully sealed from any compartment which contains ejection 
+       charges or motors.
       </para>
     </section>
     <section>
@@ -2137,11 +3250,11 @@ NAR #88757, TRA #12200
   <chapter>
     <title>Updating Device Firmware</title>
     <para>
-      The big concept to understand is that you have to use a
-      TeleDongle as a programmer to update a TeleMetrum or TeleMini,
-      and a TeleMetrum or other TeleDongle to program the TeleDongle
-      Due to limited memory resources in the cc1111, we don't support
-      programming directly over USB. 
+      TeleMega, TeleMetrum v2 and EasyMini are all programmed directly
+      over their USB connectors (self programming). TeleMetrum v1, TeleMini and
+      TeleDongle 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.
     </para>
     <para>
       You may wish to begin by ensuring you have current firmware images.
@@ -2153,65 +3266,219 @@ NAR #88757, TRA #12200
       version from <ulink url="http://www.altusmetrum.org/AltOS/"/>.
     </para>
     <para>
-      We recommend updating the altimeter first, before updating TeleDongle.
+      If you need to update the firmware on a TeleDongle, we recommend 
+      updating the altimeter first, before updating TeleDongle.  However,
+      note that TeleDongle rarely need to be updated.  Any firmware version
+      1.0.1 or later will work, version 1.2.1 may have improved receiver
+      performance slightly.
+    </para>
+    <para>
+      Self-programmable devices (TeleMega, TeleMetrum v2 and EasyMini)
+      are reprogrammed by connecting them to your computer over USB
     </para>
     <section>
-      <title>Updating TeleMetrum Firmware</title>
+      <title>
+       Updating TeleMega, TeleMetrum v2 or EasyMini Firmware
+      </title>
       <orderedlist inheritnum='inherit' numeration='arabic'>
+       <listitem>
+         <para>
+           Attach a battery and power switch to the target
+           device. Power up the device.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Using a Micro USB cable, connect the target device to your
+           computer's USB socket.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Run AltosUI, and select 'Flash Image' from the File menu.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Select the target device in the Device Selection dialog.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Select the image you want to flash to the device, which
+           should have a name in the form
+           &lt;product&gt;-v&lt;product-version&gt;-&lt;software-version&gt;.ihx, such
+           as TeleMega-v1.0-1.3.0.ihx.
+         </para>
+       </listitem>
+        <listitem>
+         <para>
+           Make sure the configuration parameters are reasonable
+           looking. If the serial number and/or RF configuration
+           values aren't right, you'll need to change them.
+         </para>
+        </listitem>
         <listitem>
+         <para>
+           Hit the 'OK' button and the software should proceed to flash
+           the device with new firmware, showing a progress bar.
+         </para>
+        </listitem>
+       <listitem>
+         <para>
+           Verify that the device is working by using the 'Configure
+           Altimeter' item to check over the configuration.
+         </para>
+       </listitem>
+      </orderedlist>
+      <section>
+       <title>Recovering From Self-Flashing Failure</title>
+       <para>
+         If the firmware loading fails, it can leave the device
+         unable to boot. Not to worry, you can force the device to
+         start the boot loader instead, which will let you try to
+         flash the device again.
+       </para>
+       <para>
+         On each device, connecting two pins from one of the exposed
+         connectors will force the boot loader to start, even if the
+         regular operating system has been corrupted in some way.
+       </para>
+       <variablelist>
+         <varlistentry>
+           <term>TeleMega</term>
+           <listitem>
+             <para>
+               Connect pin 6 and pin 1 of the companion connector. Pin 1
+               can be identified by the square pad around it, and then
+               the pins could sequentially across the board. Be very
+               careful to <emphasis>not</emphasis> short pin 8 to
+               anything as that is connected directly to the battery. Pin
+               7 carries 3.3V and the board will crash if that is
+               connected to pin 1, but shouldn't damage the board.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>TeleMetrum v2</term>
+           <listitem>
+             <para>
+               Connect pin 6 and pin 1 of the companion connector. Pin 1
+               can be identified by the square pad around it, and then
+               the pins could sequentially across the board. Be very
+               careful to <emphasis>not</emphasis> short pin 8 to
+               anything as that is connected directly to the battery. Pin
+               7 carries 3.3V and the board will crash if that is
+               connected to pin 1, but shouldn't damage the board.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>EasyMini</term>
+           <listitem>
+             <para>
+               Connect pin 6 and pin 1 of the debug connector, which is
+               the six holes next to the beeper. Pin 1 can be identified
+               by the square pad around it, and then the pins could
+               sequentially across the board, making Pin 6 the one on the
+               other end of the row.
+             </para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </section>
+    </section>
+    <section>
+      <title>Pair Programming</title>
+      <para>
+       The big concept to understand is that you have to use a
+       TeleMega, TeleMetrum or TeleDongle as a programmer to update a
+       pair programmed device. Due to limited memory resources in the
+       cc1111, we don't support programming directly over USB for these
+       devices.
+      </para>
+    </section>
+    <section>
+      <title>Updating TeleMetrum v1.x Firmware</title>
+      <orderedlist inheritnum='inherit' numeration='arabic'>
+        <listitem>
+         <para>
           Find the 'programming cable' that you got as part of the starter
           kit, that has a red 8-pin MicroMaTch connector on one end and a
           red 4-pin MicroMaTch connector on the other end.
+         </para>
         </listitem>
         <listitem>
+         <para>
           Take the 2 screws out of the TeleDongle case to get access
           to the circuit board.
+         </para>
         </listitem>
         <listitem>
+         <para>
           Plug the 8-pin end of the programming cable to the
           matching connector on the TeleDongle, and the 4-pin end to the
           matching connector on the TeleMetrum.
          Note that each MicroMaTch connector has an alignment pin that
          goes through a hole in the PC board when you have the cable
          oriented correctly.
+         </para>
         </listitem>
         <listitem>
+         <para>
           Attach a battery to the TeleMetrum board.
+         </para>
         </listitem>
         <listitem>
+         <para>
           Plug the TeleDongle into your computer's USB port, and power
           up the TeleMetrum.
+         </para>
         </listitem>
         <listitem>
+         <para>
           Run AltosUI, and select 'Flash Image' from the File menu.
+         </para>
         </listitem>
         <listitem>
+         <para>
           Pick the TeleDongle device from the list, identifying it as the
           programming device.
+         </para>
         </listitem>
         <listitem>
+         <para>
           Select the image you want put on the TeleMetrum, which should have a
           name in the form telemetrum-v1.2-1.0.0.ihx.  It should be visible
        in the default directory, if not you may have to poke around
        your system to find it.
+         </para>
         </listitem>
         <listitem>
+         <para>
           Make sure the configuration parameters are reasonable
           looking. If the serial number and/or RF configuration
           values aren't right, you'll need to change them.
+         </para>
         </listitem>
         <listitem>
+         <para>
           Hit the 'OK' button and the software should proceed to flash
           the TeleMetrum with new firmware, showing a progress bar.
+         </para>
         </listitem>
         <listitem>
+         <para>
           Confirm that the TeleMetrum board seems to have updated OK, which you
           can do by plugging in to it over USB and using a terminal program
           to connect to the board and issue the 'v' command to check
           the version, etc.
+         </para>
         </listitem>
         <listitem>
+         <para>
           If something goes wrong, give it another try.
+         </para>
         </listitem>
       </orderedlist>
     </section>
@@ -2219,16 +3486,20 @@ NAR #88757, TRA #12200
       <title>Updating TeleMini Firmware</title>
       <orderedlist inheritnum='inherit' numeration='arabic'>
         <listitem>
+<para>
          You'll need a special 'programming cable' to reprogram the
-         TeleMini. It's available on the Altus Metrum web store, or
-         you can make your own using an 8-pin MicroMaTch connector on
-         one end and a set of four pins on the other.
-        </listitem>
+         TeleMini.  You can make your own using an 8-pin MicroMaTch 
+         connector on one end and a set of four pins on the other.
+        </para>
+</listitem>
         <listitem>
+<para>
           Take the 2 screws out of the TeleDongle case to get access
           to the circuit board.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Plug the 8-pin end of the programming cable to the matching
           connector on the TeleDongle, and the 4-pins into the holes
           in the TeleMini circuit board.  Note that the MicroMaTch
@@ -2236,44 +3507,63 @@ NAR #88757, TRA #12200
           the PC board when you have the cable oriented correctly, and
           that pin 1 on the TeleMini board is marked with a square pad
           while the other pins have round pads.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Attach a battery to the TeleMini board.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Plug the TeleDongle into your computer's USB port, and power
           up the TeleMini
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Run AltosUI, and select 'Flash Image' from the File menu.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Pick the TeleDongle device from the list, identifying it as the
           programming device.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Select the image you want put on the TeleMini, 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 it.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Make sure the configuration parameters are reasonable
           looking. If the serial number and/or RF configuration
           values aren't right, you'll need to change them.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Hit the 'OK' button and the software should proceed to flash
           the TeleMini with new firmware, showing a progress bar.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Confirm that the TeleMini 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 "flight" mode and listening for telemetry.
-        </listitem>
+         letting it come up in “flight” mode and listening for telemetry.
+        </para>
+</listitem>
         <listitem>
+<para>
           If something goes wrong, give it another try.
-        </listitem>
+        </para>
+</listitem>
       </orderedlist>
     </section>
     <section>
@@ -2284,68 +3574,94 @@ NAR #88757, TRA #12200
        </para>
       <orderedlist inheritnum='inherit' numeration='arabic'>
         <listitem>
+<para>
           Find the 'programming cable' that you got as part of the starter
           kit, that has a red 8-pin MicroMaTch connector on one end and a
           red 4-pin MicroMaTch connector on the other end.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
          Find the USB cable that you got as part of the starter kit, and
-         plug the "mini" end in to the mating connector on TeleMetrum or TeleDongle.
-        </listitem>
+         plug the “mini” end in to the mating connector on TeleMetrum or TeleDongle.
+        </para>
+</listitem>
         <listitem>
+<para>
           Take the 2 screws out of the TeleDongle case to get access
           to the circuit board.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Plug the 8-pin end of the programming cable to the
           matching connector on the programmer, and the 4-pin end to the
           matching connector on the TeleDongle.
          Note that each MicroMaTch connector has an alignment pin that
          goes through a hole in the PC board when you have the cable
          oriented correctly.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Attach a battery to the TeleMetrum board if you're using one.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Plug both the programmer and the TeleDongle into your computer's USB
          ports, and power up the programmer.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Run AltosUI, and select 'Flash Image' from the File menu.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Pick the programmer device from the list, identifying it as the
           programming device.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Select the image you want put on the TeleDongle, which should have a
           name in the form teledongle-v0.2-1.0.0.ihx.  It should be visible
        in the default directory, if not you may have to poke around
        your system to find it.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Make sure the configuration parameters are reasonable
           looking. If the serial number and/or RF configuration
           values aren't right, you'll need to change them.  The TeleDongle
-         serial number is on the "bottom" of the circuit board, and can
+         serial number is on the “bottom” of the circuit board, and can
          usually be read through the translucent blue plastic case without
          needing to remove the board from the case.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Hit the 'OK' button and the software should proceed to flash
           the TeleDongle with new firmware, showing a progress bar.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           Confirm that the TeleDongle board seems to have updated OK, which you
           can do by plugging in to it over USB and using a terminal program
           to connect to the board and issue the 'v' command to check
           the version, etc.  Once you're happy, remove the programming cable
          and put the cover back on the TeleDongle.
-        </listitem>
+        </para>
+</listitem>
         <listitem>
+<para>
           If something goes wrong, give it another try.
-        </listitem>
+        </para>
+</listitem>
       </orderedlist>
       <para>
         Be careful removing the programming cable from the locking 8-pin
@@ -2360,7 +3676,142 @@ NAR #88757, TRA #12200
   <chapter>
     <title>Hardware Specifications</title>
     <section>
-      <title>TeleMetrum Specifications</title>
+      <title>
+       TeleMega Specifications
+      </title>
+      <itemizedlist>
+       <listitem>
+         <para>
+           Recording altimeter for model rocketry.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Supports dual deployment and four auxiliary pyro channels
+           (a total of 6 events).
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           70cm 40mW ham-band transceiver for telemetry down-link.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Barometric pressure sensor good to 100k feet MSL.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           1-axis high-g accelerometer for motor characterization, capable of
+           +/- 102g.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           9-axis IMU including integrated 3-axis accelerometer,
+           3-axis gyroscope and 3-axis magnetometer.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           On-board, integrated uBlox Max 7 GPS receiver with 5Hz update rate capability.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           On-board 8 Megabyte non-volatile memory for flight data storage.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           USB interface for battery charging, configuration, and data recovery.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Fully integrated support for Li-Po rechargeable batteries.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Can use either main system Li-Po or optional separate pyro battery
+           to fire e-matches.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           3.25 x 1.25 inch board designed to fit inside 38mm air-frame coupler tube.
+         </para>
+       </listitem>
+      </itemizedlist>
+    </section>
+    <section>
+      <title>
+       TeleMetrum v2 Specifications
+      </title>
+      <itemizedlist>
+       <listitem>
+         <para>
+           Recording altimeter for model rocketry.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Supports dual deployment (can fire 2 ejection charges).
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           70cm, 40mW ham-band transceiver for telemetry down-link.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Barometric pressure sensor good to 100k feet MSL.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           1-axis high-g accelerometer for motor characterization, capable of
+           +/- 102g.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           On-board, integrated uBlox Max 7 GPS receiver with 5Hz update rate capability.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           On-board 8 Megabyte non-volatile memory for flight data storage.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           USB interface for battery charging, configuration, and data recovery.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Fully integrated support for Li-Po rechargeable batteries.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Uses Li-Po to fire e-matches, can be modified to support 
+           optional separate pyro battery if needed.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           2.75 x 1 inch board designed to fit inside 29mm air-frame coupler tube.
+         </para>
+       </listitem>
+      </itemizedlist>
+    </section>
+    <section>
+      <title>TeleMetrum v1 Specifications</title>
       <itemizedlist>
        <listitem>
          <para>
@@ -2374,7 +3825,7 @@ NAR #88757, TRA #12200
        </listitem>
        <listitem>
          <para>
-           70cm ham-band transceiver for telemetry down-link.
+           70cm, 10mW ham-band transceiver for telemetry down-link.
          </para>
        </listitem>
        <listitem>
@@ -2422,7 +3873,9 @@ NAR #88757, TRA #12200
       </itemizedlist>
     </section>
     <section>
-      <title>TeleMini Specifications</title>
+      <title>
+       TeleMini v2.0 Specifications
+      </title>
       <itemizedlist>
        <listitem>
          <para>
@@ -2436,7 +3889,61 @@ NAR #88757, TRA #12200
        </listitem>
        <listitem>
          <para>
-           70cm ham-band transceiver for telemetry down-link.
+           70cm, 10mW ham-band transceiver for telemetry down-link.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Barometric pressure sensor good to 100k feet MSL.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           On-board 1 megabyte non-volatile memory for flight data storage.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           USB interface for configuration, and data recovery.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Support for Li-Po rechargeable batteries (using an
+           external charger), or any 3.7-15V external battery.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Uses Li-Po to fire e-matches, can be modified to support 
+           optional separate pyro battery if needed.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           1.5 x .8 inch board designed to fit inside 24mm air-frame coupler tube.
+         </para>
+       </listitem>
+      </itemizedlist>
+    </section>
+    <section>
+      <title>
+       TeleMini v1.0 Specifications
+      </title>
+      <itemizedlist>
+       <listitem>
+         <para>
+           Recording altimeter for model rocketry.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Supports dual deployment (can fire 2 ejection charges).
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           70cm, 10mW ham-band transceiver for telemetry down-link.
          </para>
        </listitem>
        <listitem>
@@ -2472,42 +3979,96 @@ NAR #88757, TRA #12200
        </listitem>
       </itemizedlist>
     </section>
+    <section>
+      <title>
+       EasyMini Specifications
+      </title>
+      <itemizedlist>
+       <listitem>
+         <para>
+           Recording altimeter for model rocketry.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Supports dual deployment (can fire 2 ejection charges).
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Barometric pressure sensor good to 100k feet MSL.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           On-board 1 megabyte non-volatile memory for flight data storage.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           USB interface for configuration, and data recovery.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Support for Li-Po rechargeable batteries (using an
+           external charger), or any 3.7-15V external battery.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           Uses Li-Po to fire e-matches, can be modified to support 
+           optional separate pyro battery if needed.
+         </para>
+       </listitem>
+       <listitem>
+         <para>
+           1.5 x .8 inch board designed to fit inside 24mm air-frame coupler tube.
+         </para>
+       </listitem>
+      </itemizedlist>
+    </section>
   </chapter>
   <chapter>
     <title>FAQ</title>
       <para>
-        TeleMetrum seems to shut off when disconnected from the
-        computer.  Make sure the battery is adequately charged.  Remember the
+        <emphasis>TeleMetrum seems to shut off when disconnected from the
+        computer.</emphasis>  <?linebreak?>
+       Make sure the battery is adequately charged.  Remember the
         unit will pull more power than the USB port can deliver before the
-        GPS enters "locked" mode.  The battery charges best when TeleMetrum
+        GPS enters “locked” mode.  The battery charges best when TeleMetrum
         is turned off.
       </para>
       <para>
-        It's impossible to stop the TeleDongle when it's in "p" mode, I have
-        to unplug the USB cable?  Make sure you have tried to "escape out" of
+        <emphasis>It's impossible to stop the TeleDongle when it's in “p” mode, I have
+        to unplug the USB cable? </emphasis><?linebreak?>
+       Make sure you have tried to “escape out” of
         this mode.  If this doesn't work the reboot procedure for the
         TeleDongle *is* to simply unplug it. 'cu' however will retain it's
-        outgoing buffer IF your "escape out" ('~~') does not work.
+        outgoing buffer IF your “escape out” ('~~') does not work.
         At this point using either 'ao-view' (or possibly
         'cutemon') instead of 'cu' will 'clear' the issue and allow renewed
         communication.
       </para>
       <para>
-        The amber LED (on the TeleMetrum) lights up when both
-        battery and USB are connected. Does this mean it's charging?
+        <emphasis>The amber LED (on the TeleMetrum) lights up when both
+        battery and USB are connected. Does this mean it's charging? 
+       </emphasis><?linebreak?>
         Yes, the yellow LED indicates the charging at the 'regular' rate.
         If the led is out but the unit is still plugged into a USB port,
         then the battery is being charged at a 'trickle' rate.
       </para>
       <para>
-        There are no "dit-dah-dah-dit" sound or lights like the manual mentions?
-        That's the "pad" mode.  Weak batteries might be the problem.
-        It is also possible that the TeleMetrum is horizontal and the output
-        is instead a "dit-dit" meaning 'idle'. For TeleMini, it's possible that
-       it received a command packet which would have left it in "pad" mode.
+        <emphasis>There are no “dit-dah-dah-dit” sound or lights like the manual 
+       mentions?</emphasis><?linebreak?>
+        That's the “pad” mode.  Weak batteries might be the problem.
+        It is also possible that the flight computer is horizontal and the 
+       output
+        is instead a “dit-dit” meaning 'idle'. For TeleMini, it's possible that
+       it received a command packet which would have left it in “pad” mode.
       </para>
       <para>
-        How do I save flight data?
+        <emphasis>How do I save flight data?</emphasis><?linebreak?>
         Live telemetry is written to file(s) whenever AltosUI is connected
         to the TeleDongle.  The file area defaults to ~/TeleMetrum
         but is easily changed using the menus in AltosUI. The files that
@@ -2645,18 +4206,18 @@ NAR #88757, TRA #12200
     </para>
     <para>
       Now might be a good time to take a break and read the rest of this
-      manual, particularly about the two "modes" that the altimeters
+      manual, particularly about the two “modes” that the altimeters
       can be placed in. TeleMetrum uses the position of the device when booting
-      up will determine whether the unit is in "pad" or "idle" mode. TeleMini
-      enters "idle" mode when it receives a command packet within the first 5 seconds
-      of being powered up, otherwise it enters "pad" mode.
+      up will determine whether the unit is in “pad” or “idle” mode. TeleMini
+      enters “idle” mode when it receives a command packet within the first 5 seconds
+      of being powered up, otherwise it enters “pad” mode.
     </para>
     <para>
       You can access an altimeter in idle mode from the TeleDongle's USB
       connection using the radio link
       by issuing a 'p' command to the TeleDongle. Practice connecting and
       disconnecting ('~~' while using 'cu') from the altimeter.  If
-      you cannot escape out of the "p" command, (by using a '~~' when in
+      you cannot escape out of the “p” command, (by using a '~~' when in
       CU) then it is likely that your kernel has issues.  Try a newer version.
     </para>
     <para>
@@ -2666,7 +4227,7 @@ NAR #88757, TRA #12200
       is in 'idle mode' and then place the
       rocket vertically on the launch pad, walk away and then issue a
       reboot command.  The altimeter will reboot and start sending data
-      having changed to the "pad" mode. If the TeleDongle is not receiving
+      having changed to the “pad” mode. If the TeleDongle is not receiving
       this data, you can disconnect 'cu' from the TeleDongle using the
       procedures mentioned above and THEN connect to the TeleDongle from
       inside 'ao-view'. If this doesn't work, disconnect from the
@@ -2727,46 +4288,79 @@ NAR #88757, TRA #12200
       These images, when printed, provide precise templates for the
       mounting holes in Altus Metrum flight computers
     </para>
+    <section>
+      <title>TeleMega template</title>
+      <para>
+       TeleMega has overall dimensions of 1.250 x 3.250 inches, and
+       the mounting holes are sized for use with 4-40 or M3 screws.
+      </para>
+      <informalfigure>
+       <mediaobject id="TeleMegaTemplate">
+         <imageobject>
+           <imagedata format="SVG" fileref="telemega-outline.svg"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
+    </section>
     <section>
       <title>TeleMetrum template</title>
       <para>
        TeleMetrum has overall dimensions of 1.000 x 2.750 inches, and the
        mounting holes are sized for use with 4-40 or M3 screws.
       </para>
-      <mediaobject id="TeleMetrumTemplate">
-       <imageobject>
-         <imagedata format="SVG" fileref="telemetrum.svg"/>
-       </imageobject>
-      </mediaobject>
+      <informalfigure>
+       <mediaobject id="TeleMetrumTemplate">
+         <imageobject>
+           <imagedata format="SVG" fileref="telemetrum.svg"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
+    </section>
+    <section>
+      <title>TeleMini v2/EasyMini template</title>
+      <para>
+       TeleMini v2 and EasyMini have overall dimensions of 0.800 x 1.500 inches, and the
+       mounting holes are sized for use with 4-40 or M3 screws.
+      </para>
+      <informalfigure>
+       <mediaobject id="MiniTemplate">
+         <imageobject>
+           <imagedata format="SVG" fileref="easymini-outline.svg"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
     </section>
     <section>
-      <title>TeleMini template</title>
+      <title>TeleMini v1 template</title>
       <para>
        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.
       </para>
-      <mediaobject id="TeleMiniTemplate">
-       <imageobject>
-         <imagedata format="SVG" fileref="telemini.svg"/>
-       </imageobject>
-      </mediaobject>
+      <informalfigure>
+       <mediaobject id="TeleMiniTemplate">
+         <imageobject>
+           <imagedata format="SVG" fileref="telemini.svg"/>
+         </imageobject>
+       </mediaobject>
+      </informalfigure>
     </section>
   </appendix>
   <appendix>
       <title>Calibration</title>
       <para>
-        There are only two calibrations required for a TeleMetrum board, and
-        only one for TeleDongle and TeleMini.  All boards are shipped from
-        the factory pre-calibrated, but the procedures are documented here
-       in case they are ever needed.  Re-calibration is not supported by
-       AltosUI, you must connect to the board with a serial terminal program
-       and interact directly with the on-board command interpreter to effect
-       calibration.
+        There are only two calibrations required for TeleMetrum and
+        TeleMega, and only one for TeleDongle, TeleMini and EasyMini.
+        All boards are shipped from the factory pre-calibrated, but
+        the procedures are documented here in case they are ever
+        needed.  Re-calibration is not supported by AltosUI, you must
+        connect to the board with a serial terminal program and
+        interact directly with the on-board command interpreter to
+        effect calibration.
       </para>
       <section>
         <title>Radio Frequency</title>
         <para>
-          The radio frequency is synthesized from a clock based on the 48 MHz
+          The radio frequency is synthesized from a clock based on the
           crystal on the board.  The actual frequency of this oscillator 
           must be measured to generate a calibration constant.  While our 
           GFSK modulation
@@ -2779,13 +4373,14 @@ NAR #88757, TRA #12200
           should generally not be required.
         </para>
         <para>
-          To calibrate the radio frequency, connect the UHF antenna port to a
-          frequency counter, set the board to 434.550MHz, and use the 'C'
-          command in the on-board command interpreter to generate a CW 
-          carrier.  For TeleMetrum, this is best done over USB.  For TeleMini,
-         note that the only way to escape the 'C' command is via power cycle
-         since the board will no longer be listening for commands once it
-         starts generating a CW carrier.
+          To calibrate the radio frequency, connect the UHF antenna
+          port to a frequency counter, set the board to 434.550MHz,
+          and use the 'C' command in the on-board command interpreter
+          to generate a CW carrier.  For USB-enabled boards, this is
+          best done over USB.  For TeleMini v1, note that the only way
+          to escape the 'C' command is via power cycle since the board
+          will no longer be listening for commands once it starts
+          generating a CW carrier.
        </para>
        <para>
          Wait for the transmitter temperature to stabilize and the frequency 
@@ -2796,7 +4391,7 @@ NAR #88757, TRA #12200
           command.  Testing with the 'C' command again should show a carrier
           within a few tens of Hertz of the intended frequency.
           As with all 'c' sub-commands, follow this with a 'c w' to write the
-          change to the parameter block in the on-board DataFlash chip.
+          change to the parameter block in the on-board storage chip.
         </para>
        <para>
          Note that any time you re-do the radio frequency calibration, the
@@ -2806,21 +4401,13 @@ NAR #88757, TRA #12200
        </para>
       </section>
       <section>
-        <title>TeleMetrum Accelerometer</title>
+        <title>TeleMetrum and TeleMega Accelerometers</title>
         <para>
-          The TeleMetrum accelerometer we use has its own 5 volt power 
-         supply and
-          the output must be passed through a resistive voltage divider to match
-          the input of our 3.3 volt ADC.  This means that unlike the barometric
-          sensor, the output of the acceleration sensor is not ratio-metric to
-          the ADC converter, and calibration is required.  Explicitly 
-         calibrating the accelerometers also allows us to load any device
-         from a Freescale family that includes at least +/- 40g, 50g, 100g, 
-         and 200g parts.  Using gravity,
-          a simple 2-point calibration yields acceptable results capturing both
-          the different sensitivities and ranges of the different accelerometer
-          parts and any variation in power supply voltages or resistor values
-          in the divider network.
+          While barometric sensors are factory-calibrated,
+          accelerometers are not, and so each must be calibrated once
+          installed in a flight computer.  Explicitly calibrating the
+          accelerometers also allows us to load any compatible device.
+          We perform a two-point calibration using gravity.
         </para>
         <para>
           To calibrate the acceleration sensor, use the 'c a 0' command.  You
@@ -2836,41 +4423,102 @@ NAR #88757, TRA #12200
           The +1g and -1g calibration points are included in each telemetry
           frame and are part of the header stored in onboard flash to be
          downloaded after flight.  We always store and return raw ADC 
-         samples for each sensor... so nothing is permanently "lost" or 
-         "damaged" if the calibration is poor.
+         samples for each sensor... so nothing is permanently “lost” or 
+         “damaged” if the calibration is poor.
         </para>
         <para>
          In the unlikely event an accel cal goes badly, it is possible
-         that TeleMetrum may always come up in 'pad mode' and as such not be
-         listening to either the USB or radio link.  If that happens,
-         there is a special hook in the firmware to force the board back
-         in to 'idle mode' so you can re-do the cal.  To use this hook, you
-         just need to ground the SPI clock pin at power-on.  This pin is
-         available as pin 2 on the 8-pin companion connector, and pin 1 is
-         ground.  So either carefully install a fine-gauge wire jumper
-         between the two pins closest to the index hole end of the 8-pin
-         connector, or plug in the programming cable to the 8-pin connector
-         and use a small screwdriver or similar to short the two pins closest
-         to the index post on the 4-pin end of the programming cable, and
-         power up the board.  It should come up in 'idle mode' (two beeps),
-        allowing a re-cal.
+         that TeleMetrum or TeleMega may always come up in 'pad mode'
+         and as such not be listening to either the USB or radio link.
+         If that happens, there is a special hook in the firmware to
+         force the board back in to 'idle mode' so you can re-do the
+         cal.  To use this hook, you just need to ground the SPI clock
+         pin at power-on.  This pin is available as pin 2 on the 8-pin
+         companion connector, and pin 1 is ground.  So either
+         carefully install a fine-gauge wire jumper between the two
+         pins closest to the index hole end of the 8-pin connector, or
+         plug in the programming cable to the 8-pin connector and use
+         a small screwdriver or similar to short the two pins closest
+         to the index post on the 4-pin end of the programming cable,
+         and power up the board.  It should come up in 'idle mode'
+         (two beeps), allowing a re-cal.
         </para>
       </section>
   </appendix>
-  <appendix
-      xmlns:xi="http://www.w3.org/2001/XInclude">
+  <appendix>
     <title>Release Notes</title>
-    <simplesect><title>Version 1.21</title><xi:include href="release-notes-1.2.1.xsl"  xpointer="xpointer(/article/*)"/></simplesect>
-    <simplesect><title>Version 1.2</title><xi:include  href="release-notes-1.2.xsl"  xpointer="xpointer(/article/*)"/></simplesect>
-    <simplesect><title>Version 1.1.1</title><xi:include        href="release-notes-1.1.1.xsl"  xpointer="xpointer(/article/*)"/></simplesect>
-    <simplesect><title>Version 1.1</title><xi:include  href="release-notes-1.1.xsl"  xpointer="xpointer(/article/*)"/></simplesect>
-    <simplesect><title>Version 1.0.1</title><xi:include        href="release-notes-1.0.1.xsl"  xpointer="xpointer(/article/*)"/></simplesect>
-    <simplesect><title>Version 0.9.2</title><xi:include        href="release-notes-0.9.2.xsl"  xpointer="xpointer(/article/*)"/></simplesect>
-    <simplesect><title>Version 0.9</title><xi:include  href="release-notes-0.9.xsl"  xpointer="xpointer(/article/*)"/></simplesect>
-    <simplesect><title>Version 0.8</title><xi:include  href="release-notes-0.8.xsl"  xpointer="xpointer(/article/*)"/></simplesect>
-    <simplesect><title>Version 0.7.1</title><xi:include        href="release-notes-0.7.1.xsl"  xpointer="xpointer(/article/*)"/></simplesect>
+    <simplesect>
+      <title>Version 1.3</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-1.3.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
+    <simplesect>
+      <title>Version 1.2.1</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-1.2.1.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
+    <simplesect>
+      <title>Version 1.2</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-1.2.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
+    <simplesect>
+      <title>Version 1.1.1</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-1.1.1.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
+    <simplesect>
+      <title>Version 1.1</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-1.1.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
+    <simplesect>
+      <title>Version 1.0.1</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-1.0.1.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
+    <simplesect>
+      <title>Version 0.9.2</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-0.9.2.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
+    <simplesect>
+      <title>Version 0.9</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-0.9.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
+    <simplesect>
+      <title>Version 0.8</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-0.8.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
+    <simplesect>
+      <title>Version 0.7.1</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-0.7.1.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
   </appendix>
 </book>
 
-<!--  LocalWords:  Altusmetrum
+<!-- LocalWords: Altusmetrum
 -->
diff --git a/doc/ascent.png b/doc/ascent.png
new file mode 100644 (file)
index 0000000..fd1cd09
Binary files /dev/null and b/doc/ascent.png differ
index 1215d9af14de27f9f82d8a0964d8b998ed1a65c1..14e2194e3bd26d5f5aee4ccab14ae545d01a788b 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
 "/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
 
 <article>
       The Companion Port provides two different functions:
       <itemizedlist>
        <listitem>
+         <para>
          Power. Both battery-level and 3.3V regulated power are
          available. Note that the amount of regulated power is not
          huge; TeleMetrum contains a 150mA regulator and uses, at
          peak, about 120mA or so. For applications needing more than
          a few dozen mA, placing a separate regulator on them and
          using the battery for power is probably a good idea.
+         </para>
        </listitem>
        <listitem>
+         <para>
          SPI. The flight computer operates as a SPI master, using
          a protocol defined in this document. Companion boards
          provide a matching SPI slave implementation which supplies
          telemetry information for the radio downlink during flight
+         </para>
        </listitem>
       </itemizedlist>
     </para>
   </section>
   <section>
     <title>SPI Message Formats</title>
+    <para>
     This section first defines the command message format sent from
     the flight computer to the companion board, and then the various
     reply message formats for each type of command message.
+    </para>
     <section>
       <title>Command Message</title>
       <table frame='all'>
diff --git a/doc/configure-altimeter.png b/doc/configure-altimeter.png
new file mode 100644 (file)
index 0000000..afb1932
Binary files /dev/null and b/doc/configure-altimeter.png differ
diff --git a/doc/configure-altosui.png b/doc/configure-altosui.png
new file mode 100644 (file)
index 0000000..43fd400
Binary files /dev/null and b/doc/configure-altosui.png differ
diff --git a/doc/configure-groundstation.png b/doc/configure-groundstation.png
new file mode 100644 (file)
index 0000000..9f836e7
Binary files /dev/null and b/doc/configure-groundstation.png differ
diff --git a/doc/configure-pyro.png b/doc/configure-pyro.png
new file mode 100644 (file)
index 0000000..4f03c0a
Binary files /dev/null and b/doc/configure-pyro.png differ
diff --git a/doc/descent.png b/doc/descent.png
new file mode 100644 (file)
index 0000000..0c479e7
Binary files /dev/null and b/doc/descent.png differ
diff --git a/doc/device-selection.png b/doc/device-selection.png
new file mode 100644 (file)
index 0000000..ffd067d
Binary files /dev/null and b/doc/device-selection.png differ
diff --git a/doc/easymini-outline.pdf b/doc/easymini-outline.pdf
new file mode 100644 (file)
index 0000000..a1a0b19
Binary files /dev/null and b/doc/easymini-outline.pdf differ
diff --git a/doc/easymini-outline.svg b/doc/easymini-outline.svg
new file mode 100644 (file)
index 0000000..40faddb
--- /dev/null
@@ -0,0 +1,219 @@
+<?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"
+   width="427.5"
+   height="270"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="easymini-outline.svg">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Lend"
+       style="overflow:visible;">
+      <path
+         id="path3866"
+         style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="6.4827171"
+     inkscape:cx="163.56238"
+     inkscape:cy="128.7277"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1146"
+     inkscape:window-height="846"
+     inkscape:window-x="0"
+     inkscape:window-y="26"
+     inkscape:window-maximized="0"
+     units="in">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3005" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <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 />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-782.35975)">
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:0.29770368;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect2816"
+       width="135.0623"
+       height="72.062294"
+       x="89.986351"
+       y="890.31354" />
+    <g
+       inkscape:tile-y0="681.11218"
+       inkscape:tile-x0="90"
+       id="use3601"
+       transform="translate(5.5965353,264.43715)">
+      <path
+         sodipodi:type="arc"
+         style="fill:none;stroke:#000000;stroke-width:1.41507304;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path3611"
+         sodipodi:cx="116"
+         sodipodi:cy="739.36218"
+         sodipodi:rx="17"
+         sodipodi:ry="18"
+         d="m 133,739.36218 c 0,9.94113 -7.61116,18 -17,18 -9.38884,0 -17,-8.05887 -17,-18 0,-9.94112 7.61116,-18 17,-18 9.38884,0 17,8.05888 17,18 z"
+         transform="matrix(0.32722728,0,0,0.3090422,57.632964,458.24316)" />
+      <path
+         style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.10785132;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="m 95.625,692.36218 0,-11.25"
+         id="path3613"
+         sodipodi:nodetypes="cc"
+         inkscape:connector-curvature="0" />
+      <path
+         sodipodi:nodetypes="cc"
+         id="path3615"
+         d="m 90,686.73718 11.25,0"
+         style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.09;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         inkscape:connector-curvature="0" />
+    </g>
+    <g
+       inkscape:tile-y0="681.11218"
+       inkscape:tile-x0="90"
+       id="use3603"
+       transform="translate(118.09654,214.93471)">
+      <path
+         sodipodi:type="arc"
+         style="fill:none;stroke:#000000;stroke-width:1.41507304;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path3619"
+         sodipodi:cx="116"
+         sodipodi:cy="739.36218"
+         sodipodi:rx="17"
+         sodipodi:ry="18"
+         d="m 133,739.36218 c 0,9.94113 -7.61116,18 -17,18 -9.38884,0 -17,-8.05887 -17,-18 0,-9.94112 7.61116,-18 17,-18 9.38884,0 17,8.05888 17,18 z"
+         transform="matrix(0.32722728,0,0,0.3090422,57.632964,458.24316)" />
+      <path
+         style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.10785132;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="m 95.625,692.36218 0,-11.25"
+         id="path3621"
+         sodipodi:nodetypes="cc"
+         inkscape:connector-curvature="0" />
+      <path
+         sodipodi:nodetypes="cc"
+         id="path3623"
+         d="m 90,686.73718 11.25,0"
+         style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.09;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         inkscape:connector-curvature="0" />
+    </g>
+    <g
+       inkscape:tile-y0="681.11218"
+       inkscape:tile-x0="90"
+       id="use3605"
+       transform="translate(118.09654,264.39215)">
+      <path
+         sodipodi:type="arc"
+         style="fill:none;stroke:#000000;stroke-width:1.41507304;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path3627"
+         sodipodi:cx="116"
+         sodipodi:cy="739.36218"
+         sodipodi:rx="17"
+         sodipodi:ry="18"
+         d="m 133,739.36218 c 0,9.94113 -7.61116,18 -17,18 -9.38884,0 -17,-8.05887 -17,-18 0,-9.94112 7.61116,-18 17,-18 9.38884,0 17,8.05888 17,18 z"
+         transform="matrix(0.32722728,0,0,0.3090422,57.632964,458.24316)" />
+      <path
+         style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.10785132;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="m 95.625,692.36218 0,-11.25"
+         id="path3629"
+         sodipodi:nodetypes="cc"
+         inkscape:connector-curvature="0" />
+      <path
+         sodipodi:nodetypes="cc"
+         id="path3631"
+         d="m 90,686.73718 11.25,0"
+         style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.09;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         inkscape:connector-curvature="0" />
+    </g>
+    <g
+       inkscape:tile-y0="681.11218"
+       inkscape:tile-x0="90"
+       id="use3607"
+       transform="translate(5.5965353,214.93471)">
+      <path
+         sodipodi:type="arc"
+         style="fill:none;stroke:#000000;stroke-width:1.41507304;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         id="path3635"
+         sodipodi:cx="116"
+         sodipodi:cy="739.36218"
+         sodipodi:rx="17"
+         sodipodi:ry="18"
+         d="m 133,739.36218 c 0,9.94113 -7.61116,18 -17,18 -9.38884,0 -17,-8.05887 -17,-18 0,-9.94112 7.61116,-18 17,-18 9.38884,0 17,8.05888 17,18 z"
+         transform="matrix(0.32722728,0,0,0.3090422,57.632964,458.24316)" />
+      <path
+         style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.10785132;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="m 95.625,692.36218 0,-11.25"
+         id="path3637"
+         sodipodi:nodetypes="cc"
+         inkscape:connector-curvature="0" />
+      <path
+         sodipodi:nodetypes="cc"
+         id="path3639"
+         d="m 90,686.73718 11.25,0"
+         style="color:#000000;fill:#67615b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.09;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         inkscape:connector-curvature="0" />
+    </g>
+    <path
+       style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.18224967;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;marker-end:url(#Arrow2Lend);visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       d="m 116.64314,926.46226 64.93789,0"
+       id="path2829"
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Minion Pro;-inkscape-font-specification:Minion Pro"
+       x="912.26929"
+       y="-186.53189"
+       id="text4236"
+       sodipodi:linespacing="125%"
+       transform="matrix(0,1,-1,0,0,0)"><tspan
+         sodipodi:role="line"
+         x="912.26929"
+         y="-186.53189"
+         id="tspan4242">UP</tspan></text>
+  </g>
+</svg>
diff --git a/doc/easymini-top.jpg b/doc/easymini-top.jpg
new file mode 100644 (file)
index 0000000..2b9e0a3
Binary files /dev/null and b/doc/easymini-top.jpg differ
diff --git a/doc/fire-igniter.png b/doc/fire-igniter.png
new file mode 100644 (file)
index 0000000..8580457
Binary files /dev/null and b/doc/fire-igniter.png differ
diff --git a/doc/graph-configure.png b/doc/graph-configure.png
new file mode 100644 (file)
index 0000000..b588833
Binary files /dev/null and b/doc/graph-configure.png differ
diff --git a/doc/graph-map.png b/doc/graph-map.png
new file mode 100644 (file)
index 0000000..fd0fb13
Binary files /dev/null and b/doc/graph-map.png differ
diff --git a/doc/graph-stats.png b/doc/graph-stats.png
new file mode 100644 (file)
index 0000000..6f5c979
Binary files /dev/null and b/doc/graph-stats.png differ
diff --git a/doc/graph.png b/doc/graph.png
new file mode 100644 (file)
index 0000000..c7c7b7d
Binary files /dev/null and b/doc/graph.png differ
diff --git a/doc/landed.png b/doc/landed.png
new file mode 100644 (file)
index 0000000..7b4f317
Binary files /dev/null and b/doc/landed.png differ
diff --git a/doc/launch-pad.png b/doc/launch-pad.png
new file mode 100644 (file)
index 0000000..a6f142d
Binary files /dev/null and b/doc/launch-pad.png differ
diff --git a/doc/load-maps.png b/doc/load-maps.png
new file mode 100644 (file)
index 0000000..dc7ea64
Binary files /dev/null and b/doc/load-maps.png differ
index 96179d019340c46205f435cc380f4e9034ede523..8c487e5d97d0d60d8d1cfc892b431356107892e7 100644 (file)
@@ -55,7 +55,8 @@
       </revision>
     </revhistory>
   </bookinfo>
-  <acknowledgements>
+  <dedication>
+    <title>Acknowledgements</title>
     <para>
       Thanks to John Lyngdal for suggesting that we build something like this.
     </para>
@@ -70,7 +71,7 @@ Keith Packard, KD7SQG
 NAR #88757, TRA #12200
       </literallayout>
     </para>
-  </acknowledgements>
+  </dedication>
   <chapter>
     <title>Quick Start Guide</title>
     <para>
@@ -114,20 +115,20 @@ NAR #88757, TRA #12200
        <para>
          Finish preparing the rocket for flight. After the
          previous flight data have been reported, MicroPeak waits for
-         30 seconds before starting to check for launch. This gives
+         one minute before starting to check for launch. This gives
          you time to finish assembling the rocket. As those
          activities might cause pressure changes inside the airframe,
          MicroPeak might accidentally detect boost. If you need to do
-         anything to the airframe after the 30 second window passes,
+         anything to the airframe after the one minute window passes,
          make sure to be careful not to disturb the altimeter. The
-         LED will remain dark during the 30 second delay, but after
+         LED will remain dark during the one minute delay, but after
          that, it will start blinking once every 3 seconds.
        </para>
       </listitem>
       <listitem>
        <para>
-         Fly the rocket. Once the rocket passes about 10m in height
-         (32 feet), the micro-controller will record the ground
+         Fly the rocket. Once the rocket passes about 30m in height
+         (100 feet), the micro-controller will record the ground
          pressure and track the pressure seen during the flight. In
          this mode, the LED flickers rapidly. When the rocket lands,
          and the pressure stabilizes, the micro-controller will record
@@ -400,7 +401,7 @@ NAR #88757, TRA #12200
     <section>
       <title>Lithium Battery</title>
       <para>
-       The CR1025 battery used by MicroPeak holes 30mAh of power,
+       The CR1025 battery used by MicroPeak holds 30mAh of power,
        which is sufficient to run for over 40 hours. Because
        MicroPeak powers down on landing, run time includes only time
        sitting on the launch pad or during flight.
index 75158a02a38c384c75d4e4fd9804683d291bb5fb..1f2feeb0c5ddd30239453ae1b0df113baa0e9350 100644 (file)
@@ -8,42 +8,55 @@ Version 0.7.1 is the first release containing our new cross-platform Java-based
   </para>
   <itemizedlist>
     <listitem>
+<para>
       Receive and log telemetry from a connected TeleDongle
       device. All data received is saved to log files named with the
       current date and the connected rocket serial and flight
       numbers. There is no mode in which telemetry data will not be
       saved.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Download logged data from TeleMetrum devices, either through a
       direct USB connection or over the air through a TeleDongle
       device.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Configure a TeleMetrum device, setting the radio channel,
       callsign, apogee delay and main deploy height. This can be done
       through either a USB connection or over a radio link via a
       TeleDongle device.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Replay a flight in real-time. This takes a saved telemetry log
       or eeprom download and replays it through the user interface so
       you can relive your favorite rocket flights.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Reprogram Altus Metrum devices. Using an Altus Metrum device
       connected via USB, another Altus Metrum device can be
       reprogrammed using the supplied programming cable between the
       two devices.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Export Flight data to a comma-separated-values file. This takes
       either telemetry or on-board flight data and generates data
       suitable for use in external applications. All data is exported
       using standard units so that no device-specific knowledge is
       needed to handle the data.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Speak to you during the flight. Instead of spending the flight
       hunched over your laptop looking at the screen, enjoy the view
       while the computer tells you what’s going on up there. During
@@ -52,6 +65,7 @@ Version 0.7.1 is the first release containing our new cross-platform Java-based
       range information to try and help you find your rocket in the
       air. Once on the ground, the direction and distance are
       reported.
-    </listitem>
+    </para>
+</listitem>
   </itemizedlist>
 </article>
index c54f97e97a0d1501e98a208efe482a2cea34e378..df7ef32d9afae8934ebbe547b26896ad6db26dd5 100644 (file)
@@ -9,25 +9,32 @@
   </para>
   <itemizedlist>
     <listitem>
+<para>
       Post-flight graphing tool. This lets you explore the behaviour
       of your rocket after flight with a scroll-able and zoom-able
       chart showing the altitude, speed and acceleration of the
       airframe along with events recorded by the flight computer. You
       can export graphs to PNG files, or print them directly.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Real-time moving map which overlays the in-progress flight on
       satellite imagery fetched from Google Maps. This lets you see in
       pictures where your rocket has landed, allowing you to plan
       recovery activities more accurately.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Wireless recovery system testing. Prep your rocket for flight
       and test fire the deployment charges to make sure things work as
       expected. All without threading wires through holes in your
       airframe.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Optimized flight status displays. Each flight state now has it's
       own custom 'tab' in the flight monitoring window so you can
       focus on the most important details. Pre-flight, the system
       they're all green and your rocket is ready for flight. There are
       also tabs for ascent, descent and landing along with the
       original tabular view of the data.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Monitor multiple flights simultaneously. If you have more than
       one TeleDongle, you can monitor a flight with each one on the
       same computer.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Automatic flight monitoring at startup. Plug TeleDongle into the
       machine before starting AltosUI and it will automatically
       connect to it and prepare to monitor a flight.
-    </listitem>
+    </para>
+</listitem>
     <listitem>
+<para>
       Exports Google Earth flight tracks. Using the Keyhole Markup
       Language (.kml) file format, this provides a 3D view of your
       rocket flight through the Google Earth program.
-    </listitem>
+    </para>
+</listitem>
   </itemizedlist>
 </article>
index e5f66c60cbc828f7bf29df0fea27bb129a14793d..16ff989ed0d432e51e0614db2ace31b494f0c376 100644 (file)
@@ -8,13 +8,19 @@
   </para>
   <itemizedlist>
     <listitem>
+<para>
       Fix plotting problems due to missing file in the Mac OS install image.
+</para>
     </listitem>
     <listitem>
+<para>
       Always read whole eeprom blocks, mark empty records invalid, display parsing errors to user.
+</para>
     </listitem>
     <listitem>
+      <para>
       Add software version to Configure AltosUI dialog
+</para>
     </listitem>
   </itemizedlist>
 </article>
index 547f46b12c27de47857e1507c53f01397f16f4b8..a5d6b3d7a5796f8823c1e30beedfe62d8960c370 100644 (file)
@@ -9,23 +9,29 @@
   </para>
   <itemizedlist>
     <listitem>
+      <para>
       Support for TeleMetrum v1.1 hardware. Sources for the flash
       memory part used in v1.0 dried up, so v1.1 uses a different part
       which required a new driver and support for explicit flight log
       erasing.
+</para>
     </listitem>
     <listitem>
+      <para>
       Multiple flight log support. This stores more than one flight
       log in the on-board flash memory. It also requires the user to
       explicitly erase flights so that you won't lose flight logs just
       because you fly the same board twice in one day.
+</para>
     </listitem>
     <listitem>
+      <para>
       Telemetry support for devices with serial number >=
       256. Previous versions used a telemetry packet format that
       provided only 8 bits for the device serial number. This change
       requires that both ends of the telemetry link be running the 0.9
       firmware or they will not communicate.
+</para>
     </listitem>
   </itemizedlist>
 </article>
index 1e9fcabcd43539de681f27544e705358eaf67251..8b66f7e0470d2a248281799334eb20b3d2895629 100644 (file)
     AltOS Firmware Changes
     <itemizedlist>
       <listitem>
+<para>
        Add TeleMini v1.0 support. Firmware images for TeleMini are
        included in AltOS releases.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Change telemetry to be encoded in multiple 32-byte packets. This
        enables support for TeleMini and other devices without requiring
        further updates to the TeleDongle firmware.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Support operation of TeleMetrum with the antenna pointing
        aft. Previous firmware versions required the antenna to be
        pointing upwards, now there is a configuration option allowing
        the antenna to point aft, to aid installation in some airframes.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Ability to disable telemetry. For airframes where an antenna
        just isn't possible, or where radio transmissions might cause
        trouble with other electronics, there's a configuration option
        to disable all telemetry. Note that the board will still
        enable the radio link in idle mode.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Arbitrary frequency selection. The radios in Altus Metrum
        devices can be programmed to a wide range of frequencies, so
        instead of limiting devices to 10 pre-selected 'channels', the
        70cm band. Note that the RF matching circuit on the boards is
        tuned for around 435MHz, so frequencies far from that may
        reduce the available range.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Kalman-filter based flight-tracking. The model based sensor
        fusion approach of a Kalman filter means that AltOS now
        computes apogee much more accurately than before, generally
        allows the baro-only TeleMini device to correctly identify
        Mach transitions, avoiding the error-prone selection of a Mach
        delay.
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
   <para>
     AltosUI Changes
     <itemizedlist>
       <listitem>
+<para>
        Wait for altimeter when using packet mode. Instead of quicly
        timing out when trying to initialize a packet mode
        configuration connection, AltosUI now waits indefinitely for
        the remote device to appear, providing a cancel button should
        the user get bored. This is necessary as the TeleMini can only
        be placed in "Idle" mode if AltosUI is polling it.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Add main/apogee voltage graphs to the data plot. This provides
        a visual indication if the igniters fail before being fired.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Scan for altimeter devices by watching the defined telemetry
        frequencies. This avoids the problem of remembering what
        frequency a device was configured to use, which is especially
        important with TeleMini which does not include a USB connection.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Monitor altimeter state in "Idle" mode. This provides much of
        the information presented in the "Pad" dialog from the Monitor
        Flight command, monitoring the igniters, battery and GPS
        status withing requiring the flight computer to be armed and
        ready for flight.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Pre-load map images from home. For those launch sites which
        don't provide free Wi-Fi, this allows you to download the
        necessary satellite images given the location of the launch
        you've got a launch site not on that list, please send the
        name of it, latitude and longitude along with a link to the
        web site of the controlling club to the altusmetrum mailing list.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Flight statistics are now displayed in the Graph data
        window. These include max height/speed/accel, average descent
        rates and a few other bits of information. The Graph Data
        window can now be reached from the 'Landed' tab in the Monitor
        Flight window so you can immediately see the results of a
        flight.
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
 </article>
index 14984a2aeb4e004ac9b1984bd1c37529ef6a871c..6f3a925dd66a556eb894f0f4235f18534eb85c48 100644 (file)
@@ -14,6 +14,7 @@
     AltOS Firmware Changes
     <itemizedlist>
       <listitem>
+<para>
        TeleMetrum v1.0 boards use the AT45DB081D flash memory part to
        store flight data, which is different from later TeleMetrum
        boards. The AltOS v1.1 driver for this chip couldn't erase
        configuration values. This bug doesn't affect newer TeleMetrum
        boards, and it doesn't affect the safety of rockets flying
        version 1.1 firmware.
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
   <para>
     AltosUI Changes
     <itemizedlist>
       <listitem>
+<para>
        Creating a Google Earth file (KML) from on-board flight data
        (EEPROM) would generate an empty file. The code responsible
        for reading the EEPROM file wasn't ever setting the GPS valid
        bits, and so the KML export code thought there was no GPS data
        in the file.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        The “Landed” tab was displaying all values in metric units,
        even when AltosUI was configured to display imperial
        units. Somehow I just missed this tab when doing the units stuff.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        The “Descent” tab displays the range to the rocket, which is a
        combination of the over-the-ground distance to the rockets
        current latitude/longitude and the height of the rocket. As
        eventually land. A new “Ground Distance” field has been added
        which displays the distance to a spot right underneath the
        rocket.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Sensor data wasn't being displayed for TeleMini flight
        computers in Monitor Idle mode, including things like battery
        voltage. The code that picked which kinds of data to fetch
        from the flight computer was missing a check for TeleMini when
        deciding whether to fetch the analog sensor data.
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
 </article>
index 519cd40c2378ae05b7b56c55ee601724a7f8de2f..0b2cce4e74f9a10acdb671b34737bd7ad719cebc 100644 (file)
     AltOS Firmware Changes
     <itemizedlist>
       <listitem>
+<para>
        Add apogee-lockout value. Overrides the apogee detection logic to
        prevent incorrect apogee charge firing.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Fix a bug where the data reported in telemetry packets was
        from 320ms ago.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Force the radio frequency to 434.550MHz when the debug clock
        pin is connected to ground at boot time. This provides a way
        to talk to a TeleMini which is configured to some unknown frequency.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Provide RSSI values for Monitor Idle mode. This makes it easy to check radio
        range without needing to go to flight mode.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Fix a bug which caused the old received telemetry packets to
        be retransmitted over the USB link when the radio was turned
        off and back on.
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
   <para>
     AltosUI Changes
     <itemizedlist>
       <listitem>
+<para>
        Fix a bug that caused GPS ready to happen too quickly. The
        software was using every telemetry packet to signal new GPS
        data, which caused GPS ready to be signalled after 10 packets
        instead of 10 GPS updates.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Fix Google Earth data export to work with recent versions. The
        google earth file loading code got a lot pickier, requiring
        some minor white space changes in the export code.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Make the look-n-feel configurable, providing a choice from
        the available options.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Add an 'Age' element to mark how long since a telemetry packet
        has been received. Useful to quickly gauge whether
        communications with the rocket are still active.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Add 'Configure Ground Station' dialog to set the radio
        frequency used by a particular TeleDongle without having to go
        through the flight monitor UI.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Add configuration for the new apogee-lockout value. A menu provides a list of
        reasonable values, or the value can be set by hand.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Changed how flight data are downloaded. Now there's an initial
        dialog asking which flights to download, and after that
        finishes, a second dialog comes up asking which flights to delete.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Re-compute time spent in each state for the flight graph; this
        figures out the actual boost and landing times instead of
        using the conservative values provide by the flight
        electronics. This improves the accuracy of the boost
        acceleration and main descent rate computations.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Make AltosUI run on Mac OS Lion. The default Java heap space
        was dramatically reduced for this release causing much of the
        UI to fail randomly. This most often affected the satellite
        mapping download and displays.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Change how data are displayed in the 'table' tab of the flight
        monitoring window. This eliminates entries duplicated from the
        header and adds both current altitude and pad altitude, which
        are useful in 'Monitor Idle' mode.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Add Imperial units mode to present data in feet instead of
        meters.
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
 </article>
index 5f9aef01ffad52aa1a61ad13cab1f6b864e47555..0f0569547931b17d2ceaf00f885dcd7d1c68f85d 100644 (file)
     AltOS Firmware Changes
     <itemizedlist>
       <listitem>
+<para>
        Add support for TeleBT
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        In TeleMini recovery mode (when booted with the outer two
        debug pins connected together), the radio parameters are also
        set back to defaults (434.550MHz, N0CALL, factory radio cal).
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Add support for reflashing the SkyTraq GPS chips. This
        requires special host-side code which currently only exists
        for Linux.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Correct Kalman filter model error covariance matrix. The
        values used previously assumed continuous measurements instead
        of discrete measurements.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Fix some bugs in the USB driver for TeleMetrum and TeleDongle
        that affected Windows users.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Adjusted the automatic gain control parameters that affect
        receive performance for TeleDongle. Field tests indicate that this
        may improve receive performance somewhat.
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
   <para>
     AltosUI Changes
     <itemizedlist>
       <listitem>
+<para>
        Handle missing GPS lock in 'Descent' tab. Previously, if the
        GPS position of the pad was unknown, an exception would be
        raised, breaking the Descent tab contents.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Improve the graph, adding tool-tips to show values near the
        cursor and making the displayed set of values configurable,
        adding all of the flight data as options while leaving the
        default settings alone so that the graph starts by showing
        height, speed and acceleration.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Make the initial position of the AltosUI top level window
        configurable. Along with this change, the other windows will
        pop up at 'sensible' places now, instead of on top of one
        another.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Add callsign to Monitor idle window and connecting
        dialogs. This makes it clear which callsign is being used so
        that the operator will be aware that it must match the flight
        computer value or no communication will work.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        When downloading flight data, display the block number so that
        the user has some sense of progress. Unfortunately, we don't
        know how many blocks will need to be downloaded, but at least
        it isn't just sitting there doing nothing for a long time.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Add GPS data and a map to the graph window. This lets you see
        a complete summary of the flight without needing to 'replay'
        the whole thing.
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
 </article>
index 64ba46a90d2d269a4560d5b70a9cc1c576a56db9..f26480a1f7424288557d2d1cf99d72de3108c583 100644 (file)
     AltOS Firmware Changes
     <itemizedlist>
       <listitem>
+<para>
        Add MicroPeak support. This includes support for the ATtiny85
        processor and adaptations to the core code to allow for
        devices too small to run the multi-tasking scheduler.
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
   <para>
     MicroPeak UI changes
     <itemizedlist>
       <listitem>
+<para>
        Added this new application
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
   <para>
     Distribution Changes
     <itemizedlist>
       <listitem>
+<para>
        Distribute Mac OS X packages in disk image ('.dmg') format to
        greatly simplify installation.
-      </listitem>
+      </para>
+</listitem>
       <listitem>
+<para>
        Provide version numbers for the shared Java libraries to
        ensure that upgrades work properly, and to allow for multiple
        Altus Metrum software packages to be installed in the same
        directory at the same time.
-      </listitem>
+      </para>
+</listitem>
     </itemizedlist>
   </para>
 </article>
diff --git a/doc/release-notes-1.3.xsl b/doc/release-notes-1.3.xsl
new file mode 100644 (file)
index 0000000..3bc4857
--- /dev/null
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
+
+<article>
+  <para>
+    Version 1.3 is a major release. It adds support for TeleMega,
+    TeleMetrum v2.0, TeleMini v2.0 and EasyMini.
+  </para>
+  <para>
+    AltOS Firmware Changes
+    <itemizedlist>
+      <listitem>
+       <para>
+         Add STM32L processor support. This includes enhancements to
+         the scheduler to support products with many threads.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Add NXP LPC11U14 processor support.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Support additional pyro channels. These are configurable
+         through the UI to handle air starts, staging, additional
+         recovery events and external devices such as cameras.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Add 3-axis gyro support for orientation tracking. This
+         integrates the gyros to compute the angle from vertical during
+         flight, allowing the additional pyro events to be controlled
+         by this value.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Many more device drivers, including u-Blox Max 7Q GPS,
+         Freescale MMA6555 digital single-axis accelerometer,
+         Invensense MPU6000 3-axis accelerometer + 3 axis gyro,
+         Honeywell HMC5883 3-axis magnetic sensor and the TI CC1120 and
+         CC115L digital FM transceivers
+       </para>
+      </listitem>
+    </itemizedlist>
+  </para>
+  <para>
+    AltosUI changes
+    <itemizedlist>
+      <listitem>
+       <para>
+         Support TeleMega, TeleMetrum v2.0, TeleMini v2.0 and EasyMini telemetry and log formats.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Use preferred units for main deployment height configuration,
+         instead of always doing configuration in meters.
+       </para>
+      </listitem>
+    </itemizedlist>
+  </para>
+  <para>
+    MicroPeak UI changes
+    <itemizedlist>
+      <listitem>
+       <para>
+         Add 'Download' button to menu bar.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Save the last log directory and offer that as the default for new downloads
+       </para>
+      </listitem>
+    </itemizedlist>
+  </para>
+</article>
diff --git a/doc/scan-channels.png b/doc/scan-channels.png
new file mode 100644 (file)
index 0000000..bf6b6e5
Binary files /dev/null and b/doc/scan-channels.png differ
diff --git a/doc/site-map.png b/doc/site-map.png
new file mode 100644 (file)
index 0000000..a6d3f78
Binary files /dev/null and b/doc/site-map.png differ
diff --git a/doc/table.png b/doc/table.png
new file mode 100644 (file)
index 0000000..86cb988
Binary files /dev/null and b/doc/table.png differ
diff --git a/doc/telemega-v1.0-top.jpg b/doc/telemega-v1.0-top.jpg
new file mode 100644 (file)
index 0000000..709d59f
Binary files /dev/null and b/doc/telemega-v1.0-top.jpg differ
diff --git a/doc/telemetrum-v1.1-thside.jpg b/doc/telemetrum-v1.1-thside.jpg
new file mode 100644 (file)
index 0000000..2ffbdbd
Binary files /dev/null and b/doc/telemetrum-v1.1-thside.jpg differ
index fa66bff919bea61d80f9dc24c96a96fd9e7c2793..e410150742b5caf9d6935e8b17de69885a3b2bfc 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
 "/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
 
 <article>
   </section>
   <section>
     <title>Packet Formats</title>
-    This section first defines the packet header common to all packets
-    and then the per-packet data layout.
+    <para>
+      This section first defines the packet header common to all packets
+      and then the per-packet data layout.
+    </para>
     <section>
       <title>Packet Header</title>
       <table frame='all'>
        resulting in the following signal parmeters:
       </para>
       <table>
+       <title>Modulation Scheme</title>
        <tgroup cols='3'>
          <colspec align="center" colwidth="*" colname="parameter"/>
-         <colspec align="center" text-align="." colwidth="*" colname="value"/>
+         <colspec align="center" colwidth="*" colname="value"/>
          <colspec align="center" colwidth="*" colname="description"/>
          <thead>
            <row>
       </table>
     </section>
     <section>
+      <title>Error Correction</title>
       <para>
        The cc1111 provides forward error correction in hardware,
        which AltOS uses to improve reception of weak signals. The
        overall effect of this is to halve the available bandwidth for
        data from 38 kBaud to 19 kBaud.
       </para>
-      <title>Error Correction</title>
       <table>
+       <title>Error Correction</title>
        <tgroup cols='3'>
          <colspec align="center" colwidth="*" colname="parameter"/>
          <colspec align="center" colwidth="*" colname="value"/>
          <tbody>
            <row>
              <entry>Error Correction</entry>
-             <entry>Convolutional coding FEC</entry>
-             <entry>1/2 code, constraint length m=4</entry>
+             <entry>Convolutional coding</entry>
+             <entry>1/2 rate, constraint length m=4</entry>
            </row>
            <row>
              <entry>Interleaving</entry>
       validate that the line was transmitted without any errors.
     </para>
     <table>
+      <title>Packet Format</title>
       <tgroup cols='4'>
        <colspec align="center" colwidth="2*" colname="offset"/>
        <colspec align="center" colwidth="*" colname="name"/>
diff --git a/doc/telemini-v1-top.jpg b/doc/telemini-v1-top.jpg
new file mode 100644 (file)
index 0000000..f79714c
Binary files /dev/null and b/doc/telemini-v1-top.jpg differ
diff --git a/doc/telemini-v2-top.jpg b/doc/telemini-v2-top.jpg
new file mode 100644 (file)
index 0000000..bc8ae45
Binary files /dev/null and b/doc/telemini-v2-top.jpg differ
diff --git a/doc/xorg-fo.xsl b/doc/xorg-fo.xsl
new file mode 100644 (file)
index 0000000..a36b88f
--- /dev/null
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+                       X.Org DocBook/XML customization
+
+       DocBook XSL Stylesheets FO Parameters
+       http://docbook.sourceforge.net/release/xsl/current/doc/fo/
+-->
+
+<xsl:stylesheet
+    version='1.0'
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
+    >
+<xsl:import href="file:///usr/share/xml/docbook/stylesheet/docbook-xsl/fo/docbook.xsl"/>
+
+
+                       <!-- Reference Pages HTML/FO Parameters -->
+
+
+  <xsl:param name="function.parens" select="1"/>
+
+  <!-- ANSI-style function synopses are generated for a funcsynopsis element -->
+  <xsl:param name="funcsynopsis.style" select="ansi"/>
+
+                       <!-- Linking HTML/FO Parameters -->
+
+  <!-- open new PDF documents in new tab, don't replace doc in current window -->
+  <xsl:attribute-set name="olink.properties">
+    <xsl:attribute name="show-destination">new</xsl:attribute>
+  </xsl:attribute-set>
+
+                       <!-- Miscellaneous HTML/FO Parameters-->
+
+  <!-- SVG will be considered an acceptable image format -->
+  <xsl:param name="use.svg" select="1"/>
+
+                        <!-- ToC/LoT/Index Generation -->
+  <!-- put page breaks before and after the Table of Contents,
+       so that the ToC is on a page by itself
+       Reference: http://www.sagehill.net/docbookxsl/PrintToc.html
+  -->
+  <xsl:attribute-set name="toc.margin.properties">
+    <xsl:attribute name="break-before">page</xsl:attribute>
+    <xsl:attribute name="break-after">page</xsl:attribute>
+  </xsl:attribute-set>
+
+                       <!-- Pagination and General Styles FO Parameters -->
+  <!--
+     Speed up ps & pdf creation by not creating pages with "draft" image,
+     thus not needing to wait for http fetch of draft.png from docbook website.
+    -->
+  <xsl:param name="draft.mode" select="no"/>
+
+                       <!-- Processor Extensions FO Parameters-->
+
+  <!-- PDF bookmarks extensions for FOP version 0.90 and later will be used. -->
+  <xsl:param name="fop.extensions" select="0"></xsl:param>
+  <xsl:param name="fop1.extensions" select="1"></xsl:param>
+
+                       <!-- Cross Refrences FO Parameters-->
+
+  <!-- Make links in pdf output blue so it's easier to tell they're internal
+       links
+   -->
+  <xsl:attribute-set name="xref.properties">
+    <xsl:attribute name="color">blue</xsl:attribute>
+  </xsl:attribute-set>
+
+  <!-- Make links in pdf output green so it's easier to tell they're external
+       links
+  -->
+  <xsl:attribute-set name="olink.properties">
+    <xsl:attribute name="color">green</xsl:attribute>
+  </xsl:attribute-set>
+
+  <!-- Linking to a target inside a pdf document.
+       This feature is only available as of docbook-xsl-1.76.1.
+       When set to zero, the link will point to the document -->
+  <xsl:param name="insert.olink.pdf.frag" select="0"></xsl:param>
+
+
+                       <!-- Font Families FO Parameters -->
+
+  <!--
+     Since a number of documents, especially the credits section in the
+     ReleaseNotes, use characters not found in the fop default base-14
+     PostScript fonts, set the fonts for the fop generated documents to
+     use the free DejaVu and GNU Unifont fonts which cover a much wider
+     range of characters.
+
+     DejaVu is available from http://dejavu-fonts.org/
+     GNU Unifont is available from http://unifoundry.com/unifont.html
+
+     To set fop font paths to find them after installing, see
+     http://xmlgraphics.apache.org/fop/1.0/fonts.html#basics
+    -->
+  <xsl:param name="body.font.family">DejaVu Serif</xsl:param>
+  <xsl:param name="symbol.font.family">serif,Symbol,AR PL UMing CN,AR PL ShanHeiSun Uni,GNU Unifont</xsl:param>
+
+                       <!-- Paragraph template bits -->
+
+  <!--  make it possible to turn off hyphenation when it's giving us probs -->
+  <xsl:template match="para[@hyphenate='false']">
+    <fo:block hyphenate="false" xsl:use-attribute-sets="normal.para.spacing">
+      <xsl:call-template name="anchor"/>
+      <xsl:apply-templates/>
+    </fo:block>
+  </xsl:template>
+
+  <!-- force line break -->
+  <xsl:template match="processing-instruction('linebreak')">
+    <fo:block/>
+  </xsl:template>
+
+  <xsl:attribute-set name="informalfigure.properties">
+    <xsl:attribute name="text-align">center</xsl:attribute>
+  </xsl:attribute-set>
+
+</xsl:stylesheet>
index c490e6f8e029e9caaaf3fa83be67f33ce7cf851c..6d043d602350d967e70c852bf9efb4d404f3962e 100644 (file)
@@ -3,6 +3,7 @@
 *.la
 *.java
 *.class
+*.dll
 .libs/
 classlibaltos.stamp
 libaltos_wrap.c
index 415495586961ec397d1c4f2aaecdc53b3e629d3d..831432fc1a8e6e7aec7d12f6f5c64c04d10ed569 100644 (file)
@@ -1,6 +1,6 @@
 JAVAC=javac
 AM_CFLAGS=-DLINUX -DPOSIX_TTY -I$(JVM_INCLUDE)
-AM_JAVACFLAGS=-encoding UTF-8
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
 
 altoslibdir=$(libdir)/altos
 
index f0fe78f764cf4abb703a65610b442f8e66ac5481..3a65c3d68b10cf8ffceda422ba0f93bf7aa8f551 100644 (file)
@@ -10,7 +10,8 @@ altos_puts(struct altos_file *file, char *string)
                altos_putchar(file, c);
 }
 
-main ()
+int
+main (int argc, char **argv)
 {
        struct altos_device     device;
        struct altos_list       *list;
index 4a6363edc7a069c4e0f83d930d24d9d7bdea4b2c..a623d5ae0b5c187f9b0c5a7bec962b1c73e2451d 100644 (file)
@@ -53,6 +53,8 @@ altos_get_last_error(struct altos_error *error)
 
 #ifdef DARWIN
 
+#include <unistd.h>
+
 #undef USE_POLL
 
 /* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
@@ -887,15 +889,6 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
                if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
                    !get_number (object, CFSTR(kUSBProductID), &device->product))
                        continue;
-               if (list->ftdi) {
-                       if (device->vendor != 0x0403)
-                               continue;
-               } else {
-                       if (device->vendor != 0xfffe)
-                               continue;
-                       if (device->product < 0x000a || 0x0013 < device->product)
-                               continue;
-               }
                if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
                    get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&
                    get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) {
index cfbd3f54cee22e98f28638a3d515ff22e344cab9..8b491c580c9c06e913b9438e083ae7274734f5d8 100755 (executable)
Binary files a/libaltos/libaltos.dylib and b/libaltos/libaltos.dylib differ
index 098a00fb0e293e765571f50e48894167c941f615..33b1420acc5a3329d3d3cd137b6447fa62893635 100644 (file)
@@ -1,5 +1,7 @@
 JAVAROOT=classes
-AM_JAVACFLAGS=-encoding UTF-8 -Xlint:deprecation
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
+
+man_MANS=micropeak.1
 
 altoslibdir=$(libdir)/altos
 
index 4c0ed4c3312bf1de84e5a6947f5d1e1865e9837b..07806fa4bab465014f33cd7acfd41dabec606f2c 100644 (file)
@@ -20,7 +20,7 @@ package org.altusmetrum.micropeak;
 import java.lang.*;
 import java.io.*;
 import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 class MicroIterator implements Iterator<MicroDataPoint> {
index bd6795f85f633fb8e573dac8eb02cbe3c444f472..a9095f9c6bc9ed5da1c5d21b9d9d5a4486f982d0 100644 (file)
@@ -23,7 +23,7 @@ import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class MicroDownload extends AltosUIDialog implements Runnable, ActionListener {
index 20a6f79a4cd2f5dde791f03ee116674b75283d49..5af767c6a92a3f5523285001ab649e1b67108497 100644 (file)
@@ -23,7 +23,7 @@ import java.util.ArrayList;
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.filechooser.FileNameExtensionFilter;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class MicroExport extends JFileChooser {
index cdd42e667657d377334a5afe9ef309ab4ea78be9..2b02e20a5d0c9cb9dda54c53eb6243bcbf7da4c7 100644 (file)
@@ -19,7 +19,7 @@ package org.altusmetrum.micropeak;
 
 import java.io.*;
 import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class MicroFile {
index d52eab2ccf830ead8d532f73ffcb0a7b1bb0e34f..3ca128ee97bfddc79cefd3f55ad77d2162b7b528 100644 (file)
@@ -20,7 +20,7 @@ package org.altusmetrum.micropeak;
 import javax.swing.*;
 import javax.swing.filechooser.FileNameExtensionFilter;
 import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class MicroFileChooser extends JFileChooser {
index 50508a61b42cbcb0f46bf9fc45b685caba6c6e30..fba6290723a10449ab4a3e6119064c550407d6dc 100644 (file)
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 import org.jfree.ui.*;
index 792231768808a04011246d2561c29b637bffb8ef..27a8db02a262845ba2fb2feb5c0f3f763a62ccb3 100644 (file)
@@ -23,7 +23,7 @@ import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class MicroPeak extends MicroFrame implements ActionListener, ItemListener {
@@ -231,6 +231,10 @@ public class MicroPeak extends MicroFrame implements ActionListener, ItemListene
                fileMenu.add(exitAction);
                exitAction.addActionListener(this);
 
+               JButton downloadButton = new JButton ("Download");
+               downloadButton.addActionListener(this);
+               menuBar.add(downloadButton);
+
                setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
                addWindowListener(new WindowAdapter() {
                        @Override
index 7337a1dec58b38f6ccdb75c87e402c297ca31e74..0520fa7145da1edd9ef81bd4e6eef5042d1f0b68 100644 (file)
@@ -20,7 +20,7 @@ package org.altusmetrum.micropeak;
 import java.awt.*;
 import java.io.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class MicroRaw extends JTextArea {
index 99f621ce8aa18269c408c14010838257c09a131c..1f1ef3cb86df99e779a7fa87ab3ab45548272ad7 100644 (file)
@@ -24,7 +24,7 @@ import javax.swing.filechooser.FileNameExtensionFilter;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class MicroSave extends JFileChooser {
index 99479cb4aeff3c69a1e69c71fdd2560608faad2a..32d944322caf76705fa3b31be602e4a9970d92e8 100644 (file)
@@ -18,7 +18,7 @@
 package org.altusmetrum.micropeak;
 
 import java.io.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class MicroStats {
index 145bb70ea6dd453ec9730beda5e0dde5615808b5..4400a317f193d78f1e6a17e439e7f1d0c427cdf9 100644 (file)
@@ -19,7 +19,7 @@ package org.altusmetrum.micropeak;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_1.*;
+import org.altusmetrum.altoslib_2.*;
 import org.altusmetrum.altosuilib_1.*;
 
 public class MicroStatsTable extends JComponent implements AltosFontListener {
diff --git a/micropeak/micropeak.1 b/micropeak/micropeak.1
new file mode 100644 (file)
index 0000000..ed2c77e
--- /dev/null
@@ -0,0 +1,43 @@
+.\"
+.\" 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.
+.\"
+.\"
+.TH MICROPEAK 1 "micropeak" ""
+.SH NAME
+micropeak \- MicroPeak logging altimeter download and analysis
+.SH SYNOPSIS
+.B "micropeak"
+.SH DESCRIPTION
+.I micropeak
+connects to a MicroPeak USB adapter for MicroPeak data download.
+It provides a menu-oriented
+user interface to download and analyze data logged on a MicroPeak
+altimeter.
+.SH USAGE
+When connected to a MicroPeak USB adapter,
+.I micropeak 
+can download data from a MicroPeak device, save it to a file and graph
+data from saved files.
+.P
+A number of other menu options exist, including the ability to export flight
+data in different formats.
+.SH FILES
+All data log files are recorded into a user-specified directory
+(default ~/AltusMetrum). Files are named using the current date and a
+unique flight number with a '.mpd' extension.
+.SH AUTHOR
+Keith Packard
diff --git a/pdclib b/pdclib
new file mode 160000 (submodule)
index 0000000..8b1c906
--- /dev/null
+++ b/pdclib
@@ -0,0 +1 @@
+Subproject commit 8b1c9061fa3a8f1b30ee13b373afe5cc1ad9d382
index cae36ae6a12a6d5a6363ab2e4d5ce38e6513021c..a8628fae726e31eccd5582b53550fb976f524261 100644 (file)
@@ -1,3 +1,4 @@
+Makedefs
 altitude.h
 altitude-pa.h
 ao_whiten.h
diff --git a/src/Makedefs.in b/src/Makedefs.in
new file mode 100644 (file)
index 0000000..a52f96f
--- /dev/null
@@ -0,0 +1,15 @@
+ARM_CC=@ARM_CC@
+HAVE_ARM_M3_CC=@HAVE_ARM_M3_CC@
+HAVE_ARM_M0_CC=@HAVE_ARM_M0_CC@
+PDCLIB_INCLUDES=@PDCLIB_INCLUDES@
+PDCLIB_LIBS_M0=@PDCLIB_LIBS_M0@
+PDCLIB_LIBS_M3=@PDCLIB_LIBS_M3@
+PDCLIB_ROOT=@PDCLIB_ROOT@
+HAVE_PDCLIB=@HAVE_PDCLIB@
+
+SDCC=@SDCC@
+HAVE_SDCC=@HAVE_SDCC@
+
+AVR_CC=@AVR_CC@
+AVR_OBJCOPY=@AVR_OBJCOPY@
+HAVE_AVR_CC=@HAVE_AVR_CC@
index 11f149dd77244b6d2e7e761aed50f2a07226d64c..392262d48db8a66d17ef43a71b36f221285a9896 100644 (file)
@@ -13,43 +13,59 @@ vpath load_csv.5c kalman
 vpath matrix.5c kalman
 
 include Version
+TOPDIR=.
+include Makedefs
 
 SDCCDIRS=\
        telemetrum-v1.2 telemetrum-v1.1 telemetrum-v1.0 \
-       teledongle-v0.2 teledongle-v0.1 \
-       telemini-v1.0 telenano-v0.1 \
+       teledongle-v0.2 \
+       telemini-v1.0 \
        telebt-v1.0 \
-       telemetrum-v0.1-sky telemetrum-v0.1-sirf \
-       telelaunch-v0.1 tidongle test \
        teleterra-v0.2 teleshield-v0.1 \
-       telefire-v0.1 \
-       spiradio-v0.1
+       telefire-v0.1 telefire-v0.2 \
+       telemini-v2.0
 
-AVRDIRS=\
-       telescience-v0.1 telescience-pwm telepyro-v0.1 micropeak
-
-ARMDIRS=\
+ARMM3DIRS=\
        telemega-v0.1 telemega-v0.1/flash-loader \
-       telemega-v0.3 telemega-v0.3/flash-loader \
+       telemega-v1.0 telemega-v1.0/flash-loader \
+       telemetrum-v2.0 telemetrum-v2.0/flash-loader \
        megadongle-v0.1 megadongle-v0.1/flash-loader \
-       telegps-v0.1 telegps-v0.1/flash-loader \
-       stm-bringup stm-demo \
+       telegps-v0.3 telegps-v0.3/flash-loader \
        telelco-v0.2 telelco-v0.2/flash-loader \
-       telescience-v0.2
+       telescience-v0.2 telescience-v0.2/flash-loader
+
+ARMM0DIRS=\
+       easymini-v1.0 easymini-v1.0/flash-loader
+
+AVRDIRS=\
+       telescience-v0.1 telescience-pwm micropeak nanopeak-v0.1
+
+SUBDIRS=
 
-ifneq ($(shell which sdcc),)
-       SUBDIRS += $(SDCCDIRS)
+ifeq ($(strip $(HAVE_PDCLIB)),yes)
+PDCLIB=pdclib
+CLEAN_PDCLIB=clean-pdclib
 endif
 
-ifneq ($(shell which avr-gcc),)
-       SUBDIRS += $(AVRDIRS)
+ifeq ($(strip $(HAVE_SDCC)),yes)
+SUBDIRS+=$(SDCCDIRS)
 endif
 
-ifneq ($(shell which arm-none-eabi-gcc),)
-       SUBDIRS += $(ARMDIRS)
+ifeq ($(strip $(HAVE_ARM_M3_CC)),yes)
+SUBDIRS+=$(ARMM3DIRS)
+foo=bar
 endif
 
-ALLDIRS=$(SDCCDIRS) $(AVRDIRS) $(ARMDIRS)
+ifeq ($(strip $(HAVE_ARM_M0_CC)),yes)
+SUBDIRS+=$(ARMM0DIRS)
+baz=bletch
+endif
+
+ifeq ($(strip $(HAVE_AVR_CC)),yes)
+SUBDIRS += $(AVRDIRS)
+endif
+
+ALLDIRS=$(SDCCDIRS) $(ARMM3DIRS) $(ARMM0DIRS) $(AVRDIRS)
 
 all: all-local all-recursive
 
@@ -81,7 +97,7 @@ uninstall:
 
 all-recursive: all-local
 
-all-local: altitude.h altitude-pa.h ao_kalman.h ao_whiten.h
+all-local: altitude.h altitude-pa.h ao_kalman.h ao_whiten.h $(PDCLIB)
 
 altitude.h: make-altitude
        nickle $< > $@
@@ -95,5 +111,13 @@ ao_kalman.h: make-kalman kalman.5c kalman_filter.5c load_csv.5c matrix.5c
 ao_whiten.h: make-whiten
        nickle $< > $@
 
-clean-local:
+clean-local: $(CLEAN_PDCLIB)
        rm -f altitude.h ao_kalman.h
+
+pdclib:
+       mkdir -p $(PDCLIB_ROOT)/include $(PDCLIB_ROOT)/lib 
+       cd ../pdclib && make && make prefix=`pwd`/../pdclib-root install
+
+clean-pdclib:
+       rm -rf $(PDCLIB_ROOT)
+       cd ../pdclib && make clean
index 71ffadb19e658cccb72826d49aeddc1b51d25601..52463f5d3b2f202be30b49b19d35f7601b3518c5 100644 (file)
@@ -310,6 +310,10 @@ void xrijndaelEncrypt(word32 block[], roundkey *rkk)
   xKeyAddition(block, block2, rp, BC);
 }
 
+#if NOTUSED
+/* We don't actually need this in AltOS, so don't bother including it */
+
+/* Decryption of one block. */
 static
 void xrijndaelDecrypt(word32 block[], roundkey *rkk)
 {
@@ -352,6 +356,7 @@ void xrijndaelDecrypt(word32 block[], roundkey *rkk)
 
   xKeyAddition(block, block, rp, BC);
 }
+#endif
 
 uint8_t ao_aes_mutex;
 static uint8_t key[16];
index 8c9d1ae69a6dbe81135cf606c2c12ba738effb57..d4584a9fc1eeeb2dd028948ce3d78e427acd57ee 100644 (file)
  */
 
 #define ao_spi_get_mask(reg,mask,bus,speed) do {       \
-               (reg) &= ~(mask);               \
+               (reg) &= ~(mask);                       \
        } while (0)
 
 #define ao_spi_put_mask(reg,mask,bus) do {     \
                (reg) |= (mask);                \
        } while (0)
 
-#define ao_spi_get_bit(reg,bit,pin,bus,speed) do {     \
-               (pin) = 0;                      \
-       } while (0)
-
-#define ao_spi_put_bit(reg,bit,pin,bus) do {   \
-               (pin) = 1;                      \
-       } while (0)
+#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<(bit)),bus,speed)
 
+#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<(bit)),bus)
 
 #define ao_gpio_token_paster(x,y)              x ## y
 #define ao_gpio_token_evaluator(x,y)   ao_gpio_token_paster(x,y)
@@ -46,6 +41,8 @@
                        PORTB &= ~(1 << bit);   \
        } while (0)
 
+#define ao_gpio_get(port, bit, pin)    ((PORTB >> (bit)) & 1)
+
 /*
  * The SPI mutex must be held to call either of these
  * functions -- this mutex covers the entire SPI operation,
diff --git a/src/attiny/ao_async.c b/src/attiny/ao_async.c
new file mode 100644 (file)
index 0000000..3556f54
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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>
+#include <ao_async.h>
+
+#define AO_ASYNC_BAUD  38400l
+#define AO_ASYNC_DELAY (uint8_t) (1000000l / AO_ASYNC_BAUD)
+
+#define LED_PORT       PORTB
+
+void
+ao_async_start(void)
+{
+       LED_PORT |= (1 << AO_LED_SERIAL);
+}
+
+void
+ao_async_stop(void)
+{
+       LED_PORT &= ~(1 << AO_LED_SERIAL);
+}
+
+void
+ao_async_byte(uint8_t byte)
+{
+       uint8_t         b;
+       uint16_t        w;
+
+       /*    start           data           stop */
+       w = (0x000 << 0) | (byte << 1) | (0x001 << 9);
+
+       ao_arch_block_interrupts();
+       for (b = 0; b < 10; b++) {
+               uint8_t v = LED_PORT & ~(1 << AO_LED_SERIAL);
+               v |= (w & 1) << AO_LED_SERIAL;
+               LED_PORT = v;
+               w >>= 1;
+
+               /* Carefully timed to hit around 9600 baud */
+               asm volatile ("nop");
+               asm volatile ("nop");
+
+               asm volatile ("nop");
+               asm volatile ("nop");
+               asm volatile ("nop");
+               asm volatile ("nop");
+               asm volatile ("nop");
+
+               asm volatile ("nop");
+               asm volatile ("nop");
+               asm volatile ("nop");
+               asm volatile ("nop");
+               asm volatile ("nop");
+       }
+       ao_arch_release_interrupts();
+}
diff --git a/src/attiny/ao_async.h b/src/attiny/ao_async.h
new file mode 100644 (file)
index 0000000..1b23971
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_ASYNC_H_
+#define _AO_ASYNC_H_
+
+void
+ao_async_start(void);
+
+void
+ao_async_stop(void);
+
+void
+ao_async_byte(uint8_t byte);
+
+#endif /* _AO_ASYNC_H_ */
index 2ea4f47d33421e112e5d0d0bfacdd5db7c62387f..85bb2fbabc939eb39b3ad0e31205f287668a6dff 100644 (file)
@@ -30,5 +30,6 @@ ao_exti_setup_port(uint8_t pin, uint8_t mode, void (*callback)(void));
 #define ao_exti_init()
 
 #define AO_EXTI_MODE_RISING    1
+#define AO_EXTI_PIN_NOCONFIGURE        0
 
 #endif /* _AO_EXTI_H_ */
index 932951665d527caa90eb435309b6e09756c37732..6d9bfea2098f9102d4fff464f9f5760ec588a524 100644 (file)
@@ -11,18 +11,12 @@ vpath load_csv.5c ../kalman
 vpath matrix.5c ../kalman
 vpath ao-make-product.5c ../util
 
+include ../avr/Makefile.defs
+
 MCU=atmega32u4
 DUDECPUTYPE=m32u4
 #PROGRAMMER=stk500v2 -P usb
-PROGRAMMER=usbtiny
-LOADCMD=avrdude
 LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc
-OBJCOPY=avr-objcopy
-
-ifndef VERSION
-include ../Version
-endif
 
 INC = \
        ao.h \
diff --git a/src/avr/Makefile.defs b/src/avr/Makefile.defs
new file mode 100644 (file)
index 0000000..eeb9a88
--- /dev/null
@@ -0,0 +1,16 @@
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+ifndef VERSION
+include $(TOPDIR)/Version
+endif
+
+include $(TOPDIR)/Makedefs
+
+CC=$(AVR_CC)
+OBJCOPY=$(AVR_OBJCOPY)
+LDSCRIPTS=/usr/lib/avr/lib/ldscripts
+
+PROGRAMMER=usbtiny
+LOADCMD=avrdude
index 0e19603b29429d4e8177f163ac05d7134dd9b421..78b653b3049abbbf5cd595802d67e5ced89755e1 100644 (file)
@@ -1,4 +1,5 @@
-CC=sdcc
+include ../Makedefs
+CC=$(SDCC)
 
 CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE)
 
index ed76179b5ebeec1813edad23b2f10dc8a6e6624c..1689ebef3b1b831b3b653bf5349c234e2cf1104d 100644 (file)
 
 volatile __xdata struct ao_data        ao_data_ring[AO_DATA_RING];
 volatile __data uint8_t                ao_data_head;
+#if (AO_DATA_ALL & ~(AO_DATA_ADC))
+volatile __data uint8_t                ao_data_present;
+#endif
+
+#ifdef TELENANO_V_0_1
+# define AO_ADC_FIRST_PIN      1
+#endif
+
+#if HAS_ACCEL_REF
+# define AO_ADC_FIRST_PIN      2
+#endif
 
 #ifndef AO_ADC_FIRST_PIN
-#define AO_ADC_FIRST_PIN       0
+# define AO_ADC_FIRST_PIN      0
 #endif
 
 void
 ao_adc_poll(void)
 {
-#if HAS_ACCEL_REF
-       ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 2;
-#else
-# ifdef TELENANO_V_0_1
-       ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | 1;
-# else
        ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | AO_ADC_FIRST_PIN;
-# endif
-#endif
 }
 
 void
@@ -82,6 +85,7 @@ ao_adc_isr(void) __interrupt 1
                else
 #endif
                        ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence;
+               return;
        }
 #endif
 
@@ -141,15 +145,18 @@ ao_adc_isr(void) __interrupt 1
        if (sequence) {
                /* Start next conversion */
                ADCCON3 = sequence;
+               return;
        }
 #endif /* telemini || telenano */
 
-#ifdef TELEFIRE_V_0_1
+#if defined(TELEFIRE_V_0_1) || defined(TELEFIRE_V_0_2)
        a = (uint8_t __xdata *) (&ao_data_ring[ao_data_head].adc.sense[0] + sequence - AO_ADC_FIRST_PIN);
        a[0] = ADCL;
        a[1] = ADCH;
-       if (sequence < 5)
+       if (sequence < 5) {
                ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | (sequence + 1);
+               return;
+       }
 #define GOT_ADC
 #endif /* TELEFIRE_V_0_1 */
 
@@ -157,21 +164,22 @@ ao_adc_isr(void) __interrupt 1
        a = (uint8_t __xdata *) (&ao_data_ring[ao_data_head].adc.batt);
        a[0] = ADCL;
        a[1] = ADCH;
-       if (0)
-               ;
 #define GOT_ADC
 #endif 
 
+#ifdef FETCH_ADC
+       FETCH_ADC();
+#define GOT_ADC
+#endif
+
 #ifndef GOT_ADC
 #error No known ADC configuration set
 #endif
 
-       else {
-               /* record this conversion series */
-               ao_data_ring[ao_data_head].tick = ao_time();
-               ao_data_head = ao_data_ring_next(ao_data_head);
-               ao_wakeup(DATA_TO_XDATA(&ao_data_head));
-       }
+       /* record this conversion series */
+       ao_data_ring[ao_data_head].tick = ao_time();
+       ao_data_head = ao_data_ring_next(ao_data_head);
+       ao_wakeup(DATA_TO_XDATA(&ao_data_head));
 }
 
 static void
index 9097557ffd3460359f148aa8343dba3851b0a462..34235b085421d3c49d2d86852d57f0ff39b335eb 100644 (file)
@@ -321,4 +321,9 @@ void
 ao_serial1_tx_isr(void) ao_arch_interrupt(14);
 #endif
 
+#if HAS_EXTI_0
+void
+ao_p0_isr(void) __interrupt(13);
+#endif
+
 #endif /* _AO_ARCH_H_ */
index 8f1cc09476e099766247de88705fe3bbd22bb54d..ea340dfd56901194b9534a600fb146fbbdef1be4 100644 (file)
  * ao_spi.c
  */
 
-extern __xdata uint8_t ao_spi_mutex;
+#if !HAS_SPI_0 && !HAS_SPI_1
+#define HAS_SPI_0      1
+#define SPI_0_ALT_2    1
+#endif
+
+#if HAS_SPI_0 && HAS_SPI_1
+#define MULTI_SPI      1
+#define N_SPI          2
+#else
+#define MULTI_SPI      0
+#define N_SPI          1
+#endif
+
+extern __xdata uint8_t ao_spi_mutex[N_SPI];
+
+#if MULTI_SPI
+#define ao_spi_get(bus)        ao_mutex_get(&ao_spi_mutex[bus])
+#define ao_spi_put(bus)        ao_mutex_put(&ao_spi_mutex[bus])
+#else
+#define ao_spi_get(bus)        ao_mutex_get(&ao_spi_mutex[0])
+#define ao_spi_put(bus)        ao_mutex_put(&ao_spi_mutex[0])
+#endif
 
 #define AO_SPI_SPEED_FAST      17
 #define AO_SPI_SPEED_200kHz    13
 
-#define ao_spi_set_speed(speed) (U0GCR = (UxGCR_CPOL_NEGATIVE |                \
-                                         UxGCR_CPHA_FIRST_EDGE |       \
-                                         UxGCR_ORDER_MSB |             \
-                                         ((speed) << UxGCR_BAUD_E_SHIFT)))
+#if MULTI_SPI
+#define ao_spi_set_speed(bus,speed) (*(bus ? &U1GCR : &U0GCR) =(UxGCR_CPOL_NEGATIVE | \
+                                                               UxGCR_CPHA_FIRST_EDGE | \
+                                                               UxGCR_ORDER_MSB | \
+                                                               ((speed) << UxGCR_BAUD_E_SHIFT)))
+#else
+#define ao_spi_set_speed(bus,speed) (U0GCR = (UxGCR_CPOL_NEGATIVE |    \
+                                             UxGCR_CPHA_FIRST_EDGE |   \
+                                             UxGCR_ORDER_MSB |         \
+                                             ((speed) << UxGCR_BAUD_E_SHIFT)))
+#endif
 
 #define ao_spi_get_slave(bus) do {                     \
-               ao_mutex_get(&ao_spi_mutex);            \
-               ao_spi_set_speed(AO_SPI_SPEED_FAST);    \
+               ao_spi_get(bus);                        \
+               ao_spi_set_speed(bus,AO_SPI_SPEED_FAST);        \
        } while (0)
 
 #define ao_spi_put_slave(bus) do {             \
-               ao_mutex_put(&ao_spi_mutex);    \
+               ao_spi_put(bus);                \
        } while (0)
 
 #define ao_spi_get_mask(reg,mask,bus,speed) do {       \
-               ao_mutex_get(&ao_spi_mutex);            \
-               ao_spi_set_speed(speed);                \
+               ao_spi_get(bus);                        \
+               ao_spi_set_speed(bus,speed);            \
                (reg) &= ~(mask);                       \
        } while (0)
 
 #define ao_spi_put_mask(reg,mask,bus) do {             \
        (reg) |= (mask); \
-       ao_mutex_put(&ao_spi_mutex); \
+       ao_spi_put(bus); \
        } while (0)
 
 
 #define ao_spi_get_bit(reg,bit,pin,bus,speed) do {     \
-               ao_mutex_get(&ao_spi_mutex);    \
-               ao_spi_set_speed(speed);        \
-               pin = 0;                        \
+               ao_spi_get(bus);                        \
+               ao_spi_set_speed(bus,speed);            \
+               pin = 0;                                \
        } while (0)
 
 #define ao_spi_put_bit(reg,bit,pin,bus) do {   \
                pin = 1;                        \
-               ao_mutex_put(&ao_spi_mutex);    \
+               ao_spi_put(bus);                \
        } while (0)
 
 
@@ -68,6 +96,13 @@ extern __xdata uint8_t       ao_spi_mutex;
  * from chip select low to chip select high
  */
 
+#if MULTI_SPI
+void
+ao_spi_send(void __xdata *block, uint16_t len, uint8_t bus) __reentrant;
+
+void
+ao_spi_recv(void __xdata *block, uint16_t len, uint8_t bus) __reentrant;
+#else
 void
 ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant;
 
@@ -76,6 +111,7 @@ ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant;
 
 #define ao_spi_send(block, len, bus) ao_spi_send_bus(block, len)
 #define ao_spi_recv(block, len, bus) ao_spi_recv_bus(block, len)
+#endif
 
 #if AO_SPI_SLAVE
 void
@@ -88,10 +124,15 @@ ao_spi_recv_wait(void);
 void
 ao_spi_init(void);
 
-#define ao_spi_init_cs(port, mask) do {                \
-               SPI_CS_PORT |= mask;            \
-               SPI_CS_DIR |= mask;             \
-               SPI_CS_SEL &= ~mask;            \
+#define token_paster(x,y)      x ## y
+#define token_paster3(x,y,z)   x ## y ## z
+#define token_evaluator(x,y)   token_paster(x,y)
+#define token_evaluator3(x,y,z)        token_paster3(x,y,z)
+
+#define ao_spi_init_cs(port, mask) do {                        \
+               port |= mask;                           \
+               token_evaluator(port,DIR) |= mask;      \
+               token_evaluator(port,SEL) &= ~mask;     \
        } while (0)
 
 #define cc1111_enable_output(port,dir,sel,pin,bit,v) do {      \
@@ -102,7 +143,7 @@ ao_spi_init(void);
 
 #define disable_unreachable    _Pragma("disable_warning 126")
 
-#define token_paster(x,y)      x ## y
-#define token_evaluator(x,y)   token_paster(x,y)
 #define ao_enable_output(port,bit,pin,v) cc1111_enable_output(port,token_evaluator(port,DIR), token_evaluator(port,SEL), pin, bit, v)
 #define ao_gpio_set(port, bit, pin, v) ((pin) = (v))
+#define ao_gpio_get(port, bit, pin) (pin)
+
diff --git a/src/cc1111/ao_exti.c b/src/cc1111/ao_exti.c
new file mode 100644 (file)
index 0000000..537f625
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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>
+#include <ao_exti.h>
+
+#if HAS_EXTI_0
+__xdata void   (*ao_int_callback)(void);
+
+void
+ao_p0_isr(void) __interrupt(13)
+{
+       if (P0IF && (P0IFG & (AO_MS5607_MISO_MASK))) {
+               (*ao_int_callback)();
+       }
+       P0IFG = 0;
+       P0IF = 0;
+}
+#endif
diff --git a/src/cc1111/ao_exti.h b/src/cc1111/ao_exti.h
new file mode 100644 (file)
index 0000000..49fca5d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_EXTI_H_
+#define _AO_EXTI_H_
+
+#define AO_EXTI_MODE_RISING    1
+#define AO_EXTI_MODE_FALLING   2
+#define AO_EXTI_MODE_PULL_UP   4
+#define AO_EXTI_MODE_PULL_DOWN 8
+#define AO_EXTI_PRIORITY_LOW   16
+#define AO_EXTI_PRIORITY_MED   0
+#define AO_EXTI_PRIORITY_HIGH  32
+
+extern void    (*ao_int_callback)(void);
+
+#define ao_exti_setup(gpio, pin, mode, callback) do { \
+               ao_int_callback = callback;           \
+       } while (0)
+
+#define ao_exti_set_mode(gpio, pin, mode) do { \
+       } while (0)
+
+#define ao_exti_set_callback(port, pin, callback) do { \
+               ao_int_callback = callback;             \
+       } while (0)
+
+#define ao_exti_init()
+
+#define ao_exti_enable(port, pin) do {         \
+               P0IFG &= ~(1 << pin);           \
+               P0IF = 0;                       \
+               PICTL |= PICTL_P0IENL;          \
+               IEN1 |= IEN1_P0IE;              \
+       } while (0)
+
+#define ao_exti_disable(port, pin) do {                \
+               IEN1 &= ~IEN1_P0IE;             \
+               PICTL &= ~PICTL_P0IENL;         \
+       } while (0)
+
+#endif /* _AO_EXTI_H_ */
index 88b8f686e21c09f1c8193076e0f12d5bf4cc2c0c..190647ce0dbe432f6a0b4ee5f8428b686110cf69 100644 (file)
@@ -374,7 +374,7 @@ ao_radio_recv(__xdata void *packet, uint8_t size, uint8_t timeout) __reentrant
        }
 #if NEED_RADIO_RSSI
        else
-               ao_radio_rssi = AO_RSSI_FROM_RADIO(((uint8_t *)packet)[size - 1]);
+               ao_radio_rssi = AO_RSSI_FROM_RADIO(((uint8_t *)packet)[size - 2]);
 #endif
        ao_radio_put();
        return ao_radio_dma_done;
index cdef6bda9d85948bc45ec0fd3f427068c62b4560..fb08f3f5311332226901aaf71a6f2801813e22a4 100644 (file)
 #include "ao.h"
 
 /* Default pin usage for existing Altus Metrum devices */
-#if !HAS_SPI_0 && !HAS_SPI_1
-#define HAS_SPI_0      1
-#define SPI_0_ALT_2    1
-#endif
 
 #ifndef SPI_CONST
 #define SPI_CONST      0xff
  */
 
 #if HAS_SPI_0
-#define SPI_CSR                U0CSR
-#define SPI_BUF                U0DBUFXADDR
-#define SPI_BAUD       U0BAUD
-#define SPI_GCR                U0GCR
-#define SPI_CFG_MASK   PERCFG_U0CFG_ALT_MASK
-#define SPI_DMA_TX     DMA_CFG0_TRIGGER_UTX0
-#define SPI_DMA_RX     DMA_CFG0_TRIGGER_URX0
+#define SPI_BUF_0      &U0DBUFXADDR
+#define SPI_CSR_0      U0CSR
+#define SPI_BAUD_0     U0BAUD
+#define SPI_GCR_0      U0GCR
+#define SPI_CFG_MASK_0 PERCFG_U0CFG_ALT_MASK
+#define SPI_DMA_TX_0   DMA_CFG0_TRIGGER_UTX0
+#define SPI_DMA_RX_0   DMA_CFG0_TRIGGER_URX0
 
 #if SPI_0_ALT_1
-#define SPI_CFG                PERCFG_U0CFG_ALT_1
-#define SPI_SEL                P0SEL
-#define SPI_BITS       (1 << 3) | (1 << 2) | (1 << 5)
-#define SPI_CSS_BIT    (1 << 4)
+#define SPI_CFG_0      PERCFG_U0CFG_ALT_1
+#define SPI_SEL_0      P0SEL
+#define SPI_BITS_0     (1 << 3) | (1 << 2) | (1 << 5)
+#define SPI_CSS_BIT_0  (1 << 4)
 #endif
 
 #if SPI_0_ALT_2
-#define SPI_CFG                PERCFG_U0CFG_ALT_2
-#define SPI_SEL                P1SEL
-#define SPI_PRI                P2SEL_PRI3P1_USART0
-#define SPI_BITS       (1 << 5) | (1 << 4) | (1 << 3)
-#define SPI_CSS_BIT    (1 << 2)
+#define SPI_CFG_0      PERCFG_U0CFG_ALT_2
+#define SPI_SEL_0      P1SEL
+#define SPI_PRI_0      P2SEL_PRI3P1_USART0
+#define SPI_BITS_0     (1 << 5) | (1 << 4) | (1 << 3)
+#define SPI_CSS_BIT_0  (1 << 2)
 #endif
 
 #endif
 
 #if HAS_SPI_1
-#define SPI_CSR                U1CSR
-#define SPI_BUF                U1DBUFXADDR
-#define SPI_BAUD       U1BAUD
-#define SPI_GCR                U1GCR
-#define SPI_CFG_MASK   PERCFG_U1CFG_ALT_MASK
-#define SPI_DMA_TX     DMA_CFG0_TRIGGER_UTX1
-#define SPI_DMA_RX     DMA_CFG0_TRIGGER_URX1
+#define SPI_BUF_1      &U1DBUFXADDR
+#define SPI_CSR_1      U1CSR
+#define SPI_BAUD_1     U1BAUD
+#define SPI_GCR_1      U1GCR
+#define SPI_CFG_MASK_1 PERCFG_U1CFG_ALT_MASK
+#define SPI_DMA_TX_1   DMA_CFG0_TRIGGER_UTX1
+#define SPI_DMA_RX_1   DMA_CFG0_TRIGGER_URX1
 
 #if SPI_1_ALT_1
-#define SPI_CFG                PERCFG_U1CFG_ALT_1
-#define SPI_SEL                P0SEL
-#define SPI_BITS       (1 << 4) | (1 << 5) | (1 << 3)
-#define SPI_CSS_BIT    (1 << 2)
+#define SPI_CFG_1      PERCFG_U1CFG_ALT_1
+#define SPI_SEL_1      P0SEL
+#define SPI_BITS_1     (1 << 4) | (1 << 5) | (1 << 3)
+#define SPI_CSS_BIT_1  (1 << 2)
 #endif
 
 #if SPI_1_ALT_2
-#define SPI_CFG                PERCFG_U1CFG_ALT_2
-#define SPI_SEL                P1SEL
-#define SPI_PRI                P2SEL_PRI3P1_USART1
-#define SPI_BITS       (1 << 6) | (1 << 7) | (1 << 5)
-#define SPI_CSS_BIT    (1 << 4)
+#define SPI_CFG_1      PERCFG_U1CFG_ALT_2
+#define SPI_SEL_1      P1SEL
+#define SPI_PRI_1      P2SEL_PRI3P1_USART1
+#define SPI_BITS_1     (1 << 6) | (1 << 7) | (1 << 5)
+#define SPI_CSS_BIT_1  (1 << 4)
 #endif
 
 #endif
 
+#if MULTI_SPI
+
+#define SPI_BUF(bus)           ((bus) ? SPI_BUF_1 : SPI_BUF_0)
+#define SPI_CSR(bus)           ((bus) ? SPI_CSR_1 : SPI_CSR_0)
+#define SPI_BAUD(bus)          ((bus) ? SPI_BAUD_1 : SPI_BAUD_0)
+#define SPI_GCR(bus)           ((bus) ? SPI_GCR_1 : SPI_GCR_0)
+#define SPI_CFG_MASK(bus)      ((bus) ? SPI_CFG_MASK_1 : SPI_CFG_MASK_0)
+#define SPI_DMA_TX(bus)                ((bus) ? SPI_DMA_TX_1 : SPI_DMA_TX_0)
+#define SPI_DMA_RX(bus)                ((bus) ? SPI_DMA_RX_1 : SPI_DMA_RX_0)
+#define SPI_CFG(bus)           ((bus) ? SPI_CFG_1 : SPI_CFG_0)
+#define SPI_SEL(bus)           ((bus) ? SPI_SEL_1 : SPI_SEL_0)
+#define SPI_BITS(bus)          ((bus) ? SPI_BITS_1 : SPI_BITS_0)
+#define SPI_CSS_BIT(bus)       ((bus) ? SPI_CSS_BIT_1 : SPI_CSS_BIT_0)
+
+#else
+
+#if HAS_SPI_0
+#define SPI_BUF(bus)           SPI_BUF_0
+#define SPI_CSR(bus)           SPI_CSR_0
+#define SPI_BAUD(bus)          SPI_BAUD_0
+#define SPI_GCR(bus)           SPI_GCR_0
+#define SPI_CFG_MASK(bus)      SPI_CFG_MASK_0
+#define SPI_DMA_TX(bus)                SPI_DMA_TX_0
+#define SPI_DMA_RX(bus)                SPI_DMA_RX_0
+#define SPI_CFG(bus)           SPI_CFG_0
+#define SPI_SEL(bus)           SPI_SEL_0
+#define SPI_BITS(bus)          SPI_BITS_0
+#define SPI_CSS_BIT(bus)       SPI_CSS_BIT_0
+#endif
+#if HAS_SPI_1
+#define SPI_BUF(bus)           SPI_BUF_1
+#define SPI_CSR(bus)           SPI_CSR_1
+#define SPI_BAUD(bus)          SPI_BAUD_1
+#define SPI_GCR(bus)           SPI_GCR_1
+#define SPI_CFG_MASK(bus)      SPI_CFG_MASK_1
+#define SPI_DMA_TX(bus)                SPI_DMA_TX_1
+#define SPI_DMA_RX(bus)                SPI_DMA_RX_1
+#define SPI_CFG(bus)           SPI_CFG_1
+#define SPI_SEL(bus)           SPI_SEL_1
+#define SPI_BITS(bus)          SPI_BITS_1
+#define SPI_CSS_BIT(bus)       SPI_CSS_BIT_1
+#endif
+
+#endif /* MULTI_SPI */
+
 #if AO_SPI_SLAVE
-#define CSS            SPI_CSS_BIT
+#define CSS(bus)               SPI_CSS_BIT(bus)
 #define UxCSR_DIRECTION        UxCSR_SLAVE
 #else
-#define CSS            0
+#define CSS(bus)               0
 #define UxCSR_DIRECTION        UxCSR_MASTER
 #endif
 
  * operation, from CS low to CS high. This means that any SPI
  * user must protect the SPI bus with this mutex
  */
-__xdata uint8_t        ao_spi_mutex;
-__xdata uint8_t ao_spi_dma_in_done;
-__xdata uint8_t ao_spi_dma_out_done;
+__xdata uint8_t        ao_spi_mutex[N_SPI];
+__xdata uint8_t ao_spi_dma_in_done[N_SPI];
+__xdata uint8_t ao_spi_dma_out_done[N_SPI];
 
-uint8_t        ao_spi_dma_out_id;
-uint8_t ao_spi_dma_in_id;
+uint8_t        ao_spi_dma_out_id[N_SPI];
+uint8_t ao_spi_dma_in_id[N_SPI];
 
 static __xdata uint8_t ao_spi_const;
 
+
 /* Send bytes over SPI.
  *
  * This sets up two DMA engines, one writing the data and another reading
@@ -140,45 +182,52 @@ static __xdata uint8_t ao_spi_const;
  * is complete, as the transmit register is double buffered and hence signals
  * completion one byte before the transfer is actually complete
  */
+#if MULTI_SPI
+void
+ao_spi_send(void __xdata *block, uint16_t len, uint8_t bus) __reentrant
+#else
 void
 ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant
+#define bus    0
+#endif
 {
-       ao_dma_set_transfer(ao_spi_dma_in_id,
-                           &SPI_BUF,
+       ao_dma_set_transfer(ao_spi_dma_in_id[bus],
+                           SPI_BUF(bus),
                            &ao_spi_const,
                            len,
                            DMA_CFG0_WORDSIZE_8 |
                            DMA_CFG0_TMODE_SINGLE |
-                           SPI_DMA_RX,
+                           SPI_DMA_RX(bus),
                            DMA_CFG1_SRCINC_0 |
                            DMA_CFG1_DESTINC_0 |
                            DMA_CFG1_PRIORITY_NORMAL);
-       ao_dma_set_transfer(ao_spi_dma_out_id,
+       ao_dma_set_transfer(ao_spi_dma_out_id[bus],
                            block,
-                           &SPI_BUF,
+                           SPI_BUF(bus),
                            len,
                            DMA_CFG0_WORDSIZE_8 |
                            DMA_CFG0_TMODE_SINGLE |
-                           SPI_DMA_TX,
+                           SPI_DMA_TX(bus),
                            DMA_CFG1_SRCINC_1 |
                            DMA_CFG1_DESTINC_0 |
                            DMA_CFG1_PRIORITY_NORMAL);
 
-       ao_dma_start(ao_spi_dma_in_id);
-       ao_dma_start(ao_spi_dma_out_id);
-       ao_dma_trigger(ao_spi_dma_out_id);
+       ao_dma_start(ao_spi_dma_in_id[bus]);
+       ao_dma_start(ao_spi_dma_out_id[bus]);
+       ao_dma_trigger(ao_spi_dma_out_id[bus]);
 #if !AO_SPI_SLAVE
-       __critical while (!ao_spi_dma_in_done)
-               ao_sleep(&ao_spi_dma_in_done);
+       __critical while (!ao_spi_dma_in_done[bus])
+               ao_sleep(&ao_spi_dma_in_done[bus]);
 #endif
+#undef bus
 }
 
 #if AO_SPI_SLAVE
 void
 ao_spi_send_wait(void)
 {
-       __critical while (!ao_spi_dma_in_done)
-               ao_sleep(&ao_spi_dma_in_done);
+       __critical while (!ao_spi_dma_in_done[0])
+               ao_sleep(&ao_spi_dma_in_done[0]);
 }
 #endif
 
@@ -188,16 +237,22 @@ ao_spi_send_wait(void)
  * writing constant values to the SPI transmitter as that is what
  * clocks the data coming in.
  */
+#if MULTI_SPI
+void
+ao_spi_recv(void __xdata *block, uint16_t len, uint8_t bus) __reentrant
+#else
 void
 ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant
+#define bus 0
+#endif
 {
-       ao_dma_set_transfer(ao_spi_dma_in_id,
-                           &SPI_BUF,
+       ao_dma_set_transfer(ao_spi_dma_in_id[bus],
+                           SPI_BUF(bus),
                            block,
                            len,
                            DMA_CFG0_WORDSIZE_8 |
                            DMA_CFG0_TMODE_SINGLE |
-                           SPI_DMA_RX,
+                           SPI_DMA_RX(bus),
                            DMA_CFG1_SRCINC_0 |
                            DMA_CFG1_DESTINC_1 |
                            DMA_CFG1_PRIORITY_NORMAL);
@@ -205,24 +260,24 @@ ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant
        ao_spi_const = SPI_CONST;
 
 #if !AO_SPI_SLAVE
-       ao_dma_set_transfer(ao_spi_dma_out_id,
+       ao_dma_set_transfer(ao_spi_dma_out_id[bus],
                            &ao_spi_const,
-                           &SPI_BUF,
+                           SPI_BUF(bus),
                            len,
                            DMA_CFG0_WORDSIZE_8 |
                            DMA_CFG0_TMODE_SINGLE |
-                           SPI_DMA_TX,
+                           SPI_DMA_TX(bus),
                            DMA_CFG1_SRCINC_0 |
                            DMA_CFG1_DESTINC_0 |
                            DMA_CFG1_PRIORITY_NORMAL);
 #endif
 
-       ao_dma_start(ao_spi_dma_in_id);
+       ao_dma_start(ao_spi_dma_in_id[bus]);
 #if !AO_SPI_SLAVE
-       ao_dma_start(ao_spi_dma_out_id);
-       ao_dma_trigger(ao_spi_dma_out_id);
-       __critical while (!ao_spi_dma_in_done)
-               ao_sleep(&ao_spi_dma_in_done);
+       ao_dma_start(ao_spi_dma_out_id[bus]);
+       ao_dma_trigger(ao_spi_dma_out_id[bus]);
+       __critical while (!ao_spi_dma_in_done[bus])
+               ao_sleep(&ao_spi_dma_in_done[bus]);
 #endif
 }
 
@@ -230,17 +285,43 @@ ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant
 void
 ao_spi_recv_wait(void)
 {
-       __critical while (!ao_spi_dma_in_done)
-               ao_sleep(&ao_spi_dma_in_done);
+       __critical while (!ao_spi_dma_in_done[0])
+               ao_sleep(&ao_spi_dma_in_done[0]);
 }
 #endif
 
+/* Set up the USART.
+ *
+ * SPI master/slave mode
+ */
+/* Set the baud rate and signal parameters
+ *
+ * The cc1111 is limited to a 24/8 MHz SPI clock.
+ * Every peripheral I've ever seen goes faster than that,
+ * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0)
+ */
+#define SPI_INIT(bus,o)        do {                                            \
+               /* Set up the USART pin assignment */                   \
+               PERCFG = (PERCFG & ~SPI_CFG_MASK(bus)) | SPI_CFG(bus);  \
+                                                                       \
+               /* Make the SPI pins be controlled by the USART peripheral */ \
+               SPI_SEL(bus) |= SPI_BITS(bus) | CSS(bus);               \
+               SPI_CSR(bus) = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_DIRECTION); \
+               SPI_BAUD(bus) = 0;                                      \
+               SPI_GCR(bus) = (UxGCR_CPOL_NEGATIVE |                   \
+                               UxGCR_CPHA_FIRST_EDGE |                 \
+                               UxGCR_ORDER_MSB |                       \
+                               (17 << UxGCR_BAUD_E_SHIFT));            \
+               /* Set up OUT DMA */                                    \
+               ao_spi_dma_out_id[o] = ao_dma_alloc(&ao_spi_dma_out_done[o]); \
+                                                                       \
+               /* Set up IN DMA */                                     \
+               ao_spi_dma_in_id[o] = ao_dma_alloc(&ao_spi_dma_in_done[o]);     \
+       } while (0)
+
 void
 ao_spi_init(void)
 {
-       /* Set up the USART pin assignment */
-       PERCFG = (PERCFG & ~SPI_CFG_MASK) | SPI_CFG;
-
        /* Ensure that SPI USART takes precidence over the other USART
         * for pins that they share
         */
@@ -248,30 +329,10 @@ ao_spi_init(void)
        P2SEL = (P2SEL & ~P2SEL_PRI3P1_MASK) | SPI_PRI;
 #endif
 
-       /* Make the SPI pins be controlled by the USART peripheral */
-       SPI_SEL |= SPI_BITS | CSS;
-
-       /* Set up OUT DMA */
-       ao_spi_dma_out_id = ao_dma_alloc(&ao_spi_dma_out_done);
-
-       /* Set up IN DMA */
-       ao_spi_dma_in_id = ao_dma_alloc(&ao_spi_dma_in_done);
-
-       /* Set up the USART.
-        *
-        * SPI master/slave mode
-        */
-       SPI_CSR = (UxCSR_MODE_SPI | UxCSR_RE | UxCSR_DIRECTION);
-
-       /* Set the baud rate and signal parameters
-        *
-        * The cc1111 is limited to a 24/8 MHz SPI clock.
-        * Every peripheral I've ever seen goes faster than that,
-        * so set the clock to 3MHz (BAUD_E 17, BAUD_M 0)
-        */
-       SPI_BAUD = 0;
-       SPI_GCR = (UxGCR_CPOL_NEGATIVE |
-                  UxGCR_CPHA_FIRST_EDGE |
-                  UxGCR_ORDER_MSB |
-                  (17 << UxGCR_BAUD_E_SHIFT));
+#if HAS_SPI_0
+       SPI_INIT(0, 0);
+#endif
+#if HAS_SPI_1
+       SPI_INIT(1, MULTI_SPI);
+#endif
 }
index a64b5aba90a0fb5e104a3005dbf2cdda464056ad..75cc4ce8b562e6f339d76451a103b9e3bdd73fc0 100644 (file)
@@ -39,6 +39,9 @@ void ao_timer_isr(void) __interrupt 9
        if (++ao_adc_count == ao_adc_interval) {
                ao_adc_count = 0;
                ao_adc_poll();
+#if (AO_DATA_ALL & ~(AO_DATA_ADC))
+               ao_wakeup(DATA_TO_XDATA(&ao_adc_count));
+#endif
        }
 #endif
 }
@@ -92,6 +95,13 @@ ao_clock_init(void)
        while (!(SLEEP & SLEEP_XOSC_STB))
                ;
 
+       /* Power down the unused HFRC oscillator */
+       SLEEP |= SLEEP_OSC_PD;
+
+       /* Wait for HFRC to power down */
+       while ((SLEEP & SLEEP_HFRC_STB) != 0)
+               ;
+       
        /* Crank up the timer tick and system clock speed */
        CLKCON = ((CLKCON & ~(CLKCON_TICKSPD_MASK | CLKCON_CLKSPD_MASK)) |
                  (CLKCON_TICKSPD_1 | CLKCON_CLKSPD_1));
index a655d1be903589374bae5c5d1af63244ac873697..b0ab409d7e72d96bbce7c3aba51231d13771ae89 100644 (file)
@@ -201,6 +201,11 @@ ao_usb_ep0_setup(void)
                                ao_usb_ep0_queue_byte(0);
                                break;
                        case AO_USB_REQ_SET_ADDRESS:
+#if USB_FORCE_FLIGHT_IDLE
+                               /* Go to idle mode if USB is connected
+                                */
+                               ao_flight_force_idle = 1;
+#endif
                                ao_usb_set_address(ao_usb_setup.value);
                                break;
                        case AO_USB_REQ_GET_DESCRIPTOR:
index 0ad3e4aa6504b68774fdbd7b487a59385ff9a4f2..0b634a7994dd83ad0361649f66a6463c46645b85 100644 (file)
 #define HAS_TASK       1
 #endif
 
+#ifndef AO_PORT_TYPE
+#define AO_PORT_TYPE uint8_t
+#endif
+
+typedef AO_PORT_TYPE ao_port_t;
+
 #if HAS_TASK
 #include <ao_task.h>
 #else
@@ -68,6 +74,8 @@
 #define AO_PANIC_SPI           13      /* SPI communication failure */
 #define AO_PANIC_CRASH         14      /* Processor crashed */
 #define AO_PANIC_BUFIO         15      /* Mis-using bufio API */
+#define AO_PANIC_EXTI          16      /* Mis-using exti API */
+#define AO_PANIC_FAST_TIMER    17      /* Mis-using fast timer API */
 #define AO_PANIC_SELF_TEST_CC1120      0x40 | 1        /* Self test failure */
 #define AO_PANIC_SELF_TEST_HMC5883     0x40 | 2        /* Self test failure */
 #define AO_PANIC_SELF_TEST_MPU6000     0x40 | 3        /* Self test failure */
@@ -174,7 +182,7 @@ void
 ao_cmd_hex(void);
 
 void
-ao_cmd_decimal(void);
+ao_cmd_decimal(void) __reentrant;
 
 /* Read a single hex nibble off stdin. */
 uint8_t
@@ -334,6 +342,10 @@ ao_spi_slave(void);
 #define AO_GPS_DATE_VALID      (1 << 6)
 #define AO_GPS_COURSE_VALID    (1 << 7)
 
+#define AO_GPS_NEW_DATA                1
+#define AO_GPS_NEW_TRACKING    2
+
+extern __xdata uint8_t ao_gps_new;
 extern __pdata uint16_t ao_gps_tick;
 extern __xdata uint8_t ao_gps_mutex;
 extern __xdata struct ao_telemetry_location ao_gps_data;
@@ -379,6 +391,9 @@ ao_gps_print(__xdata struct ao_gps_orig *gps_data);
 void
 ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data);
 
+void
+ao_gps_show(void) __reentrant;
+
 void
 ao_gps_init(void);
 
@@ -693,6 +708,8 @@ struct ao_ignition {
        uint8_t firing;
 };
 
+extern __code char * __code ao_igniter_status_names[];
+
 extern __xdata struct ao_ignition ao_ignition[2];
 
 enum ao_igniter_status
@@ -722,7 +739,7 @@ extern __xdata uint8_t ao_force_freq;
 #endif
 
 #define AO_CONFIG_MAJOR        1
-#define AO_CONFIG_MINOR        14
+#define AO_CONFIG_MINOR        15
 
 #define AO_AES_LEN 16
 
@@ -756,6 +773,11 @@ struct ao_config {
 #if HAS_RADIO_AMP
        uint8_t         radio_amp;              /* minor version 14 */
 #endif
+#if HAS_GYRO
+       int16_t         accel_zero_along;       /* minor version 15 */
+       int16_t         accel_zero_across;      /* minor version 15 */
+       int16_t         accel_zero_through;     /* minor version 15 */
+#endif
 };
 
 #define AO_IGNITE_MODE_DUAL            0
index 0dd87080037686a1c099c11bc024aaa0039ea06f..373db1c4794ccf81ad5f4496e3ba997c59d29860 100644 (file)
@@ -28,10 +28,6 @@ ao_adc_poll(void);
 void
 ao_adc_sleep(void);
 
-/* Get a copy of the last complete sample set */
-void
-ao_data_get(__xdata struct ao_data *packet);
-
 /* Initialize the A/D converter */
 void
 ao_adc_init(void);
index 188b8bb4c693c71aa23dd75c74ed5f7a3fc59dfa..4ebaa6079368ec80164a8176d8d010914552cc9d 100644 (file)
@@ -206,9 +206,9 @@ ao_cmd_hex(void)
 }
 
 void
-ao_cmd_decimal(void)
+ao_cmd_decimal(void) __reentrant
 {
-       __pdata uint8_t r = ao_cmd_lex_error;
+       uint8_t r = ao_cmd_lex_error;
 
        ao_cmd_lex_u32 = 0;
        ao_cmd_white();
@@ -290,9 +290,6 @@ version(void)
               , ao_log_format
 #endif
                );
-#if HAS_MS5607
-       ao_ms5607_info();
-#endif
        printf("software-version %s\n", ao_version);
 }
 #endif
index 73608a55c542923b9692458838f0e20f91106c3e..a30ec64a5e8a9d0c1c4c8ea59d7766e363ae5ea2 100644 (file)
@@ -17,7 +17,7 @@
 
 #include "ao.h"
 #include "ao_log.h"
-#include <ao_storage.h>
+#include <ao_config.h>
 #if HAS_FLIGHT
 #include <ao_sample.h>
 #include <ao_data.h>
@@ -28,6 +28,9 @@ __pdata uint8_t ao_config_loaded;
 __pdata uint8_t ao_config_dirty;
 __xdata uint8_t ao_config_mutex;
 
+#ifndef AO_CONFIG_DEFAULT_APRS_INTERVAL
+#define AO_CONFIG_DEFAULT_APRS_INTERVAL        0
+#endif
 #define AO_CONFIG_DEFAULT_MAIN_DEPLOY  250
 #define AO_CONFIG_DEFAULT_RADIO_CHANNEL        0
 #define AO_CONFIG_DEFAULT_CALLSIGN     "N0CALL"
@@ -47,20 +50,22 @@ __xdata uint8_t ao_config_mutex;
 #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       ((uint32_t) 192 * (uint32_t) 1024)
 #endif
 #endif
+#ifndef AO_CONFIG_DEFAULT_RADIO_POWER
 #define AO_CONFIG_DEFAULT_RADIO_POWER          0x60
+#endif
 #define AO_CONFIG_DEFAULT_RADIO_AMP            0
 
 #if HAS_EEPROM
 static void
 _ao_config_put(void)
 {
-       ao_storage_setup();
-       ao_storage_erase(ao_storage_config);
-       ao_storage_write(ao_storage_config, &ao_config, sizeof (ao_config));
+       ao_config_setup();
+       ao_config_erase();
+       ao_config_write(0, &ao_config, sizeof (ao_config));
 #if HAS_FLIGHT
        ao_log_write_erase(0);
 #endif
-       ao_storage_flush();
+       ao_config_flush();
 }
 
 void
@@ -92,8 +97,8 @@ _ao_config_get(void)
         * but ao_storage_setup *also* sets ao_storage_config, which we
         * need before calling ao_storage_read here
         */
-       ao_storage_setup();
-       ao_storage_read(ao_storage_config, &ao_config, sizeof (ao_config));
+       ao_config_setup();
+       ao_config_read(0, &ao_config, sizeof (ao_config));
 #endif
        if (ao_config.major != AO_CONFIG_MAJOR) {
                ao_config.major = AO_CONFIG_MAJOR;
@@ -122,8 +127,10 @@ _ao_config_get(void)
                        ao_config.radio_cal = ao_radio_cal;
 #endif
                /* Fixups for minor version 4 */
+#if HAS_FLIGHT
                if (minor < 4)
                        ao_config.flight_log_max = AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX;
+#endif
                /* Fixupes for minor version 5 */
                if (minor < 5)
                        ao_config.ignite_mode = AO_CONFIG_DEFAULT_IGNITE_MODE;
@@ -142,7 +149,7 @@ _ao_config_get(void)
                        memset(&ao_config.pyro, '\0', sizeof (ao_config.pyro));
 #endif
                if (minor < 13)
-                       ao_config.aprs_interval = 0;
+                       ao_config.aprs_interval = AO_CONFIG_DEFAULT_APRS_INTERVAL;
 #if HAS_RADIO_POWER
                if (minor < 14)
                        ao_config.radio_power = AO_CONFIG_DEFAULT_RADIO_POWER;
@@ -150,6 +157,19 @@ _ao_config_get(void)
 #if HAS_RADIO_AMP
                if (minor  < 14)
                        ao_config.radio_amp = AO_CONFIG_DEFAULT_RADIO_AMP;
+#endif
+#if HAS_GYRO
+               if (minor < 15) {
+                       ao_config.accel_zero_along = 0;
+                       ao_config.accel_zero_across = 0;
+                       ao_config.accel_zero_through = 0;
+
+                       /* Reset the main accel offsets to force
+                        * re-calibration
+                        */
+                       ao_config.accel_plus_g = 0;
+                       ao_config.accel_minus_g = 0;
+               }
 #endif
                ao_config.minor = AO_CONFIG_MINOR;
                ao_config_dirty = 1;
@@ -270,17 +290,34 @@ ao_config_accel_calibrate_show(void) __reentrant
 {
        printf("Accel cal +1g: %d -1g: %d\n",
               ao_config.accel_plus_g, ao_config.accel_minus_g);
+#if HAS_GYRO
+       printf ("IMU cal along %d across %d through %d\n",
+               ao_config.accel_zero_along,
+               ao_config.accel_zero_across,
+               ao_config.accel_zero_through);
+#endif
 }
 
 #define ACCEL_CALIBRATE_SAMPLES        1024
 #define ACCEL_CALIBRATE_SHIFT  10
 
+#if HAS_GYRO
+static int16_t accel_cal_along;
+static int16_t accel_cal_across;
+static int16_t accel_cal_through;
+#endif
+
 static int16_t
 ao_config_accel_calibrate_auto(char *orientation) __reentrant
 {
        uint16_t        i;
        int32_t         accel_total;
        uint8_t         cal_data_ring;
+#if HAS_GYRO
+       int32_t         accel_along_total = 0;
+       int32_t         accel_across_total = 0;
+       int32_t         accel_through_total = 0;
+#endif
 
        printf("Orient antenna %s and press a key...", orientation);
        flush();
@@ -294,10 +331,20 @@ ao_config_accel_calibrate_auto(char *orientation) __reentrant
                ao_sleep(DATA_TO_XDATA(&ao_sample_data));
                while (i && cal_data_ring != ao_sample_data) {
                        accel_total += (int32_t) ao_data_accel(&ao_data_ring[cal_data_ring]);
+#if HAS_GYRO
+                       accel_along_total += (int32_t) ao_data_along(&ao_data_ring[cal_data_ring]);
+                       accel_across_total += (int32_t) ao_data_across(&ao_data_ring[cal_data_ring]);
+                       accel_through_total += (int32_t) ao_data_through(&ao_data_ring[cal_data_ring]);
+#endif
                        cal_data_ring = ao_data_ring_next(cal_data_ring);
                        i--;
                }
        }
+#if HAS_GYRO
+       accel_cal_along = accel_along_total >> ACCEL_CALIBRATE_SHIFT;
+       accel_cal_across = accel_across_total >> ACCEL_CALIBRATE_SHIFT;
+       accel_cal_through = accel_through_total >> ACCEL_CALIBRATE_SHIFT;
+#endif
        return accel_total >> ACCEL_CALIBRATE_SHIFT;
 }
 
@@ -305,12 +352,28 @@ void
 ao_config_accel_calibrate_set(void) __reentrant
 {
        int16_t up, down;
+#if HAS_GYRO
+       int16_t accel_along_up, accel_along_down;
+       int16_t accel_across_up, accel_across_down;
+       int16_t accel_through_up, accel_through_down;
+#endif
+       
        ao_cmd_decimal();
        if (ao_cmd_status != ao_cmd_success)
                return;
        if (ao_cmd_lex_i == 0) {
                up = ao_config_accel_calibrate_auto("up");
+#if HAS_GYRO
+               accel_along_up = accel_cal_along;
+               accel_across_up = accel_cal_across;
+               accel_through_up = accel_cal_through;
+#endif
                down = ao_config_accel_calibrate_auto("down");
+#if HAS_GYRO
+               accel_along_down = accel_cal_along;
+               accel_across_down = accel_cal_across;
+               accel_through_down = accel_cal_through;
+#endif
        } else {
                up = ao_cmd_lex_i;
                ao_cmd_decimal();
@@ -326,6 +389,11 @@ ao_config_accel_calibrate_set(void) __reentrant
        _ao_config_edit_start();
        ao_config.accel_plus_g = up;
        ao_config.accel_minus_g = down;
+#if HAS_GYRO
+       ao_config.accel_zero_along = (accel_along_up + accel_along_down) / 2;
+       ao_config.accel_zero_across = (accel_across_up + accel_across_down) / 2;
+       ao_config.accel_zero_through = (accel_through_up + accel_through_down) / 2;
+#endif
        _ao_config_edit_finish();
 }
 #endif /* HAS_ACCEL */
@@ -399,7 +467,7 @@ void
 ao_config_log_set(void) __reentrant
 {
        uint16_t        block = (uint16_t) (ao_storage_block >> 10);
-       uint16_t        config = (uint16_t) (ao_storage_config >> 10);
+       uint16_t        log_max = (uint16_t) (ao_storage_log_max >> 10);
 
        ao_cmd_decimal();
        if (ao_cmd_status != ao_cmd_success)
@@ -408,8 +476,8 @@ ao_config_log_set(void) __reentrant
                printf("Storage must be empty before changing log size\n");
        else if (block > 1024 && (ao_cmd_lex_i & (block - 1)))
                printf("Flight log size must be multiple of %d kB\n", block);
-       else if (ao_cmd_lex_i > config)
-               printf("Flight log max %d kB\n", config);
+       else if (ao_cmd_lex_i > log_max)
+               printf("Flight log max %d kB\n", log_max);
        else {
                _ao_config_edit_start();
                ao_config.flight_log_max = (uint32_t) ao_cmd_lex_i << 10;
@@ -589,7 +657,7 @@ static void
 ao_config_show(void) __reentrant;
 
 static void
-ao_config_write(void) __reentrant;
+ao_config_save(void) __reentrant;
 
 __code struct ao_config_var ao_config_vars[] = {
 #if HAS_FLIGHT
@@ -648,7 +716,7 @@ __code struct ao_config_var ao_config_vars[] = {
          ao_config_show,               0 },
 #if HAS_EEPROM
        { "w\0Write to eeprom",
-         ao_config_write,              0 },
+         ao_config_save,               0 },
 #endif
        { "?\0Help",
          ao_config_help,               0 },
@@ -693,11 +761,14 @@ ao_config_show(void) __reentrant
        for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
                if (ao_config_vars[cmd].show)
                        (*ao_config_vars[cmd].show)();
+#if HAS_MS5607
+       ao_ms5607_info();
+#endif
 }
 
 #if HAS_EEPROM
 static void
-ao_config_write(void) __reentrant
+ao_config_save(void) __reentrant
 {
        uint8_t saved = 0;
        ao_mutex_get(&ao_config_mutex);
diff --git a/src/core/ao_config.h b/src/core/ao_config.h
new file mode 100644 (file)
index 0000000..e101af8
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_CONFIG_H_
+#define _AO_CONFIG_H_
+
+#ifndef USE_STORAGE_CONFIG
+#define USE_STORAGE_CONFIG 1
+#endif
+
+#ifndef USE_EEPROM_CONFIG
+#define USE_EEPROM_CONFIG 0
+#endif
+
+#if USE_STORAGE_CONFIG
+
+#include <ao_storage.h>
+
+#define ao_config_setup()              ao_storage_setup()
+#define ao_config_erase()              ao_storage_erase(ao_storage_config)
+#define ao_config_write(pos,bytes, len)        ao_storage_write(ao_storage_config+(pos), bytes, len)
+#define ao_config_read(pos,bytes, len) ao_storage_read(ao_storage_config+(pos), bytes, len)
+#define ao_config_flush()              ao_storage_flush()
+
+#endif
+
+#if USE_EEPROM_CONFIG
+
+#include <ao_eeprom.h>
+
+#define ao_config_setup()
+#define ao_config_erase()
+#define ao_config_write(pos,bytes, len)        ao_eeprom_write(pos, bytes, len)
+#define ao_config_read(pos,bytes, len) ao_eeprom_read(pos, bytes, len)
+#define ao_config_flush()
+
+#endif
+
+#endif /* _AO_CONFIG_H_ */
diff --git a/src/core/ao_data.c b/src/core/ao_data.c
new file mode 100644 (file)
index 0000000..6a3d02a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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>
+#include <ao_data.h>
+
+volatile __xdata struct ao_data        ao_data_ring[AO_DATA_RING];
+volatile __data uint8_t                ao_data_head;
+volatile __data uint8_t                ao_data_present;
+
+#ifndef ao_data_count
+void
+ao_data_get(__xdata struct ao_data *packet)
+{
+#if HAS_FLIGHT
+       uint8_t i = ao_data_ring_prev(ao_sample_data);
+#else
+       uint8_t i = ao_data_ring_prev(ao_data_head);
+#endif
+       memcpy(packet, (void *) &ao_data_ring[i], sizeof (struct ao_data));
+}
+#endif
index 7e2f85d8fb569894c09a75672f57f046df048007..e1d8a1392acc537b1925de297caecf0afac93c3c 100644 (file)
@@ -18,6 +18,8 @@
 #ifndef _AO_DATA_H_
 #define _AO_DATA_H_
 
+#define GRAVITY 9.80665
+
 #if HAS_ADC
 #define AO_DATA_ADC    (1 << 0)
 #else
@@ -82,6 +84,10 @@ struct ao_data {
 #define ao_data_ring_next(n)   (((n) + 1) & (AO_DATA_RING - 1))
 #define ao_data_ring_prev(n)   (((n) - 1) & (AO_DATA_RING - 1))
 
+/* Get a copy of the last complete sample set */
+void
+ao_data_get(__xdata struct ao_data *packet);
+
 extern volatile __xdata struct ao_data ao_data_ring[AO_DATA_RING];
 extern volatile __data uint8_t         ao_data_head;
 extern volatile __data uint8_t         ao_data_present;
@@ -97,7 +103,7 @@ extern volatile __data uint8_t               ao_data_count;
  * signaled by the timer tick
  */
 #define AO_DATA_WAIT() do {                            \
-               ao_sleep((void *) &ao_data_count);      \
+               ao_sleep(DATA_TO_XDATA ((void *) &ao_data_count));      \
        } while (0)
 
 #endif /* AO_DATA_RING */
@@ -268,7 +274,11 @@ typedef int16_t accel_t;
 /* MMA655X is hooked up so that positive values represent negative acceleration */
 
 #define ao_data_accel(packet)                  ((packet)->mma655x)
+#if AO_MMA655X_INVERT
+#define ao_data_accel_cook(packet)             (4095 - (packet)->mma655x)
+#else
 #define ao_data_accel_cook(packet)             ((packet)->mma655x)
+#endif
 #define ao_data_set_accel(packet, accel)       ((packet)->mma655x = (accel))
 #define ao_data_accel_invert(accel)            (4095 - (accel))
 
@@ -292,8 +302,8 @@ typedef int16_t accel_t;
 
 #define HAS_GYRO       1
 
-typedef int16_t        gyro_t;
-typedef int32_t angle_t;
+typedef int16_t        gyro_t;         /* in raw sample units */
+typedef int16_t angle_t;       /* in degrees */
 
 /* Y axis is aligned with the direction of motion (along) */
 /* X axis is aligned in the other board axis (across) */
@@ -309,4 +319,16 @@ typedef int32_t angle_t;
 
 #endif
 
+#if !HAS_MAG && HAS_HMC5883
+
+#define HAS_MAG                1
+
+typedef int16_t ao_mag_t;              /* in raw sample units */
+
+#define ao_data_mag_along(packet)      ((packet)->hmc5883.x)
+#define ao_data_mag_across(packet)     ((packet)->hmc5883.y)
+#define ao_data_mag_through(packet)    ((packet)->hmc5883.z)
+
+#endif
+
 #endif /* _AO_DATA_H_ */
diff --git a/src/core/ao_debounce.c b/src/core/ao_debounce.c
new file mode 100644 (file)
index 0000000..b9d6772
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_debounce.h>
+#include <ao_fast_timer.h>
+
+static uint8_t                 ao_debounce_initialized;
+static uint8_t                 ao_debounce_running;
+static struct ao_debounce      *ao_debounce;
+
+static uint8_t values[64];
+static uint8_t n;
+
+#define d_step(n)      (((n) + 1) & 63)
+
+static void
+_ao_debounce_set(struct ao_debounce *debounce, uint8_t value)
+{
+       if (value != debounce->value) {
+               values[n] = value;
+               n = (n + 1) & 63;
+               debounce->value = value;
+               debounce->_set(debounce, value);
+       }
+       _ao_debounce_stop(debounce);
+}
+
+void
+ao_debounce_dump(void)
+{
+       uint8_t s;
+
+       for (s = 0; s < n; s++) {
+               printf ("%d: %d\n",
+                       s, values[s]);
+       }
+       n = 0;
+}
+
+/*
+ * Get the current value, set the result when we've
+ * reached the debounce count limit
+ */
+static void
+_ao_debounce_check(struct ao_debounce *debounce)
+{
+       uint8_t next = debounce->_get(debounce);
+
+       if (next == debounce->current) {
+               if (debounce->count < debounce->hold) {
+                       if (++debounce->count == debounce->hold)
+                               _ao_debounce_set(debounce, debounce->current);
+               }
+       } else {
+               debounce->count = 0;
+               debounce->current = next;
+       }
+}
+
+static void
+_ao_debounce_isr(void)
+{
+       struct ao_debounce *debounce, *next;
+
+       for (debounce = ao_debounce; debounce; debounce = next) {
+               next = debounce->next;
+               _ao_debounce_check(debounce);
+       }
+}
+
+static void
+ao_debounce_on(void)
+{
+       ao_fast_timer_on(_ao_debounce_isr);
+}
+
+static void
+ao_debounce_off(void)
+{
+       ao_fast_timer_off(_ao_debounce_isr);
+}
+
+/*
+ * Start monitoring one pin
+ */
+void
+_ao_debounce_start(struct ao_debounce *debounce)
+{
+       uint32_t        m;
+
+       m = ao_arch_irqsave();
+       if (!debounce->running) {
+               debounce->running = 1;
+
+               /* Reset the counter */
+               debounce->count = 0;
+
+               /* Link into list */
+               debounce->next = ao_debounce;
+               ao_debounce = debounce;
+
+               /* Make sure the timer is running */
+               if (!ao_debounce_running++)
+                       ao_debounce_on();
+
+               /* And go check the current value */
+               _ao_debounce_check(debounce);
+       }
+       ao_arch_irqrestore(m);
+}
+
+/*
+ * Stop monitoring one pin
+ */
+void
+_ao_debounce_stop(struct ao_debounce *debounce)
+{
+       struct ao_debounce **prev;
+       uint32_t m;
+
+       m = ao_arch_irqsave();
+       if (debounce->running) {
+               debounce->running = 0;
+
+               /* Unlink */
+               for (prev = &ao_debounce; (*prev); prev = &((*prev)->next)) {
+                       if (*prev == debounce) {
+                               *prev = debounce->next;
+                               break;
+                       }
+               }
+               debounce->next = NULL;
+
+               /* Turn off the timer if possible */
+               if (!--ao_debounce_running)
+                       ao_debounce_off();
+       }
+       ao_arch_irqrestore(m);
+}
+
+void
+ao_debounce_init(void)
+{
+       if (ao_debounce_initialized)
+               return;
+       ao_debounce_initialized = 1;
+       ao_fast_timer_init();
+}
diff --git a/src/core/ao_debounce.h b/src/core/ao_debounce.h
new file mode 100644 (file)
index 0000000..19c620f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_DEBOUNCE_H_
+#define _AO_DEBOUNCE_H_
+
+struct ao_debounce {
+       struct ao_debounce      *next;
+
+       /* time that pin value must be stable before accepting */
+       uint8_t                 hold;
+
+       /* last value reported to app; don't report it twice */
+       uint8_t                 value;
+
+       /* current value received from pins */
+       uint8_t                 current;
+
+       /* current count of intervals pin value has been stable */
+       uint8_t                 count;
+
+       /* This pin is running */
+       uint8_t                 running;
+
+       /* Get the current pin value */
+       uint8_t                 (*_get)(struct ao_debounce *debounce);
+
+       /* The stable value has changed */
+       void                    (*_set)(struct ao_debounce *debounce, uint8_t value);
+};
+
+static inline void
+ao_debounce_config(struct ao_debounce *debounce,
+                  uint8_t (*_get)(struct ao_debounce *debounce),
+                  void (*_set)(struct ao_debounce *debounce, uint8_t value),
+                  uint8_t hold)
+{
+       debounce->next = 0;
+       debounce->hold = hold;
+       debounce->value = 0xff;
+       debounce->current = 0xff;
+       debounce->count = 0;
+       debounce->running = 0;
+       debounce->_get = _get;
+       debounce->_set = _set;
+}
+
+void
+_ao_debounce_start(struct ao_debounce *debounce);
+
+void
+_ao_debounce_stop(struct ao_debounce *debounce);
+
+void
+ao_debounce_init(void);
+
+void
+ao_debounce_dump(void);
+
+#endif /* _AO_DEBOUNCE_H_ */
diff --git a/src/core/ao_eeprom.h b/src/core/ao_eeprom.h
new file mode 100644 (file)
index 0000000..915522b
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_EEPROM_H_
+#define _AO_EEPROM_H_
+
+extern const ao_pos_t  ao_eeprom_total;
+
+/*
+ * Write to eeprom
+ */
+
+uint8_t
+ao_eeprom_write(ao_pos_t pos32, __xdata void *v, uint16_t len);
+
+/*
+ * Read from eeprom
+ */
+uint8_t
+ao_eeprom_read(ao_pos_t pos, __xdata void *v, uint16_t len);
+
+/*
+ * Initialize eeprom
+ */
+
+void
+ao_eeprom_init(void);
+
+#endif /* _AO_EEPROM_H_ */
index 9d9d4c6e0b3ddea72a724b1b3eacee94dbb9f76c..463ff4a2974b38e045fb2214ca9bc163cd490d28 100644 (file)
 #include <ao_log.h>
 #endif
 
+#if HAS_MPU6000
+#include <ao_quaternion.h>
+#endif
+
 #ifndef HAS_ACCEL
 #error Please define HAS_ACCEL
 #endif
@@ -42,6 +46,11 @@ __pdata enum ao_flight_state ao_flight_state;        /* current flight state */
 __pdata uint16_t               ao_boost_tick;          /* time of launch detect */
 __pdata uint16_t               ao_motor_number;        /* number of motors burned so far */
 
+#if HAS_IMU
+/* Any sensor can set this to mark the flight computer as 'broken' */
+__xdata uint8_t                        ao_sensor_errors;
+#endif
+
 /*
  * track min/max data over a long interval to detect
  * resting
@@ -95,6 +104,9 @@ ao_flight(void)
                            ao_config.accel_minus_g == 0 ||
                            ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP ||
                            ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP ||
+#if HAS_IMU
+                           ao_sensor_errors ||
+#endif
                            ao_ground_height < -1000 ||
                            ao_ground_height > 7000)
                        {
@@ -117,14 +129,14 @@ ao_flight(void)
                        {
                                /* Set pad mode - we can fly! */
                                ao_flight_state = ao_flight_pad;
-#if HAS_USB && HAS_RADIO && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE
+#if HAS_USB && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE
                                /* Disable the USB controller in flight mode
                                 * to save power
                                 */
                                ao_usb_disable();
 #endif
 
-#if !HAS_ACCEL
+#if !HAS_ACCEL && PACKET_HAS_SLAVE
                                /* Disable packet mode in pad state on TeleMini */
                                ao_packet_slave_stop();
 #endif
@@ -134,8 +146,10 @@ ao_flight(void)
                                ao_rdf_set(1);
                                ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
 #endif
+#if HAS_LED
                                /* signal successful initialization by turning off the LED */
                                ao_led_off(AO_LED_RED);
+#endif
                        } else {
                                /* Set idle mode */
                                ao_flight_state = ao_flight_idle;
@@ -145,8 +159,10 @@ ao_flight(void)
                                ao_packet_slave_start();
 #endif
 
+#if HAS_LED
                                /* signal successful initialization by turning off the LED */
                                ao_led_off(AO_LED_RED);
+#endif
                        }
                        /* wakeup threads due to state change */
                        ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
@@ -190,8 +206,8 @@ ao_flight(void)
 
 #if HAS_GPS
                                /* Record current GPS position by waking up GPS log tasks */
-                               ao_wakeup(&ao_gps_data);
-                               ao_wakeup(&ao_gps_tracking_data);
+                               ao_gps_new = AO_GPS_NEW_DATA | AO_GPS_NEW_TRACKING;
+                               ao_wakeup(&ao_gps_new);
 #endif
 
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
@@ -356,6 +372,18 @@ ao_flight(void)
                                ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
                        }
                        break;
+#if HAS_FLIGHT_DEBUG
+               case ao_flight_test:
+#if HAS_GYRO
+                       printf ("angle %4d pitch %7d yaw %7d roll %7d\n",
+                               ao_sample_orient,
+                               ((ao_sample_pitch << 9) - ao_ground_pitch) >> 9,
+                               ((ao_sample_yaw << 9) - ao_ground_yaw) >> 9,
+                               ((ao_sample_roll << 9) - ao_ground_roll) >> 9);
+#endif
+                       flush();
+                       break;
+#endif /* HAS_FLIGHT_DEBUG */
                default:
                        break;
                }
@@ -406,8 +434,17 @@ ao_flight_dump(void)
        printf ("  error_avg   %d\n", ao_error_h_sq_avg);
 }
 
+static void
+ao_gyro_test(void)
+{
+       ao_flight_state = ao_flight_test;
+       ao_getchar();
+       ao_flight_state = ao_flight_idle;
+}
+
 __code struct ao_cmds ao_flight_cmds[] = {
        { ao_flight_dump,       "F\0Dump flight status" },
+       { ao_gyro_test,         "G\0Test gyro code" },
        { 0, NULL },
 };
 #endif
index b80202f0d7b3e2a6716c91e84f928ec72ee00c77..c7c02ccf69cc4166e0549513d5d1b02971a4c078 100644 (file)
@@ -33,13 +33,18 @@ enum ao_flight_state {
        ao_flight_drogue = 6,
        ao_flight_main = 7,
        ao_flight_landed = 8,
-       ao_flight_invalid = 9
+       ao_flight_invalid = 9,
+       ao_flight_test = 10
 };
 
 extern __pdata enum ao_flight_state    ao_flight_state;
 extern __pdata uint16_t                        ao_boost_tick;
 extern __pdata uint16_t                        ao_motor_number;
 
+#if HAS_IMU
+extern __xdata uint8_t                 ao_sensor_errors;
+#endif
+
 extern __pdata uint16_t                        ao_launch_time;
 extern __pdata uint8_t                 ao_flight_force_idle;
 
index c52ef6219ed2afa1e0b3e0cdbd6d9e9256f14438..07201ac235b69cd1656979fae18aaa94327c2d73 100644 (file)
@@ -22,78 +22,68 @@ ao_gps_report(void)
 {
        static __xdata struct ao_log_record             gps_log;
        static __xdata struct ao_telemetry_location     gps_data;
+       static __xdata struct ao_telemetry_satellite    gps_tracking_data;
        uint8_t date_reported = 0;
+       uint8_t new;
 
        for (;;) {
-               ao_sleep(&ao_gps_data);
+               while ((new = ao_gps_new) == 0)
+                       ao_sleep(&ao_gps_new);
                ao_mutex_get(&ao_gps_mutex);
-               ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
+               if (new & AO_GPS_NEW_DATA)
+                       ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
+               if (new & AO_GPS_NEW_TRACKING)
+                       ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
+               ao_gps_new = 0;
                ao_mutex_put(&ao_gps_mutex);
 
-               if (!(gps_data.flags & AO_GPS_VALID))
-                       continue;
-
-               gps_log.tick = ao_gps_tick;
-               gps_log.type = AO_LOG_GPS_TIME;
-               gps_log.u.gps_time.hour = gps_data.hour;
-               gps_log.u.gps_time.minute = gps_data.minute;
-               gps_log.u.gps_time.second = gps_data.second;
-               gps_log.u.gps_time.flags = gps_data.flags;
-               ao_log_data(&gps_log);
-               gps_log.type = AO_LOG_GPS_LAT;
-               gps_log.u.gps_latitude = gps_data.latitude;
-               ao_log_data(&gps_log);
-               gps_log.type = AO_LOG_GPS_LON;
-               gps_log.u.gps_longitude = gps_data.longitude;
-               ao_log_data(&gps_log);
-               gps_log.type = AO_LOG_GPS_ALT;
-               gps_log.u.gps_altitude.altitude = gps_data.altitude;
-               gps_log.u.gps_altitude.unused = 0xffff;
-               ao_log_data(&gps_log);
-               if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) {
-                       gps_log.type = AO_LOG_GPS_DATE;
-                       gps_log.u.gps_date.year = gps_data.year;
-                       gps_log.u.gps_date.month = gps_data.month;
-                       gps_log.u.gps_date.day = gps_data.day;
-                       gps_log.u.gps_date.extra = 0;
-                       date_reported = ao_log_data(&gps_log);
+               if ((new & AO_GPS_NEW_DATA) && (gps_data.flags & AO_GPS_VALID)) {
+                       gps_log.tick = ao_gps_tick;
+                       gps_log.type = AO_LOG_GPS_TIME;
+                       gps_log.u.gps_time.hour = gps_data.hour;
+                       gps_log.u.gps_time.minute = gps_data.minute;
+                       gps_log.u.gps_time.second = gps_data.second;
+                       gps_log.u.gps_time.flags = gps_data.flags;
+                       ao_log_data(&gps_log);
+                       gps_log.type = AO_LOG_GPS_LAT;
+                       gps_log.u.gps_latitude = gps_data.latitude;
+                       ao_log_data(&gps_log);
+                       gps_log.type = AO_LOG_GPS_LON;
+                       gps_log.u.gps_longitude = gps_data.longitude;
+                       ao_log_data(&gps_log);
+                       gps_log.type = AO_LOG_GPS_ALT;
+                       gps_log.u.gps_altitude.altitude = gps_data.altitude;
+                       gps_log.u.gps_altitude.unused = 0xffff;
+                       ao_log_data(&gps_log);
+                       if (!date_reported && (gps_data.flags & AO_GPS_DATE_VALID)) {
+                               gps_log.type = AO_LOG_GPS_DATE;
+                               gps_log.u.gps_date.year = gps_data.year;
+                               gps_log.u.gps_date.month = gps_data.month;
+                               gps_log.u.gps_date.day = gps_data.day;
+                               gps_log.u.gps_date.extra = 0;
+                               date_reported = ao_log_data(&gps_log);
+                       }
                }
-       }
-}
-
-void
-ao_gps_tracking_report(void)
-{
-       static __xdata struct ao_log_record             gps_log;
-       static __xdata struct ao_telemetry_satellite    gps_tracking_data;
-       uint8_t c, n;
-
-       for (;;) {
-               ao_sleep(&ao_gps_tracking_data);
-               ao_mutex_get(&ao_gps_mutex);
-               gps_log.tick = ao_gps_tick;
-               ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
-               ao_mutex_put(&ao_gps_mutex);
+               if (new & AO_GPS_NEW_TRACKING) {
+                       uint8_t c, n;
 
-               if (!(n = gps_tracking_data.channels))
-                       continue;
-
-               gps_log.type = AO_LOG_GPS_SAT;
-               for (c = 0; c < n; c++)
-                       if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid))
-                       {
-                               gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1;
-                               ao_log_data(&gps_log);
+                       if ((n = gps_tracking_data.channels) != 0) {
+                               gps_log.type = AO_LOG_GPS_SAT;
+                               for (c = 0; c < n; c++)
+                                       if ((gps_log.u.gps_sat.svid = gps_tracking_data.sats[c].svid))
+                                       {
+                                               gps_log.u.gps_sat.c_n = gps_tracking_data.sats[c].c_n_1;
+                                               ao_log_data(&gps_log);
+                                       }
                        }
+               }
        }
 }
 
 __xdata struct ao_task ao_gps_report_task;
-__xdata struct ao_task ao_gps_tracking_report_task;
 
 void
 ao_gps_report_init(void)
 {
        ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report");
-       ao_add_task(&ao_gps_tracking_report_task, ao_gps_tracking_report, "gps_tracking_report");
 }
index e3af43079728033740513c6c7dc057c0eb313bec..d13885dd8cc5581c01d2a15718a730184289bd29 100644 (file)
@@ -23,66 +23,62 @@ ao_gps_report_mega(void)
 {
        static __xdata struct ao_log_mega               gps_log;
        static __xdata struct ao_telemetry_location     gps_data;
-       uint8_t date_reported = 0;
-
-       for (;;) {
-               ao_sleep(&ao_gps_data);
-               ao_mutex_get(&ao_gps_mutex);
-               ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
-               ao_mutex_put(&ao_gps_mutex);
-
-               if (!(gps_data.flags & AO_GPS_VALID))
-                       continue;
-
-               gps_log.tick = ao_gps_tick;
-               gps_log.type = AO_LOG_GPS_TIME;
-               gps_log.u.gps.latitude = gps_data.latitude;
-               gps_log.u.gps.longitude = gps_data.longitude;
-               gps_log.u.gps.altitude = gps_data.altitude;
-
-               gps_log.u.gps.hour = gps_data.hour;
-               gps_log.u.gps.minute = gps_data.minute;
-               gps_log.u.gps.second = gps_data.second;
-               gps_log.u.gps.flags = gps_data.flags;
-               gps_log.u.gps.year = gps_data.year;
-               gps_log.u.gps.month = gps_data.month;
-               gps_log.u.gps.day = gps_data.day;
-               ao_log_mega(&gps_log);
-       }
-}
-
-void
-ao_gps_tracking_report_mega(void)
-{
-       static __xdata struct ao_log_mega               gps_log;
        static __xdata struct ao_telemetry_satellite    gps_tracking_data;
+       uint8_t date_reported = 0;
+       uint8_t new;
        uint8_t c, n, i;
 
        for (;;) {
-               ao_sleep(&ao_gps_tracking_data);
+               while (!(new = ao_gps_new))
+                       ao_sleep(&ao_gps_new);
                ao_mutex_get(&ao_gps_mutex);
-               ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
+               if (new & AO_GPS_NEW_DATA)
+                       ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
+               if (new & AO_GPS_NEW_TRACKING)
+                       ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
+               ao_gps_new = 0;
                ao_mutex_put(&ao_gps_mutex);
 
-               if (!(n = gps_tracking_data.channels))
-                       continue;
+               if ((new & AO_GPS_NEW_DATA) && (gps_data.flags & AO_GPS_VALID)) {
+                       gps_log.tick = ao_gps_tick;
+                       gps_log.type = AO_LOG_GPS_TIME;
+                       gps_log.u.gps.latitude = gps_data.latitude;
+                       gps_log.u.gps.longitude = gps_data.longitude;
+                       gps_log.u.gps.altitude = gps_data.altitude;
 
-               gps_log.type = AO_LOG_GPS_SAT;
-               gps_log.tick = ao_gps_tick;
-               i = 0;
-               for (c = 0; c < n; c++)
-                       if ((gps_log.u.gps_sat.sats[i].svid = gps_tracking_data.sats[c].svid))
-                       {
-                               gps_log.u.gps_sat.sats[i].c_n = gps_tracking_data.sats[c].c_n_1;
-                               i++;
-                       }
-               gps_log.u.gps_sat.channels = i;
-               ao_log_mega(&gps_log);
+                       gps_log.u.gps.hour = gps_data.hour;
+                       gps_log.u.gps.minute = gps_data.minute;
+                       gps_log.u.gps.second = gps_data.second;
+                       gps_log.u.gps.flags = gps_data.flags;
+                       gps_log.u.gps.year = gps_data.year;
+                       gps_log.u.gps.month = gps_data.month;
+                       gps_log.u.gps.day = gps_data.day;
+                       gps_log.u.gps.course = gps_data.course;
+                       gps_log.u.gps.ground_speed = gps_data.ground_speed;
+                       gps_log.u.gps.climb_rate = gps_data.climb_rate;
+                       gps_log.u.gps.pdop = gps_data.pdop;
+                       gps_log.u.gps.hdop = gps_data.hdop;
+                       gps_log.u.gps.vdop = gps_data.vdop;
+                       gps_log.u.gps.mode = gps_data.mode;
+                       ao_log_mega(&gps_log);
+               }
+               if ((new & AO_GPS_NEW_TRACKING) && (n = gps_tracking_data.channels) != 0) {
+                       gps_log.tick = ao_gps_tick;
+                       gps_log.type = AO_LOG_GPS_SAT;
+                       i = 0;
+                       for (c = 0; c < n; c++)
+                               if ((gps_log.u.gps_sat.sats[i].svid = gps_tracking_data.sats[c].svid))
+                               {
+                                       gps_log.u.gps_sat.sats[i].c_n = gps_tracking_data.sats[c].c_n_1;
+                                       i++;
+                               }
+                       gps_log.u.gps_sat.channels = i;
+                       ao_log_mega(&gps_log);
+               }
        }
 }
 
 __xdata struct ao_task ao_gps_report_mega_task;
-__xdata struct ao_task ao_gps_tracking_report_mega_task;
 
 void
 ao_gps_report_mega_init(void)
@@ -90,7 +86,4 @@ ao_gps_report_mega_init(void)
        ao_add_task(&ao_gps_report_mega_task,
                    ao_gps_report_mega,
                    "gps_report");
-       ao_add_task(&ao_gps_tracking_report_mega_task,
-                   ao_gps_tracking_report_mega,
-                   "gps_tracking_report");
 }
diff --git a/src/core/ao_gps_report_metrum.c b/src/core/ao_gps_report_metrum.c
new file mode 100644 (file)
index 0000000..fa03897
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2009 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include "ao_log.h"
+
+void
+ao_gps_report_metrum(void)
+{
+       static __xdata struct ao_log_metrum             gps_log;
+       static __xdata struct ao_telemetry_location     gps_data;
+       static __xdata struct ao_telemetry_satellite    gps_tracking_data;
+       uint8_t c, n, i, p, valid, packets;
+       uint8_t svid;
+       uint8_t date_reported = 0;
+       uint8_t new;
+
+       for (;;) {
+               while (!(new = ao_gps_new))
+                       ao_sleep(&ao_gps_new);
+               ao_mutex_get(&ao_gps_mutex);
+               if (new & AO_GPS_NEW_DATA)
+                       ao_xmemcpy(&gps_data, &ao_gps_data, sizeof (ao_gps_data));
+               if (new & AO_GPS_NEW_TRACKING)
+                       ao_xmemcpy(&gps_tracking_data, &ao_gps_tracking_data, sizeof (ao_gps_tracking_data));
+               ao_gps_new = 0;
+               ao_mutex_put(&ao_gps_mutex);
+
+               if ((new & AO_GPS_NEW_DATA) && (gps_data.flags & AO_GPS_VALID)) {
+                       gps_log.tick = ao_gps_tick;
+                       gps_log.type = AO_LOG_GPS_POS;
+                       gps_log.u.gps.latitude = gps_data.latitude;
+                       gps_log.u.gps.longitude = gps_data.longitude;
+                       gps_log.u.gps.altitude = gps_data.altitude;
+                       ao_log_metrum(&gps_log);
+
+                       gps_log.type = AO_LOG_GPS_TIME;
+                       gps_log.u.gps_time.hour = gps_data.hour;
+                       gps_log.u.gps_time.minute = gps_data.minute;
+                       gps_log.u.gps_time.second = gps_data.second;
+                       gps_log.u.gps_time.flags = gps_data.flags;
+                       gps_log.u.gps_time.year = gps_data.year;
+                       gps_log.u.gps_time.month = gps_data.month;
+                       gps_log.u.gps_time.day = gps_data.day;
+                       ao_log_metrum(&gps_log);
+               }
+
+               if ((new & AO_GPS_NEW_TRACKING) && (n = gps_tracking_data.channels)) {
+                       gps_log.type = AO_LOG_GPS_SAT;
+                       gps_log.tick = ao_gps_tick;
+                       i = 0;
+                       for (c = 0; c < n; c++) {
+                               svid = gps_tracking_data.sats[c].svid;
+                               if (svid != 0) {
+                                       if (i == 4) {
+                                               gps_log.u.gps_sat.channels = i;
+                                               gps_log.u.gps_sat.more = 1;
+                                               ao_log_metrum(&gps_log);
+                                               i = 0;
+                                       }
+                                       gps_log.u.gps_sat.sats[i].svid = svid;
+                                       gps_log.u.gps_sat.sats[i].c_n = gps_tracking_data.sats[c].c_n_1;
+                                       i++;
+                               }
+                       }
+                       if (i) {
+                               gps_log.u.gps_sat.channels = i;
+                               gps_log.u.gps_sat.more = 0;
+                               ao_log_metrum(&gps_log);
+                       }
+               }
+       }
+}
+
+__xdata struct ao_task ao_gps_report_metrum_task;
+
+void
+ao_gps_report_metrum_init(void)
+{
+       ao_add_task(&ao_gps_report_metrum_task,
+                   ao_gps_report_metrum,
+                   "gps_report");
+}
diff --git a/src/core/ao_gps_show.c b/src/core/ao_gps_show.c
new file mode 100644 (file)
index 0000000..3a05e35
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef AO_GPS_TEST
+#include <ao.h>
+#endif
+
+void
+ao_gps_show(void) __reentrant
+{
+       uint8_t i;
+       ao_mutex_get(&ao_gps_mutex);
+       printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day);
+       printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second);
+       printf ("Lat/Lon: %ld %ld\n", (long) ao_gps_data.latitude, (long) ao_gps_data.longitude);
+       printf ("Alt: %d\n", ao_gps_data.altitude);
+       printf ("Flags: 0x%x\n", ao_gps_data.flags);
+       printf ("Sats: %d", ao_gps_tracking_data.channels);
+       for (i = 0; i < ao_gps_tracking_data.channels; i++)
+               printf (" %d %d",
+                       ao_gps_tracking_data.sats[i].svid,
+                       ao_gps_tracking_data.sats[i].c_n_1);
+       printf ("\ndone\n");
+       ao_mutex_put(&ao_gps_mutex);
+}
index 74bd0c5aea021a55a4e7f16d45300f9fcb97bebe..9f2ec0a7afc98a972ff020a5ec09df0a80890ac8 100644 (file)
 
 #include "ao.h"
 #include <ao_data.h>
+#if AO_PYRO_NUM
+#include <ao_pyro.h>
+#endif
 
+#if HAS_IGNITE
 __xdata struct ao_ignition ao_ignition[2];
 
 void
@@ -150,6 +154,8 @@ ao_igniter(void)
        }
 }
 
+#endif
+
 void
 ao_ignite_manual(void)
 {
@@ -157,33 +163,50 @@ ao_ignite_manual(void)
        if (!ao_match_word("DoIt"))
                return;
        ao_cmd_white();
-       if (ao_cmd_lex_c == 'm') {
-               if(ao_match_word("main"))
-                       ao_igniter_fire(ao_igniter_main);
-       } else {
-               if(ao_match_word("drogue"))
-                       ao_igniter_fire(ao_igniter_drogue);
+#if HAS_IGNITE
+       if (ao_cmd_lex_c == 'm' && ao_match_word("main")) {
+               ao_igniter_fire(ao_igniter_main);
+               return;
+       }
+       if (ao_cmd_lex_c == 'd' && ao_match_word("drogue")) {
+               ao_igniter_fire(ao_igniter_drogue);
+               return;
+       }
+#endif
+#if AO_PYRO_NUM
+       if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') {
+               ao_pyro_manual(ao_cmd_lex_c - '0');
+               return;
        }
+#endif
+       ao_cmd_status = ao_cmd_syntax_error;
 }
 
-static __code char * __code igniter_status_names[] = {
+__code char * __code ao_igniter_status_names[] = {
        "unknown", "ready", "active", "open"
 };
 
+#if HAS_IGNITE
 void
 ao_ignite_print_status(enum ao_igniter igniter, __code char *name) __reentrant
 {
        enum ao_igniter_status status = ao_igniter_status(igniter);
        printf("Igniter: %6s Status: %s\n",
               name,
-              igniter_status_names[status]);
+              ao_igniter_status_names[status]);
 }
+#endif
 
 void
 ao_ignite_test(void)
 {
+#if HAS_IGNITE
        ao_ignite_print_status(ao_igniter_drogue, "drogue");
        ao_ignite_print_status(ao_igniter_main, "main");
+#endif
+#if AO_PYRO_NUM
+       ao_pyro_print_status();
+#endif
 }
 
 __code struct ao_cmds ao_ignite_cmds[] = {
@@ -192,6 +215,7 @@ __code struct ao_cmds ao_ignite_cmds[] = {
        { 0,    NULL },
 };
 
+#if HAS_IGNITE
 __xdata struct ao_task ao_igniter_task;
 
 void
@@ -200,11 +224,14 @@ ao_ignite_set_pins(void)
        ao_enable_output(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, AO_IGNITER_DROGUE, 0);
        ao_enable_output(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, AO_IGNITER_MAIN, 0);
 }
+#endif
 
 void
 ao_igniter_init(void)
 {
+#if HAS_IGNITE
        ao_ignite_set_pins();
-       ao_cmd_register(&ao_ignite_cmds[0]);
        ao_add_task(&ao_igniter_task, ao_igniter, "igniter");
+#endif
+       ao_cmd_register(&ao_ignite_cmds[0]);
 }
diff --git a/src/core/ao_int64.c b/src/core/ao_int64.c
new file mode 100644 (file)
index 0000000..aa23dbe
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao_int64.h>
+
+__pdata ao_int64_t *__data ao_64r, *__data ao_64a, *__data ao_64b;
+
+void ao_plus64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, __pdata ao_int64_t *b) __FATTR {
+       __LOCAL uint32_t        t;
+
+       r->high = a->high + b->high;
+       t = a->low + b->low;
+       if (t < a->low)
+               r->high++;
+       r->low = t;
+}
+
+void ao_minus64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, __pdata ao_int64_t *b) __FATTR {
+       __LOCAL uint32_t        t;
+
+       r->high = a->high - b->high;
+       t = a->low - b->low;
+       if (t > a->low)
+               r->high--;
+       r->low = t;
+}
+
+void ao_rshift64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, uint8_t d) __FATTR {
+       if (d < 32) {
+               r->low = a->low >> d;
+               if (d)
+                       r->low |= a->high << (32 - d);
+               r->high = (int32_t) a->high >> d;
+       } else {
+               d &= 0x1f;
+               r->low = (int32_t) a->high >> d;
+               r->high = 0;
+       }
+}
+
+void ao_lshift64(__pdata ao_int64_t *r, __pdata ao_int64_t *a, uint8_t d) __FATTR {
+       if (d < 32) {
+               r->high = a->high << d;
+               if (d)
+                       r->high |= a->low >> (32 - d);
+               r->low = a->low << d;
+       } else {
+               d &= 0x1f;
+               r->high = a->low << d;
+               r->low = 0;
+       }
+}
+
+static void ao_umul64_32_32(__ARG ao_int64_t *r, uint32_t a, uint32_t b) __reentrant {
+       __LOCAL uint32_t        s;
+       __LOCAL ao_int64_t      t;
+       r->low = (uint32_t) (uint16_t) a * (uint16_t) b;
+       r->high = (uint32_t) (uint16_t) (a >> 16) * (uint16_t) (b >> 16);
+
+       s = (uint32_t) (uint16_t) (a >> 16) * (uint16_t) b;
+
+       t.high = s >> 16;
+       t.low = s << 16;
+       ao_plus64(r, r, &t);
+
+       s = (uint32_t) (uint16_t) a * (uint16_t) (b >> 16);
+
+       t.high = s >> 16;
+       t.low = s << 16;
+       ao_plus64(r, r, &t);
+}
+
+void ao_neg64(__pdata ao_int64_t *r, __pdata ao_int64_t *a) __FATTR {
+       r->high = ~a->high;
+       if (!(r->low = ~a->low + 1))
+               r->high++;
+}
+
+void ao_mul64_32_32(__ARG ao_int64_t *r, int32_t a, int32_t b) __FATTR {
+       uint8_t         negative = 0;
+
+       if (a < 0) {
+               a = -a;
+               ++negative;
+       }
+       if (b < 0) {
+               b = -b;
+               --negative;
+       }
+       ao_umul64_32_32(r, a, b);
+       if (negative)
+               ao_neg64(r, r);
+}
+
+static void ao_umul64(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG ao_int64_t *b) __reentrant {
+       __LOCAL ao_int64_t      r2, r3;
+
+       ao_umul64_32_32(&r2, a->high, b->low);
+       ao_umul64_32_32(&r3, a->low, b->high);
+       ao_umul64_32_32(r, a->low, b->low);
+
+       r->high += r2.low + r3.low;
+}
+
+static __ARG ao_int64_t        ap, bp;
+
+void ao_mul64(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG ao_int64_t *b) __FATTR {
+       uint8_t negative = 0;
+
+       if (ao_int64_negativep(a)) {
+               ao_neg64(&ap, a);
+               a = &ap;
+               ++negative;
+       }
+       if (ao_int64_negativep(b)) {
+               ao_neg64(&bp, b);
+               b = &bp;
+               --negative;
+       }
+       ao_umul64(r, a, b);
+       if (negative)
+               ao_neg64(r, r);
+}
+
+static void ao_umul64_64_16(__ARG ao_int64_t *r, __ARG ao_int64_t *a, uint16_t b) __reentrant {
+       __LOCAL uint32_t h;
+
+       h = a->high * b;
+       ao_umul64_32_32(r, a->low, b);
+       r->high += h;
+}
+
+void ao_mul64_64_16(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG uint16_t b) __FATTR {
+       uint8_t         negative = 0;
+
+       if ((int32_t) a->high < 0) {
+               ao_neg64(&ap, a);
+               a = &ap;
+               negative++;
+       } else
+               ao_umul64_64_16(r, a, b);
+       if (negative)
+               ao_neg64(r, r);
+}
diff --git a/src/core/ao_int64.h b/src/core/ao_int64.h
new file mode 100644 (file)
index 0000000..b16db58
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_INT64_H_
+#define _AO_INT64_H_
+
+#include <stdint.h>
+
+typedef struct {
+       uint32_t        high;
+       uint32_t        low;
+} ao_int64_t;
+
+#define __FATTR
+#define __ARG __pdata
+#define __LOCAL static __pdata
+
+void ao_plus64(__pdata ao_int64_t *ao_64r, __pdata ao_int64_t *ao_64a, __pdata ao_int64_t *ao_64b) __FATTR;
+void ao_minus64(__pdata ao_int64_t *ao_64r, __pdata ao_int64_t *ao_64a, __pdata ao_int64_t *ao_64b) __FATTR;
+void ao_neg64(__pdata ao_int64_t *ao_64r, __pdata ao_int64_t *ao_64a) __FATTR;
+void ao_rshift64(__pdata ao_int64_t *ao_64r, __pdata ao_int64_t *ao_64a, uint8_t d) __FATTR;
+void ao_lshift64(__pdata ao_int64_t *ao_64r, __pdata ao_int64_t *ao_64a, uint8_t d) __FATTR;
+void ao_mul64_32_32(__ARG ao_int64_t *r, __ARG int32_t a, __ARG int32_t b) __FATTR;
+void ao_mul64_64_16(__ARG ao_int64_t *r, __ARG ao_int64_t *a, __ARG uint16_t b) __FATTR;
+void ao_mul64(__ARG ao_int64_t * __ARG r, __ARG ao_int64_t * __ARG a, __ARG ao_int64_t *__ARG b) __FATTR;
+
+#define ao_int64_init32(r, a) (((r)->high = 0), (r)->low = (a))
+#define ao_int64_init64(r, a, b) (((r)->high = (a)), (r)->low = (b))
+
+#define ao_cast64(a) (((int64_t) (a)->high << 32) | (a)->low)
+
+#define ao_int64_negativep(a)  (((int32_t) (a)->high) < 0)
+
+#endif /* _AO_INT64_H_ */
index 59ffd8b27267f24c7165fb835d24815ba4af7907..7fd4f88992c09035e321b954b616819c85345379 100644 (file)
@@ -40,9 +40,9 @@ static __pdata int32_t                ao_k_accel;
 __pdata int16_t                        ao_height;
 __pdata int16_t                        ao_speed;
 __pdata int16_t                        ao_accel;
-__pdata int16_t                        ao_max_height;
+__xdata int16_t                        ao_max_height;
 static __pdata int32_t         ao_avg_height_scaled;
-__pdata int16_t                        ao_avg_height;
+__xdata int16_t                        ao_avg_height;
 
 __pdata int16_t                        ao_error_h;
 __pdata int16_t                        ao_error_h_sq_avg;
@@ -292,7 +292,4 @@ ao_kalman(void)
        else 
 #endif
                ao_avg_height = (ao_avg_height_scaled + 63) >> 7;
-#ifdef AO_FLIGHT_TEST
-       ao_sample_prev_tick = ao_sample_tick;
-#endif
 }
index 7884ec3cde155a88102e56db5905f2e57535ae95..701c81aba7444ba95c8a4ae7203c5fa7683c61dc 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "ao.h"
 #include <ao_log.h>
+#include <ao_config.h>
 
 __pdata uint32_t ao_log_current_pos;
 __pdata uint32_t ao_log_end_pos;
@@ -48,7 +49,7 @@ static __xdata struct ao_log_erase erase;
 static uint32_t
 ao_log_erase_pos(uint8_t i)
 {
-       return i * sizeof (struct ao_log_erase) + AO_STORAGE_ERASE_LOG;
+       return i * sizeof (struct ao_log_erase) + AO_CONFIG_MAX_SIZE;
 }
 
 void
@@ -56,14 +57,14 @@ ao_log_write_erase(uint8_t pos)
 {
        erase.unused = 0x00;
        erase.flight = ao_flight_number;
-       ao_storage_write(ao_log_erase_pos(pos),  &erase, sizeof (erase));
-       ao_storage_flush();
+       ao_config_write(ao_log_erase_pos(pos),  &erase, sizeof (erase));
+       ao_config_flush();
 }
 
 static void
 ao_log_read_erase(uint8_t pos)
 {
-       ao_storage_read(ao_log_erase_pos(pos), &erase, sizeof (erase));
+       ao_config_read(ao_log_erase_pos(pos), &erase, sizeof (erase));
 }
 
 
@@ -87,7 +88,7 @@ ao_log_erase_mark(void)
 static uint8_t
 ao_log_slots()
 {
-       return (uint8_t) (ao_storage_config / ao_config.flight_log_max);
+       return (uint8_t) (ao_storage_log_max / ao_config.flight_log_max);
 }
 
 uint32_t
@@ -278,6 +279,11 @@ ao_log_init(void)
 
        ao_cmd_register(&ao_log_cmds[0]);
 
+#ifndef HAS_ADC
+#error Define HAS_ADC for ao_log.c
+#endif
+#if HAS_ADC
        /* Create a task to log events to eeprom */
        ao_add_task(&ao_log_task, ao_log, "log");
+#endif
 }
index a68a40dddc0f4f8370c7edc7cd109408a1579af6..09f3118812ed64f5436b48d3252cad80c856575e 100644 (file)
@@ -44,6 +44,9 @@ extern __pdata enum ao_flight_state ao_log_state;
 #define AO_LOG_FORMAT_TELEMETRY                3       /* 32 byte ao_telemetry records */
 #define AO_LOG_FORMAT_TELESCIENCE      4       /* 32 byte typed telescience records */
 #define AO_LOG_FORMAT_TELEMEGA         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_NONE             127     /* No log at all */
 
 extern __code uint8_t ao_log_format;
@@ -134,6 +137,7 @@ ao_log_full(void);
 #define AO_LOG_GPS_ALT         'H'
 #define AO_LOG_GPS_SAT         'V'
 #define AO_LOG_GPS_DATE                'Y'
+#define AO_LOG_GPS_POS         'P'
 
 #define AO_LOG_POS_NONE                (~0UL)
 
@@ -235,7 +239,8 @@ struct ao_log_mega {
                        int16_t         v_pbatt;        /* 6 */
                        int16_t         n_sense;        /* 8 */
                        int16_t         sense[10];      /* 10 */
-               } volt;                                 /* 30 */
+                       uint16_t        pyro;           /* 30 */
+               } volt;                                 /* 32 */
                /* AO_LOG_GPS_TIME */
                struct {
                        int32_t         latitude;       /* 4 */
@@ -248,8 +253,14 @@ struct ao_log_mega {
                        uint8_t         year;           /* 18 */
                        uint8_t         month;          /* 19 */
                        uint8_t         day;            /* 20 */
-                       uint8_t         pad;            /* 21 */
-               } gps;  /* 22 */
+                       uint8_t         course;         /* 21 */
+                       uint16_t        ground_speed;   /* 22 */
+                       int16_t         climb_rate;     /* 24 */
+                       uint8_t         pdop;           /* 26 */
+                       uint8_t         hdop;           /* 27 */
+                       uint8_t         vdop;           /* 28 */
+                       uint8_t         mode;           /* 29 */
+               } gps;  /* 30 */
                /* AO_LOG_GPS_SAT */
                struct {
                        uint16_t        channels;       /* 4 */
@@ -261,6 +272,98 @@ struct ao_log_mega {
        } u;
 };
 
+struct ao_log_metrum {
+       char                    type;                   /* 0 */
+       uint8_t                 csum;                   /* 1 */
+       uint16_t                tick;                   /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;         /* 4 */
+                       int16_t         ground_accel;   /* 6 */
+                       uint32_t        ground_pres;    /* 8 */
+                       uint32_t        ground_temp;    /* 12 */
+               } flight;       /* 16 */
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;          /* 4 */
+                       uint16_t        reason;         /* 6 */
+               } state;        /* 8 */
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint32_t        pres;           /* 4 */
+                       uint32_t        temp;           /* 8 */
+                       int16_t         accel;          /* 12 */
+               } sensor;       /* 14 */
+               /* AO_LOG_TEMP_VOLT */
+               struct {
+                       int16_t         v_batt;         /* 4 */
+                       int16_t         sense_a;        /* 6 */
+                       int16_t         sense_m;        /* 8 */
+               } volt;         /* 10 */
+               /* AO_LOG_GPS_POS */
+               struct {
+                       int32_t         latitude;       /* 4 */
+                       int32_t         longitude;      /* 8 */
+                       int16_t         altitude;       /* 12 */
+               } gps;          /* 14 */
+               /* AO_LOG_GPS_TIME */
+               struct {
+                       uint8_t         hour;           /* 4 */
+                       uint8_t         minute;         /* 5 */
+                       uint8_t         second;         /* 6 */
+                       uint8_t         flags;          /* 7 */
+                       uint8_t         year;           /* 8 */
+                       uint8_t         month;          /* 9 */
+                       uint8_t         day;            /* 10 */
+                       uint8_t         pad;            /* 11 */
+               } gps_time;     /* 12 */
+               /* AO_LOG_GPS_SAT (up to three packets) */
+               struct {
+                       uint8_t channels;               /* 4 */
+                       uint8_t more;                   /* 5 */
+                       struct {
+                               uint8_t svid;
+                               uint8_t c_n;
+                       } sats[4];                      /* 6 */
+               } gps_sat;                              /* 14 */
+               uint8_t         raw[12];                /* 4 */
+       } u;    /* 16 */
+};
+
+struct ao_log_mini {
+       char            type;                           /* 0 */
+       uint8_t         csum;                           /* 1 */
+       uint16_t        tick;                           /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;         /* 4 */
+                       uint16_t        r6;
+                       uint32_t        ground_pres;    /* 8 */
+               } flight;
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;          /* 4 */
+                       uint16_t        reason;         /* 6 */
+               } state;
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint8_t         pres[3];        /* 4 */
+                       uint8_t         temp[3];        /* 7 */
+                       int16_t         sense_a;        /* 10 */
+                       int16_t         sense_m;        /* 12 */
+                       int16_t         v_batt;         /* 14 */
+               } sensor;                               /* 16 */
+       } u;                                            /* 16 */
+};                                                     /* 16 */
+
+#define ao_log_pack24(dst,value) do {          \
+               (dst)[0] = (value);             \
+               (dst)[1] = (value) >> 8;        \
+               (dst)[2] = (value) >> 16;       \
+       } while (0)
+
 /* Write a record to the eeprom log */
 uint8_t
 ao_log_data(__xdata struct ao_log_record *log) __reentrant;
@@ -268,7 +371,16 @@ ao_log_data(__xdata struct ao_log_record *log) __reentrant;
 uint8_t
 ao_log_mega(__xdata struct ao_log_mega *log) __reentrant;
 
+uint8_t
+ao_log_metrum(__xdata struct ao_log_metrum *log) __reentrant;
+
+uint8_t
+ao_log_mini(__xdata struct ao_log_mini *log) __reentrant;
+
 void
 ao_log_flush(void);
 
+void
+ao_gps_report_metrum_init(void);
+
 #endif /* _AO_LOG_H_ */
index abf953a6b7c051337eea644c0b0fe49758589141..768947d541728159f7e86d16c30d2122ad4a4914 100644 (file)
@@ -65,6 +65,7 @@ ao_log_dump_check_data(void)
        return 1;
 }
 
+#if HAS_ADC
 static __data uint8_t  ao_log_data_pos;
 
 /* a hack to make sure that ao_log_megas fill the eeprom block in even units */
@@ -151,6 +152,7 @@ ao_log(void)
                                log.u.volt.n_sense = AO_ADC_NUM_SENSE;
                                for (i = 0; i < AO_ADC_NUM_SENSE; i++)
                                        log.u.volt.sense[i] = ao_data_ring[ao_log_data_pos].adc.sense[i];
+                               log.u.volt.pyro = ao_pyro_fired;
                                ao_log_mega(&log);
                                next_other = log.tick + AO_OTHER_INTERVAL;
                        }
@@ -181,6 +183,7 @@ ao_log(void)
                        ao_sleep(&ao_log_running);
        }
 }
+#endif
 
 uint16_t
 ao_log_flight(uint8_t slot)
diff --git a/src/core/ao_log_metrum.c b/src/core/ao_log_metrum.c
new file mode 100644 (file)
index 0000000..43441e7
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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"
+#include <ao_log.h>
+#include <ao_data.h>
+#include <ao_flight.h>
+
+static __xdata uint8_t ao_log_mutex;
+static __xdata struct ao_log_metrum log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEMETRUM;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (struct ao_log_metrum); i++)
+               sum += *b++;
+       return -sum;
+}
+
+uint8_t
+ao_log_metrum(__xdata struct ao_log_metrum *log) __reentrant
+{
+       uint8_t wrote = 0;
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((__xdata uint8_t *) log);
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+                       ao_log_stop();
+               if (ao_log_running) {
+                       wrote = 1;
+                       ao_storage_write(ao_log_current_pos,
+                                        log,
+                                        sizeof (struct ao_log_metrum));
+                       ao_log_current_pos += sizeof (struct ao_log_metrum);
+               }
+       } ao_mutex_put(&ao_log_mutex);
+       return wrote;
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+       if (ao_log_csum((uint8_t *) &log) != 0)
+               return 0;
+       return 1;
+}
+
+#if HAS_ADC
+static __data uint8_t  ao_log_data_pos;
+
+/* 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_metrum))] ;
+
+#ifndef AO_SENSOR_INTERVAL_ASCENT
+#define AO_SENSOR_INTERVAL_ASCENT      1
+#define AO_SENSOR_INTERVAL_DESCENT     10
+#define AO_OTHER_INTERVAL              32
+#endif
+
+void
+ao_log(void)
+{
+       __pdata uint16_t        next_sensor, next_other;
+       uint8_t                 i;
+
+       ao_storage_setup();
+
+       ao_log_scan();
+
+       while (!ao_log_running)
+               ao_sleep(&ao_log_running);
+
+#if HAS_FLIGHT
+       log.type = AO_LOG_FLIGHT;
+       log.tick = ao_sample_tick;
+#if HAS_ACCEL
+       log.u.flight.ground_accel = ao_ground_accel;
+#endif
+       log.u.flight.ground_pres = ao_ground_pres;
+       log.u.flight.flight = ao_flight_number;
+       ao_log_metrum(&log);
+#endif
+
+       /* Write the whole contents of the ring to the log
+        * when starting up.
+        */
+       ao_log_data_pos = ao_data_ring_next(ao_data_head);
+       next_other = next_sensor = ao_data_ring[ao_log_data_pos].tick;
+       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;
+                       if ((int16_t) (log.tick - next_sensor) >= 0) {
+                               log.type = AO_LOG_SENSOR;
+#if HAS_MS5607
+                               log.u.sensor.pres = ao_data_ring[ao_log_data_pos].ms5607_raw.pres;
+                               log.u.sensor.temp = ao_data_ring[ao_log_data_pos].ms5607_raw.temp;
+#endif
+                               log.u.sensor.accel = ao_data_accel(&ao_data_ring[ao_log_data_pos]);
+                               ao_log_metrum(&log);
+                               if (ao_log_state <= ao_flight_coast)
+                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
+                               else
+                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
+                       }
+                       if ((int16_t) (log.tick - next_other) >= 0) {
+                               log.type = AO_LOG_TEMP_VOLT;
+                               log.u.volt.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
+                               log.u.volt.sense_a = ao_data_ring[ao_log_data_pos].adc.sense_a;
+                               log.u.volt.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m;
+                               ao_log_metrum(&log);
+                               next_other = log.tick + AO_OTHER_INTERVAL;
+                       }
+                       ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+               }
+#if HAS_FLIGHT
+               /* 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_metrum(&log);
+
+                       if (ao_log_state == ao_flight_landed)
+                               ao_log_stop();
+               }
+#endif
+
+               ao_log_flush();
+
+               /* Wait for a while */
+               ao_delay(AO_MS_TO_TICKS(100));
+
+               /* Stop logging when told to */
+               while (!ao_log_running)
+                       ao_sleep(&ao_log_running);
+       }
+}
+#endif
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+       if (!ao_storage_read(ao_log_pos(slot),
+                            &log,
+                            sizeof (struct ao_log_metrum)))
+               return 0;
+
+       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+               return log.u.flight.flight;
+       return 0;
+}
diff --git a/src/core/ao_log_micro.c b/src/core/ao_log_micro.c
new file mode 100644 (file)
index 0000000..d665efb
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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>
+#include <ao_micropeak.h>
+#include <ao_log_micro.h>
+#include <ao_async.h>
+
+static uint16_t ao_log_offset = STARTING_LOG_OFFSET;
+
+void
+ao_log_micro_save(void)
+{
+       uint16_t        n_samples = (ao_log_offset - STARTING_LOG_OFFSET) / sizeof (uint16_t);
+       ao_eeprom_write(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
+       ao_eeprom_write(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
+       ao_eeprom_write(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
+}
+
+void
+ao_log_micro_restore(void)
+{
+       ao_eeprom_read(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
+       ao_eeprom_read(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
+}
+
+void
+ao_log_micro_data(void)
+{
+       uint16_t        low_bits = pa;
+
+       if (ao_log_offset < MAX_LOG_OFFSET) {
+               ao_eeprom_write(ao_log_offset, &low_bits, sizeof (low_bits));
+               ao_log_offset += sizeof (low_bits);
+       }
+}
+
+#define POLY 0x8408
+
+static uint16_t
+ao_log_micro_crc(uint16_t crc, uint8_t byte)
+{
+       uint8_t i;
+
+       for (i = 0; i < 8; i++) {
+               if ((crc & 0x0001) ^ (byte & 0x0001))
+                       crc = (crc >> 1) ^ POLY;
+               else
+                       crc = crc >> 1;
+               byte >>= 1;
+       }
+       return crc;
+}
+
+static void
+ao_log_hex_nibble(uint8_t b)
+{
+       if (b < 10)
+               ao_async_byte('0' + b);
+       else
+               ao_async_byte('a' - 10 + b);
+}
+
+static void
+ao_log_hex(uint8_t b)
+{
+       ao_log_hex_nibble(b>>4);
+       ao_log_hex_nibble(b&0xf);
+}
+
+static void
+ao_log_newline(void)
+{
+       ao_async_byte('\r');
+       ao_async_byte('\n');
+}
+
+void
+ao_log_micro_dump(void)
+{
+       uint16_t        n_samples;
+       uint16_t        nbytes;
+       uint8_t         byte;
+       uint16_t        b;
+       uint16_t        crc = 0xffff;
+
+       ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
+       if (n_samples == 0xffff)
+               n_samples = 0;
+       nbytes = STARTING_LOG_OFFSET + sizeof (uint16_t) * n_samples;
+       ao_async_start();
+       ao_async_byte('M');
+       ao_async_byte('P');
+       for (b = 0; b < nbytes; b++) {
+               if ((b & 0xf) == 0)
+                       ao_log_newline();
+               ao_eeprom_read(b, &byte, 1);
+               ao_log_hex(byte);
+               crc = ao_log_micro_crc(crc, byte);
+       }
+       ao_log_newline();
+       crc = ~crc;
+       ao_log_hex(crc >> 8);
+       ao_log_hex(crc);
+       ao_log_newline();
+       ao_async_stop();
+}
diff --git a/src/core/ao_log_micro.h b/src/core/ao_log_micro.h
new file mode 100644 (file)
index 0000000..976852e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_LOG_MICRO_H_
+#define _AO_LOG_MICRO_H_
+
+#define PA_GROUND_OFFSET       0
+#define PA_MIN_OFFSET          4
+#define N_SAMPLES_OFFSET       8
+#define STARTING_LOG_OFFSET    10
+#define MAX_LOG_OFFSET         512
+
+void
+ao_log_micro_save(void);
+
+void
+ao_log_micro_restore(void);
+
+void
+ao_log_micro_data(void);
+
+void
+ao_log_micro_dump(void);
+
+#endif /* _AO_LOG_MICRO_H_ */
diff --git a/src/core/ao_log_mini.c b/src/core/ao_log_mini.c
new file mode 100644 (file)
index 0000000..99a8598
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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"
+#include <ao_log.h>
+#include <ao_data.h>
+#include <ao_flight.h>
+
+static __xdata uint8_t ao_log_mutex;
+static __xdata struct ao_log_mini log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (struct ao_log_mini); i++)
+               sum += *b++;
+       return -sum;
+}
+
+uint8_t
+ao_log_mini(__xdata struct ao_log_mini *log) __reentrant
+{
+       uint8_t wrote = 0;
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((__xdata uint8_t *) log);
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+                       ao_log_stop();
+               if (ao_log_running) {
+                       wrote = 1;
+                       ao_storage_write(ao_log_current_pos,
+                                        log,
+                                        sizeof (struct ao_log_mini));
+                       ao_log_current_pos += sizeof (struct ao_log_mini);
+               }
+       } ao_mutex_put(&ao_log_mutex);
+       return wrote;
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+       if (ao_log_csum((uint8_t *) &log) != 0)
+               return 0;
+       return 1;
+}
+
+static __data uint8_t  ao_log_data_pos;
+
+/* a hack to make sure that ao_log_minis fill the eeprom block in even units */
+typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_mini))] ;
+
+#ifndef AO_SENSOR_INTERVAL_ASCENT
+#define AO_SENSOR_INTERVAL_ASCENT      1
+#define AO_SENSOR_INTERVAL_DESCENT     10
+#endif
+
+void
+ao_log(void)
+{
+       __pdata uint16_t        next_sensor, next_other;
+
+       ao_storage_setup();
+
+       ao_log_scan();
+
+       while (!ao_log_running)
+               ao_sleep(&ao_log_running);
+
+#if HAS_FLIGHT
+       log.type = AO_LOG_FLIGHT;
+       log.tick = ao_sample_tick;
+       log.u.flight.flight = ao_flight_number;
+       log.u.flight.ground_pres = ao_ground_pres;
+       ao_log_mini(&log);
+#endif
+
+       /* Write the whole contents of the ring to the log
+        * when starting up.
+        */
+       ao_log_data_pos = ao_data_ring_next(ao_data_head);
+       next_other = next_sensor = ao_data_ring[ao_log_data_pos].tick;
+       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;
+                       if ((int16_t) (log.tick - next_sensor) >= 0) {
+                               log.type = AO_LOG_SENSOR;
+                               ao_log_pack24(log.u.sensor.pres,
+                                             ao_data_ring[ao_log_data_pos].ms5607_raw.pres);
+                               ao_log_pack24(log.u.sensor.temp,
+                                             ao_data_ring[ao_log_data_pos].ms5607_raw.temp);
+                               log.u.sensor.sense_a = ao_data_ring[ao_log_data_pos].adc.sense_a;
+                               log.u.sensor.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m;
+                               log.u.sensor.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
+                               ao_log_mini(&log);
+                               if (ao_log_state <= ao_flight_coast)
+                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
+                               else
+                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
+                       }
+                       ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+               }
+#if HAS_FLIGHT
+               /* 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_mini(&log);
+
+                       if (ao_log_state == ao_flight_landed)
+                               ao_log_stop();
+               }
+#endif
+
+               ao_log_flush();
+
+               /* Wait for a while */
+               ao_delay(AO_MS_TO_TICKS(100));
+
+               /* Stop logging when told to */
+               while (!ao_log_running)
+                       ao_sleep(&ao_log_running);
+       }
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+       if (!ao_storage_read(ao_log_pos(slot),
+                            &log,
+                            sizeof (struct ao_log_mini)))
+               return 0;
+
+       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+               return log.u.flight.flight;
+       return 0;
+}
index 23ebf7ddc62dc8e2efaf4e39531a3c2817c8ff19..095aca371d0227b0851a143b8e567ef4a6e6a261 100644 (file)
@@ -23,7 +23,7 @@ __code uint8_t ao_log_format = AO_LOG_FORMAT_TELEMETRY;
 
 static __data uint8_t                  ao_log_monitor_pos;
 __pdata enum ao_flight_state           ao_flight_state;
-__pdata int16_t                                ao_max_height;  /* max of ao_height */
+__xdata int16_t                                ao_max_height;  /* max of ao_height */
 __pdata int16_t                                sense_d, sense_m;
 __pdata uint8_t                                ao_igniter_present;
 
index 492658ea2d05502aaebe2606ae4a843678964190..67767dc9ce285c88aeaa0510889be3aa906e8557 100644 (file)
@@ -105,7 +105,7 @@ ao_log(void)
                 */
                ao_sleep(DATA_TO_XDATA(&ao_sample_data));
                while (ao_log_data != ao_sample_data) {
-                       sum += ao_data_ring[ao_log_data].adc.pres;
+                       sum += ao_data_pres(&ao_data_ring[ao_log_data]);
                        count++;
                        ao_log_data = ao_data_ring_next(ao_log_data);
                }
diff --git a/src/core/ao_microflight.c b/src/core/ao_microflight.c
new file mode 100644 (file)
index 0000000..f680e40
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#ifndef AO_FLIGHT_TEST
+#include <ao.h>
+#endif
+#include <ao_micropeak.h>
+#include <ao_log_micro.h>
+
+uint32_t       pa;
+uint32_t       pa_ground;
+uint32_t       pa_min;
+
+static void
+ao_microsample(void)
+{
+       ao_pa_get();
+       ao_microkalman_predict();
+       ao_microkalman_correct();
+}
+
+#define NUM_PA_HIST    (GROUND_AVG)
+
+#define SKIP_PA_HIST(i,j)      (((i) + (j)) & (NUM_PA_HIST - 1))
+
+static uint32_t        pa_hist[NUM_PA_HIST];
+
+void
+ao_microflight(void)
+{
+       int16_t         sample_count;
+       uint16_t        time;
+       uint32_t        pa_interval_min, pa_interval_max;
+       int32_t         pa_diff;
+       uint8_t         h, i;
+       uint8_t         accel_lock = 0;
+       uint32_t        pa_sum = 0;
+
+       /* Wait for motion, averaging values to get ground pressure */
+
+       time = ao_time();
+       ao_pa_get();
+       ao_microkalman_init();
+       pa_ground = pa;
+       sample_count = 0;
+       h = 0;
+       for (;;) {
+               time += SAMPLE_SLEEP;
+               if ((sample_count & 0x1f) == 0)
+                       ao_led_on(AO_LED_REPORT);
+               ao_delay_until(time);
+               ao_microsample();
+               if ((sample_count & 0x1f) == 0)
+                       ao_led_off(AO_LED_REPORT);
+               pa_hist[h] = pa;
+               h = SKIP_PA_HIST(h,1);
+               pa_diff = pa_ground - ao_pa;
+
+               /* Check for a significant pressure change */
+               if (pa_diff > BOOST_DETECT)
+                       break;
+
+               if (sample_count < GROUND_AVG * 2) {
+                       if (sample_count < GROUND_AVG)
+                               pa_sum += pa;
+                       ++sample_count;
+               } else {
+                       pa_ground = pa_sum >> GROUND_AVG_SHIFT;
+                       pa_sum = 0;
+                       sample_count = 0;
+               }
+       }
+
+       /* Go back and find the last sample close to the ground */
+       pa_min = pa_ground - LAND_DETECT;
+       for (i = SKIP_PA_HIST(h,-2); i != SKIP_PA_HIST(h,2); i = SKIP_PA_HIST(i,-2)) {
+               if (pa_hist[i] >= pa_min)
+                       break;
+       }
+
+       /* Log the remaining samples so we get a complete history since leaving the ground */
+       for (; i != h; i = SKIP_PA_HIST(i,2)) {
+               pa = pa_hist[i];
+               ao_log_micro_data();
+       }
+
+       /* Now sit around until the pressure is stable again and record the max */
+
+       sample_count = 0;
+       pa_min = ao_pa;
+       pa_interval_min = ao_pa;
+       pa_interval_max = ao_pa;
+       for (;;) {
+               time += SAMPLE_SLEEP;
+               ao_delay_until(time);
+               if ((sample_count & 3) == 0)
+                       ao_led_on(AO_LED_REPORT);
+               ao_microsample();
+               if ((sample_count & 3) == 0)
+                       ao_led_off(AO_LED_REPORT);
+               if (sample_count & 1)
+                       ao_log_micro_data();
+
+               /* If accelerating upwards, don't look for min pressure */
+               if (ao_pa_accel < ACCEL_LOCK_PA)
+                       accel_lock = ACCEL_LOCK_TIME;
+               else if (accel_lock)
+                       --accel_lock;
+               else if (ao_pa < pa_min)
+                       pa_min = ao_pa;
+
+               if (sample_count == (GROUND_AVG - 1)) {
+                       pa_diff = pa_interval_max - pa_interval_min;
+
+                       /* Check to see if the pressure is now stable */
+                       if (pa_diff < LAND_DETECT)
+                               break;
+                       sample_count = 0;
+                       pa_interval_min = ao_pa;
+                       pa_interval_max = ao_pa;
+               } else {
+                       if (ao_pa < pa_interval_min)
+                               pa_interval_min = ao_pa;
+                       if (ao_pa > pa_interval_max)
+                               pa_interval_max = ao_pa;
+                       ++sample_count;
+               }
+       }
+}
diff --git a/src/core/ao_microkalman.c b/src/core/ao_microkalman.c
new file mode 100644 (file)
index 0000000..0684ea2
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef AO_FLIGHT_TEST
+#include <ao.h>
+#endif
+#include <ao_micropeak.h>
+
+#define FIX_BITS       16
+
+#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
+#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
+#define from_fix8(x)   ((x) >> 8)
+#define from_fix(x)    ((x) >> 16)
+#define fix8_to_fix16(x)       ((x) << 8)
+#define fix16_to_fix8(x)       ((x) >> 8)
+
+#include <ao_kalman.h>
+
+/* Basic time step (96ms) */
+#define AO_MK_STEP     to_fix16(0.096)
+/* step ** 2 / 2 */
+#define AO_MK_STEP_2_2 to_fix16(0.004608)
+
+uint32_t       ao_k_pa;                /* 24.8 fixed point */
+int32_t                ao_k_pa_speed;          /* 16.16 fixed point */
+int32_t                ao_k_pa_accel;          /* 16.16 fixed point */
+
+uint32_t       ao_pa;                  /* integer portion */
+int16_t                ao_pa_speed;            /* integer portion */
+int16_t                ao_pa_accel;            /* integer portion */
+
+void
+ao_microkalman_init(void)
+{
+       ao_pa = pa;
+       ao_k_pa = pa << 8;
+}      
+
+void
+ao_microkalman_predict(void)
+{
+       ao_k_pa       += fix16_to_fix8((int32_t) ao_pa_speed * AO_MK_STEP + (int32_t) ao_pa_accel * AO_MK_STEP_2_2);
+       ao_k_pa_speed += (int32_t) ao_pa_accel * AO_MK_STEP;
+}
+
+void
+ao_microkalman_correct(void)
+{
+       int16_t e;      /* Height error in Pa */
+
+       e = pa - from_fix8(ao_k_pa);
+
+       ao_k_pa       += fix16_to_fix8((int32_t) e * AO_MK_BARO_K0_10);
+       ao_k_pa_speed += (int32_t) e * AO_MK_BARO_K1_10;
+       ao_k_pa_accel += (int32_t) e * AO_MK_BARO_K2_10;
+       ao_pa = from_fix8(ao_k_pa);
+       ao_pa_speed = from_fix(ao_k_pa_speed);
+       ao_pa_accel = from_fix(ao_k_pa_accel);
+}
index ec91b9783f091151358d588ddab214e819cb21aa..b9327bacbf8b4a9543775c335cefd63ab97becfc 100644 (file)
@@ -27,6 +27,12 @@ const char ao_product[] = AO_iProduct_STRING;
 #define LE_WORD(x)    ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
 
 #if HAS_USB
+
+/* Maximum power in mA */
+#ifndef AO_USB_MAX_POWER
+#define AO_USB_MAX_POWER       100
+#endif
+
 #include "ao_usb.h"
 /* USB descriptors in one giant block of bytes */
 AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] =
@@ -55,7 +61,7 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] =
        0x01,                   /*  bConfigurationValue */
        0x00,                   /*  iConfiguration */
        0xC0,                   /*  bmAttributes */
-       0x32,                   /*  bMaxPower */
+       AO_USB_MAX_POWER >> 1,  /*  bMaxPower, 2mA units */
 
        /* Control class interface */
        0x09,
index aac8fda51c7219d6895fce2655ec922b01bf4b9f..a260aa99f332cbaf7324e7e63f67956fb241719c 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
+#ifndef AO_FLIGHT_TEST
 #include <ao.h>
-#include <ao_pyro.h>
 #include <ao_sample.h>
 #include <ao_flight.h>
+#endif
+#include <ao_pyro.h>
 
 #if IS_COMPANION
 #include <ao_companion.h>
 
 #define ao_lowbit(x)   ((x) & (-x))
 
+#ifndef AO_FLIGHT_TEST
+enum ao_igniter_status
+ao_pyro_status(uint8_t p)
+{
+       __xdata struct ao_data packet;
+       __pdata int16_t value;
+
+       ao_arch_critical(
+               ao_data_get(&packet);
+               );
+
+       value = (AO_IGNITER_CLOSED>>1);
+       value = AO_SENSE_PYRO(&packet, p);
+       if (value < AO_IGNITER_OPEN)
+               return ao_igniter_open;
+       else if (value > AO_IGNITER_CLOSED)
+               return ao_igniter_ready;
+       else
+               return ao_igniter_unknown;
+}
+
+void
+ao_pyro_print_status(void)
+{
+       uint8_t p;
+
+       for(p = 0; p < AO_PYRO_NUM; p++) {
+               enum ao_igniter_status status = ao_pyro_status(p);
+               printf("Igniter: %d Status: %s\n",
+                      p, ao_igniter_status_names[status]);
+       }
+}
+#endif
+
+uint16_t       ao_pyro_fired;
+
 /*
  * Given a pyro structure, figure out
  * if the current flight state satisfies all
@@ -75,13 +113,13 @@ ao_pyro_ready(struct ao_pyro *pyro)
                                continue;
                        break;
 
-#if HAS_ORIENT
+#if HAS_GYRO
                case ao_pyro_orient_less:
-                       if (ao_orient <= pyro->orient_less)
+                       if (ao_sample_orient <= pyro->orient_less)
                                continue;
                        break;
                case ao_pyro_orient_greater:
-                       if (ao_orient >= pyro->orient_greater)
+                       if (ao_sample_orient >= pyro->orient_greater)
                                continue;
                        break;
 #endif
@@ -130,107 +168,116 @@ ao_pyro_ready(struct ao_pyro *pyro)
        return TRUE;
 }
 
-#define ao_pyro_fire_port(port, bit, pin) do { \
-               ao_gpio_set(port, bit, pin, 1); \
-               ao_delay(AO_MS_TO_TICKS(50));   \
-               ao_gpio_set(port, bit, pin, 0); \
-       } while (0)
-
-
+#ifndef AO_FLIGHT_TEST
 static void
-ao_pyro_fire(uint8_t p)
+ao_pyro_pin_set(uint8_t p, uint8_t v)
 {
        switch (p) {
 #if AO_PYRO_NUM > 0
-       case 0: ao_pyro_fire_port(AO_PYRO_PORT_0, AO_PYRO_PIN_0, AO_PYRO_0); break;
+       case 0: ao_gpio_set(AO_PYRO_PORT_0, AO_PYRO_PIN_0, AO_PYRO_0, v); break;
 #endif
 #if AO_PYRO_NUM > 1
-       case 1: ao_pyro_fire_port(AO_PYRO_PORT_1, AO_PYRO_PIN_1, AO_PYRO_1); break;
+       case 1: ao_gpio_set(AO_PYRO_PORT_1, AO_PYRO_PIN_1, AO_PYRO_1, v); break;
 #endif
 #if AO_PYRO_NUM > 2
-       case 2: ao_pyro_fire_port(AO_PYRO_PORT_2, AO_PYRO_PIN_2, AO_PYRO_2); break;
+       case 2: ao_gpio_set(AO_PYRO_PORT_2, AO_PYRO_PIN_2, AO_PYRO_2, v); break;
 #endif
 #if AO_PYRO_NUM > 3
-       case 3: ao_pyro_fire_port(AO_PYRO_PORT_3, AO_PYRO_PIN_3, AO_PYRO_3); break;
+       case 3: ao_gpio_set(AO_PYRO_PORT_3, AO_PYRO_PIN_3, AO_PYRO_3, v); break;
 #endif
 #if AO_PYRO_NUM > 4
-       case 4: ao_pyro_fire_port(AO_PYRO_PORT_4, AO_PYRO_PIN_4, AO_PYRO_4); break;
+       case 4: ao_gpio_set(AO_PYRO_PORT_4, AO_PYRO_PIN_4, AO_PYRO_4, v); break;
 #endif
 #if AO_PYRO_NUM > 5
-       case 5: ao_pyro_fire_port(AO_PYRO_PORT_5, AO_PYRO_PIN_5, AO_PYRO_5); break;
+       case 5: ao_gpio_set(AO_PYRO_PORT_5, AO_PYRO_PIN_5, AO_PYRO_5, v); break;
 #endif
 #if AO_PYRO_NUM > 6
-       case 6: ao_pyro_fire_port(AO_PYRO_PORT_6, AO_PYRO_PIN_6, AO_PYRO_6); break;
+       case 6: ao_gpio_set(AO_PYRO_PORT_6, AO_PYRO_PIN_6, AO_PYRO_6, v); break;
 #endif
 #if AO_PYRO_NUM > 7
-       case 7: ao_pyro_fire_port(AO_PYRO_PORT_7, AO_PYRO_PIN_7, AO_PYRO_7); break;
+       case 7: ao_gpio_set(AO_PYRO_PORT_7, AO_PYRO_PIN_7, AO_PYRO_7, v); break;
 #endif
        default: break;
        }
-       ao_delay(AO_MS_TO_TICKS(50));
 }
+#endif
 
 uint8_t        ao_pyro_wakeup;
 
 static void
-ao_pyro(void)
+ao_pyro_pins_fire(uint16_t fire)
 {
-       uint8_t         p, any_waiting;
-       struct ao_pyro  *pyro;
+       uint8_t p;
 
-       ao_config_get();
-       while (ao_flight_state < ao_flight_boost)
-               ao_sleep(&ao_flight_state);
+       for (p = 0; p < AO_PYRO_NUM; p++) {
+               if (fire & (1 << p))
+                       ao_pyro_pin_set(p, 1);
+       }
+       ao_delay(AO_MS_TO_TICKS(50));
+       for (p = 0; p < AO_PYRO_NUM; p++) {
+               if (fire & (1 << p)) {
+                       ao_pyro_pin_set(p, 0);
+                       ao_config.pyro[p].fired = 1;
+                       ao_pyro_fired |= (1 << p);
+               }
+       }
+       ao_delay(AO_MS_TO_TICKS(50));
+}
 
-       for (;;) {
-               ao_alarm(AO_MS_TO_TICKS(100));
-               ao_sleep(&ao_pyro_wakeup);
-               ao_clear_alarm();
-               any_waiting = 0;
-               for (p = 0; p < AO_PYRO_NUM; p++) {
-                       pyro = &ao_config.pyro[p];
+static uint8_t
+ao_pyro_check(void)
+{
+       struct ao_pyro  *pyro;
+       uint8_t         p, any_waiting;
+       uint16_t        fire = 0;
+       
+       any_waiting = 0;
+       for (p = 0; p < AO_PYRO_NUM; p++) {
+               pyro = &ao_config.pyro[p];
 
-                       /* Ignore igniters which have already fired
-                        */
-                       if (pyro->fired)
-                               continue;
+               /* Ignore igniters which have already fired
+                */
+               if (pyro->fired)
+                       continue;
 
-                       /* Ignore disabled igniters
-                        */
-                       if (!pyro->flags)
-                               continue;
+               /* Ignore disabled igniters
+                */
+               if (!pyro->flags)
+                       continue;
 
-                       any_waiting = 1;
-                       /* Check pyro state to see if it shoule fire
-                        */
-                       if (!pyro->delay_done) {
-                               if (!ao_pyro_ready(pyro))
-                                       continue;
-
-                               /* If there's a delay set, then remember when
-                                * it expires
-                                */
-                               if (pyro->flags & ao_pyro_delay)
-                                       pyro->delay_done = ao_time() + pyro->delay;
-                       }
+               any_waiting = 1;
+               /* Check pyro state to see if it should fire
+                */
+               if (!pyro->delay_done) {
+                       if (!ao_pyro_ready(pyro))
+                               continue;
 
-                       /* Check to see if we're just waiting for
-                        * the delay to expire
+                       /* If there's a delay set, then remember when
+                        * it expires
                         */
-                       if (pyro->delay_done) {
-                               if ((int16_t) (ao_time() - pyro->delay_done) < 0)
-                                       continue;
+                       if (pyro->flags & ao_pyro_delay) {
+                               pyro->delay_done = ao_time() + pyro->delay;
+                               if (!pyro->delay_done)
+                                       pyro->delay_done = 1;
                        }
+               }
 
-                       ao_pyro_fire(p);
+               /* Check to see if we're just waiting for
+                * the delay to expire
+                */
+               if (pyro->delay_done) {
+                       if ((int16_t) (ao_time() - pyro->delay_done) < 0)
+                               continue;
                }
-               if (!any_waiting)
-                       break;
+
+               fire |= (1 << p);
        }
-       ao_exit();
-}
 
-__xdata struct ao_task ao_pyro_task;
+       if (fire)
+               ao_pyro_pins_fire(fire);
+
+       return any_waiting;
+}
 
 #define NO_VALUE       0xff
 
@@ -263,7 +310,7 @@ const struct {
        { "h<", ao_pyro_height_less,    offsetof(struct ao_pyro, height_less), HELP("height less (m)") },
        { "h>", ao_pyro_height_greater, offsetof(struct ao_pyro, height_greater), HELP("height greater (m)") },
 
-#if HAS_ORIENT
+#if HAS_GYRO
        { "o<", ao_pyro_orient_less,    offsetof(struct ao_pyro, orient_less), HELP("orient less (deg)") },
        { "o>", ao_pyro_orient_greater, offsetof(struct ao_pyro, orient_greater), HELP("orient greater (deg)")  },
 #endif
@@ -283,6 +330,34 @@ const struct {
        { "", ao_pyro_none,             NO_VALUE, HELP(NULL) },
 };
 
+#define NUM_PYRO_VALUES (sizeof ao_pyro_values / sizeof ao_pyro_values[0])
+
+#ifndef AO_FLIGHT_TEST
+static void
+ao_pyro(void)
+{
+       uint8_t         any_waiting;
+
+       ao_config_get();
+       while (ao_flight_state < ao_flight_boost)
+               ao_sleep(&ao_flight_state);
+
+       for (;;) {
+               ao_alarm(AO_MS_TO_TICKS(100));
+               ao_sleep(&ao_pyro_wakeup);
+               ao_clear_alarm();
+               if (ao_flight_state >= ao_flight_landed)
+                       break;
+               any_waiting = ao_pyro_check();
+               if (!any_waiting)
+                       break;
+       }
+       ao_exit();
+}
+
+__xdata struct ao_task ao_pyro_task;
+
+
 static void
 ao_pyro_print_name(uint8_t v)
 {
@@ -400,25 +475,17 @@ ao_pyro_set(void)
        _ao_config_edit_finish();
 }
 
-static void
-ao_pyro_manual(void)
+void
+ao_pyro_manual(uint8_t p)
 {
-       ao_cmd_white();
-       if (!ao_match_word("DoIt"))
-               return;
-       ao_cmd_white();
-       ao_cmd_decimal();
-       if (ao_cmd_lex_i < 0 || AO_PYRO_NUM <= ao_cmd_lex_i)
+       printf ("ao_pyro_manual %d\n", p);
+       if (p >= AO_PYRO_NUM) {
+               ao_cmd_status = ao_cmd_syntax_error;
                return;
-       ao_pyro_fire(ao_cmd_lex_i);
-
+       }
+       ao_pyro_pins_fire(1 << p);
 }
 
-const struct ao_cmds ao_pyro_cmds[] = {
-       { ao_pyro_manual,       "P DoIt <n>\0Fire igniter" },
-       { 0, NULL }
-};
-
 void
 ao_pyro_init(void)
 {
@@ -446,6 +513,6 @@ ao_pyro_init(void)
 #if AO_PYRO_NUM > 7
        ao_enable_output(AO_PYRO_PORT_7, AO_PYRO_PIN_7, AO_PYRO_7, 0);
 #endif
-       ao_cmd_register(&ao_pyro_cmds[0]);
        ao_add_task(&ao_pyro_task, ao_pyro, "pyro");
 }
+#endif
index cde850add58eab6a2d8d2903820e6f2d44b11f9a..0c5642d6ea91f2ff12e76c6b1321ff69882b3a4c 100644 (file)
@@ -63,6 +63,8 @@ struct ao_pyro {
 
 extern uint8_t ao_pyro_wakeup;
 
+extern uint16_t        ao_pyro_fired;
+
 void
 ao_pyro_set(void);
 
@@ -72,4 +74,10 @@ ao_pyro_show(void);
 void
 ao_pyro_init(void);
 
+void
+ao_pyro_manual(uint8_t p);
+
+void
+ao_pyro_print_status(void);
+
 #endif
diff --git a/src/core/ao_quaternion.h b/src/core/ao_quaternion.h
new file mode 100644 (file)
index 0000000..044f160
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_QUATERNION_H_
+#define _AO_QUATERNION_H_
+
+#include <math.h>
+
+struct ao_quaternion {
+       float   r;              /* real bit */
+       float   x, y, z;        /* imaginary bits */
+};
+
+static inline void ao_quaternion_multiply(struct ao_quaternion *r,
+                                         const struct ao_quaternion *a,
+                                         const struct ao_quaternion *b)
+{
+       struct ao_quaternion    t;
+#define T(_a,_b)       (((a)->_a) * ((b)->_b))
+
+/*
+ * Quaternions
+ *
+ *     ii = jj = kk = ijk = -1;
+ *
+ *     kji = 1;
+ *
+ *     ij = k;         ji = -k;
+ *     kj = -i;        jk = i;
+ *     ik = -j;        ki = j;
+ *
+ * Multiplication p * q:
+ *
+ *     (pr + ipx + jpy + kpz) (qr + iqx + jqy + kqz) =
+ *
+ *             ( pr * qr +  pr * iqx +  pr * jqy +  pr * kqz) +
+ *             (ipx * qr + ipx * iqx + ipx * jqy + ipx * kqz) +
+ *             (jpy * qr + jpy * iqx + jpy * jqy + jpy * kqz) +
+ *             (kpz * qr + kpz * iqx + kpz * jqy + kpz * kqz) =
+ *
+ *
+ *              (pr * qr) + i(pr * qx) + j(pr * qy) + k(pr * qz) +
+ *             i(px * qr) -  (px * qx) + k(px * qy) - j(px * qz) +
+ *             j(py * qr) - k(py * qx) -  (py * qy) + i(py * qz) +
+ *             k(pz * qr) + j(pz * qx) - i(pz * qy) -  (pz * qz) =
+ *
+ *             1 * ( (pr * qr) - (px * qx) - (py * qy) - (pz * qz) ) +
+ *             i * ( (pr * qx) + (px * qr) + (py * qz) - (pz * qy) ) +
+ *             j * ( (pr * qy) - (px * qz) + (py * qr) + (pz * qx) ) +
+ *             k * ( (pr * qz) + (px * qy) - (py * qx) + (pz * qr);
+ */
+
+       t.r = T(r,r) - T(x,x) - T(y,y) - T(z,z);
+       t.x = T(r,x) + T(x,r) + T(y,z) - T(z,y);
+       t.y = T(r,y) - T(x,z) + T(y,r) + T(z,x);
+       t.z = T(r,z) + T(x,y) - T(y,x) + T(z,r);
+#undef T
+       *r = t;
+}
+
+static inline void ao_quaternion_conjugate(struct ao_quaternion *r,
+                                          const struct ao_quaternion *a)
+{
+       r->r = a->r;
+       r->x = -a->x;
+       r->y = -a->y;
+       r->z = -a->z;
+}
+
+static inline float ao_quaternion_normal(const struct ao_quaternion *a)
+{
+#define S(_a)  (((a)->_a) * ((a)->_a))
+       return S(r) + S(x) + S(y) + S(z);
+#undef S
+}
+
+static inline void ao_quaternion_scale(struct ao_quaternion *r,
+                                      const struct ao_quaternion *a,
+                                      float b)
+{
+       r->r = a->r * b;
+       r->x = a->x * b;
+       r->y = a->y * b;
+       r->z = a->z * b;
+}
+
+static inline void ao_quaternion_normalize(struct ao_quaternion *r,
+                                          const struct ao_quaternion *a)
+{
+       float   n = ao_quaternion_normal(a);
+
+       if (n > 0)
+               ao_quaternion_scale(r, a, 1/sqrtf(n));
+       else
+               *r = *a;
+}
+
+static inline float ao_quaternion_dot(const struct ao_quaternion *a,
+                                     const struct ao_quaternion *b)
+{
+#define T(_a)  (((a)->_a) * ((b)->_a))
+       return T(r) + T(x) + T(y) + T(z);
+#undef T
+}
+                                    
+
+static inline void ao_quaternion_rotate(struct ao_quaternion *r,
+                                       const struct ao_quaternion *a,
+                                       const struct ao_quaternion *b)
+{
+       struct ao_quaternion    c;
+       struct ao_quaternion    t;
+
+       ao_quaternion_multiply(&t, b, a);
+       ao_quaternion_conjugate(&c, b);
+       ao_quaternion_multiply(r, &t, &c);
+}
+
+/*
+ * Compute a rotation quaternion between two vectors
+ *
+ *     cos(θ) + u * sin(θ)
+ *
+ * where θ is the angle between the two vectors and u
+ * is a unit vector axis of rotation
+ */
+
+static inline void ao_quaternion_vectors_to_rotation(struct ao_quaternion *r,
+                                                    const struct ao_quaternion *a,
+                                                    const struct ao_quaternion *b)
+{
+       /*
+        * The cross product will point orthogonally to the two
+        * vectors, forming our rotation axis. The length will be
+        * sin(θ), so these values are already multiplied by that.
+        */
+
+       float x = a->y * b->z - a->z * b->y;
+       float y = a->z * b->x - a->x * b->z;
+       float z = a->x * b->y - a->y * b->x;
+
+       float s_2 = x*x + y*y + z*z;
+       float s = sqrtf(s_2);
+
+       /* cos(θ) = a · b / (|a| |b|).
+        *
+        * a and b are both unit vectors, so the divisor is one
+        */
+       float c = a->x*b->x + a->y*b->y + a->z*b->z;
+
+       float c_half = sqrtf ((1 + c) / 2);
+       float s_half = sqrtf ((1 - c) / 2);
+
+       /*
+        * Divide out the sine factor from the
+        * cross product, then multiply in the
+        * half sine factor needed for the quaternion
+        */
+       float s_scale = s_half / s;
+
+       r->x = x * s_scale;
+       r->y = y * s_scale;
+       r->z = z * s_scale;
+
+       r->r = c_half;
+
+       ao_quaternion_normalize(r, r);
+}
+
+static inline void ao_quaternion_init_vector(struct ao_quaternion *r,
+                                            float x, float y, float z)
+{
+       r->r = 0;
+       r->x = x;
+       r->y = y;
+       r->z = z;
+}
+
+static inline void ao_quaternion_init_rotation(struct ao_quaternion *r,
+                                              float x, float y, float z,
+                                              float s, float c)
+{
+       r->r = c;
+       r->x = s * x;
+       r->y = s * y;
+       r->z = s * z;
+}
+
+static inline void ao_quaternion_init_zero_rotation(struct ao_quaternion *r)
+{
+       r->r = 1;
+       r->x = r->y = r->z = 0;
+}
+
+/*
+ * The sincosf from newlib just calls sinf and cosf. This is a bit
+ * faster, if slightly less precise
+ */
+
+static inline void
+ao_sincosf(float a, float *s, float *c) {
+       float   _s = sinf(a);
+       *s = _s;
+       *c = sqrtf(1 - _s*_s);
+}
+
+/*
+ * Initialize a quaternion from 1/2 euler rotation angles (in radians).
+ *
+ * Yes, it would be nicer if there were a faster way, but because we
+ * sample the gyros at only 100Hz, we end up getting angles too large
+ * to take advantage of sin(x) ≃ x.
+ *
+ * We might be able to use just a couple of elements of the sin taylor
+ * series though, instead of the whole sin function?
+ */
+
+static inline void ao_quaternion_init_half_euler(struct ao_quaternion *r,
+                                                float x, float y, float z)
+{
+       float   s_x, c_x;
+       float   s_y, c_y;
+       float   s_z, c_z;
+
+       ao_sincosf(x, &s_x, &c_x);
+       ao_sincosf(y, &s_y, &c_y);
+       ao_sincosf(z, &s_z, &c_z);
+
+       r->r = c_x * c_y * c_z + s_x * s_y * s_z;
+       r->x = s_x * c_y * c_z - c_x * s_y * s_z;
+       r->y = c_x * s_y * c_z + s_x * c_y * s_z;
+       r->z = c_x * c_y * s_z - s_x * s_y * c_z;
+}
+
+#endif /* _AO_QUATERNION_H_ */
diff --git a/src/core/ao_report_micro.c b/src/core/ao_report_micro.c
new file mode 100644 (file)
index 0000000..0e8e287
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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>
+
+#define mid(time)      ao_led_for(AO_LED_REPORT, time)
+#define pause(time)    ao_delay(time)
+
+static void
+ao_report_digit(uint8_t digit) __reentrant
+{
+       if (!digit) {
+               mid(AO_MS_TO_TICKS(1000));
+               pause(AO_MS_TO_TICKS(300));
+       } else {
+               while (digit--) {
+                       mid(AO_MS_TO_TICKS(300));
+                       pause(AO_MS_TO_TICKS(300));
+               }
+       }
+       pause(AO_MS_TO_TICKS(1000));
+}
+
+void
+ao_report_altitude(void)
+{
+       __pdata alt_t   agl = ao_max_height;
+       static __xdata uint8_t  digits[11];
+       __pdata uint8_t ndigits, i;
+
+       if (agl < 0)
+               agl = 0;
+       ndigits = 0;
+       do {
+               digits[ndigits++] = agl % 10;
+               agl /= 10;
+       } while (agl);
+
+       i = ndigits;
+       do
+               ao_report_digit(digits[--i]);
+       while (i != 0);
+}
index dec44f9fa0910aa422ce8e7771c75001aba3fb94..adf8399dd702535d960804791669cde9f204a812 100644 (file)
 #include <ao_data.h>
 #endif
 
+#if HAS_GYRO
+#include <ao_quaternion.h>
+#endif
+
 /*
  * Current sensor values
  */
@@ -44,8 +48,7 @@ __pdata accel_t               ao_sample_accel_through;
 __pdata gyro_t         ao_sample_roll;
 __pdata gyro_t         ao_sample_pitch;
 __pdata gyro_t         ao_sample_yaw;
-__pdata angle_t                ao_sample_angle;
-__pdata angle_t                ao_sample_roll_angle;
+__pdata angle_t                ao_sample_orient;
 #endif
 
 __data uint8_t         ao_sample_data;
@@ -67,9 +70,9 @@ __pdata int32_t               ao_accel_scale;         /* sensor to m/s² conversion */
 __pdata accel_t                ao_ground_accel_along;
 __pdata accel_t                ao_ground_accel_across;
 __pdata accel_t                ao_ground_accel_through;
-__pdata gyro_t         ao_ground_pitch;
-__pdata gyro_t         ao_ground_yaw;
-__pdata gyro_t         ao_ground_roll;
+__pdata int32_t                ao_ground_pitch;
+__pdata int32_t                ao_ground_yaw;
+__pdata int32_t                ao_ground_roll;
 #endif
 
 static __pdata uint8_t ao_preflight;           /* in preflight mode */
@@ -86,6 +89,7 @@ __pdata int32_t       ao_sample_accel_through_sum;
 __pdata int32_t ao_sample_pitch_sum;
 __pdata int32_t ao_sample_yaw_sum;
 __pdata int32_t        ao_sample_roll_sum;
+static struct ao_quaternion ao_rotation;
 #endif
 
 static void
@@ -120,20 +124,95 @@ ao_sample_preflight_set(void)
        ao_ground_accel_along = ao_sample_accel_along_sum >> 9;
        ao_ground_accel_across = ao_sample_accel_across_sum >> 9;
        ao_ground_accel_through = ao_sample_accel_through_sum >> 9;
-       ao_ground_pitch = ao_sample_pitch_sum >> 9;
-       ao_ground_yaw = ao_sample_yaw_sum >> 9;
-       ao_ground_roll = ao_sample_roll_sum >> 9;
+       ao_ground_pitch = ao_sample_pitch_sum;
+       ao_ground_yaw = ao_sample_yaw_sum;
+       ao_ground_roll = ao_sample_roll_sum;
        ao_sample_accel_along_sum = 0;
        ao_sample_accel_across_sum = 0;
        ao_sample_accel_through_sum = 0;
        ao_sample_pitch_sum = 0;
        ao_sample_yaw_sum = 0;
        ao_sample_roll_sum = 0;
-       ao_sample_angle = 0;
+       ao_sample_orient = 0;
+
+       struct ao_quaternion    orient;
+
+       /* Take the pad IMU acceleration values and compute our current direction
+        */
+
+       ao_quaternion_init_vector(&orient,
+                                 (ao_ground_accel_across - ao_config.accel_zero_across),
+                                 (ao_ground_accel_through - ao_config.accel_zero_through),
+                                 (ao_ground_accel_along - ao_config.accel_zero_along));
+
+       ao_quaternion_normalize(&orient,
+                               &orient);
+
+       /* Here's up */
+
+       struct ao_quaternion    up = { .r = 0, .x = 0, .y = 0, .z = 1 };
+
+       if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
+               up.z = -1;
+
+       /* Compute rotation to get from up to our current orientation, set
+        * that as the current rotation vector
+        */
+       ao_quaternion_vectors_to_rotation(&ao_rotation, &up, &orient);
 #endif 
        nsamples = 0;
 }
 
+#if HAS_GYRO
+
+#define TIME_DIV       200.0f
+
+static void
+ao_sample_rotate(void)
+{
+#ifdef AO_FLIGHT_TEST
+       float   dt = (ao_sample_tick - ao_sample_prev_tick) / TIME_DIV;
+#else
+       static const float dt = 1/TIME_DIV;
+#endif
+       float   x = ao_mpu6000_gyro((float) ((ao_sample_pitch << 9) - ao_ground_pitch) / 512.0f) * dt;
+       float   y = ao_mpu6000_gyro((float) ((ao_sample_yaw << 9) - ao_ground_yaw) / 512.0f) * dt;
+       float   z = ao_mpu6000_gyro((float) ((ao_sample_roll << 9) - ao_ground_roll) / 512.0f) * dt;
+       struct ao_quaternion    rot;
+
+       ao_quaternion_init_half_euler(&rot, x, y, z);
+       ao_quaternion_multiply(&ao_rotation, &rot, &ao_rotation);
+
+       /* And normalize to make sure it remains a unit vector */
+       ao_quaternion_normalize(&ao_rotation, &ao_rotation);
+
+       /* Compute pitch angle from vertical by taking the pad
+        * orientation vector and rotating it by the current total
+        * rotation value. That will be a unit vector pointing along
+        * the airframe axis. The Z value will be the cosine of the
+        * change in the angle from vertical since boost.
+        *
+        * rot = ao_rotation * vertical * ao_rotation°
+        * rot = ao_rotation * (0,0,0,1) * ao_rotation°
+        *     = ((a.z, a.y, -a.x, a.r) * (a.r, -a.x, -a.y, -a.z)) .z
+        *
+        *     = (-a.z * -a.z) + (a.y * -a.y) - (-a.x * -a.x) + (a.r * a.r)
+        *     = a.z² - a.y² - a.x² + a.r²
+        *
+        * rot = ao_rotation * (0, 0, 0, -1) * ao_rotation°
+        *     = ((-a.z, -a.y, a.x, -a.r) * (a.r, -a.x, -a.y, -a.z)) .z
+        *
+        *     = (a.z * -a.z) + (-a.y * -a.y) - (a.x * -a.x) + (-a.r * a.r)
+        *     = -a.z² + a.y² + a.x² - a.r²
+        */
+
+       float rotz;
+       rotz = ao_rotation.z * ao_rotation.z - ao_rotation.y * ao_rotation.y - ao_rotation.x * ao_rotation.x + ao_rotation.r * ao_rotation.r;
+
+       ao_sample_orient = acosf(rotz) * (float) (180.0/M_PI);
+}
+#endif
+
 static void
 ao_sample_preflight(void)
 {
@@ -232,9 +311,12 @@ ao_sample(void)
                                ao_sample_preflight_update();
                        ao_kalman();
 #if HAS_GYRO
-                       /* do quaternion stuff here... */
+                       ao_sample_rotate();
 #endif
                }
+#ifdef AO_FLIGHT_TEST
+               ao_sample_prev_tick = ao_sample_tick;
+#endif
                ao_sample_data = ao_data_ring_next(ao_sample_data);
        }
        return !ao_preflight;
@@ -264,7 +346,7 @@ ao_sample_init(void)
        ao_sample_pitch = 0;
        ao_sample_yaw = 0;
        ao_sample_roll = 0;
-       ao_sample_angle = 0;
+       ao_sample_orient = 0;
 #endif
        ao_sample_data = ao_data_head;
        ao_preflight = TRUE;
index a2dac9792a8bc2c13a5de441daa3fd50adb731b6..16d4c5076774d04ad6adefc70064f1dae43d6626 100644 (file)
@@ -64,8 +64,6 @@
  * for all further flight computations
  */
 
-#define GRAVITY 9.80665
-
 /*
  * Above this height, the baro sensor doesn't work
  */
@@ -115,9 +113,16 @@ extern __pdata int32_t     ao_accel_scale;         /* sensor to m/s² conversion */
 extern __pdata accel_t ao_ground_accel_along;
 extern __pdata accel_t ao_ground_accel_across;
 extern __pdata accel_t ao_ground_accel_through;
-extern __pdata gyro_t  ao_ground_pitch;
-extern __pdata gyro_t  ao_ground_yaw;
-extern __pdata gyro_t  ao_ground_roll;
+extern __pdata int32_t ao_ground_pitch;        /* * 512 */
+extern __pdata int32_t ao_ground_yaw;          /* * 512 */
+extern __pdata int32_t ao_ground_roll;         /* * 512 */
+extern __pdata accel_t ao_sample_accel_along;
+extern __pdata accel_t ao_sample_accel_across;
+extern __pdata accel_t ao_sample_accel_through;
+extern __pdata gyro_t  ao_sample_roll;
+extern __pdata gyro_t  ao_sample_pitch;
+extern __pdata gyro_t  ao_sample_yaw;
+extern __pdata angle_t ao_sample_orient;
 #endif
 
 void ao_sample_init(void);
@@ -136,8 +141,8 @@ uint8_t ao_sample(void);
 extern __pdata int16_t                 ao_height;      /* meters */
 extern __pdata int16_t                 ao_speed;       /* m/s * 16 */
 extern __pdata int16_t                 ao_accel;       /* m/s² * 16 */
-extern __pdata int16_t                 ao_max_height;  /* max of ao_height */
-extern __pdata int16_t                 ao_avg_height;  /* running average of height */
+extern __xdata int16_t                 ao_max_height;  /* max of ao_height */
+extern __xdata int16_t                 ao_avg_height;  /* running average of height */
 
 extern __pdata int16_t                 ao_error_h;
 extern __pdata int16_t                 ao_error_h_sq_avg;
index 1d9ed41492bba22d094deac324f62fcbd104cc08..d3743d124121abeed7062d1bcf87338d1f7696a5 100644 (file)
 #include <ao_task.h>
 
 #ifndef AO_SAMPLE_PROFILE_LOW_PC
-#define AO_SAMPLE_PROFILE_LOW_PC       0x08000000
+#define AO_SAMPLE_PROFILE_LOW_PC       0x08002000
 #endif
 
 #ifndef AO_SAMPLE_PROFILE_HIGH_PC
-#define AO_SAMPLE_PROFILE_HIGH_PC      (AO_SAMPLE_PROFILE_LOW_PC + 44 * 1024)
+#define AO_SAMPLE_PROFILE_HIGH_PC      0x0800f000
 #endif
 
 #ifndef AO_SAMPLE_PROFILE_SHIFT
index adf7e4d4949491f99a5609b2f22dc4fd650466b4..6eddae7f84dcdd754b8c46d54972d352f19fc754 100644 (file)
@@ -154,7 +154,7 @@ ao_storage_zapall(void) __reentrant
        ao_cmd_white();
        if (!ao_match_word("DoIt"))
                return;
-       for (pos = 0; pos < ao_storage_config; pos += ao_storage_block)
+       for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block)
                ao_storage_erase(pos);
 }
 
index ea94639980c0574105a280844f948c394780e538..6cc6fcb70797bfa5dbc66fed6979925e58d44c50 100644 (file)
@@ -35,14 +35,22 @@ extern __pdata ao_pos_t     ao_storage_total;
 /* Block size - device is erased in these units. At least 256 bytes */
 extern __pdata ao_pos_t        ao_storage_block;
 
+#ifndef USE_STORAGE_CONFIG
+#define USE_STORAGE_CONFIG 1
+#endif
+
+#if USE_STORAGE_CONFIG
 /* Byte offset of config block. Will be ao_storage_block bytes long */
 extern __pdata ao_pos_t        ao_storage_config;
 
+#define ao_storage_log_max     ao_storage_config
+#else
+#define ao_storage_log_max     ao_storage_total
+#endif
+
 /* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
 extern __pdata uint16_t ao_storage_unit;
 
-#define AO_STORAGE_ERASE_LOG   (ao_storage_config + AO_CONFIG_MAX_SIZE)
-
 /* Initialize above values. Can only be called once the OS is running */
 void
 ao_storage_setup(void) __reentrant;
index 0aad650898d9c54dddca6d53e6fa2c799aec89d8..bafb49439d4441022be1b9159947f30a9f8d7bff 100644 (file)
@@ -109,6 +109,8 @@ ao_task_validate_alarm_queue(void)
                                ao_panic(3);
                }
        }
+       if (ao_task_alarm_tick != ao_list_first_entry(&alarm_queue, struct ao_task, alarm_queue)->alarm)
+               ao_panic(4);
 }
 #else
 #define ao_task_validate_alarm_queue()
@@ -123,6 +125,7 @@ ao_task_to_alarm_queue(struct ao_task *task)
        ao_list_for_each_entry(alarm, &alarm_queue, struct ao_task, alarm_queue) {
                if ((int16_t) (alarm->alarm - task->alarm) >= 0) {
                        ao_list_insert(&task->alarm_queue, alarm->alarm_queue.prev);
+                       ao_task_alarm_tick = ao_list_first_entry(&alarm_queue, struct ao_task, alarm_queue)->alarm;
                        ao_task_validate_alarm_queue();
                        return;
                }
@@ -420,7 +423,7 @@ ao_sleep(__xdata void *wchan)
 }
 
 void
-ao_wakeup(__xdata void *wchan)
+ao_wakeup(__xdata void *wchan) __reentrant
 {
 #if HAS_TASK_QUEUE
        struct ao_task  *sleep, *next;
index 1a4b5b6ba94ca5c604e6a6cc139844514243f26e..9c56b48021d6dd4ebe83c69f44aa04c5ade023c3 100644 (file)
@@ -45,7 +45,10 @@ struct ao_task {
 #endif
 };
 
+#ifndef AO_NUM_TASKS
 #define AO_NUM_TASKS           16      /* maximum number of tasks */
+#endif
+
 #define AO_NO_TASK             0       /* no task id */
 
 extern __xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS];
@@ -67,7 +70,7 @@ ao_sleep(__xdata void *wchan);
 
 /* Wake all tasks sleeping on wchan */
 void
-ao_wakeup(__xdata void *wchan);
+ao_wakeup(__xdata void *wchan) __reentrant;
 
 /* set an alarm to go off in 'delay' ticks */
 void
index c3bbfec5aa7d40468f903ab53919985979020636..c118d0077b3485b40577894dda456b0aba901aa6 100644 (file)
 #include "ao_log.h"
 #include "ao_product.h"
 
+#ifndef HAS_RDF
+#define HAS_RDF 1
+#endif
+
 static __pdata uint16_t ao_telemetry_interval;
 static __pdata uint8_t ao_rdf = 0;
+
+#if HAS_RDF
 static __pdata uint16_t ao_rdf_time;
+#endif
 
 #if HAS_APRS
 static __pdata uint16_t ao_aprs_time;
@@ -33,6 +40,10 @@ static __pdata uint16_t ao_aprs_time;
 #define AO_SEND_MEGA   1
 #endif
 
+#if defined (TELEMETRUM_V_2_0)
+#define AO_SEND_METRUM 1
+#endif
+
 #if defined(TELEMETRUM_V_0_1) || defined(TELEMETRUM_V_0_2) || defined(TELEMETRUM_V_1_0) || defined(TELEMETRUM_V_1_1) || defined(TELEBALLOON_V_1_1) || defined(TELEMETRUM_V_1_2)
 #define AO_TELEMETRY_SENSOR    AO_TELEMETRY_SENSOR_TELEMETRUM
 #endif
@@ -104,6 +115,7 @@ ao_send_mega_sensor(void)
        telemetry.generic.tick = packet->tick;
        telemetry.generic.type = AO_TELEMETRY_MEGA_SENSOR;
 
+       telemetry.mega_sensor.orient = ao_sample_orient;
        telemetry.mega_sensor.accel = ao_data_accel(packet);
        telemetry.mega_sensor.pres = ao_data_pres(packet);
        telemetry.mega_sensor.temp = ao_data_temp(packet);
@@ -164,6 +176,87 @@ ao_send_mega_data(void)
 }
 #endif /* AO_SEND_MEGA */
 
+#ifdef AO_SEND_METRUM
+/* Send telemetrum sensor packet */
+static void
+ao_send_metrum_sensor(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_METRUM_SENSOR;
+
+       telemetry.metrum_sensor.state = ao_flight_state;
+       telemetry.metrum_sensor.accel = ao_data_accel(packet);
+       telemetry.metrum_sensor.pres = ao_data_pres(packet);
+       telemetry.metrum_sensor.temp = ao_data_temp(packet);
+
+       telemetry.metrum_sensor.acceleration = ao_accel;
+       telemetry.metrum_sensor.speed = ao_speed;
+       telemetry.metrum_sensor.height = ao_height;
+
+       telemetry.metrum_sensor.v_batt = packet->adc.v_batt;
+       telemetry.metrum_sensor.sense_a = packet->adc.sense_a;
+       telemetry.metrum_sensor.sense_m = packet->adc.sense_m;
+
+       ao_radio_send(&telemetry, sizeof (telemetry));
+}
+
+static __pdata int8_t ao_telemetry_metrum_data_max;
+static __pdata int8_t ao_telemetry_metrum_data_cur;
+
+/* Send telemetrum data packet */
+static void
+ao_send_metrum_data(void)
+{
+       if (--ao_telemetry_metrum_data_cur <= 0) {
+               __xdata struct ao_data *packet = (__xdata struct ao_data *) &ao_data_ring[ao_data_ring_prev(ao_sample_data)];
+               uint8_t i;
+
+               telemetry.generic.tick = packet->tick;
+               telemetry.generic.type = AO_TELEMETRY_METRUM_DATA;
+
+               telemetry.metrum_data.ground_pres = ao_ground_pres;
+               telemetry.metrum_data.ground_accel = ao_ground_accel;
+               telemetry.metrum_data.accel_plus_g = ao_config.accel_plus_g;
+               telemetry.metrum_data.accel_minus_g = ao_config.accel_minus_g;
+
+               ao_radio_send(&telemetry, sizeof (telemetry));
+               ao_telemetry_metrum_data_cur = ao_telemetry_metrum_data_max;
+       }
+}
+#endif /* AO_SEND_METRUM */
+
+#ifdef AO_SEND_MINI
+
+static void
+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.mini.state = ao_flight_state;
+
+       telemetry.mini.v_batt = packet->adc.v_batt;
+       telemetry.mini.sense_a = packet->adc.sense_a;
+       telemetry.mini.sense_m = packet->adc.sense_m;
+
+       telemetry.mini.pres = ao_data_pres(packet);
+       telemetry.mini.temp = ao_data_temp(packet);
+
+       telemetry.mini.acceleration = ao_accel;
+       telemetry.mini.speed = ao_speed;
+       telemetry.mini.height = ao_height;
+
+       telemetry.mini.ground_pres = ao_ground_pres;
+
+       ao_radio_send(&telemetry, sizeof (telemetry));
+}
+
+#endif /* AO_SEND_MINI */
+
 #ifdef AO_SEND_ALL_BARO
 static uint8_t         ao_baro_sample;
 
@@ -198,7 +291,11 @@ ao_send_configuration(void)
        {
                telemetry.generic.type = AO_TELEMETRY_CONFIGURATION;
                telemetry.configuration.device = AO_idProduct_NUMBER;
+#if HAS_LOG
                telemetry.configuration.flight = ao_log_full() ? 0 : ao_flight_number;
+#else
+               telemetry.configuration.flight = ao_flight_number;
+#endif
                telemetry.configuration.config_major = AO_CONFIG_MAJOR;
                telemetry.configuration.config_minor = AO_CONFIG_MINOR;
                telemetry.configuration.apogee_delay = ao_config.apogee_delay;
@@ -295,12 +392,14 @@ ao_telemetry(void)
        for (;;) {
                while (ao_telemetry_interval == 0)
                        ao_sleep(&telemetry);
-               time = ao_rdf_time = ao_time();
+               time = ao_time();
+#if HAS_RDF
+               ao_rdf_time = time;
+#endif
 #if HAS_APRS
                ao_aprs_time = time;
 #endif
                while (ao_telemetry_interval) {
-
 #if HAS_APRS
                        if (!(ao_config.radio_enable & AO_RADIO_DISABLE_TELEMETRY))
 #endif
@@ -308,14 +407,23 @@ ao_telemetry(void)
 #ifdef AO_SEND_ALL_BARO
                                ao_send_baro();
 #endif
+
 #if HAS_FLIGHT
-#ifdef AO_SEND_MEGA
+# ifdef AO_SEND_MEGA
                                ao_send_mega_sensor();
                                ao_send_mega_data();
-#else
+# endif
+# ifdef AO_SEND_METRUM
+                               ao_send_metrum_sensor();
+                               ao_send_metrum_data();
+# endif
+# ifdef AO_SEND_MINI
+                               ao_send_mini();
+# endif
+# ifdef AO_TELEMETRY_SENSOR
                                ao_send_sensor();
-#endif
-#endif
+# endif
+#endif /* HAS_FLIGHT */
 
 #if HAS_COMPANION
                                if (ao_companion_running)
@@ -328,23 +436,25 @@ ao_telemetry(void)
 #endif
                        }
 #ifndef AO_SEND_ALL_BARO
+#if HAS_RDF
                        if (ao_rdf &&
 #if HAS_APRS
                            !(ao_config.radio_enable & AO_RADIO_DISABLE_RDF) &&
-#endif
+#endif /* HAS_APRS */
                            (int16_t) (ao_time() - ao_rdf_time) >= 0)
                        {
 #if HAS_IGNITE_REPORT
                                uint8_t c;
-#endif
+#endif /* HAS_IGNITE_REPORT */
                                ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS;
 #if HAS_IGNITE_REPORT
                                if (ao_flight_state == ao_flight_pad && (c = ao_report_igniter()))
                                        ao_radio_continuity(c);
                                else
-#endif
+#endif /* HAS_IGNITE_REPORT*/
                                        ao_radio_rdf();
                        }
+#endif /* HAS_RDF */
 #if HAS_APRS
                        if (ao_config.aprs_interval != 0 &&
                            (int16_t) (ao_time() - ao_aprs_time) >= 0)
@@ -352,8 +462,8 @@ ao_telemetry(void)
                                ao_aprs_time = ao_time() + AO_SEC_TO_TICKS(ao_config.aprs_interval);
                                ao_aprs_send();
                        }
-#endif
-#endif
+#endif /* HAS_APRS */
+#endif /* !AO_SEND_ALL_BARO */
                        time += ao_telemetry_interval;
                        delay = time - ao_time();
                        if (delay > 0) {
@@ -383,6 +493,12 @@ ao_telemetry_set_interval(uint16_t interval)
                cur++;
        ao_telemetry_mega_data_cur = cur;
 #endif
+#if AO_SEND_METRUM
+       ao_telemetry_metrum_data_max = AO_SEC_TO_TICKS(1) / interval;
+       if (ao_telemetry_metrum_data_max > cur)
+               cur++;
+       ao_telemetry_metrum_data_cur = cur;
+#endif
 
 #if HAS_COMPANION
        if (!ao_companion_setup.update_period)
@@ -411,6 +527,7 @@ ao_telemetry_set_interval(uint16_t interval)
        ao_wakeup(&telemetry);
 }
 
+#if HAS_RDF
 void
 ao_rdf_set(uint8_t rdf)
 {
@@ -421,6 +538,7 @@ ao_rdf_set(uint8_t rdf)
                ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS;
        }
 }
+#endif
 
 __xdata struct ao_task ao_telemetry_task;
 
index f2d201ded4fc7614d048899313d3a8fc7ca32372..237a35aba2a15401dc1c93695b1ae65aa1d7f47c 100644 (file)
@@ -162,7 +162,7 @@ struct ao_telemetry_mega_sensor {
        uint16_t        tick;           /*  2 */
        uint8_t         type;           /*  4 */
 
-       uint8_t         pad5;           /*  5 */
+       uint8_t         orient;         /*  5 angle from vertical */
        int16_t         accel;          /*  6 Z axis */
 
        int32_t         pres;           /*  8 Pa * 10 */
@@ -207,6 +207,72 @@ struct ao_telemetry_mega_data {
 };
 
 
+#define AO_TELEMETRY_METRUM_SENSOR     0x0A
+
+struct ao_telemetry_metrum_sensor {
+       uint16_t        serial;         /*  0 */
+       uint16_t        tick;           /*  2 */
+       uint8_t         type;           /*  4 */
+
+       uint8_t         state;          /*  5 flight state */
+       int16_t         accel;          /*  6 Z axis */
+
+       int32_t         pres;           /*  8 Pa * 10 */
+       int16_t         temp;           /* 12 °C * 100 */
+
+       int16_t         acceleration;   /* 14 m/s² * 16 */
+       int16_t         speed;          /* 16 m/s * 16 */
+       int16_t         height;         /* 18 m */
+
+       int16_t         v_batt;         /* 20 battery voltage */
+       int16_t         sense_a;        /* 22 apogee continuity sense */
+       int16_t         sense_m;        /* 24 main continuity sense */
+
+       uint8_t         pad[6];         /* 26 */
+       /* 32 */
+};
+       
+#define AO_TELEMETRY_METRUM_DATA       0x0B
+
+struct ao_telemetry_metrum_data {
+       uint16_t        serial;         /*  0 */
+       uint16_t        tick;           /*  2 */
+       uint8_t         type;           /*  4 */
+
+       int32_t         ground_pres;    /* 8 average pres on pad */
+       int16_t         ground_accel;   /* 12 average accel on pad */
+       int16_t         accel_plus_g;   /* 14 accel calibration at +1g */
+       int16_t         accel_minus_g;  /* 16 accel calibration at -1g */
+
+       uint8_t         pad[14];        /* 18 */
+       /* 32 */
+};
+
+#define AO_TELEMETRY_MINI              0x10
+
+struct ao_telemetry_mini {
+       uint16_t        serial;         /*  0 */
+       uint16_t        tick;           /*  2 */
+       uint8_t         type;           /*  4 */
+
+       uint8_t         state;          /*  5 flight state */
+       int16_t         v_batt;         /*  6 battery voltage */
+       int16_t         sense_a;        /*  8 apogee continuity */
+       int16_t         sense_m;        /* 10 main continuity */
+
+       int32_t         pres;           /* 12 Pa * 10 */
+       int16_t         temp;           /* 16 °C * 100 */
+
+       int16_t         acceleration;   /* 18 m/s² * 16 */
+       int16_t         speed;          /* 20 m/s * 16 */
+       int16_t         height;         /* 22 m */
+
+       int32_t         ground_pres;    /* 24 average pres on pad */
+
+       int32_t         pad28;          /* 28 */
+       /* 32 */
+};
+
 /* #define AO_SEND_ALL_BARO */
 
 #define AO_TELEMETRY_BARO              0x80
@@ -240,6 +306,9 @@ union ao_telemetry_all {
        struct ao_telemetry_companion           companion;
        struct ao_telemetry_mega_sensor         mega_sensor;
        struct ao_telemetry_mega_data           mega_data;
+       struct ao_telemetry_metrum_sensor       metrum_sensor;
+       struct ao_telemetry_metrum_data         metrum_data;
+       struct ao_telemetry_mini                mini;
        struct ao_telemetry_baro                baro;
 };
 
index 6bc77608ef331a8782b6be051c948deab9cdcc52..35e64e655d92297c72fd36b070c59fb351621621 100644 (file)
@@ -102,8 +102,11 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];
 #define AO_USB_INT_EP          1
 #define AO_USB_INT_SIZE                8
 
+#ifndef AO_USB_OUT_EP
 #define AO_USB_OUT_EP          4
 #define AO_USB_IN_EP           5
+#endif
+
 /*
  * USB bulk packets can only come in 8, 16, 32 and 64
  * byte sizes, so we'll use 64 for everything
diff --git a/src/drivers/ao_74hc165.c b/src/drivers/ao_74hc165.c
new file mode 100644 (file)
index 0000000..143f4e3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * 74HC165 driver.
+ * Reads a single byte from the shift register
+ */
+
+#include <ao.h>
+#include <ao_74hc165.h>
+
+uint8_t
+ao_74hc165_read(void)
+{
+       static __xdata state;
+       ao_spi_get(AO_74HC165_SPI_BUS);
+       ao_spi_set_speed(AO_74HC165_SPI_BUS, AO_SPI_SPEED_FAST);
+       AO_74HC165_CS = 1;
+       ao_spi_recv(&state, 1, AO_74HC165_SPI_BUS);
+       AO_74HC165_CS = 0;
+       ao_spi_put(AO_74HC165_SPI_BUS);
+       return state;
+}
+
+static void
+ao_74hc165_cmd(void)
+{
+       uint8_t v;
+
+       v = ao_74hc165_read();
+       printf ("Switches: 0x%02x\n", v);
+}
+
+static const struct ao_cmds ao_74hc165_cmds[] = {
+       { ao_74hc165_cmd, "L\0Show 74hc165" },
+       { 0, NULL }
+};
+
+void
+ao_74hc165_init(void)
+{
+       ao_enable_output(AO_74HC165_CS_PORT, AO_74HC165_CS_PIN, AO_74HC165_CS, 0);
+       ao_cmd_register(&ao_74hc165_cmds[0]);
+}
diff --git a/src/drivers/ao_74hc165.h b/src/drivers/ao_74hc165.h
new file mode 100644 (file)
index 0000000..3ae5135
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_74HC165_H_
+#define _AO_74HC165_H_
+
+uint8_t
+ao_74hc165_read(void);
+
+void
+ao_74hc165_init(void);
+
+#endif /* _AO_74HC165_H_ */
index a507c909ea0248d80032a0739a67f0e4a8b05819..25c0cd5cea66b753813cd566102ce5ba6f7c9da9 100644 (file)
@@ -18,6 +18,7 @@
 #include <ao.h>
 #include <ao_button.h>
 #include <ao_exti.h>
+#include <ao_debounce.h>
 #if AO_EVENT
 #include <ao_event.h>
 #define ao_button_queue(b,v)   ao_event_put_isr(AO_EVENT_BUTTON, b, v)
 #define ao_button_queue(b,v)
 #endif
 
-static uint8_t         ao_button[AO_BUTTON_COUNT];
-static AO_TICK_TYPE    ao_button_time[AO_BUTTON_COUNT];
+#define AO_BUTTON_DEBOUNCE_HOLD        10
 
-#define AO_DEBOUNCE    AO_MS_TO_TICKS(20)
+static struct ao_debounce      ao_button_debounce[AO_BUTTON_COUNT];
 
 #define port(q)        AO_BUTTON_ ## q ## _PORT
 #define bit(q) AO_BUTTON_ ## q
 #define pin(q) AO_BUTTON_ ## q ## _PIN
 
-static void
-ao_button_do(uint8_t b, uint8_t v)
-{
-       /* Debounce */
-       if ((AO_TICK_SIGNED) (ao_tick_count - ao_button_time[b]) < AO_DEBOUNCE)
-               return;
-
-       /* pins are inverted */
-       v = !v;
-       if (ao_button[b] != v) {
-               ao_button[b] = v;
-               ao_button_time[b] = ao_tick_count;
-               ao_button_queue(b, v);
-               ao_wakeup(&ao_button[b]);
-       }
-}
+/* pins are inverted */
+#define ao_button_value(b)     !ao_gpio_get(port(b), bit(b), pin(b))
 
-#define ao_button_update(b)    ao_button_do(b, ao_gpio_get(port(b), bit(b), pin(b)))
-
-static void
-ao_button_isr(void)
+static uint8_t
+_ao_button_get(struct ao_debounce *debounce)
 {
+       uint8_t b = debounce - ao_button_debounce;
+
+       switch (b) {
 #if AO_BUTTON_COUNT > 0
-       ao_button_update(0);
+       case 0: return ao_button_value(0);
 #endif
 #if AO_BUTTON_COUNT > 1
-       ao_button_update(1);
+       case 1: return ao_button_value(1);
 #endif
 #if AO_BUTTON_COUNT > 2
-       ao_button_update(2);
+       case 2: return ao_button_value(2);
 #endif
 #if AO_BUTTON_COUNT > 3
-       ao_button_update(3);
+       case 3: return ao_button_value(3);
 #endif
 #if AO_BUTTON_COUNT > 4
-       ao_button_update(4);
+       case 4: return ao_button_value(4);
 #endif
+       }
+}
+
+static void
+_ao_button_set(struct ao_debounce *debounce, uint8_t value)
+{
+       uint8_t b = debounce - ao_button_debounce;
+
+       ao_button_queue(b, value);
+}
+
+
+#define ao_button_update(b)    ao_button_do(b, ao_gpio_get(port(b), bit(b), pin(b)))
+
+static void
+ao_button_debounce_init(struct ao_debounce *debounce) {
+       ao_debounce_config(debounce,
+                          _ao_button_get,
+                          _ao_button_set,
+                          AO_BUTTON_DEBOUNCE_HOLD);
+}
+
+static void
+ao_button_isr(void)
+{
+       uint8_t b;
+
+       for (b = 0; b < AO_BUTTON_COUNT; b++)
+               _ao_debounce_start(&ao_button_debounce[b]);
 }
 
 #define init(b) do {                                                   \
+               ao_button_debounce_init(&ao_button_debounce[b]);        \
                ao_enable_port(port(b));                                \
                                                                        \
                ao_exti_setup(port(b), bit(b),                          \
@@ -91,4 +108,14 @@ ao_button_init(void)
 #if AO_BUTTON_COUNT > 1
        init(1);
 #endif
+#if AO_BUTTON_COUNT > 2
+       init(2);
+#endif
+#if AO_BUTTON_COUNT > 3
+       init(3);
+#endif
+#if AO_BUTTON_COUNT > 4
+       init(4);
+#endif
+       ao_debounce_init();
 }
index 772014ee175f0087be15537b91f81e7ef15c1348..37d04927a0de0d15a1878a0ce8c1d32220cbae72 100644 (file)
@@ -326,6 +326,8 @@ static const uint16_t packet_setup[] = {
                                 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
                                 (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
                                 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
+        CC1120_PREAMBLE_CFG1,  ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
+                                (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
        AO_CC1120_MARC_GPIO_IOCFG,              CC1120_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP,
 };
 
@@ -389,6 +391,8 @@ static const uint16_t rdf_setup[] = {
                                 (0 << CC1120_PKT_CFG0_PKG_BIT_LEN) |
                                 (0 << CC1120_PKT_CFG0_UART_MODE_EN) |
                                 (0 << CC1120_PKT_CFG0_UART_SWAP_EN)),
+        CC1120_PREAMBLE_CFG1,  ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
+                                (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
 };
 
 /*
@@ -433,6 +437,33 @@ static const uint16_t aprs_setup[] = {
                                 (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
                                 (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
                                 (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
+        CC1120_PREAMBLE_CFG1,  ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
+                                (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
+};
+
+/*
+ * For Test mode, we want an unmodulated carrier. To do that, we
+ * set the deviation to zero and enable a preamble so that the radio
+ * turns on before we send any data
+ */
+
+static const uint16_t test_setup[] = {
+       CC1120_DEVIATION_M,     0,
+       CC1120_MODCFG_DEV_E,    ((CC1120_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1120_MODCFG_DEV_E_MODEM_MODE) |
+                                (CC1120_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1120_MODCFG_DEV_E_MOD_FORMAT) |
+                                (0 << CC1120_MODCFG_DEV_E_DEV_E)),
+       CC1120_DRATE2,          ((APRS_DRATE_E << CC1120_DRATE2_DATARATE_E) |
+                                (((APRS_DRATE_M >> 16) & CC1120_DRATE2_DATARATE_M_19_16_MASK) << CC1120_DRATE2_DATARATE_M_19_16)),
+       CC1120_DRATE1,          ((APRS_DRATE_M >> 8) & 0xff),
+       CC1120_DRATE0,          ((APRS_DRATE_M >> 0) & 0xff),
+       CC1120_PKT_CFG2,        ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
+                                (CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
+       CC1120_PKT_CFG1,        ((0 << CC1120_PKT_CFG1_WHITE_DATA) |
+                                (CC1120_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1120_PKT_CFG1_ADDR_CHECK_CFG) |
+                                (CC1120_PKT_CFG1_CRC_CFG_DISABLED << CC1120_PKT_CFG1_CRC_CFG) |
+                                (0 << CC1120_PKT_CFG1_APPEND_STATUS)),
+        CC1120_PREAMBLE_CFG1,  ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
+                                (CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
 };
 
 #define AO_PKT_CFG0_INFINITE ((0 << CC1120_PKT_CFG0_RESERVED7) |       \
@@ -456,8 +487,9 @@ static uint16_t ao_radio_mode;
 #define AO_RADIO_MODE_BITS_PACKET_RX   16
 #define AO_RADIO_MODE_BITS_RDF         32
 #define AO_RADIO_MODE_BITS_APRS                64
-#define AO_RADIO_MODE_BITS_INFINITE    128
-#define AO_RADIO_MODE_BITS_FIXED       256
+#define AO_RADIO_MODE_BITS_TEST                128
+#define AO_RADIO_MODE_BITS_INFINITE    256
+#define AO_RADIO_MODE_BITS_FIXED       512
 
 #define AO_RADIO_MODE_NONE             0
 #define AO_RADIO_MODE_PACKET_TX_BUF    (AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_PACKET_TX | AO_RADIO_MODE_BITS_TX_BUF)
@@ -467,6 +499,7 @@ static uint16_t ao_radio_mode;
 #define AO_RADIO_MODE_APRS_BUF         (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
 #define AO_RADIO_MODE_APRS_LAST_BUF    (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_BUF)
 #define AO_RADIO_MODE_APRS_FINISH      (AO_RADIO_MODE_BITS_APRS | AO_RADIO_MODE_BITS_FIXED | AO_RADIO_MODE_BITS_TX_FINISH)
+#define AO_RADIO_MODE_TEST             (AO_RADIO_MODE_BITS_TEST | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF)
 
 static void
 ao_radio_set_mode(uint16_t new_mode)
@@ -504,6 +537,10 @@ ao_radio_set_mode(uint16_t new_mode)
                for (i = 0; i < sizeof (aprs_setup) / sizeof (aprs_setup[0]); i += 2)
                        ao_radio_reg_write(aprs_setup[i], aprs_setup[i+1]);
 
+       if (changes & AO_RADIO_MODE_BITS_TEST)
+               for (i = 0; i < sizeof (test_setup) / sizeof (test_setup[0]); i += 2)
+                       ao_radio_reg_write(test_setup[i], test_setup[i+1]);
+
        if (changes & AO_RADIO_MODE_BITS_INFINITE)
                ao_radio_reg_write(CC1120_PKT_CFG0, AO_PKT_CFG0_INFINITE);
 
@@ -652,6 +689,7 @@ ao_radio_test_cmd(void)
                ao_packet_slave_stop();
 #endif
                ao_radio_get(0xff);
+               ao_radio_set_mode(AO_RADIO_MODE_TEST);
                ao_radio_strobe(CC1120_STX);
 #if CC1120_TRACE
                { int t; 
index 5d226b64137212b6c6ba2502b6755c9a4dc2b2a4..a1d78c01b1d80b145262ad7f04f9bae5750cb1a2 100644 (file)
 #define CC1120_MARC_SPARE      (CC1120_EXTENDED_BIT | 0x03)
 #define CC1120_ECG_CFG         (CC1120_EXTENDED_BIT | 0x04)
 #define CC1120_SOFT_TX_DATA_CFG        (CC1120_EXTENDED_BIT | 0x05)
+#define  CC1120_SOFT_TX_DATA_CFG_SYMBOL_MAP_CFG                5
+#define  CC1120_SOFT_TX_DATA_CFG_SOFT_TX_DATA_EN       0
 #define CC1120_EXT_CTRL                (CC1120_EXTENDED_BIT | 0x06)
 #define CC1120_RCCAL_FINE      (CC1120_EXTENDED_BIT | 0x07)
 #define CC1120_RCCAL_COARSE    (CC1120_EXTENDED_BIT | 0x08)
index 05e6a762ecc722854d3f24579eb40dff07101c55..0fa1e899044a23fae470cbaa7ac1b9a657b84014 100644 (file)
@@ -245,6 +245,8 @@ ao_radio_idle(void)
                uint8_t state = ao_radio_strobe(CC115L_SIDLE);
                if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_IDLE)
                        break;
+               if ((state >> CC115L_STATUS_STATE) == CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW)
+                       ao_radio_strobe(CC115L_SFTX);
        }
        /* Flush any pending TX bytes */
        ao_radio_strobe(CC115L_SFTX);
@@ -476,6 +478,8 @@ ao_radio_setup(void)
 
        ao_config_get();
 
+       ao_radio_strobe(CC115L_SCAL);
+
        ao_radio_configured = 1;
 }
 
@@ -494,7 +498,6 @@ static void
 ao_radio_get(void)
 {
        static uint32_t last_radio_setting;
-       static uint8_t  last_power_setting;
 
        ao_mutex_get(&ao_radio_mutex);
        if (!ao_radio_configured)
@@ -505,10 +508,6 @@ ao_radio_get(void)
                ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);
                last_radio_setting = ao_config.radio_setting;
        }
-       if (ao_config.radio_power != last_power_setting) {
-               ao_radio_reg_write(CC115L_PA, ao_config.radio_power);
-               last_power_setting = ao_config.radio_power;
-       }
 }
 
 static void
@@ -614,6 +613,20 @@ ao_radio_rdf_abort(void)
        ao_wakeup(&ao_radio_wake);
 }
 
+#define POWER_STEP     0x08
+
+static void
+ao_radio_stx(void)
+{
+       uint8_t power;
+       ao_radio_pa_on();
+       ao_radio_reg_write(CC115L_PA, 0);
+       ao_radio_strobe(CC115L_STX);
+       for (power = POWER_STEP; power < ao_config.radio_power; power += POWER_STEP)
+               ao_radio_reg_write(CC115L_PA, power);
+       ao_radio_reg_write(CC115L_PA, ao_config.radio_power);
+}
+
 static void
 ao_radio_test_cmd(void)
 {
@@ -633,11 +646,10 @@ ao_radio_test_cmd(void)
                ao_packet_slave_stop();
 #endif
                ao_radio_get();
-               ao_radio_set_len(0xff);
-               ao_radio_set_mode(AO_RADIO_MODE_RDF|AO_RADIO_MODE_BITS_FIXED);
                ao_radio_strobe(CC115L_SFTX);
-               ao_radio_pa_on();
-               ao_radio_strobe(CC115L_STX);
+               ao_radio_set_len(0xff);
+               ao_radio_set_mode(AO_RADIO_MODE_RDF);
+               ao_radio_stx();
                radio_on = 1;
        }
        if (mode == 3) {
@@ -655,12 +667,14 @@ ao_radio_test_cmd(void)
        }
 }
 
+#if CC115L_TRACE
 static inline int16_t
 ao_radio_gpio_bits(void)
 {
        return AO_CC115L_DONE_INT_PORT->idr & ((1 << AO_CC115L_FIFO_INT_PIN) |
                                               (1 << AO_CC115L_DONE_INT_PIN));
 }
+#endif
 
 static void
 ao_radio_wait_fifo(void)
@@ -738,6 +752,10 @@ _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode)
        uint8_t fifo_space;
 
        fifo_space = CC115L_FIFO_SIZE;
+       ao_radio_abort = 0;
+
+       ao_radio_strobe(CC115L_SFTX);
+
        ao_radio_done = 0;
        ao_radio_fifo = 0;
        while (!done) {
@@ -784,8 +802,7 @@ _ao_radio_send_lots(ao_radio_fill_func fill, uint8_t mode)
                        ao_exti_enable(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN);
 
                        if (!started) {
-                               ao_radio_pa_on();
-                               ao_radio_strobe(CC115L_STX);
+                               ao_radio_stx();
                                started = 1;
                        }
                }
index 440ef2de6d0ecd9f89a2359ce5387a9dcfd1e820..c428125d0760771b73e7264fe3211dc632256676 100644 (file)
 #define ao_event_queue_empty() (ao_event_queue_insert == ao_event_queue_remove)
 #define ao_event_queue_full()  (ao_event_queue_next(ao_event_queue_insert) == ao_event_queue_remove)
 
-/*
- * Whether a sequence of events from the same device should be collapsed
- */
-#define ao_event_can_collapse(type)    ((type) == AO_EVENT_QUADRATURE)
-
 struct ao_event ao_event_queue[AO_EVENT_QUEUE];
 uint8_t                ao_event_queue_insert;
 uint8_t                ao_event_queue_remove;
@@ -48,17 +43,9 @@ ao_event_get(struct ao_event *ev)
 
 /* called with interrupts disabled */
 void
-ao_event_put_isr(uint8_t type, uint8_t unit, uint32_t value)
+ao_event_put_isr(uint8_t type, uint8_t unit, int32_t value)
 {
        if (!ao_event_queue_full()) {
-
-               if (ao_event_can_collapse(type) && !ao_event_queue_empty()) {
-                       uint8_t prev = ao_event_queue_prev(ao_event_queue_insert);
-
-                       if (ao_event_queue[prev].type == type &&
-                           ao_event_queue[prev].unit == unit)
-                               ao_event_queue_insert = prev;
-               }
                ao_event_queue[ao_event_queue_insert] = (struct ao_event) {
                        .type = type,
                        .unit = unit,
@@ -71,7 +58,7 @@ ao_event_put_isr(uint8_t type, uint8_t unit, uint32_t value)
 }
 
 void
-ao_event_put(uint8_t type, uint8_t unit, uint32_t value)
+ao_event_put(uint8_t type, uint8_t unit, int32_t value)
 {
        ao_arch_critical(ao_event_put_isr(type, unit, value););
 }
index 25c49c3574b7f0f629d9deeef7b6eaaa5c125bf1..ed9a743329a49dc2cda65fa3b55b38b8fb225f9a 100644 (file)
@@ -26,16 +26,16 @@ struct ao_event {
        uint8_t         type;
        uint8_t         unit;
        uint16_t        tick;
-       uint32_t        value;
+       int32_t         value;
 };
 
 uint8_t
 ao_event_get(struct ao_event *ev);
 
 void
-ao_event_put_isr(uint8_t type, uint8_t unit, uint32_t value);
+ao_event_put_isr(uint8_t type, uint8_t unit, int32_t value);
 
 void
-ao_event_put(uint8_t type, uint8_t unit, uint32_t value);
+ao_event_put(uint8_t type, uint8_t unit, int32_t value);
 
 #endif /* _AO_EVENT_H_ */
index 91fc948b466fa18935fd5d3b6d34f5f65ce4cc83..d89435b9c635f46891ae62ca948a5378e4a7238a 100644 (file)
@@ -19,6 +19,7 @@
 #include "ao.h"
 #endif
 
+__xdata uint8_t ao_gps_new;
 __xdata uint8_t ao_gps_mutex;
 __pdata uint16_t ao_gps_tick;
 __xdata struct ao_telemetry_location   ao_gps_data;
@@ -422,8 +423,9 @@ ao_gps(void) __reentrant
                        else
                                ao_gps_data.v_error = ao_sirf_data.v_error / 100;
 #endif
+                       ao_gps_new |= AO_GPS_NEW_DATA;
                        ao_mutex_put(&ao_gps_mutex);
-                       ao_wakeup(&ao_gps_data);
+                       ao_wakeup(&ao_gps_new);
                        break;
                case 4:
                        ao_mutex_get(&ao_gps_mutex);
@@ -432,8 +434,9 @@ ao_gps(void) __reentrant
                                ao_gps_tracking_data.sats[i].svid = ao_sirf_tracker_data.sats[i].svid;
                                ao_gps_tracking_data.sats[i].c_n_1 = ao_sirf_tracker_data.sats[i].c_n_1;
                        }
+                       ao_gps_new |= AO_GPS_NEW_TRACKING;
                        ao_mutex_put(&ao_gps_mutex);
-                       ao_wakeup(&ao_gps_tracking_data);
+                       ao_wakeup(&ao_gps_new);
                        break;
                }
        }
index d2f67e6b6947b1f9cd4c8e1c87fc13a018eb23b7..944a37f9b38400a05ccc3d2a437f332141af8a79 100644 (file)
@@ -32,6 +32,7 @@
 #define ao_gps_set_speed       ao_serial1_set_speed
 #endif
 
+__xdata uint8_t ao_gps_new;
 __xdata uint8_t ao_gps_mutex;
 static __data char ao_gps_char;
 static __data uint8_t ao_gps_cksum;
@@ -293,10 +294,11 @@ ao_nmea_gga(void)
 
        if (!ao_gps_error) {
                ao_mutex_get(&ao_gps_mutex);
+               ao_gps_new |= AO_GPS_NEW_DATA;
                ao_gps_tick = ao_gps_next_tick;
                ao_xmemcpy(&ao_gps_data, PDATA_TO_XDATA(&ao_gps_next), sizeof (ao_gps_data));
                ao_mutex_put(&ao_gps_mutex);
-               ao_wakeup(&ao_gps_data);
+               ao_wakeup(&ao_gps_new);
        }
 }
 
@@ -352,9 +354,10 @@ ao_nmea_gsv(void)
                ao_gps_tracking_next.channels = 0;
        else if (done) {
                ao_mutex_get(&ao_gps_mutex);
+               ao_gps_new |= AO_GPS_NEW_TRACKING;
                ao_xmemcpy(&ao_gps_tracking_data, PDATA_TO_XDATA(&ao_gps_tracking_next), sizeof(ao_gps_tracking_data));
                ao_mutex_put(&ao_gps_mutex);
-               ao_wakeup(&ao_gps_tracking_data);
+               ao_wakeup(&ao_gps_new);
        }
 }
 
@@ -483,25 +486,6 @@ ao_gps(void) __reentrant
 
 __xdata struct ao_task ao_gps_task;
 
-static void
-gps_dump(void) __reentrant
-{
-       uint8_t i;
-       ao_mutex_get(&ao_gps_mutex);
-       printf ("Date: %02d/%02d/%02d\n", ao_gps_data.year, ao_gps_data.month, ao_gps_data.day);
-       printf ("Time: %02d:%02d:%02d\n", ao_gps_data.hour, ao_gps_data.minute, ao_gps_data.second);
-       printf ("Lat/Lon: %ld %ld\n", (long) ao_gps_data.latitude, (long) ao_gps_data.longitude);
-       printf ("Alt: %d\n", ao_gps_data.altitude);
-       printf ("Flags: 0x%x\n", ao_gps_data.flags);
-       printf ("Sats: %d", ao_gps_tracking_data.channels);
-       for (i = 0; i < ao_gps_tracking_data.channels; i++)
-               printf (" %d %d",
-                       ao_gps_tracking_data.sats[i].svid,
-                       ao_gps_tracking_data.sats[i].c_n_1);
-       printf ("\ndone\n");
-       ao_mutex_put(&ao_gps_mutex);
-}
-
 static __code uint8_t ao_gps_115200[] = {
        SKYTRAQ_MSG_3(5,0,5,0)  /* Set to 115200 baud */
 };
@@ -532,7 +516,7 @@ gps_update(void) __reentrant
 }
 
 __code struct ao_cmds ao_gps_cmds[] = {
-       { gps_dump,     "g\0Display GPS" },
+       { ao_gps_show,  "g\0Display GPS" },
        { gps_update,   "U\0Update GPS firmware" },
        { 0, NULL },
 };
index 22300df3100f636753aa90d4de39519bb0474f21..4fb907462c43691807e355a21549b63a6dd1658b 100644 (file)
 
 #include "ao_gps_ublox.h"
 
+#define AO_UBLOX_DEBUG 0
+
+#include <stdarg.h>
+
+__xdata uint8_t ao_gps_new;
 __xdata uint8_t ao_gps_mutex;
 __pdata uint16_t ao_gps_tick;
 __xdata struct ao_telemetry_location   ao_gps_data;
 __xdata struct ao_telemetry_satellite  ao_gps_tracking_data;
 
-static const char ao_gps_set_nmea[] = "\r\n$PUBX,41,1,3,1,57600,0*2d\r\n";
+#undef AO_SERIAL_SPEED_UBLOX
 
-const char ao_gps_config[] = {
+#ifndef AO_SERIAL_SPEED_UBLOX
+#define AO_SERIAL_SPEED_UBLOX AO_SERIAL_SPEED_9600
+#endif
 
-};
+#if AO_SERIAL_SPEED_UBLOX == AO_SERIAL_SPEED_57600
+#define SERIAL_SPEED_STRING    "57600"
+#define SERIAL_SPEED_CHECKSUM  "2d"
+#endif
+#if AO_SERIAL_SPEED_UBLOX == AO_SERIAL_SPEED_19200
+#define SERIAL_SPEED_STRING    "19200"
+#define SERIAL_SPEED_CHECKSUM  "23"
+#endif
+#if AO_SERIAL_SPEED_UBLOX == AO_SERIAL_SPEED_9600
+#define SERIAL_SPEED_STRING    "9600"
+#define SERIAL_SPEED_CHECKSUM  "16"
+#endif
+
+static const char ao_gps_set_nmea[] =
+       "\r\n$PUBX,41,1,3,1," SERIAL_SPEED_STRING ",0*" SERIAL_SPEED_CHECKSUM "\r\n";
 
 struct ao_ublox_cksum {
        uint8_t a, b;
@@ -39,13 +60,34 @@ struct ao_ublox_cksum {
 static __pdata struct ao_ublox_cksum ao_ublox_cksum;
 static __pdata uint16_t ao_ublox_len;
 
-#ifndef ao_ublox_getchar
-#define ao_ublox_getchar       ao_serial1_getchar
-#define ao_ublox_putchar       ao_serial1_putchar
-#define ao_ublox_set_speed     ao_serial1_set_speed
+#if AO_UBLOX_DEBUG
+
+static uint8_t ao_gps_dbg_enable;
+
+#define DBG_PROTO      1
+#define DBG_CHAR       2
+#define DBG_INIT       4
+
+static void ao_gps_dbg(int level, char *format, ...) {
+       va_list a;
+
+       if (level & ao_gps_dbg_enable) {
+               va_start(a, format);
+               vprintf(format, a);
+               va_end(a);
+               flush();
+       }
+}
+
+#else
+#define ao_gps_dbg(fmt, ...)
 #endif
 
-#define ao_ublox_byte()        ((uint8_t) ao_ublox_getchar())
+static inline uint8_t ao_ublox_byte(void) {
+       uint8_t c = (uint8_t) ao_gps_getchar();
+       ao_gps_dbg(DBG_CHAR, " %02x", c);
+       return c;
+}
 
 static inline void add_cksum(struct ao_ublox_cksum *cksum, uint8_t c)
 {
@@ -61,7 +103,8 @@ static void ao_ublox_init_cksum(void)
 static void ao_ublox_put_u8(uint8_t c)
 {
        add_cksum(&ao_ublox_cksum, c);
-       ao_ublox_putchar(c);
+       ao_gps_dbg(DBG_CHAR, " (%02x)", c);
+       ao_gps_putchar(c);
 }
 
 static void ao_ublox_put_i8(int8_t c)
@@ -183,6 +226,7 @@ ao_ublox_parse(void __xdata *target, const struct ublox_packet_parse *parse) __r
                        break;
                }
        }
+       ao_gps_dbg(DBG_PROTO, "\n");
 }
 
 /*
@@ -326,6 +370,7 @@ ao_ublox_parse_nav_svinfo(void)
 {
        uint8_t nsat;
        nav_svinfo_nsat = 0;
+
        ao_ublox_parse(&nav_svinfo, nav_svinfo_packet);
        for (nsat = 0; nsat < nav_svinfo.num_ch && ao_ublox_len >= 12; nsat++) {
                if (nsat < NAV_SVINFO_MAX_SAT) {
@@ -334,6 +379,17 @@ ao_ublox_parse_nav_svinfo(void)
                        ublox_discard(12);
                }
        }
+#if AO_UBLOX_DEBUG
+       ao_gps_dbg(DBG_PROTO, "svinfo num_ch %d flags %02x\n", nav_svinfo.num_ch, nav_svinfo.flags);
+       for (nsat = 0; nsat < nav_svinfo.num_ch; nsat++)
+               ao_gps_dbg(DBG_PROTO, "\t%d: chn %d svid %d flags %02x quality %d cno %d\n",
+                           nsat,
+                           nav_svinfo_sat[nsat].chn,
+                           nav_svinfo_sat[nsat].svid,
+                           nav_svinfo_sat[nsat].flags,
+                           nav_svinfo_sat[nsat].quality,
+                           nav_svinfo_sat[nsat].cno);
+#endif
 }
 
 /*
@@ -402,45 +458,60 @@ ao_ublox_parse_nav_velned(void)
  */
 
 static void
-ao_gps_setup(void)
+ao_gps_delay(void)
 {
-       uint8_t i, k;
-       ao_ublox_set_speed(AO_SERIAL_SPEED_9600);
+       uint8_t i;
 
        /*
         * A bunch of nulls so the start bit
         * is clear
         */
+
        for (i = 0; i < 64; i++)
-               ao_ublox_putchar(0x00);
+               ao_gps_putchar(0x00);
+}
+
+static void
+ao_gps_setup(void)
+{
+       uint8_t i, k;
+
+       ao_delay(AO_SEC_TO_TICKS(3));
+
+       ao_gps_dbg(DBG_INIT, "Set speed 9600\n");
+       ao_gps_set_speed(AO_SERIAL_SPEED_9600);
 
        /*
         * Send the baud-rate setting and protocol-setting
         * command three times
         */
-       for (k = 0; k < 3; k++)
+       for (k = 0; k < 3; k++) {
+               ao_gps_delay();
+
+               ao_gps_dbg(DBG_INIT, "Send initial setting\n");
                for (i = 0; i < sizeof (ao_gps_set_nmea); i++)
-                       ao_ublox_putchar(ao_gps_set_nmea[i]);
+                       ao_gps_putchar(ao_gps_set_nmea[i]);
+       }
+
+       ao_gps_delay();
 
+#if AO_SERIAL_SPEED_UBLOX != AO_SERIAL_SPEED_9600
+       ao_gps_dbg(DBG_INIT, "Set speed high\n");
        /*
         * Increase the baud rate
         */
-       ao_ublox_set_speed(AO_SERIAL_SPEED_57600);
+       ao_gps_set_speed(AO_SERIAL_SPEED_UBLOX);
+#endif
 
-       /*
-        * Pad with nulls to give the chip
-        * time to see the baud rate switch
-        */
-       for (i = 0; i < 64; i++)
-               ao_ublox_putchar(0x00);
+       ao_gps_delay();
 }
 
 static void
 ao_ublox_putstart(uint8_t class, uint8_t id, uint16_t len)
 {
        ao_ublox_init_cksum();
-       ao_ublox_putchar(0xb5);
-       ao_ublox_putchar(0x62);
+       ao_gps_putchar(0xb5);
+       ao_gps_putchar(0x62);
        ao_ublox_put_u8(class);
        ao_ublox_put_u8(id);
        ao_ublox_put_u8(len);
@@ -450,8 +521,8 @@ ao_ublox_putstart(uint8_t class, uint8_t id, uint16_t len)
 static void
 ao_ublox_putend(void)
 {
-       ao_ublox_putchar(ao_ublox_cksum.a);
-       ao_ublox_putchar(ao_ublox_cksum.b);
+       ao_gps_putchar(ao_ublox_cksum.a);
+       ao_gps_putchar(ao_ublox_cksum.b);
 }
 
 static void
@@ -547,7 +618,7 @@ ao_gps(void) __reentrant
        /* Enable all of the messages we want */
        for (i = 0; i < sizeof (ublox_enable_nav); i++)
                ao_ublox_set_message_rate(UBLOX_NAV, ublox_enable_nav[i], 1);
-       
+
        ao_ublox_set_navigation_settings((1 << UBLOX_CFG_NAV5_MASK_DYN) | (1 << UBLOX_CFG_NAV5_MASK_FIXMODE),
                                         UBLOX_CFG_NAV5_DYNMODEL_AIRBORNE_4G,
                                         UBLOX_CFG_NAV5_FIXMODE_3D,
@@ -578,6 +649,8 @@ ao_gps(void) __reentrant
                ao_ublox_len = header_byte();
                ao_ublox_len |= header_byte() << 8;
 
+               ao_gps_dbg(DBG_PROTO, "class %02x id %02x len %d\n", class, id, ao_ublox_len);
+
                if (ao_ublox_len > 1023)
                        continue;
 
@@ -618,8 +691,10 @@ ao_gps(void) __reentrant
                        break;
                }
 
-               if (ao_ublox_len != 0)
+               if (ao_ublox_len != 0) {
+                       ao_gps_dbg(DBG_PROTO, "len left %d\n", ao_ublox_len);
                        continue;
+               }
 
                /* verify checksum and end sequence */
                cksum.a = ao_ublox_byte();
@@ -628,9 +703,9 @@ ao_gps(void) __reentrant
                        continue;
 
                switch (class) {
-               case 0x01:
+               case UBLOX_NAV:
                        switch (id) {
-                       case 0x21:
+                       case UBLOX_NAV_TIMEUTC:
                                ao_mutex_get(&ao_gps_mutex);
                                ao_gps_tick = ao_time();
 
@@ -645,7 +720,7 @@ ao_gps(void) __reentrant
                                }
                                if (nav_timeutc.valid & (1 << NAV_TIMEUTC_VALID_UTC))
                                        ao_gps_data.flags |= AO_GPS_DATE_VALID;
-                               
+
                                ao_gps_data.altitude = nav_posllh.alt_msl / 1000;
                                ao_gps_data.latitude = nav_posllh.lat;
                                ao_gps_data.longitude = nav_posllh.lon;
@@ -667,7 +742,7 @@ ao_gps(void) __reentrant
                                ao_gps_data.ground_speed = nav_velned.g_speed;
                                ao_gps_data.climb_rate = -nav_velned.vel_d;
                                ao_gps_data.course = nav_velned.heading / 200000;
-                               
+
                                ao_gps_tracking_data.channels = 0;
 
                                struct ao_telemetry_satellite_info *dst = &ao_gps_tracking_data.sats[0];
@@ -686,8 +761,8 @@ ao_gps(void) __reentrant
                                }
 
                                ao_mutex_put(&ao_gps_mutex);
-                               ao_wakeup(&ao_gps_data);
-                               ao_wakeup(&ao_gps_tracking_data);
+                               ao_gps_new = AO_GPS_NEW_DATA | AO_GPS_NEW_TRACKING;
+                               ao_wakeup(&ao_gps_new);
                                break;
                        }
                        break;
@@ -695,10 +770,32 @@ ao_gps(void) __reentrant
        }
 }
 
+#if AO_UBLOX_DEBUG
+static void ao_gps_option(void)
+{
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success) {
+               ao_cmd_status = ao_cmd_success;
+               ao_gps_show();
+       } else {
+               ao_gps_dbg_enable = ao_cmd_lex_i;
+               printf ("gps debug set to %d\n", ao_gps_dbg_enable);
+       }
+}
+#else
+#define ao_gps_option ao_gps_show
+#endif
+
+__code struct ao_cmds ao_gps_cmds[] = {
+       { ao_gps_option,        "g\0Display GPS" },
+       { 0, NULL },
+};
+
 __xdata struct ao_task ao_gps_task;
 
 void
 ao_gps_init(void)
 {
+       ao_cmd_register(&ao_gps_cmds[0]);
        ao_add_task(&ao_gps_task, ao_gps, "gps");
 }
index 390637d7fd116b5c39889b4ed65df295d6d6e1b5..e6c7bb4db0c0f8d5e23a66261d8de690546e24bc 100644 (file)
@@ -82,11 +82,11 @@ __pdata uint16_t    ao_storage_unit;
 
 #if M25_MAX_CHIPS > 1
 static uint8_t ao_m25_size[M25_MAX_CHIPS];     /* number of sectors in each chip */
-static uint8_t ao_m25_pin[M25_MAX_CHIPS];      /* chip select pin for each chip */
+static ao_port_t ao_m25_pin[M25_MAX_CHIPS];    /* chip select pin for each chip */
 static uint8_t ao_m25_numchips;                        /* number of chips detected */
 #endif
 static uint8_t ao_m25_total;                   /* total sectors available */
-static uint8_t ao_m25_wip;                     /* write in progress */
+static ao_port_t ao_m25_wip;                   /* write in progress */
 
 static __xdata uint8_t ao_m25_mutex;
 
@@ -112,7 +112,7 @@ static __xdata uint8_t      ao_m25_instruction[4];
  * Block until the specified chip is done writing
  */
 static void
-ao_m25_wait_wip(uint8_t cs)
+ao_m25_wait_wip(ao_port_t cs)
 {
        if (ao_m25_wip & cs) {
                M25_SELECT(cs);
@@ -132,7 +132,7 @@ ao_m25_wait_wip(uint8_t cs)
  * so that future operations will block until the WIP bit goes off
  */
 static void
-ao_m25_write_enable(uint8_t cs)
+ao_m25_write_enable(ao_port_t cs)
 {
        M25_SELECT(cs);
        ao_m25_instruction[0] = M25_WREN;
@@ -146,7 +146,7 @@ ao_m25_write_enable(uint8_t cs)
  * Returns the number of 64kB sectors
  */
 static uint8_t
-ao_m25_read_capacity(uint8_t cs)
+ao_m25_read_capacity(ao_port_t cs)
 {
        uint8_t capacity;
        M25_SELECT(cs);
@@ -166,12 +166,13 @@ ao_m25_read_capacity(uint8_t cs)
        return 1 << (capacity - 0x10);
 }
 
-static uint8_t
+static ao_port_t
 ao_m25_set_address(uint32_t pos)
 {
-       uint8_t chip;
+       ao_port_t       mask;
 #if M25_MAX_CHIPS > 1
        uint8_t size;
+       uint8_t         chip;
 
        for (chip = 0; chip < ao_m25_numchips; chip++) {
                size = ao_m25_size[chip];
@@ -182,16 +183,16 @@ ao_m25_set_address(uint32_t pos)
        if (chip == ao_m25_numchips)
                return 0xff;
 
-       chip = ao_m25_pin[chip];
+       mask = ao_m25_pin[chip];
 #else
-       chip = AO_M25_SPI_CS_MASK;
+       mask = AO_M25_SPI_CS_MASK;
 #endif
-       ao_m25_wait_wip(chip);
+       ao_m25_wait_wip(mask);
 
        ao_m25_instruction[1] = pos >> 16;
        ao_m25_instruction[2] = pos >> 8;
        ao_m25_instruction[3] = pos;
-       return chip;
+       return mask;
 }
 
 /*
@@ -239,7 +240,7 @@ ao_m25_scan(void)
 uint8_t
 ao_storage_erase(uint32_t pos) __reentrant
 {
-       uint8_t cs;
+       ao_port_t       cs;
 
        if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
                return 0;
@@ -249,7 +250,6 @@ ao_storage_erase(uint32_t pos) __reentrant
 
        cs = ao_m25_set_address(pos);
 
-       ao_m25_wait_wip(cs);
        ao_m25_write_enable(cs);
 
        ao_m25_instruction[0] = M25_SE;
@@ -268,7 +268,7 @@ ao_storage_erase(uint32_t pos) __reentrant
 uint8_t
 ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
 {
-       uint8_t cs;
+       ao_port_t       cs;
 
        if (pos >= ao_storage_total || pos + len > ao_storage_total)
                return 0;
@@ -295,7 +295,7 @@ ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
 uint8_t
 ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
 {
-       uint8_t cs;
+       ao_port_t       cs;
 
        if (pos >= ao_storage_total || pos + len > ao_storage_total)
                return 0;
@@ -332,7 +332,7 @@ void
 ao_storage_device_info(void) __reentrant
 {
 #if M25_DEBUG
-       uint8_t cs;
+       ao_port_t       cs;
 #endif
 #if M25_MAX_CHIPS > 1
        uint8_t chip;
index 28fe1e08b1d28b46354ce0200d2954aaacb826d3..ce83a5a32054b4c1dde55dbb7c4060199b3d2c28 100644 (file)
@@ -206,10 +206,7 @@ ao_mma655x_setup(void)
        ao_mma655x_reg_write(AO_MMA655X_AXISCFG,
                             AXISCFG_VALUE |
                             (1 << AO_MMA655X_AXISCFG_ST));
-       for (i = 0; i < 10; i++) {
-               a_st = ao_mma655x_value();
-               printf ("SELF-TEST %2d = %6d\n", i, a_st);
-       }
+       a_st = ao_mma655x_value();
 
        stdefl = ao_mma655x_reg_read(AO_MMA655X_STDEFL);
 
@@ -218,11 +215,6 @@ ao_mma655x_setup(void)
                             (0 << AO_MMA655X_AXISCFG_ST));
        a = ao_mma655x_value();
 
-       for (i = 0; i < 10; i++) {
-               a = ao_mma655x_value();
-               printf("NORMAL   %2d = %6d\n", i, a);
-       }
-
        ao_mma655x_reg_write(AO_MMA655X_DEVCFG,
                             DEVCFG_VALUE | (1 << AO_MMA655X_DEVCFG_ENDINIT));
        s0 = ao_mma655x_reg_read(AO_MMA655X_SN0);
@@ -234,8 +226,6 @@ ao_mma655x_setup(void)
        serial = lot & 0x1fff;
        lot >>= 12;
        pn = ao_mma655x_reg_read(AO_MMA655X_PN);
-       printf ("MMA655X lot %d serial %d number %d\n", lot, serial, pn);
-
 }
 
 uint16_t       ao_mma655x_current;
index c65aecbcc1d363f9db603ea439f7c27b756df47d..f8ce7346c7149d690228c57445607382ce35c05b 100644 (file)
 #include <ao_mpu6000.h>
 #include <ao_exti.h>
 
+#if HAS_MPU6000
+
 static uint8_t ao_mpu6000_wake;
 static uint8_t ao_mpu6000_configured;
 
-#define ao_mpu6000_spi_get()   ao_spi_get_bit(AO_MPU6000_SPI_CS_PORT,  \
-                                              AO_MPU6000_SPI_CS_PIN,   \
-                                              AO_MPU6000_SPI_CS,       \
-                                              AO_MPU6000_SPI_BUS,      \
-                                              AO_SPI_SPEED_1MHz)
+#ifndef AO_MPU6000_I2C_INDEX
+#define AO_MPU6000_SPI 1
+#else
+#define AO_MPU6000_SPI 0
+#endif
+
+#if AO_MPU6000_SPI
+
+#define ao_mpu6000_spi_get()   ao_spi_get(AO_MPU6000_SPI_BUS, AO_SPI_SPEED_1MHz)
+#define ao_mpu6000_spi_put()   ao_spi_put(AO_MPU6000_SPI_BUS)
+
+#define ao_mpu6000_spi_start()         ao_spi_set_cs(AO_MPU6000_SPI_CS_PORT,   \
+                                             (1 << AO_MPU6000_SPI_CS_PIN))
+
+#define ao_mpu6000_spi_end()   ao_spi_clr_cs(AO_MPU6000_SPI_CS_PORT,   \
+                                             (1 << AO_MPU6000_SPI_CS_PIN))
 
-#define ao_mpu6000_spi_put()   ao_spi_put_bit(AO_MPU6000_SPI_CS_PORT,  \
-                                              AO_MPU6000_SPI_CS_PIN,   \
-                                              AO_MPU6000_SPI_CS,       \
-                                              AO_MPU6000_SPI_BUS)
+#endif
 
 
 static void
-ao_mpu6000_reg_write(uint8_t addr, uint8_t value)
+_ao_mpu6000_reg_write(uint8_t addr, uint8_t value)
 {
        uint8_t d[2] = { addr, value };
-#ifdef AO_MPU6000_I2C_INDEX
+#if AO_MPU6000_SPI
+       ao_mpu6000_spi_start();
+       ao_spi_send(d, 2, AO_MPU6000_SPI_BUS);
+       ao_mpu6000_spi_end();
+#else
        ao_i2c_get(AO_MPU6000_I2C_INDEX);
        ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_WRITE);
        ao_i2c_send(d, 2, AO_MPU6000_I2C_INDEX, TRUE);
        ao_i2c_put(AO_MPU6000_I2C_INDEX);
-#else
-       ao_mpu6000_spi_get();
-       ao_spi_send(d, 2, AO_MPU6000_SPI_BUS);
-       ao_mpu6000_spi_put();
 #endif
 }
 
 static void
-ao_mpu6000_read(uint8_t addr, void *data, uint8_t len)
+_ao_mpu6000_read(uint8_t addr, void *data, uint8_t len)
 {
-#ifdef AO_MPU6000_I2C_INDEX
+#if AO_MPU6000_SPI
+       addr |= 0x80;
+       ao_mpu6000_spi_start();
+       ao_spi_send(&addr, 1, AO_MPU6000_SPI_BUS);
+       ao_spi_recv(data, len, AO_MPU6000_SPI_BUS);
+       ao_mpu6000_spi_end();
+#else
        ao_i2c_get(AO_MPU6000_I2C_INDEX);
        ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_WRITE);
        ao_i2c_send(&addr, 1, AO_MPU6000_I2C_INDEX, FALSE);
        ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_READ);
        ao_i2c_recv(data, len, AO_MPU6000_I2C_INDEX, TRUE);
        ao_i2c_put(AO_MPU6000_I2C_INDEX);
-#else
-       addr |= 0x80;
-       ao_mpu6000_spi_get();
-       ao_spi_send(&addr, 1, AO_MPU6000_SPI_BUS);
-       ao_spi_recv(data, len, AO_MPU6000_SPI_BUS);
-       ao_mpu6000_spi_put();
 #endif
 }
 
 static uint8_t
-ao_mpu6000_reg_read(uint8_t addr)
+_ao_mpu6000_reg_read(uint8_t addr)
 {
        uint8_t value;
-#ifdef AO_MPU6000_I2C_INDEX
+#if AO_MPU6000_SPI
+       addr |= 0x80;
+       ao_mpu6000_spi_start();
+       ao_spi_send(&addr, 1, AO_MPU6000_SPI_BUS);
+       ao_spi_recv(&value, 1, AO_MPU6000_SPI_BUS);
+       ao_mpu6000_spi_end();
+#else
        ao_i2c_get(AO_MPU6000_I2C_INDEX);
        ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_WRITE);
        ao_i2c_send(&addr, 1, AO_MPU6000_I2C_INDEX, FALSE);
        ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_READ);
        ao_i2c_recv(&value, 1, AO_MPU6000_I2C_INDEX, TRUE);
        ao_i2c_put(AO_MPU6000_I2C_INDEX);
-#else
-       addr |= 0x80;
-       ao_mpu6000_spi_get();
-       ao_spi_send(&addr, 1, AO_MPU6000_SPI_BUS);
-       ao_spi_recv(&value, 1, AO_MPU6000_SPI_BUS);
-       ao_mpu6000_spi_put();
 #endif
        return value;
 }
 
 static void
-ao_mpu6000_sample(struct ao_mpu6000_sample *sample)
+_ao_mpu6000_sample(struct ao_mpu6000_sample *sample)
 {
        uint16_t        *d = (uint16_t *) sample;
        int             i = sizeof (*sample) / 2;
 
-       ao_mpu6000_read(MPU6000_ACCEL_XOUT_H, sample, sizeof (*sample));
+       _ao_mpu6000_read(MPU6000_ACCEL_XOUT_H, sample, sizeof (*sample));
 #if __BYTE_ORDER == __LITTLE_ENDIAN
        /* byte swap */
        while (i--) {
@@ -108,6 +118,7 @@ ao_mpu6000_sample(struct ao_mpu6000_sample *sample)
 
 #define G      981     /* in cm/s² */
 
+#if 0
 static int16_t /* cm/s² */
 ao_mpu6000_accel(int16_t v)
 {
@@ -119,16 +130,17 @@ ao_mpu6000_gyro(int16_t v)
 {
        return (int16_t) ((v * (int32_t) 20000) / 32767);
 }
+#endif
 
 static uint8_t
 ao_mpu6000_accel_check(int16_t normal, int16_t test, char *which)
 {
        int16_t diff = test - normal;
 
-       if (diff < MPU6000_ST_ACCEL(16) / 2) {
+       if (diff < MPU6000_ST_ACCEL(16) / 4) {
                return 1;
        }
-       if (diff > MPU6000_ST_ACCEL(16) * 2) {
+       if (diff > MPU6000_ST_ACCEL(16) * 4) {
                return 1;
        }
        return 0;
@@ -141,142 +153,168 @@ ao_mpu6000_gyro_check(int16_t normal, int16_t test, char *which)
 
        if (diff < 0)
                diff = -diff;
-       if (diff < MPU6000_ST_GYRO(2000) / 2) {
+       if (diff < MPU6000_ST_GYRO(2000) / 4) {
                return 1;
        }
-       if (diff > MPU6000_ST_GYRO(2000) * 2) {
+       if (diff > MPU6000_ST_GYRO(2000) * 4) {
                return 1;
        }
        return 0;
 }
 
 static void
-ao_mpu6000_setup(void)
+_ao_mpu6000_wait_alive(void)
+{
+       uint8_t i;
+
+       /* Wait for the chip to wake up */
+       for (i = 0; i < 30; i++) {
+               ao_delay(AO_MS_TO_TICKS(100));
+               if (_ao_mpu6000_reg_read(MPU6000_WHO_AM_I) == 0x68)
+                       break;
+       }
+       if (i == 30)
+               ao_panic(AO_PANIC_SELF_TEST_MPU6000);
+}
+
+#define ST_TRIES       10
+
+static void
+_ao_mpu6000_setup(void)
 {
        struct ao_mpu6000_sample        normal_mode, test_mode;
-       int                             errors =0;
+       int                             errors;
+       int                             st_tries;
 
        if (ao_mpu6000_configured)
                return;
 
+       _ao_mpu6000_wait_alive();
+
        /* Reset the whole chip */
        
-       ao_mpu6000_reg_write(MPU6000_PWR_MGMT_1,
-                            (1 << MPU6000_PWR_MGMT_1_DEVICE_RESET));
+       _ao_mpu6000_reg_write(MPU6000_PWR_MGMT_1,
+                             (1 << MPU6000_PWR_MGMT_1_DEVICE_RESET));
 
        /* Wait for it to reset. If we talk too quickly, it appears to get confused */
-       ao_delay(AO_MS_TO_TICKS(100));
 
-       /* Reset signal conditioning */
-       ao_mpu6000_reg_write(MPU6000_USER_CONTROL,
-                            (0 << MPU6000_USER_CONTROL_FIFO_EN) |
-                            (0 << MPU6000_USER_CONTROL_I2C_MST_EN) |
-                            (0 << MPU6000_USER_CONTROL_I2C_IF_DIS) |
-                            (0 << MPU6000_USER_CONTROL_FIFO_RESET) |
-                            (0 << MPU6000_USER_CONTROL_I2C_MST_RESET) |
-                            (1 << MPU6000_USER_CONTROL_SIG_COND_RESET));
+       _ao_mpu6000_wait_alive();
 
-       while (ao_mpu6000_reg_read(MPU6000_USER_CONTROL) & (1 << MPU6000_USER_CONTROL_SIG_COND_RESET))
-               ao_yield();
+       /* Reset signal conditioning, disabling I2C on SPI systems */
+       _ao_mpu6000_reg_write(MPU6000_USER_CTRL,
+                             (0 << MPU6000_USER_CTRL_FIFO_EN) |
+                             (0 << MPU6000_USER_CTRL_I2C_MST_EN) |
+                             (AO_MPU6000_SPI << MPU6000_USER_CTRL_I2C_IF_DIS) |
+                             (0 << MPU6000_USER_CTRL_FIFO_RESET) |
+                             (0 << MPU6000_USER_CTRL_I2C_MST_RESET) |
+                             (1 << MPU6000_USER_CTRL_SIG_COND_RESET));
+
+       while (_ao_mpu6000_reg_read(MPU6000_USER_CTRL) & (1 << MPU6000_USER_CTRL_SIG_COND_RESET))
+               ao_delay(AO_MS_TO_TICKS(10));
 
        /* Reset signal paths */
-       ao_mpu6000_reg_write(MPU6000_SIGNAL_PATH_RESET,
-                            (1 << MPU6000_SIGNAL_PATH_RESET_GYRO_RESET) |
-                            (1 << MPU6000_SIGNAL_PATH_RESET_ACCEL_RESET) |
-                            (1 << MPU6000_SIGNAL_PATH_RESET_TEMP_RESET));
+       _ao_mpu6000_reg_write(MPU6000_SIGNAL_PATH_RESET,
+                             (1 << MPU6000_SIGNAL_PATH_RESET_GYRO_RESET) |
+                             (1 << MPU6000_SIGNAL_PATH_RESET_ACCEL_RESET) |
+                             (1 << MPU6000_SIGNAL_PATH_RESET_TEMP_RESET));
 
-       ao_mpu6000_reg_write(MPU6000_SIGNAL_PATH_RESET,
-                            (0 << MPU6000_SIGNAL_PATH_RESET_GYRO_RESET) |
-                            (0 << MPU6000_SIGNAL_PATH_RESET_ACCEL_RESET) |
-                            (0 << MPU6000_SIGNAL_PATH_RESET_TEMP_RESET));
+       _ao_mpu6000_reg_write(MPU6000_SIGNAL_PATH_RESET,
+                             (0 << MPU6000_SIGNAL_PATH_RESET_GYRO_RESET) |
+                             (0 << MPU6000_SIGNAL_PATH_RESET_ACCEL_RESET) |
+                             (0 << MPU6000_SIGNAL_PATH_RESET_TEMP_RESET));
 
        /* Select clocks, disable sleep */
-       ao_mpu6000_reg_write(MPU6000_PWR_MGMT_1,
-                            (0 << MPU6000_PWR_MGMT_1_DEVICE_RESET) |
-                            (0 << MPU6000_PWR_MGMT_1_SLEEP) |
-                            (0 << MPU6000_PWR_MGMT_1_CYCLE) |
-                            (0 << MPU6000_PWR_MGMT_1_TEMP_DIS) |
-                            (MPU6000_PWR_MGMT_1_CLKSEL_PLL_X_AXIS << MPU6000_PWR_MGMT_1_CLKSEL));
+       _ao_mpu6000_reg_write(MPU6000_PWR_MGMT_1,
+                             (0 << MPU6000_PWR_MGMT_1_DEVICE_RESET) |
+                             (0 << MPU6000_PWR_MGMT_1_SLEEP) |
+                             (0 << MPU6000_PWR_MGMT_1_CYCLE) |
+                             (0 << MPU6000_PWR_MGMT_1_TEMP_DIS) |
+                             (MPU6000_PWR_MGMT_1_CLKSEL_PLL_X_AXIS << MPU6000_PWR_MGMT_1_CLKSEL));
 
-       /* Set sample rate divider to sample at full speed
-       ao_mpu6000_reg_write(MPU6000_SMPRT_DIV, 0);
+       /* Set sample rate divider to sample at full speed */
+       _ao_mpu6000_reg_write(MPU6000_SMPRT_DIV, 0);
 
        /* Disable filtering */
-       ao_mpu6000_reg_write(MPU6000_CONFIG,
-                            (MPU6000_CONFIG_EXT_SYNC_SET_DISABLED << MPU6000_CONFIG_EXT_SYNC_SET) |
-                            (MPU6000_CONFIG_DLPF_CFG_260_256 << MPU6000_CONFIG_DLPF_CFG));
-
-       /* Configure accelerometer to +/-16G in self-test mode */
-       ao_mpu6000_reg_write(MPU6000_ACCEL_CONFIG,
-                            (1 << MPU600_ACCEL_CONFIG_XA_ST) |
-                            (1 << MPU600_ACCEL_CONFIG_YA_ST) |
-                            (1 << MPU600_ACCEL_CONFIG_ZA_ST) |
-                            (MPU600_ACCEL_CONFIG_AFS_SEL_16G << MPU600_ACCEL_CONFIG_AFS_SEL));
-
-       /* Configure gyro to +/- 2000°/s in self-test mode */
-       ao_mpu6000_reg_write(MPU6000_GYRO_CONFIG,
-                            (1 << MPU600_GYRO_CONFIG_XG_ST) |
-                            (1 << MPU600_GYRO_CONFIG_YG_ST) |
-                            (1 << MPU600_GYRO_CONFIG_ZG_ST) |
-                            (MPU600_GYRO_CONFIG_FS_SEL_2000 << MPU600_GYRO_CONFIG_FS_SEL));
-
-       ao_delay(AO_MS_TO_TICKS(200));
-       ao_mpu6000_sample(&test_mode);
+       _ao_mpu6000_reg_write(MPU6000_CONFIG,
+                             (MPU6000_CONFIG_EXT_SYNC_SET_DISABLED << MPU6000_CONFIG_EXT_SYNC_SET) |
+                             (MPU6000_CONFIG_DLPF_CFG_260_256 << MPU6000_CONFIG_DLPF_CFG));
 
 #if TRIDGE
        // read the product ID rev c has 1/2 the sensitivity of rev d
-    _mpu6000_product_id = _register_read(MPUREG_PRODUCT_ID);
-    //Serial.printf("Product_ID= 0x%x\n", (unsigned) _mpu6000_product_id);
-
-    if ((_mpu6000_product_id == MPU6000ES_REV_C4) || (_mpu6000_product_id == MPU6000ES_REV_C5) ||
-        (_mpu6000_product_id == MPU6000_REV_C4) || (_mpu6000_product_id == MPU6000_REV_C5)) {
-        // Accel scale 8g (4096 LSB/g)
-        // Rev C has different scaling than rev D
-        register_write(MPUREG_ACCEL_CONFIG,1<<3);
-    } else {
-        // Accel scale 8g (4096 LSB/g)
-        register_write(MPUREG_ACCEL_CONFIG,2<<3);
-    }
-    hal.scheduler->delay(1);
-
+       _mpu6000_product_id = _register_read(MPUREG_PRODUCT_ID);
+       //Serial.printf("Product_ID= 0x%x\n", (unsigned) _mpu6000_product_id);
+
+       if ((_mpu6000_product_id == MPU6000ES_REV_C4) || (_mpu6000_product_id == MPU6000ES_REV_C5) ||
+           (_mpu6000_product_id == MPU6000_REV_C4) || (_mpu6000_product_id == MPU6000_REV_C5)) {
+               // Accel scale 8g (4096 LSB/g)
+               // Rev C has different scaling than rev D
+               register_write(MPUREG_ACCEL_CONFIG,1<<3);
+       } else {
+               // Accel scale 8g (4096 LSB/g)
+               register_write(MPUREG_ACCEL_CONFIG,2<<3);
+       }
+       hal.scheduler->delay(1);
 #endif
 
-       /* Configure accelerometer to +/-16G */
-       ao_mpu6000_reg_write(MPU6000_ACCEL_CONFIG,
-                            (0 << MPU600_ACCEL_CONFIG_XA_ST) |
-                            (0 << MPU600_ACCEL_CONFIG_YA_ST) |
-                            (0 << MPU600_ACCEL_CONFIG_ZA_ST) |
-                            (MPU600_ACCEL_CONFIG_AFS_SEL_16G << MPU600_ACCEL_CONFIG_AFS_SEL));
-
-       /* Configure gyro to +/- 2000°/s */
-       ao_mpu6000_reg_write(MPU6000_GYRO_CONFIG,
-                            (0 << MPU600_GYRO_CONFIG_XG_ST) |
-                            (0 << MPU600_GYRO_CONFIG_YG_ST) |
-                            (0 << MPU600_GYRO_CONFIG_ZG_ST) |
-                            (MPU600_GYRO_CONFIG_FS_SEL_2000 << MPU600_GYRO_CONFIG_FS_SEL));
-
-       ao_delay(AO_MS_TO_TICKS(10));
-       ao_mpu6000_sample(&normal_mode);
+       for (st_tries = 0; st_tries < ST_TRIES; st_tries++) {
+               errors = 0;
+
+               /* Configure accelerometer to +/-16G in self-test mode */
+               _ao_mpu6000_reg_write(MPU6000_ACCEL_CONFIG,
+                                     (1 << MPU600_ACCEL_CONFIG_XA_ST) |
+                                     (1 << MPU600_ACCEL_CONFIG_YA_ST) |
+                                     (1 << MPU600_ACCEL_CONFIG_ZA_ST) |
+                                     (MPU600_ACCEL_CONFIG_AFS_SEL_16G << MPU600_ACCEL_CONFIG_AFS_SEL));
+
+               /* Configure gyro to +/- 2000°/s in self-test mode */
+               _ao_mpu6000_reg_write(MPU6000_GYRO_CONFIG,
+                                     (1 << MPU600_GYRO_CONFIG_XG_ST) |
+                                     (1 << MPU600_GYRO_CONFIG_YG_ST) |
+                                     (1 << MPU600_GYRO_CONFIG_ZG_ST) |
+                                     (MPU600_GYRO_CONFIG_FS_SEL_2000 << MPU600_GYRO_CONFIG_FS_SEL));
+
+               ao_delay(AO_MS_TO_TICKS(200));
+               _ao_mpu6000_sample(&test_mode);
+
+               /* Configure accelerometer to +/-16G */
+               _ao_mpu6000_reg_write(MPU6000_ACCEL_CONFIG,
+                                     (0 << MPU600_ACCEL_CONFIG_XA_ST) |
+                                     (0 << MPU600_ACCEL_CONFIG_YA_ST) |
+                                     (0 << MPU600_ACCEL_CONFIG_ZA_ST) |
+                                     (MPU600_ACCEL_CONFIG_AFS_SEL_16G << MPU600_ACCEL_CONFIG_AFS_SEL));
+
+               /* Configure gyro to +/- 2000°/s */
+               _ao_mpu6000_reg_write(MPU6000_GYRO_CONFIG,
+                                     (0 << MPU600_GYRO_CONFIG_XG_ST) |
+                                     (0 << MPU600_GYRO_CONFIG_YG_ST) |
+                                     (0 << MPU600_GYRO_CONFIG_ZG_ST) |
+                                     (MPU600_GYRO_CONFIG_FS_SEL_2000 << MPU600_GYRO_CONFIG_FS_SEL));
+
+               ao_delay(AO_MS_TO_TICKS(200));
+               _ao_mpu6000_sample(&normal_mode);
        
-       errors += ao_mpu6000_accel_check(normal_mode.accel_x, test_mode.accel_x, "x");
-       errors += ao_mpu6000_accel_check(normal_mode.accel_y, test_mode.accel_y, "y");
-       errors += ao_mpu6000_accel_check(normal_mode.accel_z, test_mode.accel_z, "z");
-
-       errors += ao_mpu6000_gyro_check(normal_mode.gyro_x, test_mode.gyro_x, "x");
-       errors += ao_mpu6000_gyro_check(normal_mode.gyro_y, test_mode.gyro_y, "y");
-       errors += ao_mpu6000_gyro_check(normal_mode.gyro_z, test_mode.gyro_z, "z");
+               errors += ao_mpu6000_accel_check(normal_mode.accel_x, test_mode.accel_x, "x");
+               errors += ao_mpu6000_accel_check(normal_mode.accel_y, test_mode.accel_y, "y");
+               errors += ao_mpu6000_accel_check(normal_mode.accel_z, test_mode.accel_z, "z");
+
+               errors += ao_mpu6000_gyro_check(normal_mode.gyro_x, test_mode.gyro_x, "x");
+               errors += ao_mpu6000_gyro_check(normal_mode.gyro_y, test_mode.gyro_y, "y");
+               errors += ao_mpu6000_gyro_check(normal_mode.gyro_z, test_mode.gyro_z, "z");
+               if (!errors)
+                       break;
+       }
 
-       if (errors)
-               ao_panic(AO_PANIC_SELF_TEST_MPU6000);
+       if (st_tries == ST_TRIES)
+               ao_sensor_errors = 1;
 
        /* Filter to about 100Hz, which also sets the gyro rate to 1000Hz */
-       ao_mpu6000_reg_write(MPU6000_CONFIG,
-                            (MPU6000_CONFIG_EXT_SYNC_SET_DISABLED << MPU6000_CONFIG_EXT_SYNC_SET) |
-                            (MPU6000_CONFIG_DLPF_CFG_94_98 << MPU6000_CONFIG_DLPF_CFG));
+       _ao_mpu6000_reg_write(MPU6000_CONFIG,
+                             (MPU6000_CONFIG_EXT_SYNC_SET_DISABLED << MPU6000_CONFIG_EXT_SYNC_SET) |
+                             (MPU6000_CONFIG_DLPF_CFG_94_98 << MPU6000_CONFIG_DLPF_CFG));
 
        /* Set sample rate divider to sample at 200Hz (v = gyro/rate - 1) */
-       ao_mpu6000_reg_write(MPU6000_SMPRT_DIV,
-                            1000 / 200 - 1);
+       _ao_mpu6000_reg_write(MPU6000_SMPRT_DIV,
+                             1000 / 200 - 1);
        
        ao_delay(AO_MS_TO_TICKS(100));
        ao_mpu6000_configured = 1;
@@ -287,10 +325,20 @@ struct ao_mpu6000_sample  ao_mpu6000_current;
 static void
 ao_mpu6000(void)
 {
-       ao_mpu6000_setup();
+       /* ao_mpu6000_init already grabbed the SPI bus and mutex */
+       _ao_mpu6000_setup();
+#if AO_MPU6000_SPI
+       ao_mpu6000_spi_put();
+#endif
        for (;;)
        {
-               ao_mpu6000_sample(&ao_mpu6000_current);
+#if AO_MPU6000_SPI
+               ao_mpu6000_spi_get();
+#endif
+               _ao_mpu6000_sample(&ao_mpu6000_current);
+#if AO_MPU6000_SPI
+               ao_mpu6000_spi_put();
+#endif 
                ao_arch_critical(
                        AO_DATA_PRESENT(AO_DATA_MPU6000);
                        AO_DATA_WAIT();
@@ -326,5 +374,20 @@ ao_mpu6000_init(void)
        ao_mpu6000_configured = 0;
 
        ao_add_task(&ao_mpu6000_task, ao_mpu6000, "mpu6000");
+       
+#if AO_MPU6000_SPI
+       ao_spi_init_cs(AO_MPU6000_SPI_CS_PORT, (1 << AO_MPU6000_SPI_CS_PIN));
+
+       /* Pretend to be the mpu6000 task. Grab the SPI bus right away and
+        * hold it for the task so that nothing else uses the SPI bus before
+        * we get the I2C mode disabled in the chip
+        */
+
+       ao_cur_task = &ao_mpu6000_task;
+       ao_spi_get(AO_MPU6000_SPI_BUS, AO_SPI_SPEED_1MHz);
+       ao_cur_task = NULL;
+#endif 
+
        ao_cmd_register(&ao_mpu6000_cmds[0]);
 }
+#endif
index f01e9e83b81ce9ca52ff0b2f3e32a9d07af7175d..dc3a9fbfa0e9f664d15f04726641ffd306edc104 100644 (file)
 #ifndef _AO_MPU6000_H_
 #define _AO_MPU6000_H_
 
+#ifndef M_PI
+#define M_PI 3.1415926535897832384626433
+#endif
+
 #define MPU6000_ADDR_WRITE     0xd0
 #define MPU6000_ADDR_READ      0xd1
 
 #define MPU6000_SIGNAL_PATH_RESET_ACCEL_RESET  1
 #define MPU6000_SIGNAL_PATH_RESET_TEMP_RESET   0
 
-#define MPU6000_USER_CONTROL           0x6a
-#define MPU6000_USER_CONTROL_FIFO_EN           6
-#define MPU6000_USER_CONTROL_I2C_MST_EN                5
-#define MPU6000_USER_CONTROL_I2C_IF_DIS                4
-#define MPU6000_USER_CONTROL_FIFO_RESET                2
-#define MPU6000_USER_CONTROL_I2C_MST_RESET     1
-#define MPU6000_USER_CONTROL_SIG_COND_RESET    0
+#define MPU6000_USER_CTRL              0x6a
+#define MPU6000_USER_CTRL_FIFO_EN              6
+#define MPU6000_USER_CTRL_I2C_MST_EN           5
+#define MPU6000_USER_CTRL_I2C_IF_DIS           4
+#define MPU6000_USER_CTRL_FIFO_RESET           2
+#define MPU6000_USER_CTRL_I2C_MST_RESET                1
+#define MPU6000_USER_CTRL_SIG_COND_RESET       0
 
 #define MPU6000_PWR_MGMT_1     0x6b
 #define MPU6000_PWR_MGMT_1_DEVICE_RESET                7
 /* Self test gyro is approximately 50°/s */
 #define MPU6000_ST_GYRO(full_scale)    ((int16_t) (((int32_t) 32767 * (int32_t) 50) / (full_scale)))
 
-#define MPU6000_GYRO_FULLSCALE 2000
+#define MPU6000_GYRO_FULLSCALE ((float) 2000 * M_PI/180.0)
+
+static inline float
+ao_mpu6000_gyro(float sensor) {
+       return sensor * ((float) (MPU6000_GYRO_FULLSCALE / 32767.0));
+}
+
 #define MPU6000_ACCEL_FULLSCALE        16
 
+static inline float
+ao_mpu6000_accel(int16_t sensor) {
+       return (float) sensor * ((float) (MPU6000_ACCEL_FULLSCALE * GRAVITY / 32767.0));
+}
+
 struct ao_mpu6000_sample {
        int16_t         accel_x;
        int16_t         accel_y;
index bd57400e94690524170ae6ddaa203f3103eff0b2..58ab91973ce0b63b5a51c0e6b053a1b903d10fa8 100644 (file)
 
 #if HAS_MS5607 || HAS_MS5611
 
-static struct ao_ms5607_prom   ms5607_prom;
-static uint8_t                 ms5607_configured;
+static __xdata struct ao_ms5607_prom   ms5607_prom;
+static __xdata uint8_t                 ms5607_configured;
 
 static void
 ao_ms5607_start(void) {
-       ao_spi_get(AO_MS5607_SPI_INDEX,AO_SPI_SPEED_FAST);
-       ao_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, 0);
+       ao_spi_get_bit(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, AO_MS5607_SPI_INDEX, AO_SPI_SPEED_FAST);
 }
 
 static void
 ao_ms5607_stop(void) {
-       ao_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, 1);
-       ao_spi_put(AO_MS5607_SPI_INDEX);
+       ao_spi_put_bit(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, AO_MS5607_SPI_INDEX);
 }
 
 static void
@@ -42,7 +40,7 @@ ao_ms5607_reset(void) {
 
        cmd = AO_MS5607_RESET;
        ao_ms5607_start();
-       ao_spi_send(&cmd, 1, AO_MS5607_SPI_INDEX);
+       ao_spi_send(DATA_TO_XDATA(&cmd), 1, AO_MS5607_SPI_INDEX);
        ao_delay(AO_MS_TO_TICKS(10));
        ao_ms5607_stop();
 }
@@ -71,17 +69,17 @@ ao_ms5607_crc(uint8_t *prom)
 }
 
 static void
-ao_ms5607_prom_read(struct ao_ms5607_prom *prom)
+ao_ms5607_prom_read(__xdata struct ao_ms5607_prom *prom)
 {
-       uint8_t         addr;
-       uint8_t         crc;
-       uint16_t        *r;
+       uint8_t                 addr;
+       uint8_t                 crc;
+       __xdata uint16_t        *r;
 
-       r = (uint16_t *) prom;
+       r = (__xdata uint16_t *) prom;
        for (addr = 0; addr < 8; addr++) {
                uint8_t cmd = AO_MS5607_PROM_READ(addr);
                ao_ms5607_start();
-               ao_spi_send(&cmd, 1, AO_MS5607_SPI_INDEX);
+               ao_spi_send(DATA_TO_XDATA(&cmd), 1, AO_MS5607_SPI_INDEX);
                ao_spi_recv(r, 2, AO_MS5607_SPI_INDEX);
                ao_ms5607_stop();
                r++;
@@ -116,25 +114,25 @@ ao_ms5607_setup(void)
        ao_ms5607_prom_read(&ms5607_prom);
 }
 
-static volatile uint8_t        ao_ms5607_done;
+static __xdata volatile uint8_t        ao_ms5607_done;
 
 static void
 ao_ms5607_isr(void)
 {
        ao_exti_disable(AO_MS5607_MISO_PORT, AO_MS5607_MISO_PIN);
        ao_ms5607_done = 1;
-       ao_wakeup((void *) &ao_ms5607_done);
+       ao_wakeup((__xdata void *) &ao_ms5607_done);
 }
 
 static uint32_t
 ao_ms5607_get_sample(uint8_t cmd) {
-       uint8_t reply[3];
-       uint8_t read;
+       __xdata uint8_t reply[3];
+       __xdata uint8_t read;
 
        ao_ms5607_done = 0;
 
        ao_ms5607_start();
-       ao_spi_send(&cmd, 1, AO_MS5607_SPI_INDEX);
+       ao_spi_send(DATA_TO_XDATA(&cmd), 1, AO_MS5607_SPI_INDEX);
 
        ao_exti_enable(AO_MS5607_MISO_PORT, AO_MS5607_MISO_PIN);
 
@@ -142,7 +140,8 @@ ao_ms5607_get_sample(uint8_t cmd) {
        ao_spi_put(AO_MS5607_SPI_INDEX);
 #endif
        ao_arch_block_interrupts();
-       while (!ao_ms5607_done)
+       while (!ao_gpio_get(AO_MS5607_MISO_PORT, AO_MS5607_MISO_PIN, AO_MS5607_MISO) &&
+              !ao_ms5607_done)
                ao_sleep((void *) &ao_ms5607_done);
        ao_arch_release_interrupts();
 #if AO_MS5607_PRIVATE_PINS
@@ -175,16 +174,20 @@ ao_ms5607_get_sample(uint8_t cmd) {
 #define AO_CONVERT_D2  token_evaluator(AO_MS5607_CONVERT_D2_, AO_MS5607_TEMP_OVERSAMPLE)
 
 void
-ao_ms5607_sample(struct ao_ms5607_sample *sample)
+ao_ms5607_sample(__xdata struct ao_ms5607_sample *sample)
 {
        sample->pres = ao_ms5607_get_sample(AO_CONVERT_D1);
        sample->temp = ao_ms5607_get_sample(AO_CONVERT_D2);
 }
 
+#ifdef _CC1111_H_
+#include "ao_ms5607_convert_8051.c"
+#else
 #include "ao_ms5607_convert.c"
+#endif
 
 #if HAS_TASK
-struct ao_ms5607_sample        ao_ms5607_current;
+__xdata struct ao_ms5607_sample        ao_ms5607_current;
 
 static void
 ao_ms5607(void)
@@ -193,10 +196,10 @@ ao_ms5607(void)
        for (;;)
        {
                ao_ms5607_sample(&ao_ms5607_current);
-               ao_arch_critical(
-                       AO_DATA_PRESENT(AO_DATA_MS5607);
-                       AO_DATA_WAIT();
-                       );
+               ao_arch_block_interrupts();
+               AO_DATA_PRESENT(AO_DATA_MS5607);
+               AO_DATA_WAIT();
+               ao_arch_release_interrupts();
        }
 }
 
@@ -218,11 +221,11 @@ ao_ms5607_info(void)
 static void
 ao_ms5607_dump(void)
 {
-       struct ao_ms5607_value value;
+       __xdata struct ao_ms5607_value value;
 
        ao_ms5607_convert(&ao_ms5607_current, &value);
-       printf ("Pressure:    %8u %8d\n", ao_ms5607_current.pres, value.pres);
-       printf ("Temperature: %8u %8d\n", ao_ms5607_current.temp, value.temp);
+       printf ("Pressure:    %8lu %8ld\n", ao_ms5607_current.pres, value.pres);
+       printf ("Temperature: %8lu %8ld\n", ao_ms5607_current.temp, value.temp);
        printf ("Altitude: %ld\n", ao_pa_to_altitude(value.pres));
 }
 
@@ -249,17 +252,9 @@ ao_ms5607_init(void)
         */
        ao_exti_setup(AO_MS5607_MISO_PORT,
                      AO_MS5607_MISO_PIN,
-                     AO_EXTI_MODE_RISING,
+                     AO_EXTI_MODE_RISING|
+                     AO_EXTI_PIN_NOCONFIGURE,
                      ao_ms5607_isr);
-
-#ifdef STM_MODER_ALTERNATE
-       /* Reset the pin from INPUT to ALTERNATE so that SPI works
-        * This needs an abstraction at some point...
-        */
-       stm_moder_set(AO_MS5607_MISO_PORT,
-                     AO_MS5607_MISO_PIN,
-                     STM_MODER_ALTERNATE);
-#endif
 }
 
 #endif
index b2f98a59d9677397fa60e6a0fa42b94c5c6a8ded..206efd64f8c2e8ccf7934ef0441c3bff70f16b78 100644 (file)
@@ -56,7 +56,7 @@ struct ao_ms5607_value {
        int32_t         temp;   /* in °C * 100 */
 };
 
-extern struct ao_ms5607_sample ao_ms5607_current;
+extern __xdata struct ao_ms5607_sample ao_ms5607_current;
 
 void
 ao_ms5607_setup(void);
@@ -68,12 +68,13 @@ void
 ao_ms5607_info(void);
 
 void
-ao_ms5607_sample(struct ao_ms5607_sample *sample);
+ao_ms5607_sample(__xdata struct ao_ms5607_sample *sample);
 
 void
-ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value);
+ao_ms5607_convert(__xdata struct ao_ms5607_sample *sample,
+                 __xdata struct ao_ms5607_value *value);
 
 void
-ao_ms5607_get_prom(struct ao_ms5607_prom *prom);
+ao_ms5607_get_prom(__data struct ao_ms5607_prom *prom);
 
 #endif /* _AO_MS5607_H_ */
index e61d19ed61d637eee6fff3e48982cdc82856062b..bfb952a47e7b2c8a1da54701a34765d6cd7e38f3 100644 (file)
@@ -42,11 +42,14 @@ ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value
                int32_t TEMPM = TEMP - 2000;
                int64_t OFF2 = (61 * (int64_t) TEMPM * (int64_t) TEMPM) >> 4;
                int64_t SENS2 = 2 * (int64_t) TEMPM * (int64_t) TEMPM;
-               if (TEMP < 1500) {
+               if (TEMP < -1500) {
                        int32_t TEMPP = TEMP + 1500;
-                       int64_t TEMPP2 = TEMPP * TEMPP;
-                       OFF2 = OFF2 + 15 * TEMPP2;
-                       SENS2 = SENS2 + 8 * TEMPP2;
+                       /* You'd think this would need a 64-bit int, but
+                        * that would imply a temperature below -327.67°C...
+                        */
+                       int32_t TEMPP2 = TEMPP * TEMPP;
+                       OFF2 = OFF2 + (int64_t) 15 * TEMPP2;
+                       SENS2 = SENS2 + (int64_t) 8 * TEMPP2;
                }
                TEMP -= T2;
                OFF -= OFF2;
diff --git a/src/drivers/ao_ms5607_convert_8051.c b/src/drivers/ao_ms5607_convert_8051.c
new file mode 100644 (file)
index 0000000..f3a48c4
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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_ms5607.h>
+#include <ao_int64.h>
+
+#if HAS_MS5611
+#define SHIFT_OFF      16
+#define SHIFT_TCO      7
+#define SHIFT_SENS     15
+#define SHFIT_TCS      8
+#else
+#define SHIFT_OFF      17
+#define SHIFT_TCO      6
+#define SHIFT_SENS     16
+#define SHIFT_TCS      7
+#endif
+
+void
+ao_ms5607_convert(__xdata struct ao_ms5607_sample *sample,
+                 __xdata struct ao_ms5607_value *value)
+{
+       __LOCAL int32_t dT;
+       __LOCAL int32_t TEMP;
+       __LOCAL ao_int64_t OFF;
+       __LOCAL ao_int64_t SENS;
+       __LOCAL ao_int64_t a;
+
+       dT = sample->temp - ((int32_t) ms5607_prom.tref << 8);
+       
+       /* TEMP = 2000 + (((int64_t) dT * ms5607_prom.tempsens) >> 23); */
+       ao_mul64_32_32(&a, dT, ms5607_prom.tempsens);
+       ao_rshift64(&a, &a, 23);
+       TEMP = 2000 + a.low;
+       /* */
+
+       /* OFF = ((int64_t) ms5607_prom.off << SHIFT_OFF) + (((int64_t) ms5607_prom.tco * dT) >> SHIFT_TCO);*/
+#if SHIFT_OFF > 16
+       OFF.high = ms5607_prom.off >> (32 - SHIFT_OFF);
+#else
+       OFF.high = 0;
+#endif
+       OFF.low = (uint32_t) ms5607_prom.off << SHIFT_OFF;
+       ao_mul64_32_32(&a, ms5607_prom.tco, dT);
+       ao_rshift64(&a, &a, SHIFT_TCO);
+       ao_plus64(&OFF, &OFF, &a);
+       /**/
+
+       /* SENS = ((int64_t) ms5607_prom.sens << SHIFT_SENS) + (((int64_t) ms5607_prom.tcs * dT) >> SHIFT_TCS); */
+       SENS.high = 0;
+       SENS.low = (uint32_t) ms5607_prom.sens << SHIFT_SENS;
+       ao_mul64_32_32(&a, ms5607_prom.tcs, dT);
+       ao_rshift64(&a, &a, SHIFT_TCS);
+       ao_plus64(&SENS, &SENS, &a);
+       /**/
+
+       if (TEMP < 2000) {
+               __LOCAL int32_t T2;
+               __LOCAL int32_t TEMPM;
+               __LOCAL ao_int64_t OFF2;
+               __LOCAL ao_int64_t SENS2;
+
+               /* T2 = ((int64_t) dT * (int64_t) dT) >> 31; */
+               ao_mul64_32_32(&a, dT, dT);
+               T2 = (a.low >> 31) | (a.high << 1);
+               /**/
+
+               TEMPM = TEMP - 2000;
+
+               /* OFF2 = (61 * (int64_t) TEMPM * (int64_t) TEMPM) >> 4; */
+               ao_mul64_32_32(&OFF2, TEMPM, TEMPM);
+               ao_mul64_64_16(&OFF2, &OFF2, 61);
+               ao_rshift64(&OFF2, &OFF2, 4);
+               /**/
+               
+               /* SENS2 = 2 * (int64_t) TEMPM * (int64_t) TEMPM; */
+               ao_mul64_32_32(&SENS2, TEMPM, TEMPM);
+               ao_lshift64(&SENS2, &SENS2, 1);
+               /**/
+
+               if (TEMP < -1500) {
+                       int32_t TEMPP;
+                       int32_t TEMPP2;
+
+                       TEMPP = TEMP + 1500;
+                       TEMPP2 = TEMPP * TEMPP;
+
+                       /* OFF2 = OFF2 + 15 * TEMPP2; */
+                       ao_mul64_32_32(&a, 15, TEMPP2);
+                       ao_plus64(&OFF2, &OFF2, &a);
+                       /**/
+
+                       /* SENS2 = SENS2 + 8 * TEMPP2; */
+                       a.high = 0;
+                       a.low = TEMPP2;
+                       ao_lshift64(&a, &a, 3);
+                       ao_plus64(&SENS2, &SENS2, &a);
+                       /**/
+               }
+               TEMP -= T2;
+
+               /* OFF -= OFF2; */
+               ao_minus64(&OFF, &OFF, &OFF2);
+               /**/
+
+               /* SENS -= SENS2; */
+               ao_minus64(&SENS, &SENS, &SENS2);
+               /**/
+       }
+
+       /* value->pres = ((((int64_t) sample->pres * SENS) >> 21) - OFF) >> 15; */
+       a.high = 0;
+       a.low = sample->pres;
+       ao_mul64(&a, &a, &SENS);
+       ao_rshift64(&a, &a, 21);
+       ao_minus64(&a, &a, &OFF);
+       ao_rshift64(&a, &a, 15);
+       value->pres = a.low;
+       /**/
+       
+       value->temp = TEMP;
+}
index 6cec98ab6e52bcc22ce3d68ee21d8579ae521973..62ae68e98d976dcdabee72103ce32300ad355e21 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <ao.h>
 #include <ao_pad.h>
-#include <ao_74hc497.h>
+#include <ao_74hc165.h>
 #include <ao_radio_cmac.h>
 
 static __xdata uint8_t ao_pad_ignite;
@@ -27,6 +27,7 @@ static __pdata uint8_t        ao_pad_armed;
 static __pdata uint16_t        ao_pad_arm_time;
 static __pdata uint8_t ao_pad_box;
 static __xdata uint8_t ao_pad_disabled;
+static __pdata uint16_t        ao_pad_packet_time;
 
 #define DEBUG  1
 
@@ -135,6 +136,12 @@ ao_pad_monitor(void)
                        query.arm_status = AO_PAD_ARM_STATUS_UNKNOWN;
                        arm_beep_time = 0;
                }
+               if ((ao_time() - ao_pad_packet_time) > AO_SEC_TO_TICKS(2))
+                       cur |= AO_LED_RED;
+               else if (ao_radio_cmac_rssi < -90)
+                       cur |= AO_LED_AMBER;
+               else
+                       cur |= AO_LED_GREEN;
 
                for (c = 0; c < AO_PAD_NUM; c++) {
                        int16_t         sense = packet->adc.sense[c];
@@ -171,9 +178,10 @@ ao_pad_monitor(void)
                        query.igniter_status[c] = status;
                }
                if (cur != prev) {
-                       PRINTD("change leds from %02x to %02x mask %02x\n",
-                              prev, cur, AO_LED_CONTINUITY_MASK|AO_LED_ARMED);
-                       ao_led_set_mask(cur, AO_LED_CONTINUITY_MASK | AO_LED_ARMED);
+                       PRINTD("change leds from %02x to %02x\n",
+                              prev, cur);
+                       FLUSHD();
+                       ao_led_set(cur);
                        prev = cur;
                }
 
@@ -182,10 +190,7 @@ ao_pad_monitor(void)
 
                if (ao_pad_armed) {
                        ao_strobe(1);
-                       if (sample & 2)
-                               ao_siren(1);
-                       else
-                               ao_siren(0);
+                       ao_siren(1);
                        beeping = 1;
                } else if (query.arm_status == AO_PAD_ARM_STATUS_ARMED && !beeping) {
                        if (arm_beep_time == 0) {
@@ -218,6 +223,21 @@ ao_pad_enable(void)
        ao_wakeup (&ao_pad_disabled);
 }
 
+#if HAS_74HC165
+static uint8_t
+ao_pad_read_box(void)
+{
+       uint8_t         byte = ao_74hc165_read();
+       uint8_t         h, l;
+
+       h = byte >> 4;
+       l = byte & 0xf;
+       return h * 10 + l;
+}
+#else
+#define ao_pad_read_box()      0
+#endif
+
 static void
 ao_pad(void)
 {
@@ -226,18 +246,20 @@ ao_pad(void)
 
        ao_pad_box = 0;
        ao_led_set(0);
-       ao_led_on(AO_LED_POWER);
        for (;;) {
                FLUSHD();
                while (ao_pad_disabled)
                        ao_sleep(&ao_pad_disabled);
                ret = ao_radio_cmac_recv(&command, sizeof (command), 0);
-               PRINTD ("cmac_recv %d\n", ret);
+               PRINTD ("cmac_recv %d %d\n", ret, ao_radio_cmac_rssi);
                if (ret != AO_RADIO_CMAC_OK)
                        continue;
+               ao_pad_packet_time = ao_time();
                
-               PRINTD ("tick %d box %d cmd %d channels %02x\n",
-                       command.tick, command.box, command.cmd, command.channels);
+               ao_pad_box = ao_pad_read_box();
+
+               PRINTD ("tick %d box %d (me %d) cmd %d channels %02x\n",
+                       command.tick, command.box, ao_pad_box, command.cmd, command.channels);
 
                switch (command.cmd) {
                case AO_LAUNCH_ARM:
@@ -327,7 +349,7 @@ ao_pad_test(void)
        }
 
        for (c = 0; c < AO_PAD_NUM; c++) {
-               printf ("Pad %d: ");
+               printf ("Pad %d: ", c);
                switch (query.igniter_status[c]) {
                case AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_CLOSED:     printf ("No igniter. Relay closed\n"); break;
                case AO_PAD_IGNITER_STATUS_NO_IGNITER_RELAY_OPEN:       printf ("No igniter. Relay open\n"); break;
@@ -362,6 +384,26 @@ ao_pad_set_debug(void)
        if (ao_cmd_status == ao_cmd_success)
                ao_pad_debug = ao_cmd_lex_i != 0;
 }
+
+
+static void
+ao_pad_alarm_debug(void)
+{
+       uint8_t which, value;
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       which = ao_cmd_lex_i;
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       value = ao_cmd_lex_i;
+       printf ("Set %s to %d\n", which ? "siren" : "strobe", value);
+       if (which)
+               ao_siren(value);
+       else
+               ao_strobe(value);
+}
 #endif
 
 __code struct ao_cmds ao_pad_cmds[] = {
@@ -369,6 +411,7 @@ __code struct ao_cmds ao_pad_cmds[] = {
        { ao_pad_manual,        "i <key> <n>\0Fire igniter. <key> is doit with D&I" },
 #if DEBUG
        { ao_pad_set_debug,     "D <0 off, 1 on>\0Debug" },
+       { ao_pad_alarm_debug,   "S <0 strobe, 1 siren> <0 off, 1 on>\0Set alarm output" },
 #endif
        { 0, NULL }
 };
index 6d8d18d8f8eb7df1880eb9d3ca29887786180515..d376b9681194fc94d00d394781f74b19a75ace98 100644 (file)
@@ -30,9 +30,12 @@ ao_led_apply(void)
        /* Don't try the SPI bus during initialization */
        if (!ao_cur_task)
                return;
-       ao_spi_get_bit(AO_PCA9922_CS_PORT, AO_PCA9922_CS_PIN, AO_PCA9922_CS, AO_PCA9922_SPI_BUS, AO_SPI_SPEED_FAST);
+       ao_spi_get(AO_PCA9922_SPI_BUS);
+       ao_spi_set_speed(AO_PCA9922_SPI_BUS,AO_SPI_SPEED_FAST);
+       AO_PCA9922_CS = 1;
        ao_spi_send(&ao_led_state, 1, AO_PCA9922_SPI_BUS);
-       ao_spi_put_bit(AO_PCA9922_CS_PORT, AO_PCA9922_CS_PIN, AO_PCA9922_CS, AO_PCA9922_SPI_BUS);
+       AO_PCA9922_CS = 0;
+       ao_spi_put(AO_PCA9922_SPI_BUS);
 }
 
 void
index 6cc2467a44ba2449121faaffcf4451d9401d0fe0..d07488d08d4f9307b661a0f690f9447dab4fec73 100644 (file)
 #include <ao.h>
 #include <ao_quadrature.h>
 #include <ao_exti.h>
-#if AO_EVENT
+#include <ao_fast_timer.h>
 #include <ao_event.h>
-#define ao_quadrature_queue(q) ao_event_put_isr(AO_EVENT_QUADRATURE, q, ao_quadrature_count[q])
-#else
-#define ao_quadrature_queue(q)
-#endif
 
 __xdata int32_t ao_quadrature_count[AO_QUADRATURE_COUNT];
-
 static uint8_t ao_quadrature_state[AO_QUADRATURE_COUNT];
+static int8_t  ao_quadrature_raw[AO_QUADRATURE_COUNT];
 
 #define BIT(a,b)       ((a) | ((b) << 1))
 #define STATE(old_a, old_b, new_a, new_b)      (((BIT(old_a, old_b) << 2) | BIT(new_a, new_b)))
@@ -35,41 +31,76 @@ static uint8_t      ao_quadrature_state[AO_QUADRATURE_COUNT];
 #define port(q)        AO_QUADRATURE_ ## q ## _PORT
 #define bita(q) AO_QUADRATURE_ ## q ## _A
 #define bitb(q) AO_QUADRATURE_ ## q ## _B
+#define pina(q) AO_QUADRATURE_ ## q ## _A ## _PIN
+#define pinb(q) AO_QUADRATURE_ ## q ## _B ## _PIN
+#define isr(q)  ao_quadrature_isr_ ## q
 
-#define ao_quadrature_update(q) do {                                   \
-               ao_quadrature_state[q] = ((ao_quadrature_state[q] & 3) << 2); \
-               ao_quadrature_state[q] |= ao_gpio_get(port(q), bita(q), 0); \
-               ao_quadrature_state[q] |= ao_gpio_get(port(q), bitb(q), 0) << 1; \
-       } while (0)
-       
+static inline uint16_t
+ao_quadrature_read(struct stm_gpio *gpio, uint8_t pin_a, uint8_t pin_b) {
+       uint16_t        v = stm_gpio_get_all(gpio);
+
+       return ~((((v >> pin_a) & 1) | (((v >> pin_b) & 1) << 1))) & 3;
+}
+
+#define _ao_quadrature_get(q)  ao_quadrature_read(port(q), bita(q), bitb(q))
 
 static void
-ao_quadrature_isr(void)
+_ao_quadrature_queue(uint8_t q, int8_t step)
 {
-       uint8_t q;
-#if AO_QUADRATURE_COUNT > 0
-       ao_quadrature_update(0);
-#endif
-#if AO_QUADRATURE_COUNT > 1
-       ao_quadrature_update(1);
+       ao_quadrature_count[q] += step;
+#if AO_EVENT
+       ao_event_put_isr(AO_EVENT_QUADRATURE, q, step);
 #endif
+       ao_wakeup(&ao_quadrature_count[q]);
+}
 
-       for (q = 0; q < AO_QUADRATURE_COUNT; q++) {
-               switch (ao_quadrature_state[q]) {
-               case STATE(0, 1, 0, 0):
-                       ao_quadrature_count[q]++;
-                       break;
-               case STATE(1, 0, 0, 0):
-                       ao_quadrature_count[q]--;
-                       break;
-               default:
-                       continue;
-               }
-               ao_quadrature_queue(q);
-               ao_wakeup(&ao_quadrature_count[q]);
+static const int8_t    step[16] = {
+       [STATE(0,0,0,0)] = 0,
+       [STATE(0,0,0,1)] = -1,
+       [STATE(0,0,1,0)] = 1,
+       [STATE(0,0,1,1)] = 0,
+       [STATE(0,1,0,0)] = 1,
+       [STATE(0,1,1,0)] = 0,
+       [STATE(0,1,1,1)] = -1,
+       [STATE(1,0,0,0)] = -1,
+       [STATE(1,0,0,1)] = 0,
+       [STATE(1,0,1,0)] = 0,
+       [STATE(1,0,1,1)] = 1,
+       [STATE(1,1,0,0)] = 0,
+       [STATE(1,1,0,1)] = 1,
+       [STATE(1,1,1,0)] = -1,
+       [STATE(1,1,1,1)] = 0
+};
+
+static void
+_ao_quadrature_set(uint8_t q, uint8_t value) {
+       uint8_t v;
+       
+       v = ao_quadrature_state[q] & 3;
+       value = value & 3;
+
+       if (v == value)
+               return;
+       
+       ao_quadrature_state[q] = (v << 2) | value;
+
+       ao_quadrature_raw[q] += step[ao_quadrature_state[q]];
+       if (value == 0) {
+               if (ao_quadrature_raw[q] == 4)
+                       _ao_quadrature_queue(q, 1);
+               else if (ao_quadrature_raw[q] == -4)
+                       _ao_quadrature_queue(q, -1);
+               ao_quadrature_raw[q] = 0;
        }
 }
 
+static void
+ao_quadrature_isr(void)
+{
+       _ao_quadrature_set(0, _ao_quadrature_get(0));
+       _ao_quadrature_set(1, _ao_quadrature_get(1));
+}
+
 int32_t
 ao_quadrature_poll(uint8_t q)
 {
@@ -92,6 +123,15 @@ ao_quadrature_test(void)
 
        ao_cmd_decimal();
        q = ao_cmd_lex_i;
+       if (q >= AO_QUADRATURE_COUNT) {
+               ao_cmd_status = ao_cmd_syntax_error;
+               return;
+       }
+       printf ("count %d state %x raw %d\n",
+               ao_quadrature_count[q],
+               ao_quadrature_state[q],
+               ao_quadrature_raw[q]);
+#if 0
        for (;;) {
                int32_t c;
                flush();
@@ -100,6 +140,7 @@ ao_quadrature_test(void)
                if (c == 100)
                        break;
        }
+#endif
 }
 
 static const struct ao_cmds ao_quadrature_cmds[] = {
@@ -107,18 +148,9 @@ static const struct ao_cmds ao_quadrature_cmds[] = {
        { 0, NULL }
 };
 
-#define init(q) do {                                                   \
-               ao_enable_port(port(q));                                \
-                                                                       \
-               ao_exti_setup(port(q), bita(q),                         \
-                             AO_QUADRATURE_MODE|AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_MED, \
-                             ao_quadrature_isr);                       \
-               ao_exti_enable(port(q), bita(q));                       \
-                                                                       \
-               ao_exti_setup(port(q), bitb(q),                         \
-                             AO_QUADRATURE_MODE|AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_MED, \
-                             ao_quadrature_isr);                       \
-               ao_exti_enable(port(q), bitb(q));                       \
+#define init(q) do {                                   \
+               ao_enable_input(port(q), bita(q), 0);   \
+               ao_enable_input(port(q), bitb(q), 0);   \
        } while (0)
 
 void
@@ -130,5 +162,7 @@ ao_quadrature_init(void)
 #if AO_QUADRATURE_COUNT > 1
        init(1);
 #endif
+       ao_fast_timer_init();
+       ao_fast_timer_on(ao_quadrature_isr);
        ao_cmd_register(&ao_quadrature_cmds[0]);
 }
diff --git a/src/drivers/ublox-csum.5c b/src/drivers/ublox-csum.5c
new file mode 100644 (file)
index 0000000..4e0c7c5
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/nickle
+string[] speeds = { "57600", "19200", "9600" };
+
+string make_set_nmea(string speed) {
+       return sprintf ("PUBX,41,1,3,1,%s,0", speed);
+}
+
+int csum(string x) {
+       int csum = 0;
+       for (int i = 0; i < String::length(x); i++)
+               csum ^= x[i];
+       return csum;
+}
+
+for (int i = 0; i < dim(speeds); i++) {
+       string s = make_set_nmea(speeds[i]);
+       int c = csum(s);
+       printf ("/* $%s* */\n", s);
+       printf ("#define SERIAL_SPEED_STRING   \"%s\"\n", speeds[i]);
+       printf ("#define SERIAL_SPEED_CHECKSUM \"%02x\"\n", c);
+}
+       
+       
diff --git a/src/easymini-v1.0/.gitignore b/src/easymini-v1.0/.gitignore
new file mode 100644 (file)
index 0000000..e5f7d58
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+*.elf
diff --git a/src/easymini-v1.0/Makefile b/src/easymini-v1.0/Makefile
new file mode 100644 (file)
index 0000000..7dae269
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# AltOS build
+#
+#
+
+include ../lpc/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_pins.h \
+       ao_product.h \
+       lpc.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_task.c \
+       ao_log.c \
+       ao_log_mini.c \
+       ao_cmd.c \
+       ao_config.c \
+       ao_timer_lpc.c \
+       ao_exti_lpc.c \
+       ao_usb_lpc.c \
+       ao_spi_lpc.c \
+       ao_adc_lpc.c \
+       ao_beep_lpc.c \
+       ao_m25.c \
+       ao_ms5607.c
+
+PRODUCT=EasyMini-v1.0
+PRODUCT_DEF=-DEASYMINI_V_1_0
+IDPRODUCT=0x0026
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+
+PROGNAME=easymini-v1.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_easymini.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+       $(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/easymini-v1.0/ao_easymini.c b/src/easymini-v1.0/ao_easymini.c
new file mode 100644 (file)
index 0000000..97230b6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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_exti_init();
+
+       ao_beep_init();
+
+       ao_adc_init();
+       ao_spi_init();
+       ao_storage_init();
+
+       ao_usb_init();
+
+       ao_cmd_init();
+       ao_flight_init();
+       ao_ms5607_init();
+       ao_log_init();
+       ao_report_init();
+       ao_igniter_init();
+       ao_config_init();
+
+       ao_start_scheduler();
+}
diff --git a/src/easymini-v1.0/ao_pins.h b/src/easymini-v1.0/ao_pins.h
new file mode 100644 (file)
index 0000000..e721030
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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_LED         0
+
+#define AO_STACK_SIZE  384
+
+#define IS_FLASH_LOADER        0
+
+/* Crystal on the board */
+#define AO_LPC_CLKIN   12000000
+
+/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */
+#define AO_LPC_CLKOUT  48000000
+
+/* System clock frequency */
+#define AO_LPC_SYSCLK  24000000
+
+#define HAS_USB                1
+
+#define HAS_USB_CONNECT        0
+#define HAS_USB_VBUS   0
+#define HAS_USB_PULLUP 1
+#define AO_USB_PULLUP_PORT     0
+#define AO_USB_PULLUP_PIN      20
+
+#define PACKET_HAS_SLAVE       0
+
+#define AO_LOG_FORMAT          AO_LOG_FORMAT_EASYMINI
+
+/* USART */
+
+#define HAS_SERIAL             0
+#define USE_SERIAL_0_STDIN     1
+#define SERIAL_0_18_19         1
+#define SERIAL_0_14_15         0
+#define SERIAL_0_17_18         0
+#define SERIAL_0_26_27         0
+
+/* SPI */
+
+#define HAS_SPI_0              1
+#define SPI_SCK0_P0_6          1
+#define HAS_SPI_1              1
+#define SPI_SCK1_P1_15         1
+#define SPI_MISO1_P0_22                1
+#define SPI_MOSI1_P0_21                1
+
+/* M25 */
+
+#define M25_MAX_CHIPS          1
+#define AO_M25_SPI_CS_PORT     0
+#define AO_M25_SPI_CS_MASK     (1 << 23)
+#define AO_M25_SPI_BUS         1
+
+/* MS5607 */
+
+#define HAS_MS5607             1
+#define HAS_MS5611             0
+#define AO_MS5607_PRIVATE_PINS 0
+#define AO_MS5607_CS_PORT      0
+#define AO_MS5607_CS_PIN       7
+#define AO_MS5607_CS_MASK      (1 << AO_MS5607_CS_PIN)
+#define AO_MS5607_MISO_PORT    0
+#define AO_MS5607_MISO_PIN     8
+#define AO_MS5607_MISO_MASK    (1 << AO_MS5607_MISO_PIN)
+#define AO_MS5607_SPI_INDEX    0
+
+#define HAS_ACCEL              0
+#define HAS_GPS                        0
+#define HAS_RADIO              0
+#define HAS_FLIGHT             1
+#define HAS_EEPROM             1
+#define HAS_TELEMETRY          0
+#define HAS_APRS               0
+#define HAS_LOG                        1
+#define USE_INTERNAL_FLASH     0
+#define HAS_IGNITE             1
+#define HAS_IGNITE_REPORT      1
+
+#define AO_DATA_RING           16
+
+/*
+ * ADC
+ */
+
+#define HAS_ADC                        1
+
+#define AO_NUM_ADC             3
+
+#define AO_ADC_0               1
+#define AO_ADC_1               1
+#define AO_ADC_2               1
+
+struct ao_adc {
+       int16_t         sense_a;
+       int16_t         sense_m;
+       int16_t         v_batt;
+};
+
+/*
+ * Igniter
+ */
+
+#define AO_IGNITER_CLOSED      400
+#define AO_IGNITER_OPEN                60
+
+#define AO_IGNITER_DROGUE_PORT 0
+#define AO_IGNITER_DROGUE_PIN  2
+#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   0
+#define AO_IGNITER_MAIN_PIN    3
+#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)
diff --git a/src/easymini-v1.0/flash-loader/Makefile b/src/easymini-v1.0/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..78bb409
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=easymini-v1.0
+include $(TOPDIR)/lpc/Makefile-flash.defs
diff --git a/src/easymini-v1.0/flash-loader/ao_pins.h b/src/easymini-v1.0/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..4330151
--- /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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#include <ao_flash_lpc_pins.h>
+
+#define AO_BOOT_PIN            1
+#define AO_BOOT_APPLICATION_GPIO       0
+#define AO_BOOT_APPLICATION_PIN                19
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+#define HAS_USB_PULLUP 1
+#define AO_USB_PULLUP_PORT     0
+#define AO_USB_PULLUP_PIN      20
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/lpc/Makefile-flash.defs b/src/lpc/Makefile-flash.defs
new file mode 100644 (file)
index 0000000..4a245d1
--- /dev/null
@@ -0,0 +1,61 @@
+include $(TOPDIR)/lpc/Makefile-lpc.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_flash_pins.h \
+       ao_flash_lpc_pins.h \
+       ao_flash_task.h \
+       ao_pins.h \
+       ao_product.h \
+       Makefile
+
+#
+# Common AltOS sources
+#
+SRC = \
+       ao_interrupt.c \
+       ao_romconfig.c \
+       ao_boot_chain.c \
+       ao_boot_pin.c \
+       ao_product.c \
+       ao_notask.c \
+       ao_timer_lpc.c \
+       ao_usb_lpc.c \
+       ao_flash_lpc.c \
+       ao_flash_task.c \
+       ao_flash_loader_lpc.c
+
+OBJ=$(SRC:.c=.o)
+
+PRODUCT=AltosFlash
+PRODUCT_DEF=-DALTOS_FLASH
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos-loader.ld
+
+PROGNAME=altos-flash
+PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
+
+$(PROG): Makefile $(OBJ) altos-loader.ld
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+ao_product.h: ao-make-product.5c $(TOPDIR)/Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+$(OBJ): $(INC)
+
+all: $(PROG)
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(HARDWARE)-$(PROGNAME)-*.elf
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/lpc/Makefile-lpc.defs b/src/lpc/Makefile-lpc.defs
new file mode 100644 (file)
index 0000000..3d55cf6
--- /dev/null
@@ -0,0 +1,45 @@
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/Makedefs
+
+vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/core:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR)
+vpath make-altitude $(TOPDIR)/util
+vpath make-kalman $(TOPDIR)/util
+vpath kalman.5c $(TOPDIR)/kalman
+vpath kalman_filter.5c $(TOPDIR)/kalman
+vpath load_csv.5c $(TOPDIR)/kalman
+vpath matrix.5c $(TOPDIR)/kalman
+vpath ao-make-product.5c $(TOPDIR)/util
+
+.SUFFIXES: .elf .ihx
+
+.elf.ihx:
+       $(ELFTOHEX) --output=$@ $*.elf
+
+
+ifndef VERSION
+include $(TOPDIR)/Version
+endif
+
+ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex
+CC=$(ARM_CC)
+
+AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/core -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) $(PDCLIB_INCLUDES) 
+LPC_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS)
+
+NICKLE=nickle
+
+LIBS=$(PDCLIB_LIBS_M0) -lgcc
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf "  $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+.c.o:
+       $(call quiet,CC) -c $(CFLAGS) -o $@ $<
diff --git a/src/lpc/Makefile.defs b/src/lpc/Makefile.defs
new file mode 100644 (file)
index 0000000..b6d739c
--- /dev/null
@@ -0,0 +1,15 @@
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/lpc/Makefile-lpc.defs
+include $(TOPDIR)/Makedefs
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos.ld
+
+ao_serial_lpc.h: $(TOPDIR)/lpc/baud_rate ao_pins.h
+       nickle $(TOPDIR)/lpc/baud_rate `awk '/AO_LPC_CLKOUT/{print $$3}' ao_pins.h` > $@
+
+ao_serial_lpc.o: ao_serial_lpc.h
+
+.DEFAULT_GOAL=all
diff --git a/src/lpc/altos-loader.ld b/src/lpc/altos-loader.ld
new file mode 100644 (file)
index 0000000..9df6e45
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+MEMORY {
+       rom : ORIGIN = 0x00000000, LENGTH = 4K
+       ram : ORIGIN = 0x10000000, LENGTH = 4k - 128 - 32
+       usb (!x) : ORIGIN = 0x20004000 + 2K - 256, LENGTH = 256
+       stack (!w) : ORIGIN = 0x10000000 + 4K - 128 - 32, LENGTH = 128
+}
+
+INCLUDE registers.ld
+
+EXTERN (lpc_interrupt_vector)
+
+SECTIONS {
+       /*
+        * Rom contents
+        */
+
+       .interrupt : {
+               __text_start__ = .;
+               *(.interrupt)   /* Interrupt vectors */
+
+       } > rom
+
+       .text ORIGIN(rom) + 0x100 : {
+               ao_romconfig.o(.romconfig*)
+               ao_product.o(.romconfig*)
+
+               *(.text*)       /* Executable code */
+               *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+               *(.rodata*)     /* Constants */
+               __text_end__ = .;
+       } > rom
+
+       /* Boot data which must live at the start of ram so that
+        * the application and bootloader share the same addresses.
+        * This must be all uninitialized data
+        */
+       .boot ORIGIN(ram) + SIZEOF(.interrupt) (NOLOAD) : {
+               __boot_start__ = .;
+               *(.boot*)
+               __boot_end__ = .;
+       } >ram
+
+       /* Data -- relocated to RAM, but written to ROM
+        */
+       .data : {
+               __data_start__ = .;
+               *(.data*)       /* initialized data */
+               __data_end__ = .;
+       } >ram AT>rom
+
+
+       .bss : {
+               __bss_start__ = .;
+               *(.bss*)
+               *(COMMON*)
+               __bss_end__ = .;
+       } >ram
+
+       PROVIDE(__stack__ = ORIGIN(ram) + LENGTH(ram));
+       PROVIDE(end = .);
+}
+
+ENTRY(start);
diff --git a/src/lpc/altos-standalone.ld b/src/lpc/altos-standalone.ld
new file mode 100644 (file)
index 0000000..032406f
--- /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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+MEMORY {
+       rom (rx) : ORIGIN = 0x00000000, LENGTH = 32K
+       ram (!w) : ORIGIN = 0x10000000, LENGTH = 4K - 128 - 32
+       usb (!x) : ORIGIN = 0x20004000 + 2K - 256, LENGTH = 256
+       stack (!w) : ORIGIN = 0x10000000 + 4K - 128 - 32, LENGTH = 128
+}
+
+INCLUDE registers.ld
+
+EXTERN (lpc_interrupt_vector)
+
+SECTIONS {
+       /*
+        * Rom contents
+        */
+
+       .text ORIGIN(rom) : {
+               __text_start__ = .;
+               *(.interrupt)   /* Interrupt vectors */
+
+               . = ORIGIN(rom) + 0x100;
+
+               ao_romconfig.o(.romconfig*)
+               ao_product.o(.romconfig*)
+
+               *(.text*)       /* Executable code */
+               *(.rodata*)     /* Constants */
+
+       } > rom
+
+       .ARM.exidx : {
+               *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+               __text_end__ = .;
+       } > rom
+
+       /* Boot data which must live at the start of ram so that
+        * the application and bootloader share the same addresses.
+        * This must be all uninitialized data
+        */
+       .boot (NOLOAD) : {
+               __boot_start__ = .;
+               *(.boot)
+               . = ALIGN(4);
+               __boot_end__ = .;
+       } >ram
+
+       /* Data -- relocated to RAM, but written to ROM
+        */
+       .data ORIGIN(ram) : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) {
+               __data_start__ = .;
+               *(.data)        /* initialized data */
+               __data_end__ = .;
+               __bss_start__ = .;
+       } >ram
+
+       .bss : {
+               *(.bss)
+               *(COMMON)
+               __bss_end__ = .;
+       } >ram
+       PROVIDE(end = .);
+
+       PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+}
+
+ENTRY(start);
+
+
diff --git a/src/lpc/altos.ld b/src/lpc/altos.ld
new file mode 100644 (file)
index 0000000..00d4f18
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+MEMORY {
+       rom (rx) : ORIGIN = 0x00001000, LENGTH = 28K
+       ram (!w) : ORIGIN = 0x10000000, LENGTH = 4K - 128
+       usb (!x) : ORIGIN = 0x20004000 + 2K - 256, LENGTH = 256
+       stack (!w) : ORIGIN = 0x10000000 + 4K - 128, LENGTH = 128
+}
+
+INCLUDE registers.ld
+
+EXTERN (lpc_interrupt_vector)
+
+SECTIONS {
+       /*
+        * Rom contents
+        */
+
+       .interrupt ORIGIN(ram) : AT (ORIGIN(rom)) {
+               __interrupt_start__ = .;
+               __interrupt_rom__ = ORIGIN(rom);
+               *(.interrupt)   /* Interrupt vectors */
+               __interrupt_end__ = .;
+       } > ram
+
+       .text ORIGIN(rom) + 0x100 : {
+               __text_start__ = .;
+
+               ao_romconfig.o(.romconfig*)
+               ao_product.o(.romconfig*)
+
+               *(.text*)       /* Executable code */
+               *(.rodata*)     /* Constants */
+
+       } > rom
+
+       .ARM.exidx : {
+               *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+               __text_end__ = .;
+       } > rom
+
+       /* Boot data which must live at the start of ram so that
+        * the application and bootloader share the same addresses.
+        * This must be all uninitialized data
+        */
+       .boot : {
+               __boot_start__ = .;
+               *(.boot)
+               . = ALIGN(4);
+               __boot_end__ = .;
+       } >ram
+
+       /* Data -- relocated to RAM, but written to ROM
+        */
+       .data : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) {
+               __data_start__ = .;
+               *(.data)        /* initialized data */
+               __data_end__ = .;
+               __bss_start__ = .;
+       } >ram
+
+       .bss : {
+               __bss_start__ = .;
+               *(.bss)
+               *(COMMON)
+               __bss_end__ = .;
+       } >ram
+       PROVIDE(end = .);
+
+       PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+}
+
+ENTRY(start);
+
+
diff --git a/src/lpc/ao_adc_lpc.c b/src/lpc/ao_adc_lpc.c
new file mode 100644 (file)
index 0000000..7005f86
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * 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>
+#include <ao_data.h>
+
+#ifndef AO_ADC_0
+#define AO_ADC_0       0
+#endif
+
+#ifndef AO_ADC_1
+#define AO_ADC_1       0
+#endif
+
+#ifndef AO_ADC_2
+#define AO_ADC_2       0
+#endif
+
+#ifndef AO_ADC_3
+#define AO_ADC_3       0
+#endif
+
+#ifndef AO_ADC_4
+#define AO_ADC_4       0
+#endif
+
+#ifndef AO_ADC_5
+#define AO_ADC_5       0
+#endif
+
+#ifndef AO_ADC_6
+#define AO_ADC_6       0
+#endif
+
+#ifndef AO_ADC_7
+#define AO_ADC_7       0
+#endif
+
+#define AO_ADC_NUM     (AO_ADC_0 + AO_ADC_1 + AO_ADC_2 + AO_ADC_3 + \
+                        AO_ADC_4 + AO_ADC_5 + AO_ADC_6 + AO_ADC_7)
+
+/* ADC clock is divided by this value + 1, which ensures that
+ * the ADC clock will be strictly less than 4.5MHz as required
+ */
+#define AO_ADC_CLKDIV  (AO_LPC_SYSCLK / 450000)
+
+static uint8_t         ao_adc_ready;
+static uint8_t         ao_adc_sequence;
+
+static const uint8_t   ao_adc_mask_seq[AO_ADC_NUM] = {
+#if AO_ADC_0
+       1 << 0,
+#endif
+#if AO_ADC_1
+       1 << 1,
+#endif
+#if AO_ADC_2
+       1 << 2,
+#endif
+#if AO_ADC_3
+       1 << 3,
+#endif
+#if AO_ADC_4
+       1 << 4,
+#endif
+#if AO_ADC_5
+       1 << 6,
+#endif
+#if AO_ADC_6
+       1 << 6,
+#endif
+#if AO_ADC_7
+       1 << 7,
+#endif
+};
+
+#define sample(id)     (*out++ = (uint16_t) lpc_adc.dr[id] >> 1)
+
+static inline void lpc_adc_start(void) {
+       lpc_adc.cr = ((ao_adc_mask_seq[ao_adc_sequence] << LPC_ADC_CR_SEL) |
+                     (AO_ADC_CLKDIV << LPC_ADC_CR_CLKDIV) |
+                     (0 << LPC_ADC_CR_BURST) |
+                     (LPC_ADC_CR_CLKS_11 << LPC_ADC_CR_CLKS) |
+                     (LPC_ADC_CR_START_NOW << LPC_ADC_CR_START));
+}
+
+void  lpc_adc_isr(void)
+{
+       uint16_t        *out;
+
+       /* Store converted value in packet */
+       out = (uint16_t *) &ao_data_ring[ao_data_head].adc;
+       out[ao_adc_sequence] = (uint16_t) lpc_adc.gdr >> 1;
+       if (++ao_adc_sequence < AO_ADC_NUM) {
+               lpc_adc_start();
+               return;
+       }
+
+       AO_DATA_PRESENT(AO_DATA_ADC);
+       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 burst mode
+ */
+void
+ao_adc_poll(void)
+{
+       if (!ao_adc_ready)
+               return;
+       ao_adc_ready = 0;
+       ao_adc_sequence = 0;
+       lpc_adc_start();
+}
+
+static void
+ao_adc_dump(void) __reentrant
+{
+       struct ao_data  packet;
+       int16_t *d;
+       uint8_t i;
+
+       ao_data_get(&packet);
+#ifdef AO_ADC_DUMP
+       AO_ADC_DUMP(&packet);
+#else
+       printf("tick: %5u",  packet.tick);
+       d = (int16_t *) (&packet.adc);
+       for (i = 0; i < AO_NUM_ADC; i++)
+               printf (" %2d: %5d", i, d[i]);
+       printf("\n");
+#endif
+}
+
+__code struct ao_cmds ao_adc_cmds[] = {
+       { ao_adc_dump,  "a\0Display current ADC values" },
+       { 0, NULL },
+};
+
+void
+ao_adc_init(void)
+{
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_ADC);
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_ADC_PD);
+
+       /* Enable interrupt when channel is complete */
+       lpc_adc.inten = (1 << LPC_ADC_INTEN_ADGINTEN);
+
+       lpc_nvic_set_enable(LPC_ISR_ADC_POS);
+       lpc_nvic_set_priority(LPC_ISR_ADC_POS, AO_LPC_NVIC_CLOCK_PRIORITY);
+#if AO_ADC_0
+       ao_enable_analog(0, 11, 0);
+#endif
+#if AO_ADC_1
+       ao_enable_analog(0, 12, 1);
+#endif
+#if AO_ADC_2
+       ao_enable_analog(0, 13, 2);
+#endif
+#if AO_ADC_3
+       ao_enable_analog(0, 14, 3);
+#endif
+#if AO_ADC_4
+       ao_enable_analog(0, 15, 4);
+#endif
+#if AO_ADC_5
+       ao_enable_analog(0, 16, 5);
+#endif
+#if AO_ADC_6
+       ao_enable_analog(0, 22, 6);
+#endif
+#if AO_ADC_7
+       ao_enable_analog(0, 23, 7);
+#endif
+
+       lpc_adc.cr = ((0 << LPC_ADC_CR_SEL) |
+                     (AO_ADC_CLKDIV << LPC_ADC_CR_CLKDIV) |
+                     (0 << LPC_ADC_CR_BURST) |
+                     (LPC_ADC_CR_CLKS_11 << LPC_ADC_CR_CLKS));
+
+       ao_cmd_register(&ao_adc_cmds[0]);
+
+       ao_adc_ready = 1;
+}
diff --git a/src/lpc/ao_arch.h b/src/lpc/ao_arch.h
new file mode 100644 (file)
index 0000000..d04bf2c
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_ARCH_H_
+#define _AO_ARCH_H_
+
+#include <lpc.h>
+
+/*
+ * LPC11U14 definitions and code fragments for AltOS
+ */
+
+#ifndef AO_STACK_SIZE
+#define AO_STACK_SIZE  512
+#endif
+
+#define AO_LED_TYPE    uint16_t
+
+#define AO_PORT_TYPE   uint32_t
+
+#ifndef AO_TICK_TYPE
+#define AO_TICK_TYPE   uint16_t
+#define AO_TICK_SIGNED int16_t
+#endif
+
+/* Various definitions to make GCC look more like SDCC */
+
+#define ao_arch_naked_declare  __attribute__((naked))
+#define ao_arch_naked_define
+#define __pdata
+#define __data
+#define __xdata
+#define __code const
+#define __reentrant
+#define __interrupt(n)
+#define __at(n)
+
+#define ao_arch_reboot() arm_scb.aircr = ((0x05fa << 16) |     \
+                                         (0 << 15) |           \
+                                         (1 << 2) |            \
+                                         (0 << 1))
+
+#define ao_arch_nop()          asm("nop")
+
+#define ao_arch_interrupt(n)   /* nothing */
+
+#undef putchar
+#undef getchar
+#define putchar(c)     ao_putchar(c)
+#define getchar                ao_getchar
+
+extern void putchar(char c);
+extern char getchar(void);
+
+/*
+ * ao_romconfig.c
+ */
+
+#define AO_ROMCONFIG_VERSION   2
+
+#define AO_ROMCONFIG_SYMBOL(a) __attribute__((section(".romconfig"))) const
+
+extern const uint16_t ao_romconfig_version;
+extern const uint16_t ao_romconfig_check;
+extern const uint16_t ao_serial_number;
+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
+ */
+
+#if AO_HSE
+#define AO_PLLSRC      AO_HSE
+#else
+#define AO_PLLSRC      STM_HSI_FREQ
+#endif
+
+#define AO_PLLVCO      (AO_PLLSRC * AO_PLLMUL)
+#define AO_SYSCLK      (AO_PLLVCO / AO_PLLDIV)
+#define AO_HCLK                (AO_SYSCLK / AO_AHB_PRESCALER)
+#define AO_PCLK1       (AO_HCLK / AO_APB1_PRESCALER)
+#define AO_PCLK2       (AO_HCLK / AO_APB2_PRESCALER)
+
+#if AO_APB1_PRESCALER == 1
+#define AO_TIM23467_CLK                AO_PCLK1
+#else
+#define AO_TIM23467_CLK                (2 * AO_PCLK1)
+#endif
+
+#if AO_APB2_PRESCALER == 1
+#define AO_TIM91011_CLK                AO_PCLK2
+#else
+#define AO_TIM91011_CLK                (2 * AO_PCLK2)
+#endif
+
+#define AO_LPC_NVIC_HIGH_PRIORITY      0
+#define AO_LPC_NVIC_CLOCK_PRIORITY     1
+#define AO_LPC_NVIC_MED_PRIORITY       2
+#define AO_LPC_NVIC_LOW_PRIORITY       3
+
+void
+ao_adc_init(void);
+
+#define AO_USB_OUT_EP  2
+#define AO_USB_IN_EP   3
+
+void
+ao_serial_init(void);
+
+/* SPI definitions */
+
+#define AO_SPI_SPEED_12MHz             4
+#define AO_SPI_SPEED_6MHz              8
+#define AO_SPI_SPEED_4MHz              12
+#define AO_SPI_SPEED_2MHz              24
+#define AO_SPI_SPEED_1MHz              48
+#define AO_SPI_SPEED_500kHz            96
+#define AO_SPI_SPEED_250kHz            192
+
+#define AO_SPI_SPEED_FAST      AO_SPI_SPEED_12MHz
+
+#define AO_BOOT_APPLICATION_BASE       ((uint32_t *) 0x00001000)
+#define AO_BOOT_LOADER_BASE            ((uint32_t *) 0x00000000)
+#define HAS_BOOT_LOADER                        1
+
+#endif /* _AO_ARCH_H_ */
diff --git a/src/lpc/ao_arch_funcs.h b/src/lpc/ao_arch_funcs.h
new file mode 100644 (file)
index 0000000..0891903
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_ARCH_FUNCS_H_
+#define _AO_ARCH_FUNCS_H_
+
+#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)
+#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<bit),bus)
+
+#define ao_enable_port(port) (lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO))
+#define ao_disable_port(port) (lpc_scb.sysahbclkctrl &= ~(1 << LPC_SCB_SYSAHBCLKCTRL_GPIO))
+
+#define lpc_all_bit(port,bit)  (((port) << 5) | (bit))
+
+#define ao_gpio_set(port, bit, pin, v) (lpc_gpio.byte[lpc_all_bit(port,bit)] = (v))
+
+#define ao_gpio_get(port, bit, pin)    (lpc_gpio.byte[lpc_all_bit(port,bit)])
+
+#define ao_enable_output(port,bit,pin,v) do {                  \
+               ao_enable_port(port);                           \
+               ao_gpio_set(port, bit, pin, v);                 \
+               lpc_gpio.dir[port] |= (1 << bit);               \
+       } while (0)
+
+#define ao_gpio_set_mode(port,bit,mode) do {                           \
+               vuint32_t *_ioconf = &lpc_ioconf.pio0_0 + ((port)*24+(bit)); \
+               vuint32_t _mode;                                        \
+               if (mode == AO_EXTI_MODE_PULL_UP)                       \
+                       _mode = LPC_IOCONF_MODE_PULL_UP << LPC_IOCONF_MODE; \
+               else if (mode == AO_EXTI_MODE_PULL_DOWN)                \
+                       _mode = LPC_IOCONF_MODE_PULL_UP << LPC_IOCONF_MODE; \
+               else                                                    \
+                       _mode = LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE; \
+               *_ioconf = ((*_ioconf & ~(LPC_IOCONF_MODE_MASK << LPC_IOCONF_MODE)) | \
+                           _mode |                                     \
+                           (1 << LPC_IOCONF_ADMODE));                  \
+       } while (0)
+
+#define ao_enable_input(port,bit,mode) do {                            \
+               ao_enable_port(port);                                   \
+               lpc_gpio.dir[port] &= ~(1 << bit);                      \
+               ao_gpio_set_mode(port,bit,mode);                        \
+       } while (0)
+
+#define lpc_token_paster_2(x,y)                x ## y
+#define lpc_token_evaluator_2(x,y)     lpc_token_paster_2(x,y)
+#define lpc_token_paster_3(x,y,z)      x ## y ## z
+#define lpc_token_evaluator_3(x,y,z)   lpc_token_paster_3(x,y,z)
+#define lpc_token_paster_4(w,x,y,z)    w ## x ## y ## z
+#define lpc_token_evaluator_4(w,x,y,z) lpc_token_paster_4(w,x,y,z)
+#define analog_reg(port,bit)           lpc_token_evaluator_4(pio,port,_,bit)
+#define analog_func(id)                        lpc_token_evaluator_2(LPC_IOCONF_FUNC_AD,id)
+
+#define ao_enable_analog(port,bit,id) do {                             \
+               ao_enable_port(port);                                   \
+               lpc_gpio.dir[port] &= ~(1 << bit);                      \
+               lpc_ioconf.analog_reg(port,bit) = ((analog_func(id) << LPC_IOCONF_FUNC) | \
+                                                  (0 << LPC_IOCONF_ADMODE)); \
+       } while (0)
+       
+#define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
+
+static inline uint32_t
+ao_arch_irqsave(void) {
+       uint32_t        primask;
+       asm("mrs %0,primask" : "=&r" (primask));
+       ao_arch_block_interrupts();
+       return primask;
+}
+
+static inline void
+ao_arch_irqrestore(uint32_t primask) {
+       asm("msr primask,%0" : : "r" (primask));
+}
+
+static inline void
+ao_arch_memory_barrier() {
+       asm volatile("" ::: "memory");
+}
+
+#if HAS_TASK
+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        a = (uint32_t) start;
+       int             i;
+
+       /* Return address (goes into LR) */
+       ARM_PUSH32(sp, a);
+
+       /* Clear register values r0-r7 */
+       i = 8;
+       while (i--)
+               ARM_PUSH32(sp, 0);
+
+       /* APSR */
+       ARM_PUSH32(sp, 0);
+
+       /* PRIMASK with interrupts enabled */
+       ARM_PUSH32(sp, 0);
+
+       task->sp = sp;
+}
+
+static inline void ao_arch_save_regs(void) {
+       /* Save general registers */
+       asm("push {r0-r7,lr}\n");
+
+       /* Save APSR */
+       asm("mrs r0,apsr");
+       asm("push {r0}");
+
+       /* Save PRIMASK */
+       asm("mrs r0,primask");
+       asm("push {r0}");
+}
+
+static inline void ao_arch_save_stack(void) {
+       uint32_t        *sp;
+       asm("mov %0,sp" : "=&r" (sp) );
+       ao_cur_task->sp = (sp);
+       if ((uint8_t *) sp < &ao_cur_task->stack[0])
+               ao_panic (AO_PANIC_STACK);
+}
+
+static inline void ao_arch_restore_stack(void) {
+       uint32_t        sp;
+       sp = (uint32_t) ao_cur_task->sp;
+
+       /* Switch stacks */
+       asm("mov sp, %0" : : "r" (sp) );
+
+       /* Restore PRIMASK */
+       asm("pop {r0}");
+       asm("msr primask,r0");
+
+       /* Restore APSR */
+       asm("pop {r0}");
+       asm("msr apsr_nczvq,r0");
+
+       /* Restore general registers and return */
+       asm("pop {r0-r7,pc}\n");
+}
+
+#define ao_arch_isr_stack()
+
+#endif /* HAS_TASK */
+
+#define ao_arch_wait_interrupt() do {                  \
+               asm(".global ao_idle_loc\n\twfi\nao_idle_loc:");        \
+               ao_arch_release_interrupts();                           \
+               ao_arch_block_interrupts();                             \
+       } while (0)
+
+#define ao_arch_critical(b) do {                               \
+               ao_arch_block_interrupts();                     \
+               do { b } while (0);                             \
+               ao_arch_release_interrupts();                   \
+       } while (0)
+
+/*
+ * SPI
+ */
+
+#define ao_spi_set_cs(port,mask) (lpc_gpio.clr[port] = (mask))
+#define ao_spi_clr_cs(port,mask) (lpc_gpio.set[port] = (mask))
+
+#define ao_spi_get_mask(port,mask,bus,speed) do {      \
+               ao_spi_get(bus, speed);                 \
+               ao_spi_set_cs(port, mask);              \
+       } while (0)
+
+#define ao_spi_put_mask(reg,mask,bus) do {     \
+               ao_spi_clr_cs(reg,mask);        \
+               ao_spi_put(bus);                \
+       } while (0)
+
+#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)
+#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<bit),bus)
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed);
+
+void
+ao_spi_put(uint8_t spi_index);
+
+void
+ao_spi_send(void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index);
+
+extern uint16_t        ao_spi_speed[LPC_NUM_SPI];
+
+void
+ao_spi_init(void);
+
+#define ao_spi_init_cs(port, mask) do {                                        \
+               uint8_t __bit__;                                        \
+               for (__bit__ = 0; __bit__ < 32; __bit__++) {            \
+                       if (mask & (1 << __bit__))                      \
+                               ao_enable_output(port, __bit__, PIN, 1); \
+               }                                                       \
+       } while (0)
+
+#define HAS_ARCH_START_SCHEDULER       1
+
+static inline void ao_arch_start_scheduler(void) {
+       uint32_t        sp;
+       uint32_t        control;
+
+       asm("mrs %0,msp" : "=&r" (sp));
+       asm("msr psp,%0" : : "r" (sp));
+       asm("mrs %0,control" : "=&r" (control));
+       control |= (1 << 1);
+       asm("msr control,%0" : : "r" (control));
+       asm("isb");
+}
+
+#endif /* _AO_ARCH_FUNCS_H_ */
diff --git a/src/lpc/ao_beep_lpc.c b/src/lpc/ao_beep_lpc.c
new file mode 100644 (file)
index 0000000..eb9132b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+
+void
+ao_beep(uint8_t beep)
+{
+       if (beep == 0) {
+               lpc_ct32b1.tcr = ((0 << LPC_CT32B_TCR_CEN) |
+                                 (1 << LPC_CT32B_TCR_CRST));
+               lpc_scb.sysahbclkctrl &= ~(1 << LPC_SCB_SYSAHBCLKCTRL_CT32B1);
+       } else {
+               lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_CT32B1);
+
+               /* Set prescaler to match cc1111 clocks
+                */
+               lpc_ct32b1.pr = AO_LPC_SYSCLK / 750000 - 1;
+
+               /* Write the desired data in the match registers */
+
+               /* Reset after two time units */
+               lpc_ct32b1.mr[0] = beep << 1;
+
+               /* PWM width is half of that */
+               lpc_ct32b1.mr[1] = beep;
+
+               /* Flip output 1 on PWM match */
+               lpc_ct32b1.emr = (LPC_CT32B_EMR_EMC_TOGGLE << LPC_CT32B_EMR_EMC1);
+
+               /* Reset on match 0 */
+               lpc_ct32b1.mcr = (1 << LPC_CT32B_MCR_MR0R);
+
+               /* PWM on match 1 */
+               lpc_ct32b1.pwmc = (1 << LPC_CT32B_PWMC_PWMEN1);
+               
+               /* timer mode */
+               lpc_ct32b1.ctcr = 0;
+
+               /* And turn the timer on */
+               lpc_ct32b1.tcr = ((1 << LPC_CT32B_TCR_CEN) |
+                                 (0 << LPC_CT32B_TCR_CRST));
+       }
+}
+
+void
+ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant
+{
+       ao_beep(beep);
+       ao_delay(ticks);
+       ao_beep(0);
+}
+
+void
+ao_beep_init(void)
+{
+       /* Our beeper is on c32b1_mat1
+        * which is on pin pio0_14
+        */
+
+       lpc_ioconf.pio0_14 = ((LPC_IOCONF_FUNC_PIO0_14_CT32B1_MAT1 << LPC_IOCONF_FUNC) |
+                             (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+                             (0 << LPC_IOCONF_HYS) |
+                             (0 << LPC_IOCONF_INV) |
+                             (1 << LPC_IOCONF_ADMODE) |
+                             (0 << LPC_IOCONF_OD));
+
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_CT32B1);
+
+       /* Disable the counter and reset the value */
+       lpc_ct32b1.tcr = ((0 << LPC_CT32B_TCR_CEN) |
+                         (1 << LPC_CT32B_TCR_CRST));
+}
diff --git a/src/lpc/ao_boot.h b/src/lpc/ao_boot.h
new file mode 100644 (file)
index 0000000..e0ed4de
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_BOOT_H_
+#define _AO_BOOT_H_
+
+void
+ao_boot_chain(uint32_t *base);
+
+void
+ao_boot_check_pin(void);
+
+/* Return true to switch to application (if present) */
+int
+ao_boot_check_chain(void);
+
+void
+ao_boot_reboot(uint32_t *base);
+
+static inline void
+ao_boot_loader(void) {
+       ao_boot_reboot(AO_BOOT_LOADER_BASE);
+}
+
+#endif /* _AO_BOOT_H_ */
diff --git a/src/lpc/ao_boot_chain.c b/src/lpc/ao_boot_chain.c
new file mode 100644 (file)
index 0000000..a08d1f2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_boot.h>
+
+void
+ao_boot_chain(uint32_t *base)
+{
+       uint32_t        sp;
+       uint32_t        pc;
+
+       sp = base[0];
+       pc = base[1];
+       if (0x00000100 <= pc && pc <= 0x00008000 && (pc & 1) == 1) {
+               asm ("mov sp, %0" : : "r" (sp));
+               asm ("mov lr, %0" : : "r" (pc));
+               asm ("bx lr");
+       }
+}
+
+#define AO_BOOT_SIGNAL 0x5a5aa5a5
+#define AO_BOOT_CHECK  0xc3c33c3c
+
+struct ao_boot {
+       uint32_t        *base;
+       uint32_t        signal;
+       uint32_t        check;
+};
+
+static struct ao_boot __attribute__ ((section(".boot"))) ao_boot;
+       
+int
+ao_boot_check_chain(void)
+{
+       if (ao_boot.signal == AO_BOOT_SIGNAL && ao_boot.check == AO_BOOT_CHECK) {
+               ao_boot.signal = 0;
+               ao_boot.check = 0;
+               if (ao_boot.base == 0)
+                       return 0;
+               ao_boot_chain(ao_boot.base);
+       }
+       return 1;
+}
+
+void
+ao_boot_reboot(uint32_t *base)
+{
+       ao_boot.base = base;
+       ao_boot.signal = AO_BOOT_SIGNAL;
+       ao_boot.check = AO_BOOT_CHECK;
+       ao_arch_reboot();
+}
diff --git a/src/lpc/ao_boot_pin.c b/src/lpc/ao_boot_pin.c
new file mode 100644 (file)
index 0000000..51ecc0a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_boot.h>
+#include <ao_exti.h>
+
+void
+ao_boot_check_pin(void)
+{
+       uint16_t v;
+
+       /* Enable power interface clock */
+//     stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
+       
+       /* Enable the input pin */
+       ao_enable_input(AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN,
+                       AO_BOOT_APPLICATION_MODE);
+
+       for (v = 0; v < 100; v++)
+               ao_arch_nop();
+
+       /* Read the value */
+       v = ao_gpio_get(AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, AO_BOOT_APPLICATION);
+
+       /* Reset the chip to turn off the port and the power interface clock */
+       ao_gpio_set_mode(AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, 0);
+       ao_disable_port(AO_BOOT_APPLICATION_GPIO);
+//     stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_PWREN);
+       if (v == AO_BOOT_APPLICATION_VALUE)
+               ao_boot_chain(AO_BOOT_APPLICATION_BASE);
+}
diff --git a/src/lpc/ao_exti.h b/src/lpc/ao_exti.h
new file mode 100644 (file)
index 0000000..e8599eb
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_EXTI_H_
+#define _AO_EXTI_H_
+
+#define AO_EXTI_MODE_RISING    1
+#define AO_EXTI_MODE_FALLING   2
+#define AO_EXTI_MODE_PULL_UP   4
+#define AO_EXTI_MODE_PULL_DOWN 8
+#define AO_EXTI_PRIORITY_LOW   16
+#define AO_EXTI_PRIORITY_MED   0
+#define AO_EXTI_PRIORITY_HIGH  32
+#define AO_EXTI_PIN_NOCONFIGURE        64
+
+void
+ao_exti_setup(uint8_t gpio, uint8_t pin, uint8_t mode, void (*callback)());
+
+void
+ao_exti_set_mode(uint8_t gpio, uint8_t pin, uint8_t mode);
+
+void
+ao_exti_set_callback(uint8_t gpio, uint8_t pin, void (*callback)());
+
+void
+ao_exti_enable(uint8_t gpio, uint8_t pin);
+
+void
+ao_exti_disable(uint8_t gpio, uint8_t pin);
+
+void
+ao_exti_init(void);
+
+#endif /* _AO_EXTI_H_ */
diff --git a/src/lpc/ao_exti_lpc.c b/src/lpc/ao_exti_lpc.c
new file mode 100644 (file)
index 0000000..588cf58
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * 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>
+#include <ao_exti.h>
+
+#define LPC_NUM_PINS   56
+#define LPC_NUM_PINT   8
+
+static void    (*ao_exti_callback[LPC_NUM_PINT])(void);
+
+static uint8_t ao_pint_map[LPC_NUM_PINS];
+static uint8_t ao_pint_mode[LPC_NUM_PINS];
+static uint8_t ao_pint_inuse;
+static uint8_t ao_pint_enabled;
+
+static void
+ao_exti_isr(uint8_t pint)
+{
+       uint8_t mask = 1 << pint;
+
+       if (lpc_gpio_pin.ist & mask) {
+               lpc_gpio_pin.ist = mask;
+               lpc_gpio_pin.rise = mask;
+               lpc_gpio_pin.fall = mask;
+
+               (*ao_exti_callback[pint]) ();
+       }
+}
+
+#define pin_isr(n)     void lpc_pin_int ## n ## _isr(void) { ao_exti_isr(n); }
+pin_isr(0)
+pin_isr(1)
+pin_isr(2)
+pin_isr(3)
+pin_isr(4)
+pin_isr(5)
+pin_isr(6)
+pin_isr(7)
+
+#define pin_id(port,pin)       ((port) * 24 + (pin));
+
+static void
+_ao_exti_set_enable(uint8_t pint)
+{
+       uint8_t         mask = 1 << pint;
+       uint8_t         mode;
+
+       if (ao_pint_enabled & mask)
+               mode = ao_pint_mode[pint];
+       else
+               mode = 0;
+
+       if (mode & AO_EXTI_MODE_RISING)
+               lpc_gpio_pin.sienr = mask;
+       else
+               lpc_gpio_pin.cienr = mask;
+               
+       if (mode & AO_EXTI_MODE_FALLING)
+               lpc_gpio_pin.sienf = mask;
+       else
+               lpc_gpio_pin.cienf = mask;
+       lpc_gpio_pin.rise = mask;
+       lpc_gpio_pin.fall = mask;
+}
+
+void
+ao_exti_setup (uint8_t port, uint8_t pin, uint8_t mode, void (*callback)(void)) {
+       uint8_t         id = pin_id(port,pin);
+       uint8_t         pint;
+       uint32_t        mask;
+       uint8_t         prio;
+
+       for (pint = 0; pint < LPC_NUM_PINT; pint++)
+               if ((ao_pint_inuse & (1 << pint)) == 0)
+                       break;
+       if (pint == LPC_NUM_PINT)
+               ao_panic(AO_PANIC_EXTI);
+
+       if (!mode & AO_EXTI_PIN_NOCONFIGURE)
+               ao_enable_input(port, pin, mode);
+
+       ao_arch_block_interrupts();
+       mask = (1 << pint);
+       ao_pint_inuse |= mask;
+       ao_pint_enabled &= ~mask;
+       
+       ao_pint_map[id] = pint;
+       ao_exti_callback[pint] = callback;
+
+       /* configure gpio to interrupt routing */
+       lpc_scb.pintsel[pint] = id;
+
+       /* Set edge triggered */
+       lpc_gpio_pin.isel &= ~mask;
+
+       ao_pint_enabled &= ~mask;
+       ao_pint_mode[pint] = mode;
+       _ao_exti_set_enable(pint);
+
+       /* Set interrupt mask and rising/falling mode */
+
+       prio = AO_LPC_NVIC_MED_PRIORITY;
+       if (mode & AO_EXTI_PRIORITY_LOW)
+               prio = AO_LPC_NVIC_LOW_PRIORITY;
+       else if (mode & AO_EXTI_PRIORITY_HIGH)
+               prio = AO_LPC_NVIC_HIGH_PRIORITY;
+
+       /* Set priority and enable */
+       lpc_nvic_set_priority(LPC_ISR_PIN_INT0_POS + pint, prio);
+       lpc_nvic_set_enable(LPC_ISR_PIN_INT0_POS + pint);
+       ao_arch_release_interrupts();
+}
+
+void
+ao_exti_set_mode(uint8_t port, uint8_t pin, uint8_t mode)
+{
+       uint8_t         id = pin_id(port,pin);
+       uint8_t         pint = ao_pint_map[id];
+
+       ao_arch_block_interrupts();
+       ao_pint_mode[pint] = mode;
+       _ao_exti_set_enable(pint);
+       ao_arch_release_interrupts();
+}
+
+void
+ao_exti_set_callback(uint8_t port, uint8_t pin, void (*callback)()) {
+       uint8_t         id = pin_id(port,pin);
+       uint8_t         pint = ao_pint_map[id];
+
+       ao_exti_callback[pint] = callback;
+}
+
+void
+ao_exti_enable(uint8_t port, uint8_t pin)
+{
+       uint8_t         id = pin_id(port,pin);
+       uint8_t         pint = ao_pint_map[id];
+       uint8_t         mask = 1 << pint;
+
+       ao_arch_block_interrupts();
+       ao_pint_enabled |= mask;
+       _ao_exti_set_enable(pint);
+       ao_arch_release_interrupts();
+}
+
+void
+ao_exti_disable(uint8_t port, uint8_t pin) {
+       uint8_t         id = pin_id(port,pin);
+       uint8_t         pint = ao_pint_map[id];
+       uint8_t         mask = 1 << pint;
+
+       ao_arch_block_interrupts();
+       ao_pint_enabled &= ~mask;
+       _ao_exti_set_enable(pint);
+       ao_arch_release_interrupts();
+}
+
+void
+ao_exti_init(void)
+{
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_PINT);
+}
diff --git a/src/lpc/ao_flash.h b/src/lpc/ao_flash.h
new file mode 100644 (file)
index 0000000..aaf66b3
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_FLASH_H_
+#define _AO_FLASH_H_
+
+uint32_t
+ao_flash_erase_page(uint8_t *page);
+
+uint32_t
+ao_flash_page(uint8_t *page, uint8_t *src);
+
+uint32_t
+ao_lpc_read_part_id(void);
+
+#endif /* _AO_FLASH_H_ */
diff --git a/src/lpc/ao_flash_loader_lpc.c b/src/lpc/ao_flash_loader_lpc.c
new file mode 100644 (file)
index 0000000..2ab548c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "ao.h"
+#include <ao_exti.h>
+#include <ao_boot.h>
+#include <ao_flash_task.h>
+
+int
+main(void)
+{
+       ao_clock_init();
+
+       ao_usb_init();
+
+       ao_flash_task();
+       return 0;
+}
diff --git a/src/lpc/ao_flash_lpc.c b/src/lpc/ao_flash_lpc.c
new file mode 100644 (file)
index 0000000..5a31f39
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_flash.h>
+
+#define IAP_LOCATION 0x1fff1ff1
+
+typedef void (*iap_func)(uint32_t *in, uint32_t *out);
+
+static void
+iap(uint32_t *in, uint32_t *out)
+{
+       ao_arch_block_interrupts();
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_FLASHREG);
+       ((iap_func) IAP_LOCATION)(in, out);
+       ao_arch_release_interrupts();
+}
+
+#define LPC_IAP_PREPARE_WRITE          50
+#define LPC_IAP_COPY_RAM_TO_FLASH      51
+#define LPC_IAP_ERASE_SECTOR           52
+#define LPC_IAP_BLANK_CHECK            53
+#define LPC_IAP_READ_PART_ID           54
+#define LPC_IAP_READ_BOOT_CODE_VERSION 55
+#define LPC_IAP_COMPARE                        56
+#define LPC_IAP_REINVOKE_ISP           57
+#define LPC_IAP_READ_UID               58
+#define LPC_IAP_ERASE_PAGE             59
+#define LPC_IAP_EEPROM_WRITE           61
+#define LPC_IAP_EEPROM_READ            62
+
+#define LPC_IAP_CMD_SUCCESS            0
+#define LPC_IAP_INVALID_COMMAND                1
+#define LPC_IAP_SRC_ADDR_ERROR         2
+#define LPC_IAP_DST_ADDR_ERROR         3
+#define LPC_IAP_SRC_ADDR_NOT_MAPPED    4
+#define LPC_IAP_DST_ADDR_NOT_MAPPED    5
+#define LPC_IAP_COUNT_ERROR            6
+#define LPC_IAP_INVALID_SECTOR         7
+#define LPC_IAP_SECTOR_NOT_BLANK       8
+#define LPC_IAP_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION        9
+#define LPC_IAP_COMPARE_ERROR          10
+#define LPC_IAP_BUSY                   11
+#define LPC_IAP_PARAM_ERROR            12
+#define LPC_IAP_ADDR_ERROR             13
+#define LPC_IAP_ADDR_NOT_MAPPED                14
+#define LPC_IAP_CMD_LOCKED             15
+#define LPC_IAP_INVALID_CODE           16
+#define LPC_IAP_INVALID_BAUD_RATE      17
+#define LPC_IAP_INVALID_STOP_BIT       18
+#define LPC_IAP_CODE_READ_PROTECTION_ENABLED   19
+
+#define LPC_FLASH_BASE                 ((uint8_t *) 0x0)
+#define LPC_FLASH_SECTOR               4096
+#define LPC_FLASH_SECTOR_MASK          (LPC_FLASH_SECTOR - 1)
+#define LPC_FLASH_SECTOR_SHIFT         12
+
+static uint32_t        iap_in[5], iap_out[5];
+
+static uint32_t
+ao_lpc_addr_to_sector(uint8_t *addr)
+{
+       uint32_t        off = addr - LPC_FLASH_BASE;
+
+       return off >> LPC_FLASH_SECTOR_SHIFT;
+}
+
+static uint8_t
+ao_lpc_addr_is_sector_aligned(uint8_t *addr)
+{
+       uint32_t        off = addr - LPC_FLASH_BASE;
+       return          (off & LPC_FLASH_SECTOR_MASK) == 0;
+}
+
+static uint32_t
+ao_lpc_prepare_write(uint32_t start_sector, uint32_t end_sector)
+{
+       iap_in[0] = LPC_IAP_PREPARE_WRITE;
+       iap_in[1] = start_sector;
+       iap_in[2] = end_sector;
+       iap(iap_in,iap_out);
+       return iap_out[0];
+}
+
+static uint32_t
+ao_lpc_copy_ram_to_flash(uint8_t *dst, uint8_t *src, uint32_t len, uint32_t freq)
+{
+       iap_in[0] = LPC_IAP_COPY_RAM_TO_FLASH;
+       iap_in[1] = (uint32_t) dst;
+       iap_in[2] = (uint32_t) src;
+       iap_in[3] = len;
+       iap_in[4] = freq;
+       iap(iap_in,iap_out);
+       return iap_out[0];
+}
+
+static uint32_t
+ao_lpc_erase_sector(uint32_t start_sector, uint32_t end_sector, uint32_t freq)
+{
+       iap_in[0] = LPC_IAP_ERASE_SECTOR;
+       iap_in[1] = start_sector;
+       iap_in[2] = end_sector;
+       iap_in[3] = freq;
+       iap(iap_in,iap_out);
+       return iap_out[0];
+}
+
+uint32_t
+ao_lpc_read_part_id(void)
+{
+       iap_in[0] = LPC_IAP_READ_PART_ID;
+       iap(iap_in,iap_out);
+       return iap_out[1];
+}
+
+uint32_t
+ao_flash_erase_page(uint8_t *page)
+{
+       uint32_t        ret = LPC_IAP_CMD_SUCCESS;
+       if (ao_lpc_addr_is_sector_aligned(page)) {
+               uint32_t        sector = ao_lpc_addr_to_sector(page);
+               ret = ao_lpc_prepare_write(sector, sector);
+               if (ret == LPC_IAP_CMD_SUCCESS)
+                       ret = ao_lpc_erase_sector(sector, sector, AO_LPC_SYSCLK / 1000);
+       }
+       return ret;
+}
+
+uint32_t
+ao_flash_page(uint8_t *page, uint8_t *src)
+{
+       uint32_t        sector = ao_lpc_addr_to_sector(page);
+       uint32_t        ret;
+
+       ret = ao_flash_erase_page(page);
+       if (ret != LPC_IAP_CMD_SUCCESS)
+               return ret;
+       ret = ao_lpc_prepare_write(sector, sector);
+       if (ret != LPC_IAP_CMD_SUCCESS)
+               return ret;
+       ret = ao_lpc_copy_ram_to_flash(page, src, 256, AO_LPC_SYSCLK / 1000);
+       return ret;
+}
diff --git a/src/lpc/ao_flash_lpc_pins.h b/src/lpc/ao_flash_lpc_pins.h
new file mode 100644 (file)
index 0000000..e2243d5
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_FLASH_LPC_PINS_H_
+#define _AO_FLASH_LPC_PINS_H_
+
+#include <ao_flash_pins.h>
+
+/* Crystal on the board */
+#define AO_LPC_CLKIN   12000000
+
+/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */
+#define AO_LPC_CLKOUT  48000000
+
+/* System clock frequency */
+#define AO_LPC_SYSCLK  24000000
+
+#endif /* _AO_FLASH_STM_PINS_H_ */
diff --git a/src/lpc/ao_interrupt.c b/src/lpc/ao_interrupt.c
new file mode 100644 (file)
index 0000000..c4dc786
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <string.h>
+#include <ao_boot.h>
+
+#ifndef IS_FLASH_LOADER
+#error Should define IS_FLASH_LOADER
+#define IS_FLASH_LOADER        0
+#endif
+
+#if !IS_FLASH_LOADER
+#define RELOCATE_INTERRUPT     1
+#endif
+
+extern void main(void);
+extern char __stack__;
+extern char __text_start__, __text_end__;
+extern char __data_start__, __data_end__;
+extern char __bss_start__, __bss_end__;
+#if RELOCATE_INTERRUPT
+extern char __interrupt_rom__, __interrupt_start__, __interrupt_end__;
+#endif
+
+/* Interrupt functions */
+
+void lpc_halt_isr(void)
+{
+       ao_panic(AO_PANIC_CRASH);
+}
+
+void lpc_ignore_isr(void)
+{
+}
+
+void start(void) {
+#ifdef AO_BOOT_CHAIN
+       if (ao_boot_check_chain()) {
+#ifdef AO_BOOT_PIN
+               ao_boot_check_pin();
+#endif
+       }
+#endif
+#if RELOCATE_INTERRUPT
+       memcpy(&__interrupt_start__, &__interrupt_rom__, &__interrupt_end__ - &__interrupt_start__);
+       lpc_scb.sysmemremap = LPC_SCB_SYSMEMREMAP_MAP_RAM << LPC_SCB_SYSMEMREMAP_MAP;
+#endif
+       memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__);
+       memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__);
+       main();
+}
+
+#define STRINGIFY(x) #x
+
+#define isr(name) \
+       void __attribute__ ((weak)) lpc_ ## name ## _isr(void); \
+       _Pragma(STRINGIFY(weak lpc_ ## name ## _isr = lpc_ignore_isr))
+
+#define isr_halt(name) \
+       void __attribute__ ((weak)) lpc_ ## name ## _isr(void); \
+       _Pragma(STRINGIFY(weak lpc_ ## name ## _isr = lpc_halt_isr))
+
+isr(nmi)
+isr_halt(hardfault)
+isr_halt(memmanage)
+isr_halt(busfault)
+isr_halt(usagefault)
+isr(svc)
+isr(debugmon)
+isr(pendsv)
+isr(systick)
+
+isr(pin_int0)  /* IRQ0 */
+isr(pin_int1)
+isr(pin_int2)
+isr(pin_int3)
+isr(pin_int4)  /* IRQ4 */
+isr(pin_int5)
+isr(pin_int6)
+isr(pin_int7)
+
+isr(gint0)     /* IRQ8 */
+isr(gint1)
+isr(ssp1)
+isr(i2c)
+
+isr(ct16b0)    /* IRQ16 */
+isr(ct16b1)
+isr(ct32b0)
+isr(ct32b1)
+isr(ssp0)      /* IRQ20 */
+isr(usart)
+isr(usb_irq)
+isr(usb_fiq)
+
+isr(adc)       /* IRQ24 */
+isr(wwdt)
+isr(bod)
+isr(flash)
+
+isr(usb_wakeup)
+
+#define i(addr,name)   [(addr)/4] = lpc_ ## name ## _isr
+#define c(addr,value)  [(addr)/4] = (value)
+
+__attribute__ ((section(".interrupt")))
+const void *lpc_interrupt_vector[] = {
+       [0] = &__stack__,
+       [1] = start,
+       i(0x08, nmi),
+       i(0x0c, hardfault),
+       c(0x10, 0),
+       c(0x14, 0),
+       c(0x18, 0),
+       c(0x1c, 0),
+       c(0x20, 0),
+       c(0x24, 0),
+       c(0x28, 0),
+       i(0x2c, svc),
+       i(0x30, hardfault),
+       i(0x34, hardfault),
+       i(0x38, pendsv),
+       i(0x3c, systick),
+
+       i(0x40, pin_int0),      /* IRQ0 */
+       i(0x44, pin_int1),
+       i(0x48, pin_int2),
+       i(0x4c, pin_int3),
+       i(0x50, pin_int4),      /* IRQ4 */
+       i(0x54, pin_int5),
+       i(0x58, pin_int6),
+       i(0x5c, pin_int7),
+
+       i(0x60, gint0),         /* IRQ8 */
+       i(0x64, gint1),
+       i(0x68, hardfault),
+       i(0x6c, hardfault),
+       i(0x70, hardfault),     /* IRQ12 */
+       i(0x74, hardfault),
+       i(0x78, ssp1),
+       i(0x7c, i2c),
+
+       i(0x80, ct16b0),        /* IRQ16 */
+       i(0x84, ct16b1),
+       i(0x88, ct32b0),
+       i(0x8c, ct32b1),
+       i(0x90, ssp0),          /* IRQ20 */
+       i(0x94, usart),
+       i(0x98, usb_irq),
+       i(0x9c, usb_fiq),
+
+       i(0xa0, adc),           /* IRQ24 */
+       i(0xa4, wwdt),
+       i(0xa8, bod),
+       i(0xac, flash),
+
+       i(0xb0, hardfault),     /* IRQ28 */
+       i(0xb4, hardfault),
+       i(0xb8, usb_wakeup),
+       i(0xbc, hardfault),     
+};
diff --git a/src/lpc/ao_led_lpc.c b/src/lpc/ao_led_lpc.c
new file mode 100644 (file)
index 0000000..7bef51b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+__pdata uint16_t ao_led_enable;
+
+void
+ao_led_on(uint16_t colors)
+{
+       lpc_gpio.pin[LED_PORT] |= colors;
+}
+
+void
+ao_led_off(uint16_t colors)
+{
+       lpc_gpio.pin[LED_PORT] &= ~colors;
+}
+
+void
+ao_led_set(uint16_t colors)
+{
+       uint16_t        on = colors & ao_led_enable;
+       uint16_t        off = ~colors & ao_led_enable;
+
+       ao_led_off(off);
+       ao_led_on(on);
+}
+
+void
+ao_led_toggle(uint16_t colors)
+{
+       lpc_gpio.pin[LED_PORT] ^= colors;
+}
+
+void
+ao_led_for(uint16_t colors, uint16_t ticks) __reentrant
+{
+       ao_led_on(colors);
+       ao_delay(ticks);
+       ao_led_off(colors);
+}
+
+void
+ao_led_init(uint16_t enable)
+{
+       int     bit;
+
+       ao_led_enable = enable;
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO);
+       lpc_gpio.dir[LED_PORT] |= enable;
+}
diff --git a/src/lpc/ao_romconfig.c b/src/lpc/ao_romconfig.c
new file mode 100644 (file)
index 0000000..cbb922e
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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"
+
+AO_ROMCONFIG_SYMBOL (0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION;
+AO_ROMCONFIG_SYMBOL (0) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION;
+AO_ROMCONFIG_SYMBOL (0) uint16_t ao_serial_number = 0;
+#ifdef AO_RADIO_CAL_DEFAULT
+AO_ROMCONFIG_SYMBOL (0) uint32_t ao_radio_cal = AO_RADIO_CAL_DEFAULT;
+#endif
diff --git a/src/lpc/ao_serial_lpc.c b/src/lpc/ao_serial_lpc.c
new file mode 100644 (file)
index 0000000..431ae98
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_serial.h>
+
+struct ao_fifo ao_usart_rx_fifo;
+struct ao_fifo ao_usart_tx_fifo;
+uint8_t                ao_usart_tx_avail;
+uint8_t                ao_usart_tx_avail_min;
+
+#define LPC_USART_TX_FIFO_SIZE 16
+
+void
+ao_debug_out(char c)
+{
+       if (c == '\n')
+               ao_debug_out('\r');
+       while (!(lpc_usart.lsr & (1 << LPC_USART_LSR_TEMT)))
+               ;
+       lpc_usart.rbr_thr = c;
+}
+
+static void
+_ao_serial_tx_start(void)
+{
+       if (!ao_fifo_empty(ao_usart_tx_fifo) && ao_usart_tx_avail) {
+               ao_usart_tx_avail--;
+               if (ao_usart_tx_avail < ao_usart_tx_avail_min)
+                       ao_usart_tx_avail_min = ao_usart_tx_avail;
+               ao_fifo_remove(ao_usart_tx_fifo, lpc_usart.rbr_thr);
+       }
+}
+
+void
+lpc_usart_isr(void)
+{
+       uint8_t wake_input = 0;
+       (void) lpc_usart.iir_fcr;
+
+       while (lpc_usart.lsr & (1 << LPC_USART_LSR_RDR)) {
+               char c = lpc_usart.rbr_thr;
+               if (!ao_fifo_full(ao_usart_rx_fifo))
+                       ao_fifo_insert(ao_usart_rx_fifo, c);
+               wake_input = 1;
+       }
+       if (lpc_usart.lsr & (1 << LPC_USART_LSR_THRE)) {
+               ao_usart_tx_avail = LPC_USART_TX_FIFO_SIZE;
+               _ao_serial_tx_start();
+               ao_wakeup(&ao_usart_tx_fifo);
+       }
+       if (wake_input) {
+               ao_wakeup(&ao_usart_rx_fifo);
+               if (stdin)
+                       ao_wakeup(&ao_stdin_ready);
+       }
+}
+
+int
+_ao_serial0_pollchar(void)
+{
+       int     c;
+       
+       if (ao_fifo_empty(ao_usart_rx_fifo))
+               c = AO_READ_AGAIN;
+       else {
+               uint8_t u;
+               ao_fifo_remove(ao_usart_rx_fifo,u);
+               c = u;
+       }
+       return c;
+}
+
+char
+ao_serial0_getchar(void)
+{
+       int c;
+       ao_arch_block_interrupts();
+       while ((c = _ao_serial0_pollchar()) == AO_READ_AGAIN)
+               ao_sleep(&ao_usart_rx_fifo);
+       ao_arch_release_interrupts();
+       return (char) c;
+}
+
+void
+ao_serial0_putchar(char c)
+{
+       ao_arch_block_interrupts();
+       while (ao_fifo_full(ao_usart_tx_fifo))
+               ao_sleep(&ao_usart_tx_fifo);
+       ao_fifo_insert(ao_usart_tx_fifo, c);
+       _ao_serial_tx_start();
+       ao_arch_release_interrupts();
+}
+
+void
+ao_serial0_drain(void)
+{
+       ao_arch_block_interrupts();
+       while (!ao_fifo_empty(ao_usart_tx_fifo))
+               ao_sleep(&ao_usart_tx_fifo);
+       ao_arch_release_interrupts();
+}
+
+#include "ao_serial_lpc.h"
+
+void
+ao_serial0_set_speed(uint8_t speed)
+{
+       if (speed > AO_SERIAL_SPEED_115200)
+               return;
+
+       /* Flip to allow access to divisor latches */
+       lpc_usart.lcr |= (1 << LPC_USART_LCR_DLAB);
+
+       /* DL LSB */
+       lpc_usart.rbr_thr = ao_usart_speeds[speed].dl & 0xff;
+       
+       /* DL MSB */
+       lpc_usart.ier = (ao_usart_speeds[speed].dl >> 8) & 0xff;
+
+       lpc_usart.fdr = ((ao_usart_speeds[speed].divaddval << LPC_USART_FDR_DIVADDVAL) |
+                        (ao_usart_speeds[speed].mulval << LPC_USART_FDR_MULVAL));
+
+       /* Turn access to divisor latches back off */
+       lpc_usart.lcr &= ~(1 << LPC_USART_LCR_DLAB);
+}
+
+void
+ao_serial_init(void)
+{
+#if SERIAL_0_18_19
+       lpc_ioconf.pio0_18 = ((LPC_IOCONF_FUNC_PIO0_18_RXD << LPC_IOCONF_FUNC) |
+                             (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+                             (0 << LPC_IOCONF_HYS) |
+                             (0 << LPC_IOCONF_INV) |
+                             (0 << LPC_IOCONF_OD));
+       lpc_ioconf.pio0_19 = ((LPC_IOCONF_FUNC_PIO0_19_TXD << LPC_IOCONF_FUNC) |
+                             (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+                             (0 << LPC_IOCONF_HYS) |
+                             (0 << LPC_IOCONF_INV) |
+                             (0 << LPC_IOCONF_OD));
+#endif
+
+       /* Turn on the USART */
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_USART);
+
+       /* Turn on the USART clock */
+       lpc_scb.uartclkdiv = AO_LPC_CLKOUT / AO_LPC_USARTCLK;
+
+       /* Configure USART */
+
+       /* Enable FIFOs, reset fifo contents, interrupt on 1 received char */
+       lpc_usart.iir_fcr = ((1 << LPC_USART_FCR_FIFOEN) |
+                        (1 << LPC_USART_FCR_RXFIFORES) |
+                        (1 << LPC_USART_FCR_TXFIFORES) |
+                        (LPC_USART_FCR_RXTL_1 << LPC_USART_FCR_RXTL));
+
+       ao_usart_tx_avail = LPC_USART_TX_FIFO_SIZE;
+       ao_usart_tx_avail_min = LPC_USART_TX_FIFO_SIZE;
+
+       /* 8 n 1 */
+       lpc_usart.lcr = ((LPC_USART_LCR_WLS_8 << LPC_USART_LCR_WLS) |
+                        (LPC_USART_LCR_SBS_1 << LPC_USART_LCR_SBS) |
+                        (0 << LPC_USART_LCR_PE) |
+                        (LPC_USART_LCR_PS_ODD << LPC_USART_LCR_PS) |
+                        (0 << LPC_USART_LCR_BC) |
+                        (0 << LPC_USART_LCR_DLAB));
+
+       /* Disable flow control */
+       lpc_usart.mcr = ((0 << LPC_USART_MCR_DTRCTRL) |
+                        (0 << LPC_USART_MCR_RTSCTRL) |
+                        (0 << LPC_USART_MCR_LMS) |
+                        (0 << LPC_USART_MCR_RTSEN) |
+                        (0 << LPC_USART_MCR_CTSEN));
+
+       /* 16x oversampling */
+       lpc_usart.osr = ((0 << LPC_USART_OSR_OSFRAC) |
+                        ((16 - 1) << LPC_USART_OSR_OSINT) |
+                        (0 << LPC_USART_OSR_FDINT));
+
+       /* Full duplex */
+       lpc_usart.hden = ((0 << LPC_USART_HDEN_HDEN));
+
+       /* Set baud rate */
+       ao_serial0_set_speed(AO_SERIAL_SPEED_9600);
+
+       /* Enable interrupts */
+       lpc_usart.ier = ((1 << LPC_USART_IER_RBRINTEN) |
+                        (1 << LPC_USART_IER_THREINTEN));
+
+       lpc_nvic_set_enable(LPC_ISR_USART_POS);
+       lpc_nvic_set_priority(LPC_ISR_USART_POS, 0);
+#if USE_SERIAL_0_STDIN
+       ao_add_stdio(_ao_serial_pollchar,
+                    ao_serial_putchar,
+                    NULL);
+#endif
+}
diff --git a/src/lpc/ao_spi_lpc.c b/src/lpc/ao_spi_lpc.c
new file mode 100644 (file)
index 0000000..a889137
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+static uint8_t         ao_spi_mutex[LPC_NUM_SPI];
+
+static struct lpc_ssp * const ao_lpc_ssp[LPC_NUM_SPI] = { &lpc_ssp0, &lpc_ssp1 };
+
+static uint8_t spi_dev_null;
+
+#define tx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_TNF))) != (1 << LPC_SSP_SR_TNF)
+#define rx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_RNE))) != (1 << LPC_SSP_SR_RNE)
+
+#define spi_loop(len, put, get) do {                                   \
+               while (len--) {                                         \
+                       /* Wait for space in the fifo */                \
+                       while (tx_busy(lpc_ssp))                        \
+                               ;                                       \
+                                                                       \
+                       /* send a byte */                               \
+                       lpc_ssp->dr = put;                              \
+                                                                       \
+                       /* Wait for byte to appear in the fifo */       \
+                       while (rx_busy(lpc_ssp))                        \
+                               ;                                       \
+                                                                       \
+                       /* recv a byte */                               \
+                       get lpc_ssp->dr;                                \
+               }                                                       \
+       } while (0)
+
+void
+ao_spi_send(void *block, uint16_t len, uint8_t id)
+{
+       uint8_t *b = block;
+       struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+       spi_loop(len, *b++, (void));
+}
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t id)
+{
+       struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+       spi_loop(len, value, (void));
+}
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t id)
+{
+       uint8_t *b = block;
+       struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+       spi_loop(len, 0xff, *b++ =);
+}
+
+void
+ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t id)
+{
+       uint8_t *o = out;
+       uint8_t *i = in;
+       struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+       spi_loop(len, *o++, *i++ =);
+}
+
+void
+ao_spi_get(uint8_t id, uint32_t speed)
+{
+       struct lpc_ssp  *lpc_ssp = ao_lpc_ssp[id];
+
+       ao_mutex_get(&ao_spi_mutex[id]);
+       
+       /* Set the clock prescale */
+       lpc_ssp->cpsr = speed;
+}
+
+void
+ao_spi_put(uint8_t id)
+{
+       ao_mutex_put(&ao_spi_mutex[id]);
+}
+
+static void
+ao_spi_channel_init(uint8_t id)
+{
+       struct lpc_ssp  *lpc_ssp = ao_lpc_ssp[id];
+       uint8_t d;
+
+       lpc_ssp->cr0 = ((LPC_SSP_CR0_DSS_8 << LPC_SSP_CR0_DSS) |
+                       (LPC_SSP_CR0_FRF_SPI << LPC_SSP_CR0_FRF) |
+                       (0 << LPC_SSP_CR0_CPOL) |
+                       (0 << LPC_SSP_CR0_CPHA) |
+                       (0 << LPC_SSP_CR0_SCR));
+
+       /* Enable the device */
+       lpc_ssp->cr1 = ((0 << LPC_SSP_CR1_LBM) |
+                       (1 << LPC_SSP_CR1_SSE) |
+                       (LPC_SSP_CR1_MS_MASTER << LPC_SSP_CR1_MS) |
+                       (0 << LPC_SSP_CR1_SOD));
+
+       /* Drain the receive fifo */
+       for (d = 0; d < LPC_SSP_FIFOSIZE; d++)
+               (void) lpc_ssp->dr;
+}
+
+void
+ao_spi_init(void)
+{
+#if HAS_SPI_0
+       /* Configure pins */
+#if SPI_SCK0_P0_6
+       lpc_ioconf.pio0_6 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_6_SCK0);
+#define HAS_SCK0
+#endif
+#if SPI_SCK0_P0_10
+       lpc_ioconf.pio0_10 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_10_SCK0);
+#define HAS_SCK0
+#endif
+#if SPI_SCK0_P1_29
+       lpc_ioconf.pio1_29 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_29_SCK0);
+#define HAS_SCK0
+#endif
+#ifndef HAS_SCK0
+#error "No pin specified for SCK0"
+#endif
+       lpc_ioconf.pio0_8 = ao_lpc_alternate(LPC_IOCONF_FUNC_MISO0);
+       lpc_ioconf.pio0_9 = ao_lpc_alternate(LPC_IOCONF_FUNC_MOSI0);
+
+       /* Enable the device */
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP0);
+
+       /* Turn on the clock */
+       lpc_scb.ssp0clkdiv = 1;
+
+       /* Reset the device */
+       lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
+       lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
+       ao_spi_channel_init(0);
+#endif                    
+
+#if HAS_SPI_1
+
+#if SPI_SCK1_P1_15
+       lpc_ioconf.pio1_15 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_15_SCK1);
+#define HAS_SCK1
+#endif
+#if SPI_SCK1_P1_20
+       lpc_ioconf.pio1_20 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_20_SCK1);
+#define HAS_SCK1
+#endif
+#ifndef HAS_SCK1
+#error "No pin specified for SCK1"
+#endif
+
+#if SPI_MISO1_P0_22
+       lpc_ioconf.pio0_22 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_22_MISO1);
+#define HAS_MISO1
+#endif
+#if SPI_MISO1_P1_21
+       lpc_ioconf.pio1_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_21_MISO1);
+#define HAS_MISO1
+#endif
+#ifndef HAS_MISO1
+#error "No pin specified for MISO1"
+#endif
+
+#if SPI_MOSI1_P0_21
+       lpc_ioconf.pio0_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_21_MOSI1);
+#define HAS_MOSI1
+#endif
+#if SPI_MOSI1_P1_22
+       lpc_ioconf.pio1_22 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_22_MOSI1);
+#define HAS_MOSI1
+#endif
+#ifndef HAS_MOSI1
+#error "No pin specified for MOSI1"
+#endif
+               
+       /* Enable the device */
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP1);
+
+       /* Turn on the clock */
+       lpc_scb.ssp1clkdiv = 1;
+
+       /* Reset the device */
+       lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
+       lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
+       ao_spi_channel_init(1);
+#endif /* HAS_SPI_1 */
+}
diff --git a/src/lpc/ao_timer_lpc.c b/src/lpc/ao_timer_lpc.c
new file mode 100644 (file)
index 0000000..44fb410
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+volatile __data AO_TICK_TYPE ao_tick_count;
+
+uint16_t
+ao_time(void)
+{
+       return ao_tick_count;
+}
+
+#if AO_DATA_ALL
+volatile __data uint8_t        ao_data_interval = 1;
+volatile __data uint8_t        ao_data_count;
+#endif
+
+void lpc_systick_isr(void)
+{
+       if (lpc_systick.csr & (1 << LPC_SYSTICK_CSR_COUNTFLAG)) {
+               ++ao_tick_count;
+#if HAS_TASK_QUEUE
+               if (ao_task_alarm_tick && (int16_t) (ao_tick_count - ao_task_alarm_tick) >= 0)
+                       ao_task_check_alarm((uint16_t) ao_tick_count);
+#endif
+#if AO_DATA_ALL
+               if (++ao_data_count == ao_data_interval) {
+                       ao_data_count = 0;
+                       ao_adc_poll();
+#if (AO_DATA_ALL & ~(AO_DATA_ADC))
+                       ao_wakeup((void *) &ao_data_count);
+#endif
+               }
+#endif
+       }
+}
+
+#if HAS_ADC
+void
+ao_timer_set_adc_interval(uint8_t interval)
+{
+       ao_arch_critical(
+               ao_data_interval = interval;
+               ao_data_count = 0;
+               );
+}
+#endif
+
+#define SYSTICK_RELOAD ((AO_LPC_SYSCLK / 2) / 100 - 1)
+
+/* Initialize our 100Hz clock */
+void
+ao_timer_init(void)
+{
+       lpc_systick.rvr = SYSTICK_RELOAD;
+       lpc_systick.cvr = 0;
+       lpc_systick.csr = ((1 << LPC_SYSTICK_CSR_ENABLE) |
+                          (1 << LPC_SYSTICK_CSR_TICKINT) |
+                          (LPC_SYSTICK_CSR_CLKSOURCE_CPU_OVER_2 << LPC_SYSTICK_CSR_CLKSOURCE));
+}
+
+#define AO_LPC_M       ((AO_LPC_CLKOUT / AO_LPC_CLKIN) - 1)
+
+#define AO_LPC_FCCO_MIN        156000000
+
+static void
+ao_clock_delay(void)
+{
+       uint32_t        i;
+       for (i = 0; i < 200; i++)
+               ao_arch_nop();
+}
+
+void
+ao_clock_init(void)
+{
+       uint8_t         p;
+       uint32_t        i;
+
+       /* Turn off all perhipherals except for GPIO configuration */
+       lpc_scb.sysahbclkctrl = ((1 << LPC_SCB_SYSAHBCLKCTRL_SYS) |
+                                (1 << LPC_SCB_SYSAHBCLKCTRL_ROM) |
+                                (1 << LPC_SCB_SYSAHBCLKCTRL_RAM0) |
+                                (1 << LPC_SCB_SYSAHBCLKCTRL_FLASHARRAY) |
+                                (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO) |
+                                (1 << LPC_SCB_SYSAHBCLKCTRL_IOCON));
+                                
+       /* Enable the brown-out detection at the highest voltage to
+        * make sure the flash part remains happy
+        */
+
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_BOD_PD);
+       lpc_scb.bodctrl = ((LPC_SCB_BOD_BODRSTLEV_2_63 << LPC_SCB_BOD_BODRSTLEV) |
+                          (LPC_SCB_BOD_BODINTVAL_RESERVED << LPC_SCB_BOD_BODINTVAL) |
+                          (1 << LPC_SCB_BOD_BODRSTENA));
+
+       /* Turn the IRC clock back on */
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_IRC_PD);
+       ao_clock_delay();
+       
+       /* Switch to the IRC clock */
+       lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_IRC << LPC_SCB_MAINCLKSEL_SEL;
+       lpc_scb.mainclkuen = (0 << LPC_SCB_MAINCLKUEN_ENA);
+       lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
+       while (!(lpc_scb.mainclkuen & (1 << LPC_SCB_MAINCLKUEN_ENA)))
+               ;
+       
+       /* Switch USB to the main clock */
+       lpc_scb.usbclksel = (LPC_SCB_USBCLKSEL_SEL_MAIN_CLOCK << LPC_SCB_USBCLKSEL_SEL);
+       lpc_scb.usbclkuen = (0 << LPC_SCB_USBCLKUEN_ENA);
+       lpc_scb.usbclkuen = (1 << LPC_SCB_USBCLKUEN_ENA);
+       while (!(lpc_scb.usbclkuen & (1 << LPC_SCB_USBCLKUEN_ENA)))
+               ;
+       
+       /* Find a PLL post divider ratio that gets the FCCO in range */
+       for (p = 0; p < 4; p++)
+               if (AO_LPC_CLKOUT << (1 + p) >= AO_LPC_FCCO_MIN)
+                       break;
+
+       if (p == 4)
+               ao_panic(AO_PANIC_CRASH);
+
+       /* Power down the PLL before touching the registers */
+       lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_SYSPLL_PD);
+       ao_clock_delay();
+
+       /* Set PLL divider values */
+       lpc_scb.syspllctrl = ((AO_LPC_M << LPC_SCB_SYSPLLCTRL_MSEL) |
+                             (p << LPC_SCB_SYSPLLCTRL_PSEL));
+
+       /* Turn off the external crystal clock */
+       lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_SYSOSC_PD);
+       ao_clock_delay();
+
+       /* Configure the crystal clock */
+       lpc_scb.sysoscctrl = ((0 << LPC_SCB_SYSOSCCTRL_BYPASS) |                           /* using a crystal */
+                             ((AO_LPC_CLKIN > 15000000) << LPC_SCB_SYSOSCCTRL_FREQRANGE));/* set range */
+
+       /* Turn on the external crystal clock */
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSOSC_PD);
+       ao_clock_delay();
+
+       /* Select crystal as PLL input */
+
+       lpc_scb.syspllclksel = (LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC << LPC_SCB_SYSPLLCLKSEL_SEL);
+       lpc_scb.syspllclkuen = (1 << LPC_SCB_SYSPLLCLKUEN_ENA);
+       lpc_scb.syspllclkuen = (0 << LPC_SCB_SYSPLLCLKUEN_ENA);
+       lpc_scb.syspllclkuen = (1 << LPC_SCB_SYSPLLCLKUEN_ENA);
+       while (!(lpc_scb.syspllclkuen & (1 << LPC_SCB_SYSPLLCLKUEN_ENA)))
+               ;
+       
+       /* Turn on the PLL */
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSPLL_PD);
+
+       /* Wait for it to lock */
+       
+       for (i = 0; i < 20000; i++)
+               if (lpc_scb.syspllstat & (1 << LPC_SCB_SYSPLLSTAT_LOCK))
+                       break;
+       if (i == 20000)
+               ao_panic(AO_PANIC_CRASH);
+
+       /* Switch to the PLL */
+       lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_PLL_OUTPUT << LPC_SCB_MAINCLKSEL_SEL;
+       lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
+       lpc_scb.mainclkuen = (0 << LPC_SCB_MAINCLKUEN_ENA);
+       lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
+       while (!(lpc_scb.mainclkuen & (1 << LPC_SCB_MAINCLKUEN_ENA)))
+               ;
+
+       /* Set system clock divider */
+       lpc_scb.sysahbclkdiv = AO_LPC_CLKOUT / AO_LPC_SYSCLK;
+
+       /* Shut down perhipheral clocks (enabled as needed) */
+       lpc_scb.ssp0clkdiv = 0;
+       lpc_scb.uartclkdiv = 0;
+       lpc_scb.ssp1clkdiv = 0;
+       lpc_scb.usbclkdiv = 0;
+       lpc_scb.clkoutdiv = 0;
+
+       /* Switch USB PLL source to system osc so we can power down the IRC */
+       lpc_scb.usbpllclksel = (LPC_SCB_USBPLLCLKSEL_SEL_SYSOSC << LPC_SCB_USBPLLCLKSEL_SEL);
+       lpc_scb.usbpllclkuen = (0 << LPC_SCB_USBPLLCLKUEN_ENA);
+       lpc_scb.usbpllclkuen = (1 << LPC_SCB_USBPLLCLKUEN_ENA);
+       while (!(lpc_scb.usbpllclkuen & (1 << LPC_SCB_USBPLLCLKUEN_ENA)))
+               ;
+       
+       /* Power down everything we don't need */
+       lpc_scb.pdruncfg = ((1 << LPC_SCB_PDRUNCFG_IRCOUT_PD) |
+                           (1 << LPC_SCB_PDRUNCFG_IRC_PD) |
+                           (0 << LPC_SCB_PDRUNCFG_BOD_PD) |
+                           (1 << LPC_SCB_PDRUNCFG_ADC_PD) |
+                           (1 << LPC_SCB_PDRUNCFG_WDTOSC_PD) |
+                           (1 << LPC_SCB_PDRUNCFG_USBPLL_PD) |
+                           (1 << LPC_SCB_PDRUNCFG_USBPAD_PD) |
+                           (1 << 11) |
+                           (7 << 13));
+}
diff --git a/src/lpc/ao_usb_lpc.c b/src/lpc/ao_usb_lpc.c
new file mode 100644 (file)
index 0000000..686dc3a
--- /dev/null
@@ -0,0 +1,1055 @@
+/*
+ * 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"
+#include "ao_usb.h"
+#include "ao_product.h"
+
+#ifndef USE_USB_STDIO
+#define USE_USB_STDIO  1
+#endif
+
+#if USE_USB_STDIO
+#define AO_USB_OUT_SLEEP_ADDR  (&ao_stdin_ready)
+#else
+#define AO_USB_OUT_SLEEP_ADDR  (&ao_usb_out_avail)
+#endif
+
+#define USB_DEBUG      0
+#define USB_DEBUG_DATA 0
+#define USB_ECHO       0
+
+#if USB_DEBUG
+#define debug(format, args...) printf(format, ## args);
+#else
+#define debug(format, args...)
+#endif
+
+#if USB_DEBUG_DATA
+#define debug_data(format, args...)    printf(format, ## args);
+#else
+#define debug_data(format, args...)
+#endif
+
+struct ao_usb_setup {
+       uint8_t         dir_type_recip;
+       uint8_t         request;
+       uint16_t        value;
+       uint16_t        index;
+       uint16_t        length;
+} ao_usb_setup;
+
+static uint8_t         ao_usb_ep0_state;
+
+/* Pending EP0 IN data */
+static const uint8_t   *ao_usb_ep0_in_data;    /* Remaining data */
+static uint8_t                 ao_usb_ep0_in_len;      /* Remaining amount */
+static uint16_t                ao_usb_ep0_in_max;      /* Requested amount from host */
+
+/* Temp buffer for smaller EP0 in data */
+static uint8_t ao_usb_ep0_in_buf[2];
+
+/* Pending EP0 OUT data */
+static uint8_t *ao_usb_ep0_out_data;
+static uint8_t         ao_usb_ep0_out_len;
+
+/*
+ * Objects allocated in special USB memory
+ */
+
+/* USB address of end of allocated storage */
+static uint8_t *ao_usb_sram;
+
+/* Pointer to ep0 tx/rx buffers in USB memory */
+static uint8_t *ao_usb_ep0_tx_buffer;
+static uint8_t *ao_usb_ep0_setup_buffer;
+static uint8_t *ao_usb_ep0_rx_buffer;
+
+/* Pointer to bulk data tx/rx buffers in USB memory */
+static uint8_t *ao_usb_in_tx_buffer;
+static uint8_t *ao_usb_out_rx_buffer;
+
+/* Our data buffers */
+static uint8_t ao_usb_tx_buffer[AO_USB_IN_SIZE];
+static uint8_t ao_usb_tx_count;
+
+static uint8_t ao_usb_rx_buffer[AO_USB_OUT_SIZE];
+static uint8_t ao_usb_rx_count, ao_usb_rx_pos;
+
+extern struct lpc_usb_endpoint lpc_usb_endpoint;
+
+/* Marks when we don't need to send an IN packet.
+ * This happens only when the last IN packet is not full,
+ * otherwise the host will expect to keep seeing packets.
+ * Send a zero-length packet as required
+ */
+static uint8_t ao_usb_in_flushed;
+
+/* Marks when we have delivered an IN packet to the hardware
+ * and it has not been received yet. ao_sleep on this address
+ * to wait for it to be delivered.
+ */
+static uint8_t ao_usb_in_pending;
+
+/* Marks when an OUT packet has been received by the hardware
+ * but not pulled to the shadow buffer.
+ */
+static uint8_t ao_usb_out_avail;
+static uint8_t ao_usb_running;
+static uint8_t ao_usb_configuration;
+static uint8_t ueienx_0;
+
+#define AO_USB_EP0_GOT_RESET   1
+#define AO_USB_EP0_GOT_SETUP   2
+#define AO_USB_EP0_GOT_RX_DATA 4
+#define AO_USB_EP0_GOT_TX_ACK  8
+
+static uint8_t ao_usb_ep0_receive;
+static uint8_t ao_usb_address;
+static uint8_t ao_usb_address_pending;
+
+static inline uint32_t set_toggle(uint32_t     current_value,
+                                  uint32_t     mask,
+                                  uint32_t     desired_value)
+{
+       return (current_value ^ desired_value) & mask;
+}
+
+/*
+ * Set current device address and mark the
+ * interface as active
+ */
+void
+ao_usb_set_address(uint8_t address)
+{
+       debug("ao_usb_set_address %02x\n", address);
+       lpc_usb.devcmdstat = ((address << LPC_USB_DEVCMDSTAT_DEV_ADDR) |
+                             (1 << LPC_USB_DEVCMDSTAT_DEV_EN) |
+                             (0 << LPC_USB_DEVCMDSTAT_SETUP) |
+                             (0 << LPC_USB_DEVCMDSTAT_PLL_ON) |
+                             (0 << LPC_USB_DEVCMDSTAT_LPM_SUP) |
+                             (0 << LPC_USB_DEVCMDSTAT_INTONNAK_AO) |
+                             (0 << LPC_USB_DEVCMDSTAT_INTONNAK_AI) |
+                             (0 << LPC_USB_DEVCMDSTAT_INTONNAK_CO) |
+                             (0 << LPC_USB_DEVCMDSTAT_INTONNAK_CI) |
+                             (1 << LPC_USB_DEVCMDSTAT_DCON) |
+                             (0 << LPC_USB_DEVCMDSTAT_DSUS) |
+                             (0 << LPC_USB_DEVCMDSTAT_DCON_C) |
+                             (0 << LPC_USB_DEVCMDSTAT_DSUS_C) |
+                             (0 << LPC_USB_DEVCMDSTAT_DRES_C) |
+                             (0 << LPC_USB_DEVCMDSTAT_VBUSDEBOUNCED));
+       ao_usb_address_pending = 0;
+}
+
+#define TX_DBG 0
+#define RX_DBG 0
+
+#if TX_DBG
+#define _tx_dbg0(msg) _dbg(__LINE__,msg,0)
+#define _tx_dbg1(msg,value) _dbg(__LINE__,msg,value)
+#else
+#define _tx_dbg0(msg)
+#define _tx_dbg1(msg,value)
+#endif
+
+#if RX_DBG
+#define _rx_dbg0(msg) _dbg(__LINE__,msg,0)
+#define _rx_dbg1(msg,value) _dbg(__LINE__,msg,value)
+#else
+#define _rx_dbg0(msg)
+#define _rx_dbg1(msg,value)
+#endif
+
+#if TX_DBG || RX_DBG
+static void _dbg(int line, char *msg, uint32_t value);
+#endif
+
+/*
+ * Set just endpoint 0, for use during startup
+ */
+
+static uint8_t *
+ao_usb_alloc_sram(uint16_t size)
+{
+       uint8_t *addr = ao_usb_sram;
+
+       ao_usb_sram += (size + 63) & ~63;
+       return addr;
+}
+
+static uint16_t
+ao_usb_sram_offset(uint8_t *addr)
+{
+       return (uint16_t) ((intptr_t) addr >> 6);
+}
+
+static void
+ao_usb_set_ep(vuint32_t *ep, uint8_t *addr, uint16_t nbytes)
+{
+       *ep = ((ao_usb_sram_offset(addr) << LPC_USB_EP_OFFSET) |
+              (nbytes << LPC_USB_EP_NBYTES) |
+              (0 << LPC_USB_EP_ENDPOINT_ISO) |
+              (0 << LPC_USB_EP_RATE_FEEDBACK) |
+              (0 << LPC_USB_EP_TOGGLE_RESET) |
+              (0 << LPC_USB_EP_STALL) |
+              (0 << LPC_USB_EP_DISABLED) |
+              (1 << LPC_USB_EP_ACTIVE));
+}
+
+static inline uint16_t
+ao_usb_ep_count(vuint32_t *ep)
+{
+       return (*ep >> LPC_USB_EP_NBYTES) & LPC_USB_EP_NBYTES_MASK;
+}
+
+static inline uint8_t
+ao_usb_ep_stall(vuint32_t *ep)
+{
+       return (*ep >> LPC_USB_EP_STALL) & 1;
+}
+
+static inline vuint32_t *
+ao_usb_ep0_out(void)
+{
+       return &lpc_usb_endpoint.ep0_out;
+}
+
+static inline vuint32_t *
+ao_usb_ep0_in(void)
+{
+       return &lpc_usb_endpoint.ep0_in;
+}
+
+static inline vuint32_t *
+ao_usb_epn_out(uint8_t n)
+{
+       return &lpc_usb_endpoint.epn[n-1].out[0];
+}
+
+static inline vuint32_t *
+ao_usb_epn_in(uint8_t n)
+{
+       return &lpc_usb_endpoint.epn[n-1].in[0];
+}
+
+static void
+ao_usb_set_epn_in(uint8_t n, uint8_t *addr, uint16_t nbytes)
+{
+       ao_usb_set_ep(ao_usb_epn_in(n), addr, nbytes);
+}
+
+static void
+ao_usb_set_epn_out(uint8_t n, uint8_t *addr, uint16_t nbytes)
+{
+       ao_usb_set_ep(ao_usb_epn_out(n), addr, nbytes);
+}
+
+static inline uint16_t
+ao_usb_epn_out_count(uint8_t n)
+{
+       return ao_usb_ep_count(ao_usb_epn_out(n));
+}
+
+static inline uint16_t
+ao_usb_epn_in_count(uint8_t n)
+{
+       return ao_usb_ep_count(ao_usb_epn_in(n));
+}
+
+static uint8_t *
+ao_usb_enable_ep(vuint32_t *ep, uint16_t nbytes, uint16_t set_nbytes)
+{
+       uint8_t *addr = ao_usb_alloc_sram(nbytes);
+       
+       ao_usb_set_ep(ep, addr, set_nbytes);
+       return addr;
+}
+
+static void
+ao_usb_disable_ep(vuint32_t *ep)
+{
+       *ep = ((0 << LPC_USB_EP_OFFSET) |
+              (0 << LPC_USB_EP_NBYTES) |
+              (0 << LPC_USB_EP_ENDPOINT_ISO) |
+              (0 << LPC_USB_EP_RATE_FEEDBACK) |
+              (0 << LPC_USB_EP_TOGGLE_RESET) |
+              (0 << LPC_USB_EP_STALL) |
+              (1 << LPC_USB_EP_DISABLED) |
+              (0 << LPC_USB_EP_ACTIVE));
+}
+
+static void
+ao_usb_enable_epn(uint8_t n, uint16_t out_bytes, uint8_t **out_addr, uint16_t in_bytes, uint8_t **in_addr)
+{
+       uint8_t *addr;
+
+       addr = ao_usb_enable_ep(ao_usb_epn_out(n), out_bytes, out_bytes);
+       if (out_addr)
+               *out_addr = addr;
+       ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]);
+
+       addr = ao_usb_enable_ep(ao_usb_epn_in(n), in_bytes, 0);
+       if (in_addr)
+               *in_addr = addr;
+       ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]);
+}
+
+static void
+ao_usb_disable_epn(uint8_t n)
+{
+       ao_usb_disable_ep(ao_usb_epn_out(n));
+       ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]);
+       ao_usb_disable_ep(ao_usb_epn_in(n));
+       ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]);
+}
+
+static void
+ao_usb_reset(void)
+{
+       ao_usb_set_address(0);
+       ao_usb_configuration = 0;
+}
+
+static void
+ao_usb_set_ep0(void)
+{
+       int                     e;
+
+       /* Everything is single buffered for now */
+       lpc_usb.epbufcfg = 0;
+       lpc_usb.epinuse = 0;
+       lpc_usb.epskip = 0xffffffff;
+
+       lpc_usb.intstat = 0xc00003ff;
+
+       ao_usb_sram = lpc_usb_sram;
+
+       lpc_usb.epliststart = (uint32_t) (intptr_t) &lpc_usb_endpoint;
+       lpc_usb.databufstart = ((uint32_t) (intptr_t) ao_usb_sram) & 0xffc00000;
+
+       /* Set up EP 0 - a Control end point with 32 bytes of in and out buffers */
+
+       ao_usb_ep0_rx_buffer = ao_usb_enable_ep(ao_usb_ep0_out(), AO_USB_CONTROL_SIZE, AO_USB_CONTROL_SIZE);
+       ao_usb_ep0_setup_buffer = ao_usb_alloc_sram(AO_USB_CONTROL_SIZE);
+       lpc_usb_endpoint.setup = ao_usb_sram_offset(ao_usb_ep0_setup_buffer);
+       ao_usb_ep0_tx_buffer = ao_usb_enable_ep(ao_usb_ep0_in(), AO_USB_CONTROL_SIZE, 0);
+
+       /* Clear all of the other endpoints */
+       for (e = 1; e <= 4; e++)
+               ao_usb_disable_epn(e);
+       ao_usb_reset();
+}
+
+static void
+ao_usb_set_configuration(void)
+{
+       debug ("ao_usb_set_configuration\n");
+
+       /* Set up the INT end point */
+       ao_usb_enable_epn(AO_USB_INT_EP, 0, NULL, 0, NULL);
+       
+       /* Set up the OUT end point */
+       ao_usb_enable_epn(AO_USB_OUT_EP, AO_USB_OUT_SIZE, &ao_usb_out_rx_buffer, 0, NULL);
+
+       /* Set up the IN end point */
+       ao_usb_enable_epn(AO_USB_IN_EP, 0, NULL, AO_USB_IN_SIZE, &ao_usb_in_tx_buffer);
+
+       ao_usb_running = 1;
+}
+
+/* Send an IN data packet */
+static void
+ao_usb_ep0_flush(void)
+{
+       uint8_t this_len;
+
+       this_len = ao_usb_ep0_in_len;
+       if (this_len > AO_USB_CONTROL_SIZE)
+               this_len = AO_USB_CONTROL_SIZE;
+
+       ao_usb_ep0_in_len -= this_len;
+       ao_usb_ep0_in_max -= this_len;
+
+       if (this_len < AO_USB_CONTROL_SIZE || ao_usb_ep0_in_max == 0)
+               ao_usb_ep0_state = AO_USB_EP0_IDLE;
+
+       debug_data ("Flush EP0 len %d:", this_len);
+       memcpy(ao_usb_ep0_tx_buffer, ao_usb_ep0_in_data, this_len);
+       debug_data ("\n");
+       ao_usb_ep0_in_data += this_len;
+
+       /* Mark the endpoint as TX valid to send the packet */
+       ao_usb_set_ep(ao_usb_ep0_in(), ao_usb_ep0_tx_buffer, this_len);
+       debug ("queue tx.  0 now %08x\n", *ao_usb_ep0_in());
+}
+
+/* Read data from the ep0 OUT fifo */
+static void
+ao_usb_ep0_fill(void)
+{
+       uint16_t        len;
+       uint8_t         *rx_buffer;
+
+       /* Pull all of the data out of the packet */
+       if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_SETUP)) {
+               rx_buffer = ao_usb_ep0_setup_buffer;
+               len = 8;
+       } else {
+               rx_buffer = ao_usb_ep0_rx_buffer;
+               len = AO_USB_CONTROL_SIZE - ao_usb_ep_count(ao_usb_ep0_out());
+       }
+
+       if (len > ao_usb_ep0_out_len)
+               len = ao_usb_ep0_out_len;
+       ao_usb_ep0_out_len -= len;
+
+       debug_data ("Fill EP0 len %d:", len);
+       memcpy(ao_usb_ep0_out_data, rx_buffer, len);
+       debug_data ("\n");
+       ao_usb_ep0_out_data += len;
+
+       /* ACK the packet */
+       ao_usb_set_ep(ao_usb_ep0_out(), ao_usb_ep0_rx_buffer, AO_USB_CONTROL_SIZE);
+       lpc_usb.devcmdstat |= (1 << LPC_USB_DEVCMDSTAT_SETUP);
+}
+
+static void
+ao_usb_ep0_in_reset(void)
+{
+       ao_usb_ep0_in_data = ao_usb_ep0_in_buf;
+       ao_usb_ep0_in_len = 0;
+}
+
+static void
+ao_usb_ep0_in_queue_byte(uint8_t a)
+{
+       if (ao_usb_ep0_in_len < sizeof (ao_usb_ep0_in_buf))
+               ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
+}
+
+static void
+ao_usb_ep0_in_set(const uint8_t *data, uint8_t len)
+{
+       ao_usb_ep0_in_data = data;
+       ao_usb_ep0_in_len = len;
+}
+
+static void
+ao_usb_ep0_out_set(uint8_t *data, uint8_t len)
+{
+       ao_usb_ep0_out_data = data;
+       ao_usb_ep0_out_len = len;
+}
+
+static void
+ao_usb_ep0_in_start(uint16_t max)
+{
+       ao_usb_ep0_in_max = max;
+       /* Don't send more than asked for */
+       if (ao_usb_ep0_in_len > max)
+               ao_usb_ep0_in_len = max;
+       ao_usb_ep0_flush();
+}
+
+static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
+
+/* Walk through the list of descriptors and find a match
+ */
+static void
+ao_usb_get_descriptor(uint16_t value)
+{
+       const uint8_t           *descriptor;
+       uint8_t         type = value >> 8;
+       uint8_t         index = value;
+
+       descriptor = ao_usb_descriptors;
+       while (descriptor[0] != 0) {
+               if (descriptor[1] == type && index-- == 0) {
+                       uint8_t len;
+                       if (type == AO_USB_DESC_CONFIGURATION)
+                               len = descriptor[2];
+                       else
+                               len = descriptor[0];
+                       ao_usb_ep0_in_set(descriptor, len);
+                       break;
+               }
+               descriptor += descriptor[0];
+       }
+}
+
+static void
+ao_usb_ep0_setup(void)
+{
+       /* Pull the setup packet out of the fifo */
+       ao_usb_ep0_out_set((uint8_t *) &ao_usb_setup, 8);
+       ao_usb_ep0_fill();
+       if (ao_usb_ep0_out_len != 0) {
+               debug ("invalid setup packet length\n");
+               return;
+       }
+
+       if ((ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) || ao_usb_setup.length == 0)
+               ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
+       else
+               ao_usb_ep0_state = AO_USB_EP0_DATA_OUT;
+
+       ao_usb_ep0_in_reset();
+
+       switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) {
+       case AO_USB_TYPE_STANDARD:
+               debug ("Standard setup packet\n");
+               switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
+               case AO_USB_RECIP_DEVICE:
+                       debug ("Device setup packet\n");
+                       switch(ao_usb_setup.request) {
+                       case AO_USB_REQ_GET_STATUS:
+                               debug ("get status\n");
+                               ao_usb_ep0_in_queue_byte(0);
+                               ao_usb_ep0_in_queue_byte(0);
+                               break;
+                       case AO_USB_REQ_SET_ADDRESS:
+                               debug ("set address %d\n", ao_usb_setup.value);
+                               ao_usb_address = ao_usb_setup.value;
+                               ao_usb_address_pending = 1;
+                               break;
+                       case AO_USB_REQ_GET_DESCRIPTOR:
+                               debug ("get descriptor %d\n", ao_usb_setup.value);
+                               ao_usb_get_descriptor(ao_usb_setup.value);
+                               break;
+                       case AO_USB_REQ_GET_CONFIGURATION:
+                               debug ("get configuration %d\n", ao_usb_configuration);
+                               ao_usb_ep0_in_queue_byte(ao_usb_configuration);
+                               break;
+                       case AO_USB_REQ_SET_CONFIGURATION:
+                               ao_usb_configuration = ao_usb_setup.value;
+                               debug ("set configuration %d\n", ao_usb_configuration);
+                               ao_usb_set_configuration();
+                               break;
+                       }
+                       break;
+               case AO_USB_RECIP_INTERFACE:
+                       debug ("Interface setup packet\n");
+                       switch(ao_usb_setup.request) {
+                       case AO_USB_REQ_GET_STATUS:
+                               ao_usb_ep0_in_queue_byte(0);
+                               ao_usb_ep0_in_queue_byte(0);
+                               break;
+                       case AO_USB_REQ_GET_INTERFACE:
+                               ao_usb_ep0_in_queue_byte(0);
+                               break;
+                       case AO_USB_REQ_SET_INTERFACE:
+                               break;
+                       }
+                       break;
+               case AO_USB_RECIP_ENDPOINT:
+                       debug ("Endpoint setup packet\n");
+                       switch(ao_usb_setup.request) {
+                       case AO_USB_REQ_GET_STATUS:
+                               ao_usb_ep0_in_queue_byte(0);
+                               ao_usb_ep0_in_queue_byte(0);
+                               break;
+                       }
+                       break;
+               }
+               break;
+       case AO_USB_TYPE_CLASS:
+               debug ("Class setup packet\n");
+               switch (ao_usb_setup.request) {
+               case AO_USB_SET_LINE_CODING:
+                       debug ("set line coding\n");
+                       ao_usb_ep0_out_set((uint8_t *) &ao_usb_line_coding, 7);
+                       break;
+               case AO_USB_GET_LINE_CODING:
+                       debug ("get line coding\n");
+                       ao_usb_ep0_in_set((const uint8_t *) &ao_usb_line_coding, 7);
+                       break;
+               case AO_USB_SET_CONTROL_LINE_STATE:
+                       break;
+               }
+               break;
+       }
+
+       /* If we're not waiting to receive data from the host,
+        * queue an IN response
+        */
+       if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN)
+               ao_usb_ep0_in_start(ao_usb_setup.length);
+}
+
+static void
+ao_usb_ep0_handle(uint8_t receive)
+{
+       ao_usb_ep0_receive = 0;
+
+       if (receive & AO_USB_EP0_GOT_RESET) {
+               debug ("\treset\n");
+               ao_usb_reset();
+               return;
+       }
+       if (receive & AO_USB_EP0_GOT_SETUP) {
+               debug ("\tsetup\n");
+               ao_usb_ep0_setup();
+       }
+       if (receive & AO_USB_EP0_GOT_RX_DATA) {
+               debug ("\tgot rx data\n");
+               if (ao_usb_ep0_state == AO_USB_EP0_DATA_OUT) {
+                       ao_usb_ep0_fill();
+                       if (ao_usb_ep0_out_len == 0) {
+                               ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
+                               ao_usb_ep0_in_start(0);
+                       }
+               }
+       }
+       if (receive & AO_USB_EP0_GOT_TX_ACK) {
+               debug ("\tgot tx ack\n");
+
+               /* Wait until the IN packet is received from addr 0
+                * before assigning our local address
+                */
+               if (ao_usb_address_pending) {
+#if HAS_FLIGHT
+                       /* Go to idle mode if USB is connected
+                        */
+                       ao_flight_force_idle = 1;
+#endif
+                       ao_usb_set_address(ao_usb_address);
+               }
+               if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN)
+                       ao_usb_ep0_flush();
+       }
+}
+
+static uint16_t        control_count;
+static uint16_t int_count;
+static uint16_t        in_count;
+static uint16_t        out_count;
+static uint16_t        reset_count;
+
+void
+lpc_usb_irq_isr(void)
+{
+       uint32_t        intstat = lpc_usb.intstat & lpc_usb.inten;
+
+       lpc_usb.intstat = intstat;
+       /* Handle EP0 OUT packets */
+       if (intstat & (1 << LPC_USB_INT_EPOUT(0))) {
+               if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_SETUP))
+                       ao_usb_ep0_receive |= AO_USB_EP0_GOT_SETUP;
+               else
+                       ao_usb_ep0_receive |= AO_USB_EP0_GOT_RX_DATA;
+
+               ao_usb_ep0_handle(ao_usb_ep0_receive);
+       }
+
+       /* Handle EP0 IN packets */
+       if (intstat & (1 << LPC_USB_INT_EPIN(0))) {
+               ao_usb_ep0_receive |= AO_USB_EP0_GOT_TX_ACK;
+
+               ao_usb_ep0_handle(ao_usb_ep0_receive);
+       }
+
+
+       /* Handle OUT packets */
+       if (intstat & (1 << LPC_USB_INT_EPOUT(AO_USB_OUT_EP))) {
+               ++out_count;
+               _rx_dbg1("RX ISR", *ao_usb_epn_out(AO_USB_OUT_EP));
+               ao_usb_out_avail = 1;
+               _rx_dbg0("out avail set");
+               ao_wakeup(AO_USB_OUT_SLEEP_ADDR)
+               _rx_dbg0("stdin awoken");
+       }
+
+       /* Handle IN packets */
+       if (intstat & (1 << LPC_USB_INT_EPIN(AO_USB_IN_EP))) {
+               ++in_count;
+               _tx_dbg1("TX ISR", *ao_usb_epn_in(AO_USB_IN_EP));
+               ao_usb_in_pending = 0;
+               ao_wakeup(&ao_usb_in_pending);
+       }
+
+       /* NAK all INT EP IN packets */
+       if (intstat & (1 << LPC_USB_INT_EPIN(AO_USB_INT_EP))) {
+               ;
+       }
+
+       /* Check for reset */
+       if (intstat & (1 << LPC_USB_INT_DEV)) {
+               if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_DRES_C))
+               {
+                       lpc_usb.devcmdstat |= (1 << LPC_USB_DEVCMDSTAT_DRES_C);
+                       ao_usb_ep0_receive |= AO_USB_EP0_GOT_RESET;
+                       ao_usb_ep0_handle(ao_usb_ep0_receive);
+               }
+       }
+}
+
+
+
+/* Queue the current IN buffer for transmission */
+static void
+_ao_usb_in_send(void)
+{
+       _tx_dbg0("in_send start");
+       debug ("send %d\n", ao_usb_tx_count);
+       while (ao_usb_in_pending)
+               ao_sleep(&ao_usb_in_pending);
+       ao_usb_in_pending = 1;
+       if (ao_usb_tx_count != AO_USB_IN_SIZE)
+               ao_usb_in_flushed = 1;
+       memcpy(ao_usb_in_tx_buffer, ao_usb_tx_buffer, ao_usb_tx_count);
+       ao_usb_set_ep(ao_usb_epn_in(AO_USB_IN_EP), ao_usb_in_tx_buffer, ao_usb_tx_count);
+       ao_usb_tx_count = 0;
+       _tx_dbg0("in_send end");
+}
+
+/* Wait for a free IN buffer. Interrupts are blocked */
+static void
+_ao_usb_in_wait(void)
+{
+       for (;;) {
+               /* Check if the current buffer is writable */
+               if (ao_usb_tx_count < AO_USB_IN_SIZE)
+                       break;
+
+               _tx_dbg0("in_wait top");
+               /* Wait for an IN buffer to be ready */
+               while (ao_usb_in_pending)
+                       ao_sleep(&ao_usb_in_pending);
+               _tx_dbg0("in_wait bottom");
+       }
+}
+
+void
+ao_usb_flush(void)
+{
+       if (!ao_usb_running)
+               return;
+
+       /* Anytime we've sent a character since
+        * the last time we flushed, we'll need
+        * to send a packet -- the only other time
+        * we would send a packet is when that
+        * packet was full, in which case we now
+        * want to send an empty packet
+        */
+       ao_arch_block_interrupts();
+       while (!ao_usb_in_flushed) {
+               _tx_dbg0("flush top");
+               _ao_usb_in_send();
+               _tx_dbg0("flush end");
+       }
+       ao_arch_release_interrupts();
+}
+
+void
+ao_usb_putchar(char c)
+{
+       if (!ao_usb_running)
+               return;
+
+       ao_arch_block_interrupts();
+       _ao_usb_in_wait();
+
+       ao_usb_in_flushed = 0;
+       ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c;
+
+       /* Send the packet when full */
+       if (ao_usb_tx_count == AO_USB_IN_SIZE) {
+               _tx_dbg0("putchar full");
+               _ao_usb_in_send();
+               _tx_dbg0("putchar flushed");
+       }
+       ao_arch_release_interrupts();
+}
+
+static void
+_ao_usb_out_recv(void)
+{
+       _rx_dbg0("out_recv top");
+       ao_usb_out_avail = 0;
+
+       ao_usb_rx_count = AO_USB_OUT_SIZE - ao_usb_epn_out_count(AO_USB_OUT_EP);
+
+       _rx_dbg1("out_recv count", ao_usb_rx_count);
+       debug ("recv %d\n", ao_usb_rx_count);
+       debug_data("Fill OUT len %d:", ao_usb_rx_count);
+       memcpy(ao_usb_rx_buffer, ao_usb_out_rx_buffer, ao_usb_rx_count);
+       debug_data("\n");
+       ao_usb_rx_pos = 0;
+
+       /* ACK the packet */
+       ao_usb_set_epn_out(AO_USB_OUT_EP, ao_usb_out_rx_buffer, AO_USB_OUT_SIZE);
+}
+
+int
+_ao_usb_pollchar(void)
+{
+       uint8_t c;
+
+       if (!ao_usb_running)
+               return AO_READ_AGAIN;
+
+       for (;;) {
+               if (ao_usb_rx_pos != ao_usb_rx_count)
+                       break;
+
+               _rx_dbg0("poll check");
+               /* Check to see if a packet has arrived */
+               if (!ao_usb_out_avail) {
+                       _rx_dbg0("poll none");
+                       return AO_READ_AGAIN;
+               }
+               _ao_usb_out_recv();
+       }
+
+       /* Pull a character out of the fifo */
+       c = ao_usb_rx_buffer[ao_usb_rx_pos++];
+       return c;
+}
+
+char
+ao_usb_getchar(void)
+{
+       int     c;
+
+       ao_arch_block_interrupts();
+       while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
+               ao_sleep(AO_USB_OUT_SLEEP_ADDR);
+       ao_arch_release_interrupts();
+       return c;
+}
+
+void
+ao_usb_disable(void)
+{
+       ao_arch_block_interrupts();
+
+#if HAS_USB_PULLUP
+       ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 0);
+#endif
+       /* Disable interrupts */
+       lpc_usb.inten = 0;
+
+       lpc_nvic_clear_enable(LPC_ISR_USB_IRQ_POS);
+
+       /* Disable the device */
+       lpc_usb.devcmdstat = 0;
+
+       /* Turn off USB clock */
+       lpc_scb.usbclkdiv = 0;
+
+       /* Disable USB PHY and PLL */
+       lpc_scb.pdruncfg |= ((1 << LPC_SCB_PDRUNCFG_USBPAD_PD) |
+                            (1 << LPC_SCB_PDRUNCFG_USBPLL_PD));
+
+       /* Disable USB registers and RAM */
+       lpc_scb.sysahbclkctrl &= ~((1 << LPC_SCB_SYSAHBCLKCTRL_USB) |
+                                  (1 << LPC_SCB_SYSAHBCLKCTRL_USBRAM));
+
+       ao_arch_release_interrupts();
+}
+
+void
+ao_usb_enable(void)
+{
+       int     t;
+
+       /* Enable USB pins */
+#if HAS_USB_CONNECT
+       lpc_ioconf.pio0_6 = ((LPC_IOCONF_FUNC_USB_CONNECT << LPC_IOCONF_FUNC) |
+                            (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+                            (0 << LPC_IOCONF_HYS) |
+                            (0 << LPC_IOCONF_INV) |
+                            (0 << LPC_IOCONF_OD) |
+                            0x80);
+#endif
+#if HAS_USB_VBUS
+       lpc_ioconf.pio0_3 = ((LPC_IOCONF_FUNC_USB_VBUS << LPC_IOCONF_FUNC) |
+                            (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+                            (0 << LPC_IOCONF_HYS) |
+                            (0 << LPC_IOCONF_INV) |
+                            (0 << LPC_IOCONF_OD) |
+                            0x80);
+#endif
+       /* Enable USB registers and RAM */
+       lpc_scb.sysahbclkctrl |= ((1 << LPC_SCB_SYSAHBCLKCTRL_USB) |
+                                 (1 << LPC_SCB_SYSAHBCLKCTRL_USBRAM));
+
+       /* Enable USB PHY */
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPAD_PD);
+       
+       /* Turn on USB PLL */
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPLL_PD);
+
+       lpc_scb.usbpllclksel = (LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC << LPC_SCB_SYSPLLCLKSEL_SEL);
+       lpc_scb.usbpllclkuen = (0 << LPC_SCB_USBPLLCLKUEN_ENA);
+       lpc_scb.usbpllclkuen = (1 << LPC_SCB_USBPLLCLKUEN_ENA);
+       while (!(lpc_scb.usbpllclkuen & (1 << LPC_SCB_USBPLLCLKUEN_ENA)))
+               ;
+       lpc_scb.usbpllctrl = 0x23;
+       while (!(lpc_scb.usbpllstat & 1))
+               ;
+
+       lpc_scb.usbclksel = 0;
+       lpc_scb.usbclkuen = (0 << LPC_SCB_USBCLKUEN_ENA);
+       lpc_scb.usbclkuen = (1 << LPC_SCB_USBCLKUEN_ENA);
+       while (!(lpc_scb.usbclkuen & (1 << LPC_SCB_USBCLKUEN_ENA)))
+               ;
+
+       /* Turn on USB clock, use 48MHz clock unchanged */
+       lpc_scb.usbclkdiv = 1;
+
+       /* Configure interrupts */
+       ao_arch_block_interrupts();
+
+       /* Route all interrupts to the main isr */
+       lpc_usb.introuting = 0;
+
+       /* Configure NVIC */
+
+       lpc_nvic_set_enable(LPC_ISR_USB_IRQ_POS);
+       lpc_nvic_set_priority(LPC_ISR_USB_IRQ_POS, 0);
+
+       /* Clear any spurious interrupts */
+       lpc_usb.intstat = 0xffffffff;
+
+       debug ("ao_usb_enable\n");
+
+       /* Enable interrupts */
+       lpc_usb.inten = ((1 << LPC_USB_INT_EPOUT(0)) |
+                        (1 << LPC_USB_INT_EPIN(0)) |
+                        (1 << LPC_USB_INT_EPIN(AO_USB_INT_EP)) |
+                        (1 << LPC_USB_INT_EPOUT(AO_USB_OUT_EP)) |
+                        (1 << LPC_USB_INT_EPIN(AO_USB_IN_EP)) |
+                        (1 << LPC_USB_INT_DEV));
+
+       ao_arch_release_interrupts();
+
+       lpc_usb.devcmdstat = 0;
+       for (t = 0; t < 1000; t++)
+               ao_arch_nop();
+
+       ao_usb_set_ep0();
+
+#if HAS_USB_PULLUP
+       ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 1);
+#endif
+}
+
+#if USB_ECHO
+struct ao_task ao_usb_echo_task;
+
+static void
+ao_usb_echo(void)
+{
+       char    c;
+
+       for (;;) {
+               c = ao_usb_getchar();
+               ao_usb_putchar(c);
+               ao_usb_flush();
+       }
+}
+#endif
+
+#if USB_DEBUG
+static void
+ao_usb_irq(void)
+{
+       printf ("control: %d out: %d in: %d int: %d reset: %d\n",
+               control_count, out_count, in_count, int_count, reset_count);
+}
+
+__code struct ao_cmds ao_usb_cmds[] = {
+       { ao_usb_irq, "I\0Show USB interrupt counts" },
+       { 0, NULL }
+};
+#endif
+
+void
+ao_usb_init(void)
+{
+#if HAS_USB_PULLUP
+       ao_enable_output(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 0);
+#endif
+
+       ao_usb_enable();
+
+       debug ("ao_usb_init\n");
+#if USB_ECHO
+       ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo");
+#endif
+#if USB_DEBUG
+       ao_cmd_register(&ao_usb_cmds[0]);
+#endif
+#if USE_USB_STDIO
+       ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
+#endif
+}
+
+#if TX_DBG || RX_DBG
+
+struct ao_usb_dbg {
+       int             line;
+       char            *msg;
+       uint32_t        value;
+       uint32_t        primask;
+#if TX_DBG
+       uint16_t        in_count;
+       uint32_t        in_ep;
+       uint32_t        in_pending;
+       uint32_t        tx_count;
+       uint32_t        in_flushed;
+#endif
+#if RX_DBG
+       uint8_t         rx_count;
+       uint8_t         rx_pos;
+       uint8_t         out_avail;
+       uint32_t        out_ep;
+#endif
+};
+
+#define NUM_USB_DBG    8
+
+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;
+       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 TX_DBG
+       dbg[dbg_i].in_count = in_count;
+       dbg[dbg_i].in_ep = *ao_usb_epn_in(AO_USB_IN_EP);
+       dbg[dbg_i].in_pending = ao_usb_in_pending;
+       dbg[dbg_i].tx_count = ao_usb_tx_count;
+       dbg[dbg_i].in_flushed = ao_usb_in_flushed;
+#endif
+#if RX_DBG
+       dbg[dbg_i].rx_count = ao_usb_rx_count;
+       dbg[dbg_i].rx_pos = ao_usb_rx_pos;
+       dbg[dbg_i].out_avail = ao_usb_out_avail;
+       dbg[dbg_i].out_ep = *ao_usb_epn_out(AO_USB_OUT_EP);
+#endif
+       if (++dbg_i == NUM_USB_DBG)
+               dbg_i = 0;
+}
+#endif
diff --git a/src/lpc/baud_rate b/src/lpc/baud_rate
new file mode 100644 (file)
index 0000000..2bfbf30
--- /dev/null
@@ -0,0 +1,131 @@
+#!/usr/bin/env nickle
+
+/*
+ * Given a main clock frequency,
+ * compute USART clock freq and a table
+ * of USART config parameters for our target baud rates
+ */
+
+real main_clock = 0;
+real usart_clock = 0;
+
+real[] baud_rates = { 4800, 9600, 19200, 57600, 115200 };
+
+void
+compute_baud_rate(real rate) {
+       int     divaddval;
+       int     mulval;
+
+       real    dl_est = usart_clock / (16 * rate);
+
+       if (dl_est == floor(dl_est)) {
+               divaddval = 0;
+               mulval = 1;
+       } else {
+               if (false) {
+
+                       /* This is how the docs suggest doing it; this
+                        * generates a rate which is reasonably close
+                        */
+
+                       real fr_est = 1.5;
+
+                       /* Compute fractional estimate */
+                       do {
+                               dl_est = floor(usart_clock / (16 * rate * fr_est) + 0.5);
+                               fr_est = usart_clock / (16 * rate * dl_est);
+                       } while (fr_est <= 1.1 || 1.9 <= fr_est);
+
+                       /* Given fractional estimate, compute divaddval/mulvals that work best */
+
+                       real best_dist = 1000;
+                       for (int tmp_divaddval = 1; tmp_divaddval < 15; tmp_divaddval++) {
+                               for (int tmp_mulval = 1; tmp_mulval < 16; tmp_mulval++) {
+                                       real fr = 1 + tmp_divaddval / tmp_mulval;
+                                       real dist = abs(fr - fr_est);
+                                       if (dist < best_dist) {
+                                               divaddval = tmp_divaddval;
+                                               mulval = tmp_mulval;
+                                               best_dist = dist;
+                                       }
+                               }
+                       }
+               } else {
+
+                       /* This exhaustively searches for the best match */
+
+                       real my_best_dist = 1e20;
+                       int my_best_dl;
+                       int my_best_divaddval;
+                       int my_best_mulval;
+                       for (int my_dl = 1; my_dl < 1024; my_dl++) {
+                               for (int my_mulval = 1; my_mulval < 16; my_mulval++) {
+                                       for (int my_divaddval = 0; my_divaddval < my_mulval; my_divaddval++) {
+                                               real my_rate = usart_clock / ((16 * my_dl) * (1 + my_divaddval/my_mulval));
+
+                                               real my_dist = abs(rate - my_rate);
+
+                                               if (my_dist == 0 && my_divaddval == 0) {
+                                                       my_dist = -1;
+                                               }
+
+                                               if (my_dist < my_best_dist) {
+                                                       my_best_dl = my_dl;
+                                                       my_best_divaddval = my_divaddval;
+                                                       my_best_mulval = my_mulval;
+                                                       my_best_dist = my_dist;
+                                               }
+                                       }
+                               }
+                       }
+
+                       dl_est = my_best_dl;
+                       divaddval = my_best_divaddval;
+                       mulval = my_best_mulval;
+               }
+       }
+
+       int dl = floor (dl_est);        
+
+       real actual = usart_clock / ((16 * dl) * (1 + divaddval/mulval));
+
+       printf("\t[AO_SERIAL_SPEED_%d] = { /* actual = %8.2f */\n", floor(rate), actual);
+       printf("\t\t.dl = %d,\n", dl);
+       printf("\t\t.divaddval = %d,\n", divaddval);
+       printf("\t\t.mulval = %d\n", mulval);
+       printf("\t},\n");
+}
+
+void
+main() {
+       if (dim(argv) < 2) {
+               printf ("usage: %s <main-clock>\n", argv[0]);
+               exit(1);
+       }
+       main_clock = string_to_real(argv[1]);
+
+       for (int div = 0; div < 4; div++) {
+               if (main_clock / (1 << div) <= 12000000) {
+                       usart_clock = main_clock / (1 << div);
+                       break;
+               }
+       }
+
+       if (usart_clock == 0) {
+               printf ("can't get usart clock in range\n");
+               exit(1);
+       }
+
+       printf ("#define AO_LPC_USARTCLK %d\n\n", floor(usart_clock));
+       printf("static const struct {\n");
+       printf("\tuint16_t dl;\n");
+       printf("\tuint8_t divaddval;\n");
+       printf("\tuint8_t mulval;\n");
+       printf("} ao_usart_speeds[] = {\n");
+       for (int i = 0; i < dim(baud_rates); i++) {
+               compute_baud_rate(baud_rates[i]);
+       }
+       printf ("};\n");
+}
+
+main();
diff --git a/src/lpc/figure-checksum b/src/lpc/figure-checksum
new file mode 100755 (executable)
index 0000000..0b1de57
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env nickle
+
+autoimport Process;
+
+int byteflip(int x) {
+       return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | ((x << 24) & 0xff000000);
+}
+
+void main () {
+       file    input = popen(popen_direction.read, true, "objdump",
+                             "objdump", "-j", ".text",
+                             "--start-address=0",
+                             "--stop-address=0x20",
+                             "-s", argv[1]);
+       int sum = 0;
+
+       void add_in(int addr, int value) {
+               if (addr < 0x1c) {
+                       sum += value;
+               } else if (addr == 0x1c) {
+                       printf ("-DCKSUM=0x%08x\n", -sum & 0xffffffff);
+                       exit(0);
+               }
+       }
+       while (!File::end(input)) {
+               string line = File::fgets(input);
+               string[] words = String::wordsplit(line, " ");
+
+               if (dim(words) < 5)
+                   continue;
+               if (words[0] == "0000" || words[0] == "0010") {
+                       int addr = string_to_integer(words[0], 16);
+                       for (int i = 0; i < 4; i++)
+                               add_in(addr + i * 4, byteflip(string_to_integer(words[i+1], 16)));
+               }
+       }
+}
+
+main();
diff --git a/src/lpc/lpc.h b/src/lpc/lpc.h
new file mode 100644 (file)
index 0000000..3300c86
--- /dev/null
@@ -0,0 +1,1249 @@
+/*
+ * 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.
+ */
+
+#ifndef _LPC_H_
+#define _LPC_H_
+
+#include <stdint.h>
+
+typedef volatile uint32_t      vuint32_t;
+typedef volatile uint16_t      vuint16_t;
+typedef volatile uint8_t       vuint8_t;
+typedef volatile void *                vvoid_t;
+
+struct lpc_ioconf {
+       vuint32_t       pio0_0;
+       vuint32_t       pio0_1;
+       vuint32_t       pio0_2;
+       vuint32_t       pio0_3;
+
+       vuint32_t       pio0_4;
+       vuint32_t       pio0_5;
+       vuint32_t       pio0_6;
+       vuint32_t       pio0_7;
+
+       vuint32_t       pio0_8;
+       vuint32_t       pio0_9;
+       vuint32_t       pio0_10;
+       vuint32_t       pio0_11;
+
+       vuint32_t       pio0_12;
+       vuint32_t       pio0_13;
+       vuint32_t       pio0_14;
+       vuint32_t       pio0_15;
+
+       vuint32_t       pio0_16;
+       vuint32_t       pio0_17;
+       vuint32_t       pio0_18;
+       vuint32_t       pio0_19;
+
+       vuint32_t       pio0_20;
+       vuint32_t       pio0_21;
+       vuint32_t       pio0_22;
+       vuint32_t       pio0_23;
+
+       vuint32_t       pio1_0;         /* 0x60 */
+       vuint32_t       pio1_1;
+       vuint32_t       pio1_2;
+       vuint32_t       pio1_3;
+
+       vuint32_t       pio1_4;
+       vuint32_t       pio1_5;
+       vuint32_t       pio1_6;
+       vuint32_t       pio1_7;
+
+       vuint32_t       pio1_8;         /* 0x80 */
+       vuint32_t       pio1_9;
+       vuint32_t       pio1_10;
+       vuint32_t       pio1_11;
+
+       vuint32_t       pio1_12;
+       vuint32_t       pio1_13;
+       vuint32_t       pio1_14;
+       vuint32_t       pio1_15;
+
+       vuint32_t       pio1_16;        /* 0xa0 */
+       vuint32_t       pio1_17;
+       vuint32_t       pio1_18;
+       vuint32_t       pio1_19;
+
+       vuint32_t       pio1_20;
+       vuint32_t       pio1_21;
+       vuint32_t       pio1_22;
+       vuint32_t       pio1_23;
+
+       vuint32_t       pio1_24;        /* 0xc0 */
+       vuint32_t       pio1_25;
+       vuint32_t       pio1_26;
+       vuint32_t       pio1_27;
+
+       vuint32_t       pio1_28;
+       vuint32_t       pio1_29;
+       vuint32_t       pio1_30;
+       vuint32_t       pio1_31;
+};
+
+extern struct lpc_ioconf lpc_ioconf;
+
+#define LPC_IOCONF_FUNC                0
+
+/* PIO0_0 */
+#define  LPC_IOCONF_FUNC_RESET         0
+#define  LPC_IOCONF_FUNC_PIO0_0                1
+
+/* PIO0_1 */
+#define  LPC_IOCONF_FUNC_PIO0_1                0
+#define  LPC_IOCONF_FUNC_CLKOUT                1
+#define  LPC_IOCONF_FUNC_CT32B0_MAT2   2
+#define  LPC_IOCONF_FUNC_USB_FTOGGLE   3
+
+/* PIO0_2 */
+#define  LPC_IOCONF_FUNC_PIO0_2                0
+#define  LPC_IOCONF_FUNC_SSEL0         1
+#define  LPC_IOCONF_FUNC_CT16B0_CAP0   2
+
+/* PIO0_3 */
+#define  LPC_IOCONF_FUNC_PIO0_3                0
+#define  LPC_IOCONF_FUNC_USB_VBUS      1
+
+/* PIO0_4
+#define  LPC_IOCONF_FUNC_PIO0_4                0
+#define  LPC_IOCONF_FUNC_I2C_SCL       1
+
+/* PIO0_5 */
+#define  LPC_IOCONF_FUNC_PIO0_5                0
+#define  LPC_IOCONF_FUNC_I2C_SDA       1
+
+/* PIO0_6 */
+#define  LPC_IOCONF_FUNC_PIO0_6                0
+#define  LPC_IOCONF_FUNC_USB_CONNECT   1
+#define  LPC_IOCONF_FUNC_PIO0_6_SCK0   2
+
+/* PIO0_7 */
+#define  LPC_IOCONF_FUNC_PIO0_7                0
+#define  LPC_IOCONF_FUNC_CTS           1
+
+/* PIO0_8 */
+#define  LPC_IOCONF_FUNC_PIO0_8                0
+#define  LPC_IOCONF_FUNC_MISO0         1
+#define  LPC_IOCONF_FUNC_CT16B0_MAT0   2
+
+/* PIO0_9 */
+#define  LPC_IOCONF_FUNC_PIO0_9                0
+#define  LPC_IOCONF_FUNC_MOSI0         1
+#define  LPC_IOCONF_FUNC_CT16B0_MAT1   2
+
+/* PIO0_10 */
+#define  LPC_IOCONF_FUNC_SWCLK         0
+#define  LPC_IOCONF_FUNC_PIO0_10       1
+#define  LPC_IOCONF_FUNC_PIO0_10_SCK0  2
+#define  LPC_IOCONF_FUNC_CT16B0_MAT2   3
+
+/* PIO0_11 */
+#define  LPC_IOCONF_FUNC_TDI           0
+#define  LPC_IOCONF_FUNC_PIO0_11       1
+#define  LPC_IOCONF_FUNC_AD0           2
+#define  LPC_IOCONF_FUNC_CT32B0_MAT3   3
+
+/* PIO0_12 */
+#define  LPC_IOCONF_FUNC_TMS           0
+#define  LPC_IOCONF_FUNC_PIO0_12       1
+#define  LPC_IOCONF_FUNC_AD1           2
+#define  LPC_IOCONF_FUNC_CT32B1_CAP0   3
+
+/* PIO0_13 */
+#define  LPC_IOCONF_FUNC_TD0           0
+#define  LPC_IOCONF_FUNC_PIO0_13       1
+#define  LPC_IOCONF_FUNC_AD2           2
+#define  LPC_IOCONF_FUNC_CT32B1_MAT0   3
+
+/* PIO0_14 */
+#define  LPC_IOCONF_FUNC_TRST          0
+#define  LPC_IOCONF_FUNC_PIO0_14       1
+#define  LPC_IOCONF_FUNC_AD3           2
+#define  LPC_IOCONF_FUNC_PIO0_14_CT32B1_MAT1   3
+
+/* PIO0_15 */
+#define  LPC_IOCONF_FUNC_SWDIO         0
+#define  LPC_IOCONF_FUNC_PIO0_15       1
+#define  LPC_IOCONF_FUNC_AD4           2
+#define  LPC_IOCONF_FUNC_CT32B1_MAT2   3
+
+/* PIO0_16 */
+#define  LPC_IOCONF_FUNC_PIO0_16       0
+#define  LPC_IOCONF_FUNC_AD5           1
+#define  LPC_IOCONF_FUNC_CT32B1_MAT3   2
+
+/* PIO0_17 */
+#define  LPC_IOCONF_FUNC_PIO0_17       0
+#define  LPC_IOCONF_FUNC_RTS           1
+#define  LPC_IOCONF_FUNC_CT32B0_CAP0   2
+#define  LPC_IOCONF_FUNC_SCLK          3
+
+/* PIO0_18 */
+#define  LPC_IOCONF_FUNC_PIO0_18               0
+#define  LPC_IOCONF_FUNC_PIO0_18_RXD           1
+#define  LPC_IOCONF_FUNC_PIO0_18_CT32B0_MAT0   2
+
+/* PIO0_19 */
+#define  LPC_IOCONF_FUNC_PIO0_19               0
+#define  LPC_IOCONF_FUNC_PIO0_19_TXD           1
+#define  LPC_IOCONF_FUNC_PIO0_19_CT32B0_MAT1   2
+
+/* PIO0_20 */
+#define  LPC_IOCONF_FUNC_PIO0_20       0
+#define  LPC_IOCONF_FUNC_CT16B1_CAP0   1
+
+/* PIO0_21 */
+#define  LPC_IOCONF_FUNC_PIO0_21       0
+#define  LPC_IOCONF_FUNC_CT16B1_MAT0   1
+#define  LPC_IOCONF_FUNC_PIO0_21_MOSI1 2
+
+/* PIO0_22 */
+#define  LPC_IOCONF_FUNC_PIO0_22       0
+#define  LPC_IOCONF_FUNC_AD6           1
+#define  LPC_IOCONF_FUNC_CT16B1_MAT1   2
+#define  LPC_IOCONF_FUNC_PIO0_22_MISO1 3
+
+/* PIO0_23 */
+#define  LPC_IOCONF_FUNC_PIO0_23       0
+#define  LPC_IOCONF_FUNC_AD7           1
+
+/* PIO1_0 */
+#define  LPC_IOCONF_FUNC_PIO1_0                0
+#define  LPC_IOCONF_FUNC_CT32B1_MAT1   1
+
+/* PIO1_1 */
+#define  LPC_IOCONF_FUNC_PIO1_1                0
+#define  LPC_IOCONF_FUNC_CT32B1_MAT1   1
+
+/* PIO1_2 */
+#define  LPC_IOCONF_FUNC_PIO1_2                0
+#define  LPC_IOCONF_FUNC_PIO1_2_CT32B1_MAT2    1
+
+/* PIO1_3*/
+#define  LPC_IOCONF_FUNC_PIO1_3                0
+#define  LPC_IOCONF_FUNC_PIO1_3_CT32B1_MAT3    1
+
+/* PIO1_4 */
+#define  LPC_IOCONF_FUNC_PIO1_4                0
+#define  LPC_IOCONF_FUNC_PIO1_4_CT32B1_CAP0    1
+
+/* PIO1_5 */
+#define  LPC_IOCONF_FUNC_PIO1_5                0
+#define  LPC_IOCONF_FUNC_CT32B1_CAP1   1
+
+/* PIO1_6 */
+#define  LPC_IOCONF_FUNC_PIO1_6                0
+
+/* PIO1_7 */
+#define  LPC_IOCONF_FUNC_PIO1_7                0
+
+/* PIO1_8 */
+#define  LPC_IOCONF_FUNC_PIO1_8                0
+
+/* PIO1_9 */
+#define  LPC_IOCONF_FUNC_PIO1_9                0
+
+/* PIO1_10 */
+#define  LPC_IOCONF_FUNC_PIO1_10       0
+
+/* PIO1_11 */
+#define  LPC_IOCONF_FUNC_PIO1_11       0
+
+/* PIO1_12 */
+#define  LPC_IOCONF_FUNC_PIO1_12       0
+
+/* PIO1_13 */
+#define  LPC_IOCONF_FUNC_PIO1_13       0
+#define  LPC_IOCONF_FUNC_DTR           1
+#define  LPC_IOCONF_FUNC_CT16B0_MAT0   2
+#define  LPC_IOCONF_FUNC_PIO1_13_TXD           3
+
+/* PIO1_14 */
+#define  LPC_IOCONF_FUNC_PIO1_14       0
+#define  LPC_IOCONF_FUNC_DSR           1
+#define  LPC_IOCONF_FUNC_CT16B0_MAT1   2
+#define  LPC_IOCONF_FUNC_PIO1_13_RXD           3
+
+/* PIO1_15 */
+#define  LPC_IOCONF_FUNC_PIO1_15       0
+#define  LPC_IOCONF_FUNC_DCD           1
+#define  LPC_IOCONF_FUNC_PIO1_15_CT16B0_MAT2   2
+#define  LPC_IOCONF_FUNC_PIO1_15_SCK1  3
+
+/* PIO1_16 */
+#define  LPC_IOCONF_FUNC_PIO1_16       0
+#define  LPC_IOCONF_FUNC_RI            1
+#define  LPC_IOCONF_FUNC_CT16B0_CAP0   2
+
+/* PIO1_17 */
+#define  LPC_IOCONF_FUNC_PIO1_17       0
+#define  LPC_IOCONF_FUNC_CT16B0_CAP1   1
+#define  LPC_IOCONF_FUNC_PIO1_17_RXD           2
+
+/* PIO1_18 */
+#define  LPC_IOCONF_FUNC_PIO1_18       0
+#define  LPC_IOCONF_FUNC_CT16B1_CAP1   1
+#define  LPC_IOCONF_FUNC_PIO1_18_TXD           2
+
+/* PIO1_19 */
+#define  LPC_IOCONF_FUNC_PIO1_19       0
+#define  LPC_IOCONF_FUNC_DTR           1
+#define  LPC_IOCONF_FUNC_SSEL1         2
+
+/* PIO1_20 */
+#define  LPC_IOCONF_FUNC_PIO1_20       0
+#define  LPC_IOCONF_FUNC_DSR           1
+#define  LPC_IOCONF_FUNC_PIO1_20_SCK1          2
+
+/* PIO1_21 */
+#define  LPC_IOCONF_FUNC_PIO1_21       0
+#define  LPC_IOCONF_FUNC_DCD           1
+#define  LPC_IOCONF_FUNC_PIO1_21_MISO1         2
+
+/* PIO1_22 */
+#define  LPC_IOCONF_FUNC_PIO1_22       0
+#define  LPC_IOCONF_FUNC_RI            1
+#define  LPC_IOCONF_FUNC_PIO1_22_MOSI1 2
+
+/* PIO1_23 */
+#define  LPC_IOCONF_FUNC_PIO1_23       0
+#define  LPC_IOCONF_FUNC_PIO1_23_CT16B1_MAT1   1
+#define  LPC_IOCONF_FUNC_SSEL1         2
+
+/* PIO1_24 */
+#define  LPC_IOCONF_FUNC_PIO1_24       0
+#define  LPC_IOCONF_FUNC_PIO1_24_CT32B0_MAT0   1
+
+/* PIO1_25 */
+#define  LPC_IOCONF_FUNC_PIO1_25       0
+#define  LPC_IOCONF_FUNC_PIO1_25_CT32B0_MAT1   1
+
+/* PIO1_26 */
+#define  LPC_IOCONF_FUNC_PIO1_26       0
+#define  LPC_IOCONF_FUNC_PIO1_26_CT32B0_MAT2   1
+#define  LPC_IOCONF_FUNC_PIO1_26_RXD           2
+
+/* PIO1_27 */
+#define  LPC_IOCONF_FUNC_PIO1_27       0
+#define  LPC_IOCONF_FUNC_PIO1_27_CT32B0_MAT3   1
+#define  LPC_IOCONF_FUNC_PIO1_27_TXD           2
+
+/* PIO1_28 */
+#define  LPC_IOCONF_FUNC_PIO1_28       0
+#define  LPC_IOCONF_FUNC_PIO1_28_CT32B0_CAP0   1
+#define  LPC_IOCONF_FUNC_PIO1_28_SCLK          2
+
+/* PIO1_29 */
+#define  LPC_IOCONF_FUNC_PIO1_29               0
+#define  LPC_IOCONF_FUNC_PIO1_29_SCK0          1
+#define  LPC_IOCONF_FUNC_PIO1_29_CT32B0_CAP1   2
+
+/* PIO1_31 */
+#define  LPC_IOCONF_FUNC_PIO1_31       0
+
+#define  LPC_IOCONF_FUNC_MASK          0x7
+
+#define ao_lpc_alternate(func) (((func) << LPC_IOCONF_FUNC) | \
+                               (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) | \
+                               (0 << LPC_IOCONF_HYS) |                 \
+                               (0 << LPC_IOCONF_INV) |                 \
+                               (0 << LPC_IOCONF_OD) |                  \
+                               0x80)
+
+#define LPC_IOCONF_MODE                        3
+#define  LPC_IOCONF_MODE_INACTIVE              0
+#define  LPC_IOCONF_MODE_PULL_DOWN             1
+#define  LPC_IOCONF_MODE_PULL_UP               2
+#define  LPC_IOCONF_MODE_REPEATER              3
+#define  LPC_IOCONF_MODE_MASK                  3
+
+#define LPC_IOCONF_HYS                 5
+
+#define LPC_IOCONF_INV                 6
+#define LPC_IOCONF_ADMODE              7
+#define LPC_IOCONF_FILTR               8
+#define LPC_IOCONF_OD                  10
+
+struct lpc_scb {
+       vuint32_t       sysmemremap;    /* 0x00 */
+       vuint32_t       presetctrl;
+       vuint32_t       syspllctrl;
+       vuint32_t       syspllstat;
+
+       vuint32_t       usbpllctrl;     /* 0x10 */
+       vuint32_t       usbpllstat;
+       uint32_t        r18;
+       uint32_t        r1c;
+
+       vuint32_t       sysoscctrl;     /* 0x20 */
+       vuint32_t       wdtoscctrl;
+       uint32_t        r28;
+       uint32_t        r2c;
+
+       vuint32_t       sysrststat;     /* 0x30 */
+       uint32_t        r34;
+       uint32_t        r38;
+       uint32_t        r3c;
+
+       vuint32_t       syspllclksel;   /* 0x40 */
+       vuint32_t       syspllclkuen;
+       vuint32_t       usbpllclksel;
+       vuint32_t       usbpllclkuen;
+
+       uint32_t        r50[8];
+
+       vuint32_t       mainclksel;     /* 0x70 */
+       vuint32_t       mainclkuen;
+       vuint32_t       sysahbclkdiv;
+       uint32_t        r7c;            
+
+       vuint32_t       sysahbclkctrl;  /* 0x80 */
+       uint32_t        r84[3];
+
+       uint32_t        r90;            /* 0x90 */
+       vuint32_t       ssp0clkdiv;
+       vuint32_t       uartclkdiv;
+       vuint32_t       ssp1clkdiv;
+
+       uint32_t        ra0[8];
+
+       vuint32_t       usbclksel;      /* 0xc0 */
+       vuint32_t       usbclkuen;
+       vuint32_t       usbclkdiv;
+       uint32_t        rcc;
+
+       uint32_t        rd0[4];
+       
+       vuint32_t       clkoutsel;      /* 0xe0 */
+       vuint32_t       clkoutuen;
+       vuint32_t       clkoutdiv;
+       uint32_t        rec;
+       
+       uint32_t        rf0[4];         /* 0xf0 */
+       
+       vuint32_t       pioporcap0;     /* 0x100 */
+       vuint32_t       pioporcap1;
+       uint32_t        r102[2];
+
+       uint32_t        r110[4];        /* 0x110 */
+       uint32_t        r120[4];        /* 0x120 */
+       uint32_t        r130[4];        /* 0x130 */
+       uint32_t        r140[4];        /* 0x140 */
+       
+       vuint32_t       bodctrl;        /* 0x150 */
+       vuint32_t       systckcal;
+       uint32_t        r158[2];
+
+       uint32_t        r160[4];        /* 0x160 */
+
+       vuint32_t       irqlatency;     /* 0x170 */
+       vuint32_t       nmisrc;
+       vuint32_t       pintsel[8];
+
+       vuint32_t       usbclkctrl;     /* 0x198 */
+       vuint32_t       usbclkst;
+
+       uint32_t        r1a0[6*4];      /* 0x1a0 */
+
+       uint32_t        r200;           /* 0x200 */
+       vuint32_t       starterp0;
+       uint32_t        r208[2];
+
+       uint32_t        r210;           /* 0x210 */
+       vuint32_t       starterp1;
+       uint32_t        r218[2];
+
+       uint32_t        r220[4];        /* 0x220 */
+
+       vuint32_t       pdsleepcfg;     /* 0x230 */
+       vuint32_t       pdawakecfg;
+       vuint32_t       pdruncfg;
+       uint32_t        r23c;
+
+       uint32_t        r240[12 * 4];   /* 0x240 */
+
+       uint32_t        r300[15 * 4];   /* 0x300 */
+                            
+       uint32_t        r3f0;           /* 0x3f0 */
+       vuint32_t       device_id;
+};
+
+extern struct lpc_scb lpc_scb;
+
+#define LPC_SCB_SYSMEMREMAP_MAP                0
+# define LPC_SCB_SYSMEMREMAP_MAP_BOOT_LOADER   0
+# define LPC_SCB_SYSMEMREMAP_MAP_RAM           1
+# define LPC_SCB_SYSMEMREMAP_MAP_FLASH         2
+
+#define LPC_SCB_PRESETCTRL_SSP0_RST_N  0
+#define LPC_SCB_PRESETCTRL_I2C_RST_N   1
+#define LPC_SCB_PRESETCTRL_SSP1_RST_N  2
+
+#define LPC_SCB_SYSPLLCTRL_MSEL                0
+#define LPC_SCB_SYSPLLCTRL_PSEL                5
+#define  LPC_SCB_SYSPLLCTRL_PSEL_1             0
+#define  LPC_SCB_SYSPLLCTRL_PSEL_2             1
+#define  LPC_SCB_SYSPLLCTRL_PSEL_4             2
+#define  LPC_SCB_SYSPLLCTRL_PSEL_8             3
+#define  LPC_SCB_SYSPLLCTRL_PSEL_MASK          3
+
+#define LPC_SCB_SYSPLLSTAT_LOCK                0
+
+#define LPC_SCB_USBPLLCTRL_MSEL                0
+#define LPC_SCB_USBPLLCTRL_PSEL                5
+#define  LPC_SCB_USBPLLCTRL_PSEL_1             0
+#define  LPC_SCB_USBPLLCTRL_PSEL_2             1
+#define  LPC_SCB_USBPLLCTRL_PSEL_4             2
+#define  LPC_SCB_USBPLLCTRL_PSEL_8             3
+#define  LPC_SCB_USBPLLCTRL_PSEL_MASK          3
+
+#define LPC_SCB_USBPLLSTAT_LOCK                0
+
+#define LPC_SCB_SYSOSCCTRL_BYPASS      0
+#define LPC_SCB_SYSOSCCTRL_FREQRANGE   1
+#define  LPC_SCB_SYSOSCCTRL_FREQRANGE_1_20     0
+#define  LPC_SCB_SYSOSCCTRL_FREQRANGE_15_25    1
+
+#define LPC_SCB_WDTOSCCTRL_DIVSEL              0
+#define  LPC_SCB_WDTOSCCTRL_DIVSEL_MASK                        0x1f
+#define LPC_SCB_WDTOSCCTRL_FREQSEL             5
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_0_6                        1
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_1_05               2
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_1_4                        3
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_1_75               4
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_2_1                        5
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_2_4                        6
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_2_7                        7
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_3_0                        8
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_3_25               9
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_3_5                        0x0a
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_3_75               0x0b
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_4_0                        0x0c
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_4_2                        0x0d
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_4_4                        0x0e
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_4_6                        0x0f
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_MASK               0x0f
+
+#define LPC_SCB_SYSRSTSTAT_POR         0
+#define LPC_SCB_SYSRSTSTAT_EXTRST      1
+#define LPC_SCB_SYSRSTSTAT_WDT         2
+#define LPC_SCB_SYSRSTSTAT_BOD         3
+#define LPC_SCB_SYSRSTSTAT_SYSRST      4
+
+#define LPC_SCB_SYSPLLCLKSEL_SEL       0
+#define  LPC_SCB_SYSPLLCLKSEL_SEL_IRC          0
+#define  LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC       1
+#define  LPC_SCB_SYSPLLCLKSEL_SEL_MASK         3
+
+#define LPC_SCB_SYSPLLCLKUEN_ENA       0
+
+#define LPC_SCB_USBPLLCLKSEL_SEL       0
+#define  LPC_SCB_USBPLLCLKSEL_SEL_IRC          0
+#define  LPC_SCB_USBPLLCLKSEL_SEL_SYSOSC       1
+#define  LPC_SCB_USBPLLCLKSEL_SEL_MASK         3
+
+#define LPC_SCB_USBPLLCLKUEN_ENA       0
+
+#define LPC_SCB_MAINCLKSEL_SEL         0
+#define  LPC_SCB_MAINCLKSEL_SEL_IRC            0
+#define  LPC_SCB_MAINCLKSEL_SEL_PLL_INPUT      1
+#define  LPC_SCB_MAINCLKSEL_SEL_WATCHDOG       2
+#define  LPC_SCB_MAINCLKSEL_SEL_PLL_OUTPUT     3
+#define  LPC_SCB_MAINCLKSEL_SEL_MASK           3
+
+#define LPC_SCB_MAINCLKUEN_ENA         0
+
+#define LPC_SCB_SYSAHBCLKDIV_DIV       0
+
+#define LPC_SCB_SYSAHBCLKCTRL_SYS      0
+#define LPC_SCB_SYSAHBCLKCTRL_ROM      1
+#define LPC_SCB_SYSAHBCLKCTRL_RAM0     2
+#define LPC_SCB_SYSAHBCLKCTRL_FLASHREG 3
+#define LPC_SCB_SYSAHBCLKCTRL_FLASHARRAY       4
+#define LPC_SCB_SYSAHBCLKCTRL_I2C      5
+#define LPC_SCB_SYSAHBCLKCTRL_GPIO     6
+#define LPC_SCB_SYSAHBCLKCTRL_CT16B0   7
+#define LPC_SCB_SYSAHBCLKCTRL_CT16B1   8
+#define LPC_SCB_SYSAHBCLKCTRL_CT32B0   9
+#define LPC_SCB_SYSAHBCLKCTRL_CT32B1   10
+#define LPC_SCB_SYSAHBCLKCTRL_SSP0     11
+#define LPC_SCB_SYSAHBCLKCTRL_USART    12
+#define LPC_SCB_SYSAHBCLKCTRL_ADC      13
+#define LPC_SCB_SYSAHBCLKCTRL_USB      14
+#define LPC_SCB_SYSAHBCLKCTRL_WWDT     15
+#define LPC_SCB_SYSAHBCLKCTRL_IOCON    16
+#define LPC_SCB_SYSAHBCLKCTRL_SSP1     18
+#define LPC_SCB_SYSAHBCLKCTRL_PINT     19
+#define LPC_SCB_SYSAHBCLKCTRL_GROUP0INT        23
+#define LPC_SCB_SYSAHBCLKCTRL_GROUP1INT        24
+#define LPC_SCB_SYSAHBCLKCTRL_RAM1     26
+#define LPC_SCB_SYSAHBCLKCTRL_USBRAM   27
+
+#define LPC_SCB_SSP0CLKDIV_
+#define LPC_SCB_UARTCLKDIV_
+#define LPC_SCB_SSP1CLKDIV_
+
+#define LPC_SCB_USBCLKSEL_SEL          0
+#define LPC_SCB_USBCLKSEL_SEL_USB_PLL          0
+#define LPC_SCB_USBCLKSEL_SEL_MAIN_CLOCK       1
+
+#define LPC_SCB_USBCLKUEN_ENA          0
+#define LPC_SCB_USBCLKDIV_DIV          0
+
+#define LPC_SCB_CLKOUTSEL_SEL          0
+#define  LPC_SCB_CLKOUTSEL_SEL_IRC             0
+#define  LPC_SCB_CLKOUTSEL_SEL_SYSOSC          1
+#define  LPC_SCB_CLKOUTSEL_SEL_LF              2
+#define  LPC_SCB_CLKOUTSEL_SEL_MAIN_CLOCK      3
+
+#define LPC_SCB_CLKOUTUEN_ENA          0
+
+#define LPC_SCB_BOD_BODRSTLEV          0
+# define LPC_SCB_BOD_BODRSTLEV_1_46            0
+# define LPC_SCB_BOD_BODRSTLEV_2_06            1
+# define LPC_SCB_BOD_BODRSTLEV_2_35            2
+# define LPC_SCB_BOD_BODRSTLEV_2_63            3
+#define LPC_SCB_BOD_BODINTVAL          2
+# define LPC_SCB_BOD_BODINTVAL_RESERVED                0
+# define LPC_SCB_BOD_BODINTVAL_2_22            1
+# define LPC_SCB_BOD_BODINTVAL_2_52            2
+# define LPC_SCB_BOD_BODINTVAL_2_80            3
+#define LPC_SCB_BOD_BODRSTENA          4
+
+#define LPC_SCB_PDRUNCFG_IRCOUT_PD     0
+#define LPC_SCB_PDRUNCFG_IRC_PD                1
+#define LPC_SCB_PDRUNCFG_FLASH_PD      2
+#define LPC_SCB_PDRUNCFG_BOD_PD                3
+#define LPC_SCB_PDRUNCFG_ADC_PD                4
+#define LPC_SCB_PDRUNCFG_SYSOSC_PD     5
+#define LPC_SCB_PDRUNCFG_WDTOSC_PD     6
+#define LPC_SCB_PDRUNCFG_SYSPLL_PD     7
+#define LPC_SCB_PDRUNCFG_USBPLL_PD     8
+#define LPC_SCB_PDRUNCFG_USBPAD_PD     10
+
+struct lpc_flash {
+       uint32_t        r0[4];          /* 0x0 */
+
+       vuint32_t       flashcfg;       /* 0x10 */
+};
+
+extern struct lpc_flash lpc_flash;
+
+struct lpc_gpio_pin {
+       vuint32_t       isel;           /* 0x00 */
+       vuint32_t       ienr;
+       vuint32_t       sienr;
+       vuint32_t       cienr;
+
+       vuint32_t       ienf;           /* 0x10 */
+       vuint32_t       sienf;
+       vuint32_t       cienf;
+       vuint32_t       rise;
+
+       vuint32_t       fall;           /* 0x20 */
+       vuint32_t       ist;
+};
+
+extern struct lpc_gpio_pin lpc_gpio_pin;
+
+struct lpc_gpio_group0 {
+};
+
+extern struct lpc_gpio_group0 lpc_gpio_group0;
+
+struct lpc_gpio_group1 {
+};
+
+extern struct lpc_gpio_group1 lpc_gpio_group1;
+
+struct lpc_gpio {
+       vuint8_t        byte[0x40];     /* 0x0000 */
+
+       uint8_t         r0030[0x1000 - 0x40];
+
+       vuint32_t       word[0x40];     /* 0x1000 */
+
+       uint8_t         r1100[0x2000 - 0x1100];
+       
+       vuint32_t       dir[2];         /* 0x2000 */
+
+       uint8_t         r2008[0x2080 - 0x2008];
+
+       vuint32_t       mask[2];        /* 0x2080 */
+
+       uint8_t         r2088[0x2100 - 0x2088];
+
+       vuint32_t       pin[2];         /* 0x2100 */
+
+       uint8_t         r2108[0x2200 - 0x2108];
+
+       vuint32_t       set[2];         /* 0x2200 */
+
+       uint8_t         r2208[0x2280 - 0x2208];
+
+       vuint32_t       clr[2];         /* 0x2280 */
+
+       uint8_t         r2288[0x2300 - 0x2288];
+
+       vuint32_t       not[2];         /* 0x2300 */
+};
+
+extern struct lpc_gpio lpc_gpio;
+
+struct lpc_systick {
+       uint8_t         r0000[0x10];    /* 0x0000 */
+
+       vuint32_t       csr;            /* 0x0010 */
+       vuint32_t       rvr;
+       vuint32_t       cvr;
+       vuint32_t       calib;
+};
+
+extern struct lpc_systick lpc_systick;
+
+#define LPC_SYSTICK_CSR_ENABLE         0
+#define LPC_SYSTICK_CSR_TICKINT                1
+#define LPC_SYSTICK_CSR_CLKSOURCE      2
+#define  LPC_SYSTICK_CSR_CLKSOURCE_CPU_OVER_2          0
+#define  LPC_SYSTICK_CSR_CLKSOURCE_CPU                 1
+#define LPC_SYSTICK_CSR_COUNTFLAG      16
+
+struct lpc_usart {
+       vuint32_t       rbr_thr;        /* 0x0000 */
+       vuint32_t       ier;
+       vuint32_t       iir_fcr;
+       vuint32_t       lcr;
+
+       vuint32_t       mcr;            /* 0x0010 */
+       vuint32_t       lsr;
+       vuint32_t       msr;
+       vuint32_t       scr;
+
+       vuint32_t       acr;            /* 0x0020 */
+       vuint32_t       icr;
+       vuint32_t       fdr;
+       vuint32_t       osr;
+
+       vuint32_t       ter;            /* 0x0030 */
+       uint32_t        r34[3];
+
+       vuint32_t       hden;           /* 0x0040 */
+       uint32_t        r44;
+       vuint32_t       scictrl;
+       vuint32_t       rs485ctrl;
+
+       vuint32_t       rs485addrmatch; /* 0x0050 */
+       vuint32_t       rs485dly;
+       vuint32_t       syncctrl;
+};
+
+extern struct lpc_usart lpc_usart;
+
+#define LPC_USART_IER_RBRINTEN 0
+#define LPC_USART_IER_THREINTEN        1
+#define LPC_USART_IER_RSLINTEN 2
+#define LPC_USART_IER_MSINTEN  3
+#define LPC_USART_IER_ABEOINTEN        8
+#define LPC_USART_IER_ABTOINTEN        9
+
+#define LPC_USART_IIR_INTSTATUS                0
+#define LPC_USART_IIR_INTID            1
+#define LPC_USART_IIR_INTID_RLS                        3
+#define LPC_USART_IIR_INTID_RDA                        2
+#define LPC_USART_IIR_INTID_CTI                        6
+#define LPC_USART_IIR_INTID_THRE               1
+#define LPC_USART_IIR_INTID_MS                 0
+#define LPC_USART_IIR_INTID_MASK               7
+#define LPC_USART_IIR_FIFOEN           6
+#define LPC_USART_IIR_ABEOINT          8
+#define LPC_USART_IIR_ABTOINT          9
+
+#define LPC_USART_FCR_FIFOEN           0
+#define LPC_USART_FCR_RXFIFORES                1
+#define LPC_USART_FCR_TXFIFORES                2
+#define LPC_USART_FCR_RXTL             6
+#define LPC_USART_FCR_RXTL_1                   0
+#define LPC_USART_FCR_RXTL_4                   1
+#define LPC_USART_FCR_RXTL_8                   2
+#define LPC_USART_FCR_RXTL_14                  3
+
+#define LPC_USART_LCR_WLS      0
+#define LPC_USART_LCR_WLS_5            0
+#define LPC_USART_LCR_WLS_6            1
+#define LPC_USART_LCR_WLS_7            2
+#define LPC_USART_LCR_WLS_8            3
+#define LPC_USART_LCR_WLS_MASK         3
+#define LPC_USART_LCR_SBS      2
+#define LPC_USART_LCR_SBS_1            0
+#define LPC_USART_LCR_SBS_2            1
+#define LPC_USART_LCR_SBS_MASK         1
+#define LPC_USART_LCR_PE       3
+#define LPC_USART_LCR_PS       4
+#define LPC_USART_LCR_PS_ODD           0
+#define LPC_USART_LCR_PS_EVEN          1
+#define LPC_USART_LCR_PS_ONE           2
+#define LPC_USART_LCR_PS_ZERO          3
+#define LPC_USART_LCR_PS_MASK          3
+#define LPC_USART_LCR_BC       6
+#define LPC_USART_LCR_DLAB     7
+
+#define LPC_USART_MCR_DTRCTRL  0
+#define LPC_USART_MCR_RTSCTRL  1
+#define LPC_USART_MCR_LMS      4
+#define LPC_USART_MCR_RTSEN    6
+#define LPC_USART_MCR_CTSEN    7
+
+#define LPC_USART_LSR_RDR      0
+#define LPC_USART_LSR_OE       1
+#define LPC_USART_LSR_PE       2
+#define LPC_USART_LSR_FE       3
+#define LPC_USART_LSR_BI       4
+#define LPC_USART_LSR_THRE     5
+#define LPC_USART_LSR_TEMT     6
+#define LPC_USART_LSR_RXFE     7
+#define LPC_USART_LSR_TXERR    8
+
+#define LPC_USART_MSR_DCTS     0
+#define LPC_USART_MSR_DDSR     1
+#define LPC_USART_MSR_TERI     2
+#define LPC_USART_MSR_DDCD     3
+#define LPC_USART_MSR_CTS      4
+#define LPC_USART_MSR_DSR      5
+#define LPC_USART_MSR_RI       6
+#define LPC_USART_MSR_DCD      7
+
+#define LPC_USART_ACR_START    0
+#define LPC_USART_ACR_MODE     1
+#define LPC_USART_ACR_AUTORESTART      2
+#define LPC_USART_ACR_ABEOINTCLR       8
+#define LPC_USART_ACR_ABTOINTCLR       9
+
+#define LPC_USART_FDR_DIVADDVAL        0
+#define LPC_USART_FDR_MULVAL   4
+
+#define LPC_USART_OSR_OSFRAC   1
+#define LPC_USART_OSR_OSINT    4
+#define LPC_USART_OSR_FDINT    8
+
+#define LPC_USART_TER_TXEN     7
+
+#define LPC_USART_HDEN_HDEN    0
+
+struct lpc_usb {
+       vuint32_t       devcmdstat;
+       vuint32_t       info;
+       vuint32_t       epliststart;
+       vuint32_t       databufstart;
+       vuint32_t       lpm;
+       vuint32_t       epskip;
+       vuint32_t       epinuse;
+       vuint32_t       epbufcfg;
+       vuint32_t       intstat;
+       vuint32_t       inten;
+       vuint32_t       intsetstat;
+       vuint32_t       introuting;
+       uint32_t        r30;
+       vuint32_t       eptoggle;
+} lpc_usb;
+
+extern struct lpc_usb lpc_usb;
+
+#define LPC_USB_DEVCMDSTAT_DEV_ADDR    0
+#define LPC_USB_DEVCMDSTAT_DEV_ADDR_MASK       0x7f
+#define LPC_USB_DEVCMDSTAT_DEV_EN      7
+#define LPC_USB_DEVCMDSTAT_SETUP       8
+#define LPC_USB_DEVCMDSTAT_PLL_ON      9
+#define LPC_USB_DEVCMDSTAT_LPM_SUP     11
+#define LPC_USB_DEVCMDSTAT_INTONNAK_AO 12
+#define LPC_USB_DEVCMDSTAT_INTONNAK_AI 13
+#define LPC_USB_DEVCMDSTAT_INTONNAK_CO 14
+#define LPC_USB_DEVCMDSTAT_INTONNAK_CI 15
+#define LPC_USB_DEVCMDSTAT_DCON                16
+#define LPC_USB_DEVCMDSTAT_DSUS                17
+#define LPC_USB_DEVCMDSTAT_LPM_SUS     19
+#define LPC_USB_DEVCMDSTAT_LPM_REWP    20
+#define LPC_USB_DEVCMDSTAT_DCON_C      24
+#define LPC_USB_DEVCMDSTAT_DSUS_C      25
+#define LPC_USB_DEVCMDSTAT_DRES_C      26
+#define LPC_USB_DEVCMDSTAT_VBUSDEBOUNCED       28
+
+#define LPC_USB_INFO_FRAME_NR          0
+#define LPC_USB_INFO_FRAME_NR_MASK     0x3ff
+#define LPC_USB_INFO_ERR_CODE          11
+#define LPC_USB_INFO_ERR_CODE_NO_ERROR                 0
+#define LPC_USB_INFO_ERR_CODE_PID_ENCODING_ERROR       1
+#define LPC_USB_INFO_ERR_CODE_PID_UNKNOWN              2
+#define LPC_USB_INFO_ERR_CODE_PACKET_UNEXPECTED                3
+#define LPC_USB_INFO_ERR_CODE_TOKEN_CRC_ERROR          4
+#define LPC_USB_INFO_ERR_CODE_DATA_CRC_ERROR           5
+#define LPC_USB_INFO_ERR_CODE_TIME_OUT                 6
+#define LPC_USB_INFO_ERR_CODE_BABBLE                   7
+#define LPC_USB_INFO_ERR_CODE_TRUNCATED_EOP            8
+#define LPC_USB_INFO_ERR_CODE_SENT_RECEIVED_NAK                9
+#define LPC_USB_INFO_ERR_CODE_SENT_STALL               0xa
+#define LPC_USB_INFO_ERR_CODE_OVERRUN                  0xb
+#define LPC_USB_INFO_ERR_CODE_SENT_EMPTY_PACKET                0xc
+#define LPC_USB_INFO_ERR_CODE_BITSTUFF_ERROR           0xd
+#define LPC_USB_INFO_ERR_CODE_SYNC_ERROR               0xe
+#define LPC_USB_INFO_ERR_CODE_WRONG_DATA_TOGGLE                0xf
+#define LPC_USB_INFO_ERR_CODE_MASK                     0xf
+
+#define LPC_USB_EPLISTSTART_EP_LIST                    0
+
+#define LPC_USB_DATABUFSTART_DA_BUF                    0
+
+#define LPC_USB_LPM_HIRD_HW            0
+#define LPC_USB_LPM_HIRD_HW_MASK               0xf
+#define LPC_USB_LPM_HIRD_SW            4
+#define LPC_USB_LPM_HIRD_SW_MASK               0xf
+#define LPC_USB_LPM_DATA_PENDING       8
+
+#define LPC_USB_EPSKIP_SKIP            0
+
+#define LPC_USB_EPINUSE_BUF(ep)                (ep)
+
+#define LPC_USB_EPBUFCFG_BUF_SB(ep)    (ep)
+
+#define LPC_USB_INT_EPOUT(ep)          ((ep) << 1)
+#define LPC_USB_INT_EPIN(ep)           (((ep) << 1) + 1)
+
+#define LPC_USB_INT_FRAME              30
+#define LPC_USB_INT_DEV                        31
+
+#define LPC_USB_INTIN_EP_INT_EN(ep)    (ep)
+#define LPC_USB_INTIN_FRAME_INT_EN     30
+#define LPC_USB_INTIN_DEV_INT_EN       31
+
+#define LPC_USB_INTSETSTAT_EP_SET_INT(ep)      (ep)
+#define LPC_USB_INTSETSTAT_FRAME_SET_INT       30
+#define LPC_USB_INTSETSTAT_DEV_SET_INT         31
+
+#define LPC_USB_INTROUTING_ROUTE_INT(ep)       (ep)
+#define LPC_USB_INTROUTING_INT30               30
+#define LPC_USB_INTROUTING_INT31               31
+
+#define LPC_USB_EPTOGGLE_TOGGLE(ep)            (ep)
+
+struct lpc_usb_epn {
+       vuint32_t               out[2];
+       vuint32_t               in[2];
+};
+
+struct lpc_usb_endpoint {
+       vuint32_t               ep0_out;
+       vuint32_t               setup;
+       vuint32_t               ep0_in;
+       vuint32_t               reserved_0c;
+       struct lpc_usb_epn      epn[4];
+};
+
+/* Assigned in registers.ld to point at the base
+ * of USB ram
+ */
+
+extern uint8_t lpc_usb_sram[];
+
+#define LPC_USB_EP_ACTIVE              31
+#define LPC_USB_EP_DISABLED            30
+#define LPC_USB_EP_STALL               29
+#define LPC_USB_EP_TOGGLE_RESET                28
+#define LPC_USB_EP_RATE_FEEDBACK       27
+#define LPC_USB_EP_ENDPOINT_ISO                26
+#define LPC_USB_EP_NBYTES              16
+#define  LPC_USB_EP_NBYTES_MASK                        0x3ff
+#define LPC_USB_EP_OFFSET              0
+
+#define LPC_ISR_PIN_INT0_POS   0
+#define LPC_ISR_PIN_INT1_POS   1
+#define LPC_ISR_PIN_INT2_POS   2
+#define LPC_ISR_PIN_INT3_POS   3
+#define LPC_ISR_PIN_INT4_POS   4
+#define LPC_ISR_PIN_INT5_POS   5
+#define LPC_ISR_PIN_INT6_POS   6
+#define LPC_ISR_PIN_INT7_POS   7
+#define LPC_ISR_GINT0_POS      8
+#define LPC_ISR_GINT1_POS      9
+#define LPC_ISR_SSP1_POS       14
+#define LPC_ISR_I2C_POS                15
+#define LPC_ISR_CT16B0_POS     16
+#define LPC_ISR_CT16B1_POS     17
+#define LPC_ISR_CT32B0_POS     18
+#define LPC_ISR_CT32B1_POS     19
+#define LPC_ISR_SSP0_POS       20
+#define LPC_ISR_USART_POS      21
+#define LPC_ISR_USB_IRQ_POS    22
+#define LPC_ISR_USB_FIQ_POS    23
+#define LPC_ISR_ADC_POS                24
+#define LPC_ISR_WWDT_POS       25
+#define LPC_ISR_BOD_POS                26
+#define LPC_ISR_FLASH_POS      27
+#define LPC_ISR_USB_WAKEUP_POS 30
+
+struct lpc_nvic {
+       vuint32_t       iser;           /* 0x000 0xe000e100 Set Enable Register */
+
+       uint8_t         _unused020[0x080 - 0x004];
+
+       vuint32_t       icer;           /* 0x080 0xe000e180 Clear Enable Register */
+
+       uint8_t         _unused0a0[0x100 - 0x084];
+
+       vuint32_t       ispr;           /* 0x100 0xe000e200 Set Pending Register */
+
+       uint8_t         _unused120[0x180 - 0x104];
+
+       vuint32_t       icpr;           /* 0x180 0xe000e280 Clear Pending Register */
+
+       uint8_t         _unused1a0[0x300 - 0x184];
+
+       vuint32_t       ipr[8];         /* 0x300 0xe000e400 Priority Register */
+};
+
+extern struct lpc_nvic lpc_nvic;
+
+static inline void
+lpc_nvic_set_enable(int irq) {
+       lpc_nvic.iser = (1 << irq);
+}
+
+static inline void
+lpc_nvic_clear_enable(int irq) {
+       lpc_nvic.icer = (1 << irq);
+}
+
+static inline int
+lpc_nvic_enabled(int irq) {
+       return (lpc_nvic.iser >> irq) & 1;
+}
+
+       
+static inline void
+lpc_nvic_set_pending(int irq) {
+       lpc_nvic.ispr = (1 << irq);
+}
+
+static inline void
+lpc_nvic_clear_pending(int irq) {
+       lpc_nvic.icpr = (1 << irq);
+}
+
+static inline int
+lpc_nvic_pending(int irq) {
+       return (lpc_nvic.ispr >> irq) & 1;
+}
+
+#define IRQ_PRIO_REG(irq)      ((irq) >> 2)
+#define IRQ_PRIO_BIT(irq)      (((irq) & 3) << 3)
+#define IRQ_PRIO_MASK(irq)     (0xff << IRQ_PRIO_BIT(irq))
+
+static inline void
+lpc_nvic_set_priority(int irq, uint8_t prio) {
+       int             n = IRQ_PRIO_REG(irq);
+       uint32_t        v;
+
+       v = lpc_nvic.ipr[n];
+       v &= ~IRQ_PRIO_MASK(irq);
+       v |= (prio) << IRQ_PRIO_BIT(irq);
+       lpc_nvic.ipr[n] = v;
+}
+
+static inline uint8_t
+lpc_nvic_get_priority(int irq) {
+       return (lpc_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0);
+}
+
+struct arm_scb {
+       vuint32_t       cpuid;
+       vuint32_t       icsr;
+       uint32_t        reserved08;
+       vuint32_t       aircr;
+
+       vuint32_t       scr;
+       vuint32_t       ccr;
+       uint32_t        reserved18;
+       vuint32_t       shpr2;
+
+       vuint32_t       shpr3;
+};
+
+extern struct arm_scb arm_scb;
+
+struct lpc_ssp {
+       vuint32_t       cr0;    /* 0x00 */
+       vuint32_t       cr1;
+       vuint32_t       dr;
+       vuint32_t       sr;
+
+       vuint32_t       cpsr;   /* 0x10 */
+       vuint32_t       imsc;
+       vuint32_t       ris;
+       vuint32_t       mis;
+
+       vuint32_t       icr;    /* 0x20 */
+};
+
+extern struct lpc_ssp lpc_ssp0, lpc_ssp1;
+
+#define LPC_NUM_SPI            2
+
+#define LPC_SSP_FIFOSIZE       8
+
+#define LPC_SSP_CR0_DSS                0
+#define  LPC_SSP_CR0_DSS_4             0x3
+#define  LPC_SSP_CR0_DSS_5             0x4
+#define  LPC_SSP_CR0_DSS_6             0x5
+#define  LPC_SSP_CR0_DSS_7             0x6
+#define  LPC_SSP_CR0_DSS_8             0x7
+#define  LPC_SSP_CR0_DSS_9             0x8
+#define  LPC_SSP_CR0_DSS_10            0x9
+#define  LPC_SSP_CR0_DSS_11            0xa
+#define  LPC_SSP_CR0_DSS_12            0xb
+#define  LPC_SSP_CR0_DSS_13            0xc
+#define  LPC_SSP_CR0_DSS_14            0xd
+#define  LPC_SSP_CR0_DSS_15            0xe
+#define  LPC_SSP_CR0_DSS_16            0xf
+#define LPC_SSP_CR0_FRF                4
+#define  LPC_SSP_CR0_FRF_SPI           0
+#define  LPC_SSP_CR0_FRF_TI            1
+#define  LPC_SSP_CR0_FRF_MICROWIRE     2
+#define LPC_SSP_CR0_CPOL       6
+#define  LPC_SSP_CR0_CPOL_LOW          0
+#define  LPC_SSP_CR0_CPOL_HIGH         1
+#define LPC_SSP_CR0_CPHA       7
+#define  LPC_SSP_CR0_CPHA_FIRST                0
+#define  LPC_SSP_CR0_CPHA_SECOND       1
+#define LPC_SSP_CR0_SCR                8
+
+#define LPC_SSP_CR1_LBM                0
+#define LPC_SSP_CR1_SSE                1
+#define LPC_SSP_CR1_MS         2
+#define  LPC_SSP_CR1_MS_MASTER         0
+#define  LPC_SSP_CR1_MS_SLAVE          1
+#define LPC_SSP_CR1_SOD                3
+
+#define LPC_SSP_SR_TFE         0
+#define LPC_SSP_SR_TNF         1
+#define LPC_SSP_SR_RNE         2
+#define LPC_SSP_SR_RFF         3
+#define LPC_SSP_SR_BSY         4
+
+#define LPC_SSP_IMSC_RORIM     0
+#define LPC_SSP_IMSC_RTIM      1
+#define LPC_SSP_IMSC_RXIM      2
+#define LPC_SSP_IMSC_TXIM      3
+
+#define LPC_SSP_RIS_RORRIS     0
+#define LPC_SSP_RIS_RTRIS      1
+#define LPC_SSP_RIS_RXRIS      2
+#define LPC_SSP_RIS_TXRIS      3
+
+#define LPC_SSP_MIS_RORMIS     0
+#define LPC_SSP_MIS_RTMIS      1
+#define LPC_SSP_MIS_RXMIS      2
+#define LPC_SSP_MIS_TXMIS      3
+
+#define LPC_SSP_ICR_RORIC      0
+#define LPC_SSP_ICR_RTIC       1
+
+struct lpc_adc {
+       vuint32_t       cr;     /* 0x00 */
+       vuint32_t       gdr;
+       uint32_t        r08;
+       vuint32_t       inten;
+
+       vuint32_t       dr[8];  /* 0x10 */
+
+       vuint32_t       stat;   /* 0x30 */
+};
+
+extern struct lpc_adc lpc_adc;
+
+#define LPC_ADC_CR_SEL         0
+#define LPC_ADC_CR_CLKDIV      8
+#define LPC_ADC_CR_BURST       16
+#define LPC_ADC_CR_CLKS                17
+#define  LPC_ADC_CR_CLKS_11            0
+#define  LPC_ADC_CR_CLKS_10            1
+#define  LPC_ADC_CR_CLKS_9             2
+#define  LPC_ADC_CR_CLKS_8             3
+#define  LPC_ADC_CR_CLKS_7             4
+#define  LPC_ADC_CR_CLKS_6             5
+#define  LPC_ADC_CR_CLKS_5             6
+#define  LPC_ADC_CR_CLKS_4             7
+#define LPC_ADC_CR_START       24
+#define  LPC_ADC_CR_START_NONE         0
+#define  LPC_ADC_CR_START_NOW          1
+
+#define LPC_ADC_GDR_CHN                        24
+#define LPC_ADC_GDR_OVERRUN            30
+#define LPC_ADC_GDR_DONE               31
+
+#define LPC_ADC_INTEN_ADINTEN  0
+#define LPC_ADC_INTEN_ADGINTEN 8
+
+#define LPC_ADC_STAT_DONE      0
+#define LPC_ADC_STAT_OVERRUN   8
+#define LPC_ADC_STAT_ADINT     16
+
+struct lpc_ct32b {
+       vuint32_t       ir;     /* 0x00 */
+       vuint32_t       tcr;
+       vuint32_t       tc;
+       vuint32_t       pr;
+       
+       vuint32_t       pc;     /* 0x10 */
+       vuint32_t       mcr;
+       vuint32_t       mr[4];  /* 0x18 */
+       vuint32_t       ccr;    /* 0x28 */
+       vuint32_t       cr0;
+       
+       vuint32_t       cr1_0;  /* 0x30 (only for ct32b0 */
+       vuint32_t       cr1_1;  /* 0x34 (only for ct32b1 */
+       uint32_t        r38;
+       vuint32_t       emr;
+
+       uint32_t        r40[12];
+
+       vuint32_t       ctcr;   /* 0x70 */
+       vuint32_t       pwmc;
+};
+
+extern struct lpc_ct32b lpc_ct32b0, lpc_ct32b1;
+
+#define LPC_CT32B_TCR_CEN      0
+#define LPC_CT32B_TCR_CRST     1
+
+#define LPC_CT32B_MCR_MR0R     1
+
+#define LPC_CT32B_PWMC_PWMEN0  0
+#define LPC_CT32B_PWMC_PWMEN1  1
+#define LPC_CT32B_PWMC_PWMEN2  2
+#define LPC_CT32B_PWMC_PWMEN3  3
+
+#define LPC_CT32B_EMR_EMC0     4
+#define LPC_CT32B_EMR_EMC1     6
+#define LPC_CT32B_EMR_EMC2     8
+#define LPC_CT32B_EMR_EMC3     10
+
+#define LPC_CT32B_EMR_EMC_NOTHING      0
+#define LPC_CT32B_EMR_EMC_CLEAR                1
+#define LPC_CT32B_EMR_EMC_SET          2
+#define LPC_CT32B_EMR_EMC_TOGGLE       3
+
+#endif /* _LPC_H_ */
diff --git a/src/lpc/registers.ld b/src/lpc/registers.ld
new file mode 100644 (file)
index 0000000..a523c39
--- /dev/null
@@ -0,0 +1,19 @@
+lpc_usb_sram   = 0x20004000;
+lpc_usb_endpoint = 0x20004700;
+lpc_usart      = 0x40008000;
+lpc_ct32b0     = 0x40014000;
+lpc_ct32b1     = 0x40018000;
+lpc_adc                = 0x4001c000;
+lpc_flash      = 0x4003c000;
+lpc_ssp0       = 0x40040000;
+lpc_ioconf     = 0x40044000;
+lpc_scb                = 0x40048000;
+lpc_gpio_pin   = 0x4004c000;
+lpc_ssp1       = 0x40058000;
+lpc_gpio_group0 = 0x4005c000;
+lpc_gpio_group1 = 0x40060000;
+lpc_usb                = 0x40080000;
+lpc_gpio       = 0x50000000;
+lpc_systick    = 0xe000e000;
+lpc_nvic       = 0xe000e100;
+arm_scb                = 0xe000ed00;
diff --git a/src/lpcxpresso/.gitignore b/src/lpcxpresso/.gitignore
new file mode 100644 (file)
index 0000000..892c3ac
--- /dev/null
@@ -0,0 +1,3 @@
+ao_product.h
+ao_serial_lpc.h
+*.elf
diff --git a/src/lpcxpresso/Makefile b/src/lpcxpresso/Makefile
new file mode 100644 (file)
index 0000000..374c052
--- /dev/null
@@ -0,0 +1,66 @@
+#
+# AltOS build
+#
+#
+
+include ../lpc/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_pins.h \
+       ao_product.h \
+       lpc.h
+
+#
+# Common AltOS sources
+#
+ALTOS_SRC = \
+       ao_interrupt.c \
+       ao_romconfig.c \
+       ao_product.c \
+       ao_panic.c \
+       ao_led_lpc.c \
+       ao_task.c \
+       ao_cmd.c \
+       ao_timer_lpc.c \
+       ao_serial_lpc.c \
+       ao_usb_lpc.c \
+       ao_stdio.c
+
+PRODUCT=LpcDemo-v0.0
+PRODUCT_DEF=-DLPC_DEMO
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+
+PROG=lpc-demo.elf
+
+SRC=$(ALTOS_SRC) ao_demo.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG)
+
+LDFLAGS=-L../lpc -Wl,-Taltos.ld
+
+$(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 $(PROG)
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/lpcxpresso/ao_demo.c b/src/lpcxpresso/ao_demo.c
new file mode 100644 (file)
index 0000000..0c93161
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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_usb.h>
+
+int
+main(void)
+{
+       int     i;
+       ao_led_init(LEDS_AVAILABLE);
+       ao_led_on(AO_LED_RED);
+       ao_clock_init();
+       ao_timer_init();
+       
+       ao_serial_init();
+       ao_usb_init();
+       ao_cmd_init();
+       ao_task_init();
+
+       ao_start_scheduler();
+
+       for (;;) {
+               ao_led_off(AO_LED_RED);
+               for (;;)
+                       if (ao_tick_count & 1)
+                               break;
+               ao_led_on(AO_LED_RED);
+               for (;;)
+                       if (!(ao_tick_count & 1))
+                               break;
+       }
+}
diff --git a/src/lpcxpresso/ao_pins.h b/src/lpcxpresso/ao_pins.h
new file mode 100644 (file)
index 0000000..c0074ce
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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       0
+#define        HAS_LED         1
+
+/* Crystal on the board */
+#define AO_LPC_CLKIN   12000000
+
+/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */
+#define AO_LPC_CLKOUT  48000000
+
+/* System clock frequency */
+#define AO_LPC_SYSCLK  24000000
+
+#define LED_PORT       0
+#define LED_PIN_RED    7
+
+#define AO_LED_RED     (1 << LED_PIN_RED)
+
+#define LEDS_AVAILABLE AO_LED_RED
+
+#define HAS_USB                1
+
+#define HAS_USB_CONNECT        1
+#define HAS_USB_VBUS   1
+
+#define PACKET_HAS_SLAVE       0
+
+/* USART */
+
+#define HAS_SERIAL             1
+#define USE_SERIAL_0_STDIN     1
+#define SERIAL_0_18_19         1
+#define SERIAL_0_14_15         0
+#define SERIAL_0_17_18         0
+#define SERIAL_0_26_27         0
diff --git a/src/math/ef_acos.c b/src/math/ef_acos.c
new file mode 100644 (file)
index 0000000..f73f97d
--- /dev/null
@@ -0,0 +1,84 @@
+/* ef_acos.c -- float version of e_acos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float 
+#else
+static float 
+#endif
+one =  1.0000000000e+00, /* 0x3F800000 */
+pi =  3.1415925026e+00, /* 0x40490fda */
+pio2_hi =  1.5707962513e+00, /* 0x3fc90fda */
+pio2_lo =  7.5497894159e-08, /* 0x33a22168 */
+pS0 =  1.6666667163e-01, /* 0x3e2aaaab */
+pS1 = -3.2556581497e-01, /* 0xbea6b090 */
+pS2 =  2.0121252537e-01, /* 0x3e4e0aa8 */
+pS3 = -4.0055535734e-02, /* 0xbd241146 */
+pS4 =  7.9153501429e-04, /* 0x3a4f7f04 */
+pS5 =  3.4793309169e-05, /* 0x3811ef08 */
+qS1 = -2.4033949375e+00, /* 0xc019d139 */
+qS2 =  2.0209457874e+00, /* 0x4001572d */
+qS3 = -6.8828397989e-01, /* 0xbf303361 */
+qS4 =  7.7038154006e-02; /* 0x3d9dc62e */
+
+#ifdef __STDC__
+       float __ieee754_acosf(float x)
+#else
+       float __ieee754_acosf(x)
+       float x;
+#endif
+{
+       float z,p,q,r,w,s,c,df;
+       __int32_t hx,ix;
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix==0x3f800000) {            /* |x|==1 */
+           if(hx>0) return 0.0;        /* acos(1) = 0  */
+           else return pi+(float)2.0*pio2_lo;  /* acos(-1)= pi */
+       } else if(ix>0x3f800000) {      /* |x| >= 1 */
+           return (x-x)/(x-x);         /* acos(|x|>1) is NaN */
+       }
+       if(ix<0x3f000000) {     /* |x| < 0.5 */
+           if(ix<=0x23000000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+           z = x*x;
+           p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+           q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+           r = p/q;
+           return pio2_hi - (x - (pio2_lo-x*r));
+       } else  if (hx<0) {             /* x < -0.5 */
+           z = (one+x)*(float)0.5;
+           p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+           q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+           s = __ieee754_sqrtf(z);
+           r = p/q;
+           w = r*s-pio2_lo;
+           return pi - (float)2.0*(s+w);
+       } else {                        /* x > 0.5 */
+           __int32_t idf;
+           z = (one-x)*(float)0.5;
+           s = __ieee754_sqrtf(z);
+           df = s;
+           GET_FLOAT_WORD(idf,df);
+           SET_FLOAT_WORD(df,idf&0xfffff000);
+           c  = (z-df*df)/(s+df);
+           p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+           q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+           r = p/q;
+           w = r*s+c;
+           return (float)2.0*(df+w);
+       }
+}
diff --git a/src/math/ef_rem_pio2.c b/src/math/ef_rem_pio2.c
new file mode 100644 (file)
index 0000000..f1191d0
--- /dev/null
@@ -0,0 +1,193 @@
+/* ef_rem_pio2.c -- float version of e_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_rem_pio2f(x,y)
+ * 
+ * return the remainder of x rem pi/2 in y[0]+y[1] 
+ * use __kernel_rem_pio2f()
+ */
+
+#include "fdlibm.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi 
+ */
+#ifdef __STDC__
+static const __int32_t two_over_pi[] = {
+#else
+static __int32_t two_over_pi[] = {
+#endif
+0xA2, 0xF9, 0x83, 0x6E, 0x4E, 0x44, 0x15, 0x29, 0xFC,
+0x27, 0x57, 0xD1, 0xF5, 0x34, 0xDD, 0xC0, 0xDB, 0x62, 
+0x95, 0x99, 0x3C, 0x43, 0x90, 0x41, 0xFE, 0x51, 0x63,
+0xAB, 0xDE, 0xBB, 0xC5, 0x61, 0xB7, 0x24, 0x6E, 0x3A, 
+0x42, 0x4D, 0xD2, 0xE0, 0x06, 0x49, 0x2E, 0xEA, 0x09,
+0xD1, 0x92, 0x1C, 0xFE, 0x1D, 0xEB, 0x1C, 0xB1, 0x29, 
+0xA7, 0x3E, 0xE8, 0x82, 0x35, 0xF5, 0x2E, 0xBB, 0x44,
+0x84, 0xE9, 0x9C, 0x70, 0x26, 0xB4, 0x5F, 0x7E, 0x41, 
+0x39, 0x91, 0xD6, 0x39, 0x83, 0x53, 0x39, 0xF4, 0x9C,
+0x84, 0x5F, 0x8B, 0xBD, 0xF9, 0x28, 0x3B, 0x1F, 0xF8, 
+0x97, 0xFF, 0xDE, 0x05, 0x98, 0x0F, 0xEF, 0x2F, 0x11,
+0x8B, 0x5A, 0x0A, 0x6D, 0x1F, 0x6D, 0x36, 0x7E, 0xCF, 
+0x27, 0xCB, 0x09, 0xB7, 0x4F, 0x46, 0x3F, 0x66, 0x9E,
+0x5F, 0xEA, 0x2D, 0x75, 0x27, 0xBA, 0xC7, 0xEB, 0xE5, 
+0xF1, 0x7B, 0x3D, 0x07, 0x39, 0xF7, 0x8A, 0x52, 0x92,
+0xEA, 0x6B, 0xFB, 0x5F, 0xB1, 0x1F, 0x8D, 0x5D, 0x08, 
+0x56, 0x03, 0x30, 0x46, 0xFC, 0x7B, 0x6B, 0xAB, 0xF0,
+0xCF, 0xBC, 0x20, 0x9A, 0xF4, 0x36, 0x1D, 0xA9, 0xE3, 
+0x91, 0x61, 0x5E, 0xE6, 0x1B, 0x08, 0x65, 0x99, 0x85,
+0x5F, 0x14, 0xA0, 0x68, 0x40, 0x8D, 0xFF, 0xD8, 0x80, 
+0x4D, 0x73, 0x27, 0x31, 0x06, 0x06, 0x15, 0x56, 0xCA,
+0x73, 0xA8, 0xC9, 0x60, 0xE2, 0x7B, 0xC0, 0x8C, 0x6B, 
+};
+
+/* This array is like the one in e_rem_pio2.c, but the numbers are
+   single precision and the last 8 bits are forced to 0.  */
+#ifdef __STDC__
+static const __int32_t npio2_hw[] = {
+#else
+static __int32_t npio2_hw[] = {
+#endif
+0x3fc90f00, 0x40490f00, 0x4096cb00, 0x40c90f00, 0x40fb5300, 0x4116cb00,
+0x412fed00, 0x41490f00, 0x41623100, 0x417b5300, 0x418a3a00, 0x4196cb00,
+0x41a35c00, 0x41afed00, 0x41bc7e00, 0x41c90f00, 0x41d5a000, 0x41e23100,
+0x41eec200, 0x41fb5300, 0x4203f200, 0x420a3a00, 0x42108300, 0x4216cb00,
+0x421d1400, 0x42235c00, 0x4229a500, 0x422fed00, 0x42363600, 0x423c7e00,
+0x4242c700, 0x42490f00
+};
+
+/*
+ * invpio2:  24 bits of 2/pi
+ * pio2_1:   first  17 bit of pi/2
+ * pio2_1t:  pi/2 - pio2_1
+ * pio2_2:   second 17 bit of pi/2
+ * pio2_2t:  pi/2 - (pio2_1+pio2_2)
+ * pio2_3:   third  17 bit of pi/2
+ * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+#ifdef __STDC__
+static const float 
+#else
+static float 
+#endif
+zero =  0.0000000000e+00, /* 0x00000000 */
+half =  5.0000000000e-01, /* 0x3f000000 */
+two8 =  2.5600000000e+02, /* 0x43800000 */
+invpio2 =  6.3661980629e-01, /* 0x3f22f984 */
+pio2_1  =  1.5707855225e+00, /* 0x3fc90f80 */
+pio2_1t =  1.0804334124e-05, /* 0x37354443 */
+pio2_2  =  1.0804273188e-05, /* 0x37354400 */
+pio2_2t =  6.0770999344e-11, /* 0x2e85a308 */
+pio2_3  =  6.0770943833e-11, /* 0x2e85a300 */
+pio2_3t =  6.1232342629e-17; /* 0x248d3132 */
+
+#ifdef __STDC__
+       __int32_t __ieee754_rem_pio2f(float x, float *y)
+#else
+       __int32_t __ieee754_rem_pio2f(x,y)
+       float x,y[];
+#endif
+{
+       float z,w,t,r,fn;
+       float tx[3];
+       __int32_t i,j,n,ix,hx;
+       int e0,nx;
+
+       GET_FLOAT_WORD(hx,x);
+       ix = hx&0x7fffffff;
+       if(ix<=0x3f490fd8)   /* |x| ~<= pi/4 , no need for reduction */
+           {y[0] = x; y[1] = 0; return 0;}
+       if(ix<0x4016cbe4) {  /* |x| < 3pi/4, special case with n=+-1 */
+           if(hx>0) { 
+               z = x - pio2_1;
+               if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
+                   y[0] = z - pio2_1t;
+                   y[1] = (z-y[0])-pio2_1t;
+               } else {                /* near pi/2, use 24+24+24 bit pi */
+                   z -= pio2_2;
+                   y[0] = z - pio2_2t;
+                   y[1] = (z-y[0])-pio2_2t;
+               }
+               return 1;
+           } else {    /* negative x */
+               z = x + pio2_1;
+               if((ix&0xfffffff0)!=0x3fc90fd0) { /* 24+24 bit pi OK */
+                   y[0] = z + pio2_1t;
+                   y[1] = (z-y[0])+pio2_1t;
+               } else {                /* near pi/2, use 24+24+24 bit pi */
+                   z += pio2_2;
+                   y[0] = z + pio2_2t;
+                   y[1] = (z-y[0])+pio2_2t;
+               }
+               return -1;
+           }
+       }
+       if(ix<=0x43490f80) { /* |x| ~<= 2^7*(pi/2), medium size */
+           t  = fabsf(x);
+           n  = (__int32_t) (t*invpio2+half);
+           fn = (float)n;
+           r  = t-fn*pio2_1;
+           w  = fn*pio2_1t;    /* 1st round good to 40 bit */
+           if(n<32&&(ix&0xffffff00)!=npio2_hw[n-1]) {  
+               y[0] = r-w;     /* quick check no cancellation */
+           } else {
+               __uint32_t high;
+               j  = ix>>23;
+               y[0] = r-w; 
+               GET_FLOAT_WORD(high,y[0]);
+               i = j-((high>>23)&0xff);
+               if(i>8) {  /* 2nd iteration needed, good to 57 */
+                   t  = r;
+                   w  = fn*pio2_2;     
+                   r  = t-w;
+                   w  = fn*pio2_2t-((t-r)-w);  
+                   y[0] = r-w;
+                   GET_FLOAT_WORD(high,y[0]);
+                   i = j-((high>>23)&0xff);
+                   if(i>25)  { /* 3rd iteration need, 74 bits acc */
+                       t  = r; /* will cover all possible cases */
+                       w  = fn*pio2_3; 
+                       r  = t-w;
+                       w  = fn*pio2_3t-((t-r)-w);      
+                       y[0] = r-w;
+                   }
+               }
+           }
+           y[1] = (r-y[0])-w;
+           if(hx<0)    {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+           else         return n;
+       }
+    /* 
+     * all other (large) arguments
+     */
+       if(!FLT_UWORD_IS_FINITE(ix)) {
+           y[0]=y[1]=x-x; return 0;
+       }
+    /* set z = scalbn(|x|,ilogb(x)-7) */
+       e0      = (int)((ix>>23)-134);  /* e0 = ilogb(z)-7; */
+       SET_FLOAT_WORD(z, ix - ((__int32_t)e0<<23));
+       for(i=0;i<2;i++) {
+               tx[i] = (float)((__int32_t)(z));
+               z     = (z-tx[i])*two8;
+       }
+       tx[2] = z;
+       nx = 3;
+       while(tx[nx-1]==zero) nx--;     /* skip zero term */
+       n  =  __kernel_rem_pio2f(tx,y,e0,nx,2,two_over_pi);
+       if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+       return n;
+}
diff --git a/src/math/ef_sqrt.c b/src/math/ef_sqrt.c
new file mode 100644 (file)
index 0000000..80e7f36
--- /dev/null
@@ -0,0 +1,89 @@
+/* ef_sqrtf.c -- float version of e_sqrt.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float     one     = 1.0, tiny=1.0e-30;
+#else
+static float   one     = 1.0, tiny=1.0e-30;
+#endif
+
+#ifdef __STDC__
+       float __ieee754_sqrtf(float x)
+#else
+       float __ieee754_sqrtf(x)
+       float x;
+#endif
+{
+       float z;
+       __uint32_t r,hx;
+       __int32_t ix,s,q,m,t,i;
+
+       GET_FLOAT_WORD(ix,x);
+       hx = ix&0x7fffffff;
+
+    /* take care of Inf and NaN */
+       if(!FLT_UWORD_IS_FINITE(hx))
+           return x*x+x;               /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+                                          sqrt(-inf)=sNaN */
+    /* take care of zero and -ves */
+       if(FLT_UWORD_IS_ZERO(hx)) return x;/* sqrt(+-0) = +-0 */
+       if(ix<0) return (x-x)/(x-x);            /* sqrt(-ve) = sNaN */
+
+    /* normalize x */
+       m = (ix>>23);
+       if(FLT_UWORD_IS_SUBNORMAL(hx)) {                /* subnormal x */
+           for(i=0;(ix&0x00800000L)==0;i++) ix<<=1;
+           m -= i-1;
+       }
+       m -= 127;       /* unbias exponent */
+       ix = (ix&0x007fffffL)|0x00800000L;
+       if(m&1) /* odd m, double x to make it even */
+           ix += ix;
+       m >>= 1;        /* m = [m/2] */
+
+    /* generate sqrt(x) bit by bit */
+       ix += ix;
+       q = s = 0;              /* q = sqrt(x) */
+       r = 0x01000000L;                /* r = moving bit from right to left */
+
+       while(r!=0) {
+           t = s+r; 
+           if(t<=ix) { 
+               s    = t+r; 
+               ix  -= t; 
+               q   += r; 
+           } 
+           ix += ix;
+           r>>=1;
+       }
+
+    /* use floating add to find out rounding direction */
+       if(ix!=0) {
+           z = one-tiny; /* trigger inexact flag */
+           if (z>=one) {
+               z = one+tiny;
+               if (z>one)
+                   q += 2;
+               else
+                   q += (q&1);
+           }
+       }
+       ix = (q>>1)+0x3f000000L;
+       ix += (m <<23);
+       SET_FLOAT_WORD(z,ix);
+       return z;
+}
diff --git a/src/math/fdlibm.h b/src/math/fdlibm.h
new file mode 100644 (file)
index 0000000..821619a
--- /dev/null
@@ -0,0 +1,413 @@
+
+/* @(#)fdlibm.h 5.1 93/09/24 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* AltOS local */
+#include <math.h>
+#include <stdint.h>
+#define __int32_t int32_t
+#define __uint32_t uint32_t
+
+#define __ieee754_acosf acosf
+#define __ieee754_sqrtf sqrtf
+
+/* REDHAT LOCAL: Include files.  */
+#include <math.h>
+/* #include <sys/types.h> */
+#include <machine/ieeefp.h>
+
+/* REDHAT LOCAL: Default to XOPEN_MODE.  */
+#define _XOPEN_MODE
+
+/* Most routines need to check whether a float is finite, infinite, or not a
+   number, and many need to know whether the result of an operation will
+   overflow.  These conditions depend on whether the largest exponent is
+   used for NaNs & infinities, or whether it's used for finite numbers.  The
+   macros below wrap up that kind of information:
+
+   FLT_UWORD_IS_FINITE(X)
+       True if a positive float with bitmask X is finite.
+
+   FLT_UWORD_IS_NAN(X)
+       True if a positive float with bitmask X is not a number.
+
+   FLT_UWORD_IS_INFINITE(X)
+       True if a positive float with bitmask X is +infinity.
+
+   FLT_UWORD_MAX
+       The bitmask of FLT_MAX.
+
+   FLT_UWORD_HALF_MAX
+       The bitmask of FLT_MAX/2.
+
+   FLT_UWORD_EXP_MAX
+       The bitmask of the largest finite exponent (129 if the largest
+       exponent is used for finite numbers, 128 otherwise).
+
+   FLT_UWORD_LOG_MAX
+       The bitmask of log(FLT_MAX), rounded down.  This value is the largest
+       input that can be passed to exp() without producing overflow.
+
+   FLT_UWORD_LOG_2MAX
+       The bitmask of log(2*FLT_MAX), rounded down.  This value is the
+       largest input than can be passed to cosh() without producing
+       overflow.
+
+   FLT_LARGEST_EXP
+       The largest biased exponent that can be used for finite numbers
+       (255 if the largest exponent is used for finite numbers, 254
+       otherwise) */
+
+#ifdef _FLT_LARGEST_EXPONENT_IS_NORMAL
+#define FLT_UWORD_IS_FINITE(x) 1
+#define FLT_UWORD_IS_NAN(x) 0
+#define FLT_UWORD_IS_INFINITE(x) 0
+#define FLT_UWORD_MAX 0x7fffffff
+#define FLT_UWORD_EXP_MAX 0x43010000
+#define FLT_UWORD_LOG_MAX 0x42b2d4fc
+#define FLT_UWORD_LOG_2MAX 0x42b437e0
+#define HUGE ((float)0X1.FFFFFEP128)
+#else
+#define FLT_UWORD_IS_FINITE(x) ((x)<0x7f800000L)
+#define FLT_UWORD_IS_NAN(x) ((x)>0x7f800000L)
+#define FLT_UWORD_IS_INFINITE(x) ((x)==0x7f800000L)
+#define FLT_UWORD_MAX 0x7f7fffffL
+#define FLT_UWORD_EXP_MAX 0x43000000
+#define FLT_UWORD_LOG_MAX 0x42b17217
+#define FLT_UWORD_LOG_2MAX 0x42b2d4fc
+#define HUGE ((float)3.40282346638528860e+38)
+#endif
+#define FLT_UWORD_HALF_MAX (FLT_UWORD_MAX-(1L<<23))
+#define FLT_LARGEST_EXP (FLT_UWORD_MAX>>23)
+
+/* Many routines check for zero and subnormal numbers.  Such things depend
+   on whether the target supports denormals or not:
+
+   FLT_UWORD_IS_ZERO(X)
+       True if a positive float with bitmask X is +0.  Without denormals,
+       any float with a zero exponent is a +0 representation.  With
+       denormals, the only +0 representation is a 0 bitmask.
+
+   FLT_UWORD_IS_SUBNORMAL(X)
+       True if a non-zero positive float with bitmask X is subnormal.
+       (Routines should check for zeros first.)
+
+   FLT_UWORD_MIN
+       The bitmask of the smallest float above +0.  Call this number
+       REAL_FLT_MIN...
+
+   FLT_UWORD_EXP_MIN
+       The bitmask of the float representation of REAL_FLT_MIN's exponent.
+
+   FLT_UWORD_LOG_MIN
+       The bitmask of |log(REAL_FLT_MIN)|, rounding down.
+
+   FLT_SMALLEST_EXP
+       REAL_FLT_MIN's exponent - EXP_BIAS (1 if denormals are not supported,
+       -22 if they are).
+*/
+
+#ifdef _FLT_NO_DENORMALS
+#define FLT_UWORD_IS_ZERO(x) ((x)<0x00800000L)
+#define FLT_UWORD_IS_SUBNORMAL(x) 0
+#define FLT_UWORD_MIN 0x00800000
+#define FLT_UWORD_EXP_MIN 0x42fc0000
+#define FLT_UWORD_LOG_MIN 0x42aeac50
+#define FLT_SMALLEST_EXP 1
+#else
+#define FLT_UWORD_IS_ZERO(x) ((x)==0)
+#define FLT_UWORD_IS_SUBNORMAL(x) ((x)<0x00800000L)
+#define FLT_UWORD_MIN 0x00000001
+#define FLT_UWORD_EXP_MIN 0x43160000
+#define FLT_UWORD_LOG_MIN 0x42cff1b5
+#define FLT_SMALLEST_EXP -22
+#endif
+
+#ifdef __STDC__
+#undef __P
+#define        __P(p)  p
+#else
+#define        __P(p)  ()
+#endif
+
+/* 
+ * set X_TLOSS = pi*2**52, which is possibly defined in <values.h>
+ * (one may replace the following line by "#include <values.h>")
+ */
+
+#define X_TLOSS                1.41484755040568800000e+16 
+
+/* Functions that are not documented, and are not in <math.h>.  */
+
+#ifdef _SCALB_INT
+extern double scalb __P((double, int));
+#else
+extern double scalb __P((double, double));
+#endif
+extern double significand __P((double));
+
+/* ieee style elementary functions */
+extern double __ieee754_sqrt __P((double));                    
+extern double __ieee754_acos __P((double));                    
+extern double __ieee754_acosh __P((double));                   
+extern double __ieee754_log __P((double));                     
+extern double __ieee754_atanh __P((double));                   
+extern double __ieee754_asin __P((double));                    
+extern double __ieee754_atan2 __P((double,double));                    
+extern double __ieee754_exp __P((double));
+extern double __ieee754_cosh __P((double));
+extern double __ieee754_fmod __P((double,double));
+extern double __ieee754_pow __P((double,double));
+extern double __ieee754_lgamma_r __P((double,int *));
+extern double __ieee754_gamma_r __P((double,int *));
+extern double __ieee754_log10 __P((double));
+extern double __ieee754_sinh __P((double));
+extern double __ieee754_hypot __P((double,double));
+extern double __ieee754_j0 __P((double));
+extern double __ieee754_j1 __P((double));
+extern double __ieee754_y0 __P((double));
+extern double __ieee754_y1 __P((double));
+extern double __ieee754_jn __P((int,double));
+extern double __ieee754_yn __P((int,double));
+extern double __ieee754_remainder __P((double,double));
+extern __int32_t __ieee754_rem_pio2 __P((double,double*));
+#ifdef _SCALB_INT
+extern double __ieee754_scalb __P((double,int));
+#else
+extern double __ieee754_scalb __P((double,double));
+#endif
+
+/* fdlibm kernel function */
+extern double __kernel_standard __P((double,double,int));
+extern double __kernel_sin __P((double,double,int));
+extern double __kernel_cos __P((double,double));
+extern double __kernel_tan __P((double,double,int));
+extern int    __kernel_rem_pio2 __P((double*,double*,int,int,int,const __int32_t*));
+
+/* Undocumented float functions.  */
+#ifdef _SCALB_INT
+extern float scalbf __P((float, int));
+#else
+extern float scalbf __P((float, float));
+#endif
+extern float significandf __P((float));
+
+/* ieee style elementary float functions */
+extern float __ieee754_sqrtf __P((float));                     
+extern float __ieee754_acosf __P((float));                     
+extern float __ieee754_acoshf __P((float));                    
+extern float __ieee754_logf __P((float));                      
+extern float __ieee754_atanhf __P((float));                    
+extern float __ieee754_asinf __P((float));                     
+extern float __ieee754_atan2f __P((float,float));                      
+extern float __ieee754_expf __P((float));
+extern float __ieee754_coshf __P((float));
+extern float __ieee754_fmodf __P((float,float));
+extern float __ieee754_powf __P((float,float));
+extern float __ieee754_lgammaf_r __P((float,int *));
+extern float __ieee754_gammaf_r __P((float,int *));
+extern float __ieee754_log10f __P((float));
+extern float __ieee754_sinhf __P((float));
+extern float __ieee754_hypotf __P((float,float));
+extern float __ieee754_j0f __P((float));
+extern float __ieee754_j1f __P((float));
+extern float __ieee754_y0f __P((float));
+extern float __ieee754_y1f __P((float));
+extern float __ieee754_jnf __P((int,float));
+extern float __ieee754_ynf __P((int,float));
+extern float __ieee754_remainderf __P((float,float));
+extern __int32_t __ieee754_rem_pio2f __P((float,float*));
+#ifdef _SCALB_INT
+extern float __ieee754_scalbf __P((float,int));
+#else
+extern float __ieee754_scalbf __P((float,float));
+#endif
+
+/* float versions of fdlibm kernel functions */
+extern float __kernel_sinf __P((float,float,int));
+extern float __kernel_cosf __P((float,float));
+extern float __kernel_tanf __P((float,float,int));
+extern int   __kernel_rem_pio2f __P((float*,float*,int,int,int,const __int32_t*));
+
+/* The original code used statements like
+       n0 = ((*(int*)&one)>>29)^1;             * index of high word *
+       ix0 = *(n0+(int*)&x);                   * high word of x *
+       ix1 = *((1-n0)+(int*)&x);               * low word of x *
+   to dig two 32 bit words out of the 64 bit IEEE floating point
+   value.  That is non-ANSI, and, moreover, the gcc instruction
+   scheduler gets it wrong.  We instead use the following macros.
+   Unlike the original code, we determine the endianness at compile
+   time, not at run time; I don't see much benefit to selecting
+   endianness at run time.  */
+
+#ifndef __IEEE_BIG_ENDIAN
+#ifndef __IEEE_LITTLE_ENDIAN
+ #error Must define endianness
+#endif
+#endif
+
+/* A union which permits us to convert between a double and two 32 bit
+   ints.  */
+
+#ifdef __IEEE_BIG_ENDIAN
+
+typedef union 
+{
+  double value;
+  struct 
+  {
+    __uint32_t msw;
+    __uint32_t lsw;
+  } parts;
+} ieee_double_shape_type;
+
+#endif
+
+#ifdef __IEEE_LITTLE_ENDIAN
+
+typedef union 
+{
+  double value;
+  struct 
+  {
+    __uint32_t lsw;
+    __uint32_t msw;
+  } parts;
+} ieee_double_shape_type;
+
+#endif
+
+/* Get two 32 bit ints from a double.  */
+
+#define EXTRACT_WORDS(ix0,ix1,d)                               \
+do {                                                           \
+  ieee_double_shape_type ew_u;                                 \
+  ew_u.value = (d);                                            \
+  (ix0) = ew_u.parts.msw;                                      \
+  (ix1) = ew_u.parts.lsw;                                      \
+} while (0)
+
+/* Get the more significant 32 bit int from a double.  */
+
+#define GET_HIGH_WORD(i,d)                                     \
+do {                                                           \
+  ieee_double_shape_type gh_u;                                 \
+  gh_u.value = (d);                                            \
+  (i) = gh_u.parts.msw;                                                \
+} while (0)
+
+/* Get the less significant 32 bit int from a double.  */
+
+#define GET_LOW_WORD(i,d)                                      \
+do {                                                           \
+  ieee_double_shape_type gl_u;                                 \
+  gl_u.value = (d);                                            \
+  (i) = gl_u.parts.lsw;                                                \
+} while (0)
+
+/* Set a double from two 32 bit ints.  */
+
+#define INSERT_WORDS(d,ix0,ix1)                                        \
+do {                                                           \
+  ieee_double_shape_type iw_u;                                 \
+  iw_u.parts.msw = (ix0);                                      \
+  iw_u.parts.lsw = (ix1);                                      \
+  (d) = iw_u.value;                                            \
+} while (0)
+
+/* Set the more significant 32 bits of a double from an int.  */
+
+#define SET_HIGH_WORD(d,v)                                     \
+do {                                                           \
+  ieee_double_shape_type sh_u;                                 \
+  sh_u.value = (d);                                            \
+  sh_u.parts.msw = (v);                                                \
+  (d) = sh_u.value;                                            \
+} while (0)
+
+/* Set the less significant 32 bits of a double from an int.  */
+
+#define SET_LOW_WORD(d,v)                                      \
+do {                                                           \
+  ieee_double_shape_type sl_u;                                 \
+  sl_u.value = (d);                                            \
+  sl_u.parts.lsw = (v);                                                \
+  (d) = sl_u.value;                                            \
+} while (0)
+
+/* A union which permits us to convert between a float and a 32 bit
+   int.  */
+
+typedef union
+{
+  float value;
+  __uint32_t word;
+} ieee_float_shape_type;
+
+/* Get a 32 bit int from a float.  */
+
+#define GET_FLOAT_WORD(i,d)                                    \
+do {                                                           \
+  ieee_float_shape_type gf_u;                                  \
+  gf_u.value = (d);                                            \
+  (i) = gf_u.word;                                             \
+} while (0)
+
+/* Set a float from a 32 bit int.  */
+
+#define SET_FLOAT_WORD(d,i)                                    \
+do {                                                           \
+  ieee_float_shape_type sf_u;                                  \
+  sf_u.word = (i);                                             \
+  (d) = sf_u.value;                                            \
+} while (0)
+
+/* Macros to avoid undefined behaviour that can arise if the amount
+   of a shift is exactly equal to the size of the shifted operand.  */
+
+#define SAFE_LEFT_SHIFT(op,amt)                                        \
+  (((amt) < 8 * sizeof(op)) ? ((op) << (amt)) : 0)
+
+#define SAFE_RIGHT_SHIFT(op,amt)                               \
+  (((amt) < 8 * sizeof(op)) ? ((op) >> (amt)) : 0)
+
+#ifdef  _COMPLEX_H
+
+/*
+ * Quoting from ISO/IEC 9899:TC2:
+ *
+ * 6.2.5.13 Types
+ * Each complex type has the same representation and alignment requirements as
+ * an array type containing exactly two elements of the corresponding real type;
+ * the first element is equal to the real part, and the second element to the
+ * imaginary part, of the complex number.
+ */
+typedef union {
+        float complex z;
+        float parts[2];
+} float_complex;
+
+typedef union {
+        double complex z;
+        double parts[2];
+} double_complex;
+
+typedef union {
+        long double complex z;
+        long double parts[2];
+} long_double_complex;
+
+#define REAL_PART(z)    ((z).parts[0])
+#define IMAG_PART(z)    ((z).parts[1])
+
+#endif  /* _COMPLEX_H */
+
diff --git a/src/math/ieeefp.h b/src/math/ieeefp.h
new file mode 100644 (file)
index 0000000..0b06fb7
--- /dev/null
@@ -0,0 +1,256 @@
+#ifndef _IEEE_FP_H_
+#define _IEEE_FP_H_
+
+#include "_ansi.h"
+
+#include <machine/ieeefp.h>
+
+_BEGIN_STD_C
+
+/* FIXME FIXME FIXME:
+   Neither of __ieee_{float,double}_shape_tape seem to be used anywhere
+   except in libm/test.  If that is the case, please delete these from here.
+   If that is not the case, please insert documentation here describing why
+   they're needed.  */
+
+#ifdef __IEEE_BIG_ENDIAN
+
+typedef union 
+{
+  double value;
+  struct 
+  {
+    unsigned int sign : 1;
+    unsigned int exponent: 11;
+    unsigned int fraction0:4;
+    unsigned int fraction1:16;
+    unsigned int fraction2:16;
+    unsigned int fraction3:16;
+    
+  } number;
+  struct 
+  {
+    unsigned int sign : 1;
+    unsigned int exponent: 11;
+    unsigned int quiet:1;
+    unsigned int function0:3;
+    unsigned int function1:16;
+    unsigned int function2:16;
+    unsigned int function3:16;
+  } nan;
+  struct 
+  {
+    unsigned long msw;
+    unsigned long lsw;
+  } parts;
+    long aslong[2];
+} __ieee_double_shape_type;
+
+#endif
+
+#ifdef __IEEE_LITTLE_ENDIAN
+
+typedef union 
+{
+  double value;
+  struct 
+  {
+#ifdef __SMALL_BITFIELDS
+    unsigned int fraction3:16;
+    unsigned int fraction2:16;
+    unsigned int fraction1:16;
+    unsigned int fraction0: 4;
+#else
+    unsigned int fraction1:32;
+    unsigned int fraction0:20;
+#endif
+    unsigned int exponent :11;
+    unsigned int sign     : 1;
+  } number;
+  struct 
+  {
+#ifdef __SMALL_BITFIELDS
+    unsigned int function3:16;
+    unsigned int function2:16;
+    unsigned int function1:16;
+    unsigned int function0:3;
+#else
+    unsigned int function1:32;
+    unsigned int function0:19;
+#endif
+    unsigned int quiet:1;
+    unsigned int exponent: 11;
+    unsigned int sign : 1;
+  } nan;
+  struct 
+  {
+    unsigned long lsw;
+    unsigned long msw;
+  } parts;
+
+  long aslong[2];
+
+} __ieee_double_shape_type;
+
+#endif
+
+#ifdef __IEEE_BIG_ENDIAN
+
+typedef union
+{
+  float value;
+  struct 
+  {
+    unsigned int sign : 1;
+    unsigned int exponent: 8;
+    unsigned int fraction0: 7;
+    unsigned int fraction1: 16;
+  } number;
+  struct 
+  {
+    unsigned int sign:1;
+    unsigned int exponent:8;
+    unsigned int quiet:1;
+    unsigned int function0:6;
+    unsigned int function1:16;
+  } nan;
+  long p1;
+  
+} __ieee_float_shape_type;
+
+#endif
+
+#ifdef __IEEE_LITTLE_ENDIAN
+
+typedef union
+{
+  float value;
+  struct 
+  {
+    unsigned int fraction0: 7;
+    unsigned int fraction1: 16;
+    unsigned int exponent: 8;
+    unsigned int sign : 1;
+  } number;
+  struct 
+  {
+    unsigned int function1:16;
+    unsigned int function0:6;
+    unsigned int quiet:1;
+    unsigned int exponent:8;
+    unsigned int sign:1;
+  } nan;
+  long p1;
+  
+} __ieee_float_shape_type;
+
+#endif
+
+
+
+
+
+/* FLOATING ROUNDING */
+
+typedef int fp_rnd;
+#define FP_RN 0        /* Round to nearest             */
+#define FP_RM 1                /* Round down                   */
+#define FP_RP 2                /* Round up                     */
+#define FP_RZ 3                /* Round to zero (trunate)      */
+
+fp_rnd _EXFUN(fpgetround,(void));
+fp_rnd _EXFUN(fpsetround, (fp_rnd));
+
+/* EXCEPTIONS */
+
+typedef int fp_except;
+#define FP_X_INV 0x10  /* Invalid operation            */
+#define FP_X_DX  0x80  /* Divide by zero               */
+#define FP_X_OFL 0x04  /* Overflow exception           */
+#define FP_X_UFL 0x02  /* Underflow exception          */
+#define FP_X_IMP 0x01  /* imprecise exception          */
+
+fp_except _EXFUN(fpgetmask,(void));
+fp_except _EXFUN(fpsetmask,(fp_except));
+fp_except _EXFUN(fpgetsticky,(void));
+fp_except _EXFUN(fpsetsticky, (fp_except));
+
+/* INTEGER ROUNDING */
+
+typedef int fp_rdi;
+#define FP_RDI_TOZ 0   /* Round to Zero                */
+#define FP_RDI_RD  1   /* Follow float mode            */
+
+fp_rdi _EXFUN(fpgetroundtoi,(void));
+fp_rdi _EXFUN(fpsetroundtoi,(fp_rdi));
+
+#undef isnan
+#undef isinf
+
+int _EXFUN(isnan, (double));
+int _EXFUN(isinf, (double));
+int _EXFUN(finite, (double));
+
+
+
+int _EXFUN(isnanf, (float));
+int _EXFUN(isinff, (float));
+int _EXFUN(finitef, (float));
+
+#define __IEEE_DBL_EXPBIAS 1023
+#define __IEEE_FLT_EXPBIAS 127
+
+#define __IEEE_DBL_EXPLEN 11
+#define __IEEE_FLT_EXPLEN 8
+
+
+#define __IEEE_DBL_FRACLEN (64 - (__IEEE_DBL_EXPLEN + 1))
+#define __IEEE_FLT_FRACLEN (32 - (__IEEE_FLT_EXPLEN + 1))
+
+#define __IEEE_DBL_MAXPOWTWO   ((double)(1L << 32 - 2) * (1L << (32-11) - 32 + 1))
+#define __IEEE_FLT_MAXPOWTWO   ((float)(1L << (32-8) - 1))
+
+#define __IEEE_DBL_NAN_EXP 0x7ff
+#define __IEEE_FLT_NAN_EXP 0xff
+
+#ifndef __ieeefp_isnanf
+#define __ieeefp_isnanf(x) (((*(long *)&(x) & 0x7f800000L)==0x7f800000L) && \
+                           ((*(long *)&(x) & 0x007fffffL)!=0000000000L))
+#endif
+#define isnanf(x)      __ieeefp_isnanf(x)
+
+#ifndef __ieeefp_isinff
+#define __ieeefp_isinff(x) (((*(long *)&(x) & 0x7f800000L)==0x7f800000L) && \
+                           ((*(long *)&(x) & 0x007fffffL)==0000000000L))
+#endif
+#define isinff(x)      __ieeefp_isinff(x)
+
+#ifndef __ieeefp_finitef
+#define __ieeefp_finitef(x) (((*(long *)&(x) & 0x7f800000L)!=0x7f800000L))
+#endif
+#define finitef(x)     __ieeefp_finitef(x)
+
+#ifdef _DOUBLE_IS_32BITS
+#undef __IEEE_DBL_EXPBIAS
+#define __IEEE_DBL_EXPBIAS __IEEE_FLT_EXPBIAS
+
+#undef __IEEE_DBL_EXPLEN
+#define __IEEE_DBL_EXPLEN __IEEE_FLT_EXPLEN
+
+#undef __IEEE_DBL_FRACLEN
+#define __IEEE_DBL_FRACLEN __IEEE_FLT_FRACLEN
+
+#undef __IEEE_DBL_MAXPOWTWO
+#define __IEEE_DBL_MAXPOWTWO __IEEE_FLT_MAXPOWTWO
+
+#undef __IEEE_DBL_NAN_EXP
+#define __IEEE_DBL_NAN_EXP __IEEE_FLT_NAN_EXP
+
+#undef __ieee_double_shape_type
+#define __ieee_double_shape_type __ieee_float_shape_type
+
+#endif /* _DOUBLE_IS_32BITS */
+
+_END_STD_C
+
+#endif /* _IEEE_FP_H_ */
diff --git a/src/math/kf_cos.c b/src/math/kf_cos.c
new file mode 100644 (file)
index 0000000..4f71af2
--- /dev/null
@@ -0,0 +1,59 @@
+/* kf_cos.c -- float version of k_cos.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float 
+#else
+static float 
+#endif
+one =  1.0000000000e+00, /* 0x3f800000 */
+C1  =  4.1666667908e-02, /* 0x3d2aaaab */
+C2  = -1.3888889225e-03, /* 0xbab60b61 */
+C3  =  2.4801587642e-05, /* 0x37d00d01 */
+C4  = -2.7557314297e-07, /* 0xb493f27c */
+C5  =  2.0875723372e-09, /* 0x310f74f6 */
+C6  = -1.1359647598e-11; /* 0xad47d74e */
+
+#ifdef __STDC__
+       float __kernel_cosf(float x, float y)
+#else
+       float __kernel_cosf(x, y)
+       float x,y;
+#endif
+{
+       float a,hz,z,r,qx;
+       __int32_t ix;
+       GET_FLOAT_WORD(ix,x);
+       ix &= 0x7fffffff;                       /* ix = |x|'s high word*/
+       if(ix<0x32000000) {                     /* if x < 2**27 */
+           if(((int)x)==0) return one;         /* generate inexact */
+       }
+       z  = x*x;
+       r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+       if(ix < 0x3e99999a)                     /* if |x| < 0.3 */ 
+           return one - ((float)0.5*z - (z*r - x*y));
+       else {
+           if(ix > 0x3f480000) {               /* x > 0.78125 */
+               qx = (float)0.28125;
+           } else {
+               SET_FLOAT_WORD(qx,ix-0x01000000);       /* x/4 */
+           }
+           hz = (float)0.5*z-qx;
+           a  = one-qx;
+           return a - (hz - (z*r-x*y));
+       }
+}
diff --git a/src/math/kf_rem_pio2.c b/src/math/kf_rem_pio2.c
new file mode 100644 (file)
index 0000000..261c481
--- /dev/null
@@ -0,0 +1,208 @@
+/* kf_rem_pio2.c -- float version of k_rem_pio2.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+/* In the float version, the input parameter x contains 8 bit
+   integers, not 24 bit integers.  113 bit precision is not supported.  */
+
+#ifdef __STDC__
+static const int init_jk[] = {4,7,9}; /* initial value for jk */
+#else
+static int init_jk[] = {4,7,9}; 
+#endif
+
+#ifdef __STDC__
+static const float PIo2[] = {
+#else
+static float PIo2[] = {
+#endif
+  1.5703125000e+00, /* 0x3fc90000 */
+  4.5776367188e-04, /* 0x39f00000 */
+  2.5987625122e-05, /* 0x37da0000 */
+  7.5437128544e-08, /* 0x33a20000 */
+  6.0026650317e-11, /* 0x2e840000 */
+  7.3896444519e-13, /* 0x2b500000 */
+  5.3845816694e-15, /* 0x27c20000 */
+  5.6378512969e-18, /* 0x22d00000 */
+  8.3009228831e-20, /* 0x1fc40000 */
+  3.2756352257e-22, /* 0x1bc60000 */
+  6.3331015649e-25, /* 0x17440000 */
+};
+
+#ifdef __STDC__
+static const float                     
+#else
+static float                   
+#endif
+zero   = 0.0,
+one    = 1.0,
+two8   =  2.5600000000e+02, /* 0x43800000 */
+twon8  =  3.9062500000e-03; /* 0x3b800000 */
+
+#ifdef __STDC__
+       int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __int32_t *ipio2) 
+#else
+       int __kernel_rem_pio2f(x,y,e0,nx,prec,ipio2)    
+       float x[], y[]; int e0,nx,prec; __int32_t ipio2[];
+#endif
+{
+       __int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+       float z,fw,f[20],fq[20],q[20];
+
+    /* initialize jk*/
+       jk = init_jk[prec];
+       jp = jk;
+
+    /* determine jx,jv,q0, note that 3>q0 */
+       jx =  nx-1;
+       jv = (e0-3)/8; if(jv<0) jv=0;
+       q0 =  e0-8*(jv+1);
+
+    /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+       j = jv-jx; m = jx+jk;
+       for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j];
+
+    /* compute q[0],q[1],...q[jk] */
+       for (i=0;i<=jk;i++) {
+           for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+       }
+
+       jz = jk;
+recompute:
+    /* distill q[] into iq[] reversingly */
+       for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+           fw    =  (float)((__int32_t)(twon8* z));
+           iq[i] =  (__int32_t)(z-two8*fw);
+           z     =  q[j-1]+fw;
+       }
+
+    /* compute n */
+       z  = scalbnf(z,(int)q0);        /* actual value of z */
+       z -= (float)8.0*floorf(z*(float)0.125); /* trim off integer >= 8 */
+       n  = (__int32_t) z;
+       z -= (float)n;
+       ih = 0;
+       if(q0>0) {      /* need iq[jz-1] to determine n */
+           i  = (iq[jz-1]>>(8-q0)); n += i;
+           iq[jz-1] -= i<<(8-q0);
+           ih = iq[jz-1]>>(7-q0);
+       } 
+       else if(q0==0) ih = iq[jz-1]>>8;
+       else if(z>=(float)0.5) ih=2;
+
+       if(ih>0) {      /* q > 0.5 */
+           n += 1; carry = 0;
+           for(i=0;i<jz ;i++) {        /* compute 1-q */
+               j = iq[i];
+               if(carry==0) {
+                   if(j!=0) {
+                       carry = 1; iq[i] = 0x100- j;
+                   }
+               } else  iq[i] = 0xff - j;
+           }
+           if(q0>0) {          /* rare case: chance is 1 in 12 */
+               switch(q0) {
+               case 1:
+                  iq[jz-1] &= 0x7f; break;
+               case 2:
+                  iq[jz-1] &= 0x3f; break;
+               }
+           }
+           if(ih==2) {
+               z = one - z;
+               if(carry!=0) z -= scalbnf(one,(int)q0);
+           }
+       }
+
+    /* check if recomputation is needed */
+       if(z==zero) {
+           j = 0;
+           for (i=jz-1;i>=jk;i--) j |= iq[i];
+           if(j==0) { /* need recomputation */
+               for(k=1;iq[jk-k]==0;k++);   /* k = no. of terms needed */
+
+               for(i=jz+1;i<=jz+k;i++) {   /* add q[jz+1] to q[jz+k] */
+                   f[jx+i] = (float) ipio2[jv+i];
+                   for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+                   q[i] = fw;
+               }
+               jz += k;
+               goto recompute;
+           }
+       }
+
+    /* chop off zero terms */
+       if(z==(float)0.0) {
+           jz -= 1; q0 -= 8;
+           while(iq[jz]==0) { jz--; q0-=8;}
+       } else { /* break z into 8-bit if necessary */
+           z = scalbnf(z,-(int)q0);
+           if(z>=two8) { 
+               fw = (float)((__int32_t)(twon8*z));
+               iq[jz] = (__int32_t)(z-two8*fw);
+               jz += 1; q0 += 8;
+               iq[jz] = (__int32_t) fw;
+           } else iq[jz] = (__int32_t) z ;
+       }
+
+    /* convert integer "bit" chunk to floating-point value */
+       fw = scalbnf(one,(int)q0);
+       for(i=jz;i>=0;i--) {
+           q[i] = fw*(float)iq[i]; fw*=twon8;
+       }
+
+    /* compute PIo2[0,...,jp]*q[jz,...,0] */
+       for(i=jz;i>=0;i--) {
+           for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+           fq[jz-i] = fw;
+       }
+
+    /* compress fq[] into y[] */
+       switch(prec) {
+           case 0:
+               fw = 0.0;
+               for (i=jz;i>=0;i--) fw += fq[i];
+               y[0] = (ih==0)? fw: -fw; 
+               break;
+           case 1:
+           case 2:
+               fw = 0.0;
+               for (i=jz;i>=0;i--) fw += fq[i]; 
+               y[0] = (ih==0)? fw: -fw; 
+               fw = fq[0]-fw;
+               for (i=1;i<=jz;i++) fw += fq[i];
+               y[1] = (ih==0)? fw: -fw; 
+               break;
+           case 3:     /* painful */
+               for (i=jz;i>0;i--) {
+                   fw      = fq[i-1]+fq[i]; 
+                   fq[i]  += fq[i-1]-fw;
+                   fq[i-1] = fw;
+               }
+               for (i=jz;i>1;i--) {
+                   fw      = fq[i-1]+fq[i]; 
+                   fq[i]  += fq[i-1]-fw;
+                   fq[i-1] = fw;
+               }
+               for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; 
+               if(ih==0) {
+                   y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw;
+               } else {
+                   y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+               }
+       }
+       return n&7;
+}
diff --git a/src/math/kf_sin.c b/src/math/kf_sin.c
new file mode 100644 (file)
index 0000000..e81fa0b
--- /dev/null
@@ -0,0 +1,49 @@
+/* kf_sin.c -- float version of k_sin.c
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float 
+#else
+static float 
+#endif
+half =  5.0000000000e-01,/* 0x3f000000 */
+S1  = -1.6666667163e-01, /* 0xbe2aaaab */
+S2  =  8.3333337680e-03, /* 0x3c088889 */
+S3  = -1.9841270114e-04, /* 0xb9500d01 */
+S4  =  2.7557314297e-06, /* 0x3638ef1b */
+S5  = -2.5050759689e-08, /* 0xb2d72f34 */
+S6  =  1.5896910177e-10; /* 0x2f2ec9d3 */
+
+#ifdef __STDC__
+       float __kernel_sinf(float x, float y, int iy)
+#else
+       float __kernel_sinf(x, y, iy)
+       float x,y; int iy;              /* iy=0 if y is zero */
+#endif
+{
+       float z,r,v;
+       __int32_t ix;
+       GET_FLOAT_WORD(ix,x);
+       ix &= 0x7fffffff;                       /* high word of x */
+       if(ix<0x32000000)                       /* |x| < 2**-27 */
+          {if((int)x==0) return x;}            /* generate inexact */
+       z       =  x*x;
+       v       =  z*x;
+       r       =  S2+z*(S3+z*(S4+z*(S5+z*S6)));
+       if(iy==0) return x+v*(S1+z*r);
+       else      return x-((z*(half*y-v*r)-y)-v*S1);
+}
diff --git a/src/math/machine/ieeefp.h b/src/math/machine/ieeefp.h
new file mode 100644 (file)
index 0000000..fffa380
--- /dev/null
@@ -0,0 +1,382 @@
+#ifndef __IEEE_BIG_ENDIAN
+#ifndef __IEEE_LITTLE_ENDIAN
+
+/* This file can define macros to choose variations of the IEEE float
+   format:
+
+   _FLT_LARGEST_EXPONENT_IS_NORMAL
+
+       Defined if the float format uses the largest exponent for finite
+       numbers rather than NaN and infinity representations.  Such a
+       format cannot represent NaNs or infinities at all, but it's FLT_MAX
+       is twice the IEEE value.
+
+   _FLT_NO_DENORMALS
+
+       Defined if the float format does not support IEEE denormals.  Every
+       float with a zero exponent is taken to be a zero representation.
+   ??? At the moment, there are no equivalent macros above for doubles and
+   the macros are not fully supported by --enable-newlib-hw-fp.
+
+   __IEEE_BIG_ENDIAN
+
+        Defined if the float format is big endian.  This is mutually exclusive
+        with __IEEE_LITTLE_ENDIAN.
+
+   __IEEE_LITTLE_ENDIAN
+        Defined if the float format is little endian.  This is mutually exclusive
+        with __IEEE_BIG_ENDIAN.
+
+   Note that one of __IEEE_BIG_ENDIAN or __IEEE_LITTLE_ENDIAN must be specified for a
+   platform or error will occur.
+
+   __IEEE_BYTES_LITTLE_ENDIAN
+
+        This flag is used in conjunction with __IEEE_BIG_ENDIAN to describe a situation 
+       whereby multiple words of an IEEE floating point are in big endian order, but the
+       words themselves are little endian with respect to the bytes.
+
+   _DOUBLE_IS_32BITS 
+
+        This is used on platforms that support double by using the 32-bit IEEE
+        float type.
+
+   _FLOAT_ARG
+
+        This represents what type a float arg is passed as.  It is used when the type is
+        not promoted to double.
+       
+*/
+
+#if (defined(__arm__) || defined(__thumb__)) && !defined(__MAVERICK__)
+/* ARM traditionally used big-endian words; and within those words the
+   byte ordering was big or little endian depending upon the target.
+   Modern floating-point formats are naturally ordered; in this case
+   __VFP_FP__ will be defined, even if soft-float.  */
+#ifdef __VFP_FP__
+# ifdef __ARMEL__
+#  define __IEEE_LITTLE_ENDIAN
+# else
+#  define __IEEE_BIG_ENDIAN
+# endif
+#else
+# define __IEEE_BIG_ENDIAN
+# ifdef __ARMEL__
+#  define __IEEE_BYTES_LITTLE_ENDIAN
+# endif
+#endif
+#endif
+
+#ifdef __hppa__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __SPU__
+#define __IEEE_BIG_ENDIAN
+
+#define isfinite(__y) \
+       (__extension__ ({int __cy; \
+               (sizeof (__y) == sizeof (float))  ? (1) : \
+               (__cy = fpclassify(__y)) != FP_INFINITE && __cy != FP_NAN;}))
+
+#define isinf(__x) ((sizeof (__x) == sizeof (float))  ?  (0) : __isinfd(__x))
+#define isnan(__x) ((sizeof (__x) == sizeof (float))  ?  (0) : __isnand(__x))
+
+/*
+ * Macros for use in ieeefp.h. We can't just define the real ones here
+ * (like those above) as we have name space issues when this is *not*
+ * included via generic the ieeefp.h.
+ */
+#define __ieeefp_isnanf(x)     0
+#define __ieeefp_isinff(x)     0
+#define __ieeefp_finitef(x)    1
+#endif
+
+#ifdef __sparc__
+#ifdef __LITTLE_ENDIAN_DATA__
+#define __IEEE_LITTLE_ENDIAN
+#else
+#define __IEEE_BIG_ENDIAN
+#endif
+#endif
+
+#if defined(__m68k__) || defined(__mc68000__)
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#if defined(__mc68hc11__) || defined(__mc68hc12__) || defined(__mc68hc1x__)
+#define __IEEE_BIG_ENDIAN
+#ifdef __HAVE_SHORT_DOUBLE__
+# define _DOUBLE_IS_32BITS
+#endif
+#endif
+
+#if defined (__H8300__) || defined (__H8300H__) || defined (__H8300S__) || defined (__H8500__) || defined (__H8300SX__)
+#define __IEEE_BIG_ENDIAN
+#define _FLOAT_ARG float
+#define _DOUBLE_IS_32BITS
+#endif
+
+#if defined (__xc16x__) || defined (__xc16xL__) || defined (__xc16xS__)
+#define __IEEE_LITTLE_ENDIAN
+#define _FLOAT_ARG float
+#define _DOUBLE_IS_32BITS
+#endif
+
+
+#ifdef __sh__
+#ifdef __LITTLE_ENDIAN__
+#define __IEEE_LITTLE_ENDIAN
+#else
+#define __IEEE_BIG_ENDIAN
+#endif
+#if defined(__SH2E__) || defined(__SH3E__) || defined(__SH4_SINGLE_ONLY__) || defined(__SH2A_SINGLE_ONLY__)
+#define _DOUBLE_IS_32BITS
+#endif
+#endif
+
+#ifdef _AM29K
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef _WIN32
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __i386__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __i960__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __lm32__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __M32R__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#if defined(_C4x) || defined(_C3x)
+#define __IEEE_BIG_ENDIAN
+#define _DOUBLE_IS_32BITS
+#endif
+
+#ifdef __TMS320C6X__
+#ifdef _BIG_ENDIAN
+#define __IEEE_BIG_ENDIAN
+#else
+#define __IEEE_LITTLE_ENDIAN
+#endif
+#endif
+
+#ifdef __TIC80__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __MIPSEL__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+#ifdef __MIPSEB__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __MMIX__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __D30V__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+/* necv70 was __IEEE_LITTLE_ENDIAN. */
+
+#ifdef __W65__
+#define __IEEE_LITTLE_ENDIAN
+#define _DOUBLE_IS_32BITS
+#endif
+
+#if defined(__Z8001__) || defined(__Z8002__)
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __m88k__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __mn10300__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __mn10200__
+#define __IEEE_LITTLE_ENDIAN
+#define _DOUBLE_IS_32BITS
+#endif
+
+#ifdef __v800
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __v850
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __D10V__
+#define __IEEE_BIG_ENDIAN
+#if __DOUBLE__ == 32
+#define _DOUBLE_IS_32BITS
+#endif
+#endif
+
+#ifdef __PPC__
+#if (defined(_BIG_ENDIAN) && _BIG_ENDIAN) || (defined(_AIX) && _AIX)
+#define __IEEE_BIG_ENDIAN
+#else
+#if (defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN) || (defined(__sun__) && __sun__) || (defined(_WIN32) && _WIN32)
+#define __IEEE_LITTLE_ENDIAN
+#endif
+#endif
+#endif
+
+#ifdef __xstormy16__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __arc__
+#ifdef __big_endian__
+#define __IEEE_BIG_ENDIAN
+#else
+#define __IEEE_LITTLE_ENDIAN
+#endif
+#endif
+
+#ifdef __CRX__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __fr30__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __mcore__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __mt__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __frv__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __moxie__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __ia64__
+#ifdef __BIG_ENDIAN__
+#define __IEEE_BIG_ENDIAN
+#else
+#define __IEEE_LITTLE_ENDIAN
+#endif
+#endif
+
+#ifdef __AVR__
+#define __IEEE_LITTLE_ENDIAN
+#define _DOUBLE_IS_32BITS
+#endif
+
+#if defined(__or32__) || defined(__or1k__) || defined(__or16__)
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __IP2K__
+#define __IEEE_BIG_ENDIAN
+#define __SMALL_BITFIELDS
+#define _DOUBLE_IS_32BITS
+#endif
+
+#ifdef __iq2000__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __MAVERICK__
+#ifdef __ARMEL__
+#  define __IEEE_LITTLE_ENDIAN
+#else  /* must be __ARMEB__ */
+#  define __IEEE_BIG_ENDIAN
+#endif /* __ARMEL__ */
+#endif /* __MAVERICK__ */
+
+#ifdef __m32c__
+#define __IEEE_LITTLE_ENDIAN
+#define __SMALL_BITFIELDS
+#endif
+
+#ifdef __CRIS__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __BFIN__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __x86_64__
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __mep__
+#ifdef __LITTLE_ENDIAN__
+#define __IEEE_LITTLE_ENDIAN
+#else
+#define __IEEE_BIG_ENDIAN
+#endif
+#endif
+
+#ifdef __MICROBLAZE__
+#define __IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __RL78__
+#define __IEEE_LITTLE_ENDIAN
+#define __SMALL_BITFIELDS      /* 16 Bit INT */
+#define _DOUBLE_IS_32BITS
+#endif
+
+#ifdef __RX__
+
+#ifdef __RX_BIG_ENDIAN__
+#define __IEEE_BIG_ENDIAN
+#else
+#define __IEEE_LITTLE_ENDIAN
+#endif
+
+#ifndef __RX_64BIT_DOUBLES__
+#define _DOUBLE_IS_32BITS
+#endif
+
+#ifdef __RX_16BIT_INTS__
+#define __SMALL_BITFIELDS
+#endif
+
+#endif
+
+#if (defined(__CR16__) || defined(__CR16C__) ||defined(__CR16CP__))
+#define __IEEE_LITTLE_ENDIAN
+#define __SMALL_BITFIELDS      /* 16 Bit INT */
+#endif
+
+#ifndef __IEEE_BIG_ENDIAN
+#ifndef __IEEE_LITTLE_ENDIAN
+#error Endianess not declared!!
+#endif /* not __IEEE_LITTLE_ENDIAN */
+#endif /* not __IEEE_BIG_ENDIAN */
+
+#endif /* not __IEEE_LITTLE_ENDIAN */
+#endif /* not __IEEE_BIG_ENDIAN */
+
diff --git a/src/math/math.h b/src/math/math.h
new file mode 100644 (file)
index 0000000..fd543bc
--- /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; 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 _MATH_H_
+#define _MATH_H_
+
+float acosf(float x);
+
+float cosf(float x);
+
+float sinf(float x);
+
+float sqrtf(float x);
+
+float fabsf(float x);
+
+float floorf(float x);
+
+float scalbnf(float x, int n);
+
+float copysignf(float x, float y);
+
+#endif
diff --git a/src/math/sf_copysign.c b/src/math/sf_copysign.c
new file mode 100644 (file)
index 0000000..f547c82
--- /dev/null
@@ -0,0 +1,50 @@
+/* sf_copysign.c -- float version of s_copysign.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * copysignf(float x, float y)
+ * copysignf(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+       float copysignf(float x, float y)
+#else
+       float copysignf(x,y)
+       float x,y;
+#endif
+{
+       __uint32_t ix,iy;
+       GET_FLOAT_WORD(ix,x);
+       GET_FLOAT_WORD(iy,y);
+       SET_FLOAT_WORD(x,(ix&0x7fffffff)|(iy&0x80000000));
+        return x;
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+       double copysign(double x, double y)
+#else
+       double copysign(x,y)
+       double x,y;
+#endif
+{
+       return (double) copysignf((float) x, (float) y);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/src/math/sf_cos.c b/src/math/sf_cos.c
new file mode 100644 (file)
index 0000000..4c0a9a5
--- /dev/null
@@ -0,0 +1,68 @@
+/* sf_cos.c -- float version of s_cos.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float one=1.0;
+#else
+static float one=1.0;
+#endif
+
+#ifdef __STDC__
+       float cosf(float x)
+#else
+       float cosf(x)
+       float x;
+#endif
+{
+       float y[2],z=0.0;
+       __int32_t n,ix;
+
+       GET_FLOAT_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+       ix &= 0x7fffffff;
+       if(ix <= 0x3f490fd8) return __kernel_cosf(x,z);
+
+    /* cos(Inf or NaN) is NaN */
+       else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
+
+    /* argument reduction needed */
+       else {
+           n = __ieee754_rem_pio2f(x,y);
+           switch(n&3) {
+               case 0: return  __kernel_cosf(y[0],y[1]);
+               case 1: return -__kernel_sinf(y[0],y[1],1);
+               case 2: return -__kernel_cosf(y[0],y[1]);
+               default:
+                       return  __kernel_sinf(y[0],y[1],1);
+           }
+       }
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+       double cos(double x)
+#else
+       double cos(x)
+       double x;
+#endif
+{
+       return (double) cosf((float) x);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/src/math/sf_fabs.c b/src/math/sf_fabs.c
new file mode 100644 (file)
index 0000000..2aaed32
--- /dev/null
@@ -0,0 +1,47 @@
+/* sf_fabs.c -- float version of s_fabs.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fabsf(x) returns the absolute value of x.
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+       float fabsf(float x)
+#else
+       float fabsf(x)
+       float x;
+#endif
+{
+       __uint32_t ix;
+       GET_FLOAT_WORD(ix,x);
+       SET_FLOAT_WORD(x,ix&0x7fffffff);
+        return x;
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+       double fabs(double x)
+#else
+       double fabs(x)
+       double x;
+#endif
+{
+       return (double) fabsf((float) x);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/src/math/sf_floor.c b/src/math/sf_floor.c
new file mode 100644 (file)
index 0000000..9264d81
--- /dev/null
@@ -0,0 +1,80 @@
+/* sf_floor.c -- float version of s_floor.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * floorf(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *     Bit twiddling.
+ * Exception:
+ *     Inexact flag raised if x not equal to floorf(x).
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+static const float huge = 1.0e30;
+#else
+static float huge = 1.0e30;
+#endif
+
+#ifdef __STDC__
+       float floorf(float x)
+#else
+       float floorf(x)
+       float x;
+#endif
+{
+       __int32_t i0,j0;
+       __uint32_t i,ix;
+       GET_FLOAT_WORD(i0,x);
+       ix = (i0&0x7fffffff);
+       j0 = (ix>>23)-0x7f;
+       if(j0<23) {
+           if(j0<0) {  /* raise inexact if x != 0 */
+               if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
+                   if(i0>=0) {i0=0;} 
+                   else if(!FLT_UWORD_IS_ZERO(ix))
+                       { i0=0xbf800000;}
+               }
+           } else {
+               i = (0x007fffff)>>j0;
+               if((i0&i)==0) return x; /* x is integral */
+               if(huge+x>(float)0.0) { /* raise inexact flag */
+                   if(i0<0) i0 += (0x00800000)>>j0;
+                   i0 &= (~i);
+               }
+           }
+       } else {
+           if(!FLT_UWORD_IS_FINITE(ix)) return x+x;    /* inf or NaN */
+           else return x;              /* x is integral */
+       }
+       SET_FLOAT_WORD(x,i0);
+       return x;
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+       double floor(double x)
+#else
+       double floor(x)
+       double x;
+#endif
+{
+       return (double) floorf((float) x);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/src/math/sf_scalbn.c b/src/math/sf_scalbn.c
new file mode 100644 (file)
index 0000000..7000600
--- /dev/null
@@ -0,0 +1,86 @@
+/* sf_scalbn.c -- float version of s_scalbn.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+#include <limits.h>
+#include <float.h>
+
+#if INT_MAX > 50000
+#define OVERFLOW_INT 50000
+#else
+#define OVERFLOW_INT 30000
+#endif
+
+#ifdef __STDC__
+static const float
+#else
+static float
+#endif
+two25   =  3.355443200e+07,    /* 0x4c000000 */
+twom25  =  2.9802322388e-08,   /* 0x33000000 */
+huge   = 1.0e+30,
+tiny   = 1.0e-30;
+
+#ifdef __STDC__
+       float scalbnf (float x, int n)
+#else
+       float scalbnf (x,n)
+       float x; int n;
+#endif
+{
+       __int32_t  k,ix;
+       __uint32_t hx;
+
+       GET_FLOAT_WORD(ix,x);
+       hx = ix&0x7fffffff;
+        k = hx>>23;            /* extract exponent */
+       if (FLT_UWORD_IS_ZERO(hx))
+           return x;
+        if (!FLT_UWORD_IS_FINITE(hx))
+           return x+x;         /* NaN or Inf */
+        if (FLT_UWORD_IS_SUBNORMAL(hx)) {
+           x *= two25;
+           GET_FLOAT_WORD(ix,x);
+           k = ((ix&0x7f800000)>>23) - 25; 
+            if (n< -50000) return tiny*x;      /*underflow*/
+        }
+        k = k+n; 
+        if (k > FLT_LARGEST_EXP) return huge*copysignf(huge,x); /* overflow  */
+        if (k > 0)                             /* normal result */
+           {SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23)); return x;}
+        if (k < FLT_SMALLEST_EXP) {
+            if (n > OVERFLOW_INT)      /* in case integer overflow in n+k */
+               return huge*copysignf(huge,x);  /*overflow*/
+           else return tiny*copysignf(tiny,x); /*underflow*/
+        }
+        k += 25;                               /* subnormal result */
+       SET_FLOAT_WORD(x,(ix&0x807fffff)|(k<<23));
+        return x*twom25;
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+       double scalbn(double x, int n)
+#else
+       double scalbn(x,n)
+       double x;
+       int n;
+#endif
+{
+       return (double) scalbnf((float) x, n);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
diff --git a/src/math/sf_sin.c b/src/math/sf_sin.c
new file mode 100644 (file)
index 0000000..da81845
--- /dev/null
@@ -0,0 +1,62 @@
+/* sf_sin.c -- float version of s_sin.c.
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+#include "fdlibm.h"
+
+#ifdef __STDC__
+       float sinf(float x)
+#else
+       float sinf(x)
+       float x;
+#endif
+{
+       float y[2],z=0.0;
+       __int32_t n,ix;
+
+       GET_FLOAT_WORD(ix,x);
+
+    /* |x| ~< pi/4 */
+       ix &= 0x7fffffff;
+       if(ix <= 0x3f490fd8) return __kernel_sinf(x,z,0);
+
+    /* sin(Inf or NaN) is NaN */
+       else if (!FLT_UWORD_IS_FINITE(ix)) return x-x;
+
+    /* argument reduction needed */
+       else {
+           n = __ieee754_rem_pio2f(x,y);
+           switch(n&3) {
+               case 0: return  __kernel_sinf(y[0],y[1],1);
+               case 1: return  __kernel_cosf(y[0],y[1]);
+               case 2: return -__kernel_sinf(y[0],y[1],1);
+               default:
+                       return -__kernel_cosf(y[0],y[1]);
+           }
+       }
+}
+
+#ifdef _DOUBLE_IS_32BITS
+
+#ifdef __STDC__
+       double sin(double x)
+#else
+       double sin(x)
+       double x;
+#endif
+{
+       return (double) sinf((float) x);
+}
+
+#endif /* defined(_DOUBLE_IS_32BITS) */
index 7f12963f00f9fee5137a8992f3cc5b9dae8bfd21..6035c3482576e71a3bc6bbdef6960b02219b108b 100644 (file)
@@ -62,14 +62,15 @@ CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STA
 
 PROGNAME=megadongle-v0.1
 PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
 
 SRC=$(ALTOS_SRC) ao_megadongle.c
 OBJ=$(SRC:.c=.o)
 
-all: $(PROG)
+all: $(PROG) $(HEX)
 
 $(PROG): Makefile $(OBJ) altos.ld
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
 
 $(OBJ): $(INC)
 
@@ -79,7 +80,7 @@ ao_product.h: ao-make-product.5c ../Version
 distclean:     clean
 
 clean:
-       rm -f *.o $(PROGNAME)-*.elf
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
        rm -f ao_product.h
 
 install:
index 315b93f6f91df9e6037c49cf0712240bb41b08a5..dcc328749af927de6f31484054a6d88ef177b5f4 100644 (file)
@@ -2,23 +2,19 @@
 # Tiny AltOS build
 #
 #
-vpath % ../attiny:../drivers:../core:..
+vpath % ../attiny:../drivers:../core:../product:..
 vpath ao-make-product.5c ../util
 vpath make-altitude-pa ../util
 
+include ../avr/Makefile.defs
+
 MCU=attiny85
 DUDECPUTYPE=t85
 #PROGRAMMER=stk500v2 -P usb
-PROGRAMMER=usbtiny
-LOADCMD=avrdude
 LOADSLOW=-i 32 -B 32
 LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc
-OBJCOPY=avr-objcopy
 
-ifndef VERSION
-include ../Version
-endif
+#LDFLAGS=-L$(LDSCRIPTS) -Tavr25.x
 
 ALTOS_SRC = \
        ao_micropeak.c \
@@ -28,7 +24,7 @@ ALTOS_SRC = \
        ao_ms5607.c \
        ao_exti.c \
        ao_convert_pa.c \
-       ao_report_tiny.c \
+       ao_report_micro.c \
        ao_notask.c \
        ao_eeprom_tiny.c \
        ao_panic.c \
@@ -51,7 +47,7 @@ INC=\
 IDPRODUCT=0
 PRODUCT=MicroPeak-v0.1
 PRODUCT_DEF=-DMICROPEAK
-CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../core -I.. -I../drivers
+CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../core -I.. -I../drivers -I../product
 CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY
 
 NICKLE=nickle
diff --git a/src/micropeak/ao_async.c b/src/micropeak/ao_async.c
deleted file mode 100644 (file)
index 3556f54..0000000
+++ /dev/null
@@ -1,71 +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; 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_async.h>
-
-#define AO_ASYNC_BAUD  38400l
-#define AO_ASYNC_DELAY (uint8_t) (1000000l / AO_ASYNC_BAUD)
-
-#define LED_PORT       PORTB
-
-void
-ao_async_start(void)
-{
-       LED_PORT |= (1 << AO_LED_SERIAL);
-}
-
-void
-ao_async_stop(void)
-{
-       LED_PORT &= ~(1 << AO_LED_SERIAL);
-}
-
-void
-ao_async_byte(uint8_t byte)
-{
-       uint8_t         b;
-       uint16_t        w;
-
-       /*    start           data           stop */
-       w = (0x000 << 0) | (byte << 1) | (0x001 << 9);
-
-       ao_arch_block_interrupts();
-       for (b = 0; b < 10; b++) {
-               uint8_t v = LED_PORT & ~(1 << AO_LED_SERIAL);
-               v |= (w & 1) << AO_LED_SERIAL;
-               LED_PORT = v;
-               w >>= 1;
-
-               /* Carefully timed to hit around 9600 baud */
-               asm volatile ("nop");
-               asm volatile ("nop");
-
-               asm volatile ("nop");
-               asm volatile ("nop");
-               asm volatile ("nop");
-               asm volatile ("nop");
-               asm volatile ("nop");
-
-               asm volatile ("nop");
-               asm volatile ("nop");
-               asm volatile ("nop");
-               asm volatile ("nop");
-               asm volatile ("nop");
-       }
-       ao_arch_release_interrupts();
-}
diff --git a/src/micropeak/ao_async.h b/src/micropeak/ao_async.h
deleted file mode 100644 (file)
index 1b23971..0000000
+++ /dev/null
@@ -1,30 +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; 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_ASYNC_H_
-#define _AO_ASYNC_H_
-
-void
-ao_async_start(void);
-
-void
-ao_async_stop(void);
-
-void
-ao_async_byte(uint8_t byte);
-
-#endif /* _AO_ASYNC_H_ */
diff --git a/src/micropeak/ao_log_micro.c b/src/micropeak/ao_log_micro.c
deleted file mode 100644 (file)
index d665efb..0000000
+++ /dev/null
@@ -1,121 +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; 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_micropeak.h>
-#include <ao_log_micro.h>
-#include <ao_async.h>
-
-static uint16_t ao_log_offset = STARTING_LOG_OFFSET;
-
-void
-ao_log_micro_save(void)
-{
-       uint16_t        n_samples = (ao_log_offset - STARTING_LOG_OFFSET) / sizeof (uint16_t);
-       ao_eeprom_write(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
-       ao_eeprom_write(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
-       ao_eeprom_write(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
-}
-
-void
-ao_log_micro_restore(void)
-{
-       ao_eeprom_read(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
-       ao_eeprom_read(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
-}
-
-void
-ao_log_micro_data(void)
-{
-       uint16_t        low_bits = pa;
-
-       if (ao_log_offset < MAX_LOG_OFFSET) {
-               ao_eeprom_write(ao_log_offset, &low_bits, sizeof (low_bits));
-               ao_log_offset += sizeof (low_bits);
-       }
-}
-
-#define POLY 0x8408
-
-static uint16_t
-ao_log_micro_crc(uint16_t crc, uint8_t byte)
-{
-       uint8_t i;
-
-       for (i = 0; i < 8; i++) {
-               if ((crc & 0x0001) ^ (byte & 0x0001))
-                       crc = (crc >> 1) ^ POLY;
-               else
-                       crc = crc >> 1;
-               byte >>= 1;
-       }
-       return crc;
-}
-
-static void
-ao_log_hex_nibble(uint8_t b)
-{
-       if (b < 10)
-               ao_async_byte('0' + b);
-       else
-               ao_async_byte('a' - 10 + b);
-}
-
-static void
-ao_log_hex(uint8_t b)
-{
-       ao_log_hex_nibble(b>>4);
-       ao_log_hex_nibble(b&0xf);
-}
-
-static void
-ao_log_newline(void)
-{
-       ao_async_byte('\r');
-       ao_async_byte('\n');
-}
-
-void
-ao_log_micro_dump(void)
-{
-       uint16_t        n_samples;
-       uint16_t        nbytes;
-       uint8_t         byte;
-       uint16_t        b;
-       uint16_t        crc = 0xffff;
-
-       ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
-       if (n_samples == 0xffff)
-               n_samples = 0;
-       nbytes = STARTING_LOG_OFFSET + sizeof (uint16_t) * n_samples;
-       ao_async_start();
-       ao_async_byte('M');
-       ao_async_byte('P');
-       for (b = 0; b < nbytes; b++) {
-               if ((b & 0xf) == 0)
-                       ao_log_newline();
-               ao_eeprom_read(b, &byte, 1);
-               ao_log_hex(byte);
-               crc = ao_log_micro_crc(crc, byte);
-       }
-       ao_log_newline();
-       crc = ~crc;
-       ao_log_hex(crc >> 8);
-       ao_log_hex(crc);
-       ao_log_newline();
-       ao_async_stop();
-}
diff --git a/src/micropeak/ao_log_micro.h b/src/micropeak/ao_log_micro.h
deleted file mode 100644 (file)
index 976852e..0000000
+++ /dev/null
@@ -1,39 +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; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_LOG_MICRO_H_
-#define _AO_LOG_MICRO_H_
-
-#define PA_GROUND_OFFSET       0
-#define PA_MIN_OFFSET          4
-#define N_SAMPLES_OFFSET       8
-#define STARTING_LOG_OFFSET    10
-#define MAX_LOG_OFFSET         512
-
-void
-ao_log_micro_save(void);
-
-void
-ao_log_micro_restore(void);
-
-void
-ao_log_micro_data(void);
-
-void
-ao_log_micro_dump(void);
-
-#endif /* _AO_LOG_MICRO_H_ */
diff --git a/src/micropeak/ao_microflight.c b/src/micropeak/ao_microflight.c
deleted file mode 100644 (file)
index 714bb90..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AO_FLIGHT_TEST
-#include <ao.h>
-#endif
-#include <ao_micropeak.h>
-#include <ao_log_micro.h>
-
-uint32_t       pa;
-uint32_t       pa_ground;
-uint32_t       pa_min;
-
-static void
-ao_microsample(void)
-{
-       ao_pa_get();
-       ao_microkalman_predict();
-       ao_microkalman_correct();
-}
-
-#define NUM_PA_HIST    16
-
-#define SKIP_PA_HIST(i,j)      (((i) + (j)) & (NUM_PA_HIST - 1))
-
-static uint32_t        pa_hist[NUM_PA_HIST];
-
-void
-ao_microflight(void)
-{
-       int16_t         sample_count;
-       uint16_t        time;
-       uint32_t        pa_interval_min, pa_interval_max;
-       int32_t         pa_diff;
-       uint8_t         h, i;
-       uint8_t         accel_lock = 0;
-       uint32_t        pa_sum = 0;
-
-       /* Wait for motion, averaging values to get ground pressure */
-
-       time = ao_time();
-       ao_pa_get();
-       ao_microkalman_init();
-       pa_ground = pa;
-       sample_count = 0;
-       h = 0;
-       for (;;) {
-               time += SAMPLE_SLEEP;
-               if (sample_count == 0)
-                       ao_led_on(AO_LED_REPORT);
-               ao_delay_until(time);
-               ao_microsample();
-               if (sample_count == 0)
-                       ao_led_off(AO_LED_REPORT);
-               pa_hist[h] = pa;
-               h = SKIP_PA_HIST(h,1);
-               pa_diff = pa_ground - ao_pa;
-
-               /* Check for a significant pressure change */
-               if (pa_diff > BOOST_DETECT)
-                       break;
-
-               if (sample_count < GROUND_AVG * 2) {
-                       if (sample_count < GROUND_AVG)
-                               pa_sum += pa;
-                       ++sample_count;
-               } else {
-                       pa_ground = pa_sum >> GROUND_AVG_SHIFT;
-                       pa_sum = 0;
-                       sample_count = 0;
-               }
-       }
-
-       /* Go back and find the first sample a decent interval above the ground */
-       pa_min = pa_ground - LAND_DETECT;
-       for (i = SKIP_PA_HIST(h,2); i != h; i = SKIP_PA_HIST(i,2)) {
-               if (pa_hist[i] < pa_min)
-                       break;
-       }
-
-       /* Log the remaining samples so we get a complete history since leaving the ground */
-       for (; i != h; i = SKIP_PA_HIST(i,2)) {
-               pa = pa_hist[i];
-               ao_log_micro_data();
-       }
-
-       /* Now sit around until the pressure is stable again and record the max */
-
-       sample_count = 0;
-       pa_min = ao_pa;
-       pa_interval_min = ao_pa;
-       pa_interval_max = ao_pa;
-       for (;;) {
-               time += SAMPLE_SLEEP;
-               ao_delay_until(time);
-               if ((sample_count & 3) == 0)
-                       ao_led_on(AO_LED_REPORT);
-               ao_microsample();
-               if ((sample_count & 3) == 0)
-                       ao_led_off(AO_LED_REPORT);
-               if (sample_count & 1)
-                       ao_log_micro_data();
-
-               /* If accelerating upwards, don't look for min pressure */
-               if (ao_pa_accel < ACCEL_LOCK_PA)
-                       accel_lock = ACCEL_LOCK_TIME;
-               else if (accel_lock)
-                       --accel_lock;
-               else if (ao_pa < pa_min)
-                       pa_min = ao_pa;
-
-               if (sample_count == (GROUND_AVG - 1)) {
-                       pa_diff = pa_interval_max - pa_interval_min;
-
-                       /* Check to see if the pressure is now stable */
-                       if (pa_diff < LAND_DETECT)
-                               break;
-                       sample_count = 0;
-                       pa_interval_min = ao_pa;
-                       pa_interval_max = ao_pa;
-               } else {
-                       if (ao_pa < pa_interval_min)
-                               pa_interval_min = ao_pa;
-                       if (ao_pa > pa_interval_max)
-                               pa_interval_max = ao_pa;
-                       ++sample_count;
-               }
-       }
-}
diff --git a/src/micropeak/ao_microkalman.c b/src/micropeak/ao_microkalman.c
deleted file mode 100644 (file)
index 0684ea2..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AO_FLIGHT_TEST
-#include <ao.h>
-#endif
-#include <ao_micropeak.h>
-
-#define FIX_BITS       16
-
-#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
-#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
-#define from_fix8(x)   ((x) >> 8)
-#define from_fix(x)    ((x) >> 16)
-#define fix8_to_fix16(x)       ((x) << 8)
-#define fix16_to_fix8(x)       ((x) >> 8)
-
-#include <ao_kalman.h>
-
-/* Basic time step (96ms) */
-#define AO_MK_STEP     to_fix16(0.096)
-/* step ** 2 / 2 */
-#define AO_MK_STEP_2_2 to_fix16(0.004608)
-
-uint32_t       ao_k_pa;                /* 24.8 fixed point */
-int32_t                ao_k_pa_speed;          /* 16.16 fixed point */
-int32_t                ao_k_pa_accel;          /* 16.16 fixed point */
-
-uint32_t       ao_pa;                  /* integer portion */
-int16_t                ao_pa_speed;            /* integer portion */
-int16_t                ao_pa_accel;            /* integer portion */
-
-void
-ao_microkalman_init(void)
-{
-       ao_pa = pa;
-       ao_k_pa = pa << 8;
-}      
-
-void
-ao_microkalman_predict(void)
-{
-       ao_k_pa       += fix16_to_fix8((int32_t) ao_pa_speed * AO_MK_STEP + (int32_t) ao_pa_accel * AO_MK_STEP_2_2);
-       ao_k_pa_speed += (int32_t) ao_pa_accel * AO_MK_STEP;
-}
-
-void
-ao_microkalman_correct(void)
-{
-       int16_t e;      /* Height error in Pa */
-
-       e = pa - from_fix8(ao_k_pa);
-
-       ao_k_pa       += fix16_to_fix8((int32_t) e * AO_MK_BARO_K0_10);
-       ao_k_pa_speed += (int32_t) e * AO_MK_BARO_K1_10;
-       ao_k_pa_accel += (int32_t) e * AO_MK_BARO_K2_10;
-       ao_pa = from_fix8(ao_k_pa);
-       ao_pa_speed = from_fix(ao_k_pa_speed);
-       ao_pa_accel = from_fix(ao_k_pa_accel);
-}
diff --git a/src/micropeak/ao_micropeak.c b/src/micropeak/ao_micropeak.c
deleted file mode 100644 (file)
index 10f0d19..0000000
+++ /dev/null
@@ -1,89 +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; 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_micropeak.h>
-#include <ao_ms5607.h>
-#include <ao_log_micro.h>
-#include <ao_async.h>
-
-static struct ao_ms5607_sample sample;
-static struct ao_ms5607_value  value;
-
-alt_t          ground_alt, max_alt;
-alt_t          ao_max_height;
-
-void
-ao_pa_get(void)
-{
-       ao_ms5607_sample(&sample);
-       ao_ms5607_convert(&sample, &value);
-       pa = value.pres;
-}
-
-static void
-ao_compute_height(void)
-{
-       ground_alt = ao_pa_to_altitude(pa_ground);
-       max_alt = ao_pa_to_altitude(pa_min);
-       ao_max_height = max_alt - ground_alt;
-}
-
-static void
-ao_pips(void)
-{
-       uint8_t i;
-       for (i = 0; i < 10; i++) {
-               ao_led_toggle(AO_LED_REPORT);
-               ao_delay(AO_MS_TO_TICKS(80));
-       }
-       ao_delay(AO_MS_TO_TICKS(200));
-}
-
-int
-main(void)
-{
-       ao_led_init(LEDS_AVAILABLE);
-       ao_timer_init();
-
-       /* Init external hardware */
-       ao_spi_init();
-       ao_ms5607_init();
-       ao_ms5607_setup();
-
-       /* Give the person a second to get their finger out of the way */
-       ao_delay(AO_MS_TO_TICKS(1000));
-
-       ao_log_micro_restore();
-       ao_compute_height();
-       ao_report_altitude();
-       ao_pips();
-       ao_log_micro_dump();
-       
-       ao_delay(BOOST_DELAY);
-
-       ao_microflight();
-
-       ao_log_micro_save();
-       ao_compute_height();
-       ao_report_altitude();
-       for (;;) {
-               cli();
-               set_sleep_mode(SLEEP_MODE_PWR_DOWN);
-               sleep_mode();
-       }
-}
diff --git a/src/micropeak/ao_micropeak.h b/src/micropeak/ao_micropeak.h
deleted file mode 100644 (file)
index 382b98d..0000000
+++ /dev/null
@@ -1,78 +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; 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_MICROPEAK_H_
-#define _AO_MICROPEAK_H_
-
-#define SAMPLE_SLEEP           AO_MS_TO_TICKS(96)
-
-/* 16 sample, or about two seconds worth */
-#define GROUND_AVG_SHIFT       4
-#define GROUND_AVG             (1 << GROUND_AVG_SHIFT)
-
-/* Pressure change (in Pa) to detect boost */
-#define BOOST_DETECT           120     /* 10m at sea level, 12m at 2000m */
-
-/* Wait after power on before doing anything to give the user time to assemble the rocket */
-#define BOOST_DELAY            AO_SEC_TO_TICKS(30)
-
-/* Pressure change (in Pa) to detect landing */
-#define LAND_DETECT            24      /* 2m at sea level, 2.4m at 2000m */
-
-/* Current sensor pressure value */
-extern uint32_t        pa;
-
-/* Average pressure value on ground */
-extern uint32_t        pa_ground;
-
-/* Minimum recorded filtered pressure value */
-extern uint32_t        pa_min;
-
-/* Pressure values converted to altitudes */
-extern alt_t   ground_alt, max_alt;
-
-/* max_alt - ground_alt */
-extern alt_t   ao_max_height;
-
-void
-ao_pa_get(void);
-
-void
-ao_microflight(void);
-
-#define ACCEL_LOCK_PA          -20
-#define ACCEL_LOCK_TIME                10
-
-extern uint32_t        ao_k_pa;                /* 24.8 fixed point */
-extern int32_t ao_k_pa_speed;          /* 16.16 fixed point */
-extern int32_t ao_k_pa_accel;          /* 16.16 fixed point */
-
-extern uint32_t        ao_pa;                  /* integer portion */
-extern int16_t ao_pa_speed;            /* integer portion */
-extern int16_t ao_pa_accel;            /* integer portion */
-
-void
-ao_microkalman_init(void);
-
-void
-ao_microkalman_predict(void);
-
-void
-ao_microkalman_correct(void);
-       
-#endif
-
diff --git a/src/micropeak/ao_report_tiny.c b/src/micropeak/ao_report_tiny.c
deleted file mode 100644 (file)
index 0e8e287..0000000
+++ /dev/null
@@ -1,57 +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; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <ao.h>
-
-#define mid(time)      ao_led_for(AO_LED_REPORT, time)
-#define pause(time)    ao_delay(time)
-
-static void
-ao_report_digit(uint8_t digit) __reentrant
-{
-       if (!digit) {
-               mid(AO_MS_TO_TICKS(1000));
-               pause(AO_MS_TO_TICKS(300));
-       } else {
-               while (digit--) {
-                       mid(AO_MS_TO_TICKS(300));
-                       pause(AO_MS_TO_TICKS(300));
-               }
-       }
-       pause(AO_MS_TO_TICKS(1000));
-}
-
-void
-ao_report_altitude(void)
-{
-       __pdata alt_t   agl = ao_max_height;
-       static __xdata uint8_t  digits[11];
-       __pdata uint8_t ndigits, i;
-
-       if (agl < 0)
-               agl = 0;
-       ndigits = 0;
-       do {
-               digits[ndigits++] = agl % 10;
-               agl /= 10;
-       } while (agl);
-
-       i = ndigits;
-       do
-               ao_report_digit(digits[--i]);
-       while (i != 0);
-}
diff --git a/src/nanopeak-v0.1/.gitignore b/src/nanopeak-v0.1/.gitignore
new file mode 100644 (file)
index 0000000..27cd0a7
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+nanopeak-*
diff --git a/src/nanopeak-v0.1/Makefile b/src/nanopeak-v0.1/Makefile
new file mode 100644 (file)
index 0000000..04eea90
--- /dev/null
@@ -0,0 +1,108 @@
+#
+# Tiny AltOS build
+#
+#
+vpath % ../attiny:../drivers:../core:../product:..
+vpath ao-make-product.5c ../util
+vpath make-altitude-pa ../util
+
+include ../avr/Makefile.defs
+
+MCU=attiny85
+DUDECPUTYPE=t85
+#PROGRAMMER=stk500v2 -P usb
+LOADSLOW=-i 32 -B 32
+LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
+
+#LDFLAGS=-L$(LDSCRIPTS) -Tavr25.x
+
+ALTOS_SRC = \
+       ao_micropeak.c \
+       ao_spi_attiny.c \
+       ao_led.c \
+       ao_clock.c \
+       ao_ms5607.c \
+       ao_exti.c \
+       ao_convert_pa.c \
+       ao_report_micro.c \
+       ao_notask.c \
+       ao_eeprom_tiny.c \
+       ao_panic.c \
+       ao_log_micro.c \
+       ao_async.c \
+       ao_microflight.c \
+       ao_microkalman.c
+
+INC=\
+       ao.h \
+       ao_pins.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_exti.h \
+       ao_ms5607.h \
+       ao_log_micro.h \
+       ao_micropeak.h \
+       altitude-pa.h
+
+IDPRODUCT=0
+PRODUCT=NanoPeak-v0.1
+PRODUCT_DEF=-DNANOPEAK
+CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../core -I.. -I../drivers -I../product
+CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY
+
+NICKLE=nickle
+
+PROG=nanopeak-v0.1
+
+SRC=$(ALTOS_SRC)
+OBJ=$(SRC:.c=.o)
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf "  $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: $(PROG) $(PROG).hex
+
+CHECK=sh ../util/check-avr-mem
+
+$(PROG): Makefile $(OBJ)
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ)
+       $(call quiet,CHECK) $(PROG) || ($(RM) -f $(PROG); exit 1)
+
+$(PROG).hex: $(PROG)
+       avr-size $(PROG)
+       $(OBJCOPY) -R .eeprom -O ihex $(PROG) $@
+
+
+load: $(PROG).hex
+       $(LOADCMD) $(LOADARG)$(PROG).hex
+
+load-slow: $(PROG).hex
+       $(LOADCMD) $(LOADSLOW) $(LOADARG)$(PROG).hex
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+ao_product.o: ao_product.c ao_product.h
+
+%.o : %.c $(INC)
+       $(call quiet,CC) -c $(CFLAGS) $<
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROG) $(PROG).hex
+       rm -f ao_product.h
+
+../altitude-pa.h: make-altitude-pa
+       nickle $< > $@
+
+install:
+
+uninstall:
+
+$(OBJ): ao_product.h $(INC)
diff --git a/src/nanopeak-v0.1/ao_pins.h b/src/nanopeak-v0.1/ao_pins.h
new file mode 100644 (file)
index 0000000..bd4a06d
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+#include <avr/pgmspace.h>
+
+#define AO_LED_ORANGE          (1<<3)
+#define AO_LED_SERIAL          3
+#define AO_LED_PANIC           AO_LED_ORANGE
+#define AO_LED_REPORT          AO_LED_ORANGE
+#define LEDS_AVAILABLE         (AO_LED_ORANGE)
+#define USE_SERIAL_1_STDIN     0
+#define HAS_USB                        0
+#define PACKET_HAS_SLAVE       0
+#define HAS_SERIAL_1           0
+#define HAS_TASK               0
+#define HAS_MS5607             1
+#define HAS_MS5611             0
+#define HAS_EEPROM             0
+#define HAS_BEEP               0
+#define AVR_CLOCK              250000UL
+
+/* SPI */
+#define SPI_PORT               PORTB
+#define SPI_PIN                        PINB
+#define SPI_DIR                        DDRB
+#define AO_MS5607_CS_PORT      PORTB
+#define AO_MS5607_CS_PIN       4
+
+/* MS5607 */
+#define AO_MS5607_SPI_INDEX    0
+#define AO_MS5607_MISO_PORT    PORTB
+#define AO_MS5607_MISO_PIN     0
+#define AO_MS5607_BARO_OVERSAMPLE      4096
+#define AO_MS5607_TEMP_OVERSAMPLE      1024
+
+/* I2C */
+#define I2C_PORT               PORTB
+#define I2C_PIN                        PINB
+#define I2C_DIR                        DDRB
+#define I2C_PIN_SCL            PINB2
+#define I2C_PIN_SDA            PINB0
+
+#define AO_CONST_ATTRIB                PROGMEM
+typedef int32_t alt_t;
+#define FETCH_ALT(o)           ((alt_t) pgm_read_dword(&altitude_table[o]))
+
+#define AO_ALT_VALUE(x)                ((x) * (alt_t) 10)
+
+#endif /* _AO_PINS_H_ */
index 3101b77706593c3f09350e71726ad05ff6bcb1b2..da9bcba04597487776c62fe6efd5ee444ba431a7 100644 (file)
@@ -80,9 +80,9 @@ endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-all: ../$(PROG)
+all: $(PROG)
 
-../$(PROG): $(REL) Makefile
+$(PROG): $(REL) Makefile
        $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
 
index 1e55989c36e07eeb2acb8c9bf7d2717bfeceb38f..a5e2eb7fb12912afbcb7db443e2fccd57f78b8f4 100644 (file)
@@ -82,9 +82,9 @@ endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-all: ../$(PROG)
+all: $(PROG)
 
-../$(PROG): $(REL) Makefile
+$(PROG): $(REL) Makefile
        $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)  || rm $@
 
index 5e3eed7f96cdfb33eaae6f0d2075cb724bb5766d..c740a4831149325ca8bf67965847696de6150598 100644 (file)
@@ -94,10 +94,10 @@ endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-all: ../$(PROG)
+all: $(PROG)
 
-../$(PROG): $(REL) Makefile
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
 
 ao_product.h: ao-make-product.5c ../Version
index ef8906badf6d90417d8123b4afaae115bef08327..0884079eb701543cc090c3e0ea7358b0c4ac1123 100644 (file)
@@ -83,10 +83,10 @@ endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-all: ../$(PROG)
+all: $(PROG)
 
-../$(PROG): $(REL) Makefile
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
 
 ao_product.h: ao-make-product.5c ../Version
index 67410ae0bd5332b8f3e15840ca087b71c850fae6..c31989eedf2fa213837923961da8cb7604e2d777 100644 (file)
@@ -82,9 +82,9 @@ endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-all: ../$(PROG)
+all: $(PROG)
 
-../$(PROG): $(REL) Makefile
+$(PROG): $(REL) Makefile
        $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
 
index b774df6d3668a68a44b8a55915be530a7eadaea3..dd67d820ea0f99f7cae75873448f1c9bdf4d247b 100644 (file)
@@ -35,6 +35,7 @@
 #define HAS_VERSION            0
 
 #define AO_BOOT_CHAIN          1
-#define AO_BOOT_PIN            1
+
+#define IS_FLASH_LOADER                1
 
 #endif /* _AO_FLASH_PINS_H_ */
index fdc4d0aa5ad3b9bbd059adecc5c1476558892337..4cfbf75fde3d15c38b7b8ab0809bb9a85abfc3d8 100644 (file)
@@ -73,7 +73,7 @@ static void
 ao_block_erase(void)
 {
        uint32_t        addr = ao_get_hex32();
-       uint32_t        *p = (uint32_t *) addr;
+       void            *p = (void *) addr;
 
        ao_flash_erase_page(p);
 }
@@ -82,11 +82,8 @@ static void
 ao_block_write(void)
 {
        uint32_t        addr = ao_get_hex32();
-       uint32_t        *p = (uint32_t *) addr;
-       union {
-               uint8_t         data8[256];
-               uint32_t        data32[64];
-       } u;
+       void            *p = (void *) addr;
+       uint8_t         data[256];
        uint16_t        i;
 
        if (addr < (uint32_t) AO_BOOT_APPLICATION_BASE) {
@@ -94,8 +91,8 @@ ao_block_write(void)
                return;
        }
        for (i = 0; i < 256; i++)
-               u.data8[i] = ao_usb_getchar();
-       ao_flash_page(p, u.data32);
+               data[i] = ao_usb_getchar();
+       ao_flash_page(p, (void *) data);
 }
 
 static void
diff --git a/src/product/ao_micropeak.c b/src/product/ao_micropeak.c
new file mode 100644 (file)
index 0000000..10f0d19
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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>
+#include <ao_micropeak.h>
+#include <ao_ms5607.h>
+#include <ao_log_micro.h>
+#include <ao_async.h>
+
+static struct ao_ms5607_sample sample;
+static struct ao_ms5607_value  value;
+
+alt_t          ground_alt, max_alt;
+alt_t          ao_max_height;
+
+void
+ao_pa_get(void)
+{
+       ao_ms5607_sample(&sample);
+       ao_ms5607_convert(&sample, &value);
+       pa = value.pres;
+}
+
+static void
+ao_compute_height(void)
+{
+       ground_alt = ao_pa_to_altitude(pa_ground);
+       max_alt = ao_pa_to_altitude(pa_min);
+       ao_max_height = max_alt - ground_alt;
+}
+
+static void
+ao_pips(void)
+{
+       uint8_t i;
+       for (i = 0; i < 10; i++) {
+               ao_led_toggle(AO_LED_REPORT);
+               ao_delay(AO_MS_TO_TICKS(80));
+       }
+       ao_delay(AO_MS_TO_TICKS(200));
+}
+
+int
+main(void)
+{
+       ao_led_init(LEDS_AVAILABLE);
+       ao_timer_init();
+
+       /* Init external hardware */
+       ao_spi_init();
+       ao_ms5607_init();
+       ao_ms5607_setup();
+
+       /* Give the person a second to get their finger out of the way */
+       ao_delay(AO_MS_TO_TICKS(1000));
+
+       ao_log_micro_restore();
+       ao_compute_height();
+       ao_report_altitude();
+       ao_pips();
+       ao_log_micro_dump();
+       
+       ao_delay(BOOST_DELAY);
+
+       ao_microflight();
+
+       ao_log_micro_save();
+       ao_compute_height();
+       ao_report_altitude();
+       for (;;) {
+               cli();
+               set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+               sleep_mode();
+       }
+}
diff --git a/src/product/ao_micropeak.h b/src/product/ao_micropeak.h
new file mode 100644 (file)
index 0000000..0cefca6
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_MICROPEAK_H_
+#define _AO_MICROPEAK_H_
+
+#define SAMPLE_SLEEP           AO_MS_TO_TICKS(96)
+
+/* 64 sample, or about six seconds worth */
+#define GROUND_AVG_SHIFT       6
+#define GROUND_AVG             (1 << GROUND_AVG_SHIFT)
+
+/* Pressure change (in Pa) to detect boost */
+#define BOOST_DETECT           360     /* 30m at sea level, 36m at 2000m */
+
+/* Wait after power on before doing anything to give the user time to assemble the rocket */
+#define BOOST_DELAY            AO_SEC_TO_TICKS(60)
+
+/* Pressure change (in Pa) to detect landing */
+#define LAND_DETECT            24      /* 2m at sea level, 2.4m at 2000m */
+
+/* Current sensor pressure value */
+extern uint32_t        pa;
+
+/* Average pressure value on ground */
+extern uint32_t        pa_ground;
+
+/* Minimum recorded filtered pressure value */
+extern uint32_t        pa_min;
+
+/* Pressure values converted to altitudes */
+extern alt_t   ground_alt, max_alt;
+
+/* max_alt - ground_alt */
+extern alt_t   ao_max_height;
+
+void
+ao_pa_get(void);
+
+void
+ao_microflight(void);
+
+#define ACCEL_LOCK_PA          -20
+#define ACCEL_LOCK_TIME                10
+
+extern uint32_t        ao_k_pa;                /* 24.8 fixed point */
+extern int32_t ao_k_pa_speed;          /* 16.16 fixed point */
+extern int32_t ao_k_pa_accel;          /* 16.16 fixed point */
+
+extern uint32_t        ao_pa;                  /* integer portion */
+extern int16_t ao_pa_speed;            /* integer portion */
+extern int16_t ao_pa_accel;            /* integer portion */
+
+void
+ao_microkalman_init(void);
+
+void
+ao_microkalman_predict(void);
+
+void
+ao_microkalman_correct(void);
+       
+#endif
+
index 1866eb0c1183af7ac4bff51387eaca4c2ec6c31a..8fd97033d6533329bd25af5d0e5ee3bb453f36ff 100644 (file)
@@ -629,7 +629,7 @@ ao_terragps(void)
 
        for (;;) {
                while (ao_gps_tick == gps_tick)
-                       ao_sleep(&ao_gps_data);
+                       ao_sleep(&ao_gps_new);
                gps_tick = ao_gps_tick;
                ao_gps_progress = (ao_gps_progress + 1) & 3;
        }
index a207d34f50562b6470e9e2f1d7a8bec660b8dbee..e644bc49d64785798682282b804fa1dc984fa7ab 100644 (file)
@@ -73,10 +73,10 @@ endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-all: ../$(PROG)
+all: $(PROG)
 
-../$(PROG): $(REL) Makefile
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)  || rm $@
 
 ao_product.h: ao-make-product.5c ../Version
index 1bc5aaadd789060a44f0be9b11dd22289944f6ba..797df2d697b4cc3ffd05cde93717855270386ad7 100644 (file)
@@ -4,15 +4,15 @@ vpath ao-make-product.5c ../util
 ifndef VERSION
 include ../Version
 endif
+TOPDIR=..
+include $(TOPDIR)/Makedefs
 
 CC=arm-none-eabi-gcc
 OBJCOPY=arm-none-eabi-objcopy
 
-PDCLIB=/opt/cortex
-C_LIB=$(PDCLIB)/lib/pdclib-cortex-m3.a
-C_INC=-I$(PDCLIB)/include
+C_LIB=$(PDCLIB_LIBS_M3)
 
-DEF_CFLAGS=-g -std=gnu99 -Os -mlittle-endian -mthumb -ffreestanding -nostdlib -I. -I../../src/stm $(C_INC)
+DEF_CFLAGS=-g -std=gnu99 -Os -mlittle-endian -mthumb -ffreestanding -nostdlib -I. -I../stm $(PDCLIB_INCLUDES)
 
 # to run from SRAM
 LD_FLAGS_RAM=-L../stm -Wl,-Taltos-ram.ld
@@ -28,10 +28,10 @@ all: bringup-ram.elf bringup.elf
 %.bin: %.elf
        $(OBJCOPY) -O binary $^ $@
 
-bringup.elf: $(OBJ) $(C_LIB) bringup.ld
+bringup.elf: $(OBJ) bringup.ld
        $(CC) $(CFLAGS) $(LD_FLAGS) -o $@ $(OBJ) $(C_LIB) -lgcc
 
-bringup-ram.elf: $(OBJ) $(C_LIB) altos-ram.ld
+bringup-ram.elf: $(OBJ) altos-ram.ld
        $(CC) $(CFLAGS) $(LD_FLAGS_RAM) -o $@ $(OBJ) $(C_LIB) -lgcc
 
 clean:
index d1f825db7cc0baf886eb59ff144e321b98ae2647..98fcd9e587f6721bda89fd85900db01547c72037 100644 (file)
@@ -36,10 +36,7 @@ ALTOS_SRC = \
        ao_data.c \
        ao_i2c_stm.c \
        ao_usb_stm.c \
-       ao_exti_stm.c \
-       ao_event.c \
-       ao_quadrature.c \
-       ao_button.c
+       ao_exti_stm.c
 
 PRODUCT=StmDemo-v0.0
 PRODUCT_DEF=-DSTM_DEMO
@@ -59,7 +56,7 @@ all: $(ELF) $(IHX)
 LDFLAGS=-L../stm -Wl,-Taltos.ld
 
 $(ELF): Makefile $(OBJ)
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJ) $(SAT_CLIB) -lgcc
+       $(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) > $@
@@ -69,7 +66,7 @@ $(OBJ): $(INC)
 distclean:     clean
 
 clean:
-       rm -f *.o $(PROG)
+       rm -f *.o *.elf *.ihx
        rm -f ao_product.h
 
 install:
index 5677cdf46d3b5ed2261b94f5a10ce21aab21fdb0..58cf651b472471bef053a180e525fd321740bef6 100644 (file)
@@ -153,6 +153,7 @@ ao_temp (void)
        printf ("temp: %d\n", temp);
 }
 
+#if 0
 static void
 ao_event(void)
 {
@@ -168,6 +169,7 @@ ao_event(void)
        }
 
 }
+#endif
 
 __code struct ao_cmds ao_demo_cmds[] = {
        { ao_dma_test,  "D\0DMA test" },
@@ -175,7 +177,7 @@ __code struct ao_cmds ao_demo_cmds[] = {
        { ao_spi_read, "R\0SPI read" },
        { ao_i2c_write, "i\0I2C write" },
        { ao_temp, "t\0Show temp" },
-       { ao_event, "e\0Monitor event queue" },
+/*     { ao_event, "e\0Monitor event queue" }, */
        { 0, NULL }
 };
 
index 1ea35581c41d0da7af115da74aed1154189c43e6..5c0699e1bbed20d510a76b69325f82e098dd6633 100644 (file)
@@ -41,7 +41,7 @@ all: $(PROG)
 LDFLAGS=-L../stm -Wl,-Taltos-loader.ld
 
 $(PROG): Makefile $(OBJ)
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+       $(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) > $@
index 016bb7e7d4a6891072e056c222a4f5e81e5a14b3..3890eff1a19c6d0046b2030dcfddb4ec4ef807f0 100644 (file)
@@ -6,16 +6,15 @@ vpath ao-make-product.5c $(TOPDIR)/util
 .elf.ihx:
        objcopy -O ihex $*.elf $@
 
-CC=arm-none-eabi-gcc
-SAT=/opt/cortex
-SAT_CLIB=$(SAT)/lib/pdclib-cortex-m3.a
-SAT_CFLAGS=-I$(SAT)/include
-
 ifndef VERSION
 include $(TOPDIR)/Version
 endif
+include $(TOPDIR)/Makedefs
+
+CC=$(ARM_CC)
+LIBS=$(PDCLIB_LIBS_M3) -lgcc
 
-AO_CFLAGS=-I. -I$(TOPDIR)/stm -I$(TOPDIR)/core -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR)
+AO_CFLAGS=-I. -I$(TOPDIR)/stm -I$(TOPDIR)/core -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) $(PDCLIB_INCLUDES)
 STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS) $(SAT_CFLAGS)
 
 LDFLAGS=-L$(TOPDIR)/stm -Wl,-Taltos-loader.ld
@@ -62,7 +61,7 @@ SRC = \
 
 OBJ=$(SRC:.c=.o)
 
-PRODUCT=AltosFlash-$(VERSION)
+PRODUCT=AltosFlash
 PRODUCT_DEF=-DALTOS_FLASH
 IDPRODUCT=0x000a
 
@@ -72,7 +71,7 @@ PROGNAME=altos-flash
 PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
 
 $(PROG): Makefile $(OBJ) altos-loader.ld
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
 
 ao_product.h: ao-make-product.5c $(TOPDIR)/Version
        $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
@@ -84,7 +83,7 @@ all: $(PROG)
 distclean:     clean
 
 clean:
-       rm -f *.o $(PROG)
+       rm -f *.o $(HARDWARE)-$(PROGNAME)-*.elf
        rm -f ao_product.h
 
 install:
index c8bb7d704b4573b0c306e6e03d8aaa2f8bc858b6..9adcfeb3c2bb76fc3969986a6ce3bf33171c8640 100644 (file)
@@ -1,4 +1,4 @@
-vpath % ../stm:../product:../drivers:../core:../util:../kalman:../aes:..
+vpath % ../stm:../product:../drivers:../core:../util:../kalman:../aes:../math:..
 vpath make-altitude ../util
 vpath make-kalman ../util
 vpath kalman.5c ../kalman
@@ -10,23 +10,27 @@ vpath ao-make-product.5c ../util
 .SUFFIXES: .elf .ihx
 
 .elf.ihx:
-       objcopy -O ihex $*.elf $@
+       $(ELFTOHEX) --output=$@ $*.elf
 
-CC=arm-none-eabi-gcc
-SAT=/opt/cortex
-SAT_CLIB=$(SAT)/lib/pdclib-cortex-m3.a
-SAT_CFLAGS=-I$(SAT)/include
+ifndef TOPDIR
+TOPDIR=..
+endif
 
 ifndef VERSION
-include ../Version
+include $(TOPDIR)/Version
 endif
+include $(TOPDIR)/Makedefs
+
+CC=$(ARM_CC)
+LIBS=$(PDCLIB_LIBS_M3) -lgcc
 
-AO_CFLAGS=-I. -I../stm -I../core -I../drivers -I..
-STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS) $(SAT_CFLAGS)
+AO_CFLAGS=-I. -I../stm -I../core -I../drivers -I../math -I.. $(PDCLIB_INCLUDES)
+STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS)
 
 LDFLAGS=-L../stm -Wl,-Taltos.ld
 
 NICKLE=nickle
+ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex
 
 V=0
 # The user has explicitly enabled quiet compilation.
index 2be964f2a7bad6bc5598ac9a249085273ace66c5..0753f5f7288d45ae9805a7a625d23688b8d46a02 100644 (file)
@@ -37,11 +37,11 @@ SECTIONS {
 
                ao_romconfig.o(.romconfig*)
                ao_product.o(.romconfig*)
-               *(.text       /* Executable code */
+               *(.text*)       /* Executable code */
                *(.ARM.exidx* .gnu.linkonce.armexidx.*)
                *(.rodata*)     /* Constants */
-               __text_end__ = .;
        } > rom
+       __text_end__ = .;
 
        /* Boot data which must live at the start of ram so that
         * the application and bootloader share the same addresses.
@@ -66,7 +66,7 @@ SECTIONS {
        .textram BLOCK(8): {
                __data_start__ = .;
                __text_ram_start__ = .;
-               *(.text.ram)
+               *(.ramtext)
                __text_ram_end = .;
        } >ram AT>rom
 
index 48fc4262f7cb822f298168e7f55d5a9478c757b9..53f19b406d20a884f6c33b6219b2dc55f10e9b76 100644 (file)
@@ -113,11 +113,15 @@ ao_adc_dump(void) __reentrant
        uint8_t i;
 
        ao_data_get(&packet);
+#ifdef AO_ADC_DUMP
+       AO_ADC_DUMP(&packet);
+#else
        printf("tick: %5u",  packet.tick);
        d = (int16_t *) (&packet.adc);
        for (i = 0; i < AO_NUM_ADC; i++)
                printf (" %2d: %5d", i, d[i]);
        printf("\n");
+#endif
 }
 
 __code struct ao_cmds ao_adc_cmds[] = {
index adc288c31bd1efc5fa5f9380f05dcb299fabb575..42fe727a84139d0ff47351681c868f81240ab435 100644 (file)
@@ -34,6 +34,8 @@
 #define AO_TICK_SIGNED int16_t
 #endif
 
+#define AO_PORT_TYPE   uint16_t
+
 /* Various definitions to make GCC look more like SDCC */
 
 #define ao_arch_naked_declare  __attribute__((naked))
index 1e78cabc5fbadb9a9519aaf9a63f1321a7a6d7a0..b461cd3fbf81dd9f32dac82894ea96d7c5bdaad7 100644 (file)
@@ -87,13 +87,16 @@ extern uint16_t     ao_spi_speed[STM_NUM_SPI];
 void
 ao_spi_init(void);
 
+#define ao_spi_set_cs(reg,mask) ((reg)->bsrr = ((uint32_t) (mask)) << 16)
+#define ao_spi_clr_cs(reg,mask) ((reg)->bsrr = (mask))
+
 #define ao_spi_get_mask(reg,mask,bus, speed) do {              \
                ao_spi_get(bus, speed);                         \
-               (reg)->bsrr = ((uint32_t) mask) << 16;  \
+               ao_spi_set_cs(reg,mask);                        \
        } while (0)
 
 #define ao_spi_put_mask(reg,mask,bus) do {     \
-               (reg)->bsrr = mask;             \
+               ao_spi_clr_cs(reg,mask);        \
                ao_spi_put(bus);                \
        } while (0)
 
@@ -326,7 +329,7 @@ static inline void ao_arch_restore_stack(void) {
 
        /* Restore APSR */
        asm("pop {r0}");
-       asm("msr apsr,r0");
+       asm("msr apsr_nczvq,r0");
 
        /* Restore general registers */
        asm("pop {r0-r12,lr}\n");
@@ -335,6 +338,11 @@ static inline void ao_arch_restore_stack(void) {
        asm("bx lr");
 }
 
+#ifndef HAS_SAMPLE_PROFILE
+#define HAS_SAMPLE_PROFILE 0
+#endif
+
+#if !HAS_SAMPLE_PROFILE
 #define HAS_ARCH_START_SCHEDULER       1
 
 static inline void ao_arch_start_scheduler(void) {
@@ -346,16 +354,19 @@ static inline void ao_arch_start_scheduler(void) {
        asm("mrs %0,control" : "=&r" (control));
        control |= (1 << 1);
        asm("msr control,%0" : : "r" (control));
+       asm("isb");
 }
+#endif
 
 #define ao_arch_isr_stack()
 
 #endif
 
-#define ao_arch_wait_interrupt() do {                  \
-               asm(".global ao_idle_loc\n\twfi\nao_idle_loc:");        \
-               ao_arch_release_interrupts();                           \
-               ao_arch_block_interrupts();                             \
+#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)
 
 #define ao_arch_critical(b) do {                               \
index 4761fbfc87d5fbf8f05bc0a48364a0a47e8e15eb..a95d869bdf7caacfd6eca90e66899196cacdf8bb 100644 (file)
 
 #include "ao.h"
 
+#ifndef BEEPER_CHANNEL
+#define BEEPER_CHANNEL 1
+#endif
+
 void
 ao_beep(uint8_t beep)
 {
@@ -56,6 +60,7 @@ ao_beep(uint8_t beep)
                 *  is enabled and active high.
                 */
 
+#if BEEPER_CHANNEL == 1
                stm_tim3.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) |
                                  (STM_TIM234_CCMR1_OC2M_FROZEN << STM_TIM234_CCMR1_OC2M) |
                                  (0 << STM_TIM234_CCMR1_OC2PE) |
@@ -68,7 +73,6 @@ ao_beep(uint8_t beep)
                                  (0 << STM_TIM234_CCMR1_OC1FE) |
                                  (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S));
 
-
                stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC4NP) |
                                 (0 << STM_TIM234_CCER_CC4P) |
                                 (0 << STM_TIM234_CCER_CC4E) |
@@ -81,6 +85,33 @@ ao_beep(uint8_t beep)
                                 (0 << STM_TIM234_CCER_CC1NP) |
                                 (0 << STM_TIM234_CCER_CC1P) |
                                 (1 << STM_TIM234_CCER_CC1E));
+#endif
+#if BEEPER_CHANNEL == 4
+               stm_tim3.ccmr2 = ((0 << STM_TIM234_CCMR2_OC4CE) |
+                                 (STM_TIM234_CCMR2_OC4M_TOGGLE << STM_TIM234_CCMR2_OC4M) |
+                                 (0 << STM_TIM234_CCMR2_OC4PE) |
+                                 (0 << STM_TIM234_CCMR2_OC4FE) |
+                                 (STM_TIM234_CCMR2_CC4S_OUTPUT << STM_TIM234_CCMR2_CC4S) |
+
+                                 (0 << STM_TIM234_CCMR2_OC3CE) |
+                                 (STM_TIM234_CCMR2_OC3M_FROZEN << STM_TIM234_CCMR2_OC3M) |
+                                 (0 << STM_TIM234_CCMR2_OC3PE) |
+                                 (0 << STM_TIM234_CCMR2_OC3FE) |
+                                 (STM_TIM234_CCMR2_CC3S_OUTPUT << STM_TIM234_CCMR2_CC3S));
+
+               stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC4NP) |
+                                (0 << STM_TIM234_CCER_CC4P) |
+                                (1 << STM_TIM234_CCER_CC4E) |
+                                (0 << STM_TIM234_CCER_CC3NP) |
+                                (0 << STM_TIM234_CCER_CC3P) |
+                                (0 << STM_TIM234_CCER_CC3E) |
+                                (0 << STM_TIM234_CCER_CC2NP) |
+                                (0 << STM_TIM234_CCER_CC2P) |
+                                (0 << STM_TIM234_CCER_CC2E) |
+                                (0 << STM_TIM234_CCER_CC1NP) |
+                                (0 << STM_TIM234_CCER_CC1P) |
+                                (0 << STM_TIM234_CCER_CC1E));
+#endif
 
 
                /* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */
@@ -110,13 +141,22 @@ ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant
 void
 ao_beep_init(void)
 {
-       /* Our beeper is on PC6, which is hooked to TIM3_CH1,
-        * which is on PC6
-        */
+#if BEEPER_CHANNEL == 1
 
+       /* Our beeper is on PC6, which is hooked to TIM3_CH1.
+        */
        stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN);
 
        stm_afr_set(&stm_gpioc, 6, STM_AFR_AF2);
+#endif
+#if BEEPER_CHANNEL == 4
+
+       /* Our beeper is on PB1, which is hooked to TIM3_CH4.
+        */
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+
+       stm_afr_set(&stm_gpiob, 1, STM_AFR_AF2);
+#endif
 
        /* Leave the timer off until requested */
        
diff --git a/src/stm/ao_data.c b/src/stm/ao_data.c
deleted file mode 100644 (file)
index 38d2f7f..0000000
+++ /dev/null
@@ -1,34 +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; 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>
-
-volatile __xdata struct ao_data        ao_data_ring[AO_DATA_RING];
-volatile __data uint8_t                ao_data_head;
-volatile __data uint8_t                ao_data_present;
-
-void
-ao_data_get(__xdata struct ao_data *packet)
-{
-#if HAS_FLIGHT
-       uint8_t i = ao_data_ring_prev(ao_sample_data);
-#else
-       uint8_t i = ao_data_ring_prev(ao_data_head);
-#endif
-       memcpy(packet, (void *) &ao_data_ring[i], sizeof (struct ao_data));
-}
index 58783f1a0771262f6c573abc81162d8f09c0401f..4207a8607e3d593df3482505ad5ca42eb411d385 100644 (file)
  */
 
 #include <ao.h>
-#include <ao_storage.h>
+#include <ao_eeprom.h>
 
 /* Total bytes of available storage */
-ao_pos_t       ao_storage_total = 4096;
-
-/* Block size - device is erased in these units. */
-ao_pos_t       ao_storage_block = 1024;
-
-/* Byte offset of config block. Will be ao_storage_block bytes long */
-ao_pos_t       ao_storage_config = 0;
-
-/* Storage unit size - device reads and writes must be within blocks of this size. */
-uint16_t       ao_storage_unit = 1024;
+const ao_pos_t ao_eeprom_total = 4096;
 
 /* Location of eeprom in address space */
 #define stm_eeprom     ((uint8_t *) 0x08080000)
@@ -42,16 +33,6 @@ uint16_t     ao_storage_unit = 1024;
  * the same contents, or append to an existing page easily enough
  */
 
-/*
- * Erase the specified sector
- */
-uint8_t
-ao_storage_erase(ao_pos_t pos) __reentrant
-{
-       /* Not necessary */
-       return 1;
-}
-
 static void
 ao_intflash_unlock(void)
 {
@@ -131,16 +112,16 @@ ao_intflash_read(uint16_t pos)
 }
 
 /*
- * Write to flash
+ * Write to eeprom
  */
 
 uint8_t
-ao_storage_device_write(ao_pos_t pos32, __xdata void *v, uint16_t len) __reentrant
+ao_eeprom_write(ao_pos_t pos32, __xdata void *v, uint16_t len)
 {
        uint16_t pos = pos32;
        __xdata uint8_t *d = v;
 
-       if (pos >= ao_storage_total || pos + len > ao_storage_total)
+       if (pos >= ao_eeprom_total || pos + len > ao_eeprom_total)
                return 0;
 
        ao_intflash_unlock();
@@ -166,38 +147,26 @@ ao_storage_device_write(ao_pos_t pos32, __xdata void *v, uint16_t len) __reentra
 }
 
 /*
- * Read from flash
+ * Read from eeprom
  */
 uint8_t
-ao_storage_device_read(ao_pos_t pos, __xdata void *v, uint16_t len) __reentrant
+ao_eeprom_read(ao_pos_t pos, __xdata void *v, uint16_t len)
 {
        uint8_t *d = v;
        
-       if (pos >= ao_storage_total || pos + len > ao_storage_total)
+       if (pos >= ao_eeprom_total || pos + len > ao_eeprom_total)
                return 0;
        while (len--)
                *d++ = ao_intflash_read(pos++);
        return 1;
 }
 
-void
-ao_storage_flush(void) __reentrant
-{
-}
-
-void
-ao_storage_setup(void)
-{
-}
-
-void
-ao_storage_device_info(void) __reentrant
-{
-       uint8_t i;
-       printf ("Using internal flash\n");
-}
+/*
+ * Initialize eeprom
+ */
 
 void
-ao_storage_device_init(void)
+ao_eeprom_init(void)
 {
+       /* Nothing to do here */
 }
index 35b56b571582fd392201bf0172767ff9f53119ad..ebea224d03d48934507e3673d5d049ba9bc2324e 100644 (file)
@@ -25,6 +25,7 @@
 #define AO_EXTI_PRIORITY_LOW   16
 #define AO_EXTI_PRIORITY_MED   0
 #define AO_EXTI_PRIORITY_HIGH  32
+#define AO_EXTI_PIN_NOCONFIGURE        64
 
 void
 ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)());
index 1361d0d4a8cb6caf0a41b3522c9ae49c53c71cf5..c1dcdf85303a84f0a7541023f7bca684fdaba037 100644 (file)
@@ -70,21 +70,23 @@ ao_exti_setup (struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback
        /* configure gpio to interrupt routing */
        stm_exticr_set(gpio, pin);
 
-       /* configure pin as input, setting selected pull-up/down mode */
-       stm_moder_set(gpio, pin, STM_MODER_INPUT);
-       switch (mode & (AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_PULL_DOWN)) {
-       case 0:
-       default:
-               pupdr  = STM_PUPDR_NONE;
-               break;
-       case AO_EXTI_MODE_PULL_UP:
-               pupdr = STM_PUPDR_PULL_UP;
-               break;
-       case AO_EXTI_MODE_PULL_DOWN:
-               pupdr = STM_PUPDR_PULL_DOWN;
-               break;
+       if (!(mode & AO_EXTI_PIN_NOCONFIGURE)) {
+               /* configure pin as input, setting selected pull-up/down mode */
+               stm_moder_set(gpio, pin, STM_MODER_INPUT);
+               switch (mode & (AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_PULL_DOWN)) {
+               case 0:
+               default:
+                       pupdr  = STM_PUPDR_NONE;
+                       break;
+               case AO_EXTI_MODE_PULL_UP:
+                       pupdr = STM_PUPDR_PULL_UP;
+                       break;
+               case AO_EXTI_MODE_PULL_DOWN:
+                       pupdr = STM_PUPDR_PULL_DOWN;
+                       break;
+               }
+               stm_pupdr_set(gpio, pin, pupdr);
        }
-       stm_pupdr_set(gpio, pin, pupdr);
 
        /* Set interrupt mask and rising/falling mode */
        stm_exti.imr &= ~mask;
diff --git a/src/stm/ao_fast_timer.c b/src/stm/ao_fast_timer.c
new file mode 100644 (file)
index 0000000..d61b40c
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include <ao.h>
+#include <ao_fast_timer.h>
+
+static void (*ao_fast_timer_callback[AO_FAST_TIMER_MAX])(void);
+static uint8_t ao_fast_timer_count;
+static uint8_t ao_fast_timer_users;
+
+static void
+ao_fast_timer_enable(void)
+{
+       stm_tim6.cr1 = ((0 << STM_TIM67_CR1_ARPE) |
+                       (0 << STM_TIM67_CR1_OPM) |
+                       (1 << STM_TIM67_CR1_URS) |
+                       (0 << STM_TIM67_CR1_UDIS) |
+                       (1 << STM_TIM67_CR1_CEN));
+}
+
+static void
+ao_fast_timer_disable(void)
+{
+       stm_tim6.cr1 = ((0 << STM_TIM67_CR1_ARPE) |
+                       (0 << STM_TIM67_CR1_OPM) |
+                       (1 << STM_TIM67_CR1_URS) |
+                       (0 << STM_TIM67_CR1_UDIS) |
+                       (0 << STM_TIM67_CR1_CEN));
+}
+
+void
+ao_fast_timer_on(void (*callback)(void))
+{
+       ao_fast_timer_callback[ao_fast_timer_count] = callback;
+       if (!ao_fast_timer_count++)
+               ao_fast_timer_enable();
+}
+
+void
+ao_fast_timer_off(void (*callback)(void))
+{
+       uint8_t n;
+
+       for (n = 0; n < ao_fast_timer_count; n++)
+               if (ao_fast_timer_callback[n] == callback) {
+                       for (; n < ao_fast_timer_count-1; n++) {
+                               ao_fast_timer_callback[n] = ao_fast_timer_callback[n+1];
+                       }
+                       if (!--ao_fast_timer_count)
+                               ao_fast_timer_disable();
+                       break;
+               }
+}
+
+void stm_tim6_isr(void)
+{
+       uint8_t i;
+       if (stm_tim6.sr & (1 << STM_TIM67_SR_UIF)) {
+               stm_tim6.sr = 0;
+
+               for (i = 0; i < ao_fast_timer_count; i++)
+                       (*ao_fast_timer_callback[i])();
+       }
+}
+
+/*
+ * According to the STM clock-configuration, timers run
+ * twice as fast as the APB1 clock *if* the APB1 prescaler
+ * is greater than 1.
+ */
+
+#if AO_APB1_PRESCALER > 1
+#define TIMER_23467_SCALER 2
+#else
+#define TIMER_23467_SCALER 1
+#endif
+
+#define TIMER_10kHz    ((AO_PCLK1 * TIMER_23467_SCALER) / 10000)
+
+void
+ao_fast_timer_init(void)
+{
+       if (!ao_fast_timer_users) {
+               stm_nvic_set_enable(STM_ISR_TIM6_POS);
+               stm_nvic_set_priority(STM_ISR_TIM6_POS, AO_STM_NVIC_CLOCK_PRIORITY);
+
+               /* Turn on timer 6 */
+               stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM6EN);
+
+               stm_tim6.psc = TIMER_10kHz;
+               stm_tim6.arr = 9;
+               stm_tim6.cnt = 0;
+
+               /* Enable update interrupt */
+               stm_tim6.dier = (1 << STM_TIM67_DIER_UIE);
+
+               /* Poke timer to reload values */
+               stm_tim6.egr |= (1 << STM_TIM67_EGR_UG);
+
+               stm_tim6.cr2 = (STM_TIM67_CR2_MMS_RESET << STM_TIM67_CR2_MMS);
+               ao_fast_timer_disable();
+       }
+       if (ao_fast_timer_users == AO_FAST_TIMER_MAX)
+               ao_panic(AO_PANIC_FAST_TIMER);
+       ao_fast_timer_users++;
+}
+
diff --git a/src/stm/ao_fast_timer.h b/src/stm/ao_fast_timer.h
new file mode 100644 (file)
index 0000000..90fb393
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_FAST_TIMER_H_
+#define _AO_FAST_TIMER_H_
+
+void
+ao_fast_timer_init(void);
+
+#ifndef AO_FAST_TIMER_MAX
+#define AO_FAST_TIMER_MAX      2
+#endif
+
+void
+ao_fast_timer_on(void (*callback)(void));
+
+void
+ao_fast_timer_off(void (*callback)(void));
+
+#endif /* _AO_FAST_TIMER_H_ */
index d7a855827723cbee2ce3bc226e99860bca9ac74d..38b1c2d8b585c154b8d6a24cfca28cbeaddb0e36 100644 (file)
@@ -69,7 +69,7 @@ ao_flash_wait_bsy(void)
                ;
 }
 
-static void __attribute__ ((section(".text.ram"),noinline))
+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);
@@ -91,7 +91,7 @@ ao_flash_erase_page(uint32_t *page)
        ao_flash_lock();
 }
 
-static void __attribute__ ((section(".text.ram"), noinline))
+static void __attribute__ ((section(".ramtext"), noinline))
 _ao_flash_half_page(uint32_t *dst, uint32_t *src)
 {
        uint8_t         i;
index daf2f4000f3a7c3fc012064ac431e5edc1378fdd..34f9edb90b084d40b5fbee14cdca7d313a03d30c 100644 (file)
@@ -67,20 +67,6 @@ ao_timer_set_adc_interval(uint8_t interval)
 }
 #endif
 
-/*
- * According to the STM clock-configuration, timers run
- * twice as fast as the APB1 clock *if* the APB1 prescaler
- * is greater than 1.
- */
-
-#if AO_APB1_PRESCALER > 1
-#define TIMER_23467_SCALER 2
-#else
-#define TIMER_23467_SCALER 1
-#endif
-
-#define TIMER_10kHz    ((AO_PCLK1 * TIMER_23467_SCALER) / 10000)
-
 #define SYSTICK_RELOAD (AO_SYSTICK / 100 - 1)
 
 void
@@ -104,7 +90,15 @@ ao_clock_init(void)
        /* Switch to MSI while messing about */
        stm_rcc.cr |= (1 << STM_RCC_CR_MSION);
        while (!(stm_rcc.cr & (1 << STM_RCC_CR_MSIRDY)))
-               asm("nop");
+               ao_arch_nop();
+
+       stm_rcc.cfgr = (stm_rcc.cfgr & ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW)) |
+               (STM_RCC_CFGR_SW_MSI << STM_RCC_CFGR_SW);
+
+       /* wait for system to switch to MSI */
+       while ((stm_rcc.cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) !=
+              (STM_RCC_CFGR_SWS_MSI << STM_RCC_CFGR_SWS))
+               ao_arch_nop();
 
        /* reset SW, HPRE, PPRE1, PPRE2, MCOSEL and MCOPRE */
        stm_rcc.cfgr &= (uint32_t)0x88FFC00C;
@@ -155,7 +149,6 @@ ao_clock_init(void)
        stm_flash.acr |= (1 << STM_FLASH_ACR_PRFEN);
 
        /* Enable 1 wait state so the CPU can run at 32MHz */
-       /* (haven't managed to run the CPU at 32MHz yet, it's at 16MHz) */
        stm_flash.acr |= (1 << STM_FLASH_ACR_LATENCY);
 
        /* Enable power interface clock */
index 11dde92eedf1d583df74c57252d3aa8e048dd1b9..28a9f9f3e4643beac09b0db8a0dcf6e56c348fc9 100644 (file)
@@ -572,7 +572,7 @@ ao_usb_ep0_out_set(uint8_t *data, uint8_t len)
 }
 
 static void
-ao_usb_ep0_in_start(uint8_t max)
+ao_usb_ep0_in_start(uint16_t max)
 {
        /* Don't send more than asked for */
        if (ao_usb_ep0_in_len > max)
@@ -965,7 +965,7 @@ ao_usb_disable(void)
        stm_usb.cntr = (1 << STM_USB_CNTR_PDWN) | (1 << STM_USB_CNTR_FRES);
 
        /* Disable the interface */
-       stm_rcc.apb1enr &+ ~(1 << STM_RCC_APB1ENR_USBEN);
+       stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_USBEN);
        ao_arch_release_interrupts();
 }
 
index 63bde0f8b29b475d887ddd2624c43fcc70395040..ff3f53366904d277e4e4a3fc9a7d07fb048c35c3 100644 (file)
@@ -171,6 +171,11 @@ stm_gpio_get(struct stm_gpio *gpio, int pin) {
        return (gpio->idr >> pin) & 1;
 }
 
+static inline uint16_t
+stm_gpio_get_all(struct stm_gpio *gpio) {
+       return gpio->idr;
+}
+
 extern struct stm_gpio stm_gpioa;
 extern struct stm_gpio stm_gpiob;
 extern struct stm_gpio stm_gpioc;
@@ -1734,7 +1739,7 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4;
 #define  STM_TIM234_CCMR1_CC1S_INPUT_TRC               3
 #define  STM_TIM234_CCMR1_CC1S_MASK                    3
 
-#define STM_TIM234_CCMR2_OC2CE 15
+#define STM_TIM234_CCMR2_OC4CE 15
 #define STM_TIM234_CCMR2_OC4M  12
 #define  STM_TIM234_CCMR2_OC4M_FROZEN                  0
 #define  STM_TIM234_CCMR2_OC4M_SET_HIGH_ON_MATCH       1
index 2eea996e7166762202f8864e17afa10beb087efc..6ff076a9c8598a28b922b6a7b59c215fe6dc6e7b 100644 (file)
@@ -103,7 +103,7 @@ quiet ?= $($1)
 all: $(PROG)
 
 $(PROG): $(REL) Makefile
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
 
 ao_product.h: ao-make-product.5c ../Version
index e89726552dce132bddaf0c4f09f6a45471c0b12a..12752d1f8d3655f252ba2ba62dc6c29b63d99802 100644 (file)
@@ -105,8 +105,8 @@ ao_flight(void)
 
 #if HAS_GPS
                                /* Record current GPS position by waking up GPS log tasks */
-                               ao_wakeup(&ao_gps_data);
-                               ao_wakeup(&ao_gps_tracking_data);
+                               ao_gps_new = AO_GPS_NEW_DATA | AO_GPS_NEW_TRACKING;
+                               ao_wakeup(&ao_gps_new);
 #endif
 
                                ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
index 911a8b09e11d06712c89ea6e4a49a898b3e42913..40853fc3cc04d083686fe4e54b46242ec5e0f778 100644 (file)
@@ -82,7 +82,7 @@ quiet ?= $($1)
 all: $(PROG)
 
 $(PROG): $(REL) Makefile
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
 
 ao_product.h: ao-make-product.5c ../Version
index 712b2e8b8bfb57d1925a174989d9b609b10e1264..f9e116983bea0c26545a903c6861410125708627 100644 (file)
@@ -84,10 +84,10 @@ endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-all: ../$(PROG)
+all: $(PROG)
 
-../$(PROG): $(REL) Makefile
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)  || rm $@
 
 ao_product.h: ao-make-product.5c ../Version
index 774d59f45631ba155424df7a93f34ab48af58a76..f7a3ff2cea2dc40b7e31866da843d139aac494f7 100644 (file)
 
 #define AO_LED_CONTINUITY(c)   (1 << ((c) + 2))
 #define AO_LED_CONTINUITY_MASK (0xc)
-#define AO_LED_RX              0x10
-#define AO_LED_TX              0x20
-#define AO_LED_ARMED           0x40
-#define AO_LED_POWER           0x80
-
-#define AO_LED_RED             AO_LED_TX
-#define AO_LED_GREEN           AO_LED_RX
+#define AO_LED_ARMED           0x10
+#define AO_LED_RED             0x20
+#define AO_LED_AMBER           0x40
+#define AO_LED_GREEN           0x80
 
 #define LEDS_AVAILABLE         (0xff)
 #define HAS_EXTERNAL_TEMP      0
diff --git a/src/telefire-v0.2/.gitignore b/src/telefire-v0.2/.gitignore
new file mode 100644 (file)
index 0000000..4d4f420
--- /dev/null
@@ -0,0 +1,2 @@
+telefire-*
+ao_product.h
diff --git a/src/telefire-v0.2/.sdcdbrc b/src/telefire-v0.2/.sdcdbrc
new file mode 100644 (file)
index 0000000..b9f6129
--- /dev/null
@@ -0,0 +1,2 @@
+--directory=../cc1111:../product:../core:../drivers:.
+
diff --git a/src/telefire-v0.2/Makefile b/src/telefire-v0.2/Makefile
new file mode 100644 (file)
index 0000000..a820990
--- /dev/null
@@ -0,0 +1,103 @@
+#
+# TeleFire build file
+#
+
+TELEFIRE_VER=0.2
+TELEFIRE_DEF=0_2
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+       ao.h \
+       ao_pins.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_pad.h \
+       cc1111.h \
+       ao_product.h
+
+CORE_SRC = \
+       ao_cmd.c \
+       ao_config.c \
+       ao_convert.c \
+       ao_mutex.c \
+       ao_panic.c \
+       ao_stdio.c \
+       ao_storage.c \
+       ao_task.c \
+       ao_freq.c
+
+CC1111_SRC = \
+       ao_adc.c \
+       ao_aes.c \
+       ao_beep.c \
+       ao_dma.c \
+       ao_intflash.c \
+       ao_radio.c \
+       ao_radio_cmac.c \
+       ao_romconfig.c \
+       ao_serial.c \
+       ao_spi.c \
+       ao_string.c \
+       ao_timer.c \
+       ao_usb.c \
+       _bp.c
+
+DRIVER_SRC = \
+       ao_pca9922.c \
+       ao_74hc165.c \
+       ao_pad.c \
+       ao_radio_cmac_cmd.c
+
+PRODUCT_SRC = \
+       ao_telefire.c
+
+SRC = \
+       $(CORE_SRC) \
+       $(CC1111_SRC) \
+       $(DRIVER_SRC) \
+       $(PRODUCT_SRC)
+
+PROGNAME = telefire-v$(TELEFIRE_VER)
+PROG = $(PROGNAME)-$(VERSION).ihx
+PRODUCT=TeleFire-v$(TELEFIRE_VER)
+PRODUCT_DEF=-DTELEFIRE_V_$(TELEFIRE_DEF)
+IDPRODUCT=0x000f
+CODESIZE=0x6700
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf "  $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: $(PROG)
+
+$(PROG): $(REL) Makefile
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
+       $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM)  || rm $@
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean:     clean
+
+clean: clean-cc1111
+
+install:
+
+uninstall:
+
diff --git a/src/telefire-v0.2/ao_pins.h b/src/telefire-v0.2/ao_pins.h
new file mode 100644 (file)
index 0000000..96e6b06
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_RADIO      1
+
+#define HAS_FLIGHT             0
+#define HAS_USB                        1
+#define HAS_BEEP               0
+#define HAS_GPS                        0
+#define HAS_SERIAL_1           0
+#define HAS_ADC                        1
+#define HAS_DBG                        0
+#define HAS_EEPROM             1
+#define HAS_LOG                        0
+#define HAS_PAD                        1
+#define USE_INTERNAL_FLASH     1
+#define DBG_ON_P1              0
+#define IGNITE_ON_P2           0
+#define IGNITE_ON_P1           1
+#define IGNITE_ON_P0           0
+#define PACKET_HAS_MASTER      0
+#define PACKET_HAS_SLAVE       0
+
+#define AO_LED_CONTINUITY(c)   (1 << (c))
+#define AO_LED_CONTINUITY_MASK (0xf)
+#define AO_LED_ARMED           0x10
+#define AO_LED_RED             0x20
+#define AO_LED_AMBER           0x40
+#define AO_LED_GREEN           0x80
+
+#define LEDS_AVAILABLE         (0xff)
+#define HAS_EXTERNAL_TEMP      0
+#define HAS_ACCEL_REF          0
+#define SPI_CS_ON_P1           1
+#define HAS_AES                        1
+#define DMA_SHARE_AES_RADIO    1
+
+#define SPI_CS_PORT    P1
+#define SPI_CS_SEL     P1SEL
+#define SPI_CS_DIR     P1DIR
+
+#define SPI_CONST      0x00
+
+#define HAS_SPI_0              0
+#define HAS_SPI_1              1
+#define SPI_1_ALT_1            0
+#define SPI_1_ALT_2            1
+
+#define HAS_74HC165            1
+#define AO_74HC165_CS_PORT     P1
+#define AO_74HC165_CS_PIN      4
+#define AO_74HC165_CS          P1_4
+
+#define AO_PCA9922_CS_PORT     P2
+#define AO_PCA9922_CS_PIN      0
+#define AO_PCA9922_CS          P2_0
+
+#define AO_PAD_NUM             4
+#define        AO_PAD_PORT             P1
+#define AO_PAD_DIR             P1DIR
+
+#define AO_PAD_PIN_0           0
+#define AO_PAD_0               P1_0
+#define AO_PAD_ADC_0           0
+
+#define AO_PAD_PIN_1           1
+#define AO_PAD_1               P1_1
+#define AO_PAD_ADC_1           1
+
+#define AO_PAD_PIN_2           2
+#define AO_PAD_2               P1_2
+#define AO_PAD_ADC_2           2
+
+#define AO_PAD_PIN_3           3
+#define AO_PAD_3               P1_3
+#define AO_PAD_ADC_3           3
+
+#define AO_PAD_ALL_PINS                ((1 << AO_PAD_PIN_0) | (1 << AO_PAD_PIN_1) | (1 << AO_PAD_PIN_2) | (1 << AO_PAD_PIN_3))
+#define AO_PAD_ALL_CHANNELS    ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+
+#define AO_SIREN_PORT          P2
+#define AO_SIREN_DIR           P2DIR
+#define AO_SIREN_PIN           3
+#define AO_SIREN               P2_3
+
+#define AO_STROBE_PORT         P2
+#define AO_STROBE_DIR          P2DIR
+#define AO_STROBE_PIN          4
+#define AO_STROBE              P2_4
+
+/* 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                4
+#define AO_PAD_ADC_BATT                5
+
+#define AO_ADC_FIRST_PIN       0
+
+struct ao_adc {
+       int16_t         sense[AO_PAD_NUM];
+       int16_t         pyro;
+       int16_t         batt;
+};
+
+#define AO_ADC_DUMP(p)                                                 \
+       printf ("tick: %5u 0: %5d 1: %5d 2: %5d 3: %5d pyro: %5d batt %5d\n", \
+               (p)->tick,                                              \
+               (p)->adc.sense[0],                                      \
+               (p)->adc.sense[1],                                      \
+               (p)->adc.sense[2],                                      \
+               (p)->adc.sense[3],                                      \
+               (p)->adc.pyro,                                          \
+               (p)->adc.batt)
+
+#define AO_ADC_PINS    ((1 << AO_PAD_ADC_0) | \
+                        (1 << AO_PAD_ADC_1) | \
+                        (1 << AO_PAD_ADC_2) | \
+                        (1 << AO_PAD_ADC_3) | \
+                        (1 << AO_PAD_ADC_PYRO) | \
+                        (1 << AO_PAD_ADC_BATT))
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/telefire-v0.2/ao_telefire.c b/src/telefire-v0.2/ao_telefire.c
new file mode 100644 (file)
index 0000000..f27ca5e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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>
+#include <ao_pad.h>
+#include <ao_74hc165.h>
+#include <ao_radio_cmac_cmd.h>
+
+void
+main(void)
+{
+       ao_clock_init();
+
+       ao_led_init(LEDS_AVAILABLE);
+
+       ao_task_init();
+
+       ao_timer_init();
+       ao_adc_init();
+       ao_cmd_init();
+       ao_spi_init();
+       ao_74hc165_init();
+       ao_storage_init();
+       ao_usb_init();
+       ao_radio_init();
+       ao_aes_init();
+       ao_pad_init();
+//     ao_radio_cmac_cmd_init();
+       ao_config_init();
+       ao_start_scheduler();
+}
index 2c41235bc1e049538798365f4f0d037438fa6051..49e325ac9b48b376057259f1c072e67c67bcb3f8 100644 (file)
@@ -52,11 +52,11 @@ ALTOS_SRC = \
        ao_exti_stm.c \
        ao_serial_stm.c \
        ao_gps_skytraq.c \
+       ao_gps_show.c \
        ao_cc115l.c \
        ao_fec_tx.c \
        ao_rfpa0133.c \
        ao_aprs.c \
-       ao_storage.c \
        ao_eeprom_stm.c \
        ao_sdcard.c \
        ao_bufio.c \
@@ -74,14 +74,15 @@ CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STA
 
 PROGNAME=telegps-v0.1
 PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
 
 SRC=$(ALTOS_SRC) ao_telegps.c
 OBJ=$(SRC:.c=.o)
 
-all: $(PROG)
+all: $(PROG) $(HEX)
 
 $(PROG): Makefile $(OBJ) altos.ld
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
 
 $(OBJ): $(INC)
 
@@ -91,7 +92,7 @@ ao_product.h: ao-make-product.5c ../Version
 distclean:     clean
 
 clean:
-       rm -f *.o $(PROGNAME)-*.elf
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
        rm -f ao_product.h
 
 install:
index 5bea2681b24657ebd160e313c86ffbffab51cb74..7ff599562dff637263528423901c38df70aab36f 100644 (file)
 #define ao_gps_fifo            (ao_stm_usart2.rx_fifo)
 
 #define HAS_EEPROM             1
-#define USE_INTERNAL_FLASH     1
+#define USE_INTERNAL_FLASH     0
+#define USE_EEPROM_CONFIG      1
+#define USE_STORAGE_CONFIG     0
+
 #define HAS_USB                        1
 #define HAS_BEEP               0
 #define HAS_RADIO              1
index 68116bfb0f2a5af0a569ed708a2e898c57811ac5..bc37b504fd43da32f247d93a8d2b087891cb950e 100644 (file)
@@ -18,6 +18,7 @@
 #include <ao.h>
 #include <ao_exti.h>
 #include <ao_fat.h>
+#include <ao_eeprom.h>
 
 uint16_t       ao_flight_number = 1;
 
@@ -40,7 +41,7 @@ main(void)
        ao_dma_init();
        ao_exti_init();
 
-       ao_storage_init();
+       ao_eeprom_init();
 
        ao_serial_init();
 
diff --git a/src/telegps-v0.3/.gitignore b/src/telegps-v0.3/.gitignore
new file mode 100644 (file)
index 0000000..892c3ac
--- /dev/null
@@ -0,0 +1,3 @@
+ao_product.h
+ao_serial_lpc.h
+*.elf
diff --git a/src/telegps-v0.3/Makefile b/src/telegps-v0.3/Makefile
new file mode 100644 (file)
index 0000000..bb9c8c6
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# AltOS build
+#
+#
+
+include ../lpc/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_pins.h \
+       ao_product.h \
+       ao_task.h \
+       ao_whiten.h \
+       ao_cc115l.h \
+       ao_fec.h \
+       lpc.h \
+       Makefile
+
+
+ALTOS_SRC = \
+       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_lpc.c \
+       ao_mutex.c \
+       ao_freq.c \
+       ao_spi_lpc.c \
+       ao_usb_lpc.c \
+       ao_exti_lpc.c \
+       ao_serial_lpc.c \
+       ao_gps_ublox.c \
+       ao_gps_show.c \
+       ao_cc115l.c \
+       ao_fec_tx.c \
+       ao_aprs.c \
+       ao_telemetry.c \
+       ao_storage.c \
+       ao_m25.c \
+       ao_log.c \
+       ao_log_mega.c \
+       ao_gps_report_mega.c \
+       $(SAMPLE_PROFILE)
+
+PRODUCT=TeleGPS-v0.3
+PRODUCT_DEF=-DTELEGPS
+IDPRODUCT=0x0025
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) $(PROFILE_DEF) -Os -g
+
+PROGNAME=telegps-v0.3
+PROG=$(PROGNAME)-$(VERSION).elf
+
+SRC=$(ALTOS_SRC) ao_telegps.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG)
+
+LDFLAGS=-L../lpc -Wl,-Taltos.ld
+
+$(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 ao_serial_lpc.h $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/telegps-v0.3/ao_pins.h b/src/telegps-v0.3/ao_pins.h
new file mode 100644 (file)
index 0000000..a4afaa5
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define AO_STACK_SIZE  448
+
+#define IS_FLASH_LOADER                0
+
+/* Crystal on the board */
+#define AO_LPC_CLKIN   12000000
+
+/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */
+#define AO_LPC_CLKOUT  48000000
+
+/* System clock frequency */
+#define AO_LPC_SYSCLK  24000000
+
+#define HAS_SERIAL_0           1
+#define SERIAL_0_18_19         1
+#define USE_SERIAL_0_STDIN     0
+
+#define ao_gps_getchar         ao_serial0_getchar
+#define ao_gps_putchar         ao_serial0_putchar
+#define ao_gps_set_speed       ao_serial0_set_speed
+#define ao_gps_fifo            (ao_usart_rx_fifo)
+
+#define HAS_EEPROM             1
+#define USE_INTERNAL_FLASH     0
+#define HAS_USB                        1
+#define HAS_BEEP               0
+#define HAS_RADIO              1
+#define HAS_TELEMETRY          1
+#define HAS_RDF                        0
+#define HAS_APRS               1
+#define HAS_RADIO_RECV         0
+
+#define HAS_USB_PULLUP         1
+#define AO_USB_PULLUP_PORT     0
+#define AO_USB_PULLUP_PIN      7
+
+/* Flash part */
+#define HAS_SPI_0              1
+#define SPI_SCK0_P0_6          1
+#define SPI_0_OSPEEDR          AO_SPI_OSPEED_12MHz
+
+/* Radio */
+#define HAS_SPI_1              1
+#define SPI_SCK1_P1_15         1
+#define SPI_MISO1_P0_22                1
+#define SPI_MOSI1_P0_21                1
+
+#define HAS_GPS                        1
+#define HAS_FLIGHT             0
+#define HAS_ADC                        0
+#define HAS_LOG                        1
+
+#define AO_CONFIG_DEFAULT_APRS_INTERVAL        5
+#define AO_CONFIG_DEFAULT_RADIO_POWER          0xc0
+
+/*
+ * GPS
+ */
+
+#define AO_SERIAL_SPEED_UBLOX  AO_SERIAL_SPEED_9600
+
+/*
+ * Radio (cc115l)
+ */
+
+/* gets pretty close to 434.550 */
+
+#define AO_RADIO_CAL_DEFAULT   0x10b6a5
+
+#define HAS_RADIO_POWER                1
+#define AO_FEC_DEBUG           0
+#define AO_CC115L_SPI_CS_PORT  0
+#define AO_CC115L_SPI_CS_PIN   3
+#define AO_CC115L_SPI_BUS      0
+
+#define AO_CC115L_FIFO_INT_GPIO_IOCFG  CC115L_IOCFG2
+#define AO_CC115L_FIFO_INT_PORT                0
+#define AO_CC115L_FIFO_INT_PIN         20
+
+#define AO_CC115L_DONE_INT_GPIO_IOCFG  CC115L_IOCFG0
+#define AO_CC115L_DONE_INT_PORT                0
+#define AO_CC115L_DONE_INT_PIN         2
+
+/*
+ * Flash (M25)
+ */
+#define M25_MAX_CHIPS          1
+#define AO_M25_SPI_CS_PORT     0
+#define AO_M25_SPI_CS_MASK     (1 << 23)
+#define AO_M25_SPI_BUS         1
+
+#define PACKET_HAS_SLAVE       0
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/telegps-v0.3/ao_telegps.c b/src/telegps-v0.3/ao_telegps.c
new file mode 100644 (file)
index 0000000..608817e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+#include <ao_fat.h>
+
+uint16_t       ao_flight_number = 1;
+
+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();
+
+       ao_gps_init();
+#if HAS_LOG
+       ao_gps_report_mega_init();
+       ao_log_init();
+#endif
+
+       ao_telemetry_init();
+       ao_telemetry_set_interval(AO_SEC_TO_TICKS(1));
+
+#if HAS_SAMPLE_PROFILE
+       ao_sample_profile_init();
+#endif
+       ao_config_init();
+       
+       ao_start_scheduler();
+       return 0;
+}
diff --git a/src/telegps-v0.3/flash-loader/Makefile b/src/telegps-v0.3/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..6f4ce0d
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telegps-v0.3
+include $(TOPDIR)/lpc/Makefile-flash.defs
diff --git a/src/telegps-v0.3/flash-loader/ao_pins.h b/src/telegps-v0.3/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..91097a2
--- /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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#include <ao_flash_lpc_pins.h>
+
+#define AO_BOOT_PIN            1
+#define AO_BOOT_APPLICATION_GPIO       0
+#define AO_BOOT_APPLICATION_PIN                19
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+#define HAS_USB_PULLUP         1
+#define AO_USB_PULLUP_PORT     0
+#define AO_USB_PULLUP_PIN      7
+
+#endif /* _AO_PINS_H_ */
index 240833082bdf7c7f80dc790856feab4ef88dbd4a..44d9237fc760f7e1a1d2aae28423e1d03357ca39 100644 (file)
@@ -69,14 +69,15 @@ CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
 
 PROGNAME=telelco-v0.1
 PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
 
 SRC=$(ALTOS_SRC) ao_telelco.c
 OBJ=$(SRC:.c=.o)
 
-all: $(PROG)
+all: $(PROG) $(HEX)
 
 $(PROG): Makefile $(OBJ) altos.ld
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
 
 ../altitude.h: make-altitude
        nickle $< > $@
@@ -89,7 +90,7 @@ ao_product.h: ao-make-product.5c ../Version
 distclean:     clean
 
 clean:
-       rm -f *.o $(PROGNAME)-*.elf
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
        rm -f ao_product.h
 
 install:
index cc6e62c4a2502480e1be827ba645d697515104eb..f28bdd320510697bc0f760714d1c5ae9d0b1a469 100644 (file)
@@ -21,6 +21,7 @@ INC = \
        ao_radio_spi.h \
        ao_radio_cmac.h \
        ao_cc1120_CC1120.h \
+       ao_debounce.h \
        stm32l.h
 
 #
@@ -47,8 +48,8 @@ ALTOS_SRC = \
        ao_dma_stm.c \
        ao_spi_stm.c \
        ao_beep_stm.c \
-       ao_storage.c \
        ao_eeprom_stm.c \
+       ao_fast_timer.c \
        ao_lcd_stm.c \
        ao_usb_stm.c \
        ao_exti_stm.c \
@@ -59,6 +60,7 @@ ALTOS_SRC = \
        ao_fec_tx.c \
        ao_fec_rx.c \
        ao_seven_segment.c \
+       ao_debounce.c \
        ao_quadrature.c \
        ao_button.c \
        ao_event.c \
@@ -75,14 +77,15 @@ CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
 
 PROGNAME=telelco-v0.2
 PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
 
 SRC=$(ALTOS_SRC) ao_telelco.c
 OBJ=$(SRC:.c=.o)
 
-all: $(PROG)
+all: $(PROG) $(HEX)
 
 $(PROG): Makefile $(OBJ) altos.ld
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
 
 ../altitude.h: make-altitude
        nickle $< > $@
@@ -95,7 +98,7 @@ ao_product.h: ao-make-product.5c ../Version
 distclean:     clean
 
 clean:
-       rm -f *.o $(PROGNAME)-*.elf
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
        rm -f ao_product.h
 
 install:
index 418c0509539e34dfc65a4d5707e23c60e4468b14..e8d16ca93cfdaf24b0c9a237b2f407571bb0899e 100644 (file)
@@ -49,16 +49,16 @@ static uint16_t     ao_lco_tick_offset;
 static struct ao_pad_query     ao_pad_query;
 
 static void
-ao_lco_set_pad(void)
+ao_lco_set_pad(uint8_t pad)
 {
-       ao_seven_segment_set(AO_LCO_PAD_DIGIT, ao_lco_pad + 1);
+       ao_seven_segment_set(AO_LCO_PAD_DIGIT, pad + 1);
 }
 
 static void
-ao_lco_set_box(void)
+ao_lco_set_box(uint8_t box)
 {
-       ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, ao_lco_box % 10);
-       ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, ao_lco_box / 10);
+       ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, box % 10);
+       ao_seven_segment_set(AO_LCO_BOX_DIGIT_10, box / 10);
 }
 
 #define MASK_SIZE(n)   (((n) + 7) >> 3)
@@ -103,8 +103,6 @@ ao_lco_input(void)
        int8_t  dir, new_box, new_pad;
 
        ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200));
-       ao_lco_set_pad();
-       ao_lco_set_box();
        for (;;) {
                ao_event_get(&event);
                PRINTD("event type %d unit %d value %d\n",
@@ -114,11 +112,9 @@ ao_lco_input(void)
                        switch (event.unit) {
                        case AO_QUADRATURE_PAD:
                                if (!ao_lco_armed) {
-                                       if (event.value == ao_lco_pad)
-                                               break;
-                                       dir = ((int8_t) event.value - (int8_t) ao_lco_pad) > 0 ? 1 : -1;
-                                       new_pad = event.value;
-                                       while (!ao_lco_pad_present(new_pad)) {
+                                       dir = (int8_t) event.value;
+                                       new_pad = ao_lco_pad;
+                                       do {
                                                new_pad += dir;
                                                if (new_pad > AO_PAD_MAX_CHANNELS)
                                                        new_pad = 0;
@@ -126,34 +122,30 @@ ao_lco_input(void)
                                                        new_pad = AO_PAD_MAX_CHANNELS - 1;
                                                if (new_pad == ao_lco_pad)
                                                        break;
-                                       }
+                                       } while (!ao_lco_pad_present(new_pad));
                                        if (new_pad != ao_lco_pad) {
                                                ao_lco_pad = new_pad;
-                                               ao_quadrature_count[AO_QUADRATURE_PAD] = ao_lco_pad;
-                                               ao_lco_set_pad();
+                                               ao_lco_set_pad(ao_lco_pad);
                                        }
                                }
                                break;
                        case AO_QUADRATURE_BOX:
                                if (!ao_lco_armed) {
-                                       if (event.value == ao_lco_box)
-                                               break;
-                                       dir = ((int8_t) event.value - (int8_t) ao_lco_box) > 0 ? 1 : -1;
-                                       new_box = event.value;
-                                       while (!ao_lco_box_present(new_box)) {
+                                       dir = (int8_t) event.value;
+                                       new_box = ao_lco_box;
+                                       do {
                                                new_box += dir;
                                                if (new_box > ao_lco_max_box)
                                                        new_box = ao_lco_min_box;
                                                else if (new_box < ao_lco_min_box)
-                                                       new_box = ao_lco_min_box;
+                                                       new_box = ao_lco_max_box;
                                                if (new_box == ao_lco_box)
                                                        break;
-                                       }
-                                       ao_quadrature_count[AO_QUADRATURE_PAD] = new_box;
+                                       } while (!ao_lco_box_present(new_box));
                                        if (ao_lco_box != new_box) {
                                                ao_lco_box = new_box;
                                                ao_lco_got_channels = 0;
-                                               ao_lco_set_box();
+                                               ao_lco_set_box(ao_lco_box);
                                        }
                                }
                                break;
@@ -219,7 +211,7 @@ ao_lco_update(void)
                ao_lco_valid = 1;
                if (!c) {
                        ao_lco_pad = ao_lco_pad_first();
-                       ao_lco_set_pad();
+                       ao_lco_set_pad(ao_lco_pad);
                }
        } else
                ao_lco_valid = 0;
@@ -232,13 +224,24 @@ ao_lco_update(void)
               query.igniter_status[2],
               query.igniter_status[3]);
 #endif
-
        ao_wakeup(&ao_pad_query);
 }
 
+static void
+ao_lco_box_reset_present(void)
+{
+       ao_lco_min_box = 0xff;
+       ao_lco_max_box = 0x00;
+       memset(ao_lco_box_mask, 0, sizeof (ao_lco_box_mask));
+}
+
 static void
 ao_lco_box_set_present(uint8_t box)
 {
+       if (box < ao_lco_min_box)
+               ao_lco_min_box = box;
+       if (box > ao_lco_max_box)
+               ao_lco_max_box = box;
        if (box >= AO_PAD_MAX_BOXES)
                return;
        ao_lco_box_mask[MASK_ID(box)] |= 1 << MASK_SHIFT(box);
@@ -249,19 +252,18 @@ ao_lco_search(void)
 {
        uint16_t        tick_offset;
        int8_t          r;
-
-       ao_lco_min_box = 0xff;
-       ao_lco_max_box = 0x00;
-       for (ao_lco_box = 0; ao_lco_box < AO_PAD_MAX_BOXES; ao_lco_box++) {
-               if ((ao_lco_box % 10) == 0)
-                       ao_lco_set_box();
-               r = ao_lco_query(ao_lco_box, &ao_pad_query, &ao_lco_tick_offset);
+       uint8_t         box;
+
+       ao_lco_box_reset_present();
+       for (box = 0; box < AO_PAD_MAX_BOXES; box++) {
+               if ((box % 10) == 0)
+                       ao_lco_set_box(box);
+               tick_offset = 0;
+               r = ao_lco_query(box, &ao_pad_query, &tick_offset);
+               PRINTD("box %d result %d\n", box, r);
                if (r == AO_RADIO_CMAC_OK) {
-                       if (ao_lco_box < ao_lco_min_box)
-                               ao_lco_min_box = ao_lco_box;
-                       if (ao_lco_box > ao_lco_max_box)
-                               ao_lco_max_box = ao_lco_box;
-                       ao_lco_box_set_present(ao_lco_box);
+                       ao_lco_box_set_present(box);
+                       ao_delay(AO_MS_TO_TICKS(30));
                }
        }
        if (ao_lco_min_box <= ao_lco_max_box)
@@ -271,6 +273,8 @@ ao_lco_search(void)
        ao_lco_valid = 0;
        ao_lco_got_channels = 0;
        ao_lco_pad = 0;
+       ao_lco_set_pad(ao_lco_pad);
+       ao_lco_set_box(ao_lco_box);
 }
 
 static void
@@ -382,6 +386,7 @@ ao_lco_set_debug(void)
 
 __code struct ao_cmds ao_lco_cmds[] = {
        { ao_lco_set_debug,     "D <0 off, 1 on>\0Debug" },
+       { ao_lco_search,        "s\0Search for pad boxes" },
        { 0, NULL }
 };
 #endif
index 07ea1b4594f893ff7620f655f629eb100d4f4267..62f221a1da8979402697e6da3dfbebe94db05bbe 100644 (file)
@@ -43,6 +43,8 @@
 
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     1
+#define USE_EEPROM_CONFIG      1
+#define USE_STORAGE_CONFIG     0
 #define HAS_USB                        1
 #define HAS_BEEP               1
 #define HAS_RADIO              1
  */
 
 #define AO_QUADRATURE_COUNT    2
-#define AO_QUADRATURE_MODE     0
 
 #define AO_QUADRATURE_0_PORT   &stm_gpioe
 #define AO_QUADRATURE_0_A      3
index 66bf0ba18e6ee7d7007b36baefd08e2a73974a10..d9f7c693823da1b8bb168452b9b412d56a16c6cc 100644 (file)
@@ -28,6 +28,7 @@
 #include <ao_lco.h>
 #include <ao_lco_cmd.h>
 #include <ao_radio_cmac_cmd.h>
+#include <ao_eeprom.h>
 
 int
 main(void)
@@ -52,7 +53,7 @@ main(void)
        ao_quadrature_init();
        ao_button_init();
 
-       ao_storage_init();
+       ao_eeprom_init();
        
        ao_radio_init();
 
index a72d08f213a16da7577c5ce1a2f3688990570ad4..0145f49c5f45ad063a6f45da19a0614fb93e3554 100644 (file)
@@ -25,6 +25,8 @@ INC = \
        ao_task.h \
        ao_whiten.h \
        ao_sample_profile.h \
+       ao_quaternion.h \
+       math.h \
        ao_mpu.h \
        stm32l.h \
        Makefile
@@ -44,6 +46,20 @@ INC = \
 #STACK_GUARD=ao_mpu_stm.c
 #STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
 
+MATH_SRC=\
+       ef_acos.c \
+       ef_sqrt.c \
+       ef_rem_pio2.c \
+       kf_cos.c \
+       kf_sin.c \
+       kf_rem_pio2.c \
+       sf_copysign.c \
+       sf_cos.c \
+       sf_sin.c \
+       sf_fabs.c \
+       sf_floor.c \
+       sf_scalbn.c
+
 ALTOS_SRC = \
        ao_boot_chain.c \
        ao_interrupt.c \
@@ -59,6 +75,7 @@ ALTOS_SRC = \
        ao_mutex.c \
        ao_serial_stm.c \
        ao_gps_skytraq.c \
+       ao_gps_show.c \
        ao_gps_report_mega.c \
        ao_ignite.c \
        ao_freq.c \
@@ -73,6 +90,7 @@ ALTOS_SRC = \
        ao_hmc5883.c \
        ao_adc_stm.c \
        ao_beep_stm.c \
+       ao_eeprom_stm.c \
        ao_storage.c \
        ao_m25.c \
        ao_usb_stm.c \
@@ -92,6 +110,7 @@ ALTOS_SRC = \
        ao_companion.c \
        ao_pyro.c \
        ao_aprs.c \
+       $(MATH_SRC) \
        $(PROFILE) \
        $(SAMPLE_PROFILE) \
        $(STACK_GUARD)
@@ -104,14 +123,15 @@ CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STA
 
 PROGNAME=telemega-v0.1
 PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
 
 SRC=$(ALTOS_SRC) ao_telemega.c
 OBJ=$(SRC:.c=.o)
 
-all: $(PROG)
+all: $(PROG) $(HEX)
 
 $(PROG): Makefile $(OBJ) altos.ld
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
 
 ../altitude-pa.h: make-altitude-pa
        nickle $< > $@
@@ -124,7 +144,7 @@ ao_product.h: ao-make-product.5c ../Version
 distclean:     clean
 
 clean:
-       rm -f *.o $(PROGNAME)-*.elf
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
        rm -f ao_product.h
 
 install:
index 4c645871fe758d6f6159da4aa49e38ef2823e936..daeb9f1741d0e08aa6de2be1274dd8ac135a60a1 100644 (file)
 #define ao_gps_set_speed       ao_serial3_set_speed
 #define ao_gps_fifo            (ao_stm_usart3.rx_fifo)
 
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       (1024 * 1024)
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
+#define USE_EEPROM_CONFIG      1
+#define USE_STORAGE_CONFIG     0
 #define HAS_USB                        1
 #define HAS_BEEP               1
 #define HAS_RADIO              1
 #define HAS_GPS                        1
 #define HAS_FLIGHT             1
 #define HAS_ADC                        1
+#define HAS_ADC_TEMP           1
 #define HAS_LOG                        1
 
 /*
 #define HAS_IGNITE             1
 #define HAS_IGNITE_REPORT      1
 
-#define AO_SENSE_DROGUE(p)     ((p)->adc.sense[0])
-#define AO_SENSE_MAIN(p)       ((p)->adc.sense[1])
+#define AO_SENSE_PYRO(p,n)     ((p)->adc.sense[n])
+#define AO_SENSE_DROGUE(p)     ((p)->adc.sense[4])
+#define AO_SENSE_MAIN(p)       ((p)->adc.sense[5])
 #define AO_IGNITER_CLOSED      400
 #define AO_IGNITER_OPEN                60
 
-#define AO_IGNITER_DROGUE_PORT (&stm_gpiod)
-#define AO_IGNITER_DROGUE_PIN  6
+/* Pyro A */
+#define AO_PYRO_PORT_0 (&stm_gpiod)
+#define AO_PYRO_PIN_0  6
 
-#define AO_IGNITER_MAIN_PORT   (&stm_gpiod)
-#define AO_IGNITER_MAIN_PIN    7
+/* Pyro B */
+#define AO_PYRO_PORT_1 (&stm_gpiod)
+#define AO_PYRO_PIN_1  7
 
-#define AO_PYRO_PORT_0 (&stm_gpiob)
-#define AO_PYRO_PIN_0  5
+/* Pyro C */
+#define AO_PYRO_PORT_2 (&stm_gpiob)
+#define AO_PYRO_PIN_2  5
 
-#define AO_PYRO_PORT_1 (&stm_gpioe)
-#define AO_PYRO_PIN_1  4
+/* Pyro D */
+#define AO_PYRO_PORT_3 (&stm_gpioe)
+#define AO_PYRO_PIN_3  4
 
-#define AO_PYRO_PORT_2 (&stm_gpioe)
-#define AO_PYRO_PIN_2  6
+/* Drogue */
+#define AO_IGNITER_DROGUE_PORT (&stm_gpioe)
+#define AO_IGNITER_DROGUE_PIN  6
 
-#define AO_PYRO_PORT_3 (&stm_gpioe)
-#define AO_PYRO_PIN_3  5
+/* Main */
+#define AO_IGNITER_MAIN_PORT   (&stm_gpioe)
+#define AO_IGNITER_MAIN_PIN    5
 
 /* Number of general purpose pyro channels available */
 #define AO_PYRO_NUM    4
@@ -159,11 +170,16 @@ struct ao_adc {
        int16_t                 sense[AO_ADC_NUM_SENSE];
        int16_t                 v_batt;
        int16_t                 v_pbatt;
-       int16_t                 accel_ref;
-       int16_t                 accel;
        int16_t                 temp;
 };
 
+#define AO_ADC_DUMP(p) \
+       printf("tick: %5u A: %5d B: %5d C: %5d D: %5d drogue: %5d main: %5d batt: %5d pbatt: %5d temp: %5d\n", \
+              (p)->tick, \
+              (p)->adc.sense[0], (p)->adc.sense[1], (p)->adc.sense[2], \
+              (p)->adc.sense[3], (p)->adc.sense[4], (p)->adc.sense[5], \
+              (p)->adc.v_batt, (p)->adc.v_pbatt, (p)->adc.temp)
+
 #define AO_ADC_SENSE_A         0
 #define AO_ADC_SENSE_A_PORT    (&stm_gpioa)
 #define AO_ADC_SENSE_A_PIN     0
@@ -180,13 +196,13 @@ struct ao_adc {
 #define AO_ADC_SENSE_D_PORT    (&stm_gpioa)
 #define AO_ADC_SENSE_D_PIN     3
 
-#define AO_ADC_SENSE_E         4
-#define AO_ADC_SENSE_E_PORT    (&stm_gpioa)
-#define AO_ADC_SENSE_E_PIN     4
+#define AO_ADC_SENSE_DROGUE    4
+#define AO_ADC_SENSE_DROGUE_PORT       (&stm_gpioa)
+#define AO_ADC_SENSE_DROGUE_PIN        4
 
-#define AO_ADC_SENSE_F         22
-#define AO_ADC_SENSE_F_PORT    (&stm_gpioe)
-#define AO_ADC_SENSE_F_PIN     7
+#define AO_ADC_SENSE_MAIN      22
+#define AO_ADC_SENSE_MAIN_PORT (&stm_gpioe)
+#define AO_ADC_SENSE_MAIN_PIN  7
 
 #define AO_ADC_V_BATT          8
 #define AO_ADC_V_BATT_PORT     (&stm_gpiob)
@@ -196,22 +212,13 @@ struct ao_adc {
 #define AO_ADC_V_PBATT_PORT    (&stm_gpiob)
 #define AO_ADC_V_PBATT_PIN     1
 
-#define AO_ADC_ACCEL_REF       10
-#define AO_ADC_ACCEL_REF_PORT  (&stm_gpioc)
-#define AO_ADC_ACCEL_REF_PIN   0
-
-#define AO_ADC_ACCEL           11
-#define AO_ADC_ACCEL_PORT      (&stm_gpioc)
-#define AO_ADC_ACCEL_PIN       1
-
 #define AO_ADC_TEMP            16
 
 #define AO_ADC_RCC_AHBENR      ((1 << STM_RCC_AHBENR_GPIOAEN) | \
                                 (1 << STM_RCC_AHBENR_GPIOEEN) | \
-                                (1 << STM_RCC_AHBENR_GPIOBEN) | \
-                                (1 << STM_RCC_AHBENR_GPIOCEN))
+                                (1 << STM_RCC_AHBENR_GPIOBEN))
 
-#define AO_NUM_ADC_PIN         (AO_ADC_NUM_SENSE + 4)
+#define AO_NUM_ADC_PIN         (AO_ADC_NUM_SENSE + 2)
 
 #define AO_ADC_PIN0_PORT       AO_ADC_SENSE_A_PORT
 #define AO_ADC_PIN0_PIN                AO_ADC_SENSE_A_PIN
@@ -221,32 +228,26 @@ struct ao_adc {
 #define AO_ADC_PIN2_PIN                AO_ADC_SENSE_C_PIN
 #define AO_ADC_PIN3_PORT       AO_ADC_SENSE_D_PORT
 #define AO_ADC_PIN3_PIN                AO_ADC_SENSE_D_PIN
-#define AO_ADC_PIN4_PORT       AO_ADC_SENSE_E_PORT
-#define AO_ADC_PIN4_PIN                AO_ADC_SENSE_E_PIN
-#define AO_ADC_PIN5_PORT       AO_ADC_SENSE_F_PORT
-#define AO_ADC_PIN5_PIN                AO_ADC_SENSE_F_PIN
+#define AO_ADC_PIN4_PORT       AO_ADC_SENSE_DROGUE_PORT
+#define AO_ADC_PIN4_PIN                AO_ADC_SENSE_DROGUE_PIN
+#define AO_ADC_PIN5_PORT       AO_ADC_SENSE_MAIN_PORT
+#define AO_ADC_PIN5_PIN                AO_ADC_SENSE_MAIN_PIN
 #define AO_ADC_PIN6_PORT       AO_ADC_V_BATT_PORT
 #define AO_ADC_PIN6_PIN                AO_ADC_V_BATT_PIN
 #define AO_ADC_PIN7_PORT       AO_ADC_V_PBATT_PORT
 #define AO_ADC_PIN7_PIN                AO_ADC_V_PBATT_PIN
-#define AO_ADC_PIN8_PORT       AO_ADC_ACCEL_REF_PORT
-#define AO_ADC_PIN8_PIN                AO_ADC_ACCEL_REF_PIN
-#define AO_ADC_PIN9_PORT       AO_ADC_ACCEL_PORT
-#define AO_ADC_PIN9_PIN                AO_ADC_ACCEL_PIN
 
-#define AO_NUM_ADC             (AO_ADC_NUM_SENSE + 5)
+#define AO_NUM_ADC             (AO_ADC_NUM_SENSE + 3)
 
 #define AO_ADC_SQ1             AO_ADC_SENSE_A
 #define AO_ADC_SQ2             AO_ADC_SENSE_B
 #define AO_ADC_SQ3             AO_ADC_SENSE_C
 #define AO_ADC_SQ4             AO_ADC_SENSE_D
-#define AO_ADC_SQ5             AO_ADC_SENSE_E
-#define AO_ADC_SQ6             AO_ADC_SENSE_F
+#define AO_ADC_SQ5             AO_ADC_SENSE_DROGUE
+#define AO_ADC_SQ6             AO_ADC_SENSE_MAIN
 #define AO_ADC_SQ7             AO_ADC_V_BATT
 #define AO_ADC_SQ8             AO_ADC_V_PBATT
-#define AO_ADC_SQ9             AO_ADC_ACCEL_REF
-#define AO_ADC_SQ10            AO_ADC_ACCEL
-#define AO_ADC_SQ11            AO_ADC_TEMP
+#define AO_ADC_SQ9             AO_ADC_TEMP
 
 /*
  * Pressure sensor settings
@@ -296,7 +297,6 @@ struct ao_adc {
 #define AO_CC1120_MARC_GPIO    3
 #define AO_CC1120_MARC_GPIO_IOCFG      CC1120_IOCFG3
 
-
 #define HAS_BOOT_RADIO         0
 
 /*
@@ -316,8 +316,7 @@ struct ao_adc {
 #define AO_MPU6000_INT_PORT    (&stm_gpioc)
 #define AO_MPU6000_INT_PIN     13
 #define AO_MPU6000_I2C_INDEX   STM_I2C_INDEX(1)
-
-#define HAS_HIGHG_ACCEL                0
+#define HAS_IMU                        1
 
 /*
  * mma655x
index fbdab64a8766dbbc8a43d21a8e417da4d93691d1..7b035269bccd5d0d678a4a8ae23bb1682f77aa96 100644 (file)
@@ -24,6 +24,7 @@
 #include <ao_packet.h>
 #include <ao_companion.h>
 #include <ao_profile.h>
+#include <ao_eeprom.h>
 #if HAS_SAMPLE_PROFILE
 #include <ao_sample_profile.h>
 #endif
@@ -71,6 +72,7 @@ main(void)
        ao_mma655x_init();
 #endif
 
+       ao_eeprom_init();
        ao_storage_init();
        
        ao_flight_init();
diff --git a/src/telemega-v0.3/.gitignore b/src/telemega-v0.3/.gitignore
deleted file mode 100644 (file)
index e67759a..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ao_product.h
-telemega-*.elf
diff --git a/src/telemega-v0.3/Makefile b/src/telemega-v0.3/Makefile
deleted file mode 100644 (file)
index 398c7da..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#
-# AltOS build
-#
-#
-
-include ../stm/Makefile.defs
-
-INC = \
-       ao.h \
-       ao_arch.h \
-       ao_arch_funcs.h \
-       ao_companion.h \
-       ao_data.h \
-       ao_sample.h \
-       ao_pins.h \
-       altitude-pa.h \
-       ao_kalman.h \
-       ao_product.h \
-       ao_ms5607.h \
-       ao_hmc5883.h \
-       ao_mpu6000.h \
-       ao_mma655x.h \
-       ao_cc1120_CC1120.h \
-       ao_profile.h \
-       ao_task.h \
-       ao_whiten.h \
-       ao_sample_profile.h \
-       ao_mpu.h \
-       stm32l.h \
-       Makefile
-
-#
-# Common AltOS sources
-#
-#      ao_hmc5883.c
-
-#PROFILE=ao_profile.c
-#PROFILE_DEF=-DAO_PROFILE=1
-
-#SAMPLE_PROFILE=ao_sample_profile.c \
-#      ao_sample_profile_timer.c
-#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1
-
-#STACK_GUARD=ao_mpu_stm.c
-#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
-
-ALTOS_SRC = \
-       ao_boot_chain.c \
-       ao_interrupt.c \
-       ao_product.c \
-       ao_romconfig.c \
-       ao_cmd.c \
-       ao_config.c \
-       ao_task.c \
-       ao_led.c \
-       ao_stdio.c \
-       ao_panic.c \
-       ao_timer.c \
-       ao_mutex.c \
-       ao_serial_stm.c \
-       ao_gps_ublox.c \
-       ao_gps_report_mega.c \
-       ao_ignite.c \
-       ao_freq.c \
-       ao_dma_stm.c \
-       ao_spi_stm.c \
-       ao_cc1120.c \
-       ao_fec_tx.c \
-       ao_fec_rx.c \
-       ao_data.c \
-       ao_ms5607.c \
-       ao_mma655x.c \
-       ao_hmc5883.c \
-       ao_adc_stm.c \
-       ao_beep_stm.c \
-       ao_storage.c \
-       ao_m25.c \
-       ao_usb_stm.c \
-       ao_exti_stm.c \
-       ao_report.c \
-       ao_i2c_stm.c \
-       ao_mpu6000.c \
-       ao_convert_pa.c \
-       ao_log.c \
-       ao_log_mega.c \
-       ao_sample.c \
-       ao_kalman.c \
-       ao_flight.c \
-       ao_telemetry.c \
-       ao_packet_slave.c \
-       ao_packet.c \
-       ao_companion.c \
-       ao_pyro.c \
-       ao_aprs.c \
-       $(PROFILE) \
-       $(SAMPLE_PROFILE) \
-       $(STACK_GUARD)
-
-PRODUCT=TeleMega-v0.3
-PRODUCT_DEF=-DTELEMEGA
-IDPRODUCT=0x0023
-
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
-
-PROGNAME=telemega-v0.3
-PROG=$(PROGNAME)-$(VERSION).elf
-
-SRC=$(ALTOS_SRC) ao_telemega.c
-OBJ=$(SRC:.c=.o)
-
-all: $(PROG)
-
-$(PROG): Makefile $(OBJ) altos.ld
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
-
-../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
-       rm -f ao_product.h
-
-install:
-
-uninstall:
diff --git a/src/telemega-v0.3/ao_pins.h b/src/telemega-v0.3/ao_pins.h
deleted file mode 100644 (file)
index b1504d2..0000000
+++ /dev/null
@@ -1,344 +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; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_PINS_H_
-#define _AO_PINS_H_
-
-#define HAS_TASK_QUEUE         1
-
-/* 8MHz High speed external crystal */
-#define AO_HSE                 8000000
-
-/* PLLVCO = 96MHz (so that USB will work) */
-#define AO_PLLMUL              12
-#define AO_RCC_CFGR_PLLMUL     (STM_RCC_CFGR_PLLMUL_12)
-
-/* SYSCLK = 32MHz (no need to go faster than CPU) */
-#define AO_PLLDIV              3
-#define AO_RCC_CFGR_PLLDIV     (STM_RCC_CFGR_PLLDIV_3)
-
-/* HCLK = 32MHz (CPU clock) */
-#define AO_AHB_PRESCALER       1
-#define AO_RCC_CFGR_HPRE_DIV   STM_RCC_CFGR_HPRE_DIV_1
-
-/* Run APB1 at 16MHz (HCLK/2) */
-#define AO_APB1_PRESCALER      2
-#define AO_RCC_CFGR_PPRE1_DIV  STM_RCC_CFGR_PPRE2_DIV_2
-
-/* Run APB2 at 16MHz (HCLK/2) */
-#define AO_APB2_PRESCALER      2
-#define AO_RCC_CFGR_PPRE2_DIV  STM_RCC_CFGR_PPRE2_DIV_2
-
-#define HAS_SERIAL_1           1
-#define USE_SERIAL_1_STDIN     0
-#define SERIAL_1_PB6_PB7       0
-#define SERIAL_1_PA9_PA10      1
-
-#define HAS_SERIAL_2           0
-#define USE_SERIAL_2_STDIN     0
-#define SERIAL_2_PA2_PA3       0
-#define SERIAL_2_PD5_PD6       0
-
-#define HAS_SERIAL_3           1
-#define USE_SERIAL_3_STDIN     0
-#define SERIAL_3_PB10_PB11     0
-#define SERIAL_3_PC10_PC11     1
-#define SERIAL_3_PD8_PD9       0
-
-#define ao_gps_getchar         ao_serial3_getchar
-#define ao_gps_putchar         ao_serial3_putchar
-#define ao_gps_set_speed       ao_serial3_set_speed
-#define ao_gps_fifo            (ao_stm_usart3.rx_fifo)
-
-#define HAS_EEPROM             1
-#define USE_INTERNAL_FLASH     0
-#define HAS_USB                        1
-#define HAS_BEEP               1
-#define HAS_RADIO              1
-#define HAS_TELEMETRY          1
-#define HAS_APRS               1
-
-#define HAS_SPI_1              1
-#define SPI_1_PA5_PA6_PA7      1       /* Barometer */
-#define SPI_1_PB3_PB4_PB5      0
-#define SPI_1_PE13_PE14_PE15   1       /* Accelerometer, Gyro */
-#define SPI_1_OSPEEDR          STM_OSPEEDR_10MHz
-
-#define HAS_SPI_2              1
-#define SPI_2_PB13_PB14_PB15   1       /* Flash, Companion */
-#define SPI_2_PD1_PD3_PD4      0
-#define SPI_2_OSPEEDR          STM_OSPEEDR_10MHz
-
-#define SPI_2_PORT             (&stm_gpiob)
-#define SPI_2_SCK_PIN          13
-#define SPI_2_MISO_PIN         14
-#define SPI_2_MOSI_PIN         15
-
-#define HAS_I2C_1              1
-#define I2C_1_PB8_PB9          1
-
-#define HAS_I2C_2              0
-#define I2C_2_PB10_PB11                0
-
-#define PACKET_HAS_SLAVE       1
-#define PACKET_HAS_MASTER      0
-
-#define LOW_LEVEL_DEBUG                0
-
-#define LED_PORT_ENABLE                STM_RCC_AHBENR_GPIOCEN
-#define LED_PORT               (&stm_gpioc)
-#define LED_PIN_RED            8
-#define LED_PIN_GREEN          9
-#define AO_LED_RED             (1 << LED_PIN_RED)
-#define AO_LED_GREEN           (1 << LED_PIN_GREEN)
-
-#define LEDS_AVAILABLE         (AO_LED_RED | AO_LED_GREEN)
-
-#define HAS_GPS                        1
-#define HAS_FLIGHT             1
-#define HAS_ADC                        1
-#define HAS_ADC_TEMP           1
-#define HAS_LOG                        1
-
-/*
- * Igniter
- */
-
-#define HAS_IGNITE             1
-#define HAS_IGNITE_REPORT      1
-
-#define AO_SENSE_DROGUE(p)     ((p)->adc.sense[0])
-#define AO_SENSE_MAIN(p)       ((p)->adc.sense[1])
-#define AO_IGNITER_CLOSED      400
-#define AO_IGNITER_OPEN                60
-
-#define AO_IGNITER_DROGUE_PORT (&stm_gpiod)
-#define AO_IGNITER_DROGUE_PIN  6
-
-#define AO_IGNITER_MAIN_PORT   (&stm_gpiod)
-#define AO_IGNITER_MAIN_PIN    7
-
-#define AO_PYRO_PORT_0 (&stm_gpiob)
-#define AO_PYRO_PIN_0  5
-
-#define AO_PYRO_PORT_1 (&stm_gpioe)
-#define AO_PYRO_PIN_1  4
-
-#define AO_PYRO_PORT_2 (&stm_gpioe)
-#define AO_PYRO_PIN_2  6
-
-#define AO_PYRO_PORT_3 (&stm_gpioe)
-#define AO_PYRO_PIN_3  5
-
-/* Number of general purpose pyro channels available */
-#define AO_PYRO_NUM    4
-
-#define AO_IGNITER_SET_DROGUE(v)       stm_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, v)
-#define AO_IGNITER_SET_MAIN(v)         stm_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, v)
-
-/*
- * ADC
- */
-#define AO_DATA_RING           32
-#define AO_ADC_NUM_SENSE       6
-
-struct ao_adc {
-       int16_t                 sense[AO_ADC_NUM_SENSE];
-       int16_t                 v_batt;
-       int16_t                 v_pbatt;
-       int16_t                 temp;
-};
-
-#define AO_ADC_SENSE_A         0
-#define AO_ADC_SENSE_A_PORT    (&stm_gpioa)
-#define AO_ADC_SENSE_A_PIN     0
-
-#define AO_ADC_SENSE_B         1
-#define AO_ADC_SENSE_B_PORT    (&stm_gpioa)
-#define AO_ADC_SENSE_B_PIN     1
-
-#define AO_ADC_SENSE_C         2
-#define AO_ADC_SENSE_C_PORT    (&stm_gpioa)
-#define AO_ADC_SENSE_C_PIN     2
-
-#define AO_ADC_SENSE_D         3
-#define AO_ADC_SENSE_D_PORT    (&stm_gpioa)
-#define AO_ADC_SENSE_D_PIN     3
-
-#define AO_ADC_SENSE_E         4
-#define AO_ADC_SENSE_E_PORT    (&stm_gpioa)
-#define AO_ADC_SENSE_E_PIN     4
-
-#define AO_ADC_SENSE_F         22
-#define AO_ADC_SENSE_F_PORT    (&stm_gpioe)
-#define AO_ADC_SENSE_F_PIN     7
-
-#define AO_ADC_V_BATT          8
-#define AO_ADC_V_BATT_PORT     (&stm_gpiob)
-#define AO_ADC_V_BATT_PIN      0
-
-#define AO_ADC_V_PBATT         9
-#define AO_ADC_V_PBATT_PORT    (&stm_gpiob)
-#define AO_ADC_V_PBATT_PIN     1
-
-#define AO_ADC_TEMP            16
-
-#define AO_ADC_RCC_AHBENR      ((1 << STM_RCC_AHBENR_GPIOAEN) | \
-                                (1 << STM_RCC_AHBENR_GPIOEEN) | \
-                                (1 << STM_RCC_AHBENR_GPIOBEN))
-
-#define AO_NUM_ADC_PIN         (AO_ADC_NUM_SENSE + 2)
-
-#define AO_ADC_PIN0_PORT       AO_ADC_SENSE_A_PORT
-#define AO_ADC_PIN0_PIN                AO_ADC_SENSE_A_PIN
-#define AO_ADC_PIN1_PORT       AO_ADC_SENSE_B_PORT
-#define AO_ADC_PIN1_PIN                AO_ADC_SENSE_B_PIN
-#define AO_ADC_PIN2_PORT       AO_ADC_SENSE_C_PORT
-#define AO_ADC_PIN2_PIN                AO_ADC_SENSE_C_PIN
-#define AO_ADC_PIN3_PORT       AO_ADC_SENSE_D_PORT
-#define AO_ADC_PIN3_PIN                AO_ADC_SENSE_D_PIN
-#define AO_ADC_PIN4_PORT       AO_ADC_SENSE_E_PORT
-#define AO_ADC_PIN4_PIN                AO_ADC_SENSE_E_PIN
-#define AO_ADC_PIN5_PORT       AO_ADC_SENSE_F_PORT
-#define AO_ADC_PIN5_PIN                AO_ADC_SENSE_F_PIN
-#define AO_ADC_PIN6_PORT       AO_ADC_V_BATT_PORT
-#define AO_ADC_PIN6_PIN                AO_ADC_V_BATT_PIN
-#define AO_ADC_PIN7_PORT       AO_ADC_V_PBATT_PORT
-#define AO_ADC_PIN7_PIN                AO_ADC_V_PBATT_PIN
-
-#define AO_NUM_ADC             (AO_ADC_NUM_SENSE + 3)
-
-#define AO_ADC_SQ1             AO_ADC_SENSE_A
-#define AO_ADC_SQ2             AO_ADC_SENSE_B
-#define AO_ADC_SQ3             AO_ADC_SENSE_C
-#define AO_ADC_SQ4             AO_ADC_SENSE_D
-#define AO_ADC_SQ5             AO_ADC_SENSE_E
-#define AO_ADC_SQ6             AO_ADC_SENSE_F
-#define AO_ADC_SQ7             AO_ADC_V_BATT
-#define AO_ADC_SQ8             AO_ADC_V_PBATT
-#define AO_ADC_SQ9             AO_ADC_TEMP
-
-/*
- * Pressure sensor settings
- */
-#define HAS_MS5607             1
-#define HAS_MS5611             0
-#define AO_MS5607_PRIVATE_PINS 1
-#define AO_MS5607_CS_PORT      (&stm_gpioc)
-#define AO_MS5607_CS_PIN       4
-#define AO_MS5607_CS_MASK      (1 << AO_MS5607_CS)
-#define AO_MS5607_MISO_PORT    (&stm_gpioa)
-#define AO_MS5607_MISO_PIN     6
-#define AO_MS5607_MISO_MASK    (1 << AO_MS5607_MISO)
-#define AO_MS5607_SPI_INDEX    AO_SPI_1_PA5_PA6_PA7
-
-/*
- * SPI Flash memory
- */
-
-#define M25_MAX_CHIPS          1
-#define AO_M25_SPI_CS_PORT     (&stm_gpiod)
-#define AO_M25_SPI_CS_MASK     (1 << 3)
-#define AO_M25_SPI_BUS         AO_SPI_2_PB13_PB14_PB15
-
-/*
- * Radio (cc1120)
- */
-
-/* gets pretty close to 434.550 */
-
-#define AO_RADIO_CAL_DEFAULT   0x6ca333
-
-#define AO_FEC_DEBUG           0
-#define AO_CC1120_SPI_CS_PORT  (&stm_gpioc)
-#define AO_CC1120_SPI_CS_PIN   5
-#define AO_CC1120_SPI_BUS      AO_SPI_2_PB13_PB14_PB15
-#define AO_CC1120_SPI          stm_spi2
-
-#define AO_CC1120_INT_PORT             (&stm_gpioe)
-#define AO_CC1120_INT_PIN              1
-#define AO_CC1120_MCU_WAKEUP_PORT      (&stm_gpioc)
-#define AO_CC1120_MCU_WAKEUP_PIN       (0)
-
-#define AO_CC1120_INT_GPIO     2
-#define AO_CC1120_INT_GPIO_IOCFG       CC1120_IOCFG2
-
-#define AO_CC1120_MARC_GPIO    3
-#define AO_CC1120_MARC_GPIO_IOCFG      CC1120_IOCFG3
-
-#define HAS_BOOT_RADIO         0
-
-/*
- * Mag sensor (hmc5883)
- */
-
-#define HAS_HMC5883            1
-#define AO_HMC5883_INT_PORT    (&stm_gpioc)
-#define AO_HMC5883_INT_PIN     12
-#define AO_HMC5883_I2C_INDEX   STM_I2C_INDEX(1)
-
-/*
- * mpu6000
- */
-
-#define HAS_MPU6000            1       
-#define AO_MPU6000_INT_PORT    (&stm_gpioe)
-#define AO_MPU6000_INT_PIN     0
-#define AO_MPU6000_SPI_BUS     AO_SPI_1_PE13_PE14_PE15
-#define AO_MPU6000_SPI_CS_PORT (&stm_gpiod)
-#define AO_MPU6000_SPI_CS_PIN  2
-
-#define HAS_HIGHG_ACCEL                1
-
-/*
- * mma655x
- */
-
-#define HAS_MMA655X            1
-#define AO_MMA655X_SPI_INDEX   AO_SPI_1_PE13_PE14_PE15
-#define AO_MMA655X_CS_PORT     (&stm_gpiod)
-#define AO_MMA655X_CS_PIN      4
-
-#define NUM_CMDS               16
-
-/*
- * Companion
- */
-
-#define AO_COMPANION_CS_PORT   (&stm_gpiod)
-#define AO_COMPANION_CS_PIN    (0)
-#define AO_COMPANION_SPI_BUS   AO_SPI_2_PB13_PB14_PB15
-
-/*
- * Monitor
- */
-
-#define HAS_MONITOR            0
-#define LEGACY_MONITOR         0
-#define HAS_MONITOR_PUT                1
-#define AO_MONITOR_LED         0
-#define HAS_RSSI               0
-
-/*
- * Profiling Viterbi decoding
- */
-
-#ifndef AO_PROFILE
-#define AO_PROFILE             0
-#endif
-
-#endif /* _AO_PINS_H_ */
diff --git a/src/telemega-v0.3/ao_telemega.c b/src/telemega-v0.3/ao_telemega.c
deleted file mode 100644 (file)
index fbdab64..0000000
+++ /dev/null
@@ -1,100 +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; 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_hmc5883.h>
-#include <ao_mpu6000.h>
-#include <ao_mma655x.h>
-#include <ao_log.h>
-#include <ao_exti.h>
-#include <ao_packet.h>
-#include <ao_companion.h>
-#include <ao_profile.h>
-#if HAS_SAMPLE_PROFILE
-#include <ao_sample_profile.h>
-#endif
-#include <ao_pyro.h>
-#if HAS_STACK_GUARD
-#include <ao_mpu.h>
-#endif
-
-int
-main(void)
-{
-       ao_clock_init();
-       
-#if HAS_STACK_GUARD
-       ao_mpu_init();
-#endif
-
-       ao_task_init();
-       ao_serial_init();
-       ao_led_init(LEDS_AVAILABLE);
-       ao_led_on(AO_LED_GREEN);
-       ao_timer_init();
-
-       ao_i2c_init();
-       ao_spi_init();
-       ao_dma_init();
-       ao_exti_init();
-
-       ao_adc_init();
-#if HAS_BEEP
-       ao_beep_init();
-#endif
-       ao_cmd_init();
-
-#if HAS_MS5607
-       ao_ms5607_init();
-#endif
-#if HAS_HMC5883
-       ao_hmc5883_init();
-#endif
-#if HAS_MPU6000
-       ao_mpu6000_init();
-#endif
-#if HAS_MMA655X
-       ao_mma655x_init();
-#endif
-
-       ao_storage_init();
-       
-       ao_flight_init();
-       ao_log_init();
-       ao_report_init();
-
-       ao_usb_init();
-       ao_gps_init();
-       ao_gps_report_mega_init();
-       ao_telemetry_init();
-       ao_radio_init();
-       ao_packet_slave_init(FALSE);
-       ao_igniter_init();
-       ao_companion_init();
-       ao_pyro_init();
-
-       ao_config_init();
-#if AO_PROFILE
-       ao_profile_init();
-#endif
-#if HAS_SAMPLE_PROFILE
-       ao_sample_profile_init();
-#endif
-       
-       ao_start_scheduler();
-       return 0;
-}
diff --git a/src/telemega-v0.3/flash-loader/Makefile b/src/telemega-v0.3/flash-loader/Makefile
deleted file mode 100644 (file)
index 8fda18c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# AltOS flash loader build
-#
-#
-
-TOPDIR=../..
-HARDWARE=telemega-v0.3
-include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/telemega-v0.3/flash-loader/ao_pins.h b/src/telemega-v0.3/flash-loader/ao_pins.h
deleted file mode 100644 (file)
index 1af92f1..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _AO_PINS_H_
-#define _AO_PINS_H_
-
-/* External crystal at 8MHz */
-#define AO_HSE         8000000
-
-#include <ao_flash_stm_pins.h>
-
-/* Companion port cs_companion0 PD0 */
-
-#define AO_BOOT_PIN            1
-#define AO_BOOT_APPLICATION_GPIO       stm_gpiod
-#define AO_BOOT_APPLICATION_PIN                0
-#define AO_BOOT_APPLICATION_VALUE      1
-#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
-
-#endif /* _AO_PINS_H_ */
diff --git a/src/telemega-v1.0/.gitignore b/src/telemega-v1.0/.gitignore
new file mode 100644 (file)
index 0000000..e67759a
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+telemega-*.elf
diff --git a/src/telemega-v1.0/Makefile b/src/telemega-v1.0/Makefile
new file mode 100644 (file)
index 0000000..543f7e7
--- /dev/null
@@ -0,0 +1,153 @@
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_companion.h \
+       ao_data.h \
+       ao_sample.h \
+       ao_pins.h \
+       altitude-pa.h \
+       ao_kalman.h \
+       ao_product.h \
+       ao_ms5607.h \
+       ao_hmc5883.h \
+       ao_mpu6000.h \
+       ao_mma655x.h \
+       ao_cc1120_CC1120.h \
+       ao_profile.h \
+       ao_task.h \
+       ao_whiten.h \
+       ao_sample_profile.h \
+       ao_quaternion.h \
+       math.h \
+       ao_mpu.h \
+       stm32l.h \
+       math.h \
+       Makefile
+
+#
+# Common AltOS sources
+#
+#      ao_hmc5883.c
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+#SAMPLE_PROFILE=ao_sample_profile.c \
+#      ao_sample_profile_timer.c
+#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1
+
+#STACK_GUARD=ao_mpu_stm.c
+#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
+
+MATH_SRC=\
+       ef_acos.c \
+       ef_sqrt.c \
+       ef_rem_pio2.c \
+       kf_cos.c \
+       kf_sin.c \
+       kf_rem_pio2.c \
+       sf_copysign.c \
+       sf_cos.c \
+       sf_fabs.c \
+       sf_floor.c \
+       sf_scalbn.c \
+       sf_sin.c
+
+ALTOS_SRC = \
+       ao_boot_chain.c \
+       ao_interrupt.c \
+       ao_product.c \
+       ao_romconfig.c \
+       ao_cmd.c \
+       ao_config.c \
+       ao_task.c \
+       ao_led.c \
+       ao_stdio.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_mutex.c \
+       ao_serial_stm.c \
+       ao_gps_ublox.c \
+       ao_gps_show.c \
+       ao_gps_report_mega.c \
+       ao_ignite.c \
+       ao_freq.c \
+       ao_dma_stm.c \
+       ao_spi_stm.c \
+       ao_cc1120.c \
+       ao_fec_tx.c \
+       ao_fec_rx.c \
+       ao_data.c \
+       ao_ms5607.c \
+       ao_mma655x.c \
+       ao_hmc5883.c \
+       ao_adc_stm.c \
+       ao_beep_stm.c \
+       ao_eeprom_stm.c \
+       ao_storage.c \
+       ao_m25.c \
+       ao_usb_stm.c \
+       ao_exti_stm.c \
+       ao_report.c \
+       ao_i2c_stm.c \
+       ao_mpu6000.c \
+       ao_convert_pa.c \
+       ao_log.c \
+       ao_log_mega.c \
+       ao_sample.c \
+       ao_kalman.c \
+       ao_flight.c \
+       ao_telemetry.c \
+       ao_packet_slave.c \
+       ao_packet.c \
+       ao_companion.c \
+       ao_pyro.c \
+       ao_aprs.c \
+       $(MATH_SRC) \
+       $(PROFILE) \
+       $(SAMPLE_PROFILE) \
+       $(STACK_GUARD)
+
+PRODUCT=TeleMega-v1.0
+PRODUCT_DEF=-DTELEMEGA
+IDPRODUCT=0x0023
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+
+PROGNAME=telemega-v1.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_telemega.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+../altitude-pa.h: make-altitude-pa
+       nickle $< > $@
+
+$(OBJ): $(INC)
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/telemega-v1.0/ao_pins.h b/src/telemega-v1.0/ao_pins.h
new file mode 100644 (file)
index 0000000..95644da
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_TASK_QUEUE         1
+
+/* 8MHz High speed external crystal */
+#define AO_HSE                 8000000
+
+/* PLLVCO = 96MHz (so that USB will work) */
+#define AO_PLLMUL              12
+#define AO_RCC_CFGR_PLLMUL     (STM_RCC_CFGR_PLLMUL_12)
+
+/* SYSCLK = 32MHz (no need to go faster than CPU) */
+#define AO_PLLDIV              3
+#define AO_RCC_CFGR_PLLDIV     (STM_RCC_CFGR_PLLDIV_3)
+
+/* HCLK = 32MHz (CPU clock) */
+#define AO_AHB_PRESCALER       1
+#define AO_RCC_CFGR_HPRE_DIV   STM_RCC_CFGR_HPRE_DIV_1
+
+/* Run APB1 at 16MHz (HCLK/2) */
+#define AO_APB1_PRESCALER      2
+#define AO_RCC_CFGR_PPRE1_DIV  STM_RCC_CFGR_PPRE2_DIV_2
+
+/* Run APB2 at 16MHz (HCLK/2) */
+#define AO_APB2_PRESCALER      2
+#define AO_RCC_CFGR_PPRE2_DIV  STM_RCC_CFGR_PPRE2_DIV_2
+
+#define HAS_SERIAL_1           1
+#define USE_SERIAL_1_STDIN     0
+#define SERIAL_1_PB6_PB7       0
+#define SERIAL_1_PA9_PA10      1
+
+#define HAS_SERIAL_2           0
+#define USE_SERIAL_2_STDIN     0
+#define SERIAL_2_PA2_PA3       0
+#define SERIAL_2_PD5_PD6       0
+
+#define HAS_SERIAL_3           1
+#define USE_SERIAL_3_STDIN     0
+#define SERIAL_3_PB10_PB11     0
+#define SERIAL_3_PC10_PC11     1
+#define SERIAL_3_PD8_PD9       0
+
+#define ao_gps_getchar         ao_serial3_getchar
+#define ao_gps_putchar         ao_serial3_putchar
+#define ao_gps_set_speed       ao_serial3_set_speed
+#define ao_gps_fifo            (ao_stm_usart3.rx_fifo)
+
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       (1024 * 1024)
+#define HAS_EEPROM             1
+#define USE_INTERNAL_FLASH     0
+#define USE_EEPROM_CONFIG      1
+#define USE_STORAGE_CONFIG     0
+#define HAS_USB                        1
+#define HAS_BEEP               1
+#define HAS_RADIO              1
+#define HAS_TELEMETRY          1
+#define HAS_APRS               1
+
+#define HAS_SPI_1              1
+#define SPI_1_PA5_PA6_PA7      1       /* Barometer */
+#define SPI_1_PB3_PB4_PB5      0
+#define SPI_1_PE13_PE14_PE15   1       /* Accelerometer, Gyro */
+#define SPI_1_OSPEEDR          STM_OSPEEDR_10MHz
+
+#define HAS_SPI_2              1
+#define SPI_2_PB13_PB14_PB15   1       /* Flash, Companion */
+#define SPI_2_PD1_PD3_PD4      0
+#define SPI_2_OSPEEDR          STM_OSPEEDR_10MHz
+
+#define SPI_2_PORT             (&stm_gpiob)
+#define SPI_2_SCK_PIN          13
+#define SPI_2_MISO_PIN         14
+#define SPI_2_MOSI_PIN         15
+
+#define HAS_I2C_1              1
+#define I2C_1_PB8_PB9          1
+
+#define HAS_I2C_2              0
+#define I2C_2_PB10_PB11                0
+
+#define PACKET_HAS_SLAVE       1
+#define PACKET_HAS_MASTER      0
+
+#define LOW_LEVEL_DEBUG                0
+
+#define LED_PORT_ENABLE                STM_RCC_AHBENR_GPIOCEN
+#define LED_PORT               (&stm_gpioc)
+#define LED_PIN_RED            8
+#define LED_PIN_GREEN          9
+#define AO_LED_RED             (1 << LED_PIN_RED)
+#define AO_LED_GREEN           (1 << LED_PIN_GREEN)
+
+#define LEDS_AVAILABLE         (AO_LED_RED | AO_LED_GREEN)
+
+#define HAS_GPS                        1
+#define HAS_FLIGHT             1
+#define HAS_ADC                        1
+#define HAS_ADC_TEMP           1
+#define HAS_LOG                        1
+
+/*
+ * Igniter
+ */
+
+#define HAS_IGNITE             1
+#define HAS_IGNITE_REPORT      1
+
+#define AO_SENSE_PYRO(p,n)     ((p)->adc.sense[n])
+#define AO_SENSE_DROGUE(p)     ((p)->adc.sense[4])
+#define AO_SENSE_MAIN(p)       ((p)->adc.sense[5])
+#define AO_IGNITER_CLOSED      400
+#define AO_IGNITER_OPEN                60
+
+/* Pyro A */
+#define AO_PYRO_PORT_0 (&stm_gpiod)
+#define AO_PYRO_PIN_0  6
+
+/* Pyro B */
+#define AO_PYRO_PORT_1 (&stm_gpiod)
+#define AO_PYRO_PIN_1  7
+
+/* Pyro C */
+#define AO_PYRO_PORT_2 (&stm_gpiob)
+#define AO_PYRO_PIN_2  5
+
+/* Pyro D */
+#define AO_PYRO_PORT_3 (&stm_gpioe)
+#define AO_PYRO_PIN_3  4
+
+/* Drogue */
+#define AO_IGNITER_DROGUE_PORT (&stm_gpioe)
+#define AO_IGNITER_DROGUE_PIN  6
+
+/* Main */
+#define AO_IGNITER_MAIN_PORT   (&stm_gpioe)
+#define AO_IGNITER_MAIN_PIN    5
+
+/* Number of general purpose pyro channels available */
+#define AO_PYRO_NUM    4
+
+#define AO_IGNITER_SET_DROGUE(v)       stm_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, v)
+#define AO_IGNITER_SET_MAIN(v)         stm_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, v)
+
+/*
+ * ADC
+ */
+#define AO_DATA_RING           32
+#define AO_ADC_NUM_SENSE       6
+
+struct ao_adc {
+       int16_t                 sense[AO_ADC_NUM_SENSE];
+       int16_t                 v_batt;
+       int16_t                 v_pbatt;
+       int16_t                 temp;
+};
+
+#define AO_ADC_DUMP(p) \
+       printf("tick: %5u A: %5d B: %5d C: %5d D: %5d drogue: %5d main: %5d batt: %5d pbatt: %5d temp: %5d\n", \
+              (p)->tick, \
+              (p)->adc.sense[0], (p)->adc.sense[1], (p)->adc.sense[2], \
+              (p)->adc.sense[3], (p)->adc.sense[4], (p)->adc.sense[5], \
+              (p)->adc.v_batt, (p)->adc.v_pbatt, (p)->adc.temp)
+
+#define AO_ADC_SENSE_A         0
+#define AO_ADC_SENSE_A_PORT    (&stm_gpioa)
+#define AO_ADC_SENSE_A_PIN     0
+
+#define AO_ADC_SENSE_B         1
+#define AO_ADC_SENSE_B_PORT    (&stm_gpioa)
+#define AO_ADC_SENSE_B_PIN     1
+
+#define AO_ADC_SENSE_C         2
+#define AO_ADC_SENSE_C_PORT    (&stm_gpioa)
+#define AO_ADC_SENSE_C_PIN     2
+
+#define AO_ADC_SENSE_D         3
+#define AO_ADC_SENSE_D_PORT    (&stm_gpioa)
+#define AO_ADC_SENSE_D_PIN     3
+
+#define AO_ADC_SENSE_DROGUE    4
+#define AO_ADC_SENSE_DROGUE_PORT       (&stm_gpioa)
+#define AO_ADC_SENSE_DROGUE_PIN        4
+
+#define AO_ADC_SENSE_MAIN      22
+#define AO_ADC_SENSE_MAIN_PORT (&stm_gpioe)
+#define AO_ADC_SENSE_MAIN_PIN  7
+
+#define AO_ADC_V_BATT          8
+#define AO_ADC_V_BATT_PORT     (&stm_gpiob)
+#define AO_ADC_V_BATT_PIN      0
+
+#define AO_ADC_V_PBATT         9
+#define AO_ADC_V_PBATT_PORT    (&stm_gpiob)
+#define AO_ADC_V_PBATT_PIN     1
+
+#define AO_ADC_TEMP            16
+
+#define AO_ADC_RCC_AHBENR      ((1 << STM_RCC_AHBENR_GPIOAEN) | \
+                                (1 << STM_RCC_AHBENR_GPIOEEN) | \
+                                (1 << STM_RCC_AHBENR_GPIOBEN))
+
+#define AO_NUM_ADC_PIN         (AO_ADC_NUM_SENSE + 2)
+
+#define AO_ADC_PIN0_PORT       AO_ADC_SENSE_A_PORT
+#define AO_ADC_PIN0_PIN                AO_ADC_SENSE_A_PIN
+#define AO_ADC_PIN1_PORT       AO_ADC_SENSE_B_PORT
+#define AO_ADC_PIN1_PIN                AO_ADC_SENSE_B_PIN
+#define AO_ADC_PIN2_PORT       AO_ADC_SENSE_C_PORT
+#define AO_ADC_PIN2_PIN                AO_ADC_SENSE_C_PIN
+#define AO_ADC_PIN3_PORT       AO_ADC_SENSE_D_PORT
+#define AO_ADC_PIN3_PIN                AO_ADC_SENSE_D_PIN
+#define AO_ADC_PIN4_PORT       AO_ADC_SENSE_DROGUE_PORT
+#define AO_ADC_PIN4_PIN                AO_ADC_SENSE_DROGUE_PIN
+#define AO_ADC_PIN5_PORT       AO_ADC_SENSE_MAIN_PORT
+#define AO_ADC_PIN5_PIN                AO_ADC_SENSE_MAIN_PIN
+#define AO_ADC_PIN6_PORT       AO_ADC_V_BATT_PORT
+#define AO_ADC_PIN6_PIN                AO_ADC_V_BATT_PIN
+#define AO_ADC_PIN7_PORT       AO_ADC_V_PBATT_PORT
+#define AO_ADC_PIN7_PIN                AO_ADC_V_PBATT_PIN
+
+#define AO_NUM_ADC             (AO_ADC_NUM_SENSE + 3)
+
+#define AO_ADC_SQ1             AO_ADC_SENSE_A
+#define AO_ADC_SQ2             AO_ADC_SENSE_B
+#define AO_ADC_SQ3             AO_ADC_SENSE_C
+#define AO_ADC_SQ4             AO_ADC_SENSE_D
+#define AO_ADC_SQ5             AO_ADC_SENSE_DROGUE
+#define AO_ADC_SQ6             AO_ADC_SENSE_MAIN
+#define AO_ADC_SQ7             AO_ADC_V_BATT
+#define AO_ADC_SQ8             AO_ADC_V_PBATT
+#define AO_ADC_SQ9             AO_ADC_TEMP
+
+/*
+ * Pressure sensor settings
+ */
+#define HAS_MS5607             1
+#define HAS_MS5611             0
+#define AO_MS5607_PRIVATE_PINS 1
+#define AO_MS5607_CS_PORT      (&stm_gpioc)
+#define AO_MS5607_CS_PIN       4
+#define AO_MS5607_CS_MASK      (1 << AO_MS5607_CS)
+#define AO_MS5607_MISO_PORT    (&stm_gpioa)
+#define AO_MS5607_MISO_PIN     6
+#define AO_MS5607_MISO_MASK    (1 << AO_MS5607_MISO)
+#define AO_MS5607_SPI_INDEX    AO_SPI_1_PA5_PA6_PA7
+
+/*
+ * SPI Flash memory
+ */
+
+#define M25_MAX_CHIPS          1
+#define AO_M25_SPI_CS_PORT     (&stm_gpiod)
+#define AO_M25_SPI_CS_MASK     (1 << 3)
+#define AO_M25_SPI_BUS         AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Radio (cc1120)
+ */
+
+/* gets pretty close to 434.550 */
+
+#define AO_RADIO_CAL_DEFAULT   0x6ca333
+
+#define AO_FEC_DEBUG           0
+#define AO_CC1120_SPI_CS_PORT  (&stm_gpioc)
+#define AO_CC1120_SPI_CS_PIN   5
+#define AO_CC1120_SPI_BUS      AO_SPI_2_PB13_PB14_PB15
+#define AO_CC1120_SPI          stm_spi2
+
+#define AO_CC1120_INT_PORT             (&stm_gpioe)
+#define AO_CC1120_INT_PIN              1
+#define AO_CC1120_MCU_WAKEUP_PORT      (&stm_gpioc)
+#define AO_CC1120_MCU_WAKEUP_PIN       (0)
+
+#define AO_CC1120_INT_GPIO     2
+#define AO_CC1120_INT_GPIO_IOCFG       CC1120_IOCFG2
+
+#define AO_CC1120_MARC_GPIO    3
+#define AO_CC1120_MARC_GPIO_IOCFG      CC1120_IOCFG3
+
+#define HAS_BOOT_RADIO         0
+
+/*
+ * Mag sensor (hmc5883)
+ */
+
+#define HAS_HMC5883            1
+#define AO_HMC5883_INT_PORT    (&stm_gpioc)
+#define AO_HMC5883_INT_PIN     12
+#define AO_HMC5883_I2C_INDEX   STM_I2C_INDEX(1)
+
+/*
+ * mpu6000
+ */
+
+#define HAS_MPU6000            1
+#define AO_MPU6000_INT_PORT    (&stm_gpioe)
+#define AO_MPU6000_INT_PIN     0
+#define AO_MPU6000_SPI_BUS     AO_SPI_1_PE13_PE14_PE15
+#define AO_MPU6000_SPI_CS_PORT (&stm_gpiod)
+#define AO_MPU6000_SPI_CS_PIN  2
+#define HAS_IMU                        1
+
+/*
+ * mma655x
+ */
+
+#define HAS_MMA655X            1
+#define AO_MMA655X_SPI_INDEX   AO_SPI_1_PE13_PE14_PE15
+#define AO_MMA655X_CS_PORT     (&stm_gpiod)
+#define AO_MMA655X_CS_PIN      4
+
+#define NUM_CMDS               16
+
+/*
+ * Companion
+ */
+
+#define AO_COMPANION_CS_PORT   (&stm_gpiod)
+#define AO_COMPANION_CS_PIN    (0)
+#define AO_COMPANION_SPI_BUS   AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Monitor
+ */
+
+#define HAS_MONITOR            0
+#define LEGACY_MONITOR         0
+#define HAS_MONITOR_PUT                1
+#define AO_MONITOR_LED         0
+#define HAS_RSSI               0
+
+/*
+ * Profiling Viterbi decoding
+ */
+
+#ifndef AO_PROFILE
+#define AO_PROFILE             0
+#endif
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/telemega-v1.0/ao_telemega.c b/src/telemega-v1.0/ao_telemega.c
new file mode 100644 (file)
index 0000000..7b03526
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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_hmc5883.h>
+#include <ao_mpu6000.h>
+#include <ao_mma655x.h>
+#include <ao_log.h>
+#include <ao_exti.h>
+#include <ao_packet.h>
+#include <ao_companion.h>
+#include <ao_profile.h>
+#include <ao_eeprom.h>
+#if HAS_SAMPLE_PROFILE
+#include <ao_sample_profile.h>
+#endif
+#include <ao_pyro.h>
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
+
+int
+main(void)
+{
+       ao_clock_init();
+       
+#if HAS_STACK_GUARD
+       ao_mpu_init();
+#endif
+
+       ao_task_init();
+       ao_serial_init();
+       ao_led_init(LEDS_AVAILABLE);
+       ao_led_on(AO_LED_GREEN);
+       ao_timer_init();
+
+       ao_i2c_init();
+       ao_spi_init();
+       ao_dma_init();
+       ao_exti_init();
+
+       ao_adc_init();
+#if HAS_BEEP
+       ao_beep_init();
+#endif
+       ao_cmd_init();
+
+#if HAS_MS5607
+       ao_ms5607_init();
+#endif
+#if HAS_HMC5883
+       ao_hmc5883_init();
+#endif
+#if HAS_MPU6000
+       ao_mpu6000_init();
+#endif
+#if HAS_MMA655X
+       ao_mma655x_init();
+#endif
+
+       ao_eeprom_init();
+       ao_storage_init();
+       
+       ao_flight_init();
+       ao_log_init();
+       ao_report_init();
+
+       ao_usb_init();
+       ao_gps_init();
+       ao_gps_report_mega_init();
+       ao_telemetry_init();
+       ao_radio_init();
+       ao_packet_slave_init(FALSE);
+       ao_igniter_init();
+       ao_companion_init();
+       ao_pyro_init();
+
+       ao_config_init();
+#if AO_PROFILE
+       ao_profile_init();
+#endif
+#if HAS_SAMPLE_PROFILE
+       ao_sample_profile_init();
+#endif
+       
+       ao_start_scheduler();
+       return 0;
+}
diff --git a/src/telemega-v1.0/flash-loader/Makefile b/src/telemega-v1.0/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..a11f800
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telemega-v1.0
+include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/telemega-v1.0/flash-loader/ao_pins.h b/src/telemega-v1.0/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..1af92f1
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 8MHz */
+#define AO_HSE         8000000
+
+#include <ao_flash_stm_pins.h>
+
+/* Companion port cs_companion0 PD0 */
+
+#define AO_BOOT_PIN            1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpiod
+#define AO_BOOT_APPLICATION_PIN                0
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
index 69cd3461faf8dbcd282836ff386f35c0bf2dcdaa..a6634c2957cca259f44990d1b2382f75a82c1677 100644 (file)
@@ -11,6 +11,7 @@ TM_INC = \
 
 TM_SRC = \
        ao_gps_skytraq.c \
+       ao_gps_show.c \
        ao_25lc1024.c
 
 include ../product/Makefile.telemetrum
index 4aae84c8e0749ce901197d4f17894072c63957fd..476a3b0aef64abe369fb740dca84f45d9eca02d3 100644 (file)
@@ -11,6 +11,7 @@ TM_INC = \
 TM_SRC = \
        ao_companion.c \
        ao_gps_skytraq.c \
+       ao_gps_show.c \
        ao_at45db161d.c
 
 include ../product/Makefile.telemetrum
index 4bea03db3243ce92396623081ba65f74f1798b2c..e44be7f9ae5c9bfde8b180a857a28fd42ecaabf4 100644 (file)
@@ -11,6 +11,7 @@ TM_INC =
 TM_SRC = \
        ao_companion.c \
        ao_gps_skytraq.c \
+       ao_gps_show.c \
        ao_m25.c
 
 include ../product/Makefile.telemetrum
index 4b650adf1fbd29539dd8b6dd79381d85bd6e956c..f2285fbed52b0c3c5f21f39fd9e13133715dd3da 100644 (file)
@@ -11,6 +11,7 @@ TM_INC =
 TM_SRC = \
        ao_companion.c \
        ao_gps_skytraq.c \
+       ao_gps_show.c \
        ao_m25.c
 
 include ../product/Makefile.telemetrum
diff --git a/src/telemetrum-v2.0/.gitignore b/src/telemetrum-v2.0/.gitignore
new file mode 100644 (file)
index 0000000..35ce24d
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+telemetrum-*.elf
diff --git a/src/telemetrum-v2.0/Makefile b/src/telemetrum-v2.0/Makefile
new file mode 100644 (file)
index 0000000..cebc9ca
--- /dev/null
@@ -0,0 +1,124 @@
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_companion.h \
+       ao_data.h \
+       ao_sample.h \
+       ao_pins.h \
+       altitude-pa.h \
+       ao_kalman.h \
+       ao_product.h \
+       ao_ms5607.h \
+       ao_mma655x.h \
+       ao_cc1120_CC1120.h \
+       ao_profile.h \
+       ao_task.h \
+       ao_whiten.h \
+       ao_sample_profile.h \
+       ao_mpu.h \
+       stm32l.h \
+       Makefile
+
+#PROFILE=ao_profile.c
+#PROFILE_DEF=-DAO_PROFILE=1
+
+#SAMPLE_PROFILE=ao_sample_profile.c \
+#      ao_sample_profile_timer.c
+#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1
+
+#STACK_GUARD=ao_mpu_stm.c
+#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1
+
+ALTOS_SRC = \
+       ao_boot_chain.c \
+       ao_interrupt.c \
+       ao_product.c \
+       ao_romconfig.c \
+       ao_cmd.c \
+       ao_config.c \
+       ao_task.c \
+       ao_led.c \
+       ao_stdio.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_mutex.c \
+       ao_serial_stm.c \
+       ao_gps_ublox.c \
+       ao_gps_show.c \
+       ao_gps_report_metrum.c \
+       ao_ignite.c \
+       ao_freq.c \
+       ao_dma_stm.c \
+       ao_spi_stm.c \
+       ao_cc1120.c \
+       ao_fec_tx.c \
+       ao_fec_rx.c \
+       ao_data.c \
+       ao_ms5607.c \
+       ao_mma655x.c \
+       ao_adc_stm.c \
+       ao_beep_stm.c \
+       ao_storage.c \
+       ao_m25.c \
+       ao_usb_stm.c \
+       ao_exti_stm.c \
+       ao_eeprom_stm.c \
+       ao_report.c \
+       ao_convert_pa.c \
+       ao_log.c \
+       ao_log_metrum.c \
+       ao_sample.c \
+       ao_kalman.c \
+       ao_flight.c \
+       ao_telemetry.c \
+       ao_packet_slave.c \
+       ao_packet.c \
+       ao_companion.c \
+       ao_aprs.c \
+       $(PROFILE) \
+       $(SAMPLE_PROFILE) \
+       $(STACK_GUARD)
+
+PRODUCT=TeleMetrum-v2.0
+PRODUCT_DEF=-DTELEMETRUM_V_2_0
+IDPRODUCT=0x000b
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+
+PROGNAME=telemetrum-v2.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_telemetrum.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+../altitude-pa.h: make-altitude-pa
+       nickle $< > $@
+
+$(OBJ): $(INC)
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/telemetrum-v2.0/ao_pins.h b/src/telemetrum-v2.0/ao_pins.h
new file mode 100644 (file)
index 0000000..02f0f5e
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_TASK_QUEUE         1
+
+/* 8MHz High speed external crystal */
+#define AO_HSE                 8000000
+
+/* PLLVCO = 96MHz (so that USB will work) */
+#define AO_PLLMUL              12
+#define AO_RCC_CFGR_PLLMUL     (STM_RCC_CFGR_PLLMUL_12)
+
+/* SYSCLK = 32MHz (no need to go faster than CPU) */
+#define AO_PLLDIV              3
+#define AO_RCC_CFGR_PLLDIV     (STM_RCC_CFGR_PLLDIV_3)
+
+/* HCLK = 32MHz (CPU clock) */
+#define AO_AHB_PRESCALER       1
+#define AO_RCC_CFGR_HPRE_DIV   STM_RCC_CFGR_HPRE_DIV_1
+
+/* Run APB1 at 16MHz (HCLK/2) */
+#define AO_APB1_PRESCALER      2
+#define AO_RCC_CFGR_PPRE1_DIV  STM_RCC_CFGR_PPRE2_DIV_2
+
+/* Run APB2 at 16MHz (HCLK/2) */
+#define AO_APB2_PRESCALER      2
+#define AO_RCC_CFGR_PPRE2_DIV  STM_RCC_CFGR_PPRE2_DIV_2
+
+#define HAS_SERIAL_1           0
+#define USE_SERIAL_1_STDIN     0
+#define SERIAL_1_PB6_PB7       0
+#define SERIAL_1_PA9_PA10      1
+
+#define HAS_SERIAL_2           0
+#define USE_SERIAL_2_STDIN     0
+#define SERIAL_2_PA2_PA3       0
+#define SERIAL_2_PD5_PD6       0
+
+#define HAS_SERIAL_3           1
+#define USE_SERIAL_3_STDIN     0
+#define SERIAL_3_PB10_PB11     1
+#define SERIAL_3_PC10_PC11     0
+#define SERIAL_3_PD8_PD9       0
+
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       (512 * 1024)
+#define HAS_EEPROM             1
+#define USE_INTERNAL_FLASH     0
+#define USE_EEPROM_CONFIG      1
+#define USE_STORAGE_CONFIG     0
+#define HAS_USB                        1
+#define HAS_BEEP               1
+#define BEEPER_CHANNEL         4
+#define HAS_RADIO              1
+#define HAS_TELEMETRY          1
+#define HAS_APRS               1
+
+#define HAS_SPI_1              1
+#define SPI_1_PA5_PA6_PA7      1       /* Barometer */
+#define SPI_1_PB3_PB4_PB5      1       /* Accelerometer */
+#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   1       /* Flash, Companion, Radio */
+#define SPI_2_PD1_PD3_PD4      0
+#define SPI_2_OSPEEDR          STM_OSPEEDR_10MHz
+
+#define SPI_2_PORT             (&stm_gpiob)
+#define SPI_2_SCK_PIN          13
+#define SPI_2_MISO_PIN         14
+#define SPI_2_MOSI_PIN         15
+
+#define HAS_I2C_1              0
+#define I2C_1_PB8_PB9          0
+
+#define HAS_I2C_2              0
+#define I2C_2_PB10_PB11                0
+
+#define PACKET_HAS_SLAVE       1
+#define PACKET_HAS_MASTER      0
+
+#define LOW_LEVEL_DEBUG                0
+
+#define LED_PORT_ENABLE                STM_RCC_AHBENR_GPIOCEN
+#define LED_PORT               (&stm_gpioc)
+#define LED_PIN_RED            14
+#define LED_PIN_GREEN          15
+#define AO_LED_RED             (1 << LED_PIN_RED)
+#define AO_LED_GREEN           (1 << LED_PIN_GREEN)
+
+#define LEDS_AVAILABLE         (AO_LED_RED | AO_LED_GREEN)
+
+#define HAS_GPS                        1
+#define HAS_FLIGHT             1
+#define HAS_ADC                        1
+#define HAS_ADC_TEMP           1
+#define HAS_LOG                        1
+
+/*
+ * Igniter
+ */
+
+#define HAS_IGNITE             1
+#define HAS_IGNITE_REPORT      1
+
+#define AO_SENSE_DROGUE(p)     ((p)->adc.sense_a)
+#define AO_SENSE_MAIN(p)       ((p)->adc.sense_m)
+#define AO_IGNITER_CLOSED      400
+#define AO_IGNITER_OPEN                60
+
+/* Drogue */
+#define AO_IGNITER_DROGUE_PORT (&stm_gpioa)
+#define AO_IGNITER_DROGUE_PIN  8
+
+/* Main */
+#define AO_IGNITER_MAIN_PORT   (&stm_gpioa)
+#define AO_IGNITER_MAIN_PIN    9
+
+#define AO_IGNITER_SET_DROGUE(v)       stm_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, v)
+#define AO_IGNITER_SET_MAIN(v)         stm_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, v)
+
+/*
+ * ADC
+ */
+#define AO_DATA_RING           32
+#define AO_ADC_NUM_SENSE       2
+
+struct ao_adc {
+       int16_t                 sense_a;
+       int16_t                 sense_m;
+       int16_t                 v_batt;
+       int16_t                 temp;
+};
+
+#define AO_ADC_DUMP(p) \
+       printf("tick: %5u drogue: %5d main: %5d batt: %5d\n", \
+              (p)->tick, \
+              (p)->adc.sense_a, (p)->adc.sense_m, \
+              (p)->adc.v_batt);
+
+#define AO_ADC_SENSE_DROGUE    0
+#define AO_ADC_SENSE_DROGUE_PORT       (&stm_gpioa)
+#define AO_ADC_SENSE_DROGUE_PIN        0
+
+#define AO_ADC_SENSE_MAIN      1
+#define AO_ADC_SENSE_MAIN_PORT (&stm_gpioa)
+#define AO_ADC_SENSE_MAIN_PIN  1
+
+#define AO_ADC_V_BATT          8
+#define AO_ADC_V_BATT_PORT     (&stm_gpiob)
+#define AO_ADC_V_BATT_PIN      0
+
+#define AO_ADC_TEMP            16
+
+#define AO_ADC_RCC_AHBENR      ((1 << STM_RCC_AHBENR_GPIOAEN) | \
+                                (1 << STM_RCC_AHBENR_GPIOEEN) | \
+                                (1 << STM_RCC_AHBENR_GPIOBEN))
+
+#define AO_NUM_ADC_PIN         3
+
+#define AO_ADC_PIN0_PORT       AO_ADC_SENSE_DROGUE_PORT
+#define AO_ADC_PIN0_PIN                AO_ADC_SENSE_DROGUE_PIN
+#define AO_ADC_PIN1_PORT       AO_ADC_SENSE_MAIN_PORT
+#define AO_ADC_PIN1_PIN                AO_ADC_SENSE_MAIN_PIN
+#define AO_ADC_PIN2_PORT       AO_ADC_V_BATT_PORT
+#define AO_ADC_PIN2_PIN                AO_ADC_V_BATT_PIN
+
+#define AO_NUM_ADC             (AO_NUM_ADC_PIN + 1)
+
+#define AO_ADC_SQ1             AO_ADC_SENSE_DROGUE
+#define AO_ADC_SQ2             AO_ADC_SENSE_MAIN
+#define AO_ADC_SQ3             AO_ADC_V_BATT
+#define AO_ADC_SQ4             AO_ADC_TEMP
+
+/*
+ * GPS
+ */
+
+#define AO_SERIAL_SPEED_UBLOX  AO_SERIAL_SPEED_9600
+
+#define ao_gps_getchar         ao_serial3_getchar
+#define ao_gps_putchar         ao_serial3_putchar
+#define ao_gps_set_speed       ao_serial3_set_speed
+#define ao_gps_fifo            (ao_stm_usart3.rx_fifo)
+
+/*
+ * Pressure sensor settings
+ */
+#define HAS_MS5607             1
+#define HAS_MS5611             0
+#define AO_MS5607_PRIVATE_PINS 1
+#define AO_MS5607_CS_PORT      (&stm_gpiob)
+#define AO_MS5607_CS_PIN       12
+#define AO_MS5607_CS_MASK      (1 << AO_MS5607_CS)
+#define AO_MS5607_MISO_PORT    (&stm_gpioa)
+#define AO_MS5607_MISO_PIN     6
+#define AO_MS5607_MISO_MASK    (1 << AO_MS5607_MISO)
+#define AO_MS5607_SPI_INDEX    AO_SPI_1_PA5_PA6_PA7
+
+/*
+ * SPI Flash memory
+ */
+
+#define M25_MAX_CHIPS          1
+#define AO_M25_SPI_CS_PORT     (&stm_gpiob)
+#define AO_M25_SPI_CS_MASK     (1 << 8)
+#define AO_M25_SPI_BUS         AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Radio (cc1120)
+ */
+
+/* gets pretty close to 434.550 */
+
+#define AO_RADIO_CAL_DEFAULT   0x6ca333
+
+#define AO_FEC_DEBUG           0
+#define AO_CC1120_SPI_CS_PORT  (&stm_gpioa)
+#define AO_CC1120_SPI_CS_PIN   2
+#define AO_CC1120_SPI_BUS      AO_SPI_2_PB13_PB14_PB15
+#define AO_CC1120_SPI          stm_spi2
+
+#define AO_CC1120_INT_PORT             (&stm_gpioa)
+#define AO_CC1120_INT_PIN              (3)
+#define AO_CC1120_MCU_WAKEUP_PORT      (&stm_gpioa)
+#define AO_CC1120_MCU_WAKEUP_PIN       (4)
+
+#define AO_CC1120_INT_GPIO     2
+#define AO_CC1120_INT_GPIO_IOCFG       CC1120_IOCFG2
+
+#define AO_CC1120_MARC_GPIO    3
+#define AO_CC1120_MARC_GPIO_IOCFG      CC1120_IOCFG3
+
+#define HAS_BOOT_RADIO         0
+
+#define HAS_HIGHG_ACCEL                1
+
+/*
+ * mma655x
+ */
+
+#define HAS_MMA655X            1
+#define AO_MMA655X_SPI_INDEX   AO_SPI_1_PB3_PB4_PB5
+#define AO_MMA655X_CS_PORT     (&stm_gpiob)
+#define AO_MMA655X_CS_PIN      9
+#define AO_MMA655X_INVERT      1
+
+#define NUM_CMDS               16
+
+/*
+ * Companion
+ */
+
+#define AO_COMPANION_CS_PORT   (&stm_gpiob)
+#define AO_COMPANION_CS_PIN    (6)
+#define AO_COMPANION_SPI_BUS   AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Monitor
+ */
+
+#define HAS_MONITOR            0
+#define LEGACY_MONITOR         0
+#define HAS_MONITOR_PUT                1
+#define AO_MONITOR_LED         0
+#define HAS_RSSI               0
+
+/*
+ * Profiling Viterbi decoding
+ */
+
+#ifndef AO_PROFILE
+#define AO_PROFILE             0
+#endif
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/telemetrum-v2.0/ao_telemetrum.c b/src/telemetrum-v2.0/ao_telemetrum.c
new file mode 100644 (file)
index 0000000..46599cb
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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_ms5607.h>
+#include <ao_mma655x.h>
+#include <ao_log.h>
+#include <ao_exti.h>
+#include <ao_packet.h>
+#include <ao_companion.h>
+#include <ao_eeprom.h>
+#include <ao_profile.h>
+#if HAS_SAMPLE_PROFILE
+#include <ao_sample_profile.h>
+#endif
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
+
+int
+main(void)
+{
+       ao_clock_init();
+       
+#if HAS_STACK_GUARD
+       ao_mpu_init();
+#endif
+
+       ao_task_init();
+       ao_serial_init();
+       ao_led_init(LEDS_AVAILABLE);
+       ao_led_on(AO_LED_RED);
+       ao_timer_init();
+
+       ao_spi_init();
+       ao_dma_init();
+       ao_exti_init();
+
+       ao_adc_init();
+#if HAS_BEEP
+       ao_beep_init();
+#endif
+       ao_cmd_init();
+
+#if HAS_MS5607
+       ao_ms5607_init();
+#endif
+#if HAS_MMA655X
+       ao_mma655x_init();
+#endif
+
+       ao_eeprom_init();
+
+       ao_storage_init();
+       
+       ao_flight_init();
+       ao_log_init();
+       ao_report_init();
+
+       ao_usb_init();
+       ao_gps_init();
+       ao_gps_report_metrum_init();
+       ao_telemetry_init();
+       ao_radio_init();
+       ao_packet_slave_init(FALSE);
+       ao_igniter_init();
+       ao_companion_init();
+
+       ao_config_init();
+#if AO_PROFILE
+       ao_profile_init();
+#endif
+#if HAS_SAMPLE_PROFILE
+       ao_sample_profile_init();
+#endif
+       
+       ao_start_scheduler();
+       return 0;
+}
diff --git a/src/telemetrum-v2.0/flash-loader/Makefile b/src/telemetrum-v2.0/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..cb99c51
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telemetrum-v2.0
+include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/telemetrum-v2.0/flash-loader/ao_pins.h b/src/telemetrum-v2.0/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..304bb7c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 8MHz */
+#define AO_HSE         8000000
+
+#include <ao_flash_stm_pins.h>
+
+/* Companion port cs_companion0 PB6 */
+
+#define AO_BOOT_PIN                    1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpiob
+#define AO_BOOT_APPLICATION_PIN                6
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/telemini-v2.0/.gitignore b/src/telemini-v2.0/.gitignore
new file mode 100644 (file)
index 0000000..568925a
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+telemini-v2.0*
diff --git a/src/telemini-v2.0/.sdcdbrc b/src/telemini-v2.0/.sdcdbrc
new file mode 100644 (file)
index 0000000..b9f6129
--- /dev/null
@@ -0,0 +1,2 @@
+--directory=../cc1111:../product:../core:../drivers:.
+
diff --git a/src/telemini-v2.0/Makefile b/src/telemini-v2.0/Makefile
new file mode 100644 (file)
index 0000000..fcac2c4
--- /dev/null
@@ -0,0 +1,115 @@
+#
+# TeleMini build file
+#
+
+TELEMINI_VER=2.0
+TELEMINI_DEF=2_0
+
+vpath %.c ..:../core:../cc1111:../drivers:../product
+vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath ao-make-product.5c ../util
+
+ifndef VERSION
+include ../Version
+endif
+
+INC = \
+       ao.h \
+       ao_pins.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       cc1111.h \
+       ao_ms5607.h \
+       ao_ms5607_convert_8051.c \
+       ao_product.h \
+       ao_int64.h \
+       ao_sample.h \
+       ao_exti.h \
+       ao_task.h
+
+CORE_SRC = \
+       ao_cmd.c \
+       ao_config.c \
+       ao_convert.c \
+       ao_flight.c \
+       ao_kalman.c \
+       ao_log.c \
+       ao_log_mini.c \
+       ao_mutex.c \
+       ao_panic.c \
+       ao_report.c \
+       ao_sample.c \
+       ao_stdio.c \
+       ao_storage.c \
+       ao_task.c \
+       ao_telemetry.c \
+       ao_freq.c \
+       ao_int64.c
+
+CC1111_SRC = \
+       ao_adc.c \
+       ao_dma.c \
+       ao_ignite.c \
+       ao_led.c \
+       ao_packet.c \
+       ao_packet_slave.c \
+       ao_radio.c \
+       ao_romconfig.c \
+       ao_string.c \
+       ao_spi.c \
+       ao_usb.c \
+       ao_convert_pa.c \
+       ao_beep.c \
+       ao_timer.c \
+       ao_exti.c \
+       _bp.c
+
+DRIVER_SRC = \
+       ao_ms5607.c \
+       ao_m25.c
+
+PRODUCT_SRC = \
+       ao_telemini.c
+
+SRC = \
+       $(CORE_SRC) \
+       $(CC1111_SRC) \
+       $(DRIVER_SRC) \
+       $(PRODUCT_SRC)
+
+PROGNAME = telemini-v$(TELEMINI_VER)
+PROG = $(PROGNAME)-$(VERSION).ihx
+PRODUCT=TeleMini-v$(TELEMINI_VER)
+PRODUCT_DEF=-DTELEMINI_V_$(TELEMINI_DEF)
+IDPRODUCT=0x0027
+
+include ../cc1111/Makefile.cc1111
+
+NICKLE=nickle
+CHECK_STACK=sh ../util/check-stack
+
+V=0
+# The user has explicitly enabled quiet compilation.
+ifeq ($(V),0)
+quiet = @printf "  $1 $2 $@\n"; $($1)
+endif
+# Otherwise, print the full command line.
+quiet ?= $($1)
+
+all: $(PROG)
+
+$(PROG): $(REL) Makefile
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
+       $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
+
+ao_product.h: ao-make-product.5c ../Version
+       $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+
+distclean:     clean
+
+clean: clean-cc1111
+
+install:
+
+uninstall:
+
diff --git a/src/telemini-v2.0/ao_pins.h b/src/telemini-v2.0/ao_pins.h
new file mode 100644 (file)
index 0000000..c4681ee
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#define HAS_RADIO      1
+
+#define HAS_FLIGHT             1
+#define HAS_USB                        1
+#define USB_FORCE_FLIGHT_IDLE  1
+#define HAS_BEEP               1
+#define HAS_GPS                        0
+#define HAS_SERIAL_1           0
+#define HAS_EEPROM             1
+#define HAS_LOG                        1
+#define USE_INTERNAL_FLASH     0
+#define HAS_DBG                        0
+#define PACKET_HAS_SLAVE       1
+
+#define AO_LED_GREEN           1
+#define AO_LED_RED             2
+#define LEDS_AVAILABLE         (AO_LED_RED|AO_LED_GREEN)
+#define HAS_EXTERNAL_TEMP      0
+#define HAS_ACCEL              0
+#define HAS_IGNITE             1
+#define HAS_IGNITE_REPORT 1
+#define HAS_MONITOR            0
+
+/*
+ * SPI
+ */
+
+#define HAS_SPI_0              1
+#define SPI_0_ALT_1            1
+#define HAS_SPI_1              1
+#define SPI_1_ALT_2            1
+#define SPI_CS_PORT            P1
+#define SPI_CS_SEL             P1SEL
+#define SPI_CS_DIR             P1DIR
+
+/*
+ * Flash
+ */
+#define AO_M25_SPI_BUS         1
+#define AO_M25_SPI_CS_PORT     SPI_CS_PORT
+#define AO_M25_SPI_CS_MASK     0x04    /* cs_flash is P1_2 */
+#define M25_MAX_CHIPS          1
+
+/*
+ * MS5607
+ */
+
+#define HAS_MS5607             1
+#define HAS_MS5611             0
+#define AO_MS5607_PRIVATE_PINS 0
+#define AO_MS5607_CS_PORT      P1
+#define AO_MS5607_CS_PIN       3
+#define AO_MS5607_CS           P1_3
+#define AO_MS5607_CS_MASK      (1 << AO_MS5607_CS_PIN)
+#define AO_MS5607_MISO_PORT    P0
+#define AO_MS5607_MISO_PIN     2
+#define AO_MS5607_MISO         P0_2
+#define AO_MS5607_MISO_MASK    (1 << AO_MS5607_MISO_PIN)
+#define AO_MS5607_SPI_INDEX    0
+#define HAS_EXTI_0             1
+
+/*
+ * Igniters
+ */
+#define AO_IGNITER_PORT                P2
+#define AO_IGNITER_DROGUE_PORT AO_IGNITER_PORT
+#define AO_IGNITER_DROGUE      P2_3
+#define AO_IGNITER_MAIN                P2_4
+#define AO_IGNITER_DIR         P2DIR
+#define AO_IGNITER_DROGUE_BIT  (1 << 3)
+#define AO_IGNITER_MAIN_BIT    (1 << 4)
+#define AO_IGNITER_DROGUE_PIN  3
+#define AO_IGNITER_MAIN_PIN    4
+
+#define AO_IGNITER_DROGUE_PORT AO_IGNITER_PORT
+#define AO_IGNITER_MAIN_PORT   AO_IGNITER_PORT
+
+/* test these values with real igniters */
+#define AO_IGNITER_OPEN                1000
+#define AO_IGNITER_CLOSED      7000
+#define AO_IGNITER_FIRE_TIME   AO_MS_TO_TICKS(50)
+#define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000)
+
+#define AO_SEND_MINI
+#define AO_LOG_FORMAT          AO_LOG_FORMAT_TELEMINI
+
+/*
+ * ADC
+ */
+
+#define HAS_ADC                        1
+#define AO_ADC_FIRST_PIN       0
+
+struct ao_adc {
+       int16_t         sense_a;        /* apogee continuity sense */
+       int16_t         sense_m;        /* main continuity sense */
+       int16_t         v_batt;         /* battery voltage */
+};
+
+#define ao_data_count  ao_adc_count
+
+#define AO_SENSE_DROGUE(p)     ((p)->adc.sense_a)
+#define AO_SENSE_MAIN(p)       ((p)->adc.sense_m)
+
+#define AO_NUM_TASKS   10
+
+#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)
+
+#define AO_ADC_PINS    ((1 << 0) | (1 << 1) | (1 << 4))
+
+#define FETCH_ADC() do {                                               \
+               a = (uint8_t __xdata *) (&ao_data_ring[ao_data_head].adc); \
+               switch (sequence) {                                     \
+               case 4:                                                 \
+                       a += 4;                                         \
+                       sequence = 0;                                   \
+                       break;                                          \
+               case 1:                                                 \
+                       a += 2;                                         \
+                       sequence = 4;                                   \
+                       break;                                          \
+               case 0:                                                 \
+                       sequence = 1;                                   \
+                       break;                                          \
+               }                                                       \
+               a[0] = ADCL;                                            \
+               a[1] = ADCH;                                            \
+               if (sequence) {                                         \
+                       ADCCON3 = ADCCON3_EREF_VDD | ADCCON3_EDIV_512 | sequence; \
+                       return;                                         \
+               }                                                       \
+               AO_DATA_PRESENT(AO_DATA_ADC);                           \
+               if (ao_data_present != AO_DATA_ALL)                     \
+                       return;                                         \
+               ao_data_ring[ao_data_head].ms5607_raw.pres = ao_ms5607_current.pres; \
+               ao_data_ring[ao_data_head].ms5607_raw.temp = ao_ms5607_current.temp; \
+       } while (0)
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/telemini-v2.0/ao_telemini.c b/src/telemini-v2.0/ao_telemini.c
new file mode 100644 (file)
index 0000000..0d8dd1c
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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_pins.h"
+#include <ao_exti.h>
+
+__xdata uint8_t ao_force_freq;
+
+void
+main(void)
+{
+       ao_clock_init();
+
+#if HAS_STACK_GUARD
+       ao_mpu_init();
+#endif
+       ao_task_init();
+
+       /* Turn on the red LED until the system is stable */
+       ao_led_init(LEDS_AVAILABLE);
+       ao_led_on(AO_LED_RED);
+
+       ao_timer_init();
+
+       ao_spi_init();
+       ao_exti_init();
+       ao_adc_init();
+#if HAS_BEEP
+       ao_beep_init();
+#endif
+       ao_cmd_init();
+#if HAS_MS5607
+       ao_ms5607_init();
+#endif
+       ao_storage_init();
+
+       ao_flight_init();
+       ao_log_init();
+       ao_report_init();
+
+       ao_usb_init();
+       ao_telemetry_init();
+       ao_radio_init();
+       ao_packet_slave_init(TRUE);
+
+       ao_igniter_init();
+
+       ao_config_init();
+       ao_start_scheduler();
+}
index 6743ba66db37c9a30f2c690580dfa35611bd0d16..025b324a360833c6befa99fb84b4aab561713c5d 100644 (file)
@@ -5,18 +5,12 @@
 vpath % .:..:../core:../product:../drivers:../avr
 vpath ao-make-product.5c ../util
 
+include ../avr/Makefile.defs
+
 MCU=atmega32u4
 DUDECPUTYPE=m32u4
 #PROGRAMMER=stk500v2 -P usb
-PROGRAMMER=usbtiny
-LOADCMD=avrdude
 LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc
-OBJCOPY=avr-objcopy
-
-ifndef VERSION
-include ../Version
-endif
 
 INC = \
        ao.h \
index dfccadf8d77f924453ee157cf888bbc981f3bf61..5d9c09703a74e3fd67616ba039d484f716015943 100644 (file)
@@ -1,2 +1,2 @@
-telescience-v0.1*
+telescience-pwm*
 ao_product.h
index 43d77e2e3052c1f5de11c2934ae6971defcc0b6a..de81b8d798ec397af3b71ed62b01377eb67a372d 100644 (file)
@@ -5,18 +5,14 @@
 vpath % ..:../core:../product:../drivers:../avr
 vpath ao-make-product.5c ../util
 
+include ../avr/Makefile.defs
+
 MCU=atmega32u4
 DUDECPUTYPE=m32u4
 #PROGRAMMER=stk500v2 -P usb
-PROGRAMMER=usbtiny
-LOADCMD=avrdude
 LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc
-OBJCOPY=avr-objcopy
 
-ifndef VERSION
-include ../Version
-endif
+#LDFLAGS=-L$(LDSCRIPTS) -Tavr5.x
 
 INC = \
        ao.h \
index d24128ef53a2161e51e85b659126038045ae8e75..6e4eb6de429a7e1c7d35a93ae26b00a40f61613c 100644 (file)
@@ -5,18 +5,14 @@
 vpath % ..:../core:../product:../drivers:../avr
 vpath ao-make-product.5c ../util
 
+include ../avr/Makefile.defs
+
 MCU=atmega32u4
 DUDECPUTYPE=m32u4
 #PROGRAMMER=stk500v2 -P usb
-PROGRAMMER=usbtiny
-LOADCMD=avrdude
 LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
-CC=avr-gcc
-OBJCOPY=avr-objcopy
 
-ifndef VERSION
-include ../Version
-endif
+#LDFLAGS=-L$(LDSCRIPTS) -Tavr5.x
 
 INC = \
        ao.h \
index f16ef268f416f8551e7ff451e20af3a7e15546a8..6b7ea8c783ec6e441587a39f163c67e56c83af58 100644 (file)
@@ -61,14 +61,15 @@ CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STA
 
 PROGNAME=telescience-v0.2
 PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
 
 SRC=$(ALTOS_SRC) ao_telescience.c
 OBJ=$(SRC:.c=.o)
 
-all: $(PROG)
+all: $(PROG) $(HEX)
 
 $(PROG): Makefile $(OBJ) altos.ld
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
 
 $(OBJ): $(INC)
 
@@ -78,7 +79,7 @@ ao_product.h: ao-make-product.5c ../Version
 distclean:     clean
 
 clean:
-       rm -f *.o $(PROGNAME)-*.elf
+       rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx
        rm -f ao_product.h
 
 install:
diff --git a/src/telescience-v0.2/flash-loader/Makefile b/src/telescience-v0.2/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..7a2ceb7
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telescience-v0.2
+include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/telescience-v0.2/flash-loader/ao_pins.h b/src/telescience-v0.2/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..907ff34
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* External crystal at 8MHz */
+#define AO_HSE         8000000
+
+#include <ao_flash_stm_pins.h>
+
+/* Companion port SS PA4 */
+
+#define AO_BOOT_PIN            1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpioa
+#define AO_BOOT_APPLICATION_PIN                4
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
index ab2a025f4004da4c60b077882f4d8c5a07b83776..e8b262efe25f224fde19d538fab2eeeb09122c75 100644 (file)
@@ -92,10 +92,10 @@ endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-all: ../$(PROG)
+all: $(PROG)
 
-../$(PROG): $(REL) Makefile
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
 
 ao_product.h: ao-make-product.5c ../Version
index 65db57ce5191a0e1167174f7dca904c4059ff7ba..88637360d35f191be751c532af839a30d52d051e 100644 (file)
@@ -52,7 +52,8 @@ CC1111_SRC = \
 DRIVER_SRC = \
        ao_m25.c \
        ao_lcd.c \
-       ao_gps_skytraq.c
+       ao_gps_skytraq.c \
+       ao_gps_show.c
 
 PRODUCT_SRC = \
        ao_teleterra_0_2.c \
@@ -85,10 +86,10 @@ endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-all: ../$(PROG)
+all: $(PROG)
 
-../$(PROG): $(REL) Makefile
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
 
 ao_product.h: ao-make-product.5c ../Version
index 90af65170d28a8d8beb150f2ef0d1d614ef6a9a4..b8b2513e5b54f57c9df6d95c8692832dd56b0493 100644 (file)
@@ -5,6 +5,10 @@ ao_flight_test_baro
 ao_flight_test_accel
 ao_gps_test
 ao_gps_test_skytraq
+ao_gps_test_ublox
+ao_int64_test
+ao_ms5607_convert_test
+ao_quaternion_test
 ao_convert_test
 ao_convert_pa_test
 ao_fat_test
index 76d50f167c476a221a6fc3b2f6dc05bbd4e94beb..7ae06a8033d8311e9b3cedcc836be871d66c5f15 100644 (file)
@@ -1,14 +1,15 @@
-vpath % ..:../core:../drivers:../util:../micropeak:../aes
+vpath % ..:../core:../drivers:../util:../micropeak:../aes:../product
 
 PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \
        ao_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_aprs_test ao_micropeak_test ao_fat_test ao_aes_test ao_int64_test \
+       ao_ms5607_convert_test ao_quaternion_test
 
-INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h
+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../core -I../drivers -I../micropeak -O0 -g -Wall
+CFLAGS=-I.. -I. -I../core -I../drivers -I../micropeak -I../product -O0 -g -Wall
 
 all: $(PROGS) ao_aprs_data.wav
 
@@ -29,16 +30,16 @@ ao_flight_test_baro: ao_flight_test.c ao_host.h ao_flight.c  ao_sample.c ao_kalm
 ao_flight_test_accel: ao_flight_test.c ao_host.h ao_flight.c  ao_sample.c ao_kalman.c $(INCS)
        cc $(CFLAGS) -o $@ -DFORCE_ACCEL=1 ao_flight_test.c
 
-ao_flight_test_mm: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c $(INCS)
+ao_flight_test_mm: ao_flight_test.c ao_host.h ao_flight.c ao_sample.c ao_kalman.c ao_pyro.c ao_pyro.h $(INCS)
        cc -DTELEMEGA=1 $(CFLAGS) -o $@ $< -lm
 
 ao_gps_test: ao_gps_test.c ao_gps_sirf.c ao_gps_print.c ao_host.h
        cc $(CFLAGS) -o $@ $<
 
-ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_host.h
+ao_gps_test_skytraq: ao_gps_test_skytraq.c ao_gps_skytraq.c ao_gps_print.c ao_gps_show.c ao_host.h
        cc $(CFLAGS) -o $@ $<
 
-ao_gps_test_ublox: ao_gps_test_ublox.c ao_gps_ublox.c ao_gps_print.c ao_host.h ao_gps_ublox.h
+ao_gps_test_ublox: ao_gps_test_ublox.c ao_gps_ublox.c ao_gps_print.c ao_gps_show.c ao_host.h ao_gps_ublox.h
        cc $(CFLAGS) -o $@ $<
 
 ao_convert_test: ao_convert_test.c ao_convert.c altitude.h
@@ -73,3 +74,12 @@ ao_fat_test: ao_fat_test.c ao_fat.c ao_bufio.c
 
 ao_aes_test: ao_aes_test.c ao_aes.c ao_aes_tables.c
        cc $(CFLAGS) -o $@ ao_aes_test.c
+
+ao_int64_test: ao_int64_test.c ao_int64.c ao_int64.h
+       cc $(CFLAGS) -o $@ ao_int64_test.c
+
+ao_ms5607_convert_test: ao_ms5607_convert_test.c ao_ms5607_convert_8051.c ao_int64.c ao_int64.h
+       cc $(CFLAGS) -o $@ ao_ms5607_convert_test.c
+
+ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h
+       cc $(CFLAGS) -o $@ ao_quaternion_test.c -lm
index 99bed7eeb94df17dbd94f3560d5b7fe93a2c2ca8..0abb4090d397e0a615ea1ca31a00288f7057d5a5 100644 (file)
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stddef.h>
 #include <string.h>
 #include <getopt.h>
 #include <math.h>
 
+#define GRAVITY 9.80665
+
 #define AO_HERTZ       100
 
 #define HAS_ADC 1
 #define AO_MS_TO_SPEED(ms)     ((int16_t) ((ms) * 16))
 #define AO_MSS_TO_ACCEL(mss)   ((int16_t) ((mss) * 16))
 
+#define AO_GPS_NEW_DATA                1
+#define AO_GPS_NEW_TRACKING    2
+
+int ao_gps_new;
+
 #if TELEMEGA
 #define AO_ADC_NUM_SENSE       6
 #define HAS_MS5607             1
 #define HAS_MPU6000            1
 #define HAS_MMA655X            1
+#define HAS_HMC5883            1
 
 struct ao_adc {
        int16_t                 sense[AO_ADC_NUM_SENSE];
@@ -83,6 +92,95 @@ struct ao_adc {
 
 #include <ao_data.h>
 #include <ao_log.h>
+#include <ao_telemetry.h>
+
+#if TELEMEGA
+int ao_gps_count;
+struct ao_telemetry_location ao_gps_first;
+struct ao_telemetry_location ao_gps_prev;
+struct ao_telemetry_location ao_gps_static;
+
+struct ao_telemetry_satellite ao_gps_tracking;
+
+static inline double sqr(double a) { return a * a; }
+
+void
+cc_great_circle (double start_lat, double start_lon,
+                double end_lat, double end_lon,
+                double *dist, double *bearing)
+{
+       const double rad = M_PI / 180;
+       const double earth_radius = 6371.2 * 1000;      /* in meters */
+       double lat1 = rad * start_lat;
+       double lon1 = rad * -start_lon;
+       double lat2 = rad * end_lat;
+       double lon2 = rad * -end_lon;
+
+//     double d_lat = lat2 - lat1;
+       double d_lon = lon2 - lon1;
+
+       /* From http://en.wikipedia.org/wiki/Great-circle_distance */
+       double vdn = sqrt(sqr(cos(lat2) * sin(d_lon)) +
+                         sqr(cos(lat1) * sin(lat2) -
+                             sin(lat1) * cos(lat2) * cos(d_lon)));
+       double vdd = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(d_lon);
+       double d = atan2(vdn,vdd);
+       double course;
+
+       if (cos(lat1) < 1e-20) {
+               if (lat1 > 0)
+                       course = M_PI;
+               else
+                       course = -M_PI;
+       } else {
+               if (d < 1e-10)
+                       course = 0;
+               else
+                       course = acos((sin(lat2)-sin(lat1)*cos(d)) /
+                                     (sin(d)*cos(lat1)));
+               if (sin(lon2-lon1) > 0)
+                       course = 2 * M_PI-course;
+       }
+       *dist = d * earth_radius;
+       *bearing = course * 180/M_PI;
+}
+
+double
+ao_distance_from_pad(void)
+{
+       double  dist, bearing;
+       if (!ao_gps_count)
+               return 0;
+       
+       cc_great_circle(ao_gps_first.latitude / 1e7,
+                       ao_gps_first.longitude / 1e7,
+                       ao_gps_static.latitude / 1e7,
+                       ao_gps_static.longitude / 1e7,
+                       &dist, &bearing);
+       return dist;
+}
+
+double
+ao_gps_angle(void)
+{
+       double  dist, bearing;
+       double  height;
+       double  angle;
+
+       if (ao_gps_count < 2)
+               return 0;
+
+       cc_great_circle(ao_gps_prev.latitude / 1e7,
+                       ao_gps_prev.longitude / 1e7,
+                       ao_gps_static.latitude / 1e7,
+                       ao_gps_static.longitude / 1e7,
+                       &dist, &bearing);
+       height = ao_gps_static.altitude - ao_gps_prev.altitude;
+
+       angle = atan2(dist, height);
+       return angle * 180/M_PI;
+}
+#endif
 
 #define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
 #define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
@@ -120,6 +218,7 @@ int ao_summary = 0;
 #define ao_rdf_set(rdf)
 #define ao_packet_slave_start()
 #define ao_packet_slave_stop()
+#define flush()
 
 enum ao_igniter {
        ao_igniter_drogue = 0,
@@ -137,6 +236,18 @@ int        tick_offset;
 
 static int32_t ao_k_height;
 
+int16_t
+ao_time(void)
+{
+       return ao_data_static.tick;
+}
+
+void
+ao_delay(int16_t interval)
+{
+       return;
+}
+
 void
 ao_ignite(enum ao_igniter igniter)
 {
@@ -200,6 +311,8 @@ struct ao_cmds {
 #include <ao_ms5607.h>
 struct ao_ms5607_prom  ms5607_prom;
 #include "ao_ms5607_convert.c"
+#define AO_PYRO_NUM    4
+#include <ao_pyro.h>
 #else
 #include "ao_convert.c"
 #endif
@@ -210,6 +323,12 @@ struct ao_config {
        int16_t         accel_minus_g;
        uint8_t         pad_orientation;
        uint16_t        apogee_lockout;
+#if TELEMEGA
+       struct ao_pyro  pyro[AO_PYRO_NUM];      /* minor version 12 */
+       int16_t         accel_zero_along;
+       int16_t         accel_zero_across;
+       int16_t         accel_zero_through;
+#endif
 };
 
 #define AO_PAD_ORIENTATION_ANTENNA_UP  0
@@ -222,7 +341,6 @@ struct ao_config ao_config;
 #define DATA_TO_XDATA(x) (x)
 
 
-#define GRAVITY 9.80665
 extern int16_t ao_ground_accel, ao_flight_accel;
 extern int16_t ao_accel_2g;
 
@@ -246,6 +364,22 @@ uint16_t   prev_tick;
 #include "ao_sqrt.c"
 #include "ao_sample.c"
 #include "ao_flight.c"
+#if TELEMEGA
+#define AO_PYRO_NUM    4
+
+#define AO_PYRO_0      0
+#define AO_PYRO_1      1
+#define AO_PYRO_2      2
+#define AO_PYRO_3      3
+
+static void
+ao_pyro_pin_set(uint8_t pin, uint8_t value)
+{
+       printf ("set pyro %d %d\n", pin, value);
+}
+
+#include "ao_pyro.c"
+#endif
 
 #define to_double(f)   ((f) / 65536.0)
 
@@ -305,17 +439,20 @@ ao_test_exit(void)
        exit(0);
 }
 
-#if HAS_MPU6000
-static double
-ao_mpu6000_accel(int16_t sensor)
-{
-       return sensor / 32767.0 * MPU6000_ACCEL_FULLSCALE * GRAVITY;
-}
+#ifdef TELEMEGA
+struct ao_azel {
+       int     az;
+       int     el;
+};
 
-static double
-ao_mpu6000_gyro(int32_t sensor)
+static void
+azel (struct ao_azel *r, struct ao_quaternion *q)
 {
-       return sensor / 32767.0 * MPU6000_GYRO_FULLSCALE;
+       double  v;
+
+       r->az = floor (atan2(q->y, q->x) * 180/M_PI + 0.5);
+       v = sqrt (q->x*q->x + q->y*q->y);
+       r->el = floor (atan2(q->z, v) * 180/M_PI + 0.5);
 }
 #endif
 
@@ -342,6 +479,7 @@ ao_insert(void)
                double  height = ao_pres_to_altitude(ao_data_static.adc.pres_real) - ao_ground_height;
 #endif
 
+               (void) accel;
                if (!tick_offset)
                        tick_offset = -ao_data_static.tick;
                if ((prev_tick - ao_data_static.tick) > 0x400)
@@ -372,25 +510,115 @@ ao_insert(void)
                }
 
                if (!ao_summary) {
+#if TELEMEGA
+                       static struct ao_quaternion     ao_ground_mag;
+                       static int                      ao_ground_mag_set;
+
+                       if (!ao_ground_mag_set) {
+                               ao_quaternion_init_vector (&ao_ground_mag,
+                                                          ao_data_mag_across(&ao_data_static),
+                                                          ao_data_mag_through(&ao_data_static),
+                                                          ao_data_mag_along(&ao_data_static));
+                               ao_quaternion_normalize(&ao_ground_mag, &ao_ground_mag);
+                               ao_quaternion_rotate(&ao_ground_mag, &ao_ground_mag, &ao_rotation);
+                               ao_ground_mag_set = 1;
+                       }
+
+                       struct ao_quaternion            ao_mag, ao_mag_rot;
+
+                       ao_quaternion_init_vector(&ao_mag,
+                                                 ao_data_mag_across(&ao_data_static),
+                                                 ao_data_mag_through(&ao_data_static),
+                                                 ao_data_mag_along(&ao_data_static));
+
+                       ao_quaternion_normalize(&ao_mag, &ao_mag);
+                       ao_quaternion_rotate(&ao_mag_rot, &ao_mag, &ao_rotation);
+                       
+                       float                           ao_dot;
+                       int                             ao_mag_angle;
+
+                       ao_dot = ao_quaternion_dot(&ao_mag_rot, &ao_ground_mag);
+
+                       struct ao_azel                  ground_azel, mag_azel, rot_azel;
+
+                       azel(&ground_azel, &ao_ground_mag);
+                       azel(&mag_azel, &ao_mag);
+                       azel(&rot_azel, &ao_mag_rot);
+
+                       ao_mag_angle = floor (acos(ao_dot) * 180 / M_PI + 0.5);
+
+                       (void) ao_mag_angle;
+
+                       static struct ao_quaternion     ao_x = { .r = 0, .x = 1, .y = 0, .z = 0 };
+                       struct ao_quaternion            ao_out;
+
+                       ao_quaternion_rotate(&ao_out, &ao_x, &ao_rotation);
+
+                       int     out = floor (atan2(ao_out.y, ao_out.x) * 180 / M_PI);
+
+#if 0
+                       printf ("%7.2f state %-8.8s height %8.4f tilt %4d rot %4d mag_tilt %4d mag_rot %4d\n",
+                               time,
+                               ao_state_names[ao_flight_state],
+                               ao_k_height / 65536.0,
+                               ao_sample_orient, out,
+                               mag_azel.el,
+                               mag_azel.az);
+#endif
+                       printf ("%7.2f state %-8.8s height %8.4f tilt %4d rot %4d dist %12.2f gps_tilt %4d gps_sats %2d\n",
+                               time,
+                               ao_state_names[ao_flight_state],
+                               ao_k_height / 65536.0,
+                               ao_sample_orient, out,
+                               ao_distance_from_pad(),
+                               (int) floor (ao_gps_angle() + 0.5),
+                               (ao_gps_static.flags & 0xf) * 10);
+
+#if 0
+                       printf ("\t\tstate %-8.8s ground az: %4d el %4d mag az %4d el %4d rot az %4d el %4d el_diff %4d az_diff %4d angle %4d tilt %4d ground %8.5f %8.5f %8.5f cur %8.5f %8.5f %8.5f rot %8.5f %8.5f %8.5f\n",
+                               ao_state_names[ao_flight_state],
+                               ground_azel.az, ground_azel.el,
+                               mag_azel.az, mag_azel.el,
+                               rot_azel.az, rot_azel.el,
+                               ground_azel.el - rot_azel.el,
+                               ground_azel.az - rot_azel.az,
+                               ao_mag_angle,
+                               ao_sample_orient,
+                               ao_ground_mag.x,
+                               ao_ground_mag.y,
+                               ao_ground_mag.z,
+                               ao_mag.x,
+                               ao_mag.y,
+                               ao_mag.z,
+                               ao_mag_rot.x,
+                               ao_mag_rot.y,
+                               ao_mag_rot.z);
+#endif
+#endif
+
+#if 0
                        printf("%7.2f height %8.2f accel %8.3f "
 #if TELEMEGA
-                              "roll %8.3f angle %8.3f qangle %8.3f "
-                              "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f "
+                              "angle %5d "
+                              "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f mag_x %8d mag_y %8d, mag_z %8d mag_angle %4d "
 #endif
                               "state %-8.8s k_height %8.2f k_speed %8.3f k_accel %8.3f avg_height %5d drogue %4d main %4d error %5d\n",
                               time,
                               height,
                               accel,
 #if TELEMEGA
-                              ao_mpu6000_gyro(ao_sample_roll_angle) / 100.0,
-                              ao_mpu6000_gyro(ao_sample_angle) / 100.0,
-                              ao_sample_qangle,
+                              ao_sample_orient,
+
                               ao_mpu6000_accel(ao_data_static.mpu6000.accel_x),
                               ao_mpu6000_accel(ao_data_static.mpu6000.accel_y),
                               ao_mpu6000_accel(ao_data_static.mpu6000.accel_z),
                               ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_x - ao_ground_mpu6000.gyro_x),
                               ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_y - ao_ground_mpu6000.gyro_y),
                               ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_z - ao_ground_mpu6000.gyro_z),
+                              ao_data_static.hmc5883.x,
+                              ao_data_static.hmc5883.y,
+                              ao_data_static.hmc5883.z,
+                              ao_mag_angle,
 #endif
                               ao_state_names[ao_flight_state],
                               ao_k_height / 65536.0,
@@ -400,6 +628,7 @@ ao_insert(void)
                               drogue_height,
                               main_height,
                               ao_error_h_sq_avg);
+#endif
                        
 //                     if (ao_flight_state == ao_flight_landed)
 //                             ao_test_exit();
@@ -407,125 +636,6 @@ ao_insert(void)
        }
 }
 
-#define AO_MAX_CALLSIGN                        8
-#define AO_MAX_VERSION                 8
-#define AO_MAX_TELEMETRY               128
-
-struct ao_telemetry_generic {
-       uint16_t        serial;         /* 0 */
-       uint16_t        tick;           /* 2 */
-       uint8_t         type;           /* 4 */
-       uint8_t         payload[27];    /* 5 */
-       /* 32 */
-};
-
-#define AO_TELEMETRY_SENSOR_TELEMETRUM 0x01
-#define AO_TELEMETRY_SENSOR_TELEMINI   0x02
-#define AO_TELEMETRY_SENSOR_TELENANO   0x03
-
-struct ao_telemetry_sensor {
-       uint16_t        serial;         /*  0 */
-       uint16_t        tick;           /*  2 */
-       uint8_t         type;           /*  4 */
-
-       uint8_t         state;          /*  5 flight state */
-       int16_t         accel;          /*  6 accelerometer (TM only) */
-       int16_t         pres;           /*  8 pressure sensor */
-       int16_t         temp;           /* 10 temperature sensor */
-       int16_t         v_batt;         /* 12 battery voltage */
-       int16_t         sense_d;        /* 14 drogue continuity sense (TM/Tm) */
-       int16_t         sense_m;        /* 16 main continuity sense (TM/Tm) */
-
-       int16_t         acceleration;   /* 18 m/s² * 16 */
-       int16_t         speed;          /* 20 m/s * 16 */
-       int16_t         height;         /* 22 m */
-
-       int16_t         ground_pres;    /* 24 average pres on pad */
-       int16_t         ground_accel;   /* 26 average accel on pad */
-       int16_t         accel_plus_g;   /* 28 accel calibration at +1g */
-       int16_t         accel_minus_g;  /* 30 accel calibration at -1g */
-       /* 32 */
-};
-
-#define AO_TELEMETRY_CONFIGURATION     0x04
-
-struct ao_telemetry_configuration {
-       uint16_t        serial;                         /*  0 */
-       uint16_t        tick;                           /*  2 */
-       uint8_t         type;                           /*  4 */
-
-       uint8_t         device;                         /*  5 device type */
-       uint16_t        flight;                         /*  6 flight number */
-       uint8_t         config_major;                   /*  8 Config major version */
-       uint8_t         config_minor;                   /*  9 Config minor version */
-       uint16_t        apogee_delay;                   /* 10 Apogee deploy delay in seconds */
-       uint16_t        main_deploy;                    /* 12 Main deploy alt in meters */
-       uint16_t        flight_log_max;                 /* 14 Maximum flight log size in kB */
-       char            callsign[AO_MAX_CALLSIGN];      /* 16 Radio operator identity */
-       char            version[AO_MAX_VERSION];        /* 24 Software version */
-       /* 32 */
-};
-
-#define AO_TELEMETRY_LOCATION          0x05
-
-#define AO_GPS_MODE_NOT_VALID          'N'
-#define AO_GPS_MODE_AUTONOMOUS         'A'
-#define AO_GPS_MODE_DIFFERENTIAL       'D'
-#define AO_GPS_MODE_ESTIMATED          'E'
-#define AO_GPS_MODE_MANUAL             'M'
-#define AO_GPS_MODE_SIMULATED          'S'
-
-struct ao_telemetry_location {
-       uint16_t        serial;         /*  0 */
-       uint16_t        tick;           /*  2 */
-       uint8_t         type;           /*  4 */
-
-       uint8_t         flags;          /*  5 Number of sats and other flags */
-       int16_t         altitude;       /*  6 GPS reported altitude (m) */
-       int32_t         latitude;       /*  8 latitude (degrees * 10⁷) */
-       int32_t         longitude;      /* 12 longitude (degrees * 10⁷) */
-       uint8_t         year;           /* 16 (- 2000) */
-       uint8_t         month;          /* 17 (1-12) */
-       uint8_t         day;            /* 18 (1-31) */
-       uint8_t         hour;           /* 19 (0-23) */
-       uint8_t         minute;         /* 20 (0-59) */
-       uint8_t         second;         /* 21 (0-59) */
-       uint8_t         pdop;           /* 22 (m * 5) */
-       uint8_t         hdop;           /* 23 (m * 5) */
-       uint8_t         vdop;           /* 24 (m * 5) */
-       uint8_t         mode;           /* 25 */
-       uint16_t        ground_speed;   /* 26 cm/s */
-       int16_t         climb_rate;     /* 28 cm/s */
-       uint8_t         course;         /* 30 degrees / 2 */
-       uint8_t         unused[1];      /* 31 */
-       /* 32 */
-};
-
-#define AO_TELEMETRY_SATELLITE         0x06
-
-struct ao_telemetry_satellite_info {
-       uint8_t         svid;
-       uint8_t         c_n_1;
-};
-
-struct ao_telemetry_satellite {
-       uint16_t                                serial;         /*  0 */
-       uint16_t                                tick;           /*  2 */
-       uint8_t                                 type;           /*  4 */
-       uint8_t                                 channels;       /*  5 number of reported sats */
-
-       struct ao_telemetry_satellite_info      sats[12];       /* 6 */
-       uint8_t                                 unused[2];      /* 30 */
-       /* 32 */
-};
-
-union ao_telemetry_all {
-       struct ao_telemetry_generic             generic;
-       struct ao_telemetry_sensor              sensor;
-       struct ao_telemetry_configuration       configuration;
-       struct ao_telemetry_location            location;
-       struct ao_telemetry_satellite           satellite;
-};
 
 uint16_t
 uint16(uint8_t *bytes, int off)
@@ -555,207 +665,6 @@ int32(uint8_t *bytes, int off)
 
 static int log_format;
 
-#if TELEMEGA
-
-static double
-ao_vec_norm(double x, double y, double z)
-{
-       return x*x + y*y + z*z;
-}
-
-static void
-ao_vec_normalize(double *x, double *y, double *z)
-{
-       double  scale = 1/sqrt(ao_vec_norm(*x, *y, *z));
-
-       *x *= scale;
-       *y *= scale;
-       *z *= scale;
-}
-
-struct ao_quat {
-       double  q0, q1, q2, q3;
-};
-
-static void
-ao_quat_mul(struct ao_quat *r, struct ao_quat *a, struct ao_quat *b)
-{
-       r->q0 = a->q0 * b->q0 - a->q1 * b->q1 - a->q2 * b->q2 - a->q3 * b->q3;
-       r->q1 = a->q0 * b->q1 + a->q1 * b->q0 + a->q2 * b->q3 - a->q3 * b->q2;
-       r->q2 = a->q0 * b->q2 - a->q1 * b->q3 + a->q2 * b->q0 + a->q3 * b->q1;
-       r->q3 = a->q0 * b->q3 + a->q1 * b->q2 - a->q2 * b->q1 + a->q3 * b->q0;
-}
-
-#if 0
-static void
-ao_quat_scale(struct ao_quat *r, struct ao_quat *a, double s)
-{
-       r->q0 = a->q0 * s;
-       r->q1 = a->q1 * s;
-       r->q2 = a->q2 * s;
-       r->q3 = a->q3 * s;
-}
-#endif
-
-static void
-ao_quat_conj(struct ao_quat *r, struct ao_quat *a)
-{
-       r->q0 =  a->q0;
-       r->q1 = -a->q1;
-       r->q2 = -a->q2;
-       r->q3 = -a->q3;
-}
-
-static void
-ao_quat_rot(struct ao_quat *r, struct ao_quat *a, struct ao_quat *q)
-{
-       struct ao_quat  t;
-       struct ao_quat  c;
-       ao_quat_mul(&t, q, a);
-       ao_quat_conj(&c, q);
-       ao_quat_mul(r, &t, &c);
-}
-
-static void
-ao_quat_from_angle(struct ao_quat *r,
-                  double x_rad,
-                  double y_rad,
-                  double z_rad)
-{
-       double angle = sqrt (x_rad * x_rad + y_rad * y_rad + z_rad * z_rad);
-       double s = sin(angle/2);
-       double c = cos(angle/2);
-
-       r->q0 = c;
-       r->q1 = x_rad * s / angle;
-       r->q2 = y_rad * s / angle;
-       r->q3 = z_rad * s / angle;
-}
-
-static void
-ao_quat_from_vector(struct ao_quat *r, double x, double y, double z)
-{
-       ao_vec_normalize(&x, &y, &z);
-       double  x_rad = atan2(z, y);
-       double  y_rad = atan2(x, z);
-       double  z_rad = atan2(y, x);
-
-       ao_quat_from_angle(r, x_rad, y_rad, z_rad);
-}
-
-static double
-ao_quat_norm(struct ao_quat *a)
-{
-       return (a->q0 * a->q0 +
-               a->q1 * a->q1 +
-               a->q2 * a->q2 +
-               a->q3 * a->q3);
-}
-
-static void
-ao_quat_normalize(struct ao_quat *a)
-{
-       double  norm = ao_quat_norm(a);
-
-       if (norm) {
-               double m = 1/sqrt(norm);
-
-               a->q0 *= m;
-               a->q1 *= m;
-               a->q2 *= m;
-               a->q3 *= m;
-       }
-}
-
-static struct ao_quat  ao_up, ao_current;
-static struct ao_quat  ao_orient;
-static int             ao_orient_tick;
-
-void
-set_orientation(double x, double y, double z, int tick)
-{
-       struct ao_quat  t;
-
-       printf ("set_orientation %g %g %g\n", x, y, z);
-       ao_quat_from_vector(&ao_orient, x, y, z);
-       ao_up.q1 = ao_up.q2 = 0;
-       ao_up.q0 = ao_up.q3 = sqrt(2)/2;
-       ao_orient_tick = tick;
-
-       ao_orient.q0 = 1;
-       ao_orient.q1 = 0;
-       ao_orient.q2 = 0;
-       ao_orient.q3 = 0;
-
-       printf ("orient (%g) %g %g %g up (%g) %g %g %g\n",
-               ao_orient.q0,
-               ao_orient.q1,
-               ao_orient.q2,
-               ao_orient.q3,
-               ao_up.q0,
-               ao_up.q1,
-               ao_up.q2,
-               ao_up.q3);
-
-       ao_quat_rot(&t, &ao_up, &ao_orient);
-       printf ("pad orient (%g) %g %g %g\n",
-               t.q0,
-               t.q1,
-               t.q2,
-               t.q3);
-
-}
-
-void
-update_orientation (double rate_x, double rate_y, double rate_z, int tick)
-{
-       struct ao_quat  q_dot;
-       double          lambda;
-       double          dt = (tick - ao_orient_tick) / 100.0;
-
-       ao_orient_tick = tick;
-//     lambda = 1 - ao_quat_norm(&ao_orient);
-       lambda = 0;
-
-       q_dot.q0 = -0.5 * (ao_orient.q1 * rate_x + ao_orient.q2 * rate_y + ao_orient.q3 * rate_z) + lambda * ao_orient.q0;
-       q_dot.q1 =  0.5 * (ao_orient.q0 * rate_x + ao_orient.q2 * rate_z - ao_orient.q3 * rate_y) + lambda * ao_orient.q1;
-       q_dot.q2 =  0.5 * (ao_orient.q0 * rate_y + ao_orient.q3 * rate_x - ao_orient.q1 * rate_z) + lambda * ao_orient.q2;
-       q_dot.q3 =  0.5 * (ao_orient.q0 * rate_z + ao_orient.q1 * rate_y - ao_orient.q2 * rate_x) + lambda * ao_orient.q3;
-
-#if 0
-       printf ("update_orientation %g %g %g (%g s)\n", rate_x, rate_y, rate_z, dt);
-       printf ("q_dot (%g) %g %g %g\n",
-               q_dot.q0,
-               q_dot.q1,
-               q_dot.q2,
-               q_dot.q3);
-#endif
-
-       ao_orient.q0 += q_dot.q0 * dt;
-       ao_orient.q1 += q_dot.q1 * dt;
-       ao_orient.q2 += q_dot.q2 * dt;
-       ao_orient.q3 += q_dot.q3 * dt;
-
-       ao_quat_normalize(&ao_orient);
-
-       ao_quat_rot(&ao_current, &ao_up, &ao_orient);
-
-       ao_sample_qangle = 180 / M_PI * acos(ao_current.q3 * sqrt(2));
-#if 0
-       printf ("orient (%g) %g %g %g current (%g) %g %g %g\n",
-               ao_orient.q0,
-               ao_orient.q1,
-               ao_orient.q2,
-               ao_orient.q3,
-               ao_current.q0,
-               ao_current.q1,
-               ao_current.q2,
-               ao_current.q3);
-#endif
-}
-#endif
-
 void
 ao_sleep(void *wchan)
 {
@@ -771,6 +680,10 @@ ao_sleep(void *wchan)
                char            *words[64];
                int             nword;
 
+#if TELEMEGA
+               if (ao_flight_state >= ao_flight_boost && ao_flight_state < ao_flight_landed)
+                       ao_pyro_check();
+#endif
                for (;;) {
                        if (ao_records_read > 2 && ao_flight_state == ao_flight_startup)
                        {
@@ -826,43 +739,31 @@ ao_sleep(void *wchan)
                                        ao_data_static.ms5607_raw.temp = int32(bytes, 4);
                                        ao_ms5607_convert(&ao_data_static.ms5607_raw, &value);
                                        ao_data_static.mpu6000.accel_x = int16(bytes, 8);
-                                       ao_data_static.mpu6000.accel_y = -int16(bytes, 10);
+                                       ao_data_static.mpu6000.accel_y = int16(bytes, 10);
                                        ao_data_static.mpu6000.accel_z = int16(bytes, 12);
                                        ao_data_static.mpu6000.gyro_x = int16(bytes, 14);
-                                       ao_data_static.mpu6000.gyro_y = -int16(bytes, 16);
+                                       ao_data_static.mpu6000.gyro_y = int16(bytes, 16);
                                        ao_data_static.mpu6000.gyro_z = int16(bytes, 18);
+                                       ao_data_static.hmc5883.x = int16(bytes, 20);
+                                       ao_data_static.hmc5883.y = int16(bytes, 22);
+                                       ao_data_static.hmc5883.z = int16(bytes, 24);
 #if HAS_MMA655X
                                        ao_data_static.mma655x = int16(bytes, 26);
 #endif
-                                       if (ao_records_read == 0)
-                                               ao_ground_mpu6000 = ao_data_static.mpu6000;
-                                       else if (ao_records_read < 10) {
-#define f(f) ao_ground_mpu6000.f = ao_ground_mpu6000.f + ((ao_data_static.mpu6000.f - ao_ground_mpu6000.f) >> 2)
-                                               f(accel_x);
-                                               f(accel_y);
-                                               f(accel_z);
-                                               f(gyro_x);
-                                               f(gyro_y);
-                                               f(gyro_z);
-
-                                               double          accel_x = ao_mpu6000_accel(ao_ground_mpu6000.accel_x);
-                                               double          accel_y = ao_mpu6000_accel(ao_ground_mpu6000.accel_y);
-                                               double          accel_z = ao_mpu6000_accel(ao_ground_mpu6000.accel_z);
-
-                                               /* X and Y are in the ground plane, arbitraryily picked as MPU X and Z axes
-                                                * Z is normal to the ground, the MPU y axis
-                                                */
-                                               set_orientation(accel_x, accel_z, accel_y, tick);
-                                       } else {
-                                               double          rate_x = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_x - ao_ground_mpu6000.gyro_x);
-                                               double          rate_y = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_y - ao_ground_mpu6000.gyro_y);
-                                               double          rate_z = ao_mpu6000_gyro(ao_data_static.mpu6000.gyro_z - ao_ground_mpu6000.gyro_z);
-
-                                               update_orientation(rate_x * M_PI / 180, rate_z * M_PI / 180, rate_y * M_PI / 180, tick);
-                                       }
                                        ao_records_read++;
                                        ao_insert();
                                        return;
+                               case 'G':
+                                       ao_gps_prev = ao_gps_static;
+                                       ao_gps_static.tick = tick;
+                                       ao_gps_static.latitude = int32(bytes, 0);
+                                       ao_gps_static.longitude = int32(bytes, 4);
+                                       ao_gps_static.altitude = int32(bytes, 8);
+                                       ao_gps_static.flags = bytes[13];
+                                       if (!ao_gps_count)
+                                               ao_gps_first = ao_gps_static;
+                                       ao_gps_count++;
+                                       break;
                                }
                                continue;
                        } else if (nword == 3 && strcmp(words[0], "ms5607") == 0) {
@@ -883,6 +784,23 @@ ao_sleep(void *wchan)
                                else if (strcmp(words[1], "crc:") == 0)
                                        ms5607_prom.crc = strtoul(words[2], NULL, 10);
                                continue;
+                       } else if (nword >= 3 && strcmp(words[0], "Pyro") == 0) {
+                               int     p = strtoul(words[1], NULL, 10);
+                               int     i, j;
+                               struct ao_pyro  *pyro = &ao_config.pyro[p];
+
+                               for (i = 2; i < nword; i++) {
+                                       for (j = 0; j < NUM_PYRO_VALUES; j++)
+                                               if (!strcmp (words[2], ao_pyro_values[j].name))
+                                                       break;
+                                       if (j == NUM_PYRO_VALUES)
+                                               continue;
+                                       pyro->flags |= ao_pyro_values[j].flag;
+                                       if (ao_pyro_values[j].offset != NO_VALUE && i + 1 < nword) {
+                                               int16_t val = strtoul(words[++i], NULL, 10);
+                                               *((int16_t *) ((char *) pyro + ao_pyro_values[j].offset)) = val;
+                                       }
+                               }
                        }
 #else
                        if (nword == 4 && log_format != AO_LOG_FORMAT_TELEMEGA) {
@@ -899,6 +817,13 @@ ao_sleep(void *wchan)
                        } else if (nword >= 6 && strcmp(words[0], "Accel") == 0) {
                                ao_config.accel_plus_g = atoi(words[3]);
                                ao_config.accel_minus_g = atoi(words[5]);
+#ifdef TELEMEGA
+                       } else if (nword >= 8 && strcmp(words[0], "IMU") == 0) {
+                               ao_config.accel_zero_along = atoi(words[3]);
+                               ao_config.accel_zero_across = atoi(words[5]);
+                               ao_config.accel_zero_through = atoi(words[7]);
+                               printf ("%d %d %d\n", ao_config.accel_zero_along, ao_config.accel_zero_across, ao_config.accel_zero_through);
+#endif
                        } else if (nword >= 4 && strcmp(words[0], "Main") == 0) {
                                ao_config.main_deploy = atoi(words[2]);
                        } else if (nword >= 3 && strcmp(words[0], "Apogee") == 0 &&
index 3844a3265452f623d5065f48e31b6061cdabe002..e799ab0fc8f0a70e612c72bcbbe6c8c724842a31 100644 (file)
@@ -26,6 +26,9 @@
 #define AO_GPS_NUM_SAT_MASK    (0xf << 0)
 #define AO_GPS_NUM_SAT_SHIFT   (0)
 
+#define AO_GPS_NEW_DATA                1
+#define AO_GPS_NEW_TRACKING    2
+
 #define AO_GPS_VALID           (1 << 4)
 #define AO_GPS_RUNNING         (1 << 5)
 #define AO_GPS_DATE_VALID      (1 << 6)
@@ -427,11 +430,18 @@ void
 ao_dump_state(void *wchan)
 {
        int     i;
-       if (wchan == &ao_gps_data)
+
+       if (wchan != &ao_gps_new)
+               return;
+       
+       if (ao_gps_new & AO_GPS_NEW_DATA) {
                ao_gps_print(&ao_gps_data);
-       else
+               putchar('\n');
+       }
+       if (ao_gps_new & AO_GPS_NEW_TRACKING) {
                ao_gps_tracking_print(&ao_gps_tracking_data);
-       putchar('\n');
+               putchar('\n');
+       }
        return;
        printf ("%02d:%02d:%02d",
                ao_gps_data.hour, ao_gps_data.minute,
index 81008b39ebc282e6aa4682779691d6e2580528b2..1b590d5e972a5fff6bce45cf37f069c7f9a492ad 100644 (file)
@@ -26,6 +26,9 @@
 #define AO_GPS_NUM_SAT_MASK    (0xf << 0)
 #define AO_GPS_NUM_SAT_SHIFT   (0)
 
+#define AO_GPS_NEW_DATA                1
+#define AO_GPS_NEW_TRACKING    2
+
 #define AO_GPS_VALID           (1 << 4)
 #define AO_GPS_RUNNING         (1 << 5)
 #define AO_GPS_DATE_VALID      (1 << 6)
@@ -75,6 +78,11 @@ struct ao_gps_tracking_orig {
 #define ao_telemetry_satellite ao_gps_tracking_orig
 #define ao_telemetry_satellite_info ao_gps_sat_orig
 
+extern __xdata struct ao_telemetry_location    ao_gps_data;
+extern __xdata struct ao_telemetry_satellite   ao_gps_tracking_data;
+
+uint8_t ao_gps_mutex;
+
 void
 ao_mutex_get(uint8_t *mutex)
 {
@@ -432,17 +440,14 @@ uint8_t   ao_task_minimize_latency;
 #define ao_usb_getchar()       0
 
 #include "ao_gps_print.c"
+#include "ao_gps_show.c"
 #include "ao_gps_skytraq.c"
 
 void
 ao_dump_state(void *wchan)
 {
-       if (wchan == &ao_gps_data)
-               ao_gps_print(&ao_gps_data);
-       else
-               ao_gps_tracking_print(&ao_gps_tracking_data);
-       putchar('\n');
-       return;
+       if (wchan == &ao_gps_new)
+               ao_gps_show();
 }
 
 int
index 806717354e301c9d2d79ddd7d8ee38893b0bb125..4eb4b837d6db7951b947041720f2cba742c62a7f 100644 (file)
@@ -26,6 +26,9 @@
 #define AO_GPS_NUM_SAT_MASK    (0xf << 0)
 #define AO_GPS_NUM_SAT_SHIFT   (0)
 
+#define AO_GPS_NEW_DATA                1
+#define AO_GPS_NEW_TRACKING    2
+
 #define AO_GPS_VALID           (1 << 4)
 #define AO_GPS_RUNNING         (1 << 5)
 #define AO_GPS_DATE_VALID      (1 << 6)
@@ -77,6 +80,11 @@ struct ao_telemetry_satellite {
 #define ao_gps_tracking_orig ao_telemetry_satellite
 #define ao_gps_sat_orig ao_telemetry_satellite_info
 
+extern __xdata struct ao_telemetry_location    ao_gps_data;
+extern __xdata struct ao_telemetry_satellite   ao_gps_tracking_data;
+
+uint8_t ao_gps_mutex;
+
 void
 ao_mutex_get(uint8_t *mutex)
 {
@@ -125,7 +133,7 @@ static uint16_t     recv_len;
 static void check_ublox_message(char *which, uint8_t *msg);
 
 char
-ao_serial1_getchar(void)
+ao_gps_getchar(void)
 {
        char    c;
        uint8_t uc;
@@ -158,7 +166,7 @@ static int  message_len;
 static uint16_t        send_len;
 
 void
-ao_serial1_putchar(char c)
+ao_gps_putchar(char c)
 {
        int     i;
        uint8_t uc = (uint8_t) c;
@@ -191,7 +199,7 @@ ao_serial1_putchar(char c)
 #define AO_SERIAL_SPEED_115200 3
 
 static void
-ao_serial1_set_speed(uint8_t speed)
+ao_gps_set_speed(uint8_t speed)
 {
        int     fd = ao_gps_fd;
        struct termios  termios;
@@ -224,6 +232,7 @@ uint8_t     ao_task_minimize_latency;
 #define ao_usb_getchar()       0
 
 #include "ao_gps_print.c"
+#include "ao_gps_show.c"
 #include "ao_gps_ublox.c"
 
 static void
@@ -341,11 +350,8 @@ check_ublox_message(char *which, uint8_t *msg)
 void
 ao_dump_state(void *wchan)
 {
-       if (wchan == &ao_gps_data)
-               ao_gps_print(&ao_gps_data);
-       else
-               ao_gps_tracking_print(&ao_gps_tracking_data);
-       putchar('\n');
+       if (wchan == &ao_gps_new)
+               ao_gps_show();
        return;
 }
 
diff --git a/src/test/ao_int64_test.c b/src/test/ao_int64_test.c
new file mode 100644 (file)
index 0000000..8557a1c
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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 __data
+#define __pdata
+#define __xdata
+#define __reentrant
+
+#include <ao_int64.h>
+#include <ao_int64.c>
+#include <stdio.h>
+#include <stdlib.h>
+
+int    errors;
+
+#define test_o(op,func,mod,a,b,ao_a,ao_b) do {                         \
+               r = (a) op (b);                                         \
+               func(&ao_r, ao_a, ao_b);                                \
+               c = ao_cast64(&ao_r);                                   \
+               if (c != r) {                                           \
+                       printf ("trial %4d: %lld " #func mod " %lld = %lld (should be %lld)\n", \
+                               trial, (int64_t) (a), (int64_t) b, c, r); \
+                       ++errors;                                       \
+               }                                                       \
+       } while (0)
+
+#define test(op,func,a,b,ao_a,ao_b) test_o(op,func,"",a,b,ao_a,ao_b)
+
+#define test_a(op,func,a,b,ao_a,ao_b) do {     \
+               ao_r = *ao_a;                   \
+               test_o(op,func,"_a",a,b,&ao_r,ao_b);    \
+       } while (0)
+
+#define test_b(op,func,a,b,ao_a,ao_b) do {     \
+               ao_r = *ao_b;                   \
+               test_o(op,func,"_b",a,b,ao_a,&ao_r);    \
+       } while (0)
+
+#define test_x(op,func,a,b,ao_a,ao_b) do {     \
+               ao_r = *ao_a;                   \
+               test_o(op,func,"_xa",a,a,&ao_r,&ao_r);  \
+               ao_r = *ao_b;                   \
+               test_o(op,func,"_xb",b,b,&ao_r,&ao_r);  \
+       } while (0)
+
+void
+do_test(int trial, int64_t a, int64_t b)
+{
+       int64_t r, c;
+       ao_int64_t      ao_a, ao_b, ao_r;
+
+       ao_int64_init64(&ao_a, a >> 32, a);
+       ao_int64_init64(&ao_b, b >> 32, b);
+
+       test(+, ao_plus64, a, b, &ao_a, &ao_b);
+       test_a(+, ao_plus64, a, b, &ao_a, &ao_b);
+       test_b(+, ao_plus64, a, b, &ao_a, &ao_b);
+       test_x(+, ao_plus64, a, b, &ao_a, &ao_b);
+       test(-, ao_minus64, a, b, &ao_a, &ao_b);
+       test_a(-, ao_minus64, a, b, &ao_a, &ao_b);
+       test_b(-, ao_minus64, a, b, &ao_a, &ao_b);
+       test_x(-, ao_minus64, a, b, &ao_a, &ao_b);
+       test(*, ao_mul64_32_32,(int64_t) (int32_t) a, (int32_t) b, (int32_t) a, (int32_t) b);
+       test(*, ao_mul64, a, b, &ao_a, &ao_b);
+       test_a(*, ao_mul64, a, b, &ao_a, &ao_b);
+       test_b(*, ao_mul64, a, b, &ao_a, &ao_b);
+       test_x(*, ao_mul64, a, b, &ao_a, &ao_b);
+       test(*, ao_mul64_64_16, a, (uint16_t) b, &ao_a, (uint16_t) b);
+       test_a(*, ao_mul64_64_16, a, (uint16_t) b, &ao_a, (uint16_t) b);
+       test(>>, ao_rshift64, a, (uint8_t) b & 0x3f, &ao_a, (uint8_t) b & 0x3f);
+       test_a(>>, ao_rshift64, a, (uint8_t) b & 0x3f, &ao_a, (uint8_t) b & 0x3f);
+       test(<<, ao_lshift64, a, (uint8_t) b & 0x3f, &ao_a, (uint8_t) b & 0x3f);
+       test_a(<<, ao_lshift64, a, (uint8_t) b & 0x3f, &ao_a, (uint8_t) b & 0x3f);
+}
+
+#define TESTS  10000000
+
+static int64_t
+random64(void)
+{
+       return (int64_t) random() + ((int64_t) random() << 31) /* + ((int64_t) random() << 33) */;
+}
+
+int
+main (int argc, char **argv)
+{
+       int     i, start;
+
+       if (argv[1])
+               start = atoi(argv[1]);
+       else
+               start = 0;
+       srandom(1000);
+       for (i = 0; i < TESTS; i++) {
+               int64_t a = random64();
+               int64_t b = random64();
+               if (i >= start)
+                       do_test(i, a, b);
+       }
+       return errors;
+}
diff --git a/src/test/ao_ms5607_convert_test.c b/src/test/ao_ms5607_convert_test.c
new file mode 100644 (file)
index 0000000..ad59320
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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 __xdata
+#define __data
+#define __pdata
+#define __reentrant
+
+#include <stdint.h>
+#include <ao_ms5607.h>
+
+struct ao_ms5607_prom ms5607_prom = {
+       0x002c,
+       0xa6e0,
+       0x988e,
+       0x6814,
+       0x5eff,
+       0x8468,
+       0x6c86,
+       0xa271,
+};
+
+int32_t D1_mm = 6179630;
+int32_t D2_mm = 8933155;
+
+#include <ao_ms5607_convert.c>
+#define ao_ms5607_convert ao_ms5607_convert_8051
+#include <ao_ms5607_convert_8051.c>
+#include <ao_int64.c>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct ao_ms5607_sample ao_sample = {
+       6179630,
+       8933155
+};
+
+int errors;
+
+void test(int trial, struct ao_ms5607_sample *sample)
+{
+       struct ao_ms5607_value  value, value_8051;
+
+       ao_ms5607_convert(sample, &value);
+       ao_ms5607_convert_8051(sample, &value_8051);
+       if (value.temp != value_8051.temp || value.pres != value_8051.pres) {
+               ++errors;
+               printf ("trial %d: %d, %d -> %d, %d (should be %d, %d)\n",
+                       trial,
+                       sample->pres, sample->temp,
+                       value_8051.pres, value_8051.temp,
+                       value.pres, value.temp);
+       }
+}
+
+#define TESTS  10000000
+
+#include <stdlib.h>
+
+static int32_t rand24(void) { return random() & 0xffffff; }
+
+int
+main(int argc, char **argv)
+{
+       struct ao_ms5607_sample sample;
+       int     i, start;
+
+       if (argv[1])
+               start = atoi(argv[1]);
+       else
+               start = 0;
+
+       srandom(10000);
+       test(-1, &ao_sample);
+       for (i = 0; i < TESTS; i++) {
+               sample.pres = rand24();
+               sample.temp = rand24();
+               if (i >= start)
+                       test(i, &sample);
+       }
+       return errors;
+}
diff --git a/src/test/ao_quaternion_test.c b/src/test/ao_quaternion_test.c
new file mode 100644 (file)
index 0000000..b630f1d
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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 _GNU_SOURCE
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <getopt.h>
+#include <math.h>
+
+#include "ao_quaternion.h"
+
+#if 0
+static void
+print_q(char *name, struct ao_quaternion *q)
+{
+       printf ("%8.8s: r%8.5f x%8.5f y%8.5f z%8.5f ", name,
+               q->r, q->x, q->y, q->z);
+}
+#endif
+
+#define STEPS  16
+
+#define DEG    (1.0f * 3.1415926535f / 180.0f)
+
+struct ao_rotation {
+       int     steps;
+       float   x, y, z;
+};
+
+static struct ao_rotation ao_path[] = {
+       { .steps = 45, .x =  2*DEG, .y = 0, .z = 0 },
+
+       { .steps = 45, .x = 0, .y = 2*DEG, .z = 0 },
+       
+       { .steps = 45, .x = -2*DEG, .y = 0, .z = 0 },
+
+       { .steps = 45, .x = 0, .y = -2*DEG, .z = 0 },
+};
+
+#define NUM_PATH       (sizeof ao_path / sizeof ao_path[0])
+
+static int close(float a, float b) {
+       return fabsf (a - b) < 1e-5;
+}
+
+static int check_quaternion(char *where, struct ao_quaternion *got, struct ao_quaternion *expect) {
+       if (!close (got->r, expect->r) ||
+           !close (got->x, expect->x) ||
+           !close (got->y, expect->y) ||
+           !close (got->z, expect->z))
+       {
+               printf ("%s: got r%8.5f x%8.5f y%8.5f z%8.5f expect r%8.5f x%8.5f y%8.5f z%8.5f\n",
+                       where,
+                       got->r, got->x, got->y, got->z,
+                       expect->r, expect->x, expect->y, expect->z);
+               return 1;
+       }
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       struct ao_quaternion    position;
+       struct ao_quaternion    position_expect;
+       struct ao_quaternion    rotation;
+       struct ao_quaternion    rotated;
+       struct ao_quaternion    little_rotation;
+       int                     i;
+       int                     p;
+       int                     ret = 0;
+
+       /* vector */
+       ao_quaternion_init_vector(&position, 1, 1, 1);
+       ao_quaternion_init_vector(&position_expect, -1, -1, 1);
+
+       /* zero rotation */
+       ao_quaternion_init_zero_rotation(&rotation);
+
+#define dump() do {                                                    \
+                                                                       \
+               ao_quaternion_rotate(&rotated, &position, &rotation);   \
+               print_q("rotated", &rotated);                           \
+               print_q("rotation", &rotation);                         \
+               printf ("\n");                                          \
+       } while (0)
+
+//     dump();
+
+       for (p = 0; p < NUM_PATH; p++) {
+               ao_quaternion_init_half_euler(&little_rotation,
+                                             ao_path[p].x / 2.0f,
+                                             ao_path[p].y / 2.0f,
+                                             ao_path[p].z / 2.0f);
+//             printf ("\t\tx: %8.4f, y: %8.4f, z: %8.4f ", ao_path[p].x, ao_path[p].y, ao_path[p].z);
+//             print_q("step", &little_rotation);
+//             printf("\n");
+               for (i = 0; i < ao_path[p].steps; i++) {
+                       ao_quaternion_multiply(&rotation, &little_rotation, &rotation);
+
+                       ao_quaternion_normalize(&rotation, &rotation);
+
+//                     dump();
+               }
+       }
+
+       ao_quaternion_rotate(&rotated, &position, &rotation);
+
+       ret += check_quaternion("rotation", &rotated, &position_expect);
+
+       struct ao_quaternion    vertical;
+       struct ao_quaternion    angle;
+       struct ao_quaternion    rot;
+
+       ao_quaternion_init_vector(&vertical, 0, 0, 1);
+       ao_quaternion_init_vector(&angle, 0, 0, 1);
+
+       ao_quaternion_init_half_euler(&rot,
+                                     M_PI * 3.0 / 8.0 , 0, 0);
+
+       ao_quaternion_rotate(&angle, &angle, &rot);
+
+       struct ao_quaternion    rot_compute;
+
+       ao_quaternion_vectors_to_rotation(&rot_compute, &vertical, &angle);
+
+       ret += check_quaternion("vector rotation", &rot_compute, &rot);
+
+       struct ao_quaternion    rotd;
+
+       ao_quaternion_rotate(&rotd, &vertical, &rot_compute);
+
+       ret += check_quaternion("vector rotated", &rotd, &angle);
+
+       return ret;
+}
+
diff --git a/src/test/mega.flights b/src/test/mega.flights
new file mode 100644 (file)
index 0000000..71c44e6
--- /dev/null
@@ -0,0 +1,12 @@
+2013-10-12-serial-0094-flight-0001.eeprom
+2013-09-02-serial-094-flight-002.eeprom
+2013-03-02-serial-069-flight-002.eeprom
+2013-03-02-serial-069-flight-001.eeprom
+2013-05-27-serial-084-flight-001.mega
+2013-05-26-serial-085-flight-002.mega
+2013-05-19-serial-084-flight-003.mega
+2013-04-21-serial-069-flight-002.mega
+2012-10-20-serial-068-flight-004.mega
+2012-07-03-serial-058-flight-007.mega
+2012-06-30-serial-058-flight-006.mega
+2012-06-30-serial-058-flight-005.mega
diff --git a/src/test/plot-rot b/src/test/plot-rot
new file mode 100755 (executable)
index 0000000..b6b77c9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+case $# in
+1)
+       file="$1"
+       title="$1"
+       ;;
+2)
+       file="$1"
+       title="$2"
+       ;;
+*)
+       echo "Usage: $0 <data-file> <title>"
+       exit 1
+esac
+
+gnuplot -persist << EOF
+set ylabel "altitude (m)"
+set y2label "angle (d)"
+set xlabel "time (s)"
+set xtics border out nomirror
+set ytics border out nomirror
+set y2tics border out nomirror
+set title "$title"
+plot "$file" using 1:5 with lines axes x1y1 title "height",\
+"$file" using 1:9 with lines axes x1y2 title "gyro rot", \
+"$file" using 1:7 with lines axes x1y2 title "gyro tilt", \
+"$file" using 1:13 with lines axes x1y2 title "mag rot", \
+"$file" using 1:11 with lines axes x1y2 title "mag tilt"
+EOF
index 5f5bd2ca745cba12e56e36a7753b9a207a09a223..27f8ddcdeedc832fab8a40574195551850c72c26 100755 (executable)
@@ -1,11 +1,29 @@
+#!/bin/sh
+
+case $# in
+1)
+       file="$1"
+       title="$1"
+       ;;
+2)
+       file="$1"
+       title="$2"
+       ;;
+*)
+       echo "Usage: $0 <data-file> <title>"
+       exit 1
+esac
+
 gnuplot -persist << EOF
-set ylabel "altitude (m)"
+set ylabel "distance (m)"
 set y2label "angle (d)"
 set xlabel "time (s)"
 set xtics border out nomirror
 set ytics border out nomirror
 set y2tics border out nomirror
-plot "$1" using 1:3 with lines axes x1y1 title "raw height",\
-"$1" using 1:9 with lines axes x1y2 title "angle",\
-"$1" using 1:11 with lines axes x1y2 title "qangle"
+set title "$title"
+plot "$file" using 1:5 with lines axes x1y1 title "height",\
+"$file" using 1:7 with lines axes x1y2 title "angle",\
+"$file" using 1:13 with lines axes x1y2 title "gps angle",\
+"$file" using 1:15 with lines axes x1y2 title "sats"
 EOF
diff --git a/src/test/run-all-mm b/src/test/run-all-mm
new file mode 100755 (executable)
index 0000000..d9c2043
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+./run-mm `cat mega.flights`
index 6f3d97a23e2565c32b5869dd839e8e4a649ed97c..ae5e5f4226252f6e9ea7d6973a72e478189edbc4 100755 (executable)
@@ -3,15 +3,20 @@
 DIR=~/misc/rockets/flights
 
 for i in "$@"; do
-case "$i" in
-    */*)
-    file="$i"
-    ;;
-    *)
-    file="$DIR/$i"
-    ;;
-esac
-./ao_flight_test_mm "$file" > run-out.mm
+    case "$i" in
+       */*)
+       file="$i"
+       ;;
+       *)
+       file="$DIR/$i"
+       ;;
+    esac
+    base=`basename "$i" .eeprom`
+
+    ./ao_flight_test_mm "$file" > $base.plot
+
+    sh ./plotmm $base.plot `basename "$file"`
+done
 
 #./ao_flight_test_accel "$file" > run-out.accel
 #"run-out.accel" using 1:9 with lines lt 4 axes x1y1 title "accel height",\
@@ -21,21 +26,21 @@ esac
 #"run-out.accel" using 1:17 with lines lt 4 axes x1y1 title "accel main",\
 #
 
-gnuplot << EOF
-set ylabel "altitude (m)"
-set y2label "velocity (m/s), acceleration(m/s²)"
-set xlabel "time (s)"
-set xtics border out nomirror
-set ytics border out nomirror
-set y2tics border out nomirror
-set title "$i"
-plot "run-out.mm" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\
-"run-out.mm" using 1:5 with lines lw 2 lt 1 axes x1y2 title "raw accel",\
-"run-out.mm" using 1:21 with lines lt 2 axes x1y1 title "mm height",\
-"run-out.mm" using 1:23 with lines lt 2 axes x1y2 title "mm speed",\
-"run-out.mm" using 1:25 with lines lt 2 axes x1y2 title "mm accel",\
-"run-out.mm" using 1:29 with lines lt 2 axes x1y1 title "mm drogue",\
-"run-out.mm" using 1:31 with lines lt 2 axes x1y1 title "mm main"
-pause mouse close
-EOF
-done
\ No newline at end of file
+#gnuplot << EOF
+#set ylabel "altitude (m)"
+#set y2label "velocity (m/s), acceleration(m/s²)"
+#set xlabel "time (s)"
+#set xtics border out nomirror
+#set ytics border out nomirror
+#set y2tics border out nomirror
+#set title "$i"
+#plot "run-out.mm" using 1:3 with lines lw 2 lt 1 axes x1y1 title "raw height",\
+#"run-out.mm" using 1:5 with lines lw 2 lt 1 axes x1y2 title "raw accel",\
+#"run-out.mm" using 1:21 with lines lt 2 axes x1y1 title "mm height",\
+#"run-out.mm" using 1:23 with lines lt 2 axes x1y2 title "mm speed",\
+#"run-out.mm" using 1:25 with lines lt 2 axes x1y2 title "mm accel",\
+#"run-out.mm" using 1:29 with lines lt 2 axes x1y1 title "mm drogue",\
+#"run-out.mm" using 1:31 with lines lt 2 axes x1y1 title "mm main"
+#pause mouse close
+#EOF
+#done
\ No newline at end of file
index 1514c4dfe9f639fd43f59ab30f4058b16ec72b3f..b2ba537bfc36336e6fa82f18e489c4882fc95340 100644 (file)
@@ -72,10 +72,10 @@ endif
 # Otherwise, print the full command line.
 quiet ?= $($1)
 
-all: ../$(PROG)
+all: $(PROG)
 
-../$(PROG): $(REL) Makefile
-       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL) && cp $(PROG) $(PMAP) ..
+$(PROG): $(REL) Makefile
+       $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(REL)
        $(call quiet,CHECK_STACK) ../cc1111/ao_arch.h $(PMEM) || rm $@
 
 ao_product.h: ao-make-product.5c ../Version
index 386dd2869ef1e12f688cb35aa9c27845854e2490..220069b3c3f16a9f575bc9292faf5f715258bec4 100755 (executable)
@@ -33,8 +33,8 @@ DefaultDestDir        = 12
 %TeleMega%     = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial\r
 %MegaDongle    = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial\r
 %TeleGPS%      = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial\r
-%AltusMetrum26%        = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
-%AltusMetrum27%        = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
+%EasyMini%     = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
+%TeleMini%     = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
 %AltusMetrum28%        = AltusMetrum.Install, USB\VID_FFFE&PID_0028, AltusMetrumSerial\r
 %AltusMetrum29%        = AltusMetrum.Install, USB\VID_FFFE&PID_0029, AltusMetrumSerial\r
 %AltusMetrum2a%        = AltusMetrum.Install, USB\VID_FFFE&PID_002a, AltusMetrumSerial\r
@@ -55,8 +55,8 @@ DefaultDestDir        = 12
 %TeleMega%     = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial\r
 %MegaDongle    = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial\r
 %TeleGPS%      = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial\r
-%AltusMetrum26%        = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
-%AltusMetrum27%        = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
+%EasyMini%     = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
+%TeleMini%     = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
 %AltusMetrum28%        = AltusMetrum.Install, USB\VID_FFFE&PID_0028, AltusMetrumSerial\r
 %AltusMetrum29%        = AltusMetrum.Install, USB\VID_FFFE&PID_0029, AltusMetrumSerial\r
 %AltusMetrum2a%        = AltusMetrum.Install, USB\VID_FFFE&PID_002a, AltusMetrumSerial\r
@@ -77,8 +77,8 @@ DefaultDestDir        = 12
 %TeleMega%     = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial\r
 %MegaDongle    = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial\r
 %TeleGPS%      = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial\r
-%AltusMetrum26%        = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
-%AltusMetrum27%        = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
+%EasyMini%     = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
+%TeleMini%     = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
 %AltusMetrum28%        = AltusMetrum.Install, USB\VID_FFFE&PID_0028, AltusMetrumSerial\r
 %AltusMetrum29%        = AltusMetrum.Install, USB\VID_FFFE&PID_0029, AltusMetrumSerial\r
 %AltusMetrum2a%        = AltusMetrum.Install, USB\VID_FFFE&PID_002a, AltusMetrumSerial\r
@@ -99,8 +99,8 @@ DefaultDestDir        = 12
 %TeleMega%     = AltusMetrum.Install, USB\VID_FFFE&PID_0023, AltusMetrumSerial\r
 %MegaDongle    = AltusMetrum.Install, USB\VID_FFFE&PID_0024, AltusMetrumSerial\r
 %TeleGPS%      = AltusMetrum.Install, USB\VID_FFFE&PID_0025, AltusMetrumSerial\r
-%AltusMetrum26%        = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
-%AltusMetrum27%        = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
+%EasyMini%     = AltusMetrum.Install, USB\VID_FFFE&PID_0026, AltusMetrumSerial\r
+%TeleMini%     = AltusMetrum.Install, USB\VID_FFFE&PID_0027, AltusMetrumSerial\r
 %AltusMetrum28%        = AltusMetrum.Install, USB\VID_FFFE&PID_0028, AltusMetrumSerial\r
 %AltusMetrum29%        = AltusMetrum.Install, USB\VID_FFFE&PID_0029, AltusMetrumSerial\r
 %AltusMetrum2a%        = AltusMetrum.Install, USB\VID_FFFE&PID_002a, AltusMetrumSerial\r
@@ -140,7 +140,7 @@ HKR,,DeviceType, 1,         01
 HKR,, Properties, 1, C0,01,00,00, 00,00,00,00, FF,00,00,00, 07,00,00,00, 0F,00,00,00, F7,0F,00,00, 00,84,03,00, C0,DA,00,00\r
 \r
 [Uninstall.AddReg]\r
-HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\%TeleMetrum%,DisplayName,,"%TeleMetrum%"\r
+HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\%AltusMetrum%,DisplayName,,"%AltusMetrum%"\r
 \r
 [Strings]\r
 Mfg            = "altusmetrum.org"\r
@@ -148,5 +148,22 @@ AltusMetrum        = "AltusMetrum"
 TeleMetrum     = "TeleMetrum"\r
 TeleDongle     = "TeleDongle"\r
 TeleTerra      = "TeleTerra"\r
+TeleBT         = "TeleBT"\r
+TeleLaunch     = "TeleLaunch"\r
+TeleLCO                = "TeleLCO"\r
+TeleScience    = "TeleScience"\r
+TelePyro       = "TelePyro"\r
+TeleShield     = "TeleShield"\r
+TeleMega       = "TeleMega"\r
+MegaDongle     = "MegaDongle"\r
+TeleGPS                = "TeleGPS"\r
+EasyMini       = "EasyMini"\r
+TeleMini       = "TeleMini"\r
+AltusMetrum28  = "AltusMetrum28"\r
+AltusMetrum29  = "AltusMetrum29"\r
+AltusMetrum2a  = "AltusMetrum2a"\r
+AltusMetrum2b  = "AltusMetrum2b"\r
+AltusMetrum2c  = "AltusMetrum2c"\r
+\r
 DriverName     = "Altus Metrum Device Driver"\r
 \r