Merge branch 'branch-1.4' into debian
authorBdale Garbee <bdale@gag.com>
Sun, 15 Jun 2014 23:47:41 +0000 (17:47 -0600)
committerBdale Garbee <bdale@gag.com>
Sun, 15 Jun 2014 23:47:41 +0000 (17:47 -0600)
724 files changed:
ChangeLog
Makefile.am
Releasing
altosdroid/Makefile.am
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/AltosViewPager.java
altosdroid/src/org/altusmetrum/AltosDroid/AltosVoice.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/AltosCSV.java [new file with mode: 0644]
altoslib/AltosCompanion.java
altoslib/AltosConfigData.java
altoslib/AltosConfigDataException.java [new file with mode: 0644]
altoslib/AltosConfigValues.java
altoslib/AltosConvert.java
altoslib/AltosDebug.java
altoslib/AltosDistance.java
altoslib/AltosEeprom.java
altoslib/AltosEepromChunk.java
altoslib/AltosEepromDownload.java
altoslib/AltosEepromFile.java
altoslib/AltosEepromGPS.java [new file with mode: 0644]
altoslib/AltosEepromHeader.java
altoslib/AltosEepromIterable.java
altoslib/AltosEepromList.java
altoslib/AltosEepromLog.java
altoslib/AltosEepromMega.java
altoslib/AltosEepromMetrum2.java
altoslib/AltosEepromMini.java
altoslib/AltosEepromMonitor.java
altoslib/AltosEepromTM.java
altoslib/AltosEepromTm.java
altoslib/AltosFile.java
altoslib/AltosFlash.java
altoslib/AltosFlashListener.java
altoslib/AltosFlightReader.java
altoslib/AltosFlightStats.java [new file with mode: 0644]
altoslib/AltosFrequency.java
altoslib/AltosGPS.java
altoslib/AltosGPSSat.java
altoslib/AltosGreatCircle.java
altoslib/AltosHeight.java
altoslib/AltosHexfile.java
altoslib/AltosHexsym.java
altoslib/AltosIMU.java
altoslib/AltosIdle.java
altoslib/AltosIdleFetch.java
altoslib/AltosIdleMonitor.java
altoslib/AltosIdleMonitorListener.java
altoslib/AltosIgnite.java
altoslib/AltosKML.java [new file with mode: 0644]
altoslib/AltosLatitude.java [new file with mode: 0644]
altoslib/AltosLib.java
altoslib/AltosLine.java
altoslib/AltosLink.java
altoslib/AltosListenerState.java
altoslib/AltosLocation.java [new file with mode: 0644]
altoslib/AltosLog.java
altoslib/AltosLongitude.java [new file with mode: 0644]
altoslib/AltosMag.java
altoslib/AltosMma655x.java
altoslib/AltosMs5607.java
altoslib/AltosNoSymbol.java
altoslib/AltosOrient.java
altoslib/AltosParse.java
altoslib/AltosPreferences.java
altoslib/AltosPreferencesBackend.java
altoslib/AltosProgrammer.java
altoslib/AltosPyro.java
altoslib/AltosReplayReader.java
altoslib/AltosRomconfig.java
altoslib/AltosSelfFlash.java
altoslib/AltosSensorEMini.java
altoslib/AltosSensorMM.java
altoslib/AltosSensorMega.java
altoslib/AltosSensorMetrum.java
altoslib/AltosSensorTM.java
altoslib/AltosSensorTMini.java
altoslib/AltosSpeed.java
altoslib/AltosState.java
altoslib/AltosStateIterable.java
altoslib/AltosStateUpdate.java
altoslib/AltosTelemetry.java
altoslib/AltosTelemetryConfiguration.java
altoslib/AltosTelemetryFile.java
altoslib/AltosTelemetryIterable.java
altoslib/AltosTelemetryLegacy.java
altoslib/AltosTelemetryLocation.java
altoslib/AltosTelemetryMap.java
altoslib/AltosTelemetryMegaData.java
altoslib/AltosTelemetryMegaSensor.java
altoslib/AltosTelemetryMetrumData.java
altoslib/AltosTelemetryMetrumSensor.java
altoslib/AltosTelemetryMini.java
altoslib/AltosTelemetryRaw.java
altoslib/AltosTelemetryReader.java
altoslib/AltosTelemetrySatellite.java
altoslib/AltosTelemetrySensor.java
altoslib/AltosTelemetryStandard.java
altoslib/AltosTemperature.java
altoslib/AltosUnits.java
altoslib/AltosUnitsListener.java
altoslib/AltosVoltage.java [new file with mode: 0644]
altoslib/AltosWriter.java [new file with mode: 0644]
altoslib/Makefile.am
altosui/.gitignore
altosui/Altos.java
altosui/AltosAscent.java
altosui/AltosBTDevice.java [deleted file]
altosui/AltosBTDeviceIterator.java [deleted file]
altosui/AltosBTKnown.java [deleted file]
altosui/AltosBTManage.java [deleted file]
altosui/AltosCSV.java [deleted file]
altosui/AltosCSVUI.java [deleted file]
altosui/AltosChannelMenu.java
altosui/AltosCompanionInfo.java
altosui/AltosConfig.java
altosui/AltosConfigFreqUI.java [deleted file]
altosui/AltosConfigPyroUI.java
altosui/AltosConfigTD.java
altosui/AltosConfigTDUI.java
altosui/AltosConfigUI.java
altosui/AltosConfigureUI.java
altosui/AltosDataChooser.java [deleted file]
altosui/AltosDescent.java
altosui/AltosDeviceUIDialog.java [deleted file]
altosui/AltosDisplayThread.java [deleted file]
altosui/AltosEepromDelete.java [deleted file]
altosui/AltosEepromManage.java [deleted file]
altosui/AltosEepromMonitor.java [deleted file]
altosui/AltosEepromMonitorUI.java [deleted file]
altosui/AltosEepromSelect.java [deleted file]
altosui/AltosFlashUI.java [deleted file]
altosui/AltosFlightDisplay.java [deleted file]
altosui/AltosFlightInfoTableModel.java [deleted file]
altosui/AltosFlightStats.java [deleted file]
altosui/AltosFlightStatsTable.java [deleted file]
altosui/AltosFlightStatus.java
altosui/AltosFlightStatusTableModel.java
altosui/AltosFlightStatusUpdate.java
altosui/AltosFlightUI.java
altosui/AltosFreqList.java [deleted file]
altosui/AltosGraph.java [deleted file]
altosui/AltosGraphDataPoint.java [deleted file]
altosui/AltosGraphDataSet.java [deleted file]
altosui/AltosGraphUI.java
altosui/AltosIdleMonitorUI.java
altosui/AltosIgniteUI.java
altosui/AltosIgnitor.java [new file with mode: 0644]
altosui/AltosInfoTable.java [deleted file]
altosui/AltosKML.java [deleted file]
altosui/AltosLanded.java
altosui/AltosLaunch.java
altosui/AltosLaunchUI.java
altosui/AltosLed.java [deleted file]
altosui/AltosLights.java [deleted file]
altosui/AltosPad.java
altosui/AltosRomconfigUI.java [deleted file]
altosui/AltosScanUI.java [deleted file]
altosui/AltosSerial.java [deleted file]
altosui/AltosSerialInUseException.java [deleted file]
altosui/AltosSiteMap.java [deleted file]
altosui/AltosSiteMapCache.java [deleted file]
altosui/AltosSiteMapPreload.java [deleted file]
altosui/AltosSiteMapTile.java [deleted file]
altosui/AltosUI.app/Contents/Resources/AltosUIIcon.icns [deleted file]
altosui/AltosUI.java
altosui/AltosUIPreferencesBackend.java
altosui/AltosVoice.java [deleted file]
altosui/AltosWriter.java [deleted file]
altosui/GrabNDrag.java [deleted file]
altosui/Makefile-standalone
altosui/Makefile.am
altosui/altos-windows.nsi.in
altosui/altos.desktop.in [new file with mode: 0644]
altosui/linux-install.sh [new file with mode: 0644]
altosuilib/AltosBTDevice.java [new file with mode: 0644]
altosuilib/AltosBTDeviceIterator.java [new file with mode: 0644]
altosuilib/AltosBTKnown.java [new file with mode: 0644]
altosuilib/AltosBTManage.java [new file with mode: 0644]
altosuilib/AltosCSVUI.java [new file with mode: 0644]
altosuilib/AltosConfigFreqUI.java [new file with mode: 0644]
altosuilib/AltosDataChooser.java [new file with mode: 0644]
altosuilib/AltosDevice.java
altosuilib/AltosDeviceDialog.java
altosuilib/AltosDeviceUIDialog.java [new file with mode: 0644]
altosuilib/AltosDisplayThread.java [new file with mode: 0644]
altosuilib/AltosEepromDelete.java [new file with mode: 0644]
altosuilib/AltosEepromManage.java [new file with mode: 0644]
altosuilib/AltosEepromMonitor.java [new file with mode: 0644]
altosuilib/AltosEepromMonitorUI.java [new file with mode: 0644]
altosuilib/AltosEepromSelect.java [new file with mode: 0644]
altosuilib/AltosFlashUI.java [new file with mode: 0644]
altosuilib/AltosFlightDisplay.java [new file with mode: 0644]
altosuilib/AltosFlightInfoTableModel.java [new file with mode: 0644]
altosuilib/AltosFlightStatsTable.java [new file with mode: 0644]
altosuilib/AltosFontListener.java
altosuilib/AltosFreqList.java [new file with mode: 0644]
altosuilib/AltosGraph.java [new file with mode: 0644]
altosuilib/AltosGraphDataPoint.java [new file with mode: 0644]
altosuilib/AltosGraphDataSet.java [new file with mode: 0644]
altosuilib/AltosInfoTable.java [new file with mode: 0644]
altosuilib/AltosLed.java [new file with mode: 0644]
altosuilib/AltosLights.java [new file with mode: 0644]
altosuilib/AltosPositionListener.java
altosuilib/AltosRomconfigUI.java [new file with mode: 0644]
altosuilib/AltosScanUI.java [new file with mode: 0644]
altosuilib/AltosSerial.java [new file with mode: 0644]
altosuilib/AltosSerialInUseException.java [new file with mode: 0644]
altosuilib/AltosUIAxis.java
altosuilib/AltosUIConfigure.java
altosuilib/AltosUIDataMissing.java
altosuilib/AltosUIDataPoint.java
altosuilib/AltosUIDataSet.java
altosuilib/AltosUIDialog.java
altosuilib/AltosUIEnable.java
altosuilib/AltosUIFlightTab.java [new file with mode: 0644]
altosuilib/AltosUIFrame.java
altosuilib/AltosUIGraph.java
altosuilib/AltosUIGrapher.java
altosuilib/AltosUIIndicator.java [new file with mode: 0644]
altosuilib/AltosUILatLon.java [new file with mode: 0644]
altosuilib/AltosUILib.java
altosuilib/AltosUIListener.java
altosuilib/AltosUIMap.java [new file with mode: 0644]
altosuilib/AltosUIMapCache.java [new file with mode: 0644]
altosuilib/AltosUIMapImage.java [new file with mode: 0644]
altosuilib/AltosUIMapLine.java [new file with mode: 0644]
altosuilib/AltosUIMapMark.java [new file with mode: 0644]
altosuilib/AltosUIMapPath.java [new file with mode: 0644]
altosuilib/AltosUIMapPreload.java [new file with mode: 0644]
altosuilib/AltosUIMapRectangle.java [new file with mode: 0644]
altosuilib/AltosUIMapStore.java [new file with mode: 0644]
altosuilib/AltosUIMapStoreListener.java [new file with mode: 0644]
altosuilib/AltosUIMapTile.java [new file with mode: 0644]
altosuilib/AltosUIMapTileListener.java [new file with mode: 0644]
altosuilib/AltosUIMapTransform.java [new file with mode: 0644]
altosuilib/AltosUIMapView.java [new file with mode: 0644]
altosuilib/AltosUIMapZoomListener.java [new file with mode: 0644]
altosuilib/AltosUIMarker.java
altosuilib/AltosUIPreferences.java
altosuilib/AltosUIPreferencesBackend.java
altosuilib/AltosUISeries.java
altosuilib/AltosUIUnitsIndicator.java [new file with mode: 0644]
altosuilib/AltosUIVersion.java.in
altosuilib/AltosUIVoltageIndicator.java [new file with mode: 0644]
altosuilib/AltosUSBDevice.java
altosuilib/AltosVoice.java [new file with mode: 0644]
altosuilib/GrabNDrag.java [new file with mode: 0644]
altosuilib/Makefile.am
altusmetrum.cat [new file with mode: 0644]
altusmetrum.inf [new file with mode: 0755]
ao-bringup/cal-freq
ao-bringup/test-baro [new file with mode: 0755]
ao-bringup/test-easymini [new file with mode: 0755]
ao-bringup/test-flash [new file with mode: 0755]
ao-bringup/test-gps [new file with mode: 0755]
ao-bringup/test-igniter [new file with mode: 0755]
ao-bringup/test-telegps [new file with mode: 0755]
ao-bringup/turnon_easymini [new file with mode: 0755]
ao-bringup/turnon_telebt
ao-bringup/turnon_teledongle
ao-bringup/turnon_telegps [new file with mode: 0755]
ao-bringup/turnon_telemega
ao-bringup/turnon_telemetrum
ao-tools/ao-flash/ao-flash-lpc [changed mode: 0644->0755]
ao-tools/ao-load/ao-load.c
ao-tools/ao-telem/ao-telem.c
ao-tools/ao-usbload/ao-usbload.c
ao-tools/lib/ao-editaltos.c
ao-tools/lib/ao-hex.h
ao-tools/lib/cc-telemetry.h
ao-tools/lib/cc-usb.c
ao-tools/lib/cc-usb.h
configure.ac
debian/altos.desktop [deleted file]
debian/altos.install
debian/control
doc/Makefile
doc/altos.xsl
doc/altusmetrum.xsl
doc/ascent.png
doc/configure-altimeter.png
doc/configure-pyro.png
doc/descent.png
doc/easymini-outline.pdf [deleted file]
doc/easymini-outline.svg [deleted file]
doc/easymini-outline.xsl [new file with mode: 0644]
doc/easymini.svg [new file with mode: 0644]
doc/graph-configure.png
doc/graph-map.png
doc/ignitor.png [new file with mode: 0644]
doc/landed.png
doc/launch-pad.png
doc/load-maps.png
doc/micropeak.xsl
doc/release-notes-1.4.xsl [new file with mode: 0644]
doc/site-map.png
doc/telegps-configure.png [new file with mode: 0644]
doc/telegps-graph-configure.png [new file with mode: 0644]
doc/telegps-graph-graph.png [new file with mode: 0644]
doc/telegps-graph-map.png [new file with mode: 0644]
doc/telegps-graph-stats.png [new file with mode: 0644]
doc/telegps-info.png [new file with mode: 0644]
doc/telegps-location.png [new file with mode: 0644]
doc/telegps-map.png [new file with mode: 0644]
doc/telegps-preferences.png [new file with mode: 0644]
doc/telegps-scan.png [new file with mode: 0644]
doc/telegps-status.png [new file with mode: 0644]
doc/telegps-table.png [new file with mode: 0644]
doc/telegps-v1.0-top.jpg [new file with mode: 0644]
doc/telegps.xsl [new file with mode: 0644]
doc/telemega-outline.pdf [deleted file]
doc/telemega-outline.svg [deleted file]
doc/telemega-outline.xsl [new file with mode: 0644]
doc/telemega.svg [new file with mode: 0644]
doc/telemetrum-outline.pdf [deleted file]
doc/telemetrum-outline.svg [deleted file]
doc/telemetrum-outline.xsl [new file with mode: 0644]
doc/telemetrum.svg
doc/telemini.svg
icon/.gitignore [new file with mode: 0644]
icon/Makefile.am [new file with mode: 0644]
icon/altus-metrum-128.png [deleted file]
icon/altus-metrum-16.png [deleted file]
icon/altus-metrum-256.png [deleted file]
icon/altus-metrum-32.png [deleted file]
icon/altus-metrum-48.png [deleted file]
icon/altus-metrum-512.png [deleted file]
icon/altus-metrum-64.png [deleted file]
icon/altus-metrum.ico [deleted file]
icon/altusmetrum.svg [new file with mode: 0644]
icon/micro-peak.ico [deleted file]
icon/micropeak-128.png [deleted file]
icon/micropeak-16.png [deleted file]
icon/micropeak-256.png [deleted file]
icon/micropeak-32.png [deleted file]
icon/micropeak-48.png [deleted file]
icon/micropeak-64.png [deleted file]
icon/micropeak.svg [new file with mode: 0644]
icon/telegps.svg [new file with mode: 0644]
jenkins.sh [new file with mode: 0755]
libaltos/Makefile.am
libaltos/libaltos.c
micropeak/.gitignore
micropeak/Makefile.am
micropeak/MicroData.java
micropeak/MicroDataPoint.java
micropeak/MicroDeviceDialog.java
micropeak/MicroDownload.java
micropeak/MicroExport.java
micropeak/MicroFile.java
micropeak/MicroFileChooser.java
micropeak/MicroFrame.java
micropeak/MicroGraph.java
micropeak/MicroPeak.java
micropeak/MicroRaw.java
micropeak/MicroSave.java
micropeak/MicroSerial.java
micropeak/MicroSerialLog.java
micropeak/MicroStats.java
micropeak/MicroStatsTable.java
micropeak/MicroUSB.java
micropeak/micropeak-windows.nsi.in
micropeak/micropeak.desktop.in [new file with mode: 0644]
signing-driver [new file with mode: 0644]
src/Makefile
src/attiny/ao_async.c
src/avr-demo/Makefile
src/avr/ao_usb_avr.c
src/cc1111/Makefile.cc1111
src/cc1111/ao_arch.h
src/cc1111/ao_pins.h
src/cc1111/ao_timer.c
src/cc1111/ao_usb.c
src/core/altitude.h [deleted file]
src/core/ao.h [deleted file]
src/core/ao_adc.h [deleted file]
src/core/ao_aes.h [deleted file]
src/core/ao_beep.h [deleted file]
src/core/ao_btm.h [deleted file]
src/core/ao_cmd.c [deleted file]
src/core/ao_companion.h [deleted file]
src/core/ao_config.c [deleted file]
src/core/ao_config.h [deleted file]
src/core/ao_convert.c [deleted file]
src/core/ao_convert_pa.c [deleted file]
src/core/ao_convert_pa_test.c [deleted file]
src/core/ao_convert_test.c [deleted file]
src/core/ao_convert_volt.c [deleted file]
src/core/ao_data.c [deleted file]
src/core/ao_data.h [deleted file]
src/core/ao_dbg.h [deleted file]
src/core/ao_debounce.c [deleted file]
src/core/ao_debounce.h [deleted file]
src/core/ao_ee_fake.c [deleted file]
src/core/ao_eeprom.h [deleted file]
src/core/ao_fec.h [deleted file]
src/core/ao_fec_rx.c [deleted file]
src/core/ao_fec_tx.c [deleted file]
src/core/ao_flight.c [deleted file]
src/core/ao_flight.h [deleted file]
src/core/ao_flight_nano.c [deleted file]
src/core/ao_freq.c [deleted file]
src/core/ao_gps_print.c [deleted file]
src/core/ao_gps_report.c [deleted file]
src/core/ao_gps_report_mega.c [deleted file]
src/core/ao_gps_report_metrum.c [deleted file]
src/core/ao_gps_show.c [deleted file]
src/core/ao_host.h [deleted file]
src/core/ao_ignite.c [deleted file]
src/core/ao_int64.c [deleted file]
src/core/ao_int64.h [deleted file]
src/core/ao_kalman.c [deleted file]
src/core/ao_lcd.h [deleted file]
src/core/ao_led.h [deleted file]
src/core/ao_list.h [deleted file]
src/core/ao_log.c [deleted file]
src/core/ao_log.h [deleted file]
src/core/ao_log_big.c [deleted file]
src/core/ao_log_mega.c [deleted file]
src/core/ao_log_metrum.c [deleted file]
src/core/ao_log_micro.c [deleted file]
src/core/ao_log_micro.h [deleted file]
src/core/ao_log_mini.c [deleted file]
src/core/ao_log_single.c [deleted file]
src/core/ao_log_telem.c [deleted file]
src/core/ao_log_telescience.c [deleted file]
src/core/ao_log_tiny.c [deleted file]
src/core/ao_microflight.c [deleted file]
src/core/ao_microkalman.c [deleted file]
src/core/ao_monitor.c [deleted file]
src/core/ao_mutex.c [deleted file]
src/core/ao_notask.c [deleted file]
src/core/ao_notask.h [deleted file]
src/core/ao_packet.h [deleted file]
src/core/ao_panic.c [deleted file]
src/core/ao_product.c [deleted file]
src/core/ao_pyro.c [deleted file]
src/core/ao_pyro.h [deleted file]
src/core/ao_quaternion.h [deleted file]
src/core/ao_radio_cmac.c [deleted file]
src/core/ao_radio_cmac.h [deleted file]
src/core/ao_radio_cmac_cmd.c [deleted file]
src/core/ao_radio_cmac_cmd.h [deleted file]
src/core/ao_report.c [deleted file]
src/core/ao_report_micro.c [deleted file]
src/core/ao_rssi.c [deleted file]
src/core/ao_sample.c [deleted file]
src/core/ao_sample.h [deleted file]
src/core/ao_sample_profile.c [deleted file]
src/core/ao_sample_profile.h [deleted file]
src/core/ao_send_packet.c [deleted file]
src/core/ao_send_packet.h [deleted file]
src/core/ao_serial.h [deleted file]
src/core/ao_sqrt.c [deleted file]
src/core/ao_state.c [deleted file]
src/core/ao_stdio.c [deleted file]
src/core/ao_storage.c [deleted file]
src/core/ao_storage.h [deleted file]
src/core/ao_task.c [deleted file]
src/core/ao_task.h [deleted file]
src/core/ao_telem.h [deleted file]
src/core/ao_telemetry.c [deleted file]
src/core/ao_telemetry.h [deleted file]
src/core/ao_usb.h [deleted file]
src/drivers/ao_aprs.c
src/drivers/ao_cc115l.c
src/drivers/ao_gps_ublox.c
src/drivers/ao_lco_func.c
src/drivers/ao_ms5607.c
src/drivers/ao_ms5607.h
src/drivers/ao_ms5607_convert.c
src/drivers/ao_ms5607_convert_8051.c
src/drivers/ao_pad.c
src/drivers/ao_pca9922.c
src/drivers/ao_quadrature.c
src/easymega-v0.1/.gitignore [new file with mode: 0644]
src/easymega-v0.1/Makefile [new file with mode: 0644]
src/easymega-v0.1/ao_easymega.c [new file with mode: 0644]
src/easymega-v0.1/ao_pins.h [new file with mode: 0644]
src/easymega-v0.1/flash-loader/Makefile [new file with mode: 0644]
src/easymega-v0.1/flash-loader/ao_pins.h [new file with mode: 0644]
src/easymini-v1.0/Makefile
src/easymini-v1.0/ao_pins.h
src/kernel/altitude.h [new file with mode: 0644]
src/kernel/ao.h [new file with mode: 0644]
src/kernel/ao_adc.h [new file with mode: 0644]
src/kernel/ao_aes.h [new file with mode: 0644]
src/kernel/ao_balloon.c [new file with mode: 0644]
src/kernel/ao_beep.h [new file with mode: 0644]
src/kernel/ao_boot.h [new file with mode: 0644]
src/kernel/ao_btm.h [new file with mode: 0644]
src/kernel/ao_cmd.c [new file with mode: 0644]
src/kernel/ao_companion.h [new file with mode: 0644]
src/kernel/ao_config.c [new file with mode: 0644]
src/kernel/ao_config.h [new file with mode: 0644]
src/kernel/ao_convert.c [new file with mode: 0644]
src/kernel/ao_convert_pa.c [new file with mode: 0644]
src/kernel/ao_convert_pa_test.c [new file with mode: 0644]
src/kernel/ao_convert_test.c [new file with mode: 0644]
src/kernel/ao_convert_volt.c [new file with mode: 0644]
src/kernel/ao_data.c [new file with mode: 0644]
src/kernel/ao_data.h [new file with mode: 0644]
src/kernel/ao_dbg.h [new file with mode: 0644]
src/kernel/ao_debounce.c [new file with mode: 0644]
src/kernel/ao_debounce.h [new file with mode: 0644]
src/kernel/ao_distance.c [new file with mode: 0644]
src/kernel/ao_distance.h [new file with mode: 0644]
src/kernel/ao_ee_fake.c [new file with mode: 0644]
src/kernel/ao_eeprom.h [new file with mode: 0644]
src/kernel/ao_fake_flight.c [new file with mode: 0644]
src/kernel/ao_fake_flight.h [new file with mode: 0644]
src/kernel/ao_fec.h [new file with mode: 0644]
src/kernel/ao_fec_rx.c [new file with mode: 0644]
src/kernel/ao_fec_tx.c [new file with mode: 0644]
src/kernel/ao_flight.c [new file with mode: 0644]
src/kernel/ao_flight.h [new file with mode: 0644]
src/kernel/ao_flight_nano.c [new file with mode: 0644]
src/kernel/ao_freq.c [new file with mode: 0644]
src/kernel/ao_gps_print.c [new file with mode: 0644]
src/kernel/ao_gps_report.c [new file with mode: 0644]
src/kernel/ao_gps_report_mega.c [new file with mode: 0644]
src/kernel/ao_gps_report_metrum.c [new file with mode: 0644]
src/kernel/ao_gps_show.c [new file with mode: 0644]
src/kernel/ao_host.h [new file with mode: 0644]
src/kernel/ao_ignite.c [new file with mode: 0644]
src/kernel/ao_int64.c [new file with mode: 0644]
src/kernel/ao_int64.h [new file with mode: 0644]
src/kernel/ao_kalman.c [new file with mode: 0644]
src/kernel/ao_lcd.h [new file with mode: 0644]
src/kernel/ao_led.h [new file with mode: 0644]
src/kernel/ao_list.h [new file with mode: 0644]
src/kernel/ao_log.c [new file with mode: 0644]
src/kernel/ao_log.h [new file with mode: 0644]
src/kernel/ao_log_big.c [new file with mode: 0644]
src/kernel/ao_log_gps.c [new file with mode: 0644]
src/kernel/ao_log_gps.h [new file with mode: 0644]
src/kernel/ao_log_mega.c [new file with mode: 0644]
src/kernel/ao_log_metrum.c [new file with mode: 0644]
src/kernel/ao_log_micro.c [new file with mode: 0644]
src/kernel/ao_log_micro.h [new file with mode: 0644]
src/kernel/ao_log_mini.c [new file with mode: 0644]
src/kernel/ao_log_single.c [new file with mode: 0644]
src/kernel/ao_log_telem.c [new file with mode: 0644]
src/kernel/ao_log_telescience.c [new file with mode: 0644]
src/kernel/ao_log_tiny.c [new file with mode: 0644]
src/kernel/ao_microflight.c [new file with mode: 0644]
src/kernel/ao_microkalman.c [new file with mode: 0644]
src/kernel/ao_monitor.c [new file with mode: 0644]
src/kernel/ao_mutex.c [new file with mode: 0644]
src/kernel/ao_notask.c [new file with mode: 0644]
src/kernel/ao_notask.h [new file with mode: 0644]
src/kernel/ao_packet.h [new file with mode: 0644]
src/kernel/ao_panic.c [new file with mode: 0644]
src/kernel/ao_product.c [new file with mode: 0644]
src/kernel/ao_pyro.c [new file with mode: 0644]
src/kernel/ao_pyro.h [new file with mode: 0644]
src/kernel/ao_quaternion.h [new file with mode: 0644]
src/kernel/ao_radio_cmac.c [new file with mode: 0644]
src/kernel/ao_radio_cmac.h [new file with mode: 0644]
src/kernel/ao_radio_cmac_cmd.c [new file with mode: 0644]
src/kernel/ao_radio_cmac_cmd.h [new file with mode: 0644]
src/kernel/ao_report.c [new file with mode: 0644]
src/kernel/ao_report_micro.c [new file with mode: 0644]
src/kernel/ao_rssi.c [new file with mode: 0644]
src/kernel/ao_sample.c [new file with mode: 0644]
src/kernel/ao_sample.h [new file with mode: 0644]
src/kernel/ao_sample_profile.c [new file with mode: 0644]
src/kernel/ao_sample_profile.h [new file with mode: 0644]
src/kernel/ao_send_packet.c [new file with mode: 0644]
src/kernel/ao_send_packet.h [new file with mode: 0644]
src/kernel/ao_serial.h [new file with mode: 0644]
src/kernel/ao_sqrt.c [new file with mode: 0644]
src/kernel/ao_state.c [new file with mode: 0644]
src/kernel/ao_stdio.c [new file with mode: 0644]
src/kernel/ao_storage.c [new file with mode: 0644]
src/kernel/ao_storage.h [new file with mode: 0644]
src/kernel/ao_task.c [new file with mode: 0644]
src/kernel/ao_task.h [new file with mode: 0644]
src/kernel/ao_telem.h [new file with mode: 0644]
src/kernel/ao_telemetry.c [new file with mode: 0644]
src/kernel/ao_telemetry.h [new file with mode: 0644]
src/kernel/ao_tracker.c [new file with mode: 0644]
src/kernel/ao_tracker.h [new file with mode: 0644]
src/kernel/ao_usb.h [new file with mode: 0644]
src/lpc/Makefile-lpc.defs
src/lpc/ao_adc_lpc.c
src/lpc/ao_arch.h
src/lpc/ao_boot.h [deleted file]
src/lpc/ao_boot_chain.c
src/lpc/ao_exti_lpc.c
src/lpc/ao_interrupt.c
src/lpc/ao_led_lpc.c
src/lpc/ao_serial_lpc.c
src/lpc/ao_usb_lpc.c
src/lpcxpresso/ao_pins.h
src/megadongle-v0.1/Makefile
src/micropeak/Makefile
src/microwater/.gitignore [new file with mode: 0644]
src/microwater/Makefile [new file with mode: 0644]
src/microwater/ao_pins.h [new file with mode: 0644]
src/nanopeak-v0.1/Makefile
src/product/Makefile.teledongle
src/product/Makefile.telelaunch
src/product/Makefile.telemetrum
src/product/Makefile.telemini
src/product/Makefile.telenano
src/product/ao_flash_task.c
src/product/ao_micropeak.h
src/spiradio-v0.1/.sdcdbrc
src/spiradio-v0.1/Makefile
src/stm-bringup/Makefile
src/stm-demo/Makefile
src/stm-demo/ao_demo.c
src/stm-demo/ao_pins.h
src/stm-demo/flash-loader/Makefile [new file with mode: 0644]
src/stm-demo/flash-loader/ao_pins.h [new file with mode: 0644]
src/stm-flash/Makefile
src/stm/Makefile-flash.defs
src/stm/Makefile.defs
src/stm/ao_arch.h
src/stm/ao_boot.h [deleted file]
src/stm/ao_boot_chain.c
src/stm/ao_boot_pin.c
src/stm/ao_fast_timer.c
src/stm/ao_interrupt.c
src/stm/ao_timer.c
src/stm/ao_usb_stm.c
src/stm/registers.ld
src/stm/stm32l.h
src/teleballoon-v1.1/Makefile
src/teleballoon-v1.1/ao_balloon.c [deleted file]
src/teleballoon-v1.1/ao_pins.h
src/teleballoon-v2.0/.gitignore [new file with mode: 0644]
src/teleballoon-v2.0/Makefile [new file with mode: 0644]
src/teleballoon-v2.0/ao_pins.h [new file with mode: 0644]
src/teleballoon-v2.0/ao_teleballoon.c [new file with mode: 0644]
src/telebt-v1.0/.sdcdbrc
src/telebt-v1.0/Makefile
src/telefire-v0.1/.sdcdbrc
src/telefire-v0.1/Makefile
src/telefire-v0.2/.sdcdbrc
src/telefire-v0.2/Makefile
src/telegps-v0.1/Makefile
src/telegps-v0.3/Makefile
src/telegps-v0.3/ao_pins.h
src/telegps-v0.3/ao_telegps.c
src/telegps-v1.0/.gitignore [new file with mode: 0644]
src/telegps-v1.0/Makefile [new file with mode: 0644]
src/telegps-v1.0/ao_pins.h [new file with mode: 0644]
src/telegps-v1.0/ao_telegps.c [new file with mode: 0644]
src/telegps-v1.0/flash-loader/Makefile [new file with mode: 0644]
src/telegps-v1.0/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/telemega-v0.1/ao_pins.h
src/telemega-v1.0/Makefile
src/telemega-v1.0/ao_pins.h
src/telemetrum-v1.0/.sdcdbrc
src/telemetrum-v1.1/.sdcdbrc
src/telemetrum-v1.1/Makefile
src/telemetrum-v1.2/Makefile
src/telemetrum-v2.0/Makefile
src/telemetrum-v2.0/ao_pins.h
src/telemini-v1.0/.sdcdbrc
src/telemini-v2.0/.sdcdbrc
src/telemini-v2.0/Makefile
src/telemini-v2.0/ao_pins.h
src/telepyro-v0.1/Makefile
src/telescience-pwm/Makefile
src/telescience-v0.1/Makefile
src/teleshield-v0.1/Makefile
src/teleterra-v0.2/.sdcdbrc
src/teleterra-v0.2/Makefile
src/test/Makefile
src/test/ao_aprs_test.c
src/test/ao_flight_test.c
src/test/ao_ms5607_convert_test.c
src/tidongle/Makefile
src/usbrelay-v0.1/ao_pins.h [new file with mode: 0644]
src/usbrelay-v0.1/ao_serial_lpc.h [new file with mode: 0644]
src/usbrelay-v0.1/ao_usbrelay.c [new file with mode: 0644]
src/usbrelay-v0.1/flash-loader/ao_pins.h [new file with mode: 0644]
src/usbtrng/Makefile [new file with mode: 0644]
src/usbtrng/ao_pins.h [new file with mode: 0644]
src/usbtrng/ao_usbtrng.c [new file with mode: 0644]
src/usbtrng/flash-loader/Makefile [new file with mode: 0644]
src/usbtrng/flash-loader/ao_pins.h [new file with mode: 0644]
telegps/.gitignore [new file with mode: 0644]
telegps/Info.plist.in [new file with mode: 0644]
telegps/Makefile.am [new file with mode: 0644]
telegps/ReadMe-Mac.rtf [new file with mode: 0644]
telegps/TeleGPS.app/Contents/MacOS/JavaApplicationStub [new file with mode: 0755]
telegps/TeleGPS.app/Contents/PkgInfo [new file with mode: 0644]
telegps/TeleGPS.app/Contents/Resources/TeleGPSIcon.icns [new file with mode: 0644]
telegps/TeleGPS.java [new file with mode: 0644]
telegps/TeleGPSConfig.java [new file with mode: 0644]
telegps/TeleGPSConfigUI.java [new file with mode: 0644]
telegps/TeleGPSDisplayThread.java [new file with mode: 0644]
telegps/TeleGPSGraphUI.java [new file with mode: 0644]
telegps/TeleGPSInfo.java [new file with mode: 0644]
telegps/TeleGPSPreferences.java [new file with mode: 0644]
telegps/TeleGPSState.java [new file with mode: 0644]
telegps/TeleGPSStatus.java [new file with mode: 0644]
telegps/TeleGPSStatusUpdate.java [new file with mode: 0644]
telegps/telegps-fat [new file with mode: 0755]
telegps/telegps-windows.nsi.in [new file with mode: 0644]
telegps/telegps.1 [new file with mode: 0644]
telegps/telegps.desktop.in [new file with mode: 0644]
telemetrum.inf [deleted file]

index 51afdad19891739481ac7888a39baa11b2e95f5a..e8d53477ea646773ac6427b85bb0946f657e5026 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
+commit 97a7cbaee806965ca7c696fb02f6e1d24b026b9b
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Jun 15 17:43:06 2014 -0600
+
+    add release to revision history
+
+commit 79c3dc334d79eacd63bbbbec046fc2c31266560c
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Jun 15 17:40:27 2014 -0600
+
+    tweaks
+
+commit a6c61fb993d3fd15183f8755d9058f05c606c9c0
+Merge: 0634119 4384899
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 15 16:31:01 2014 -0700
+
+    Merge remote-tracking branch 'origin/master'
+
+commit 0634119df45bf8d8a040b47bdfc6d9801b5e069a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 15 16:24:28 2014 -0700
+
+    micropeak: Deal with 64-bit windows
+    
+    Install 64-bit version of java. Install our bits in the 64-bit app directory
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b6eb1ac1b777b6c11e8f24c5ab5915b224101d40
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 15 16:16:59 2014 -0700
+
+    Add notes about windows driver signing in the 'signing-driver' file
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6277827520df4df5ecda58898e5f99035f90282c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 15 16:11:49 2014 -0700
+
+    altosui: Ship telegps firmware
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3b5651d311d4268a130996e71afc11b508e59637
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 15 16:10:15 2014 -0700
+
+    windows: Sign altusmetrum.inf with altusmetrum.cat
+    
+    This .cat file will need to be updated when we get our 'real'
+    signature.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ef6998c2d052bf639f257b71baefacf3a652506f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 15 16:06:42 2014 -0700
+
+    icon: Add drop-shadows to the SVG files; stop generating in the png versions
+    
+    Now everyone gets drop shadows.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 43848991defaeb7fae994101675b0056f9d9a2ed
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Jun 15 17:29:49 2014 -0600
+
+    update Releasing document to include TeleGPS firmware files in those copied
+
+commit 90e03dfc8534fc4fc25f6a5ee9ec109b98baa238
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Jun 15 17:28:02 2014 -0600
+
+    document mounting hole size for TeleGPS
+
+commit 44fc36b3f74386f0055eac4d9b9d201e6fff0847
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 15 16:08:27 2014 -0700
+
+    altosui: Deal with 64-bit windows
+    
+    Get a 64-bit java version installed
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1a563026409ccff5dea6f89e567accb09bc4b5f6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 15 14:09:09 2014 -0700
+
+    telegps: Deal with 64-bit windows differently on install
+    
+    Download a 64-bit version of java as needed, install in 64-bit paths
+    instead of 32-bit paths.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit abf731b3d79b66d9da62496cebf157f2888a4c93
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 15 12:39:49 2014 -0700
+
+    windows: Rename telemetrum.inf to altusmetrum.inf
+    
+    Use the corporate name for this file
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8073007292875169a6304824ae52039ce6564813
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 22:29:01 2014 -0700
+
+    telegps: Include telegps firmware in windows package
+    
+    This was disabled when the firmware wasn't ready yet
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6cad0b783f654864f0d6d8726c74605f108db3e0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 22:23:10 2014 -0700
+
+    altosuilib: Remove some debugging printfs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 823ef386f9dc5c5df197936f4254921f2e0282b0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 20:08:40 2014 -0700
+
+    altoslib: AltosFlightStatsTable: another editable text field that shouldn't be
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5392ee3c5328f8384ed30a2d147e4be96075e064
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 18:51:25 2014 -0700
+
+    altosuilib: Serialize access to async tile notify function in preload
+    
+    This ensures that we see each tile getting downloaded and don't
+    mis-count, which would result in wedging the process
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 23708b4760250f55e8e3b1a0141df9a9ee17a936
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 18:34:09 2014 -0700
+
+    icon: Make the icon shadows a bit less harsh
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4e3318645d08dda483aced97450b344629902c4d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 18:11:28 2014 -0700
+
+    debian: Build requires /usr/bin/convert now
+    
+    This is provided by either graphicsmagick or imagemagick
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 382e27de3472489f8f26c8c0868732d67754ecf5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 18:09:31 2014 -0700
+
+    telegps/micropeak: Ship built Mac OSX icons
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 33da986161c38936cff82fe43046f0bcd5e24d8e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 18:07:39 2014 -0700
+
+    icon: Build resolutions needed for Java bits too
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 66c4a091bb6a294f9d406e75f3634492c886d139
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 18:06:36 2014 -0700
+
+    altosui: Build MacOSX icon from svg
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b825ea71ebcc4a8da3e339ab3e21b0ad47f2e48f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 18:02:51 2014 -0700
+
+    icon: Build windows ico files, clean built files
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4ec960b705b87b15d015abb2a9a3e23eee414f1d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 17:51:46 2014 -0700
+
+    icon: Create all icons from .svg files
+    
+    Remove images from repository, leaving only the svg files and build
+    instructions
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 951fda701ed31f4d8390c130215597e8f63e837e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 16:26:22 2014 -0700
+
+    altosuilib: Make graph enable buttons be CheckBoxes instead of RadioButtons
+    
+    aj noticed.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8e00f59be582de86cef28b33ce5523f39d3dc933
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 16:05:51 2014 -0700
+
+    telegps: Fix Mac icon file name
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 92943bf4536d4167edd097e61de5e6b4f29130f8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 15:44:20 2014 -0700
+
+    micropeak: Make statistics entries un-editable
+    
+    Otherwise you can actually type in the various fields.x
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1fc3032d688cbb7c09c1dffde30cc815f3594e29
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 15:20:07 2014 -0700
+
+    alotsuilib: Remove old "mega" and "mini" file extensions from data chooser
+    
+    We never shipped AltosUI which stored mega/mini files in different extensions
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c11b2f5caa3fbe2bc977e716ec1c3ccee9e75884
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 14:41:13 2014 -0700
+
+    altosui/telegps: Switch to AltosUIIndicator and AltosUIFlightTab
+    
+    Removes replicated code across all flight tabs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f5887a3e7cf993e23dbb1e0f6b9ebece78c34413
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 14:40:24 2014 -0700
+
+    altosuilib: Add AltosUIFlightTab class
+    
+    This covers most of the common functions for all flight status display tabs.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8250777e6e869bcee9781691caa1f2a7cfb33b43
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 14:39:26 2014 -0700
+
+    altosuilib: Add more options to AltosUIIndicator to suit AltosUI
+    
+    This makes AltosUIIndicator capable of displaying most stuff in AltosUI
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 19273a4a341342ca6b5d65cfc490d92cbf23356f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 14:38:00 2014 -0700
+
+    altosuilib: Make sure only one thread is closing serial device
+    
+    Multiple closers can cause a crash by freeing the libaltos device twice
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2903f0911e79e381c6125022bb84096321c258eb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 14:37:35 2014 -0700
+
+    altosuilib: provide getName() for AltosInfoTable
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 242e968a6982f2ceaa79780cbeec8c4e21321b44
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 14:36:49 2014 -0700
+
+    altosuilib: In graph, show zero sats in view as 0 instead of MISSING
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c7553c54765dcc9ac532fe52aae9594b2ad5e560
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 14:36:11 2014 -0700
+
+    altosuilib: Require all flight display classes to provide a name
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 14f0faae48849ff6f1e326a294b54c504c730bb9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 14:34:59 2014 -0700
+
+    altoslib: When GPS disappears, set range and elevation to MISSING
+    
+    Use MISSING instead of bogus values so that displayers can tell what
+    to do.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 451950bba9ee3b25b5d0c6e5f0b55f08a5b29f73
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 14 14:33:58 2014 -0700
+
+    altoslib: Add units converters for latitude and longitude
+    
+    Makes display of these values consistent across all instances
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ae7084f5199318dc6582e212492a50cfda1cebb8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 22:36:00 2014 -0700
+
+    doc: TeleGPS docs are complete
+    
+    All TeleGPS features should now be documented to some degree
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bfbabfa60f3cedd994f693867bce56aad05be02a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 22:04:57 2014 -0700
+
+    telegps: Allow TeleGPS preferences to have a custom title and label
+    
+    Don't just inherit the AltosUI ones
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 536db8d03aedb45698c42418c50a46d609fc98ad
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 22:04:35 2014 -0700
+
+    doc: Add a bunch more stuff to the telegps docs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9a6a3c34293eac6442f766e13ce148f595e891eb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 21:26:33 2014 -0700
+
+    altosuilib: Make map-cache per-window instead of global
+    
+    This consumes more memory, but avoids cache conflicts between windows
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 92895c87bc3d97bf4990f1feda0bd8b07da4c405
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 21:25:41 2014 -0700
+
+    telegps: Shuffle menu entries around
+    
+    I think this makes them a bit more logical
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fb2d0c1ef98d9df3f64fb756d78392ce63a73435
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 15:54:08 2014 -0700
+
+    altosdroid: Improve voice for TeleGPS
+    
+    This avoids making lots of useless voice announcements for TeleGPS
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 191ea4a7bbcb22d70c648a9ba746f1061e6f74cb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 15:53:30 2014 -0700
+
+    altosdroid: Don't crash when the map is touched
+    
+    The map 'canScroll' method was crashing when dereferencing a null
+    value somewhere. Just check all of them and bail instead of crashing.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3f7e885055f8a97f334e0cd3163b760b174114b6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 15:23:30 2014 -0700
+
+    telegps: Add status tab
+    
+    This includes pad-relative information, battery voltage and version information
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 876acbdc22ff93c22836f789e0b6394eb19e0da3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 15:22:25 2014 -0700
+
+    altoslib: Correctly save firmware version in AltosState
+    
+    It wasn't getting cloned
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3bfba8f9dbc1627a317804713f83b9d06566d008
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 15:21:28 2014 -0700
+
+    altoslib: Add conversion class for voltages
+    
+    Provide a common presentation for voltage values
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7ed63b6c3d5878a59f52f4114b5b01942735805f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 15:20:20 2014 -0700
+
+    altosuilib: Build some common classes for displaying values in flight window
+    
+    Right now, all of the flight displays have piles of custom code for
+    displaying values. These new widgets should be able to replace most of
+    that.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a21dbb05fad2625d17bc2302faa96dc295e6ed7c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 00:28:38 2014 -0700
+
+    telegps: Show flight number in monitor window
+    
+    This lets the user find the flight by number
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8cb41ce9a64029b611b3595c86a4a8e74b952ff4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 00:28:09 2014 -0700
+
+    telegps: Disconnect telemetry device when closing monitor window
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fd9ae83492648c5d39f60bdcff15481efb365701
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 00:27:19 2014 -0700
+
+    altoslib: Remove telem monitoring when closing log file
+    
+    If we don't remove the telemetry monitor, the telemetry device will
+    still be sending telemetry, which isn't good.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 07baa7596b36cf808cd1ee26ff158b1cf8585294
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Jun 13 00:01:46 2014 -0700
+
+    altoslib: Call state.set_serial first for telemetry parsing
+    
+    If we ever get around to supporting multiple simultaneous remote
+    devices, we'll need to notice that the serial changed right away
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f49540acd48292bd9f68ded647561d0e800c619d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 12 23:59:37 2014 -0700
+
+    altos/telegps: Create new flight if current flight is erased
+    
+    telegps is unique in that USB may be connected while a flight is
+    active and sensible things should happen. If a flight is being
+    recorded and gets erased, then a new flight should be started.
+    
+    This is done by hooking in the flight erase code and calling out to
+    the tracker code to figure out whether to switch to a new flight or not.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8117ba3553789a2bae9beb92fbe9e14e3cc79389
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 12 23:56:07 2014 -0700
+
+    altos: Define ao_log_mutex in ao_log.c rather than every log product
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dcaaf51245b44a440ee8590512f71195c30c16ae
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 12 21:54:13 2014 -0700
+
+    altos/telegps: Keep ring of recent GPS positions to detect motion quickly
+    
+    Instead of comparing only against the last logged value, keep a ring
+    and start logging as soon as we move away from the furthest one in the ring.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 740d964ab82da8695c04650926afee4a0905011c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 12 21:53:07 2014 -0700
+
+    altos/telegps: Set default log to 496kB for 4 logs
+    
+    This leaves space for four flight logs.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 77b5c0cc7f085aa3c0fada5d4a943eeaf16cf6e0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 12 21:52:13 2014 -0700
+
+    altos: Show current flight number for TeleGPS
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bfdaa95cb72c833896076d4e1a4bfe61d9549fed
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 12 15:59:20 2014 -0700
+
+    debian: Fix build depends icotool -> icoutils
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7e911c2afff78db2e385c6346c90bfcd72a8f3fb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 12 14:34:02 2014 -0700
+
+    altos/telegps: Don't log data when plugged in to USB
+    
+    We don't want to accidentally log stuff when you're just trying to
+    charge the battery.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7d77d83685cbfce5323767bbfae3bd18be175ffc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 12 14:32:15 2014 -0700
+
+    telegps: Don't re-add frequency menu when already present.
+    
+    If the receiver disappears, we'll stop tracking, but won't pull the
+    frequency menu down. Doing that would take a bit of work, and it
+    doesn't seem worth the effort. As a kludge-around, avoid re-creating
+    the frequency menu if it's already displayed when we connect to
+    another device.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8044eb8e23366e91c741060939baff5137f841c7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 12 14:12:08 2014 -0700
+
+    altosui/telegps: Reduce CPU time needed for flight displays
+    
+    Don't update displays which aren't shown; track hierarchy changes to
+    trigger display from most recent state data.
+    
+    Don't update values which haven't changed; remember previous values
+    and compare with new before updating widget contents.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e00ffe6ab6197ab48ba8ce3cf71a197f7215649f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 23:28:55 2014 -0700
+
+    doc: Add TeleGPS screenshots
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c7774114f7bc62e2100c7575b1dcf3536ed56343
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 23:28:36 2014 -0700
+
+    doc: Update altusmetrum docs and screen shots for 1.4
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1ed591c7bdf19fe54bbde1827d0717f0ae51e003
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 23:27:16 2014 -0700
+
+    telegps: Remove 'Flight' from titles
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0495f1b5282d8f7449cbbc1dbf99d63818d7c03c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 23:26:36 2014 -0700
+
+    altos/telegps: Build .ihx versions for TeleGPS
+    
+    Needed to load with java
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6f306b267f63d0f59fb77b1ce41c678042dd6802
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 23:04:46 2014 -0700
+
+    altosuilib: Repaint map when starting line draw
+    
+    Starting line draw will remove any existing line, so repaint to get
+    rid of it
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit efb6a3d5ed12f8061a48a66efcfe066e68eaf792
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 23:04:11 2014 -0700
+
+    altoslib: Report GPS height when baro height is not available
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 57272609b0d2890029fdeceeca14da93cebdb471
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 21:37:23 2014 -0700
+
+    altosui: Don't list tracker parameters when configuring altimeter
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bfc0c65c9f9ec9547d71016fc897ba35bdb414f8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 20:36:49 2014 -0700
+
+    altosuilib: Handle font and units changes in maps and stats table
+    
+    Add AltosFontListener and AltosUnitsListener bits as needed
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2182c49298e0862a60dea104450d5f74dbeaeeb2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 19:57:24 2014 -0700
+
+    doc: Update 1.4 release notes to include a few more changes
+    
+    pyro firing time.
+    flight erase on TeleMega/TeleMetrum v2
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d744e588b7504f314e39b1407152d11c031673c9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 19:51:37 2014 -0700
+
+    altosui: Add pyro firing time configuration
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fcbfb3aea20e564045fc6a86f978cacabfc73226
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 18:58:09 2014 -0700
+
+    altosdroid: Altosdroid build doesn't work in parallel, so stop trying
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c661d5de7d9c8e430211e0f97ab0bf3f09a1a543
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 18:53:42 2014 -0700
+
+    altos: Re-enable telemini v2.0 builds
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 18b0f0966dfc4d1a716d4faea6f661bd3594bd94
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 18:53:10 2014 -0700
+
+    altos/telemini-v2.0: Disable beep frequency config on TeleMini v2.0
+    
+    Not enough flash otherwise.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ac5b15692874ea3f7b3814250ab49c68786aa982
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 18:51:19 2014 -0700
+
+    altosuilib: Remove old widget-based map UI
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7a70e6fe3a11382d7f6653d19afac9ceb563db3b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 18:50:07 2014 -0700
+
+    altos: Disable TeleMini v2.0 build for now
+
+commit a8325483adb8d9ffda62d3f4900cf52bde70ff62
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 18:48:11 2014 -0700
+
+    altoslib: Use GPS seconds as an additional sort key for TeleGPS eeprom
+    
+    Long idle periods with TeleGPS can easily overflow 16 bits of tick
+    count. Using the GPS seconds provides an additional sort which will
+    span the tick wrap-around.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit db2443fdbf65b65703217174303027c439124a83
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Jun 11 18:46:47 2014 -0700
+
+    altosuilib: Rewrite map GUI bits
+    
+    Use a single large Canvas and draw images on top by hand.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ac33ca137551e32235cd2a0304da4b5e7af51a44
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 11:36:03 2014 -0700
+
+    telegps: Add statistics tab to graph UI
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 73249dbf16382c91c2a220ff852a4f099fe0de3d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 11:35:30 2014 -0700
+
+    altosuilib: Move AltosFlightStatsTable to altosuilib
+    
+    So that TeleGPS can share it
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9ef32b103c5c312aaa90b6546e504f2edeb1f99a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 11:34:21 2014 -0700
+
+    altosuilib: Skip voice announcements for invalid values
+    
+    When height and speed values aren't available, don't say anything
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 90686853e46b7f0df9bdaf671f859819eef926e0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 11:32:57 2014 -0700
+
+    altosui: Show "Missing" instead of huge numbers in descent/landed tabs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7bdd0deabaae38ddfecd1ea2ea8deaf9af40b2ac
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 11:31:53 2014 -0700
+
+    altoslib: Use GPS speed/height values when other sensors are missing
+    
+    This lets TeleGPS report height/speed values without needing to
+    customize every AltosState user to pull out GPS values when the other
+    sensors aren't present.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6fc58142d2a108c91d257eb0175098bf082834f9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 11:30:36 2014 -0700
+
+    altosuilib: Split battery graph enable out from other adc enables
+    
+    This lets TeleGPS just show the battery voltage values without also
+    adding enable lines for the other flight computer ADC values like
+    ignitor voltages.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9d39bbd22e6cde1bbb39e7b5450f297d47365769
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 10:19:43 2014 -0700
+
+    altoslib: Check for time going backwards when replaying from file
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ff13cf1359e1f4ae33b16a5867fd364993566b65
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 10:18:44 2014 -0700
+
+    altoslib: Add new 'stateless' flight state for TeleGPS
+    
+    TeleGPS has no flight state, so add a new 'stateless' state for code
+    to handle this case differently than any of the existing states
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 871fb4753a3b54cc2e22309e80e24dfe9cc54511
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 10:15:47 2014 -0700
+
+    altoslib: TeleGPS no longer logs satellite information
+    
+    This doubles the amount of space available to log position information
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5f2029bd4e31289fb03e6af39abdbc16f8b8fa78
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 10:14:07 2014 -0700
+
+    altoslib/altosui/telegps: Switch TeleGPS config to motion/interval
+    
+    TeleGPS had configurable boost-detect values; those have been replaced
+    with a configurable stop-tracking motion limit and logging/telemetry
+    interval value.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ae1174317fc476e39077f7dc257ec08709c6b301
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 10:11:03 2014 -0700
+
+    altoslib/altosui/telegps: Change log size configuration
+    
+    * Use new log-space value provided by firmware when available.
+    
+    * Divide that up into 1-8 flights and offer those sizes as options to
+      the user instead of a fixed set of sizes.
+    
+    * Show how many flights each selection will store
+    
+    * This also checks values provided by the user
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 44ca50a2c9404c92cc887a23dfa25b335ebe6198
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 09:55:04 2014 -0700
+
+    altos: Set TeleGPS default log size to half of avaiable memory
+    
+    LPC11U14 doesn't have on-chip config space, so we're consuming a block
+    of external flash. As a result, only 1984kB are available for
+    logging. Set the default log size to half of that to store two flights.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9d7f4fb6af0fee843191766858e39a481aeda347
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 09:52:15 2014 -0700
+
+    altos: Simplify tracker logic, removing boost detect
+    
+    This removes the ao_flight_state value from the tracker code and makes
+    it simply log position information when the device has moved within
+    the last 10 log intervals. This also changes the configuration
+    parameters to define what 'motionless' means, and what interval to
+    configure the GPS receiver for, log data and send telemetry.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c5a7889a8da3da64deb0f118656784e0ee3fd511
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 09:47:04 2014 -0700
+
+    Revert adding state to GPS location packets
+    
+    TeleGPS no longer has ao_flight_state
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f6d633d73a8f826cf2a3128e3e234bd11af49718
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 09:44:57 2014 -0700
+
+    Revert "ao-tools: Parse TeleGPS state value from gps location packet"
+    
+    This reverts commit 428d09294ba0395fedd71346ad00fd90a4cdde97.
+
+commit da9575fce5ff4dfe83522e290973a01c43e4661f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 09:42:43 2014 -0700
+
+    altos: Make extra pyro channel firing time configurable
+    
+    This adds a 'I' parameter to set the extra pyro channel firing time
+    (in ticks). This has no effect on the main/drogue channels.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 75df97b5f6ade3310618a477b685d39b7fd4666e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 09:37:43 2014 -0700
+
+    altos: Report total available log space in version command
+    
+    This provides a more accurate means of determining available log space
+    than guessing whether some portion of the flash chip holds
+    configuration data.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 998eae61ecf56dd6ead4ec6ad82c952ae84170df
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Jun 10 09:36:59 2014 -0700
+
+    Revert "altos: Write current flight state to GPS data from GPS drivers"
+    
+    This reverts commit db6003d34595fbd103d5b131912b6a797254f1c5.
+
+commit d696b34b4823647e2e91093ba9d5a351d3a52f8a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Jun 8 16:08:30 2014 -0700
+
+    Revert "altoslib: Parse TeleGPS state value from GPS telemetry packet"
+    
+    This reverts commit d69547796caf74405f8304d23d4ae318315bbd7b.
+
+commit 5c117621444bc13aebbc7dc618b4a56f620931ac
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 22:37:30 2014 -0700
+
+    Bump to version 1.3.2.4
+
+commit b33de8ba1e48d8ad0cb78f1c5692bb81da916080
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 22:25:17 2014 -0700
+
+    altoslib: Recover battery voltage from TeleGPS configuration packet
+    
+    TeleGPS stuffs battery voltage in the apogee_delay slot of the
+    configuration packet. Pull it out from there and stick it into the
+    current state.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6950506beacb1bcd5b8e54c3935174cf800e9aed
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 22:24:08 2014 -0700
+
+    altoslib: TeleMega uses 5.6k/10k divider for v_batt
+    
+    I suspect the 15 and 27 values are a 'close approximation' for integer
+    work on the cc1111 devices
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ee2216af17f23781ea912caba29fbd7e4d9ff480
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 22:23:19 2014 -0700
+
+    altos: Enable ADC for TeleGPS v1.0 battery voltage measuring
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ef85b3bc5300904ebfb878b1c7313a82b5b7aebf
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 21:57:43 2014 -0700
+
+    altos: Encode TeleGPS battery voltage in configuration packet
+    
+    TeleGPS doesn't need apogee delay, so re-purpose it for the battery voltage
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d69547796caf74405f8304d23d4ae318315bbd7b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 21:13:40 2014 -0700
+
+    altoslib: Parse TeleGPS state value from GPS telemetry packet
+    
+    TeleGPS adds 0x80 to the state value to signify that this otherwise
+    unused byte contains the current state value
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 428d09294ba0395fedd71346ad00fd90a4cdde97
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 21:12:44 2014 -0700
+
+    ao-tools: Parse TeleGPS state value from gps location packet
+    
+    TeleGPS encodes state in a spare gps location packet byte, masking in
+    0x80 to signify that the state value is valid
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 23d9d37fd2a8f4b867f34e71a2b0f7cb090717c1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 21:12:09 2014 -0700
+
+    altos: Make telegps builds depend on ao_tracker.h
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d165079b9275c69e727a1dac996ad1788c58ed40
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 21:11:33 2014 -0700
+
+    altos: Reduce tracker GPS buffer to 4 samples
+    
+    We just don't have enough RAM for 8 samples.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bd9e4f30b2a491b030246943767960ab053ac94c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 21:05:01 2014 -0700
+
+    altos: Define lat/lon sum variables as 64-bit instead of 16
+    
+    Oops. 16 bits won't hold position information...
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 08550425fca3da73d8f16de567a2c956b85d676e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 21:02:26 2014 -0700
+
+    altos: Use 0x80 to indicate valid state value in the GPS location packet
+    
+    And only set this for tracker products; other products place state in
+    separate state packets
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d8b271502bfd1301b2244e3be5e8c9917a9c624a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 12:17:46 2014 -0700
+
+    Set version to 1.3.2.3
+    
+    Mayhem 2014 Saturday 2014-6-7
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d550c3b3eccbb0283c588b5df69edb2e9b44b4cc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:52:28 2014 -0700
+
+    telegps: Track graph windows as one of the TeleGPS windows
+    
+    TeleGPS exits when the number of windows goes to zero; track graphing
+    windows in addition to the usual flight monitoring windows.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9f2189e0b99aa32b788ecb4576dcb9bcc926f4e2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:50:42 2014 -0700
+
+    altosuilib: Fix crash when initializing site map cache
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 611dc26ab4a3ee303c0253698b1e12931aa3644f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:50:04 2014 -0700
+
+    altosuilib: Add GPS altitude as a possible graph value
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5617919091d4c4a1e627470ddab0b45cf649f7a1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:49:14 2014 -0700
+
+    altosuilib: Show GPS instead of (missing) flight data for TeleGPS graphs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e0dfa934ba76d6f913af37999e05c20e614bd3e9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:47:11 2014 -0700
+
+    altoslib: Record whether flight data includes sensor values in AltosFlightStats
+    
+    Provide a way to elide the usual flight data from a graph for TeleGPS
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fcea12ac416b1eab11e9e8aae801358574308f73
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:46:32 2014 -0700
+
+    altoslib:  Add TeleGPS log parsing code
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 537db628c0223f0c1f797705a353857c696f8051
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:44:55 2014 -0700
+
+    altoslib: All products with logging have the 'l' command
+    
+    Instead of listing products with the 'l' command, just exclude
+    products that don't have logging from using the 'l' command to collect
+    the number of stored flights.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d562a5d3a6dfea334a66ee74893b400bdca09315
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:44:07 2014 -0700
+
+    altos: Switch TeleGPS to GPS logging format
+    
+    It's customized for TeleGPS uses
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d71e6a5fc68d5b9bc1d12bbfc3fd5a4d86fb12f2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:41:59 2014 -0700
+
+    altos: Update other CONFIG_EEPROM users to set LOG_ERASE_MARK
+    
+    All products placing config and erase marks in on-CPU EEPROM needs to
+    configure the erase code correctly.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 394ab536257ab58de0190b3828dd3bb897ad4474
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:40:41 2014 -0700
+
+    altos: Write tracker logging from tracker thread directly
+    
+    Also, logs 8 pre-launch GPS packets so we can get the ground position.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit db6003d34595fbd103d5b131912b6a797254f1c5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:39:10 2014 -0700
+
+    altos: Write current flight state to GPS data from GPS drivers
+    
+    This will be useful with TeleGPS which has no other packet containing
+    flight state.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 302842ccda46a0a3d58b60d5c7fc82e05f614b0b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:34:29 2014 -0700
+
+    altos: Add TeleGPS logging format
+    
+    This is mostly like the mega format, but places the flight state in a
+    spare byte of the GPS data and writes the gps starting location to the
+    flight packet.
+    
+    Log data is written by the main tracker thread; there's no reason for
+    a separate thread given the GPS update rate and the lack of flight
+    controls. This means ao_log_gps has an API to be called from there,
+    rather than a thread to run.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 62aa51f0b785bea146d1e9331e6253de2d547c94
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 11:01:14 2014 -0700
+
+    altos/telemega-v1.0: Adjust config params to make flight erase work
+    
+    Flight erase records are supposed to be written after the ao_config to
+    eeprom in telemega. They were getting written in the middle of one of
+    the pyro channel config blocks. Put a bunch of space between the two
+    by making the config max 1024 bytes instead of 128 bytes.
+    
+    Set the log erase marker to 0x55 -- eeprom comes from the factory as
+    0x00, so we use any value other than 0x55 to indicate 'unused' erase
+    slots.
+    
+    Save space for more flight erase blocks; we've  got plenty.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5d973570ef2324b21a64477eecb0a292652ff467
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 10:54:14 2014 -0700
+
+    altos: Clear out eeprom erase records when writing entry 0
+    
+    When writing config/erase to eeprom, there's no 'erase' operation as
+    on-chip eeprom is writable at a byte level. As such, we can't tell
+    when the erase blocks get reset when the config gets written. When
+    this happens, erase block 0 gets written explicitly, so just use that
+    call to trigger explicit erasing of the data.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1d6ca536c688d35b3cba0a829b04b93c5124b328
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 10:09:51 2014 -0700
+
+    altos: Allow value other than 0 for marking erased flights
+    
+    on-chip eeprom doesn't erase to 0xff, so let TeleMega use a different
+    value.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b8a29d65ec605a995de1d1ec8b110d620d2f7a87
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 10:05:21 2014 -0700
+
+    altos: Allow AO_CONFIG_MAX_SIZE to be configured. Validate it.
+    
+    TeleMega config is 200 bytes. AO_CONFIG_MAX_SIZE was 128. That didn't
+    work out well when logging erased flight information. Allow TeleMega
+    to use a larger value (1k), and then do a compiler hack to make sure
+    the defined value is at least as large as the ao_config structure.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1873d539a8f1a0e1e8ad539af5d49a77a129b928
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Jun 7 07:41:11 2014 -0700
+
+    altos: Move ao_tracker.c to kernel
+    
+    Doesn't make sense to be in product
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6a79fe8144dcab10294caa4b0eac967eeb0d8e7e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 21:42:10 2014 -0700
+
+    altos: Add telegps-v1.0 code and loader
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0e867c67c8e2c40058ae36723e06b2ce00bd0419
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 21:40:39 2014 -0700
+
+    altos/telegps-v0.3: Remove ao_flight_number from main program
+    
+    We've got logging enabled now
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f830d4e9202d2a138fc9aaacb2388f94390399db
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 21:39:50 2014 -0700
+
+    altos/telegps-v0.3: Disable APRS by default. Set log max to 1M
+    
+    And adjust default radio cal to be a bit closer
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cab6d80f11e07dd26b865727eb7ce4fd45be5c7c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 21:37:38 2014 -0700
+
+    altos: Force telemetry on by default for v0.3 TeleGPS boards
+    
+    These don't have a USB connect indicator, so just turn on telemetry by
+    default
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 102b1977c138b30c2d2592ab310f7be072130a3b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 21:36:16 2014 -0700
+
+    altos/lpc: HAS_USB_CONNECT has been changed to mean a custom pin
+    
+    The LPC stuff isn't actually very useful and TeleGPS uses a custom pin
+    instead, and was using HAS_USB_CONNECT to mean the same thing. That
+    wasn't good.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ec3de3ac461f2380d23c5c5d948333a9a210c400
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 21:35:41 2014 -0700
+
+    altos: Fix config to set default log size for all devices with log
+    
+    Not just devices with flight
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d8f84ba82bab653c041eb85f93b9dcb1083bd849
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 18:55:26 2014 -0700
+
+    altos: Add AO_LOG_FLIGHT packet to TeleGPS logs
+    
+    This encodes the flight number for tracking of data files.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fe0aaf4413035f9de2c805c612c71188ec8c6f4d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 18:49:59 2014 -0700
+
+    altos/telegps-v0.3: Add tracker task
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6160ddadeae324b4a68db800c98c339156b63076
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 18:49:01 2014 -0700
+
+    altos: Add debug to tracker to force launch
+    
+    This lets us test the move from pad to drogue state
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4a29df3f9f6c4969eb01598f6917ce78c9ce37a6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 18:47:27 2014 -0700
+
+    altos: tracker distance computation flipped arguments around
+    
+    ao_distance takes (lat, lon, lat, lon) not (lat, lat, lon, lon)
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b619199345256cdc456f8a0b99c0ad9335e877c7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 18:45:18 2014 -0700
+
+    altos: Fix tracker start state
+    
+    Make sure log can start by scanning existing logs
+    Enable RDF by default
+    Turn off telemetry until we decide whether to turn it on in the loop
+    Allow TeleGPS v0.3 to run without ADC
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 97dac0f66bc938940e6b49409d950a1736c92655
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 18:44:26 2014 -0700
+
+    altos: Stick flight state in GPS location packets
+    
+    Useful for TeleGPS
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eebcf07950e909e4516b08c32e289a870f772793
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 18:35:45 2014 -0700
+
+    altos: Have tracker average 5 GPS samples before moving to pad mode
+    
+    Avoids early GPS noise right after lock
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e063701310c1ab5b766c27f24088699aad142fbd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 18:33:33 2014 -0700
+
+    altos: Change tracker not-moving speed to 2m/s and document
+    
+    Just adjust to avoid sensing motion from GPS noise
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d7df6e8c47df35c0d27f1a2559ecc305ef28d271
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 18:31:06 2014 -0700
+
+    altos: ao_distance was overflowing when checking for longitude wrap
+    
+    Need to shift everyone right one bit to fit in 32 bits
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2db2b75f8847ca0066bb19771653a65c9098ae52
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 17:24:57 2014 -0700
+
+    altos: Allow cc115l driver to be built without radio power control
+    
+    TeleGPS just wants full power, so remove the configuration option
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b8201bc9ba4a5f5f0522b68493cd5e7f013fd4bb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 17:14:28 2014 -0700
+
+    altos: Include sensor logging task only on flight boards
+    
+    This lets TeleGPS use the logging infrastructure without wasting a
+    task to log sensor data
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3e28d8a242955d65d8cd50dbba4cad4609e2e1ae
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 17:12:06 2014 -0700
+
+    altos: Add tracker task for TeleGPS
+    
+    This replaces the flight code to monitor GPS state and switch flight
+    states between startup/pad/drogue
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6e152dd5c0786a650aed8f0c09babdc93895bff1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 17:10:28 2014 -0700
+
+    altos: Add ao_distance.c to compute cartesian distances on the globe
+    
+    This is not a great circle distance, but should be good enough for
+    points reasonably close together
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8e7b8b0533e03e89425296d464b7a1a26fb63686
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 16:52:36 2014 -0700
+
+    telegps: Update icon and icon building
+    
+    Switch to satellite icon, build the osx and windows icons.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1bcafc452f50e518c4d86cbd6b9057c4bf7e676f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Jun 5 16:50:29 2014 -0700
+
+    altosuilib: Let the user hand-edit the preload map radius
+    
+    In case they want more than 5
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f59d69064763cfad2b4b15fd9660fd5fa21dba5e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 2 23:43:54 2014 -0700
+
+    doc: Create release notes for version 1.4
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cd2179cb0d71749f3637cc3ee03ccc6adfd74aae
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 2 22:59:23 2014 -0700
+
+    telegps: Trap AltosConfigDataException in telegps config
+    
+    This was added for pyro configuration errors in AltosUI
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5e4087cd2fbb3ac67f90cd82edaa73c1eedbf67c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 2 22:23:31 2014 -0700
+
+    altoslib: Add missing AltosConfigDataException file
+
+commit ace5f42b5567cff07a61b622171ac364ea8c165d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 2 22:07:39 2014 -0700
+
+    altosui: Display error message when parsing pyro channel values fails
+    
+    Build an exception handling chain to get numeric parse errors
+    propagated all the way back to the original 'save' command and up into
+    a dialog window, including the pyro channel, field and value that were
+    in error.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 206fbb99d28961ce159e3affdd5c96f5e379a603
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 2 22:06:22 2014 -0700
+
+    altosui: Fix pyro channel value formatting
+    
+    Was using %6.1f for 1 and 2 fraction digit values as the
+    conditional structure for figuring out which format to use was
+    broken.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d20c608ce833fb8949dce527f92887775d216823
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 2 22:05:11 2014 -0700
+
+    altos: Fetch/store only 8 bits for pyro state values
+    
+    These fields are uint8_t, not int16_t. Fetching and storing 16 bits is
+    a bad idea.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b7abc063fb27da29cd7a717bbea15f92882bd205
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 2 22:04:11 2014 -0700
+
+    altos: Maximum pyro configuration parameter has 4 bytes in the name
+    
+    "f>=" needs four bytes, not just three to store the whole string. If
+    we only store three, then we never manage to compare correctly as the
+    null terminating byte is missing.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7385c76af46ff400b9e79a8540199be289cb57c0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Jun 2 22:03:26 2014 -0700
+
+    altos: Configuring pyro channels can use more than 48 characters
+    
+    Increase the command buffer from 48 to 128 bytes to hold the longest
+    pyro configuration commands
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 177d3c0333fd4218f01e05c78cbc5f186c8e32c0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri May 30 17:27:10 2014 -0700
+
+    altos: Allow sparse GPS data logging for TeleGPS
+    
+    When the device hasn't moved for a while, stop logging data. Start as
+    soon as it moves again.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 12c408c5aa1d234fe9c946078d8a343b4fda7ebb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri May 30 17:30:08 2014 -0700
+
+    altos: Test APRS altitude encoding
+    
+    Verify fixed point version against naïve implementation
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a7b0a5613c8e59b4c672b21f8d0890fd5cffd4dc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri May 30 17:24:51 2014 -0700
+
+    altos: Switch APRS altitude encoding computation to fixed point
+    
+    APRS altitude is logarithmically encoded, so this implementation
+    includes a fixed point log-base-2 function along with a bit of other
+    fixed point stuff. This eliminates all floating point from TeleGPS,
+    saving around 4kB of code space.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2d9842ee011139f5783a102ceb2b7f4c88b1a10f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri May 30 17:17:42 2014 -0700
+
+    telegps: Add config for tracker starting distances
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 29d325f418b401f61580288b5947b0df8ac5b717
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 29 22:03:48 2014 -0700
+
+    telegps: Fixup windows fat build harder
+
+commit b74dfc9c2cbe14593738eb994e9163d466155326
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 29 21:48:11 2014 -0700
+
+    TeleGPS firmware isn't quite ready, don't include in windows fat build yet
+
+commit e60d0456f59c76ad786bc8f8065fbe84e6cae922
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 29 21:37:53 2014 -0700
+
+    Capture windows build error messages
+
+commit 48074131ad05b4646e5d2dcf30ba4a1d17e249f8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 29 16:39:26 2014 -0700
+
+    telegps: Add missing TeleGPSGraphUI.java file
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ca7e64a09823977e1af028e9482424e643beee68
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 29 14:40:39 2014 -0700
+
+    Build telegps distribution bits with 'make fat'
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bf684a4c290573a3aa627fd8ddf6f6ebbe5fa057
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 29 14:36:14 2014 -0700
+
+    telegps: Add graph display
+    
+    Moved the altosui graph files to altosuilib and fixed things up.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f80075be4ebb9c5fe00c24b8c7638fad23267424
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 29 14:03:58 2014 -0700
+
+    java: Refactor AltosFlightDisplay units and font update handling
+    
+    Make AltosFlightDisplay explicitly implement AltosFontListener and
+    AltosUnitsListener interfaces to make everyone use the same API. Then,
+    actually go implement units listeners so that changing units updates
+    all of the active displays immediately
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 71715337eb532a1fbe1a753240e7417d5223489f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 29 10:16:15 2014 -0700
+
+    telegps: Add info table
+    
+    Move a couple of files from altosui to altosuilib, hook up the info
+    table after changing it to implement the AltosFlightDisplay interface
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 13f84be8d1568a3fc2ed5eef5dcc2093c149285e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 22:53:06 2014 -0700
+
+    telegps: Add flash device functionality
+    
+    Move bits from altosui to altosuilib and use those.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8ba523cd793f2263bb1acd7a5a10f8964075bdc5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 22:45:23 2014 -0700
+
+    telegps: Auto-connect to any base stations plugged in at startup
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c30130d0bdc18ee351eb3d02e51f70f8a05905b1
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 22:06:43 2014 -0700
+
+    telegps: Don't try to ship TeleGPS firmware yet
+    
+    It's not quite ready. Instead, ship TBT and TD firmware.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3871b9ac036e3adfa1da089245fc7973b268c921
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 21:56:52 2014 -0700
+
+    telegps: Add 'Info' tab
+    
+    This contains a summary of the tracking info, including position,
+    speed and course.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4cec35564324f909dcddeb7c0d83a2daa8223042
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 20:58:01 2014 -0700
+
+    telegps: Hook up data download dialog
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9a4c2c7fc6af922d052e23a1b99bf847fbf9b0e9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 20:48:59 2014 -0700
+
+    telegps: Add scan UI
+    
+    Move scan UI bits into altosuilib, allow telegps to not show telemetry
+    format options.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 82a69777c67128192b50bbf77ace0a6525f49cac
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 20:24:04 2014 -0700
+
+    telegps: Add preferences dialog
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a7fd31842a602a8ac803d0e09efb4ffabf7a289b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 20:19:44 2014 -0700
+
+    telegps: Add device configuration dialogs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d6c5904e2a05c8ae023a8cd954cf16c19c477d7d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 20:00:10 2014 -0700
+
+    telegps: Use altosui's Instdrv NSIS plugin for telegps
+    
+    Instead of copying it, just point at it
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fe14315d4cfccf8b53d9c4b7fa79302fd36b2c9a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 19:50:52 2014 -0700
+
+    telegps: Working towards building fat versions of telegps application
+    
+    Lots more of the bits necessary for windows/macosx
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 47ff6f7528e3984012e874f91ea4f5c1d68cb465
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 19:45:01 2014 -0700
+
+    doc: Add outline of TeleGPS doc
+    
+    No actual content, mostly a place holder to make the build work
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e19121d5e7368ef723d4642d26c24252a386a790
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 19:44:21 2014 -0700
+
+    Mark version 1.3.2.2
+    
+    Preliminary 1.3.3 version (1.4?)
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2fa7785f9efdefaf0fc2fa8e0b03c85047613b84
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 16:08:30 2014 -0700
+
+    telegps: Add first version of telegps
+    
+    Not much implemented yet, but a shell of the UI and the map
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9b3516419981967a1c6ab956269139977ac368ca
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 16:06:14 2014 -0700
+
+    altosui/altosuilib: Shuffle lots more code from altosui into
+    altosuilib
+    
+    All of the bluetooth management stuff, and AltosSerial.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 02e657e45e217dc483a81f28020cfe65a826e9be
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 10:43:09 2014 -0700
+
+    Document the need for ~/altusmetrumllc/google-maps-api-key
+    
+    Stick this in Releasing
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9b9e4bf1b51c45553879141811748e65debfc251
+Author: Tom Marble <tmarble@info9.net>
+Date:   Wed May 28 14:08:02 2014 -0500
+
+    jenkins.sh: make -j 4 can fail, fix for altosui-test
+
+commit 96ffe5bbd2a1b44ddda6cb25d37d2b0a672045f5
+Author: Tom Marble <tmarble@info9.net>
+Date:   Wed May 28 12:50:42 2014 -0500
+
+    fix for jenkins.sh
+
+commit 5eaef0c98488fa3fbd3a6494dc15e1b793eb6f94
+Author: Tom Marble <tmarble@info9.net>
+Date:   Wed May 28 12:38:36 2014 -0500
+
+    add jenkins.sh
+
+commit 324380dcf86be338c6d556b901d6889ddde97f7e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 10:31:47 2014 -0700
+
+    altosuilib: Don't try to draw to destroyed map windows
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1e5807ef428c9a0eb88ed8a3aef40098ab347d80
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 10:27:52 2014 -0700
+
+    altosuilib: Publish AltosSiteMap.centre. Add prefetchMaps with old API
+    
+    This gets altosui working again.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 52ce41952c5a3c31532fa4f0d1b3155a162b76f4
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 10:16:38 2014 -0700
+
+    altosuilib: Update map preloading UI to include zoom and maptypes
+    
+    This lets you specify precisely which maps to load.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5c3991768d3cb17fc99ad32b2d6d8d11f0e37dfa
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 02:18:41 2014 -0700
+
+    altosuilib: Remove debug printf in AltosSiteMapCache
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4a5ef9eaa8b809c56813625133120e7e91fc8e65
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 02:06:18 2014 -0700
+
+    altoslib: When log-format is missing, use product
+    
+    log-format was added for 1.0; earlier log files don't include that,
+    but do say which product they're from.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3773e89c47d356c4df58edc5725c33bca89b9605
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 28 00:42:24 2014 -0700
+
+    altosuilib: Add google maps API key, configured with -with-google-key
+    
+    This places the actual key outside of the repository, allowing the
+    user to configure the name of the file containing the key. By default,
+    this pulls the key from $HOME/altusmetrumllc/google-maps-api-key.
+    
+    With the key present, there are no longer any rate limits to loading
+    map data.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e6cfa25702b3dc1d492c5f1a4d0b4ba4831d30bd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 27 20:34:29 2014 -0700
+
+    altosuilib: Decompress map images asynchronously and in parallel
+    
+    This speeds up loading map images from disk quite a bit, and keeps the
+    UI responsive while that happens as well.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8e44580cbe978f1570d4d2ac13d3dd7cd470ecf7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 27 15:39:13 2014 -0700
+
+    altosuilib: Add distance measuring line to site map.
+    
+    Use any modifier or button other than the left one to draw a line on
+    the map. The length of the line is shown at the start of the line.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c674a20432c2cb97e5bc2a3de891f78b9e172fe9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 27 11:05:02 2014 -0700
+
+    altos: Fake flight code changes in kernel and stm
+    
+    Redirects data input from local sensors to USB sourced data, leaving
+    USB enabled when the computer goes into pad mode.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit db08e99361d82de63058d3388823f486e5fc9839
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 27 10:58:53 2014 -0700
+
+    altosuilib: Add multiple zoom levels and content types to map
+    
+    Also changes the file format for hybrid, satellite and terrain maps to
+    jpg to save disk space.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 535271f7312f1a88af11d4f1dbf3d405b660f26c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 25 21:14:42 2014 -0700
+
+    altos/test: Fix ADC structure for mega, use ao_config.h
+    
+    This switches from hand-coding the ao_config structure to using
+    ao_config.h and also updates the ADC structure for ao_flight_test_mega
+    to using the same one as telemega does natively
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1894b51daceaf9fb6b49a0625e09a366985d15b6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 25 21:12:29 2014 -0700
+
+    altos: Move ao_config declarations to ao_config.h
+    
+    No sense leaving these in ao.h, and it's nice to make that file smaller
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3d5db24708b37d86eac187169e2553a408dfeb83
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 25 21:11:23 2014 -0700
+
+    altos: Make MS5607 PROM a public variable
+    
+    This will let the fake flight code update it as necessary, without
+    creating a new interface in ao_ms5607.c
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4df84dd5d007120f54cbda380789306608f2fc46
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 25 21:08:44 2014 -0700
+
+    micropeak: Add -Xlint:unchecked to javac line
+    
+    This shows missing parametric type errors
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f0216d721ed13f4d3dc608bb6ad8f83732b27c0a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 25 21:01:38 2014 -0700
+
+    altoslib/altosuilib: Change versions to altoslib:4, altosuilib:2
+    
+    API has changed for these libraries, time to bump the file versions
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d63319f6f29ef714bb1d5c359c2448f63e7a4534
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 25 20:58:24 2014 -0700
+
+    ao-tools: Add cc_usb_write function
+    
+    This writes raw bytes to the USB port; useful for sending binary data
+    for flashing or the upcoming flight test stuff.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0a6c76fc0525d6588a1d88127f0085f13a02f1af
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 25 20:55:11 2014 -0700
+
+    altosui/altosuilib/altoslib: Move more stuff out of autosui. Reduce site map memory
+    
+    Prepare to share with TeleGPS application.
+    
+    This also has the changes to the site map tile which cache only a few
+    images and regenerate the flight path on the fly, saving piles of memory
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4ac7797d3efb9cc2d9fae88519f55e40b1050224
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun May 25 20:47:49 2014 -0700
+
+    altosui/altosuilib: Cleanup -Xlint:unchecked warnings
+    
+    Add parametric types to avoid unchecked warnings.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b60a3689910731d9bdb8a431a3dcc9e99f961b35
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 22 18:46:58 2014 -0700
+
+    altoslib: Move CSV/KML output code to altoslib
+    
+    It's sharable, so share it
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2625a464417c8475c66101757ca2c30cd6c74e0c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 21 14:02:35 2014 -0700
+
+    altos: Add config values for tracker start motion limits
+    
+    TeleGPS switches from 'pad' to 'drogue' states after the device moves
+    a specified distance from the initial starting point. These values can
+    be configured, and this is the configuration for them.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 161ae96f9ec11e2586df07c0f6d724ddc4dad76c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 21 14:00:05 2014 -0700
+
+    altos/test: Parse mega ground data. Fix pyro parsing
+    
+    This gets ao_flight_test_mega working with eeprom files
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 43be26603827b5930bf3e8082610cfa19b45534d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 21 13:58:54 2014 -0700
+
+    altos/test: Get APRS generation test working again
+    
+    APRS now includes sat info, so we have to fake that up to generate an
+    APRS test file
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2a3846df381a5eeac8ec3327c770af502aaf4e76
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 21 01:37:57 2014 -0700
+
+    altos: Don't define ao_ignite_decivolt without igniters
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit af782e92c6a0c0a6b0fc2fa52519749a88ca8fb8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 21 01:36:40 2014 -0700
+
+    altos: Expose ao_gps_set_rate from u-blox driver
+    
+    This lets applications set the desired GPS update rate to reduce power usage
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8b488bdd0f5c91be7e5aae1c8f0193e713734b14
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 21 01:35:33 2014 -0700
+
+    altos: Fix cc115l debug build
+    
+    New compiler warning flags and moving to the nxp require a few minor
+    changes in the code to make it work.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit cb228304d8df3063914ab505a530d4ea79ca027d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 21 01:34:27 2014 -0700
+
+    altos: Allow APRS to send just battery voltage
+    
+    Don't require apogee and main voltages as well
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ca338a897ba3237652a3ae092e660f26c9e35074
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 21 01:39:46 2014 -0700
+
+    altos/lpc: whitespace
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0a3312e725d914bbba6355e07d2f1d2833d2d6c2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 21 01:39:01 2014 -0700
+
+    altos/lpc: adc code computes number of active ADC channels
+    
+    Don't require the application to provide AO_NUM_ADC when AO_ADC_NUM is
+    computed automatically.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b278a73cb54ba2f107bf91089f87c11528f017ab
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed May 21 01:41:38 2014 -0700
+
+    altos/stm: Make stm applications depend on ao_boot.h
+    
+    This should make sure they get recompiled when boot stuff changes.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f3544daf08f38aa8e28ca214a19ab7fd47c0c802
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri May 16 00:00:12 2014 -0600
+
+    altosui: Remove another beep config debug printf
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit eeacc001ba089b4bf5552b8ef36e61a0a96efabe
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 15 23:57:50 2014 -0600
+
+    altosui: Remove debug printf about beep config
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6833e466d7d77765199bf4d21437c34a4eceb044
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 15 23:46:41 2014 -0600
+
+    altos: stm and lpc ao_boot.h were identical. move to kernel.
+    
+    These two files were absolutely identical, so share them by moving
+    under kernel instead.x
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 211d9af507daf9a8611ed1813415bee27e3839eb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 15 23:34:17 2014 -0600
+
+    altos: Use explicit boot loader signal in ao_boot_reboot
+    
+    Instead of just "knowing" that ao_boot_loader will be passed zero when
+    the application wants to get back to the boot loader, explicitly
+    define the values so that both sides always agree.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0bf1c74e83fe49a11916b52596363f4dd56c522c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 15 23:10:54 2014 -0600
+
+    doc: Document the Apogee Lockout setting
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit dbb0fcf6d161a9d49fe699c37a18e4c33c409b59
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu May 15 17:20:39 2014 -0600
+
+    include EasyMega Makefiles
+
+commit 0948f5d96456b2e7f57ad75dfc9ef455ba197163
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu May 15 17:19:08 2014 -0600
+
+    working?
+
+commit 0fd608868aa03f81b2d902e1da13ee0b1ab20b78
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu May 15 16:23:17 2014 -0600
+
+    lose the (old) easymega-v1.0 directory in favor of my fresher 0.1
+
+commit 819f73698f57e76dca50fe4fadccebd23ffb776d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 15 09:31:24 2014 -0600
+
+    altos: Make quadrature debounce per-pin rather than per-device
+    
+    Debouncing per-pin means we don't lose transitions, which makes
+    counting a lot more precise.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit da13064382e9673e69cdfae6abbac253c9fc42fc
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 15 09:30:32 2014 -0600
+
+    altos/telemini-v2.0: Enable beep frequency configuration
+    
+    Now that there's space for this, add it in.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 36002fc724702d34302f3cc0df593019ca8db4e0
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 15 09:29:52 2014 -0600
+
+    altos/telemini-v2.0: Remove old baro->alt conversion table
+    
+    TeleMini doesn't have two baro sensors...
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d0d29cc233b0d444782530fea15d957b2b4c45d7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 15 09:28:30 2014 -0600
+
+    altos/cc1111: Switch P1_0 from a green LED to USB pullup
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3225fb54ec1beaf6dc8553ab4f5b86bea6bdf1f3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu May 15 09:27:34 2014 -0600
+
+    altos/cc1111: Add support for CPU-driven USB pullup
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 940ec6a2d5b054f68da39945a00f4d1b36d1b318
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 13 22:46:19 2014 -0700
+
+    altos/cc1111: Errata fix isn't needed for discontinued products
+    
+    And, doesn't fit in memory for some of them, so don't compile it.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit feb0b5f8b28767197f87e5818812d6640c1f40e6
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue May 13 17:30:47 2014 -0700
+
+    altos/cc1111: Wait for xtal to be stable
+    
+    Errata http://www.ti.com/lit/er/swrz022c/swrz022c.pdf says that the
+    xtal is stable bit is bogus and that you need to just delay for a while.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8124af8c27b2b9e446aa3a4f1da83d4db7c1ea87
+Merge: 6dd7eae 3bcf4bd
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 23:21:55 2014 -0700
+
+    Merge remote-tracking branch 'origin/master'
+
+commit 6dd7eae5e4752d2098797e96953db8923e26835b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 23:20:08 2014 -0700
+
+    ao-tools/ao-usbload: Check image flash usage against device flash availability
+    
+    For devices which report the range of valid flash addresses from their
+    boot loader, check the loaded image to make sure it fits within that range.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8a114bac1145359f3953ce70f049a6be71df5300
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 23:18:41 2014 -0700
+
+    altos/flash-loader: Check memory addresses against flash space
+    
+    This validates memory read/write requests to make sure they are within
+    the available flash memory space.
+    
+    This also reports the flash base and bounds addresses in the 'version'
+    command so that the loader can validate the image before attempting to
+    write it.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a25c34ef0a92beaa0695e0d0020eda5e26b309e2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 22:56:38 2014 -0700
+
+    altos/stm: Use #define'd constants for GPIO register addresses
+    
+    This lets the compiler short-circuit the tests in ao_enable_gpio and
+    ao_disable_gpio to save a bit of code space and time.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 530894f508874f4cb3db644ca9ca679ed704f964
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 22:55:38 2014 -0700
+
+    altos/stm: Figure out available flash space based on chip id registers
+    
+    Look at the flash size and the device id registers to figure out how
+    much flash is available.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2c543be5548ccda6bd29a2a7659fcc287f7a9f07
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 22:54:35 2014 -0700
+
+    altos/stm: White space fix in ao_boot_pin.c
+
+commit 2f196323a2829f9537f3b339f19478127ffde623
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 22:53:07 2014 -0700
+
+    altos/stm: Use flash address of boot loader instead of 0x0
+    
+    Flash is at 0x08000000, but when the chip boots, it can be at 0x0 as
+    well. Use the 0x08000000 address when rebooting to flash
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6a6053dfed6fc1a7f50be0c62782d0050758cd0b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 22:51:50 2014 -0700
+
+    altos: Assume all LPC products will have 32KB of flash
+    
+    If we ever use something smaller than this, we'll need to figure out
+    how to tell how much memory the device has.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d1908101241b1002fbc582b0a2c27045065a6615
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 22:51:16 2014 -0700
+
+    altos: Report amount of program space available in the version command
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3af4e824938fe07fe75c6d24d9906aebfbe578f3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 22:50:41 2014 -0700
+
+    altos: Add LED test command to pca9922 driver
+    
+    This lets you control the LEDs from the command line to test things.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 47750e236c45ab03f28fc3393996edb2bd4312e3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 22:49:39 2014 -0700
+
+    ao-bringup: Use official binaries for EasyMini turnon
+    
+    Don't use locally built ones, use the official ones found in
+    ~/altusmetrumllc/Binaries to ensure that all devices are shipped with
+    known firmware.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5f4a1b3e553276a4d6727c111fe290fa3690fa1e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 22:48:45 2014 -0700
+
+    ao-bringup: test-baro should accept altitudes a bit below sea level
+    
+    Testing baro sensors on a particularly high pressure day at Keith's
+    house yields altitudes down to -20m or so.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 238ddde1ffdb8521d06519306cfb76271ae552b9
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 12 22:47:55 2014 -0700
+
+    atosui: Hide Callsign and RSSI tabs for devices without a radio
+    
+    When doing Monitor Idle with EasyMini, it's nice to not put fields on
+    the screen which won't ever have useful data in them.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3bcf4bdd3e3f3751ad9d517696b5573dd4593846
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon May 12 17:31:14 2014 -0600
+
+    update TeleMega turn-on script and Releasing for new stable firmware home
+
+commit cbb6f7a3abbde39163f2905badba0ae88744b104
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Fri May 9 12:30:25 2014 -0600
+
+    fix copyright year
+
+commit 8d9c79f5c162e07d57d42c6ba5825a3327a911d5
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri May 9 00:05:39 2014 -0700
+
+    altos: Simplify quadrature tracking
+    
+    Set the timer to 200Hz for a 5ms debounce interval. Then, simply look
+    for transitions ending in both bits in the encoder being off, which
+    indicates the the encoder is resting in a detent. If bit '2' is
+    turning off, the encoder was rotated clockwise, otherwise the encoder
+    was rotated counter clockwise.
+    
+    This is a lot more reliable, although still not perfect.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ef48e1bb73c791d731b0d2c0e5beef1539103049
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 5 23:46:34 2014 -0700
+
+    altos: Clean up trailing whitespace in ao_pad.c
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c8ad50495e2d81209a4882dd4f82c19d9ae2ac34
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 5 23:45:30 2014 -0700
+
+    altos: Fix byte offsets in the mega AO_LOG_FLIGHT packets
+    
+    Just comments, but even those should be correct
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit b22dff94778b1f15a6ad1989d526b936f0fa09ea
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 5 23:43:44 2014 -0700
+
+    altos: ublox driver always offers course data when it has a fix
+    
+    Set the AO_GPS_COURSE_VALID bit to signal that this part of the GPS
+    data is valid.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c9d6a1fbb3148f03864df6d1ed5f6b6dccd7b383
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 5 23:41:43 2014 -0700
+
+    altosui: Add GPS course, ground speed and climb rate to graphs
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 39fbc4cb1d4c92522c90aa5e36fd62a4827d8306
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 5 23:38:44 2014 -0700
+
+    altoslib: Parse remaining mega AO_LOG_FLIGNT and AO_LOG_GPS_TIME fields
+    
+    GPS fields past 'day' were not getting parsed. Ground values for the
+    IMU were not getting parsed, but a false 'temperature' value was being read.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d2e6efa810b7fccc5af937386a40ae5af064bf26
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon May 5 23:38:05 2014 -0700
+
+    altoslib: Add a comment to remind us to fix the IMU code to deal with calibration
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d59d6787bfe26c3b18491ece602ad6cc5cf26c42
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat May 3 10:58:31 2014 -0700
+
+    altos: 8051 64 * 16 multiply function was broken for negative 64-bit
+    
+    It was jumping around the actual multiply when the 64-bit argument was negative.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c49e13a7807a74bb66c83cd4a2e10eb601f59e62
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu May 8 16:24:26 2014 -0600
+
+    relay control implemented, this project is now complete
+
+commit acaad70e3db8f0b6ae45ca8309833db57bdf5ca2
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu May 8 16:09:11 2014 -0600
+
+    first cut of usbrelay-v0.1 support .. LEDs wiggle, not switching relay yet
+
+commit 2dfc4bc92b11252f17103f28198a702a3fdc2b2d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri May 2 13:53:08 2014 -0700
+
+    altosui: Add configuration UI for beeper tone
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 027b1470c7a2d007eaab5c8d49f772b0c7559b80
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri May 2 12:26:07 2014 -0700
+
+    altos: Add configurable beep tone
+    
+    This lets you directly set the mid-range beep tone; the high and low
+    tones remain set off of that in the same ratio as before.
+    
+    Note that none of the cc1111 products get this feature as they don't
+    have enough flash space anymore...
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8e3842660274ac4bcd7b5a78f5db215222b1c4de
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 30 22:14:37 2014 -0700
+
+    altos: For telelco discovery packets, retry 5 times with shorter timeout
+    
+    A timeout of 10ms is more than enough to receive a query packet, but
+    if we miss it during device discovery, it's a pain, so retry 5 times
+    to make sure we find everyone.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0223fced2c6d2b9f63ede6258afae46c3f55c200
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 30 22:13:44 2014 -0700
+
+    ao-tools: Clean up ao-sym structure an initializers
+    
+    Remove unused 'default_addr' field. Use named initializers when
+    setting up the struct.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 35efd4e51ece706234f80c076eb7f4f70c66098d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 30 22:12:30 2014 -0700
+
+    ao-load: Make ao_sym static to avoid collision with ao-editaltos
+    
+    ao-load doesn't use ao-editaltos at this point, but does share the
+    same name for the symbol table. To make the linker happier, make the
+    ao-load version static.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit fd406000659a11862e05c22dbb20cdb738f56b01
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 30 22:11:39 2014 -0700
+
+    ao-telem: Dump orientation field from TeleMega sensor telemetry packet
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2cf65d60e1c73dbff0badbe1ee6cb43d75bf803c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 30 22:10:29 2014 -0700
+
+    altosui: Mark TeleMega additional pyro ignitor fired points in graphs
+    
+    Add markers to indicate when each additional pyro channel fires
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ecebb3902868d1d7485d2bc99ba4140c6b90567e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 30 21:30:46 2014 -0700
+
+    altoslib: Track pyro firing state when reading mega eeprom files
+    
+    TeleMega records whether each pyro has been fired in the eeprom file;
+    track that in the AltosState record.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5fb246fb50e262aa81ef7eb430be9782cfcf8848
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Apr 29 19:04:30 2014 -0700
+
+    altosui: Add extra ignitors to graphable objects
+    
+    List all of the available extra ignitors as possible things to graph.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f8429152e438eb72618edaf5983ae1cd5d3d4dab
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Apr 13 08:58:36 2014 -0600
+
+    ugly hack (just make sleep longer) to work around ttyACM* discovery issue
+
+commit 3b5c4d88671e6c511fbfb1ce6b046f558dd6c2bf
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 12 17:46:34 2014 -0700
+
+    altos: Switch beeping to farnsworth spacing
+    
+    Use 17wpm/12wpm farnsworth spacing for the state reports. Leave the
+    numeric reports running slowly as those require counting.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8628f7e02834a476d5cb3afa4cbf8d46a4b3c513
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 12 17:45:38 2014 -0700
+
+    altosuilib: Make lines in graphs 2 units wide
+    
+    This makes the graphs a lot easier to read.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9e18c524fa2d1f648f265b3c3105f5ceacf06c10
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 11 16:40:06 2014 -0700
+
+    altoslib/altosui/altosuilib/libaltos: Remove trailing whitespace
+    
+    Just cleaning up the source code.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7b275ddfe20f54857d7d1abb98607c406b678090
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 11 16:31:32 2014 -0700
+
+    altos: Add 'microwater' product
+    
+    This is a custom firmware spin for micropeak designed for use with
+    water rockets that sets the boost detect altitude to 10m instead of 30m.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 99c729495a8cc589718607ee35d22454c6af2994
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 6 23:46:48 2014 -0700
+
+    altosui: Disable flight log configuration while flights are stored
+    
+    The log code won't let you resize the maximum flight log while there
+    is still data on the flight computer; the code to figure that out in
+    the UI was busted, leaving users confused about why it wasn't working.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4211c59e585545817b3cac02b41bb73106d6403e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 6 22:27:37 2014 -0700
+
+    altos: Fix nanopeak compile
+    
+    Nanopeak uses port B bit 3 for the LED instead of bit 4. Fix the async
+    code to support arbitrary bits for the serial LED.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 350d941a825d0271933de0bfdea82d3af5744c21
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 6 20:14:49 2014 -0700
+
+    altos: Provide stable binaries for MicroPeak
+    
+    Publish MicroPeak .hex file to LLC repo and install it from there,
+    rather than rebuilding it locally. This ensures that the installed
+    bits don't depend on local configuration of any kind.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2427eae5f3b429d302fbe14f708dcbc68c851954
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Apr 6 19:48:07 2014 -0700
+
+    altos: Replace C code attiny async output with inline asm
+    
+    Using inline asm instead of C ensures that compiler changes will not
+    affect the timing of the serial data.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 1d943d4cade0a40723143626abf6e67f8eca9dcb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 5 18:17:17 2014 -0700
+
+    altos: Build TeleBalloon v2.0 by default
+    
+    We're supporting this now, we might as well build it.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c14cfb1436c988eb0a0d26d7c4d83aeccecbc8a3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 5 18:16:21 2014 -0700
+
+    ao-bringup: Split out easymini test into separate script
+    
+    This lets you run the easy mini testing code without also flashing the device.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9cb10d73fee0e3f36c778fd2a9c9992b87669fe2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 5 18:14:35 2014 -0700
+
+    altosui: Add ignitor tab for TeleMega extra ignitors
+    
+    Show the current state of the additional ignitors in another tab;
+    there's not really room in the 'Pad' tab.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ca66a035edecd7feffcd22257d3413ce0e189c07
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 5 00:28:13 2014 -0700
+
+    doc: Document new voltage beeping at startup time
+
+commit 18148c33540cda8cb6658724a048ffd426c1a6bb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 5 00:20:22 2014 -0700
+
+    Bump version to 1.3.3
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0d367fc24bfd0377db6f3b00a888a18245616767
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Apr 5 00:18:57 2014 -0700
+
+    altos: Report battery voltage instead of S at startup
+    
+    This works on everything with a beeper except TeleMetrum v1.0 which
+    just doesn't have enough flash space for the code.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8bd732ac9cb816630f46dd269448ff8422620df8
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 4 23:40:22 2014 -0700
+
+    doc: Outline files are now generated, so don't put them in git
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ca4b20f9781b1dc6974d26952973dfe0d607478c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 4 23:38:40 2014 -0700
+
+    ao-tools: Wait for device to become ready instead of failing
+    
+    For some reason, USB devices take 'a while' to become usable; instead
+    of bailing immediately, sit around waiting to see if the device
+    becomes usable if we get an EBUSY or EACCES error.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2424c0e6fe53789dc83d1e96439dcdc13e847b07
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 4 23:37:15 2014 -0700
+
+    ao-tools: Use 'program' command in ao-flash-lpc instead of 'flash'
+    
+    The program meta-command is supposed to do the whole thing, and seems
+    more reliable in actually getting what we want flashed to the board.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 4800497fa1fc449807ef0097cc3fed367641ae29
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 4 23:36:34 2014 -0700
+
+    ao-bringup: Get turnon_telemini working
+    
+    This script now does complete testing of the board
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 24167015705ae831692b95735968b04a876f935e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Apr 4 23:34:48 2014 -0700
+
+    altos: Rename 'core' to 'kernel'
+    
+    core remains a bad name to use -- dirvish skips files (and
+    directories, it seems) with that name.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bb9fdef607728cc326a82aa632e59724f272e53b
+Author: Keith Packard <keithp@keithp.com>
+Date:   Thu Apr 3 00:10:19 2014 -0700
+
+    altoslib: Missed a couple of easy mini voltage API changes
+    
+    Oh, and Tm was using Em conversions (which is almost right, except Tm
+    doesn't have the history)
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 834cd051af1b80a98678de221d3c45cb30f8bb0d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 2 23:35:36 2014 -0700
+
+    Add easymini turnon script and helpers
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 21d584b9bf93b96a05ab374105493c0e17df320f
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 2 22:04:18 2014 -0700
+
+    altoslib: Fix EasyMini voltage computations
+    
+    Early Em prototypes had a 3.0V regulator.
+    Early v1.0 boards measured power past the blocking diode.
+    
+    Deal with both conditions to try and report more accurate voltages for
+    EasyMini data.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit adddad0dd45f67d01487c8dd75b040ca3ab50fe2
+Author: Keith Packard <keithp@keithp.com>
+Date:   Wed Apr 2 20:36:26 2014 -0700
+
+    altoslib: Ignore speed/accel after boost when finding maxima
+    
+    Large spikes in acceleration often occur with ejection charges, which
+    can cause bogus acceleration and speed data to be seen. Ignore those
+    for the purpose of computing the maximum values of each.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ff4deb417a460d96645fb6934890c2c195142be3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Mar 28 23:33:25 2014 -0700
+
+    altos: HAS_LED is useless; remove it
+    
+    ao_flight was trying to decide whether to turn off the red LED by
+    checking whether HAS_LED was defined. And yet, none of the flight
+    firmware defines that anymore, except for easymini which defines it to
+    zero.
+    
+    Remove all uses and defines of this value, substituting AO_LED_RED in
+    ao_flight.c, which has to be defined for the ao_led_off call to work.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ca0bf9fb2d6323d7a454e5ce04b48d11366eee67
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Mar 16 18:12:33 2014 -0700
+
+    Add easymega firmware
+    
+    A trimmed down TeleMega build with no radio or GPS, along with pin
+    changes necessary for the device.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 7e0b549b9b30d0a1290d28b2b94025a98af6a4de
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Mar 10 22:55:45 2014 -0700
+
+    altosui: Hide Tilt Angle values when not available
+    
+    In the Ascent table, make sure the tilt angle fields are hidden when
+    they are set to MISSING.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3b50e50fb814a572f7b4ea9e268a1ae150fe678c
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Mar 9 21:10:10 2014 -0700
+
+    altos: Another missing usbtrng file
+
+commit b5ac64bc0a6fd0fc23f39283e469c9820bdc88fe
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Mar 9 21:08:25 2014 -0700
+
+    altos: Missing ao_pins files for usbtrng
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 469bd376d84bf8d76faa3b726d96061d4d98b998
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Mar 9 20:59:43 2014 -0700
+
+    altos: Fix LPC LED driver
+    
+    Was using wrong types
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6a4a074d690fb34af49704ac3cc4826eaf06dd9d
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Mar 9 20:58:36 2014 -0700
+
+    altos: fix building LPC serial support for STDIO
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9671ca6c42544463fd551f81113c221265a2296e
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Mar 9 20:57:31 2014 -0700
+
+    altos: Don't require projects to define PACKET_HAS_SLAVE
+    
+    Really, most don't need it, and whinging about not having it defined
+    isn't useful.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit e1e00a4b67fbdbae339219b35aefd44a1bcf9486
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Mar 8 21:39:33 2014 -0800
+
+    Add USB True Random Number Generator product
+    
+    Just basic device support
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6dad9ca543fbed3f849b01300224b1b21ef2eb08
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Mar 8 16:25:33 2014 -0800
+
+    Re-add LCD bits to stm-demo
+
+commit 32f0f39a953dabe19ec92611570e4a82da8f8dce
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sat Mar 8 16:25:10 2014 -0800
+
+    Add flash loader for stm-demo board
+
+commit 4c7da6d0ad568448c37761cd0c0108b9161a9345
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Mar 7 21:27:26 2014 -0800
+
+    doc: Add separate outline pdf generation
+    
+    This generates one-page pdf files that contain just the outline of
+    each product.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8f2a85027b496451c5934eb36fcdffbd5e5da177
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Feb 28 23:04:54 2014 -0800
+
+    Install .desktopfile as _SCRIPTS so they are left executable
+    
+    .desktop files should be marked executable so that the desktop
+    environment knows they are correct.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a072cbb137126e677d3ebbf0245ec4ea5aa481ad
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Feb 28 21:16:57 2014 -0800
+
+    altosui: Retry device enumeration after rebooting for self flash
+    
+    Windows takes 'a while' to include the rebooted device in the list of
+    available devices, so try a few times with a 100ms delay so that we
+    can avoid asking the user to select from an empty list.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ac2cfb03158b4902466a72edad5dc471ee6bdb91
+Author: Keith Packard <keithp@keithp.com>
+Date:   Fri Feb 28 21:16:36 2014 -0800
+
+    Mark development sequence to 1.3.3 by bumping version to 1.3.2.1
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 57e5d13c0577e1b0a6e8117e2d04eeda6cf0b045
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Feb 23 17:42:08 2014 -0800
+
+    libaltos: Link so with -znoexecstack flag
+    
+    This marks the library as not requiring an executable stack, which
+    openjdk prefers
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 104b8bfc9b37fda175f2cb2a1e33601fbf6f48f6
+Merge: 403b95e 1edf7ef
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Feb 20 13:23:52 2014 -0700
+
+    Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit 403b95ee27782309b564855b85285c9f5f5c7068
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Feb 20 13:23:32 2014 -0700
+
+    update turnon scripts to store cal values
+
+commit 3ef0cc28758c68e6076afa809e157a84ce3661fb
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Feb 20 13:23:20 2014 -0700
+
+    typo fixes from Matt Kraai
+
+commit 1edf7ef8026ac4ab698a7f99671e9348d18ffd0a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Feb 18 09:47:51 2014 -0800
+
+    altos: Create balloon-specific load for TMv2 hardware
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ff4ae350c24b3d6ef71e29191bb719b07ab9c5bb
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Feb 18 09:46:17 2014 -0800
+
+    altos: Make balloon code run again
+    
+    This fixes the balloon code so that it works with recent altos bits
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8b6f051663dd17492bece9efb9e898ef113ab414
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Feb 18 09:45:41 2014 -0800
+
+    altos: Set reasonable accel values when !HAS_ACCEL
+    
+    This lets us use telemetrum log and telemetry formats for balloons
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9f6983e3d61fa5231f3d0ce33dbc5aadf946b597
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Feb 18 09:44:52 2014 -0800
+
+    altos: Expose ao_usb_running globally
+    
+    This lets other bits of the code know when USB has been connected.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 9b9d5b273a410e315739c5c6eaa4105523056b9a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Tue Feb 18 09:43:43 2014 -0800
+
+    altos: Move balloon flight code to core
+    
+    This lets us create more than one balloon product
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 43b1797189095c402e1c35bdc317c4196e180e66
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 17 21:30:28 2014 -0800
+
+    doc: Need to publish .svg files as well
+    
+    The drill templates are all .svg files that are referenced by the
+    generated html.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 874d0065ecb066ee746a016876edebc7cc6e3d96
+Author: Keith Packard <keithp@keithp.com>
+Date:   Mon Feb 17 21:27:57 2014 -0800
+
+    Re-create drill templates
+    
+    Using inkscape, the drill templates weren't getting printed
+    correctly. Switching to hand-generated svg fixes that.
+    
+    The .xsl file is also fixed to really encourage the images to be
+    printed at exactly 100%.
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6e713f0a53d608a8855884b7a48e4e3423d8a3d2
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Feb 17 00:15:58 2014 -0700
+
+    deliver images used in MicroPeak manual to web server, too
+
+commit 1d421a43494cf2003ac23fb8cd21d6ae05edfac8
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Mon Feb 17 00:10:05 2014 -0700
+
+    update copyright year assertion in MicroPeak manual, remember during releases
+
+commit a3ddb5906167e445f937b16fafb7f5c537852f0a
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Feb 16 18:01:10 2014 -0800
+
+    Mark .desktop files as executable
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c860d837a0c97a091c5f47fce91bdb8beb4602d3
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Feb 16 15:53:50 2014 -0800
+
+    micropeak: Construct linux install script
+    
+    Uses the same script as altosui, just edits the final path name
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 948a614a62754fd4fffd9b84ad83fd444e4f0437
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Feb 16 15:17:40 2014 -0800
+
+    Move .desktop and icon management out of debian dir
+    
+    This constructs a .desktop file from a template and installs it, along
+    with suitable .svg icons, during the normal build process
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 066a01ad0b4e73fdb47b43a42c1d0b7fae81a180
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Feb 16 14:57:38 2014 -0800
+
+    Put altusmetrum.svg and micropeak.svg in icon directory
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 95f5a6ef52947088993d395874cf6aa502fd2503
+Merge: 135b6d4 de2a619
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Feb 16 15:53:35 2014 -0700
+
+    Merge branch 'master' of ssh://git.gag.com/scm/git/fw/altos
+
+commit 135b6d4019f584c050b3d70c11fb5bcf2c7396c4
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Feb 16 15:53:22 2014 -0700
+
+    use svg in the .desktop file
+
+commit 13dccd1869cdf00d4aa0df55a3ece33936cd520a
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Sun Feb 16 15:51:32 2014 -0700
+
+    have the cal-freq script save cal values to a file
+
+commit de2a619900ee23911c866d5aaff63a0f9388bfc7
+Author: Keith Packard <keithp@keithp.com>
+Date:   Sun Feb 16 13:01:29 2014 -0800
+
+    Add linux installer script
+    
+    Create a linux installer shell script that unpacks the archive in a
+    sensible place and adds a .desktop file to the environment
+    
+    Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit bf268354535a3a7b2e093235e5347ed2a6d809ff
+Author: Bdale Garbee <bdale@gag.com>
+Date:   Thu Feb 13 21:53:13 2014 -0700
+
+    updating changelog for release
+
 commit e53be56179f4cd93227b6bdc28c2ae60b81db57d
 Author: Keith Packard <keithp@keithp.com>
 Date:   Sun Feb 9 23:47:47 2014 -0800
index fa4da1fe65939473c1f2c9fe54b294d11a4180dc..15d2c82da0c1263f4a6cc68e120b08efd090b086 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS=ao-tools src doc altoslib libaltos altosuilib altosui micropeak ao-utils altosdroid
+SUBDIRS=ao-tools src doc icon altoslib libaltos altosuilib altosui micropeak ao-utils altosdroid telegps
 
 EXTRA_DIST = ChangeLog
 
@@ -20,6 +20,7 @@ fat:
        cd altosuilib && $(MAKE) all
        cd altosui && $(MAKE) fat
        cd micropeak && $(MAKE) fat
+       cd telegps && $(MAKE) fat
 
 set-java-versions:
-       $(top_srcdir)/fix-java-versions org.altusmetrum.altoslib=$(ALTOSLIB_VERSION) org.altusmetrum.altosuilib=$(ALTOSUILIB_VERSION)
\ No newline at end of file
+       $(top_srcdir)/fix-java-versions org.altusmetrum.altoslib=$(ALTOSLIB_VERSION) org.altusmetrum.altosuilib=$(ALTOSUILIB_VERSION)
index 1c8bd2a1b61f3525945a0ba0a3f64a02d3527f58..1822efbe9d29cf87f30764f0e37cbbd0f6f6a194 100644 (file)
--- a/Releasing
+++ b/Releasing
@@ -7,6 +7,12 @@ These are Bdale's notes on how to do a release.
          and add release to the revision history at the front (release notes
          will be pulled in automatically)
 
+       - get a Google Maps API key and install it in
+          ~/altusmetrumllc/google-maps-api-key. If you don't have a
+          key, the app will still work, but downloading map tiles will
+          be slow, and you will only be able to download a limited
+          number per day.
+
        - update the version in configure.ac
         git log > ChangeLog
        git commit -a
@@ -56,6 +62,19 @@ These are Bdale's notes on how to do a release.
 
                this pushes packages for each platform to web site
 
+       # store a stable copy of ARM binaries for production use
+       cp src/easymini-v1.0/*.elf \
+          src/telegps-v1.0/*.elf \
+          src/telemega-v1.0/*.elf \
+          src/telemetrum-v2.0/*.elf \
+          ~/altusmetrumllc/Binaries/
+       cp src/easymini-v1.0/flash-loader/*.elf \
+          src/telegps-v1.0/flash-loader/*.elf \
+          src/telemega-v1.0/flash-loader/*.elf \
+          src/telemetrum-v2.0/flash-loader/*.elf \
+          ~/altusmetrumllc/Binaries/loaders/
+       (cd ~/altusmetrumllc ; git commit -a) 
+
        - copy the relevant release notes file from doc/ to 
            /home/bdale/web/altusmetrum/AltOS/releases/<rev>
 
index 1590e0c952697b63cf787588faa8f06534267320..d5784483e74663a869df6a1cdb3611563537bb2a 100644 (file)
@@ -40,6 +40,8 @@ SRC=$(JAVA_SRC) $(DRAWABLES)
 
 all: $(all_target)
 
+.NOTPARALLEL:
+
 $(EXT_LIBDIR):
        mkdir -p $(EXT_LIBDIR)
 
index 634769ccff6e7e94fc5de49ce665a735e113ec11..1b4d45ed3e66536eabac8b1ca25633fa6d1a4be3 100644 (file)
@@ -31,7 +31,7 @@ import android.os.Handler;
 //import android.os.Message;
 import android.util.Log;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 public class AltosBluetooth extends AltosLink {
 
index 9125d56bfa6ceed6843491b8181f91889dacb712..f61baf1e411a933518bc1cf245f20ddd8673511d 100644 (file)
@@ -49,7 +49,7 @@ import android.widget.Toast;
 import android.app.AlertDialog;
 import android.location.Location;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 public class AltosDroid extends FragmentActivity {
        // Debugging
index 067cb6208a014ce745feb1e556ac6abf4e1624de..f6e6881de3df550b08eb29832541af0ae8fc37e0 100644 (file)
@@ -23,7 +23,7 @@ import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Environment;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 public class AltosDroidPreferences implements AltosPreferencesBackend {
        public final static String        NAME    = "org.altusmetrum.AltosDroid";
index 9d155385db3f61fee18fca876923e500d9518744..fac4b8d4530027de625ccd39430828b6d940d1ab 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 import android.location.Location;
 
 public interface AltosDroidTab {
index ebddc2661023a1d960a90eec0b3606104bbd4652..223ae75a0e48f9e99f91f0b85a758ee260e08730 100644 (file)
@@ -34,10 +34,14 @@ public class AltosViewPager extends ViewPager {
 
     @Override
     protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
-        if(v.getClass().getPackage().getName().startsWith("maps.")){
+       if(v.getClass() != null &&
+          v.getClass().getPackage() != null &&
+          v.getClass().getPackage().getName() != null &&
+          v.getClass().getPackage().getName().startsWith("maps."))
+       {
             return true;
         }
         return super.canScroll(v, checkV, dx, x, y);
     }
 
-}
\ No newline at end of file
+}
index b50cab2232254e8f4d68aff83d233b16a685e492..5e8515cb35d8a06e753e6fdb210809e73199a2de 100644 (file)
@@ -21,7 +21,7 @@ package org.altusmetrum.AltosDroid;
 import android.speech.tts.TextToSpeech;
 import android.speech.tts.TextToSpeech.OnInitListener;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 public class AltosVoice {
 
@@ -63,14 +63,17 @@ public class AltosVoice {
 
                boolean spoke = false;
                if (old_state == null || old_state.state != state.state) {
-                       speak(state.state_name());
+                       if (state.state != AltosLib.ao_flight_stateless)
+                               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)));
+                               if (state.max_speed() != AltosLib.MISSING)
+                                       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)));
+                               if (state.max_height() != AltosLib.MISSING)
+                                       speak(String.format("max height: %d meters.", (int) (state.max_height() + 0.5)));
                                spoke = true;
                        }
                }
@@ -109,8 +112,9 @@ public class AltosVoice {
                        }
 
                        /* If the rocket isn't on the pad, then report height */
-                       if (AltosLib.ao_flight_drogue <= state.state &&
-                           state.state < AltosLib.ao_flight_landed &&
+                       if (((AltosLib.ao_flight_drogue <= state.state &&
+                             state.state < AltosLib.ao_flight_landed) ||
+                            state.state == AltosLib.ao_flight_stateless) &&
                            state.range >= 0)
                        {
                                speak(String.format("Height %d, bearing %s %d, elevation %d, range %d.\n",
@@ -121,7 +125,8 @@ public class AltosVoice {
                                                    (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)));
+                               if (state.height() != AltosLib.MISSING)
+                                       speak(String.format("%d meters", (int) (state.height() + 0.5)));
                        } else {
                                reported_landing = 0;
                        }
index edfd82458f1392cee616a26303f1e05128a472c4..e4a815eb6f929f57b218a2988da17fe25dc76215 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import android.app.Activity;
 import android.os.Bundle;
index cc070b0d1192dbfa14532b18bd72d4c77d09587c..cbbe4d4473ab9bc62f09c201d0248e008def6737 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import android.app.Activity;
 import android.os.Bundle;
index 5a70397825a47a969f391bd45c51e924bcc73ecf..b2e6fd2016a87877cca3d12fa973804239f7f8d8 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import android.app.Activity;
 import android.os.Bundle;
index 5fe88f51c3a0c39818258b833e9ab7f2083e410f..38922771f73f097e4938ccbddca1423ceca4a2a8 100644 (file)
@@ -19,7 +19,7 @@ package org.altusmetrum.AltosDroid;
 
 import java.util.Arrays;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import com.google.android.gms.maps.CameraUpdateFactory;
 import com.google.android.gms.maps.GoogleMap;
index 3f0a188703c0eda6cdbd6ec6f678e78623bec5b6..2d88974d3d787f516c15ea352b6e3936a5cfae84 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import android.app.Activity;
 import android.os.Bundle;
@@ -125,7 +125,9 @@ public class TabPad extends Fragment implements AltosDroidTab {
                        mDataLoggingLights.set(state.flight != 0, state.flight == AltosLib.MISSING);
 
                        if (state.gps != null) {
-                               mGPSLockedView.setText(AltosDroid.integer("%4d sats", state.gps.nsat));
+                               int soln = state.gps.nsat;
+                               int nsat = state.gps.cc_gps_sat != null ? state.gps.cc_gps_sat.length : 0;
+                               mGPSLockedView.setText(String.format("%4d in soln, %4d in view", soln, nsat));
                                mGPSLockedLights.set(state.gps.locked && state.gps.nsat >= 4, false);
                                if (state.gps_ready)
                                        mGPSReadyView.setText("Ready");
index c8c61838989d59ae48d85c31de93c481eb1accb6..4215a3303df0d757a8b14ca80ee016f6654a2094 100644 (file)
@@ -1,6 +1,6 @@
 package org.altusmetrum.AltosDroid;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
index 2a2cc4040de33ead81269752adbd99716a559e4a..5bc4b90dd9e417ec4901611e9b2b0b10ea968ac4 100644 (file)
@@ -25,7 +25,7 @@ import java.util.concurrent.*;
 import android.util.Log;
 import android.os.Handler;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 
 public class TelemetryReader extends Thread {
index 96cedad81aeca07e0bce56db0c1c8e014514daac..da5e044f0abc5b122416b996c4c81149ccb07c11 100644 (file)
@@ -44,7 +44,7 @@ import android.location.LocationManager;
 import android.location.LocationListener;
 import android.location.Criteria;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 
 public class TelemetryService extends Service implements LocationListener {
index 43dc20bd3f0a33322603da70d0eb981151f0b4cd..3d340e5d2c32f7d31e1a11535cf9cdef0133f4be 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosAccel extends AltosUnits {
 
index 949627317800c07aa46e2d9c8ed5636863034b72..253ca435dc83753330397a623639133ace8401b3 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosCRCException extends Exception {
        public int rssi;
diff --git a/altoslib/AltosCSV.java b/altoslib/AltosCSV.java
new file mode 100644 (file)
index 0000000..27e1fad
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * 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_4;
+
+import java.io.*;
+import java.util.*;
+
+public class AltosCSV implements AltosWriter {
+       File                    name;
+       PrintStream             out;
+       boolean                 header_written;
+       boolean                 seen_boost;
+       int                     boost_tick;
+       LinkedList<AltosState>  pad_states;
+       AltosState              state;
+
+       static final int ALTOS_CSV_VERSION = 5;
+
+       /* Version 4 format:
+        *
+        * General info
+        *      version number
+        *      serial number
+        *      flight number
+        *      callsign
+        *      time (seconds since boost)
+        *      clock (tick count / 100)
+        *      rssi
+        *      link quality
+        *
+        * Flight status
+        *      state
+        *      state name
+        *
+        * Basic sensors
+        *      acceleration (m/s²)
+        *      pressure (mBar)
+        *      altitude (m)
+        *      height (m)
+        *      accelerometer speed (m/s)
+        *      barometer speed (m/s)
+        *      temp (°C)
+        *      battery (V)
+        *      drogue (V)
+        *      main (V)
+        *
+        * Advanced sensors (if available)
+        *      accel_x (m/s²)
+        *      accel_y (m/s²)
+        *      accel_z (m/s²)
+        *      gyro_x (d/s)
+        *      gyro_y (d/s)
+        *      gyro_z (d/s)
+        *      mag_x (g)
+        *      mag_y (g)
+        *      mag_z (g)
+        *
+        * GPS data (if available)
+        *      connected (1/0)
+        *      locked (1/0)
+        *      nsat (used for solution)
+        *      latitude (°)
+        *      longitude (°)
+        *      altitude (m)
+        *      year (e.g. 2010)
+        *      month (1-12)
+        *      day (1-31)
+        *      hour (0-23)
+        *      minute (0-59)
+        *      second (0-59)
+        *      from_pad_dist (m)
+        *      from_pad_azimuth (deg true)
+        *      from_pad_range (m)
+        *      from_pad_elevation (deg from horizon)
+        *      hdop
+        *
+        * GPS Sat data
+        *      C/N0 data for all 32 valid SDIDs
+        *
+        * Companion data
+        *      companion_id (1-255. 10 is TeleScience)
+        *      time of last companion data (seconds since boost)
+        *      update_period (0.1-2.55 minimum telemetry interval)
+        *      channels (0-12)
+        *      channel data for all 12 possible channels
+        */
+
+       void write_general_header() {
+               out.printf("version,serial,flight,call,time,clock,rssi,lqi");
+       }
+
+       void write_general(AltosState state) {
+               out.printf("%s, %d, %d, %s, %8.2f, %8.2f, %4d, %3d",
+                          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(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(AltosState state) {
+               out.printf("%8.2f,%10.2f,%8.2f,%8.2f,%8.2f,%8.2f,%5.1f,%5.2f,%5.2f,%5.2f",
+                          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(AltosState state) {
+               AltosIMU        imu = state.imu;
+               AltosMag        mag = state.mag;
+
+               if (imu == null)
+                       imu = new AltosIMU();
+               if (mag == null)
+                       mag = new AltosMag();
+               out.printf("%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d",
+                          imu.accel_x, imu.accel_y, imu.accel_z,
+                          imu.gyro_x, imu.gyro_y, imu.gyro_z,
+                          mag.x, mag.y, mag.z);
+       }
+
+       void write_gps_header() {
+               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(AltosState state) {
+               AltosGPS        gps = state.gps;
+               if (gps == null)
+                       gps = new AltosGPS();
+
+               AltosGreatCircle from_pad = state.from_pad;
+               if (from_pad == null)
+                       from_pad = new AltosGreatCircle();
+
+               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,
+                          gps.lat,
+                          gps.lon,
+                          gps.alt,
+                          gps.year,
+                          gps.month,
+                          gps.day,
+                          gps.hour,
+                          gps.minute,
+                          gps.second,
+                          from_pad.distance,
+                          state.range,
+                          from_pad.bearing,
+                          state.elevation,
+                          gps.hdop);
+       }
+
+       void write_gps_sat_header() {
+               for(int i = 1; i <= 32; i++) {
+                       out.printf("sat%02d", i);
+                       if (i != 32)
+                               out.printf(",");
+               }
+       }
+
+       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) {
+                               for(int j = 0; j < gps.cc_gps_sat.length; j++)
+                                       if (gps.cc_gps_sat[j].svid == i) {
+                                               c_n0 = gps.cc_gps_sat[j].c_n0;
+                                               break;
+                                       }
+                       }
+                       out.printf ("%3d", c_n0);
+                       if (i != 32)
+                               out.printf(",");
+               }
+       }
+
+       void write_companion_header() {
+               out.printf("companion_id,companion_time,companion_update,companion_channels");
+               for (int i = 0; i < 12; i++)
+                       out.printf(",companion_%02d", i);
+       }
+
+       void write_companion(AltosState state) {
+               AltosCompanion companion = state.companion;
+
+               int     channels_written = 0;
+               if (companion == null) {
+                       out.printf("0,0,0,0");
+               } else {
+                       out.printf("%3d,%5.2f,%5.2f,%2d",
+                                  companion.board_id,
+                                  (companion.tick - boost_tick) / 100.0,
+                                  companion.update_period / 100.0,
+                                  companion.channels);
+                       for (; channels_written < companion.channels; channels_written++)
+                               out.printf(",%5d", companion.companion_data[channels_written]);
+               }
+               for (; channels_written < 12; channels_written++)
+                       out.printf(",0");
+       }
+
+       void write_header(boolean advanced, boolean gps, boolean companion) {
+               out.printf("#"); write_general_header();
+               out.printf(","); write_flight_header();
+               out.printf(","); write_basic_header();
+               if (advanced)
+                       out.printf(","); write_advanced_header();
+               if (gps) {
+                       out.printf(","); write_gps_header();
+                       out.printf(","); write_gps_sat_header();
+               }
+               if (companion) {
+                       out.printf(","); write_companion_header();
+               }
+               out.printf ("\n");
+       }
+
+       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(state); out.printf(",");
+                       write_gps_sat(state);
+               }
+               if (state.companion != null) {
+                       out.printf(",");
+                       write_companion(state);
+               }
+               out.printf ("\n");
+       }
+
+       void flush_pad() {
+               while (!pad_states.isEmpty()) {
+                       write_one (pad_states.remove());
+               }
+       }
+
+       public void write(AltosState state) {
+               if (state.state == AltosLib.ao_flight_startup)
+                       return;
+               if (!header_written) {
+                       write_header(state.imu != null || state.mag != null,
+                                    state.gps != null, state.companion != null);
+                       header_written = true;
+               }
+               if (!seen_boost) {
+                       if (state.state >= AltosLib.ao_flight_boost) {
+                               seen_boost = true;
+                               boost_tick = state.tick;
+                               flush_pad();
+                       }
+               }
+               if (seen_boost)
+                       write_one(state);
+               else
+                       pad_states.add(state);
+       }
+
+       public PrintStream out() {
+               return out;
+       }
+
+       public void close() {
+               if (!pad_states.isEmpty()) {
+                       boost_tick = pad_states.element().tick;
+                       flush_pad();
+               }
+               out.close();
+       }
+
+       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_states = new LinkedList<AltosState>();
+       }
+
+       public AltosCSV(File in_name) throws FileNotFoundException {
+               this(new PrintStream(in_name), in_name);
+       }
+
+       public AltosCSV(String in_string) throws FileNotFoundException {
+               this(new File(in_string));
+       }
+}
index 47ca328e5bcd9c70f5b8721b812cbcbcd9fd5966..09bfe9f3c7482e3a5238b27e7340be074ee1de63 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosCompanion {
        public final static int board_id_telescience = 0x0a;
index c4e108f848e40313b6113ad9e8539231c30f1dcb..e104395803c7dd2cc3ba63b36fe8d8081d99c350 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.*;
 import java.text.*;
@@ -29,6 +29,7 @@ public class AltosConfigData implements Iterable<String> {
        public int      serial;
        public int      flight;
        public int      log_format;
+       public int      log_space;
        public String   version;
 
        /* Strings returned */
@@ -66,10 +67,14 @@ public class AltosConfigData implements Iterable<String> {
        public AltosPyro[]      pyros;
        public int              npyro;
        public int              pyro;
+       public double           pyro_firing_time;
 
        /* HAS_APRS */
        public int              aprs_interval;
 
+       /* HAS_BEEP */
+       public int              beep;
+
        /* Storage info replies */
        public int      storage_size;
        public int      storage_erase_unit;
@@ -77,6 +82,10 @@ public class AltosConfigData implements Iterable<String> {
        /* Log listing replies */
        public int      stored_flight;
 
+       /* HAS_TRACKER */
+       public int      tracker_motion;
+       public int      tracker_interval;
+
        public static String get_string(String line, String label) throws  ParseException {
                if (line.startsWith(label)) {
                        String  quoted = line.substring(label.length()).trim();
@@ -100,10 +109,40 @@ public class AltosConfigData implements Iterable<String> {
                throw new ParseException("mismatch", 0);
        }
 
+       public static int[] get_values(String line, String label) throws NumberFormatException, ParseException {
+               if (line.startsWith(label)) {
+                       String tail = line.substring(label.length()).trim();
+                       String[] tokens = tail.split("\\s+");
+                       if (tokens.length > 1) {
+                               int[]   values = new int[2];
+                               values[0] = Integer.parseInt(tokens[0]);
+                               values[1] = Integer.parseInt(tokens[1]);
+                               return values;
+                       }
+               }
+               throw new ParseException("mismatch", 0);
+       }
+
        public Iterator<String> iterator() {
                return lines.iterator();
        }
 
+       public int log_space() {
+               if (log_space > 0)
+                       return log_space;
+
+               if (storage_size > 0) {
+                       int     space = storage_size;
+
+                       if (storage_erase_unit > 0 && use_flash_for_config())
+                               space -= storage_erase_unit;
+
+                       if (space > 0)
+                               return space;
+               }
+               return 0;
+       }
+
        public int log_available() {
                switch (log_format) {
                case AltosLib.AO_LOG_FORMAT_TINY:
@@ -117,7 +156,7 @@ public class AltosConfigData implements Iterable<String> {
                        if (flight_log_max <= 0)
                                return 1;
                        int     log_max = flight_log_max * 1024;
-                       int     log_space = storage_size - storage_erase_unit;
+                       int     log_space = log_space();
                        int     log_used;
 
                        if (stored_flight <= 0)
@@ -182,6 +221,7 @@ public class AltosConfigData implements Iterable<String> {
                serial = 0;
                flight = 0;
                log_format = AltosLib.AO_LOG_FORMAT_UNKNOWN;
+               log_space = -1;
                version = "unknown";
 
                main_deploy = -1;
@@ -207,9 +247,15 @@ public class AltosConfigData implements Iterable<String> {
                pyro = 0;
                npyro = 0;
                pyros = null;
+               pyro_firing_time = -1;
 
                aprs_interval = -1;
 
+               beep = -1;
+
+               tracker_motion = -1;
+               tracker_interval = -1;
+
                storage_size = -1;
                storage_erase_unit = -1;
                stored_flight = 0;
@@ -223,6 +269,7 @@ public class AltosConfigData implements Iterable<String> {
                try { serial = get_int(line, "serial-number"); } catch (Exception e) {}
                try { flight = get_int(line, "current-flight"); } catch (Exception e) {}
                try { log_format = get_int(line, "log-format"); } catch (Exception e) {}
+               try { log_space = get_int(line, "log-space"); } catch (Exception e) {}
                try { version = get_string(line, "software-version"); } catch (Exception e) {}
 
                /* Version also contains MS5607 info, which we ignore here */
@@ -282,10 +329,21 @@ public class AltosConfigData implements Iterable<String> {
                                        pyros[pyro++] = p;
                        } catch (Exception e) {}
                }
+               try { pyro_firing_time = get_int(line, "Pyro time:") / 100.0; } catch (Exception e) {}
 
                /* HAS_APRS */
                try { aprs_interval = get_int(line, "APRS interval:"); } catch (Exception e) {}
 
+               /* HAS_BEEP */
+               try { beep = get_int(line, "Beeper setting:"); } catch (Exception e) {}
+
+               /* HAS_TRACKER */
+               try {
+                       int[] values = get_values(line, "Tracker setting:");
+                       tracker_motion = values[0];
+                       tracker_interval = values[1];
+               } catch (Exception e) {}
+
                /* Storage info replies */
                try { storage_size = get_int(line, "Storage size:"); } catch (Exception e) {}
                try { storage_erase_unit = get_int(line, "Storage erase unit:"); } catch (Exception e) {}
@@ -351,16 +409,16 @@ public class AltosConfigData implements Iterable<String> {
                                                       channel);
        }
 
-       public int log_limit() {
-               if (storage_size > 0 && storage_erase_unit > 0) {
-                       int     log_limit = storage_size - storage_erase_unit;
-                       if (log_limit > 0)
-                               return log_limit / 1024;
-               }
-               return 1024;
+       boolean use_flash_for_config() {
+               if (product.startsWith("TeleMega"))
+                       return false;
+               if (product.startsWith("TeleMetrum-v2"))
+                       return false;
+               return true;
        }
 
-       public void get_values(AltosConfigValues source) {
+
+       public void get_values(AltosConfigValues source) throws AltosConfigDataException {
 
                /* HAS_FLIGHT */
                if (main_deploy >= 0)
@@ -395,9 +453,21 @@ public class AltosConfigData implements Iterable<String> {
                /* AO_PYRO_NUM */
                if (npyro > 0)
                        pyros = source.pyros();
+               if (pyro_firing_time >= 0)
+                       pyro_firing_time = source.pyro_firing_time();
 
+               /* HAS_APRS */
                if (aprs_interval >= 0)
                        aprs_interval = source.aprs_interval();
+
+               /* HAS_BEEP */
+               if (beep >= 0)
+                       beep = source.beep();
+               /* HAS_TRACKER */
+               if (tracker_motion >= 0)
+                       tracker_motion = source.tracker_motion();
+               if (tracker_interval >= 0)
+                       tracker_interval = source.tracker_interval();
        }
 
        public void set_values(AltosConfigValues dest) {
@@ -410,18 +480,23 @@ public class AltosConfigData implements Iterable<String> {
                dest.set_radio_calibration(radio_calibration);
                dest.set_radio_frequency(frequency());
                boolean max_enabled = true;
+
+               if (log_space() == 0)
+                       max_enabled = false;
+
                switch (log_format) {
                case AltosLib.AO_LOG_FORMAT_TINY:
                        max_enabled = false;
                        break;
                default:
-                       if (stored_flight >= 0)
+                       if (stored_flight > 0)
                                max_enabled = false;
                        break;
                }
+
                dest.set_flight_log_max_enabled(max_enabled);
                dest.set_radio_enable(radio_enable);
-               dest.set_flight_log_max_limit(log_limit());
+               dest.set_flight_log_max_limit(log_space() / 1024);
                dest.set_flight_log_max(flight_log_max);
                dest.set_ignite_mode(ignite_mode);
                dest.set_pad_orientation(pad_orientation);
@@ -430,7 +505,11 @@ public class AltosConfigData implements Iterable<String> {
                        dest.set_pyros(pyros);
                else
                        dest.set_pyros(null);
+               dest.set_pyro_firing_time(pyro_firing_time);
                dest.set_aprs_interval(aprs_interval);
+               dest.set_beep(beep);
+               dest.set_tracker_motion(tracker_motion);
+               dest.set_tracker_interval(tracker_interval);
        }
 
        public void save(AltosLink link, boolean remote) throws InterruptedException, TimeoutException {
@@ -492,11 +571,21 @@ public class AltosConfigData implements Iterable<String> {
                                                   pyros[p].toString());
                        }
                }
+               if (pyro_firing_time >= 0)
+                       link.printf("c I %d\n", (int) (pyro_firing_time * 100.0 + 0.5));
 
                /* HAS_APRS */
                if (aprs_interval >= 0)
                        link.printf("c A %d\n", aprs_interval);
 
+               /* HAS_BEEP */
+               if (beep >= 0)
+                       link.printf("c b %d\n", beep);
+
+               /* HAS_TRACKER */
+               if (tracker_motion >= 0 && tracker_interval >= 0)
+                       link.printf("c t %d %d\n", tracker_motion, tracker_interval);
+
                link.printf("c w\n");
                link.flush_output();
        }
@@ -506,12 +595,12 @@ public class AltosConfigData implements Iterable<String> {
                link.printf("c s\nf\nv\n");
                read_link(link, "software-version");
                switch (log_format) {
-               case AltosLib.AO_LOG_FORMAT_FULL:
-               case AltosLib.AO_LOG_FORMAT_TINY:
-               case AltosLib.AO_LOG_FORMAT_TELEMEGA:
+               case AltosLib.AO_LOG_FORMAT_UNKNOWN:
+               case AltosLib.AO_LOG_FORMAT_NONE:
+                       break;
+               default:
                        link.printf("l\n");
                        read_link(link, "done");
-               default:
                        break;
                }
        }
diff --git a/altoslib/AltosConfigDataException.java b/altoslib/AltosConfigDataException.java
new file mode 100644 (file)
index 0000000..ae5621c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_4;
+
+public class AltosConfigDataException extends Exception {
+
+       public AltosConfigDataException(String format, Object... args) {
+               super(String.format(format, args));
+       }
+
+}
index 4aa55d6a68085d6889fa52b4ed7aaeb79573932c..724ba7dc4bc91e3dc8e7aa282074b0b3fc34d23f 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public interface AltosConfigValues {
        /* set and get all of the dialog values */
@@ -27,23 +27,23 @@ public interface AltosConfigValues {
 
        public abstract void set_main_deploy(int new_main_deploy);
 
-       public abstract int main_deploy();
+       public abstract int main_deploy() throws AltosConfigDataException;
 
        public abstract void set_apogee_delay(int new_apogee_delay);
 
-       public abstract int apogee_delay();
+       public abstract int apogee_delay() throws AltosConfigDataException;
 
        public abstract void set_apogee_lockout(int new_apogee_lockout);
 
-       public abstract int apogee_lockout();
+       public abstract int apogee_lockout() throws AltosConfigDataException;
 
        public abstract void set_radio_frequency(double new_radio_frequency);
 
-       public abstract double radio_frequency();
+       public abstract double radio_frequency() throws AltosConfigDataException;
 
        public abstract void set_radio_calibration(int new_radio_calibration);
 
-       public abstract int radio_calibration();
+       public abstract int radio_calibration() throws AltosConfigDataException;
 
        public abstract void set_radio_enable(int new_radio_enable);
 
@@ -57,7 +57,7 @@ public interface AltosConfigValues {
 
        public abstract void set_flight_log_max_enabled(boolean enable);
 
-       public abstract int flight_log_max();
+       public abstract int flight_log_max() throws AltosConfigDataException;
 
        public abstract void set_flight_log_max_limit(int flight_log_max_limit);
 
@@ -71,9 +71,25 @@ public interface AltosConfigValues {
 
        public abstract void set_pyros(AltosPyro[] new_pyros);
 
-       public abstract AltosPyro[] pyros();
+       public abstract AltosPyro[] pyros() throws AltosConfigDataException;
 
-       public abstract int aprs_interval();
+       public abstract void set_pyro_firing_time(double new_pyro_firing_time);
+
+       public abstract double pyro_firing_time() throws AltosConfigDataException;
+
+       public abstract int aprs_interval() throws AltosConfigDataException;
 
        public abstract void set_aprs_interval(int new_aprs_interval);
+
+       public abstract int beep() throws AltosConfigDataException;
+
+       public abstract void set_beep(int new_beep);
+
+       public abstract int tracker_motion() throws AltosConfigDataException;
+
+       public abstract void set_tracker_motion(int tracker_motion);
+
+       public abstract int tracker_interval() throws AltosConfigDataException;
+
+       public abstract void set_tracker_interval(int tracker_motion);
 }
index 8f214c8b40c7a80fc6778a3b6806e471b76b7ad6..dc0fbb6253608529b0e6e6fb33ec02be7687f21d 100644 (file)
@@ -18,7 +18,7 @@
 /*
  * Sensor data conversion functions
  */
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosConvert {
        /*
@@ -208,7 +208,7 @@ public class AltosConvert {
 
        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 3.3 * mega_adc(v_batt) * (5.6 + 10.0) / 10.0;
                return AltosLib.MISSING;
        }
 
@@ -224,10 +224,27 @@ public class AltosConvert {
                return sensor / 32767.0 * supply * 127/27;
        }
 
-       static double easy_mini_voltage(int sensor) {
-               double  supply = 3.0;
+       static double tele_gps_voltage(int sensor) {
+               double  supply = 3.3;
 
-               return sensor / 32767.0 * supply * 127/27;
+               return sensor / 32767.0 * supply * (5.6 + 10.0) / 10.0;
+       }
+
+       static double easy_mini_voltage(int sensor, int serial) {
+               double  supply = 3.3;
+               double  diode_offset = 0.0;
+
+               /* early prototypes had a 3.0V regulator */
+               if (serial < 1000)
+                       supply = 3.0;
+
+               /* Purple v1.0 boards had the sensor after the
+                * blocking diode, which drops about 150mV
+                */
+               if (serial < 1665)
+                       diode_offset = 0.150;
+
+               return sensor / 32767.0 * supply * 127/27 + diode_offset;
        }
 
        public static double radio_to_frequency(int freq, int setting, int cal, int channel) {
@@ -332,6 +349,12 @@ public class AltosConvert {
 
        public static AltosOrient orient = new AltosOrient();
 
+       public static AltosVoltage voltage = new AltosVoltage();
+
+       public static AltosLatitude latitude = new AltosLatitude();
+
+       public static AltosLongitude longitude = new AltosLongitude();
+
        public static String show_gs(String format, double a) {
                a = meters_to_g(a);
                format = format.concat(" g");
@@ -348,4 +371,42 @@ public class AltosConvert {
                        csum += data[i + start];
                return csum & 0xff;
        }
+
+       public static double beep_value_to_freq(int value) {
+               if (value == 0)
+                       return 4000;
+               return 1.0/2.0 * (24.0e6/32.0) / (double) value;
+       }
+
+       public static int beep_freq_to_value(double freq) {
+               if (freq == 0)
+                       return 94;
+               return (int) Math.floor (1.0/2.0 * (24.0e6/32.0) / freq + 0.5);
+       }
+
+       public static final int BEARING_LONG = 0;
+       public static final int BEARING_SHORT = 1;
+       public static final int BEARING_VOICE = 2;
+
+       public static String bearing_to_words(int length, double bearing) {
+               String [][] bearing_string = {
+                       {
+                               "North", "North North East", "North East", "East North East",
+                               "East", "East South East", "South East", "South South East",
+                               "South", "South South West", "South West", "West South West",
+                               "West", "West North West", "North West", "North North West"
+                       }, {
+                               "N", "NNE", "NE", "ENE",
+                               "E", "ESE", "SE", "SSE",
+                               "S", "SSW", "SW", "WSW",
+                               "W", "WNW", "NW", "NNW"
+                       }, {
+                               "north", "nor nor east", "north east", "east nor east",
+                               "east", "east sow east", "south east", "sow sow east",
+                               "south", "sow sow west", "south west", "west sow west",
+                               "west", "west nor west", "north west", "nor nor west "
+                       }
+               };
+               return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16];
+       }
 }
index 4dfb31e5ebf5860e85d9dbe542dcb91535c494f1..b0e52fc1c5855abfd1b41e9bd4209b6980dce92a 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 
index 71ee81d7c9ee895d1fadc7b824feb38b29f8d093..76ca20c07521995323dc31690763956f052e2ced 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosDistance extends AltosUnits {
 
index 57ee73adb87bfdb4b52dcf9402550c7b5c9611a6..020590ebfc0a9f667d82c67fbbfe906ea0a954d5 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -43,6 +43,10 @@ public abstract class AltosEeprom implements AltosStateUpdate {
                return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24);
        }
 
+       public boolean has_seconds() { return false; }
+
+       public int seconds() { return 0; }
+
        public final static int header_length = 4;
 
        public abstract int record_length();
index c884b6593af6eea75acbe7601b9f1f8be9bf3d66..91eebc5ab18edee44feb72586b2a994febc51813 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.text.*;
 import java.util.concurrent.*;
@@ -84,6 +84,9 @@ public class AltosEepromChunk {
                case AltosLib.AO_LOG_FORMAT_EASYMINI:
                        eeprom = new AltosEepromMini(this, offset);
                        break;
+               case AltosLib.AO_LOG_FORMAT_TELEGPS:
+                       eeprom = new AltosEepromGPS(this, offset);
+                       break;
                default:
                        throw new ParseException("unknown eeprom format " + log_format, 0);
                }
@@ -125,4 +128,4 @@ public class AltosEepromChunk {
                        }
                }
        }
-}
\ No newline at end of file
+}
index 041010797837ef615b8ac7fad57c174ae9173b76..a2dfc438afcf76838b9c212a3c4ad34e48297124 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -132,7 +132,7 @@ public class AltosEepromDownload implements Runnable {
 
                CheckFile(false);
        }
-       
+
        void CaptureLog(AltosEepromLog log) throws IOException, InterruptedException, TimeoutException, ParseException {
                int                     block, state_block = 0;
                int                     log_format = flights.config_data.log_format;
index 91ffc223764d3a909d23ba7e10fc9020e3197e32..b7e446ce6a1627fbdd8b6d4637176bfe1f4351a6 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -72,7 +72,17 @@ public class AltosEepromFile extends AltosStateIterable {
                headers = new AltosEepromIterable(AltosEepromHeader.read(input));
 
                start = headers.state();
-               start.set_state(AltosLib.ao_flight_pad);
+               if (start.state != AltosLib.ao_flight_stateless)
+                       start.set_state(AltosLib.ao_flight_pad);
+
+               if (start.log_format == AltosLib.MISSING) {
+                       if (start.product != null) {
+                               if (start.product.startsWith("TeleMetrum"))
+                                       start.log_format = AltosLib.AO_LOG_FORMAT_FULL;
+                               else if (start.product.startsWith("TeleMini"))
+                                       start.log_format = AltosLib.AO_LOG_FORMAT_TINY;
+                       }
+               }
 
                switch (start.log_format) {
                case AltosLib.AO_LOG_FORMAT_FULL:
@@ -93,6 +103,9 @@ public class AltosEepromFile extends AltosStateIterable {
                case AltosLib.AO_LOG_FORMAT_EASYMINI:
                        body = new AltosEepromIterable(AltosEepromMini.read(input));
                        break;
+               case AltosLib.AO_LOG_FORMAT_TELEGPS:
+                       body = new AltosEepromIterable(AltosEepromGPS.read(input));
+                       break;
                default:
                        body = new AltosEepromIterable(new LinkedList<AltosEeprom>());
                        break;
@@ -120,4 +133,4 @@ public class AltosEepromFile extends AltosStateIterable {
                }
                return new AltosEepromIterator(state, i);
        }
-}
\ No newline at end of file
+}
diff --git a/altoslib/AltosEepromGPS.java b/altoslib/AltosEepromGPS.java
new file mode 100644 (file)
index 0000000..3c1852c
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_4;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromGPS extends AltosEeprom {
+       public static final int record_length = 32;
+
+       public static final int max_sat = 12;
+
+       public int record_length() { return record_length; }
+
+       /* AO_LOG_FLIGHT elements */
+       public int flight() { return data16(0); }
+       public int start_altitude() { return data16(2); }
+       public int start_latitude() { return data32(4); }
+       public int start_longitude() { return data32(8); }
+
+       /* AO_LOG_GPS_TIME elements */
+       public int latitude() { return data32(0); }
+       public int longitude() { return data32(4); }
+       public int altitude() { return data16(8); }
+       public int hour() { return data8(10); }
+       public int minute() { return data8(11); }
+       public int second() { return data8(12); }
+       public int flags() { return data8(13); }
+       public int year() { return data8(14); }
+       public int month() { return data8(15); }
+       public int day() { return data8(16); }
+       public int course() { return data8(17); }
+       public int ground_speed() { return data16(18); }
+       public int climb_rate() { return data16(20); }
+       public int pdop() { return data8(22); }
+       public int hdop() { return data8(23); }
+       public int vdop() { return data8(24); }
+       public int mode() { return data8(25); }
+
+       public boolean has_seconds() { return cmd == AltosLib.AO_LOG_GPS_TIME; }
+
+       public int seconds() {
+               switch (cmd) {
+               case AltosLib.AO_LOG_GPS_TIME:
+                       return second() + 60 * (minute() + 60 * (hour() + 24 * (day() + 31 * month())));
+               default:
+                       return 0;
+               }
+       }
+
+       public AltosEepromGPS (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_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_boost_tick(tick);
+                       state.set_flight(flight());
+                       /* no place to log start lat/lon yet */
+                       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();
+                       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();
+                       break;
+               }
+       }
+
+       public AltosEepromGPS (String line) {
+               parse_string(line);
+       }
+
+       static public LinkedList<AltosEeprom> read(FileInputStream input) {
+               LinkedList<AltosEeprom> tgpss = new LinkedList<AltosEeprom>();
+
+               for (;;) {
+                       try {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               try {
+                                       AltosEepromGPS tgps = new AltosEepromGPS(line);
+                                       if (tgps.cmd != AltosLib.AO_LOG_INVALID)
+                                               tgpss.add(tgps);
+                               } catch (Exception e) {
+                                       System.out.printf ("exception\n");
+                               }
+                       } catch (IOException ie) {
+                               break;
+                       }
+               }
+
+               return tgpss;
+       }
+}
index 6ce7ddd38516ecd3de0db752801e77b76b1202dc..839aa06e0fbdac648bb1de80ab60ac24d17f8078 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -53,9 +53,10 @@ public class AltosEepromHeader extends AltosEeprom {
                case AltosLib.AO_LOG_MANUFACTURER:
                        break;
                case AltosLib.AO_LOG_PRODUCT:
+                       state.product = data;
                        break;
                case AltosLib.AO_LOG_LOG_FORMAT:
-                       state.log_format = config_a;
+                       state.set_log_format(config_a);
                        break;
                case AltosLib.AO_LOG_SERIAL_NUMBER:
                        state.set_serial(config_a);
@@ -162,7 +163,7 @@ public class AltosEepromHeader extends AltosEeprom {
                        break;
                }
        }
-       
+
        public AltosEepromHeader (String[] tokens) {
                last = false;
                valid = true;
@@ -269,7 +270,7 @@ public class AltosEepromHeader extends AltosEeprom {
                for (AltosEepromHeader header : headers) {
                        header.write(out);
                }
-               
+
        }
 
        public AltosEepromHeader (String line) {
index 081721b3ecec0ac18a19dd76d69b1ab601171a85..d6832c1b91bbd30e539591fffa54c9544cb60a67 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -38,6 +38,13 @@ class AltosEepromOrdered implements Comparable<AltosEepromOrdered> {
                if (cmd_diff != 0)
                        return cmd_diff;
 
+               if (eeprom.has_seconds() && o.eeprom.has_seconds()) {
+                       int     seconds_diff = eeprom.seconds() - o.eeprom.seconds();
+
+                       if (seconds_diff != 0)
+                               return seconds_diff;
+               }
+
                int     tick_diff = tick - o.tick;
 
                if (tick_diff != 0)
@@ -116,4 +123,4 @@ public class AltosEepromIterable implements Iterable<AltosEeprom> {
                        eeproms = new LinkedList<AltosEeprom>();
                return new AltosEepromOrderedIterator(eeproms);
        }
-}
\ No newline at end of file
+}
index a9dac13aaa9a67623c8d28e38c58793f7b642e11..ab853a884a89d000faafc41103720a23ad480970 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
index cc2982071432db8f0f987ba6f7f06466042850b1..1a430c03dd2273f3eb25af49055b7f7198453a4d 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.text.*;
 import java.util.concurrent.*;
index b8a1b9e86dc61ad09403b33c9de4ec54274a3150..71719a26477eb47db8a103790abe6f314ac2cfe8 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -32,7 +32,12 @@ public class AltosEepromMega extends AltosEeprom {
        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); }
+       public int ground_accel_along() { return data16(8); }
+       public int ground_accel_across() { return data16(10); }
+       public int ground_accel_through() { return data16(12); }
+       public int ground_roll() { return data16(14); }
+       public int ground_pitch() { return data16(16); }
+       public int ground_yaw() { return data16(18); }
 
        /* AO_LOG_STATE elements */
        public int state() { return data16(0); }
@@ -70,7 +75,14 @@ public class AltosEepromMega extends AltosEeprom {
        public int year() { return data8(14); }
        public int month() { return data8(15); }
        public int day() { return data8(16); }
-       
+       public int course() { return data8(17); }
+       public int ground_speed() { return data16(18); }
+       public int climb_rate() { return data16(20); }
+       public int pdop() { return data8(22); }
+       public int hdop() { return data8(23); }
+       public int vdop() { return data8(24); }
+       public int mode() { return data8(25); }
+
        /* AO_LOG_GPS_SAT elements */
        public int nsat() { return data16(0); }
        public int svid(int n) { return data8(2 + n * 2); }
@@ -106,7 +118,6 @@ public class AltosEepromMega extends AltosEeprom {
                        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);
@@ -150,6 +161,7 @@ public class AltosEepromMega extends AltosEeprom {
                                voltages[i] = AltosConvert.mega_pyro_voltage(sense(i));
 
                        state.set_ignitor_voltage(voltages);
+                       state.set_pyro_fired(pyro());
                        break;
                case AltosLib.AO_LOG_GPS_TIME:
                        state.set_tick(tick);
@@ -172,6 +184,11 @@ public class AltosEepromMega extends AltosEeprom {
                        gps.year = 2000 + year();
                        gps.month = month();
                        gps.day = day();
+                       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();
                        break;
                case AltosLib.AO_LOG_GPS_SAT:
                        state.set_tick(tick);
index f1bca6dc14344b118597ce25dafc1eb877e7f453..d137614a8949a30069d771d50260b7d8d921d6a1 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -59,7 +59,7 @@ public class AltosEepromMetrum2 extends AltosEeprom {
        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); }
@@ -161,7 +161,7 @@ public class AltosEepromMetrum2 extends AltosEeprom {
                                        break;
                                try {
                                        AltosEepromMetrum2 metrum = new AltosEepromMetrum2(line);
-                                       
+
                                        if (metrum.cmd != AltosLib.AO_LOG_INVALID)
                                                metrums.add(metrum);
                                } catch (Exception e) {
index fb3b4d23b6d7fbafe5868c948d49563322f123da..32985639e52b73729ce021c897f29029dfc874d9 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -43,7 +43,7 @@ public class AltosEepromMini extends AltosEeprom {
 
        double voltage(AltosState state, int sensor) {
                if (state.log_format == AltosLib.AO_LOG_FORMAT_EASYMINI)
-                       return AltosConvert.easy_mini_voltage(sensor);
+                       return AltosConvert.easy_mini_voltage(sensor, state.serial);
                else
                        return AltosConvert.tele_mini_voltage(sensor);
        }
index 9ab1a5ab103acd402e3f25cd4b5f8379ff20ba30..b97287c3b1801a1d69ce911f528c3f3b4e86e43d 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public interface AltosEepromMonitor {
 
index c8b1e60cb450d06151839a6d71019d8c87c3a04c..77fe20c5789d31eb99a5ce57d617b74a5e5f11ff 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
index 049dd340612568cb56f6002ae62740e0526a52b7..6cbb72535740d74a6fa31d573f5bb84a4f539402 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
index 37bf70751a7a88dba353e0dea09f36d4d14cd355..2a7389960b08bb8604fabe0c4beb3e5ea3f347d9 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3; 
+package org.altusmetrum.altoslib_4;
 
 import java.io.File;
 import java.util.*;
index 25c76863b6b037de0fbd50605cc49caa607fb647..8e8722c2727dec1b343b5127fbb28ab57183c632 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 
index b7fcd73bfae19b0b6a329a4897666b7a24adcc69..8bb86bba1c42aaf0a9d69c11f94503d51cca0f7b 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public interface AltosFlashListener {
        public void position(String label, int percent);
index 86757e8272521a1b2e474e0a8c6b11027137678e..2fcd556ea6c5ad0e607b3a58df9d22390cb73c88 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.text.*;
 import java.io.*;
diff --git a/altoslib/AltosFlightStats.java b/altoslib/AltosFlightStats.java
new file mode 100644 (file)
index 0000000..56feb84
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 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_4;
+
+import java.io.*;
+
+public class AltosFlightStats {
+       public double           max_height;
+       public double           max_gps_height;
+       public double           max_speed;
+       public double           max_acceleration;
+       public double[] state_speed = new double[AltosLib.ao_flight_invalid + 1];
+       public double[] state_accel = new double[AltosLib.ao_flight_invalid + 1];
+       public int[]            state_count = new int[AltosLib.ao_flight_invalid + 1];
+       public double[] state_start = new double[AltosLib.ao_flight_invalid + 1];
+       public double[] state_end = new double[AltosLib.ao_flight_invalid + 1];
+       public int              serial;
+       public int              flight;
+       public int              year, month, day;
+       public int              hour, minute, second;
+       public double           lat, lon;
+       public double           pad_lat, pad_lon;
+       public boolean          has_flight_data;
+       public boolean          has_gps;
+       public boolean          has_flight_adc;
+       public boolean          has_battery;
+       public boolean          has_rssi;
+       public boolean          has_imu;
+       public boolean          has_mag;
+       public boolean          has_orient;
+       public int              num_ignitor;
+
+       double landed_time(AltosStateIterable states) {
+               AltosState state = null;
+
+               for (AltosState s : states) {
+                       state = s;
+                       if (state.state == AltosLib.ao_flight_landed)
+                               break;
+               }
+
+               if (state == null)
+                       return 0;
+
+               double  landed_height = state.height();
+
+               state = null;
+
+               boolean above = true;
+
+               double  landed_time = -1000;
+
+               for (AltosState s : states) {
+                       state = s;
+
+                       if (state.height() > landed_height + 10) {
+                               above = true;
+                       } else {
+                               if (above && state.height() < landed_height + 2) {
+                                       above = false;
+                                       landed_time = state.time;
+                               }
+                       }
+               }
+               if (landed_time == -1000)
+                       landed_time = state.time;
+               return landed_time;
+       }
+
+       double boost_time(AltosStateIterable states) {
+               double boost_time = AltosLib.MISSING;
+               AltosState      state = null;
+
+               for (AltosState s : states) {
+                       state = s;
+                       if (state.acceleration() < 1)
+                               boost_time = state.time;
+                       if (state.state >= AltosLib.ao_flight_boost && state.state <= AltosLib.ao_flight_landed)
+                               break;
+               }
+               if (state == null)
+                       return 0;
+
+               if (boost_time == AltosLib.MISSING)
+                       boost_time = state.time;
+               return boost_time;
+       }
+
+
+       public AltosFlightStats(AltosStateIterable states) throws InterruptedException, IOException {
+               double          boost_time = boost_time(states);
+               double          end_time = 0;
+               double          landed_time = landed_time(states);
+
+               year = month = day = AltosLib.MISSING;
+               hour = minute = second = AltosLib.MISSING;
+               serial = flight = AltosLib.MISSING;
+               lat = lon = AltosLib.MISSING;
+               has_flight_data = false;
+               has_gps = false;
+               has_flight_adc = false;
+               has_battery = false;
+               has_rssi = false;
+               has_imu = false;
+               has_mag = false;
+               has_orient = false;
+               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_battery = true;
+                       if (state.main_voltage != AltosLib.MISSING)
+                               has_flight_adc = true;
+                       if (state.rssi != AltosLib.MISSING)
+                               has_rssi = true;
+                       end_time = state.time;
+
+                       if (state.pressure() != AltosLib.MISSING)
+                               has_flight_data = true;
+
+                       int state_id = state.state;
+                       if (state.time >= boost_time && state_id < AltosLib.ao_flight_boost)
+                               state_id = AltosLib.ao_flight_boost;
+                       if (state.time >= landed_time && state_id < AltosLib.ao_flight_landed)
+                               state_id = AltosLib.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;
+                       }
+                       max_height = state.max_height();
+                       max_speed = state.max_speed();
+                       max_acceleration = state.max_acceleration();
+                       max_gps_height = state.max_gps_height();
+
+                       if (0 <= state_id && state_id < AltosLib.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]++;
+                               }
+                               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;
+                       }
+                       if (state.pad_lat != AltosLib.MISSING) {
+                               pad_lat = state.pad_lat;
+                               pad_lon = state.pad_lon;
+                       }
+                       if (state.gps != null && state.gps.locked && state.gps.nsat >= 4) {
+                               lat = state.gps.lat;
+                               lon = state.gps.lon;
+                               has_gps = true;
+                       }
+                       if (state.imu != null)
+                               has_imu = true;
+                       if (state.mag != null)
+                               has_mag = true;
+                       if (state.orient() != AltosLib.MISSING)
+                               has_orient = true;
+                       if (state.ignitor_voltage != null && state.ignitor_voltage.length > num_ignitor)
+                               num_ignitor = state.ignitor_voltage.length;
+               }
+               for (int s = AltosLib.ao_flight_startup; s <= AltosLib.ao_flight_landed; s++) {
+                       if (state_count[s] > 0) {
+                               state_speed[s] /= state_count[s];
+                               state_accel[s] /= state_count[s];
+                       } else {
+                               state_speed[s] = AltosLib.MISSING;
+                               state_accel[s] = AltosLib.MISSING;
+                       }
+                       if (state_start[s] == 0)
+                               state_start[s] = end_time;
+                       if (state_end[s] == 0)
+                               state_end[s] = end_time;
+               }
+       }
+}
index 5770b646ae36a1f4175083534fc4e9743c4ef8a2..7c291ea9036b29f0169730c5bbb39525ec0b9adb 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosFrequency {
        public double   frequency;
index 01e6fdbccf5575ba56ef838aeb3a8780163bd375..2708d026e840184a0013c8b632a26a1ffe7780db 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.text.*;
 import java.util.concurrent.*;
index 76fa3a560015c304038f19de1b7fb31ec555569f..ef24d4974f844f0a055bf5d354a2dec6e293a30e 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosGPSSat {
        public int      svid;
index b884a3bc210712fbe190f15727800d6309005628..4782c34d34d858ed6fd361594ae69befb1853120 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.lang.Math;
 
@@ -30,30 +30,12 @@ public class AltosGreatCircle implements Cloneable {
        static final double rad = Math.PI / 180;
        static final double earth_radius = 6371.2 * 1000;       /* in meters */
 
-       public static final int BEARING_LONG = 0;
-       public static final int BEARING_SHORT = 1;
-       public static final int BEARING_VOICE = 2;
+       public static final int BEARING_LONG = AltosConvert.BEARING_LONG;
+       public static final int BEARING_SHORT = AltosConvert.BEARING_SHORT;
+       public static final int BEARING_VOICE = AltosConvert.BEARING_VOICE;
 
        public String bearing_words(int length) {
-               String [][] bearing_string = {
-                       {
-                               "North", "North North East", "North East", "East North East",
-                               "East", "East South East", "South East", "South South East",
-                               "South", "South South West", "South West", "West South West",
-                               "West", "West North West", "North West", "North North West"
-                       }, {
-                               "N", "NNE", "NE", "ENE",
-                               "E", "ESE", "SE", "SSE",
-                               "S", "SSW", "SW", "WSW",
-                               "W", "WNW", "NW", "NNW"
-                       }, {
-                               "north", "nor nor east", "north east", "east nor east",
-                               "east", "east sow east", "south east", "sow sow east",
-                               "south", "sow sow west", "south west", "west sow west",
-                               "west", "west nor west", "north west", "nor nor west "
-                       }
-               };
-               return bearing_string[length][(int)((bearing / 90 * 8 + 1) / 2)%16];
+               return AltosConvert.bearing_to_words(length, bearing);
        }
 
        public AltosGreatCircle (double start_lat, double start_lon, double start_alt,
index a81897e7c4a533bcfabb47d0f32cfbf0c6a5303d..84981032a76e909e6af429b7ff32f72c72db6fdc 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosHeight extends AltosUnits {
 
index 60f4ecdc5012f64f1b64d61c5fc18c0c06682203..d5fa8f5fe1c08b86e99649e09bec6895f5129dcf 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.LinkedList;
index a98ef0fc13223eb161d759670871fee19dd3d9d6..403b5644b50d3bdb524a59cccefff2b286304448 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosHexsym {
        String  name;
index 260f35876aff359df7e49ae12edff4ea4fa9217a..a22b3fed29290ca6e59f765734c581f388d1e55c 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.concurrent.*;
 
@@ -28,6 +28,18 @@ public class AltosIMU implements Cloneable {
        public double           gyro_y;
        public double           gyro_z;
 
+/*
+ * XXX use ground measurements to adjust values
+
+       public double           ground_accel_x;
+       public double           ground_accel_y;
+       public double           ground_accel_z;
+
+       public double           ground_gyro_x;
+       public double           ground_gyro_y;
+       public double           ground_gyro_z;
+*/
+
        public static int       counts_per_g = 2048;
 
        public static double convert_accel(int counts) {
index c7b546b6c67e350592e689932e4ff69eb789fee1..55f6f5c9d834e5cfa5fa6a009da66c568060cf73 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
index 02cb7a947a30b4df6a8e766c733f280b05b54342..5cd8bf367944907ebec648aa6dc3e99c35f4e582 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -142,7 +142,7 @@ public class AltosIdleFetch implements AltosStateUpdate {
                        state.set_received_time(System.currentTimeMillis());
                } catch (TimeoutException te) {
                }
-               
+
        }
 
        public AltosIdleFetch(AltosLink link) {
index 8342f8a53d9da17ce3fc0f9cb29b16ba7fbf95fd..f81abdff0baac58d40094beb566b1a5a4ee23461 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.concurrent.*;
index dcaa77a6c8f21058f337a106667c74fe59a7a728..6a9abea24dea350540620a9160473f5eb49829f7 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public interface AltosIdleMonitorListener {
        public void update(AltosState state, AltosListenerState listener_state);
index 8ab47d1de49a9ba8c54e6327ca096addd5334563..c21f17ac2234da61d93ad414494180747aa4ea27 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.*;
 import java.io.*;
diff --git a/altoslib/AltosKML.java b/altoslib/AltosKML.java
new file mode 100644 (file)
index 0000000..d55da9e
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * 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_4;
+
+import java.io.*;
+
+public class AltosKML implements AltosWriter {
+
+       File                    name;
+       PrintStream             out;
+       int                     flight_state = -1;
+       AltosState              prev = null;
+       double                  gps_start_altitude;
+
+       static final String[] kml_state_colors = {
+               "FF000000",
+               "FF000000",
+               "FF000000",
+               "FF0000FF",
+               "FF4080FF",
+               "FF00FFFF",
+               "FFFF0000",
+               "FF00FF00",
+               "FF000000",
+               "FFFFFFFF"
+       };
+
+       static final String kml_header_start =
+               "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+               "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
+               "<Document>\n" +
+               "  <name>AO Flight#%d S/N: %03d</name>\n" +
+               "  <description>\n";
+       static final String kml_header_end =
+               "  </description>\n" +
+               "  <open>0</open>\n";
+
+       static final String kml_style_start =
+               "  <Style id=\"ao-flightstate-%s\">\n" +
+               "    <LineStyle><color>%s</color><width>4</width></LineStyle>\n" +
+               "    <BalloonStyle>\n" +
+               "      <text>\n";
+
+       static final String kml_style_end =
+               "      </text>\n" +
+               "    </BalloonStyle>\n" +
+               "  </Style>\n";
+
+       static final String kml_placemark_start =
+               "  <Placemark>\n" +
+               "    <name>%s</name>\n" +
+               "    <styleUrl>#ao-flightstate-%s</styleUrl>\n" +
+               "    <LineString>\n" +
+               "      <tessellate>1</tessellate>\n" +
+               "      <altitudeMode>absolute</altitudeMode>\n" +
+               "      <coordinates>\n";
+
+       static final String kml_coord_fmt =
+       "        %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
+
+       static final String kml_placemark_end =
+               "      </coordinates>\n" +
+               "    </LineString>\n" +
+               "  </Placemark>\n";
+
+       static final String kml_footer =
+               "</Document>\n" +
+               "</kml>\n";
+
+       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);
+               out.printf("Time:     %2d:%02d:%02d\n",
+                          record.gps.hour, record.gps.minute, record.gps.second);
+               out.printf("%s", kml_header_end);
+       }
+
+       boolean started = false;
+
+       void state_start(AltosState state) {
+               String  state_name = AltosLib.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(AltosState state) {
+               out.printf("%s", kml_placemark_end);
+       }
+
+       void coord(AltosState state) {
+               AltosGPS        gps = state.gps;
+               double          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,
+                          state.time, gps.nsat);
+       }
+
+       void end() {
+               out.printf("%s", kml_footer);
+       }
+
+       public void close() {
+               if (prev != null) {
+                       state_end(prev);
+                       end();
+                       prev = null;
+               }
+       }
+
+       public void write(AltosState state) {
+               AltosGPS        gps = state.gps;
+
+               if (gps == null)
+                       return;
+
+               if (gps.lat == AltosLib.MISSING)
+                       return;
+               if (gps.lon == AltosLib.MISSING)
+                       return;
+               if (!started) {
+                       start(state);
+                       started = true;
+                       gps_start_altitude = gps.alt;
+               }
+               if (prev != null && prev.gps_sequence == state.gps_sequence)
+                       return;
+               if (state.state != flight_state) {
+                       flight_state = state.state;
+                       if (prev != null) {
+                               coord(state);
+                               state_end(prev);
+                       }
+                       state_start(state);
+               }
+               coord(state);
+               prev = state;
+       }
+
+       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 {
+               name = in_name;
+               out = new PrintStream(name);
+       }
+
+       public AltosKML(String in_string) throws FileNotFoundException {
+               this(new File(in_string));
+       }
+}
diff --git a/altoslib/AltosLatitude.java b/altoslib/AltosLatitude.java
new file mode 100644 (file)
index 0000000..6156d6d
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_4;
+
+public class AltosLatitude extends AltosLocation {
+       public String pos() { return "N"; }
+       public String neg() { return "S"; }
+}
index 05f0af8df5d4fa518191dc7e1a96c88c0e4772a1..69c6d604003d7ff39bacba50b7affb14270c1d73 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.*;
 import java.io.*;
@@ -79,6 +79,7 @@ public class AltosLib {
        public static final int ao_flight_main = 7;
        public static final int ao_flight_landed = 8;
        public static final int ao_flight_invalid = 9;
+       public static final int ao_flight_stateless = 10;
 
        /* USB product IDs */
        public final static int vendor_altusmetrum = 0xfffe;
@@ -187,6 +188,7 @@ public class AltosLib {
                string_to_state.put("main", ao_flight_main);
                string_to_state.put("landed", ao_flight_landed);
                string_to_state.put("invalid", ao_flight_invalid);
+               string_to_state.put("stateless", ao_flight_stateless);
                map_initialized = true;
        }
 
@@ -203,7 +205,7 @@ public class AltosLib {
                throw new IllegalArgumentException(String.format("Invalid telemetry %d",
                                                                 telemetry));
        }
-       
+
        private static String[] state_to_string = {
                "startup",
                "idle",
@@ -215,6 +217,7 @@ public class AltosLib {
                "main",
                "landed",
                "invalid",
+               "stateless",
        };
 
        private static String[] state_to_string_capital = {
@@ -228,6 +231,7 @@ public class AltosLib {
                "Main",
                "Landed",
                "Invalid",
+               "Stateless",
        };
 
        public static int state(String state) {
@@ -265,6 +269,7 @@ public class AltosLib {
        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_TELEGPS = 9;
        public static final int AO_LOG_FORMAT_NONE = 127;
 
        public static boolean isspace(int c) {
@@ -479,4 +484,8 @@ public class AltosLib {
                default: return "unknown";
                }
        }
+
+       public static String ignitor_name(int i) {
+               return String.format("Ignitor %c", 'A' + i);
+       }
 }
index 9d796a896f38e8cb880c9b982e1b671c2fa74289..f9c712a327597ecdac8010da611affc5c50d6a80 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosLine {
        public String   line;
index 97fa70625ce8d90aa5e1e84eb1f1b01b7c4ba8e2..7f434a064200921d881eaf5051a580d6d1258ac8 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.concurrent.*;
@@ -76,7 +76,7 @@ public abstract class AltosLink implements Runnable {
                return get_reply(5000);
        }
 
-               
+
        public abstract boolean can_cancel_reply();
        public abstract boolean show_reply_timeout();
        public abstract void hide_reply_timeout();
@@ -215,7 +215,7 @@ public abstract class AltosLink implements Runnable {
                                        break;
                                }
                        }
-                       
+
                } finally {
                        --in_reply;
                }
index 53ed33f9219d2b26e69114137a164b774c3b7a4b..5bf761b0a5fa035d0a01b91952b48ecba0daf33b 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosListenerState {
        public int      crc_errors;
diff --git a/altoslib/AltosLocation.java b/altoslib/AltosLocation.java
new file mode 100644 (file)
index 0000000..725a02b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_4;
+
+public abstract class AltosLocation extends AltosUnits {
+
+       public abstract String pos();
+       public abstract String neg();
+
+       public double value(double v, boolean imperial_units) {
+               return v;
+       }
+
+       public double inverse(double v, boolean imperial_units) {
+               return v;
+       }
+
+       public String show_units(boolean imperial_units) {
+               return "°";
+       }
+
+       public String say_units(boolean imperial_units) {
+               return "degrees";
+       }
+
+       public int show_fraction(int width, boolean imperial_units) {
+               return 2;
+       }
+
+       public String show(int width, double v, boolean imperial_units) {
+               String  h = pos();
+               if (v < 0) {
+                       h = neg();
+                       v = -v;
+               }
+               int deg = (int) Math.floor(v);
+               double min = (v - Math.floor(v)) * 60.0;
+               return String.format("%s %4d° %9.6f", h, deg, min);
+       }
+
+       public String say(double v, boolean imperial_units) {
+               String  h = pos();
+               if (v < 0) {
+                       h = neg();
+                       v = -v;
+               }
+               int deg = (int) Math.floor(v);
+               double min = (v - Math.floor(v)) * 60.0;
+               return String.format("%s %d degrees %d", h, deg, (int) Math.floor(min + 0.5));
+       }
+}
index 70c017b7df950c2353ed21d57346b9b6305f72fc..c4e9e4257a1f318dbf7a90bfe00fd85bf2d1918e 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.text.*;
@@ -48,6 +48,7 @@ public class AltosLog implements Runnable {
        }
 
        public void close() {
+               link.remove_monitor(input_queue);
                close_log_file();
                if (log_thread != null) {
                        log_thread.interrupt();
diff --git a/altoslib/AltosLongitude.java b/altoslib/AltosLongitude.java
new file mode 100644 (file)
index 0000000..29a5dcd
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_4;
+
+public class AltosLongitude extends AltosLocation {
+       public String pos() { return "E"; }
+       public String neg() { return "W"; }
+}
index d2bb9da6fbe086430a92c03be434fb844a4b1bf0..9262de2d3e8e6f06fc1892cb22bbc3cff3af8618 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.concurrent.*;
 
@@ -87,4 +87,3 @@ public class AltosMag implements Cloneable {
                }
        }
 }
-       
\ No newline at end of file
index 0d90c351a8e7f21e1ee222fe0da29fd6accea4ff..cb2e63d4269cb9de38004377cf4f2471a19bae3e 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.concurrent.*;
 
index 97d08c3ea7c894f6f74be8515b6d0aaf0b5ed7ae..5aa3a7ec6bf8bb0f673a8308ea9b0b818f458390 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.concurrent.*;
 
@@ -44,7 +44,7 @@ public class AltosMs5607 {
                //int P;
 
                dT = raw_temp - ((int) tref << 8);
-       
+
                TEMP = (int) (2000 + (((long) dT * (long) tempsens) >> 23));
 
                if (ms5611) {
@@ -55,7 +55,7 @@ public class AltosMs5607 {
                        OFF = ((long) off << 17) + (((long) tco * (long) dT) >> 6);
 
                        SENS = ((long) sens << 16) + (((long) tcs * (long) dT) >> 7);
-               } 
+               }
 
                if (TEMP < 2000) {
                        int     T2 = (int) (((long) dT * (long) dT) >> 31);
index 791899c06706f3ea48e17c71dec7079af9c2ebcd..f5e53b8cb032e663e4ad1a290022e833f0b3109d 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosNoSymbol extends Exception {
        public AltosNoSymbol(String name) {
index d916a0fba52bc4269e83dd5583f07e89c109a730..5fcbe28dd16b5fb38b80daeaf339ceae6c6c1e92 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosOrient extends AltosUnits {
 
index 5137fef8caddc1c34da4bccb2c47e0771e822074..1bff76823f0d7d1d2d69c85404815c7d52ca4b1e 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.text.*;
 
index b8920d266c2324ef01474c7f3c7133aa59a3425d..d299f27b02ddd865e23f8e4e05c8a06ce3361ed5 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -55,7 +55,7 @@ public class AltosPreferences {
 
        /* Launcher channel preference name */
        public final static String launcherChannelPreference = "LAUNCHER-CHANNEL";
-       
+
        /* Default logdir is ~/TeleMetrum */
        public final static String logdirName = "TeleMetrum";
 
@@ -349,7 +349,7 @@ public class AltosPreferences {
                        return launcher_channel;
                }
        }
-       
+
        public static AltosPreferencesBackend bt_devices() {
                synchronized (backend) {
                        return backend.node("bt_devices");
index 2eb29702c322a221e87bcfce959828d7ce6dd12a..461b5c80ec1d409f61917068484dae4788bd9ebe 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.File;
 
index 750e1f02b7e2655660cb25c87186a2f69290c30e..c96f04ca47da88eb0a16d76169fa3f57e0948c23 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 
index aefc6fbda7d7383441e3673fd35771bd564b03f2..9e47bc804282f9b6319e1a2b151b81ab03bf5784 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.*;
 import java.text.*;
@@ -105,7 +105,7 @@ public class AltosPyro {
        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, AltosUnits units, double scale) {
                string_to_pyro.put(string, flag);
                pyro_to_string.put(flag, string);
@@ -114,7 +114,7 @@ public class AltosPyro {
                        pyro_to_units.put(flag, units);
                pyro_to_scale.put(flag, scale);
        }
-       
+
        public static int string_to_pyro(String name) {
                if (string_to_pyro.containsKey(name))
                        return string_to_pyro.get(name);
@@ -174,7 +174,7 @@ public class AltosPyro {
 
                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, 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);
        }
index 4cf642ca43801e378181bab6189adbdefca47dea..bf7e0e5b0b36dce0a52ce526b84ec042e66aa466 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -39,7 +39,7 @@ public class AltosReplayReader extends AltosFlightReader {
 
        public void update(AltosState state) throws InterruptedException {
                /* Make it run in realtime after the rocket leaves the pad */
-               if (state.state > AltosLib.ao_flight_pad)
+               if (state.state > AltosLib.ao_flight_pad && state.time_change > 0)
                        Thread.sleep((int) (Math.min(state.time_change,10) * 1000));
                state.set_received_time(System.currentTimeMillis());
        }
index 1273fbc605e2b95aad949482bfd92e5ffec87643..10df11afd6cc7c9277dcd63d1475588e7a43fcf8 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 
@@ -144,7 +144,7 @@ public class AltosRomconfig {
                ao_romconfig_check,
                ao_serial_number
        };
-               
+
        private static boolean name_required(String name) {
                for (String required : required_names)
                        if (name.equals(required))
index aae993ebc368731fb42899a67303d6212a27cb1c..502c6d65ba5fd426a71b0c5b0085dfa4581b0bfb 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 
@@ -47,7 +47,7 @@ public class AltosSelfFlash extends AltosProgrammer {
                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++)
@@ -55,7 +55,7 @@ public class AltosSelfFlash extends AltosProgrammer {
                }
                return data;
        }
-               
+
        void write_memory(long addr, byte[] data, int start, int len) {
                int b;
                link.printf("W %x\n", addr);
index f888754c80ea812ee953b1f0d054cbc476dfb44e..ee0238f965f8a2b6c68d9ebca523ec35ffc494ef 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.concurrent.TimeoutException;
 
@@ -31,10 +31,10 @@ public class AltosSensorEMini {
 
                        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));
-                       
+                       state.set_battery_voltage(AltosConvert.easy_mini_voltage(sensor_emini.batt, config_data.serial));
+                       state.set_apogee_voltage(AltosConvert.easy_mini_voltage(sensor_emini.apogee, config_data.serial));
+                       state.set_main_voltage(AltosConvert.easy_mini_voltage(sensor_emini.main, config_data.serial));
+
                } catch (TimeoutException te) {
                }
        }
index 0c23d671cfe8128f2d207c882d83d7c15beec9ce..e34e71b7f599a4b363a7b18a027134f8dd901bbb 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.concurrent.TimeoutException;
 
index c52f688d6495f459c4337dae879edc6e2a70e765..02f3a25622e596ff2749315b05921b2dbbed128a 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.concurrent.TimeoutException;
 
index bb794a1e598f04f624b76a77a47b3a6cf0baf7ee..e5421ef53d1a79dadade3a63f1954879e92836cf 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.concurrent.TimeoutException;
 
index b8f54bcb257845f4a11c357a230055b80e018c2a..2d60d8cfbaf9e33ee3a73807ba1e09c448e4d6ef 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.concurrent.TimeoutException;
 
@@ -40,7 +40,7 @@ public class AltosSensorTM {
                        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) {
                }
        }
index 35857e350113e4ef24c06e1dbf223252278619f1..b9eeca0cc1d803403d09b5e6283d7a30e5c2ee80 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.util.concurrent.TimeoutException;
 
@@ -31,10 +31,10 @@ public class AltosSensorTMini {
 
                        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));
-                       
+                       state.set_battery_voltage(AltosConvert.tele_mini_voltage(sensor_tmini.batt));
+                       state.set_apogee_voltage(AltosConvert.tele_mini_voltage(sensor_tmini.apogee));
+                       state.set_main_voltage(AltosConvert.tele_mini_voltage(sensor_tmini.main));
+
                } catch (TimeoutException te) {
                }
        }
index d93229dd0a3837d0a6bfaa59010a91bd6ba7668f..9134f5f4a59c60c729f1835ccadd10de4eb17502 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosSpeed extends AltosUnits {
 
index 758fd6366b7b7f40d1b3967bcc24bdcb8f4d9313..b05cd3586061ad111d99084733f84865c360339e 100644 (file)
@@ -19,7 +19,7 @@
  * Track flight state from telemetry or eeprom data stream
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosState implements Cloneable {
 
@@ -50,12 +50,13 @@ public class AltosState implements Cloneable {
                private double  set_time;
                private double  prev_set_time;
 
+               boolean can_max() { return true; }
+
                void set(double new_value, double time) {
                        if (new_value != AltosLib.MISSING) {
                                value = new_value;
-                               if (max_value == AltosLib.MISSING || value > max_value) {
+                               if (can_max() && (max_value == AltosLib.MISSING || value > max_value))
                                        max_value = value;
-                               }
                                set_time = time;
                        }
                }
@@ -108,7 +109,7 @@ public class AltosState implements Cloneable {
 
                void set_derivative(AltosValue in) {
                        double  n = in.rate();
-                       
+
                        if (n == AltosLib.MISSING)
                                return;
 
@@ -123,7 +124,7 @@ public class AltosState implements Cloneable {
                        /* Clip changes to reduce noise */
                        double  ddt = in.time() - pt;
                        double  ddv = (n - p) / ddt;
-                               
+
                        final double max = 100000;
 
                        /* 100gs */
@@ -246,11 +247,11 @@ public class AltosState implements Cloneable {
                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);
@@ -337,7 +338,7 @@ public class AltosState implements Cloneable {
        }
 
        private AltosGroundPressure ground_pressure;
-               
+
        public double ground_pressure() {
                return ground_pressure.value();
        }
@@ -388,6 +389,11 @@ public class AltosState implements Cloneable {
 
        private AltosGpsAltitude        gps_altitude;
 
+       private AltosValue              gps_ground_speed;
+       private AltosValue              gps_ascent_rate;
+       private AltosValue              gps_course;
+       private AltosValue              gps_speed;
+
        public double altitude() {
                double a = altitude.value();
                if (a != AltosLib.MISSING)
@@ -418,6 +424,34 @@ public class AltosState implements Cloneable {
                gps_altitude.set(new_gps_altitude, time);
        }
 
+       public double gps_ground_speed() {
+               return gps_ground_speed.value();
+       }
+
+       public double max_gps_ground_speed() {
+               return gps_ground_speed.max();
+       }
+
+       public double gps_ascent_rate() {
+               return gps_ascent_rate.value();
+       }
+
+       public double max_gps_ascent_rate() {
+               return gps_ascent_rate.max();
+       }
+
+       public double gps_course() {
+               return gps_course.value();
+       }
+
+       public double gps_speed() {
+               return gps_speed.value();
+       }
+
+       public double max_gps_speed() {
+               return gps_speed.max();
+       }
+
        class AltosPressure extends AltosValue {
                void set(double p, double time) {
                        super.set(p, time);
@@ -447,7 +481,7 @@ public class AltosState implements Cloneable {
                double g = ground_altitude();
                if (a != AltosLib.MISSING && g != AltosLib.MISSING)
                        return a - g;
-               return AltosLib.MISSING;
+               return gps_height();
        }
 
        public double max_height() {
@@ -459,7 +493,7 @@ public class AltosState implements Cloneable {
                double g = ground_altitude();
                if (a != AltosLib.MISSING && g != AltosLib.MISSING)
                        return a - g;
-               return AltosLib.MISSING;
+               return max_gps_height();
        }
 
        public double gps_height() {
@@ -481,7 +515,11 @@ public class AltosState implements Cloneable {
        }
 
        class AltosSpeed extends AltosCValue {
-               
+
+               boolean can_max() {
+                       return state < AltosLib.ao_flight_fast || state == AltosLib.ao_flight_stateless;
+               }
+
                void set_accel() {
                        acceleration.set_derivative(this);
                }
@@ -508,17 +546,34 @@ public class AltosState implements Cloneable {
                double v = kalman_speed.value();
                if (v != AltosLib.MISSING)
                        return v;
-               return speed.value();
+               v = speed.value();
+               if (v != AltosLib.MISSING)
+                       return v;
+               v = gps_speed();
+               if (v != AltosLib.MISSING)
+                       return v;
+               return AltosLib.MISSING;
        }
 
        public double max_speed() {
                double v = kalman_speed.max();
                if (v != AltosLib.MISSING)
                        return v;
-               return speed.max();
+               v = speed.max();
+               if (v != AltosLib.MISSING)
+                       return v;
+               v = max_gps_speed();
+               if (v != AltosLib.MISSING)
+                       return v;
+               return AltosLib.MISSING;
        }
 
        class AltosAccel extends AltosCValue {
+
+               boolean can_max() {
+                       return state < AltosLib.ao_flight_fast || state == AltosLib.ao_flight_stateless;
+               }
+
                void set_measured(double a, double time) {
                        super.set_measured(a, time);
                        if (ascent)
@@ -604,11 +659,14 @@ public class AltosState implements Cloneable {
        public double   ground_accel_avg;
 
        public int      log_format;
+       public String   product;
 
        public AltosMs5607      baro;
 
        public AltosCompanion   companion;
 
+       public int      pyro_fired;
+
        public void set_npad(int npad) {
                this.npad = npad;
                gps_waiting = MIN_PAD_SAMPLES - npad;
@@ -682,11 +740,16 @@ public class AltosState implements Cloneable {
 
                gps_altitude = new AltosGpsAltitude();
                gps_ground_altitude = new AltosGpsGroundAltitude();
+               gps_ground_speed = new AltosValue();
+               gps_speed = new AltosValue();
+               gps_ascent_rate = new AltosValue();
+               gps_course = new AltosValue();
 
                speak_tick = AltosLib.MISSING;
                speak_altitude = AltosLib.MISSING;
 
                callsign = null;
+               firmware_version = null;
 
                accel_plus_g = AltosLib.MISSING;
                accel_minus_g = AltosLib.MISSING;
@@ -696,11 +759,14 @@ public class AltosState implements Cloneable {
                ground_accel_avg = AltosLib.MISSING;
 
                log_format = AltosLib.MISSING;
+               product = null;
                serial = AltosLib.MISSING;
                receiver_serial = AltosLib.MISSING;
 
                baro = null;
                companion = null;
+
+               pyro_fired = 0;
        }
 
        void finish_update() {
@@ -729,7 +795,7 @@ public class AltosState implements Cloneable {
                time = old.time;
                time_change = old.time_change;
                prev_time = old.time;
-               
+
                tick = old.tick;
                prev_tick = old.tick;
                boost_tick = old.boost_tick;
@@ -747,7 +813,7 @@ public class AltosState implements Cloneable {
                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);
@@ -808,6 +874,10 @@ public class AltosState implements Cloneable {
 
                gps_altitude.copy(old.gps_altitude);
                gps_ground_altitude.copy(old.gps_ground_altitude);
+               gps_ground_speed.copy(old.gps_ground_speed);
+               gps_ascent_rate.copy(old.gps_ascent_rate);
+               gps_course.copy(old.gps_course);
+               gps_speed.copy(old.gps_speed);
 
                pad_lat = old.pad_lat;
                pad_lon = old.pad_lon;
@@ -817,6 +887,7 @@ public class AltosState implements Cloneable {
                speak_altitude = old.speak_altitude;
 
                callsign = old.callsign;
+               firmware_version = old.firmware_version;
 
                accel_plus_g = old.accel_plus_g;
                accel_minus_g = old.accel_minus_g;
@@ -825,28 +896,31 @@ public class AltosState implements Cloneable {
                ground_accel_avg = old.ground_accel_avg;
 
                log_format = old.log_format;
+               product = old.product;
                serial = old.serial;
                receiver_serial = old.receiver_serial;
 
                baro = old.baro;
                companion = old.companion;
+
+               pyro_fired = old.pyro_fired;
        }
-       
+
        void update_time() {
        }
 
        void update_gps() {
-               elevation = 0;
-               range = -1;
+               elevation = AltosLib.MISSING;
+               range = AltosLib.MISSING;
 
                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) {
+                       if (state == AltosLib.ao_flight_pad || state == AltosLib.ao_flight_stateless) {
                                set_npad(npad+1);
-                               if (pad_lat != AltosLib.MISSING) {
+                               if (pad_lat != AltosLib.MISSING && (npad < 10 || state == AltosLib.ao_flight_pad)) {
                                        pad_lat = (pad_lat * 31 + gps.lat) / 32;
                                        pad_lon = (pad_lon * 31 + gps.lon) / 32;
                                        gps_ground_altitude.set_filtered(gps.alt, time);
@@ -858,6 +932,15 @@ public class AltosState implements Cloneable {
                                gps_ground_altitude.set(gps.alt, time);
                        }
                        gps_altitude.set(gps.alt, time);
+                       if (gps.climb_rate != AltosLib.MISSING)
+                               gps_ascent_rate.set(gps.climb_rate, time);
+                       if (gps.ground_speed != AltosLib.MISSING)
+                               gps_ground_speed.set(gps.ground_speed, time);
+                       if (gps.climb_rate != AltosLib.MISSING && gps.ground_speed != AltosLib.MISSING)
+                               gps_speed.set(Math.sqrt(gps.ground_speed * gps.ground_speed +
+                                                       gps.climb_rate * gps.climb_rate), time);
+                       if (gps.course != AltosLib.MISSING)
+                               gps_course.set(gps.course, time);
                }
                if (gps.lat != 0 && gps.lon != 0 &&
                    pad_lat != AltosLib.MISSING &&
@@ -902,18 +985,34 @@ public class AltosState implements Cloneable {
                                  state <= AltosLib.ao_flight_coast);
                        boost = (AltosLib.ao_flight_boost == state);
                }
-
        }
 
        public void set_device_type(int device_type) {
                this.device_type = device_type;
+               switch (device_type) {
+               case AltosLib.product_telegps:
+                       this.state = AltosLib.ao_flight_stateless;
+                       break;
+               }
        }
 
-       public void set_config(int major, int minor, int apogee_delay, int main_deploy, int flight_log_max) {
-               config_major = major;
-               config_minor = minor;
+       public void set_log_format(int log_format) {
+               this.log_format = log_format;
+               switch (log_format) {
+               case AltosLib.AO_LOG_FORMAT_TELEGPS:
+                       this.state = AltosLib.ao_flight_stateless;
+                       break;
+               }
+       }
+
+       public void set_flight_params(int apogee_delay, int main_deploy) {
                this.apogee_delay = apogee_delay;
                this.main_deploy = main_deploy;
+       }
+
+       public void set_config(int major, int minor, int flight_log_max) {
+               config_major = major;
+               config_minor = minor;
                this.flight_log_max = flight_log_max;
        }
 
@@ -1104,6 +1203,10 @@ public class AltosState implements Cloneable {
                this.ignitor_voltage = voltage;
        }
 
+       public void set_pyro_fired(int fired) {
+               this.pyro_fired = fired;
+       }
+
        public double time_since_boost() {
                if (tick == AltosLib.MISSING)
                        return 0.0;
index 5a919b66c40a5565d047333e18aaa065535ce8cf..be812095342988dc6f2f889f74d4f2bda5a9cff1 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -24,6 +24,6 @@ public abstract class AltosStateIterable implements Iterable<AltosState> {
 
        public void write_comments (PrintStream out) {
        }
-       
+
        public abstract void write(PrintStream out);
 }
index 4614c67a1f0db70397be7747a77158b9e93c9691..ac4e963e6de6750b21150684745bfc37bd51337f 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public interface AltosStateUpdate {
        public void     update_state(AltosState state) throws InterruptedException;
index 01bedd5e71173f759e3545440b62a7730bda5d91..8182ec6bb67fe9eaefa016b1337a6f9c9bba5d16 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.text.*;
 
@@ -43,9 +43,9 @@ public abstract class AltosTelemetry implements AltosStateUpdate {
        }
 
        public void update_state(AltosState state) {
+               state.set_serial(serial);
                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);
@@ -67,7 +67,7 @@ public abstract class AltosTelemetry implements AltosStateUpdate {
        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;
 
index 67a437489294f28291dc5ea3e0c8ca7f0fef165c..e38840519c3f20276c8c9834e0e5fa5cd9a78a61 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 
 public class AltosTelemetryConfiguration extends AltosTelemetryStandard {
@@ -25,6 +25,7 @@ public class AltosTelemetryConfiguration extends AltosTelemetryStandard {
        int     config_minor;
        int     apogee_delay;
        int     main_deploy;
+       int     v_batt;
        int     flight_log_max;
        String  callsign;
        String  version;
@@ -36,6 +37,7 @@ public class AltosTelemetryConfiguration extends AltosTelemetryStandard {
                flight         = uint16(6);
                config_major   = uint8(8);
                config_minor   = uint8(9);
+               v_batt         = uint16(10);
                apogee_delay   = uint16(10);
                main_deploy    = uint16(12);
                flight_log_max = uint16(14);
@@ -47,7 +49,11 @@ public class AltosTelemetryConfiguration extends AltosTelemetryStandard {
                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_config(config_major, config_minor, flight_log_max);
+               if (device_type == AltosLib.product_telegps)
+                       state.set_battery_voltage(AltosConvert.tele_gps_voltage(v_batt));
+               else
+                       state.set_flight_params(apogee_delay, main_deploy);
 
                state.set_callsign(callsign);
                state.set_firmware_version(version);
index 09d7d3f8ce26c02432892527d170b8264ddf3c9b..3d3fa407085c641dda785a5ee8235e99b31d9033 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
@@ -62,7 +62,7 @@ public class AltosTelemetryFile extends AltosStateIterable {
        }
 
        public void write(PrintStream out) {
-               
+
        }
 
        public AltosTelemetryFile(FileInputStream input) {
index 002f53b4eacdc86f3dfdfd0223d29143b5c620fb..cba97ddc01309ddf9637d6b4ca53f1de4ec6ad4d 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.io.*;
 import java.util.*;
index d302adddb487b54956793d2f083c950c461410a0..3367ece78bc2a50145b3aa84df36c9aae4e24357 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.text.*;
 
@@ -470,7 +470,7 @@ public class AltosTelemetryLegacy extends AltosTelemetry {
                batt = int16(29);
                apogee = int16(31);
                main = int16(33);
-               
+
                ground_accel = int16(7);
                ground_pres = int16(15);
                accel_plus_g = int16(17);
index 8dcda9e173abf75f67fef1077c43502a208166fe..8368188f895492d42b83385babb524836e1a0b68 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 
 public class AltosTelemetryLocation extends AltosTelemetryStandard {
index 37b2527b663b410466e619cf1adf7bb1e565d913..8d0de355f195346df58079a2849f48cd315eaa87 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 import java.text.*;
 import java.util.HashMap;
 
index a4df70bee80ed084f1c17723802c594590b0c4b3..fac5695f27fbf6048a5f5d7b994f1e0ffe3ea529 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosTelemetryMegaData extends AltosTelemetryStandard {
        int     state;
-       
+
        int     v_batt;
        int     v_pyro;
        int     sense[];
@@ -41,7 +41,7 @@ public class AltosTelemetryMegaData extends AltosTelemetryStandard {
                v_batt = int16(6);
                v_pyro = int16(8);
 
-               sense = new int[6];     
+               sense = new int[6];
 
                for (int i = 0; i < 6; i++) {
                        sense[i] = int8(10 + i) << 4;
@@ -62,7 +62,7 @@ public class AltosTelemetryMegaData extends AltosTelemetryStandard {
                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));
 
index d1a463c06cd8ede43dd8252c7eec6216acdfcf95..9e73bc4e2c6b53114b9b43bf7fcaad7a6c801c44 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosTelemetryMegaSensor extends AltosTelemetryStandard {
        int     accel;
@@ -67,7 +67,7 @@ public class AltosTelemetryMegaSensor extends AltosTelemetryStandard {
                state.set_orient(orient);
 
                AltosIMU imu = new AltosIMU();
-               
+
                imu.accel_x = AltosIMU.convert_accel(accel_x);
                imu.accel_y = AltosIMU.convert_accel(accel_y);
                imu.accel_z = AltosIMU.convert_accel(accel_z);
index b8f7e9ea6768fb045664b8faeda104db286211ce..966173069e81a8bbe320adc3b5ff69fe7a7e98f8 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 
 public class AltosTelemetryMetrumData extends AltosTelemetryStandard {
index 232468bbf67ca5967d42f4d4f8996f1ffee09b5c..e7055404b24fe5b1f6c36309d3ca0e32355f0525 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 
 public class AltosTelemetryMetrumSensor extends AltosTelemetryStandard {
index e0a493dc06c7c6c3eb5afed0ab44d06a9c7aa960..fbfaff8e2cc406ce52397f37670bbbfd87a5664c 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 
 public class AltosTelemetryMini extends AltosTelemetryStandard {
index 91cfbb18d5e23320fd8fe2d8c9bb0827d4248bfe..0dca62aa62abf988c0552279732bf04598cd52d0 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosTelemetryRaw extends AltosTelemetryStandard {
        public AltosTelemetryRaw(int[] bytes) {
index 5e28358762c72e9ca51f013efa782ae5742529db..3dff661a3e3a91ed876166d32a59b334c17f4cd2 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 import java.text.*;
 import java.io.*;
index 01252bdea92a81186e176b0d2b9fccc52da96abb..d611e88c004b371b26630beb018aabd8b88c0d69 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosTelemetrySatellite extends AltosTelemetryStandard {
        int             channels;
@@ -43,7 +43,7 @@ public class AltosTelemetrySatellite extends AltosTelemetryStandard {
                super.update_state(state);
 
                AltosGPS        gps = state.make_temp_gps(true);
-               
+
                gps.cc_gps_sat = sats;
                state.set_temp_gps();
        }
index d6389865c15197e8a90310b45bbcc3cc54486e9b..ad4d92837a955c2ab80019e3bf5e2862f2559f7e 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 
 public class AltosTelemetrySensor extends AltosTelemetryStandard {
index c9531fcb3fcd0470de446f4d1aa1fcb174b6f6c7..23ae9d21fc05894fc76ef14ac29b1493ddbc32a8 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public abstract class AltosTelemetryStandard extends AltosTelemetry {
        int[]   bytes;
index 36e2656436827614f7fa7e221d4fe3838753193b..5fa71b8683b48cd9f710f6d4a5c4368a4f107e7a 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public class AltosTemperature extends AltosUnits {
 
index e573a43b7f1e2289e0051006d5680772317a494e..d29cfae7450825f7bea624759b1a4c578dfe06ab 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public abstract class AltosUnits {
 
@@ -41,7 +41,7 @@ public abstract class AltosUnits {
        public double value(double v) {
                return value(v, AltosConvert.imperial_units);
        }
-               
+
        public double inverse(double v) {
                return inverse(v, AltosConvert.imperial_units);
        }
@@ -49,15 +49,15 @@ public abstract class AltosUnits {
        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;
        }
index e9b29f9a866a23722aeb64fac49438b7eddf90e4..ca6faafd34166edf90e192b2a856c15384f46817 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_3;
+package org.altusmetrum.altoslib_4;
 
 public interface AltosUnitsListener {
        public void units_changed(boolean imperial_units);
diff --git a/altoslib/AltosVoltage.java b/altoslib/AltosVoltage.java
new file mode 100644 (file)
index 0000000..351bf11
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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_4;
+
+public class AltosVoltage extends AltosUnits {
+
+       public double value(double v, boolean imperial_units) {
+               return v;
+       }
+
+       public double inverse(double v, boolean imperial_units) {
+               return v;
+       }
+
+       public String show_units(boolean imperial_units) {
+               return "V";
+       }
+
+       public String say_units(boolean imperial_units) {
+               return "volts";
+       }
+
+       public int show_fraction(int width, boolean imperial_units) {
+               return 2;
+       }
+}
diff --git a/altoslib/AltosWriter.java b/altoslib/AltosWriter.java
new file mode 100644 (file)
index 0000000..c3479a9
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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_4;
+
+public interface AltosWriter {
+
+       public void write(AltosState state);
+
+       public void write(AltosStateIterable states);
+
+       public void close();
+}
index 2ee4d89f635e97db90b065c08d95d296b58d165c..e81418bb318dad34f82fc9db7c624094229b49bd 100644 (file)
@@ -1,4 +1,4 @@
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
 
 JAVAROOT=bin
 
@@ -28,9 +28,11 @@ altoslib_JAVA = \
        AltosLib.java \
        AltosCompanion.java \
        AltosConfigData.java \
+       AltosConfigDataException.java \
        AltosConfigValues.java \
        AltosConvert.java \
        AltosCRCException.java \
+       AltosCSV.java \
        AltosDebug.java \
        AltosEeprom.java \
        AltosEepromChunk.java \
@@ -45,11 +47,13 @@ altoslib_JAVA = \
        AltosEepromMega.java \
        AltosEepromMetrum2.java \
        AltosEepromMini.java \
+       AltosEepromGPS.java \
        AltosEepromMonitor.java \
        AltosFile.java \
        AltosFlash.java \
        AltosFlashListener.java \
        AltosFlightReader.java \
+       AltosFlightStats.java \
        AltosFrequency.java \
        AltosGPS.java \
        AltosGPSSat.java \
@@ -62,6 +66,7 @@ altoslib_JAVA = \
        AltosIdleMonitorListener.java \
        AltosIgnite.java \
        AltosIMU.java \
+       AltosKML.java \
        AltosLine.java \
        AltosLink.java \
        AltosListenerState.java \
@@ -114,7 +119,12 @@ altoslib_JAVA = \
        AltosSpeed.java \
        AltosTemperature.java \
        AltosAccel.java \
-       AltosPyro.java
+       AltosVoltage.java \
+       AltosLocation.java \
+       AltosLatitude.java \
+       AltosLongitude.java \
+       AltosPyro.java \
+       AltosWriter.java
 
 JAR=altoslib_$(ALTOSLIB_VERSION).jar
 
index 4ee3f4ade928def48d503681b8ac5c49dc8beecf..10b600e441ca086d4da85f5c90ea13e01e4cf1f9 100644 (file)
@@ -14,8 +14,10 @@ altosui-jdb
 classaltosui.stamp
 altos-windows.nsi
 Altos-Linux-*.tar.bz2
+Altos-Linux-*.sh
 Altos-Mac-*.zip
 Altos-Windows-*.exe
+altos.desktop
 *.dll
 *.dylib
 *.so
index 4b171fa77512f7de17a3a5c827d8bdab389b209b..28038ad687653e5829c756b848103eb8cf18f1b2 100644 (file)
@@ -20,8 +20,8 @@ package altosui;
 import java.awt.*;
 import libaltosJNI.*;
 
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class Altos extends AltosUILib {
 
index 3f74fdd1a481224c0db121c8dab2cc9ad7a5190a..3bc804068fef165716cb60686fd70dc5df0deebf 100644 (file)
 
 package altosui;
 
+import java.util.*;
 import java.awt.*;
+import java.awt.event.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
-public class AltosAscent extends JComponent implements AltosFlightDisplay {
-       GridBagLayout   layout;
-       JLabel                  cur, max;
+public class AltosAscent extends AltosUIFlightTab {
+       JLabel  cur, max;
 
-       public class AscentStatus {
-               JLabel          label;
-               JTextField      value;
-               AltosLights     lights;
+       class Height extends AltosUIUnitsIndicator {
 
-               void show() {
-                       value.setVisible(true);
-                       lights.setVisible(true);
-                       label.setVisible(true);
-               }
-
-               void hide() {
-                       value.setVisible(false);
-                       lights.setVisible(false);
-                       label.setVisible(false);
-               }
-
-               void show(AltosState state, AltosListenerState listener_state) {}
-
-               void show(String s) {
-                       show();
-                       value.setText(s);
-               }
-               
-               void show(AltosUnits units, double v) {
-                       show(units.show(8, v));
-               }
-
-               void show(String format, double v) {
-                       show(String.format(format, v));
-               }
-
-               void reset() {
-                       value.setText("");
-                       lights.set(false);
-               }
-
-               void set_font() {
-                       label.setFont(Altos.label_font);
-                       value.setFont(Altos.value_font);
+               public double value(AltosState state, int i) {
+                       if (i == 0)
+                               return state.height();
+                       else
+                               return state.max_height();
                }
 
-               public AscentStatus (GridBagLayout layout, int y, String text) {
-                       GridBagConstraints      c = new GridBagConstraints();
-                       c.weighty = 1;
-
-                       lights = new AltosLights();
-                       c.gridx = 0; c.gridy = y;
-                       c.anchor = GridBagConstraints.CENTER;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       layout.setConstraints(lights, c);
-                       add(lights);
-
-                       label = new JLabel(text);
-                       label.setFont(Altos.label_font);
-                       label.setHorizontalAlignment(SwingConstants.LEFT);
-                       c.gridx = 1; c.gridy = y;
-                       c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       layout.setConstraints(label, c);
-                       add(label);
-
-                       value = new JTextField(Altos.text_width);
-                       value.setFont(Altos.value_font);
-                       value.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = 2; c.gridy = y;
-                       c.gridwidth = 2;
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.BOTH;
-                       c.weightx = 1;
-                       layout.setConstraints(value, c);
-                       add(value);
-
+               public Height(Container container, int y) {
+                       super(container, y, AltosConvert.height, "Height", 2, false, 1);
                }
        }
 
-       public class AscentValue {
-               JLabel          label;
-               JTextField      value;
-               void show(AltosState state, AltosListenerState listener_state) {}
-
-               void reset() {
-                       value.setText("");
+       class Speed extends AltosUIUnitsIndicator {
+               public double value(AltosState state, int i) {
+                       if (i == 0)
+                               return state.speed();
+                       else
+                               return state.max_speed();
                }
 
-               void show() {
-                       label.setVisible(true);
-                       value.setVisible(true);
+               public Speed(Container container, int y) {
+                       super(container, y, AltosConvert.speed, "Speed", 2, false, 1);
                }
+       }
 
-               void show(String s) {
-                       show();
-                       value.setText(s);
-               }
-               
-               void show(AltosUnits units, double v) {
-                       show(units.show(8, v));
-               }
+       class Accel extends AltosUIUnitsIndicator {
+               public boolean hide(double v) { return v == AltosLib.MISSING; }
 
-               void show(String format, double v) {
-                       show(String.format(format, v));
-               }
-
-               void hide() {
-                       label.setVisible(false);
-                       value.setVisible(false);
-               }
-               void set_font() {
-                       label.setFont(Altos.label_font);
-                       value.setFont(Altos.value_font);
+               public double value(AltosState state, int i) {
+                       if (i == 0)
+                               return state.acceleration();
+                       else
+                               return state.max_acceleration();
                }
 
-               public AscentValue (GridBagLayout layout, int y, String text) {
-                       GridBagConstraints      c = new GridBagConstraints();
-                       c.weighty = 1;
-
-                       label = new JLabel(text);
-                       label.setFont(Altos.label_font);
-                       label.setHorizontalAlignment(SwingConstants.LEFT);
-                       c.gridx = 1; c.gridy = y;
-                       c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       layout.setConstraints(label, c);
-                       add(label);
-
-                       value = new JTextField(Altos.text_width);
-                       value.setFont(Altos.value_font);
-                       value.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = 2; c.gridy = y;
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.BOTH;
-                       c.gridwidth = 2;
-                       c.weightx = 1;
-                       layout.setConstraints(value, c);
-                       add(value);
+               public Accel(Container container, int y) {
+                       super(container, y, AltosConvert.accel, "Acceleration", 2, false, 1);
                }
        }
 
-       public class AscentValueHold {
-               JLabel          label;
-               JTextField      value;
-               JTextField      max_value;
-               double          max;
+       class Orient extends AltosUIUnitsIndicator {
 
-               void show(AltosState state, AltosListenerState listener_state) {}
+               public boolean hide(double v) { return v == AltosLib.MISSING; }
 
-               void reset() {
-                       value.setText("");
-                       max_value.setText("");
-                       max = AltosLib.MISSING;
+               public double value(AltosState state, int i) {
+                       if (i == 0)
+                               return state.orient();
+                       else
+                               return state.max_orient();
                }
 
-               void set_font() {
-                       label.setFont(Altos.label_font);
-                       value.setFont(Altos.value_font);
-                       max_value.setFont(Altos.value_font);
+               public Orient(Container container, int y) {
+                       super(container, y, AltosConvert.orient, "Tilt Angle", 2, false, 1);
                }
 
-               void show(AltosUnits units, double v) {
-                       if (v == AltosLib.MISSING) {
-                               value.setText("Missing");
-                               max_value.setText("Missing");
-                       } else {
-                               value.setText(units.show(8, v));
-                               if (v > max || max == AltosLib.MISSING) {
-                                       max_value.setText(units.show(8, v));
-                                       max = v;
-                               }
-                       }
-               }
-               public AscentValueHold (GridBagLayout layout, int y, String text) {
-                       GridBagConstraints      c = new GridBagConstraints();
-                       c.weighty = 1;
-
-                       label = new JLabel(text);
-                       label.setFont(Altos.label_font);
-                       label.setHorizontalAlignment(SwingConstants.LEFT);
-                       c.gridx = 1; c.gridy = y;
-                       c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       layout.setConstraints(label, c);
-                       add(label);
-
-                       value = new JTextField(Altos.text_width);
-                       value.setFont(Altos.value_font);
-                       value.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = 2; c.gridy = y;
-                       c.anchor = GridBagConstraints.EAST;
-                       c.fill = GridBagConstraints.BOTH;
-                       c.weightx = 1;
-                       layout.setConstraints(value, c);
-                       add(value);
-
-                       max_value = new JTextField(Altos.text_width);
-                       max_value.setFont(Altos.value_font);
-                       max_value.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = 3; c.gridy = y;
-                       c.anchor = GridBagConstraints.EAST;
-                       c.fill = GridBagConstraints.BOTH;
-                       c.weightx = 1;
-                       layout.setConstraints(max_value, c);
-                       add(max_value);
-               }
        }
 
+       class Apogee extends AltosUIUnitsIndicator {
 
-       class Height extends AscentValueHold {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.height, state.height());
+               public double value(AltosState state, int i) {
+                       return state.apogee_voltage;
                }
-               public Height (GridBagLayout layout, int y) {
-                       super (layout, y, "Height");
-               }
-       }
 
-       Height  height;
+               public boolean good(double v) { return v >= AltosLib.ao_igniter_good; }
+               public boolean hide(double v) { return v == AltosLib.MISSING; }
 
-       class Speed extends AscentValueHold {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.speed, state.speed());
-               }
-               public Speed (GridBagLayout layout, int y) {
-                       super (layout, y, "Speed");
+               public Apogee (Container container, int y) {
+                       super(container, y, AltosConvert.voltage, "Apogee Igniter Voltage", 1, true, 2);
                }
        }
 
-       Speed   speed;
-
-       class Accel extends AscentValueHold {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.accel, state.acceleration());
+       class Main extends AltosUIUnitsIndicator {
+               public double value(AltosState state, int i) {
+                       return state.main_voltage;
                }
-               public Accel (GridBagLayout layout, int y) {
-                       super (layout, y, "Acceleration");
-               }
-       }
 
-       Accel   accel;
+               public boolean good(double v) { return v >= AltosLib.ao_igniter_good; }
+               public boolean hide(double v) { return v == AltosLib.MISSING; }
 
-       class Orient extends AscentValueHold {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.orient, state.orient());
-               }
-               public Orient (GridBagLayout layout, int y) {
-                       super (layout, y, "Tilt Angle");
+               public Main (Container container, int y) {
+                       super(container, y, AltosConvert.voltage, "Main Igniter Voltage", 1, true, 2);
                }
        }
 
-       Orient  orient;
+       class Lat extends AltosUIUnitsIndicator {
 
-       String pos(double p, String pos, String neg) {
-               String  h = pos;
-               if (p < 0) {
-                       h = neg;
-                       p = -p;
+               public boolean hide(AltosState state, int i) {
+                       return state.gps == null || !state.gps.connected;
                }
-               int deg = (int) Math.floor(p);
-               double min = (p - Math.floor(p)) * 60.0;
-               return String.format("%s %4d° %9.6f", h, deg, min);
-       }
 
-       class Apogee extends AscentStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       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");
+               public double value(AltosState state, int i) {
+                       if (state.gps == null)
+                               return AltosLib.MISSING;
+                       if (!state.gps.connected)
+                               return AltosLib.MISSING;
+                       return state.gps.lat;
                }
-       }
 
-       Apogee apogee;
-
-       class Main extends AscentStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       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");
+               Lat (Container container, int y) {
+                       super (container, y, AltosConvert.latitude, "Latitude", 1, false, 2);
                }
        }
 
-       Main main;
+       class Lon extends AltosUIUnitsIndicator {
 
-       class Lat extends AscentValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
-                               show(pos(state.gps.lat,"N", "S"));
-                       else
-                               show("???");
+               public boolean hide(AltosState state, int i) {
+                       return state.gps == null || !state.gps.connected;
                }
-               public Lat (GridBagLayout layout, int y) {
-                       super (layout, y, "Latitude");
-               }
-       }
-
-       Lat lat;
 
-       class Lon extends AscentValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
-                               show(pos(state.gps.lon,"E", "W"));
-                       else
-                               show("???");
-               }
-               public Lon (GridBagLayout layout, int y) {
-                       super (layout, y, "Longitude");
+               public double value(AltosState state, int i) {
+                       if (state.gps == null)
+                               return AltosLib.MISSING;
+                       if (!state.gps.connected)
+                               return AltosLib.MISSING;
+                       return state.gps.lon;
                }
-       }
 
-       Lon lon;
-
-       public void reset() {
-               lat.reset();
-               lon.reset();
-               main.reset();
-               apogee.reset();
-               height.reset();
-               speed.reset();
-               accel.reset();
-               orient.reset();
-       }
-
-       public void set_font() {
-               cur.setFont(Altos.label_font);
-               max.setFont(Altos.label_font);
-               lat.set_font();
-               lon.set_font();
-               main.set_font();
-               apogee.set_font();
-               height.set_font();
-               speed.set_font();
-               accel.set_font();
-               orient.set_font();
+               Lon (Container container, int y) {
+                       super (container, y, AltosConvert.longitude, "Longitude", 1, false, 2);
+               }
        }
 
-       public void show(AltosState state, AltosListenerState listener_state) {
-               if (state.gps != null && state.gps.connected) {
-                       lat.show(state, listener_state);
-                       lon.show(state, listener_state);
-               } else {
-                       lat.hide();
-                       lon.hide();
-               }
-               height.show(state, listener_state);
-               if (state.main_voltage != AltosLib.MISSING)
-                       main.show(state, listener_state);
-               else
-                       main.hide();
-               if (state.apogee_voltage != AltosLib.MISSING)
-                       apogee.show(state, listener_state);
-               else
-                       apogee.hide();
-               speed.show(state, listener_state);
-               accel.show(state, listener_state);
-               orient.show(state, listener_state);
+       public void font_size_changed(int font_size) {
+               super.font_size_changed(font_size);
+               cur.setFont(AltosUILib.label_font);
+               max.setFont(AltosUILib.label_font);
        }
 
        public void labels(GridBagLayout layout, int y) {
                GridBagConstraints      c;
 
                cur = new JLabel("Current");
-               cur.setFont(Altos.label_font);
+               cur.setFont(AltosUILib.label_font);
                c = new GridBagConstraints();
                c.gridx = 2; c.gridy = y;
                c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
@@ -403,7 +169,7 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
                add(cur);
 
                max = new JLabel("Maximum");
-               max.setFont(Altos.label_font);
+               max.setFont(AltosUILib.label_font);
                c.gridx = 3; c.gridy = y;
                layout.setConstraints(max, c);
                add(max);
@@ -414,25 +180,15 @@ public class AltosAscent extends JComponent implements AltosFlightDisplay {
        }
 
        public AltosAscent() {
-               layout = new GridBagLayout();
-
-               setLayout(layout);
-
-               /* Elements in ascent display:
-                *
-                * lat
-                * lon
-                * height
-                */
                int y = 0;
                labels(layout, y++);
-               height = new Height(layout, y++);
-               speed = new Speed(layout, y++);
-               accel = new Accel(layout, y++);
-               orient = new Orient(layout, y++);
-               lat = new Lat(layout, y++);
-               lon = new Lon(layout, y++);
-               apogee = new Apogee(layout, y++);
-               main = new Main(layout, y++);
+               add(new Height(this, y++));
+               add(new Speed(this, y++));
+               add(new Accel(this, y++));
+               add(new Orient(this, y++));
+               add(new Lat(this, y++));
+               add(new Lon(this, y++));
+               add(new Apogee(this, y++));
+               add(new Main(this, y++));
        }
 }
diff --git a/altosui/AltosBTDevice.java b/altosui/AltosBTDevice.java
deleted file mode 100644 (file)
index 727a9f6..0000000
+++ /dev/null
@@ -1,124 +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 libaltosJNI.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosBTDevice extends altos_bt_device implements AltosDevice {
-
-       public String getProductName() {
-               String  name = getName();
-               if (name == null)
-                       return "Altus Metrum";
-               int     dash = name.lastIndexOf("-");
-               if (dash < 0)
-                       return name;
-               return name.substring(0,dash);
-       }
-
-       public int getProduct() {
-               if (Altos.bt_product_telebt.equals(getProductName()))
-                       return Altos.product_telebt;
-               return 0;
-       }
-
-       public String getPath() {
-               return getAddr();
-       }
-
-       public String getErrorString() {
-               altos_error     error = new altos_error();
-
-               libaltos.altos_get_last_error(error);
-               return String.format("%s (%d)", error.getString(), error.getCode());
-       }
-
-       public int getSerial() {
-               String name = getName();
-               if (name == null)
-                       return 0;
-               int dash = name.lastIndexOf("-");
-               if (dash < 0 || dash >= name.length())
-                       return 0;
-               String sn = name.substring(dash + 1, name.length());
-               try {
-                       return Integer.parseInt(sn);
-               } catch (NumberFormatException ne) {
-                       return 0;
-               }
-       }
-
-       public String toString() {
-               return String.format("%-20.20s %4d %s",
-                                    getProductName(), getSerial(), getAddr());
-       }
-
-       public String toShortString() {
-               return String.format("%s %d %s",
-                                    getProductName(), getSerial(), getAddr());
-
-       }
-
-       public SWIGTYPE_p_altos_file open() {
-               return libaltos.altos_bt_open(this);
-       }
-
-       /*
-       private boolean isAltusMetrum() {
-               if (getName().startsWith(Altos.bt_product_telebt))
-                       return true;
-               return false;
-       }
-       */
-
-       public boolean matchProduct(int want_product) {
-
-//             if (!isAltusMetrum())
-//                     return false;
-
-               if (want_product == Altos.product_any)
-                       return true;
-
-               if (want_product == Altos.product_basestation)
-                       return matchProduct(Altos.product_telebt);
-
-               if (want_product == getProduct())
-                       return true;
-
-               return false;
-       }
-
-       public boolean equals(Object o) {
-               if (!(o instanceof AltosBTDevice))
-                       return false;
-               AltosBTDevice other = (AltosBTDevice) o;
-               return getName().equals(other.getName()) && getAddr().equals(other.getAddr());
-       }
-
-       public int hashCode() {
-               return getName().hashCode() ^ getAddr().hashCode();
-       }
-
-       public AltosBTDevice(String name, String addr) {
-               Altos.load_library();
-               libaltos.altos_bt_fill_in(name, addr,this);
-       }
-
-       public AltosBTDevice() {
-       }
-}
\ No newline at end of file
diff --git a/altosui/AltosBTDeviceIterator.java b/altosui/AltosBTDeviceIterator.java
deleted file mode 100644 (file)
index 4be5edf..0000000
+++ /dev/null
@@ -1,62 +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.util.*;
-import libaltosJNI.*;
-
-public class AltosBTDeviceIterator implements Iterator<AltosBTDevice> {
-       AltosBTDevice   current;
-       boolean         done;
-       SWIGTYPE_p_altos_bt_list list;
-
-       public boolean hasNext() {
-               if (list == null)
-                       return false;
-               if (current != null)
-                       return true;
-               if (done)
-                       return false;
-               current = new AltosBTDevice();
-               while (libaltos.altos_bt_list_next(list, current) != 0) {
-//                     if (current.matchProduct(product))
-                               return true;
-               }
-               current = null;
-               done = true;
-               return false;
-       }
-
-       public AltosBTDevice next() {
-               if (hasNext()) {
-                       AltosBTDevice   next = current;
-                       current = null;
-                       return next;
-               }
-               return null;
-       }
-
-       public void remove() {
-               throw new UnsupportedOperationException();
-       }
-
-       public AltosBTDeviceIterator(int inquiry_time) {
-               done = false;
-               current = null;
-               list = libaltos.altos_bt_list_start(inquiry_time);
-       }
-}
diff --git a/altosui/AltosBTKnown.java b/altosui/AltosBTKnown.java
deleted file mode 100644 (file)
index 968d72d..0000000
+++ /dev/null
@@ -1,101 +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.util.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosBTKnown implements Iterable<AltosBTDevice> {
-       LinkedList<AltosBTDevice>       devices = new LinkedList<AltosBTDevice>();
-       AltosPreferencesBackend         bt_pref = AltosUIPreferences.bt_devices();
-
-       private String get_address(String name) {
-               return bt_pref.getString(name, "");
-       }
-
-       private void set_address(String name, String addr) {
-               bt_pref.putString(name, addr);
-       }
-
-       private void remove(String name) {
-               bt_pref.remove(name);
-       }
-
-       private void load() {
-               try {
-                       String[] names = bt_pref.keys();
-                       for (int i = 0; i < names.length; i++) {
-                               String  name = names[i];
-                               String  addr = get_address(name);
-                               devices.add(new AltosBTDevice(name, addr));
-                       }
-               } catch (IllegalStateException ie) {
-               }
-       }
-
-       public Iterator<AltosBTDevice> iterator() {
-               return devices.iterator();
-       }
-
-       private void flush() {
-               AltosUIPreferences.flush_preferences();
-       }
-
-       public void set(Iterable<AltosBTDevice> new_devices) {
-               for (AltosBTDevice old : devices) {
-                       boolean found = false;
-                       for (AltosBTDevice new_device : new_devices) {
-                               if (new_device.equals(old)) {
-                                       found = true;
-                                       break;
-                               }
-                       }
-                       if (!found)
-                               remove(old.getName());
-               }
-               devices = new LinkedList<AltosBTDevice>();
-               for (AltosBTDevice new_device : new_devices) {
-                       devices.add(new_device);
-                       set_address(new_device.getName(), new_device.getAddr());
-               }
-               flush();
-       }
-
-       public List<AltosDevice> list(int product) {
-               LinkedList<AltosDevice> list = new LinkedList<AltosDevice>();
-               for (AltosBTDevice device : devices) {
-                       if (device.matchProduct(product))
-                               list.add(device);
-               }
-               return list;
-       }
-
-       public AltosBTKnown() {
-               devices = new LinkedList<AltosBTDevice>();
-               bt_pref = AltosUIPreferences.bt_devices();
-               load();
-       }
-
-       static AltosBTKnown     known;
-
-       static public AltosBTKnown bt_known() {
-               if (known == null)
-                       known = new AltosBTKnown();
-               return known;
-       }
-}
diff --git a/altosui/AltosBTManage.java b/altosui/AltosBTManage.java
deleted file mode 100644 (file)
index 1015f7c..0000000
+++ /dev/null
@@ -1,357 +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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.plaf.basic.*;
-import java.util.*;
-import java.util.concurrent.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosBTManage extends AltosUIDialog implements ActionListener, Iterable<AltosBTDevice> {
-       LinkedBlockingQueue<AltosBTDevice> found_devices;
-       Frame frame;
-       LinkedList<ActionListener> listeners;
-       AltosBTKnown    bt_known;
-
-       class DeviceList extends JList implements Iterable<AltosBTDevice> {
-               LinkedList<AltosBTDevice> devices;
-               DefaultListModel        list_model;
-
-               public void add (AltosBTDevice device) {
-                       if (!devices.contains(device)) {
-                               devices.add(device);
-                               list_model.addElement(device);
-                       }
-               }
-
-               public void remove (AltosBTDevice device) {
-                       if (devices.contains(device)) {
-                               devices.remove(device);
-                               list_model.removeElement(device);
-                       }
-               }
-
-               public boolean contains(AltosBTDevice device) {
-                       return devices.contains(device);
-               }
-
-               //Subclass JList to workaround bug 4832765, which can cause the
-               //scroll pane to not let the user easily scroll up to the beginning
-               //of the list.  An alternative would be to set the unitIncrement
-               //of the JScrollBar to a fixed value. You wouldn't get the nice
-               //aligned scrolling, but it should work.
-               public int getScrollableUnitIncrement(Rectangle visibleRect,
-                                                     int orientation,
-                                                     int direction) {
-                       int row;
-                       if (orientation == SwingConstants.VERTICAL &&
-                           direction < 0 && (row = getFirstVisibleIndex()) != -1) {
-                               Rectangle r = getCellBounds(row, row);
-                               if ((r.y == visibleRect.y) && (row != 0))  {
-                                       Point loc = r.getLocation();
-                                       loc.y--;
-                                       int prevIndex = locationToIndex(loc);
-                                       Rectangle prevR = getCellBounds(prevIndex, prevIndex);
-
-                                       if (prevR == null || prevR.y >= r.y) {
-                                               return 0;
-                                       }
-                                       return prevR.height;
-                               }
-                       }
-                       return super.getScrollableUnitIncrement(
-                               visibleRect, orientation, direction);
-               }
-
-               public Iterator<AltosBTDevice> iterator() {
-                       return devices.iterator();
-               }
-
-               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++)
-                               l.add((AltosBTDevice)a[i]);
-                       return l;
-               }
-
-               public DeviceList() {
-                       devices = new LinkedList<AltosBTDevice>();
-                       list_model = new DefaultListModel();
-                       setModel(list_model);
-                       setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-                       setLayoutOrientation(JList.HORIZONTAL_WRAP);
-                       setVisibleRowCount(-1);
-               }
-       }
-
-       DeviceList      visible_devices;
-
-       DeviceList      known_devices;
-       Thread          bt_thread;
-
-       public Iterator<AltosBTDevice> iterator() {
-               return known_devices.iterator();
-       }
-
-       public void commit() {
-               bt_known.set(this);
-       }
-
-       public void add_known() {
-               try {
-                       for (AltosBTDevice device : visible_devices.selected_list()) {
-                               known_devices.add(device);
-                               visible_devices.remove(device);
-                       }
-               } catch (InterruptedException ie) {
-               }
-       }
-
-       public void remove_known() {
-               try {
-                       for (AltosBTDevice device : known_devices.selected_list()) {
-                               known_devices.remove(device);
-                               visible_devices.add(device);
-                       }
-               } catch (InterruptedException ie) {
-               }
-       }
-
-       public void addActionListener(ActionListener l) {
-               listeners.add(l);
-       }
-
-       private void forwardAction(ActionEvent e) {
-               for (ActionListener l : listeners)
-                       l.actionPerformed(e);
-       }
-
-       public void actionPerformed(ActionEvent e) {
-               String  command = e.getActionCommand();
-               if ("ok".equals(command)) {
-                       bt_thread.interrupt();
-                       commit();
-                       setVisible(false);
-                       forwardAction(e);
-               } else if ("cancel".equals(command)) {
-                       bt_thread.interrupt();
-                       setVisible(false);
-                       forwardAction(e);
-               } else if ("select".equals(command)) {
-                       add_known();
-               } else if ("deselect".equals(command)) {
-                       remove_known();
-               }
-       }
-
-       public void got_visible_device() {
-               while (!found_devices.isEmpty()) {
-                       AltosBTDevice   device = found_devices.remove();
-                       if (!known_devices.contains(device))
-                               visible_devices.add(device);
-               }
-       }
-
-       class BTGetVisibleDevices implements Runnable {
-               public void run () {
-                       for (;;)
-                               for (int time = 1; time <= 8; time <<= 1) {
-                                       AltosBTDeviceIterator   i = new AltosBTDeviceIterator(time);
-                                       AltosBTDevice           device;
-
-                                       if (Thread.interrupted())
-                                               return;
-                                       try {
-                                               while ((device = i.next()) != null) {
-                                                       Runnable r;
-
-                                                       if (Thread.interrupted())
-                                                               return;
-                                                       found_devices.add(device);
-                                                       r = new Runnable() {
-                                                                       public void run() {
-                                                                               got_visible_device();
-                                                                       }
-                                                               };
-                                                       SwingUtilities.invokeLater(r);
-                                               }
-                                       } catch (Exception e) {
-                                               System.out.printf("uh-oh, exception %s\n", e.toString());
-                                       }
-                               }
-               }
-       }
-
-       public static void show(Component frameComp, AltosBTKnown known) {
-               Frame   frame = JOptionPane.getFrameForComponent(frameComp);
-               AltosBTManage   dialog;
-
-               dialog = new AltosBTManage(frame, known);
-               dialog.setVisible(true);
-       }
-
-       public AltosBTManage(Frame in_frame, AltosBTKnown in_known) {
-               super(in_frame, "Manage Bluetooth Devices", true);
-
-               frame = in_frame;
-               bt_known = in_known;
-               BTGetVisibleDevices     get_visible_devices = new BTGetVisibleDevices();
-               bt_thread = new Thread(get_visible_devices);
-               bt_thread.start();
-
-               listeners = new LinkedList<ActionListener>();
-
-               found_devices = new LinkedBlockingQueue<AltosBTDevice>();
-
-               Container pane = getContentPane();
-               pane.setLayout(new GridBagLayout());
-
-               GridBagConstraints c = new GridBagConstraints();
-               c.insets = new Insets(4,4,4,4);
-
-               /*
-                * Known devices label and list
-                */
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 0;
-               c.gridy = 0;
-               c.gridwidth = 1;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(new JLabel("Known Devices"), c);
-
-               known_devices = new DeviceList();
-               for (AltosBTDevice device : bt_known)
-                       known_devices.add(device);
-
-               JScrollPane known_list_scroller = new JScrollPane(known_devices);
-               known_list_scroller.setPreferredSize(new Dimension(400, 80));
-               known_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
-               c.fill = GridBagConstraints.BOTH;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 0;
-               c.gridy = 1;
-               c.gridwidth = 1;
-               c.gridheight = 2;
-               c.weightx = 1;
-               c.weighty = 1;
-               pane.add(known_list_scroller, c);
-
-               /*
-                * Visible devices label and list
-                */
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 2;
-               c.gridy = 0;
-               c.gridwidth = 1;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-
-               pane.add(new JLabel("Visible Devices"), c);
-
-               visible_devices = new DeviceList();
-               JScrollPane visible_list_scroller = new JScrollPane(visible_devices);
-               visible_list_scroller.setPreferredSize(new Dimension(400, 80));
-               visible_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
-               c.fill = GridBagConstraints.BOTH;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 2;
-               c.gridy = 1;
-               c.gridheight = 2;
-               c.gridwidth = 1;
-               c.weightx = 1;
-               c.weighty = 1;
-               pane.add(visible_list_scroller, c);
-
-               /*
-                * Arrows between the two lists
-                */
-               BasicArrowButton select_arrow = new BasicArrowButton(SwingConstants.WEST);
-               select_arrow.setActionCommand("select");
-               select_arrow.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.SOUTH;
-               c.gridx = 1;
-               c.gridy = 1;
-               c.gridheight = 1;
-               c.gridwidth = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(select_arrow, c);
-
-               BasicArrowButton deselect_arrow = new BasicArrowButton(SwingConstants.EAST);
-               deselect_arrow.setActionCommand("deselect");
-               deselect_arrow.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.NORTH;
-               c.gridx = 1;
-               c.gridy = 2;
-               c.gridheight = 1;
-               c.gridwidth = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(deselect_arrow, c);
-
-               JButton cancel_button = new JButton("Cancel");
-               cancel_button.setActionCommand("cancel");
-               cancel_button.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.gridx = 0;
-               c.gridy = 3;
-               c.gridheight = 1;
-               c.gridwidth = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(cancel_button, c);
-
-               JButton ok_button = new JButton("OK");
-               ok_button.setActionCommand("ok");
-               ok_button.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.gridx = 2;
-               c.gridy = 3;
-               c.gridheight = 1;
-               c.gridwidth = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(ok_button, c);
-
-               getRootPane().setDefaultButton(ok_button);
-
-               pack();
-               setLocationRelativeTo(frame);
-               setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
-               addWindowListener(new WindowAdapter() {
-                       @Override
-                       public void windowClosing(WindowEvent e) {
-                               bt_thread.interrupt();
-                               setVisible(false);
-                       }
-               });
-       }
-}
diff --git a/altosui/AltosCSV.java b/altosui/AltosCSV.java
deleted file mode 100644 (file)
index 13f29f0..0000000
+++ /dev/null
@@ -1,335 +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.io.*;
-import java.util.*;
-import org.altusmetrum.altoslib_3.*;
-
-public class AltosCSV implements AltosWriter {
-       File                    name;
-       PrintStream             out;
-       boolean                 header_written;
-       boolean                 seen_boost;
-       int                     boost_tick;
-       LinkedList<AltosState>  pad_states;
-       AltosState              state;
-
-       static final int ALTOS_CSV_VERSION = 5;
-
-       /* Version 4 format:
-        *
-        * General info
-        *      version number
-        *      serial number
-        *      flight number
-        *      callsign
-        *      time (seconds since boost)
-        *      clock (tick count / 100)
-        *      rssi
-        *      link quality
-        *
-        * Flight status
-        *      state
-        *      state name
-        *
-        * Basic sensors
-        *      acceleration (m/s²)
-        *      pressure (mBar)
-        *      altitude (m)
-        *      height (m)
-        *      accelerometer speed (m/s)
-        *      barometer speed (m/s)
-        *      temp (°C)
-        *      battery (V)
-        *      drogue (V)
-        *      main (V)
-        *
-        * Advanced sensors (if available)
-        *      accel_x (m/s²)
-        *      accel_y (m/s²)
-        *      accel_z (m/s²)
-        *      gyro_x (d/s)
-        *      gyro_y (d/s)
-        *      gyro_z (d/s)
-        *      mag_x (g)
-        *      mag_y (g)
-        *      mag_z (g)
-        *
-        * GPS data (if available)
-        *      connected (1/0)
-        *      locked (1/0)
-        *      nsat (used for solution)
-        *      latitude (°)
-        *      longitude (°)
-        *      altitude (m)
-        *      year (e.g. 2010)
-        *      month (1-12)
-        *      day (1-31)
-        *      hour (0-23)
-        *      minute (0-59)
-        *      second (0-59)
-        *      from_pad_dist (m)
-        *      from_pad_azimuth (deg true)
-        *      from_pad_range (m)
-        *      from_pad_elevation (deg from horizon)
-        *      hdop
-        *
-        * GPS Sat data
-        *      C/N0 data for all 32 valid SDIDs
-        *
-        * Companion data
-        *      companion_id (1-255. 10 is TeleScience)
-        *      time of last companion data (seconds since boost)
-        *      update_period (0.1-2.55 minimum telemetry interval)
-        *      channels (0-12)
-        *      channel data for all 12 possible channels
-        */
-
-       void write_general_header() {
-               out.printf("version,serial,flight,call,time,clock,rssi,lqi");
-       }
-
-       void write_general(AltosState state) {
-               out.printf("%s, %d, %d, %s, %8.2f, %8.2f, %4d, %3d",
-                          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(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(AltosState state) {
-               out.printf("%8.2f,%10.2f,%8.2f,%8.2f,%8.2f,%8.2f,%5.1f,%5.2f,%5.2f,%5.2f",
-                          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(AltosState state) {
-               AltosIMU        imu = state.imu;
-               AltosMag        mag = state.mag;
-
-               if (imu == null)
-                       imu = new AltosIMU();
-               if (mag == null)
-                       mag = new AltosMag();
-               out.printf("%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d",
-                          imu.accel_x, imu.accel_y, imu.accel_z,
-                          imu.gyro_x, imu.gyro_y, imu.gyro_z,
-                          mag.x, mag.y, mag.z);
-       }
-
-       void write_gps_header() {
-               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(AltosState state) {
-               AltosGPS        gps = state.gps;
-               if (gps == null)
-                       gps = new AltosGPS();
-
-               AltosGreatCircle from_pad = state.from_pad;
-               if (from_pad == null)
-                       from_pad = new AltosGreatCircle();
-
-               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,
-                          gps.lat,
-                          gps.lon,
-                          gps.alt,
-                          gps.year,
-                          gps.month,
-                          gps.day,
-                          gps.hour,
-                          gps.minute,
-                          gps.second,
-                          from_pad.distance,
-                          state.range,
-                          from_pad.bearing,
-                          state.elevation,
-                          gps.hdop);
-       }
-
-       void write_gps_sat_header() {
-               for(int i = 1; i <= 32; i++) {
-                       out.printf("sat%02d", i);
-                       if (i != 32)
-                               out.printf(",");
-               }
-       }
-
-       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) {
-                               for(int j = 0; j < gps.cc_gps_sat.length; j++)
-                                       if (gps.cc_gps_sat[j].svid == i) {
-                                               c_n0 = gps.cc_gps_sat[j].c_n0;
-                                               break;
-                                       }
-                       }
-                       out.printf ("%3d", c_n0);
-                       if (i != 32)
-                               out.printf(",");
-               }
-       }
-
-       void write_companion_header() {
-               out.printf("companion_id,companion_time,companion_update,companion_channels");
-               for (int i = 0; i < 12; i++)
-                       out.printf(",companion_%02d", i);
-       }
-
-       void write_companion(AltosState state) {
-               AltosCompanion companion = state.companion;
-
-               int     channels_written = 0;
-               if (companion == null) {
-                       out.printf("0,0,0,0");
-               } else {
-                       out.printf("%3d,%5.2f,%5.2f,%2d",
-                                  companion.board_id,
-                                  (companion.tick - boost_tick) / 100.0,
-                                  companion.update_period / 100.0,
-                                  companion.channels);
-                       for (; channels_written < companion.channels; channels_written++)
-                               out.printf(",%5d", companion.companion_data[channels_written]);
-               }
-               for (; channels_written < 12; channels_written++)
-                       out.printf(",0");
-       }
-
-       void write_header(boolean advanced, boolean gps, boolean companion) {
-               out.printf("#"); write_general_header();
-               out.printf(","); write_flight_header();
-               out.printf(","); write_basic_header();
-               if (advanced)
-                       out.printf(","); write_advanced_header();
-               if (gps) {
-                       out.printf(","); write_gps_header();
-                       out.printf(","); write_gps_sat_header();
-               }
-               if (companion) {
-                       out.printf(","); write_companion_header();
-               }
-               out.printf ("\n");
-       }
-
-       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(state); out.printf(",");
-                       write_gps_sat(state);
-               }
-               if (state.companion != null) {
-                       out.printf(",");
-                       write_companion(state);
-               }
-               out.printf ("\n");
-       }
-
-       void flush_pad() {
-               while (!pad_states.isEmpty()) {
-                       write_one (pad_states.remove());
-               }
-       }
-
-       public void write(AltosState state) {
-               if (state.state == Altos.ao_flight_startup)
-                       return;
-               if (!header_written) {
-                       write_header(state.imu != null || state.mag != null,
-                                    state.gps != null, state.companion != null);
-                       header_written = true;
-               }
-               if (!seen_boost) {
-                       if (state.state >= Altos.ao_flight_boost) {
-                               seen_boost = true;
-                               boost_tick = state.tick;
-                               flush_pad();
-                       }
-               }
-               if (seen_boost)
-                       write_one(state);
-               else
-                       pad_states.add(state);
-       }
-
-       public PrintStream out() {
-               return out;
-       }
-
-       public void close() {
-               if (!pad_states.isEmpty()) {
-                       boost_tick = pad_states.element().tick;
-                       flush_pad();
-               }
-               out.close();
-       }
-
-       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_states = new LinkedList<AltosState>();
-       }
-
-       public AltosCSV(File in_name) throws FileNotFoundException {
-               this(new PrintStream(in_name), in_name);
-       }
-
-       public AltosCSV(String in_string) throws FileNotFoundException {
-               this(new File(in_string));
-       }
-}
diff --git a/altosui/AltosCSVUI.java b/altosui/AltosCSVUI.java
deleted file mode 100644 (file)
index 05cabcd..0000000
+++ /dev/null
@@ -1,104 +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.*;
-import java.awt.event.*;
-import javax.swing.*;
-import java.io.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosCSVUI
-       extends AltosUIDialog
-       implements ActionListener
-{
-       JFileChooser            csv_chooser;
-       JPanel                  accessory;
-       JComboBox               combo_box;
-       Iterable<AltosState>    states;
-       AltosWriter             writer;
-
-       static String[]         combo_box_items = { "Comma Separated Values (.CSV)", "Googleearth Data (.KML)" };
-
-       void set_default_file() {
-               File    current = csv_chooser.getSelectedFile();
-               String  current_name = current.getName();
-               String  new_name = null;
-               String  selected = (String) combo_box.getSelectedItem();
-
-               if (selected.contains("CSV"))
-                       new_name = Altos.replace_extension(current_name, ".csv");
-               else if (selected.contains("KML"))
-                       new_name = Altos.replace_extension(current_name, ".kml");
-               if (new_name != null)
-                       csv_chooser.setSelectedFile(new File(new_name));
-       }
-
-       public void actionPerformed(ActionEvent e) {
-               if (e.getActionCommand().equals("comboBoxChanged"))
-                       set_default_file();
-       }
-
-       public AltosCSVUI(JFrame frame, AltosStateIterable states, File source_file) {
-               this.states = states;
-               csv_chooser = new JFileChooser(source_file);
-
-               accessory = new JPanel();
-               accessory.setLayout(new GridBagLayout());
-
-               GridBagConstraints      c = new GridBagConstraints();
-               c.fill = GridBagConstraints.NONE;
-               c.weightx = 1;
-               c.weighty = 0;
-               c.insets = new Insets (4, 4, 4, 4);
-
-               JLabel accessory_label = new JLabel("Export File Type");
-               c.gridx = 0;
-               c.gridy = 0;
-               accessory.add(accessory_label, c);
-
-               combo_box = new JComboBox(combo_box_items);
-               combo_box.addActionListener(this);
-               c.gridx = 0;
-               c.gridy = 1;
-               accessory.add(combo_box, c);
-
-               csv_chooser.setAccessory(accessory);
-               csv_chooser.setSelectedFile(source_file);
-               set_default_file();
-               int ret = csv_chooser.showSaveDialog(frame);
-               if (ret == JFileChooser.APPROVE_OPTION) {
-                       File file = csv_chooser.getSelectedFile();
-                       String type = (String) combo_box.getSelectedItem();
-                       try {
-                               if (type.contains("CSV"))
-                                       writer = new AltosCSV(file);
-                               else
-                                       writer = new AltosKML(file);
-                               writer.write(states);
-                               writer.close();
-                       } catch (FileNotFoundException ee) {
-                               JOptionPane.showMessageDialog(frame,
-                                                             ee.getMessage(),
-                                                             "Cannot open file",
-                                                             JOptionPane.ERROR_MESSAGE);
-                       }
-               }
-       }
-}
index f90a11c0aa93a13b60eb3d761d01ee2a2b157ba9..382b6ae47809f9202521af7bb281a37bf6c66ae1 100644 (file)
@@ -20,7 +20,7 @@ package altosui;
 import java.awt.event.*;
 import javax.swing.*;
 
-public class AltosChannelMenu extends JComboBox implements ActionListener {
+public class AltosChannelMenu extends JComboBox<String> implements ActionListener {
        int                             channel;
 
        public AltosChannelMenu(int current_channel) {
index 4cc6c462f28e948bbadad37c0b03da90299f538c..e7b335ac7f6fcc32168e3c0c7cedb08b5928d674 100644 (file)
@@ -19,9 +19,10 @@ package altosui;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
-public class AltosCompanionInfo extends JTable {
+public class AltosCompanionInfo extends JTable implements AltosFlightDisplay {
        private AltosFlightInfoTableModel model;
 
        static final int info_columns = 2;
@@ -32,25 +33,28 @@ public class AltosCompanionInfo extends JTable {
                return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10;
        }
 
-       public void set_font() {
+       public void font_size_changed(int font_size) {
                setFont(Altos.table_value_font);
                setRowHeight(desired_row_height());
                doLayout();
        }
 
+       public void units_changed(boolean imperial_units) {
+       }
+
        public AltosCompanionInfo() {
                super(new AltosFlightInfoTableModel(info_rows, info_columns));
                model = (AltosFlightInfoTableModel) getModel();
                setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS);
                setShowGrid(true);
-               set_font();
+               font_size_changed(AltosUIPreferences.font_size());
        }
 
        public Dimension getPreferredScrollableViewportSize() {
                return getPreferredSize();
        }
 
-       void info_reset() {
+       public void reset() {
                model.reset();
        }
 
@@ -82,13 +86,15 @@ public class AltosCompanionInfo extends JTable {
                        return String.format("%02x\n", companion.board_id);
                }
        }
-       
+
+       public String getName() { return "Companion"; }
+
        public void show(AltosState state, AltosListenerState listener_state) {
                if (state == null)
                        return;
                if (state.companion != null)
                        companion = state.companion;
-               info_reset();
+               reset();
                info_add_row(0, "Companion board", "%s", board_name());
                if (companion != null) {
                        info_add_row(0, "Last Data", "%5d", companion.tick);
index e1805fc12be91d70b1365f86d08dc8e019985ea1..6eb7d40cb34ea88e7a0d60469ed9a179094bbd6a 100644 (file)
@@ -22,8 +22,8 @@ import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.text.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class AltosConfig implements ActionListener {
 
@@ -229,22 +229,28 @@ public class AltosConfig implements ActionListener {
 
        void save_data() {
 
-               /* bounds check stuff */
-               if (config_ui.flight_log_max() > data.log_limit()) {
+               try {
+                       /* bounds check stuff */
+                       if (config_ui.flight_log_max() > data.log_space() / 1024) {
+                               JOptionPane.showMessageDialog(owner,
+                                                             String.format("Requested flight log, %dk, is larger than the available space, %dk.\n",
+                                                                           config_ui.flight_log_max(),
+                                                                           data.log_space() / 1024),
+                                                             "Maximum Flight Log Too Large",
+                                                             JOptionPane.ERROR_MESSAGE);
+                               return;
+                       }
+
+                       /* Pull data out of the UI and stuff back into our local data record */
+
+                       data.get_values(config_ui);
+                       run_serial_thread(serial_mode_save);
+               } catch (AltosConfigDataException ae) {
                        JOptionPane.showMessageDialog(owner,
-                                                     String.format("Requested flight log, %dk, is larger than the available space, %dk.\n",
-                                                                   config_ui.flight_log_max(),
-                                                                   data.log_limit()),
-                                                     "Maximum Flight Log Too Large",
+                                                     ae.getMessage(),
+                                                     "Configuration Data Error",
                                                      JOptionPane.ERROR_MESSAGE);
-                       return;
                }
-
-               /* Pull data out of the UI and stuff back into our local data record */
-
-               data.get_values(config_ui);
-
-               run_serial_thread(serial_mode_save);
        }
 
        public void actionPerformed(ActionEvent e) {
@@ -298,4 +304,4 @@ public class AltosConfig implements ActionListener {
                        }
                }
        }
-}
\ No newline at end of file
+}
diff --git a/altosui/AltosConfigFreqUI.java b/altosui/AltosConfigFreqUI.java
deleted file mode 100644 (file)
index e9923a3..0000000
+++ /dev/null
@@ -1,412 +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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import java.util.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-class AltosEditFreqUI extends AltosUIDialog implements ActionListener {
-       Frame           frame;
-       JTextField      frequency;
-       JTextField      description;
-       JButton         ok_button, cancel_button;
-       boolean         got_ok;
-
-       public void actionPerformed(ActionEvent e) {
-               String  cmd = e.getActionCommand();
-
-               if ("ok".equals(cmd)) {
-                       got_ok = true;
-                       setVisible(false);
-               }
-               if ("cancel".equals(cmd)) {
-                       got_ok = false;
-                       setVisible(false);
-               }
-       }
-
-       public AltosFrequency get() {
-               if (!got_ok)
-                       return null;
-
-               String  f_s = frequency.getText();
-               String  d_s = description.getText();
-
-               try {
-                       double  f_d = Double.parseDouble(f_s);
-
-                       return new AltosFrequency(f_d, d_s);
-               } catch (NumberFormatException ne) {
-               }
-               return null;
-       }
-
-       public AltosEditFreqUI(Frame in_frame, AltosFrequency existing) {
-               super(in_frame, true);
-
-               got_ok = false;
-               frame = in_frame;
-
-               Container pane = getContentPane();
-               pane.setLayout(new GridBagLayout());
-
-               GridBagConstraints c = new GridBagConstraints();
-               c.insets = new Insets (4,4,4,4);
-               
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 0;
-               c.gridy = 0;
-               c.gridwidth = 1;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(new JLabel("Frequency"), c);
-
-               frequency = new JTextField(12);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 1;
-               c.gridy = 0;
-               c.gridwidth = 1;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(frequency, c);
-
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 0;
-               c.gridy = 1;
-               c.gridwidth = 1;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(new JLabel("Description"), c);
-
-               description = new JTextField(12);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 1;
-               c.gridy = 1;
-               c.gridwidth = 1;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(description, c);
-
-               ok_button = new JButton("OK");
-               ok_button.setActionCommand("ok");
-               ok_button.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 0;
-               c.gridy = 2;
-               c.gridwidth = 1;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(ok_button, c);
-               
-               cancel_button = new JButton("Cancel");
-               cancel_button.setActionCommand("cancel");
-               cancel_button.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 1;
-               c.gridy = 2;
-               c.gridwidth = 1;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(cancel_button, c);
-               
-               if (existing == null)
-                       setTitle("Add New Frequency");
-               else {
-                       setTitle("Edit Existing Frequency");
-                       frequency.setText(String.format("%7.3f", existing.frequency));
-                       description.setText(existing.description);
-               }
-               getRootPane().setDefaultButton(ok_button);
-
-               pack();
-               setLocationRelativeTo(frame);
-               
-       }
-
-       public AltosEditFreqUI(Frame in_frame) {
-               this(in_frame, (AltosFrequency) null);
-       }
-}
-
-public class AltosConfigFreqUI extends AltosUIDialog implements ActionListener {
-
-       Frame frame;
-       LinkedList<ActionListener> listeners;
-
-       class FrequencyList extends JList {
-               DefaultListModel list_model;
-
-               public void add(AltosFrequency frequency) {
-                       int i;
-                       for (i = 0; i < list_model.size(); i++) {
-                               AltosFrequency  f = (AltosFrequency) list_model.get(i);
-                               if (frequency.frequency == f.frequency)
-                                       return;
-                               if (frequency.frequency < f.frequency)
-                                       break;
-                       }
-                       list_model.insertElementAt(frequency, i);
-               }
-
-               public void remove(AltosFrequency frequency) {
-                       list_model.removeElement(frequency);
-               }
-
-               //Subclass JList to workaround bug 4832765, which can cause the
-               //scroll pane to not let the user easily scroll up to the beginning
-               //of the list.  An alternative would be to set the unitIncrement
-               //of the JScrollBar to a fixed value. You wouldn't get the nice
-               //aligned scrolling, but it should work.
-               public int getScrollableUnitIncrement(Rectangle visibleRect,
-                                                     int orientation,
-                                                     int direction) {
-                       int row;
-                       if (orientation == SwingConstants.VERTICAL &&
-                           direction < 0 && (row = getFirstVisibleIndex()) != -1) {
-                               Rectangle r = getCellBounds(row, row);
-                               if ((r.y == visibleRect.y) && (row != 0))  {
-                                       Point loc = r.getLocation();
-                                       loc.y--;
-                                       int prevIndex = locationToIndex(loc);
-                                       Rectangle prevR = getCellBounds(prevIndex, prevIndex);
-
-                                       if (prevR == null || prevR.y >= r.y) {
-                                               return 0;
-                                       }
-                                       return prevR.height;
-                               }
-                       }
-                       return super.getScrollableUnitIncrement(
-                               visibleRect, orientation, direction);
-               }
-
-               public AltosFrequency selected() {
-                       AltosFrequency  f = (AltosFrequency) getSelectedValue();
-                       return f;
-               }
-
-               public AltosFrequency[] frequencies() {
-                       AltosFrequency[]        ret;
-
-                       ret = new AltosFrequency[list_model.size()];
-                       for (int i = 0; i < list_model.size(); i++)
-                               ret[i] = (AltosFrequency) list_model.get(i);
-                       return ret;
-               }
-
-               public FrequencyList(AltosFrequency[] in_frequencies) {
-                       list_model = new DefaultListModel();
-                       setModel(list_model);
-                       setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-                       setLayoutOrientation(JList.HORIZONTAL_WRAP);
-                       for (int i = 0; i < in_frequencies.length; i++) {
-                               add(in_frequencies[i]);
-                       }
-                       setVisibleRowCount(in_frequencies.length);
-               }
-       }
-
-       FrequencyList   frequencies;
-
-       void save_frequencies() {
-               AltosUIPreferences.set_common_frequencies(frequencies.frequencies());
-       }
-
-       JButton add, edit, remove;
-
-       JButton cancel, ok;
-
-       public void actionPerformed(ActionEvent e) {
-               String  cmd = e.getActionCommand();
-
-               if ("ok".equals(cmd)) {
-                       save_frequencies();
-                       setVisible(false);
-               } else if ("cancel".equals(cmd)) {
-                       setVisible(false);
-               } else if ("add".equals(cmd)) {
-                       AltosEditFreqUI ui = new AltosEditFreqUI(frame);
-                       ui.setVisible(true);
-                       AltosFrequency  f = ui.get();
-                       if (f != null)
-                               frequencies.add(f);
-               } else if ("edit".equals(cmd)) {
-                       AltosFrequency  old_f = frequencies.selected();
-                       if (old_f == null)
-                               return;
-                       AltosEditFreqUI ui = new AltosEditFreqUI(frame, old_f);
-                       ui.setVisible(true);
-                       AltosFrequency  new_f = ui.get();
-                       if (new_f != null) {
-                               if (old_f != null)
-                                       frequencies.remove(old_f);
-                               frequencies.add(new_f);
-                       }
-               } else if ("remove".equals(cmd)) {
-                       AltosFrequency  old_f = frequencies.selected();
-                       if (old_f == null)
-                               return;
-                       int ret = JOptionPane.showConfirmDialog(this,
-                                                               String.format("Remove frequency \"%s\"?",
-                                                                             old_f.toShortString()),
-                                                               "Remove Frequency",
-                                                               JOptionPane.YES_NO_OPTION);
-                       if (ret == JOptionPane.YES_OPTION)
-                               frequencies.remove(old_f);
-               }
-       }
-
-       public AltosFrequency[] frequencies() {
-               return frequencies.frequencies();
-       }
-       
-       public AltosConfigFreqUI(Frame in_frame,
-                                AltosFrequency[] in_frequencies) {
-               super(in_frame, "Manage Frequencies", true);
-
-               frame = in_frame;
-
-               listeners = new LinkedList<ActionListener>();
-
-               frequencies = new FrequencyList(in_frequencies);
-
-               Container pane = getContentPane();
-               pane.setLayout(new GridBagLayout());
-
-               GridBagConstraints c = new GridBagConstraints();
-               c.insets = new Insets(4,4,4,4);
-
-               /*
-                * Frequencies label and list
-                */
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 0;
-               c.gridy = 0;
-               c.gridwidth = 1;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(new JLabel("Frequencies"), c);
-
-               JScrollPane list_scroller = new JScrollPane(frequencies);
-               list_scroller.setAlignmentX(LEFT_ALIGNMENT);
-               c.fill = GridBagConstraints.BOTH;
-               c.anchor = GridBagConstraints.WEST;
-               c.gridx = 0;
-               c.gridy = 1;
-               c.gridwidth = 6;
-               c.gridheight = 2;
-               c.weightx = 1;
-               c.weighty = 1;
-               pane.add(list_scroller, c);
-
-               add = new JButton("Add");
-               add.setActionCommand("add");
-               add.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.gridx = 0;
-               c.gridy = 3;
-               c.gridwidth = 2;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(add, c);
-
-               edit = new JButton("Edit");
-               edit.setActionCommand("edit");
-               edit.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.gridx = 2;
-               c.gridy = 3;
-               c.gridwidth = 2;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(edit, c);
-
-               remove = new JButton("Remove");
-               remove.setActionCommand("remove");
-               remove.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.gridx = 4;
-               c.gridy = 3;
-               c.gridwidth = 2;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(remove, c);
-
-               ok = new JButton("OK");
-               ok.setActionCommand("ok");
-               ok.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.gridx = 0;
-               c.gridy = 4;
-               c.gridwidth = 3;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(ok, c);
-
-               cancel = new JButton("Cancel");
-               cancel.setActionCommand("cancel");
-               cancel.addActionListener(this);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.gridx = 3;
-               c.gridy = 4;
-               c.gridwidth = 3;
-               c.gridheight = 1;
-               c.weightx = 0;
-               c.weighty = 0;
-               pane.add(cancel, c);
-
-               pack();
-               setLocationRelativeTo(frame);
-       }
-
-       public static void show(Component frameComp) {
-               Frame   frame = JOptionPane.getFrameForComponent(frameComp);
-               AltosConfigFreqUI       dialog;
-
-               dialog = new AltosConfigFreqUI(frame, AltosUIPreferences.common_frequencies());
-               dialog.setVisible(true);
-       }
-
-}
index b14c39ab86e1c5ea2f0ca74d92194003d66394a3..f0b4f0f998a2cb31de3bc668a81aa5fdd10b52fb 100644 (file)
@@ -21,8 +21,8 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.event.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class AltosConfigPyroUI
        extends AltosUIDialog
@@ -50,7 +50,7 @@ public class AltosConfigPyroUI
                public int              flag;
                public JCheckBox        enable;
                public JTextField       value;
-               public JComboBox        combo;
+               public JComboBox<String>        combo;
                AltosConfigPyroUI       ui;
                boolean                 setting;
 
@@ -63,22 +63,22 @@ public class AltosConfigPyroUI
 
                public void itemStateChanged(ItemEvent e) {
                        set_enable(enable.isSelected());
-                       if (!setting) 
+                       if (!setting)
                                ui.set_dirty();
                }
 
                public void changedUpdate(DocumentEvent e) {
-                       if (!setting) 
+                       if (!setting)
                                ui.set_dirty();
                }
 
                public void insertUpdate(DocumentEvent e) {
-                       if (!setting) 
+                       if (!setting)
                                ui.set_dirty();
                }
 
                public void removeUpdate(DocumentEvent e) {
-                       if (!setting) 
+                       if (!setting)
                                ui.set_dirty();
                }
 
@@ -105,11 +105,13 @@ public class AltosConfigPyroUI
                                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)
+                               String  format;
+                               if (scale >= 100)
                                        format = "%6.2f";
+                               else if (scale >= 10)
+                                       format = "%6.1f";
+                               else
+                                       format = "%6.0f";
                                value.setText(String.format(format, unit_value));
                        }
                        if (combo != null)
@@ -122,12 +124,16 @@ public class AltosConfigPyroUI
                        return enable.isSelected();
                }
 
-               public double value() {
+               public double value() throws AltosConfigDataException {
                        if (value != null) {
                                AltosUnits units = AltosPyro.pyro_to_units(flag);
-                               if (units != null)
-                                       return units.parse(value.getText());
-                               return Double.parseDouble(value.getText());
+                               try {
+                                       if (units != null)
+                                               return units.parse(value.getText());
+                                       return Double.parseDouble(value.getText());
+                               } catch (NumberFormatException e) {
+                                       throw new AltosConfigDataException("\"%s\": %s\n", value.getText(), e.getMessage());
+                               }
                        }
                        if (combo != null)
                                return combo.getSelectedIndex() + AltosLib.ao_flight_boost;
@@ -149,7 +155,7 @@ public class AltosConfigPyroUI
                        enable = new JCheckBox();
                        enable.addItemListener(this);
                        pane.add(enable, c);
-                       
+
                        if ((flag & AltosPyro.pyro_no_value) == 0) {
                                c = new GridBagConstraints();
                                c.gridx = x+1; c.gridy = y;
@@ -159,7 +165,7 @@ public class AltosConfigPyroUI
                                c.insets = il;
                                if ((flag & AltosPyro.pyro_state_value) != 0) {
                                        make_state_names();
-                                       combo = new JComboBox(state_names);
+                                       combo = new JComboBox<String>(state_names);
                                        combo.addItemListener(this);
                                        pane.add(combo, c);
                                } else {
@@ -187,15 +193,21 @@ public class AltosConfigPyroUI
                        }
                }
 
-               public AltosPyro get() {
+               public AltosPyro get() throws AltosConfigDataException {
                        AltosPyro       p = new AltosPyro(channel);
 
                        int row = 0;
                        for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
                                if ((AltosPyro.pyro_all & flag) != 0) {
                                        if (items[row].enabled()) {
+                                               try {
                                                p.flags |= flag;
                                                p.set_value(flag, items[row].value());
+                                               } catch (AltosConfigDataException ae) {
+                                                       throw new AltosConfigDataException("%s, %s",
+                                                                                          AltosPyro.pyro_to_name(flag),
+                                                                                          ae.getMessage());
+                                               }
                                        }
                                        row++;
                                }
@@ -224,7 +236,7 @@ public class AltosConfigPyroUI
 
                        items = new PyroItem[nrow];
                        int row = 0;
-                       
+
                        GridBagConstraints      c;
                        c = new GridBagConstraints();
                        c.gridx = x; c.gridy = y;
@@ -254,13 +266,40 @@ public class AltosConfigPyroUI
                }
        }
 
-       public AltosPyro[] get_pyros() {
+       public AltosPyro[] get_pyros() throws AltosConfigDataException {
                AltosPyro[]     pyros = new AltosPyro[columns.length];
-               for (int c = 0; c < columns.length; c++)
-                       pyros[c] = columns[c].get();
+               for (int c = 0; c < columns.length; c++) {
+                       try {
+                               pyros[c] = columns[c].get();
+                       } catch (AltosConfigDataException ae) {
+                               throw new AltosConfigDataException ("Channel %c, %s", c + 'A', ae.getMessage());
+                       }
+               }
                return pyros;
        }
 
+       JLabel                  pyro_firing_time_label;
+       JComboBox<String>       pyro_firing_time_value;
+
+       static String[]         pyro_firing_time_values = {
+               "0.050", "0.100", "0.250", "0.500", "1.0", "2.0"
+       };
+
+       public void set_pyro_firing_time(double new_pyro_firing_time) {
+               pyro_firing_time_value.setSelectedItem(Double.toString(new_pyro_firing_time));
+               pyro_firing_time_value.setEnabled(new_pyro_firing_time >= 0);
+       }
+
+       public double get_pyro_firing_time() throws AltosConfigDataException {
+               String  v = pyro_firing_time_value.getSelectedItem().toString();
+
+               try {
+                       return Double.parseDouble(v);
+               } catch (NumberFormatException e) {
+                       throw new AltosConfigDataException("Invalid pyro firing time \"%s\"", v);
+               }
+       }
+
        public void set_dirty() {
                owner.set_dirty();
        }
@@ -317,7 +356,7 @@ public class AltosConfigPyroUI
                        setVisible(false);
        }
 
-       public AltosConfigPyroUI(AltosConfigUI in_owner, AltosPyro[] pyros) {
+       public AltosConfigPyroUI(AltosConfigUI in_owner, AltosPyro[] pyros, double pyro_firing_time) {
 
                super(in_owner, "Configure Pyro Channels", false);
 
@@ -362,6 +401,32 @@ public class AltosConfigPyroUI
                        columns[i].set(pyros[i]);
                }
 
+               /* Pyro firing time */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 2;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               pyro_firing_time_label = new JLabel("Pyro Firing Time(s):");
+               pane.add(pyro_firing_time_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 2; c.gridy = row;
+               c.gridwidth = 7;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               pyro_firing_time_value = new JComboBox<String>(pyro_firing_time_values);
+               pyro_firing_time_value.setEditable(true);
+               pyro_firing_time_value.addItemListener(this);
+               set_pyro_firing_time(pyro_firing_time);
+               pane.add(pyro_firing_time_value, c);
+               pyro_firing_time_value.setToolTipText("Length of extra pyro channel firing pulse");
+
                c = new GridBagConstraints();
                c.gridx = pyros.length*2-1;
                c.fill = GridBagConstraints.HORIZONTAL;
@@ -371,7 +436,7 @@ public class AltosConfigPyroUI
                pane.add(close, c);
                close.addActionListener(this);
                close.setActionCommand("Close");
-               
+
                addWindowListener(new ConfigListener(this, owner));
                AltosPreferences.register_units_listener(this);
        }
index ad9ebbfacf82b4ab8a3ad479713f949b30850935..bfbd2c7710ef296118724e50a85cce9c625be561 100644 (file)
@@ -21,8 +21,8 @@ import java.awt.event.*;
 import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class AltosConfigTD implements ActionListener {
 
index 3ce0d98c1c8068a48eaa0370cc3674bc6d0ccc73..22b3384d6a995e7a341c6eac16a1f6c4c8f17121 100644 (file)
@@ -21,8 +21,8 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.event.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class AltosConfigTDUI
        extends AltosUIDialog
@@ -311,7 +311,7 @@ public class AltosConfigTDUI
                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;
@@ -319,7 +319,7 @@ public class AltosConfigTDUI
                }
                for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
                        AltosFrequency  f = (AltosFrequency) radio_frequency_value.getItemAt(i);
-                       
+
                        if (new_radio_frequency < f.frequency)
                                break;
                }
index 21ea50e638f6bb21ddcab43dd0c5009c2b67bfb9..1b5ff9881b0c2ee28458e9ff8772d778fcf3bf5e 100644 (file)
@@ -21,102 +21,130 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.event.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class AltosConfigUI
        extends AltosUIDialog
        implements ActionListener, ItemListener, DocumentListener, AltosConfigValues, AltosUnitsListener
 {
 
-       Container       pane;
-       JLabel          product_label;
-       JLabel          version_label;
-       JLabel          serial_label;
-       JLabel          main_deploy_label;
-       JLabel          apogee_delay_label;
-       JLabel          apogee_lockout_label;
-       JLabel          frequency_label;
-       JLabel          radio_calibration_label;
-       JLabel          radio_frequency_label;
-       JLabel          radio_enable_label;
-       JLabel          aprs_interval_label;
-       JLabel          flight_log_max_label;
-       JLabel          ignite_mode_label;
-       JLabel          pad_orientation_label;
-       JLabel          callsign_label;
+       Container               pane;
+       JLabel                  product_label;
+       JLabel                  version_label;
+       JLabel                  serial_label;
+       JLabel                  main_deploy_label;
+       JLabel                  apogee_delay_label;
+       JLabel                  apogee_lockout_label;
+       JLabel                  frequency_label;
+       JLabel                  radio_calibration_label;
+       JLabel                  radio_frequency_label;
+       JLabel                  radio_enable_label;
+       JLabel                  aprs_interval_label;
+       JLabel                  flight_log_max_label;
+       JLabel                  ignite_mode_label;
+       JLabel                  pad_orientation_label;
+       JLabel                  callsign_label;
+       JLabel                  beep_label;
+       JLabel                  tracker_motion_label;
+       JLabel                  tracker_interval_label;
 
        public boolean          dirty;
 
-       JFrame          owner;
-       JLabel          product_value;
-       JLabel          version_value;
-       JLabel          serial_value;
-       JComboBox       main_deploy_value;
-       JComboBox       apogee_delay_value;
-       JComboBox       apogee_lockout_value;
-       AltosFreqList   radio_frequency_value;
-       JTextField      radio_calibration_value;
-       JRadioButton    radio_enable_value;
-       JComboBox       aprs_interval_value;
-       JComboBox       flight_log_max_value;
-       JComboBox       ignite_mode_value;
-       JComboBox       pad_orientation_value;
-       JTextField      callsign_value;
-
-       JButton         pyro;
-
-       JButton         save;
-       JButton         reset;
-       JButton         reboot;
-       JButton         close;
-
-       AltosPyro[]     pyros;
-
-       ActionListener  listener;
-
-       static String[] main_deploy_values_m = {
+       JFrame                  owner;
+       JLabel                  product_value;
+       JLabel                  version_value;
+       JLabel                  serial_value;
+       JComboBox<String>       main_deploy_value;
+       JComboBox<String>       apogee_delay_value;
+       JComboBox<String>       apogee_lockout_value;
+       AltosFreqList           radio_frequency_value;
+       JTextField              radio_calibration_value;
+       JRadioButton            radio_enable_value;
+       JComboBox<String>       aprs_interval_value;
+       JComboBox<String>       flight_log_max_value;
+       JComboBox<String>       ignite_mode_value;
+       JComboBox<String>       pad_orientation_value;
+       JTextField              callsign_value;
+       JComboBox<String>       beep_value;
+       JComboBox<String>       tracker_motion_value;
+       JComboBox<String>       tracker_interval_value;
+
+       JButton                 pyro;
+
+       JButton                 save;
+       JButton                 reset;
+       JButton                 reboot;
+       JButton                 close;
+
+       AltosPyro[]             pyros;
+       double                  pyro_firing_time;
+
+       ActionListener          listener;
+
+       static String[]         main_deploy_values_m = {
                "100", "150", "200", "250", "300", "350",
                "400", "450", "500"
        };
 
-       static String[] main_deploy_values_ft = {
+       static String[]         main_deploy_values_ft = {
                "250", "500", "750", "1000", "1250", "1500",
                "1750", "2000"
        };
 
-       static String[] apogee_delay_values = {
+       static String[]         apogee_delay_values = {
                "0", "1", "2", "3", "4", "5"
        };
 
-       static String[] apogee_lockout_values = {
+       static String[]         apogee_lockout_values = {
                "0", "5", "10", "15", "20"
        };
 
-       static String[] flight_log_max_values = {
-               "64", "128", "192", "256", "320",
-               "384", "448", "512", "576", "640",
-               "704", "768", "832", "896", "960",
-       };
-
-       static String[] ignite_mode_values = {
+       static String[]         ignite_mode_values = {
                "Dual Deploy",
                "Redundant Apogee",
                "Redundant Main",
        };
 
-       static String[] aprs_interval_values = {
+       static String[]         aprs_interval_values = {
                "Disabled",
                "2",
                "5",
                "10"
        };
 
-       static String[] pad_orientation_values = {
+       static String[]         beep_values = {
+               "3750",
+               "4000",
+               "4250",
+       };
+
+       static String[]         pad_orientation_values = {
                "Antenna Up",
                "Antenna Down",
        };
 
+       static String[]         tracker_motion_values_m = {
+               "2",
+               "5",
+               "10",
+               "25",
+       };
+
+       static String[]         tracker_motion_values_ft = {
+               "5",
+               "20",
+               "50",
+               "100"
+       };
+
+       static String[]         tracker_interval_values = {
+               "1",
+               "2",
+               "5",
+               "10"
+       };
+
        /* A window listener to catch closing events and tell the config code */
        class ConfigListener extends WindowAdapter {
                AltosConfigUI   ui;
@@ -132,11 +160,21 @@ public class AltosConfigUI
                }
        }
 
+       boolean is_telemini_v1() {
+               String  product = product_value.getText();
+               return product != null && product.startsWith("TeleMini-v1");
+       }
+
        boolean is_telemini() {
                String  product = product_value.getText();
                return product != null && product.startsWith("TeleMini");
        }
 
+       boolean is_easymini() {
+               String  product = product_value.getText();
+               return product != null && product.startsWith("EasyMini");
+       }
+
        boolean is_telemetrum() {
                String  product = product_value.getText();
                return product != null && product.startsWith("TeleMetrum");
@@ -167,12 +205,10 @@ public class AltosConfigUI
                if (flight_log_max_value.isEnabled())
                        flight_log_max_value.setToolTipText("Size reserved for each flight log (in kB)");
                else {
-                       if (is_telemetrum())
-                               flight_log_max_value.setToolTipText("Cannot set max value with flight logs in memory");
-                       else if (is_telemini())
-                               flight_log_max_value.setToolTipText("TeleMini stores only one flight");
+                       if (is_telemini_v1())
+                               flight_log_max_value.setToolTipText("TeleMini-v1 stores only one flight");
                        else
-                               flight_log_max_value.setToolTipText("Cannot set max flight log value");
+                               flight_log_max_value.setToolTipText("Cannot set max value with flight logs in memory");
                }
        }
 
@@ -189,13 +225,20 @@ public class AltosConfigUI
                else {
                        if (is_telemetrum())
                                pad_orientation_value.setToolTipText("Older TeleMetrum firmware must fly antenna forward");
-                       else if (is_telemini())
-                               pad_orientation_value.setToolTipText("TeleMini doesn't care how it is mounted");
+                       else if (is_telemini() || is_easymini())
+                               pad_orientation_value.setToolTipText("TeleMini and EasyMini don't care how they are mounted");
                        else
                                pad_orientation_value.setToolTipText("Can't select orientation");
                }
        }
 
+       void set_beep_tool_tip() {
+               if (beep_value.isEnabled())
+                       beep_value.setToolTipText("What frequency the beeper will sound at");
+               else
+                       beep_value.setToolTipText("Older firmware could not select beeper frequency");
+       }
+
        /* Build the UI using a grid bag */
        public AltosConfigUI(JFrame in_owner, boolean remote) {
                super (in_owner, "Configure Flight Computer", false);
@@ -296,7 +339,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<String>(main_deploy_values());
                main_deploy_value.setEditable(true);
                main_deploy_value.addItemListener(this);
                pane.add(main_deploy_value, c);
@@ -322,7 +365,7 @@ public class AltosConfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = ir;
                c.ipady = 5;
-               apogee_delay_value = new JComboBox(apogee_delay_values);
+               apogee_delay_value = new JComboBox<String>(apogee_delay_values);
                apogee_delay_value.setEditable(true);
                apogee_delay_value.addItemListener(this);
                pane.add(apogee_delay_value, c);
@@ -348,7 +391,7 @@ public class AltosConfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = ir;
                c.ipady = 5;
-               apogee_lockout_value = new JComboBox(apogee_lockout_values);
+               apogee_lockout_value = new JComboBox<String>(apogee_lockout_values);
                apogee_lockout_value.setEditable(true);
                apogee_lockout_value.addItemListener(this);
                pane.add(apogee_lockout_value, c);
@@ -451,7 +494,7 @@ public class AltosConfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = ir;
                c.ipady = 5;
-               aprs_interval_value = new JComboBox(aprs_interval_values);
+               aprs_interval_value = new JComboBox<String>(aprs_interval_values);
                aprs_interval_value.setEditable(true);
                aprs_interval_value.addItemListener(this);
                pane.add(aprs_interval_value, c);
@@ -491,7 +534,7 @@ public class AltosConfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = il;
                c.ipady = 5;
-               flight_log_max_label = new JLabel("Maximum Flight Log Size:");
+               flight_log_max_label = new JLabel("Maximum Flight Log Size (kB):");
                pane.add(flight_log_max_label, c);
 
                c = new GridBagConstraints();
@@ -502,7 +545,7 @@ public class AltosConfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = ir;
                c.ipady = 5;
-               flight_log_max_value = new JComboBox(flight_log_max_values);
+               flight_log_max_value = new JComboBox<String>();
                flight_log_max_value.setEditable(true);
                flight_log_max_value.addItemListener(this);
                pane.add(flight_log_max_value, c);
@@ -528,7 +571,7 @@ public class AltosConfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = ir;
                c.ipady = 5;
-               ignite_mode_value = new JComboBox(ignite_mode_values);
+               ignite_mode_value = new JComboBox<String>(ignite_mode_values);
                ignite_mode_value.setEditable(false);
                ignite_mode_value.addItemListener(this);
                pane.add(ignite_mode_value, c);
@@ -554,13 +597,90 @@ public class AltosConfigUI
                c.anchor = GridBagConstraints.LINE_START;
                c.insets = ir;
                c.ipady = 5;
-               pad_orientation_value = new JComboBox(pad_orientation_values);
+               pad_orientation_value = new JComboBox<String>(pad_orientation_values);
                pad_orientation_value.setEditable(false);
                pad_orientation_value.addItemListener(this);
                pane.add(pad_orientation_value, c);
                set_pad_orientation_tool_tip();
                row++;
 
+               /* Beeper */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               beep_label = new JLabel("Beeper Frequency:");
+               pane.add(beep_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               beep_value = new JComboBox<String>(beep_values);
+               beep_value.setEditable(true);
+               beep_value.addItemListener(this);
+               pane.add(beep_value, c);
+               set_beep_tool_tip();
+               row++;
+
+               /* Tracker triger horiz distances */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               tracker_motion_label = new JLabel(get_tracker_motion_label());
+               pane.add(tracker_motion_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               tracker_motion_value = new JComboBox<String>(tracker_motion_values());
+               tracker_motion_value.setEditable(true);
+               tracker_motion_value.addItemListener(this);
+               pane.add(tracker_motion_value, c);
+               row++;
+
+               /* Tracker triger vert distances */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               tracker_interval_label = new JLabel("Position Reporting Interval(s):");
+               pane.add(tracker_interval_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               tracker_interval_value = new JComboBox<String>(tracker_interval_values);
+               tracker_interval_value.setEditable(true);
+               tracker_interval_value.addItemListener(this);
+               pane.add(tracker_interval_value, c);
+               set_tracker_tool_tip();
+               row++;
+
                /* Pyro channels */
                c = new GridBagConstraints();
                c.gridx = 4; c.gridy = row;
@@ -673,7 +793,7 @@ public class AltosConfigUI
 
                if (cmd.equals("Pyro")) {
                        if (pyro_ui == null && pyros != null)
-                               pyro_ui = new AltosConfigPyroUI(this, pyros);
+                               pyro_ui = new AltosConfigPyroUI(this, pyros, pyro_firing_time);
                        if (pyro_ui != null)
                                pyro_ui.make_visible();
                        return;
@@ -742,14 +862,14 @@ public class AltosConfigUI
        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)
@@ -758,13 +878,20 @@ public class AltosConfigUI
                        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);
+
+               if (tracker_motion_value.isEnabled()) {
+                       String motion = tracker_motion_value.getSelectedItem().toString();
+                       tracker_motion_label.setText(get_tracker_motion_label());
+                       set_tracker_motion_values();
+                       set_tracker_motion((int) (AltosConvert.height.parse(motion, !imperial_units) + 0.5));
+               }
        }
 
        public void set_apogee_delay(int new_apogee_delay) {
@@ -772,8 +899,19 @@ public class AltosConfigUI
                apogee_delay_value.setEnabled(new_apogee_delay >= 0);
        }
 
-       public int apogee_delay() {
-               return Integer.parseInt(apogee_delay_value.getSelectedItem().toString());
+       private int parse_int(String name, String s, boolean split) throws AltosConfigDataException {
+               String v = s;
+               if (split)
+                       v = s.split("\\s+")[0];
+               try {
+                       return Integer.parseInt(v);
+               } catch (NumberFormatException ne) {
+                       throw new AltosConfigDataException("Invalid %s \"%s\"", name, s);
+               }
+       }
+
+       public int apogee_delay() throws AltosConfigDataException {
+               return parse_int("apogee delay", apogee_delay_value.getSelectedItem().toString(), false);
        }
 
        public void set_apogee_lockout(int new_apogee_lockout) {
@@ -781,8 +919,8 @@ public class AltosConfigUI
                apogee_lockout_value.setEnabled(new_apogee_lockout >= 0);
        }
 
-       public int apogee_lockout() {
-               return Integer.parseInt(apogee_lockout_value.getSelectedItem().toString());
+       public int apogee_lockout() throws AltosConfigDataException {
+               return parse_int("apogee lockout", apogee_lockout_value.getSelectedItem().toString(), false);
        }
 
        public void set_radio_frequency(double new_radio_frequency) {
@@ -801,8 +939,8 @@ public class AltosConfigUI
                        radio_calibration_value.setText(String.format("%d", new_radio_calibration));
        }
 
-       public int radio_calibration() {
-               return Integer.parseInt(radio_calibration_value.getText());
+       public int radio_calibration() throws AltosConfigDataException {
+               return parse_int("radio calibration", radio_calibration_value.getText(), false);
        }
 
        public void set_radio_enable(int new_radio_enable) {
@@ -833,9 +971,22 @@ public class AltosConfigUI
                return callsign_value.getText();
        }
 
+       int     flight_log_max_limit;
+       int     flight_log_max;
+
+       public String flight_log_max_label(int flight_log_max) {
+               if (flight_log_max_limit != 0) {
+                       int     nflight = flight_log_max_limit / flight_log_max;
+                       String  plural = nflight > 1 ? "s" : "";
+
+                       return String.format("%d (%d flight%s)", flight_log_max, nflight, plural);
+               }
+               return String.format("%d", flight_log_max);
+       }
+
        public void set_flight_log_max(int new_flight_log_max) {
-               flight_log_max_value.setEnabled(new_flight_log_max > 0);
-               flight_log_max_value.setSelectedItem(Integer.toString(new_flight_log_max));
+               flight_log_max_value.setSelectedItem(flight_log_max_label(new_flight_log_max));
+               flight_log_max = new_flight_log_max;
                set_flight_log_max_tool_tip();
        }
 
@@ -844,20 +995,19 @@ public class AltosConfigUI
                set_flight_log_max_tool_tip();
        }
 
-       public int flight_log_max() {
-               return Integer.parseInt(flight_log_max_value.getSelectedItem().toString());
+       public int flight_log_max() throws AltosConfigDataException {
+               return parse_int("flight log max", flight_log_max_value.getSelectedItem().toString(), true);
        }
 
-       public void set_flight_log_max_limit(int flight_log_max_limit) {
-               //boolean       any_added = false;
+       public void set_flight_log_max_limit(int new_flight_log_max_limit) {
+               flight_log_max_limit = new_flight_log_max_limit;
                flight_log_max_value.removeAllItems();
-               for (int i = 0; i < flight_log_max_values.length; i++) {
-                       if (Integer.parseInt(flight_log_max_values[i]) < flight_log_max_limit){
-                               flight_log_max_value.addItem(flight_log_max_values[i]);
-                               //any_added = true;
-                       }
+               for (int i = 8; i >= 1; i--) {
+                       int     size = flight_log_max_limit / i;
+                       flight_log_max_value.addItem(String.format("%d (%d flights)", size, i));
                }
-               flight_log_max_value.addItem(String.format("%d", flight_log_max_limit));
+               if (flight_log_max != 0)
+                       set_flight_log_max(flight_log_max);
        }
 
        public void set_ignite_mode(int new_ignite_mode) {
@@ -901,6 +1051,87 @@ public class AltosConfigUI
                        return -1;
        }
 
+       public void set_beep(int new_beep) {
+               int new_freq = (int) Math.floor (AltosConvert.beep_value_to_freq(new_beep) + 0.5);
+               for (int i = 0; i < beep_values.length; i++)
+                       if (new_beep == AltosConvert.beep_freq_to_value(Integer.parseInt(beep_values[i]))) {
+                               beep_value.setSelectedIndex(i);
+                               set_beep_tool_tip();
+                               return;
+                       }
+               beep_value.setSelectedItem(String.format("%d", new_freq));
+               beep_value.setEnabled(new_beep >= 0);
+               set_beep_tool_tip();
+       }
+
+       public int beep() {
+               if (beep_value.isEnabled())
+                       return AltosConvert.beep_freq_to_value(Integer.parseInt(beep_value.getSelectedItem().toString()));
+               else
+                       return -1;
+       }
+
+       String[] tracker_motion_values() {
+               if (AltosConvert.imperial_units)
+                       return tracker_motion_values_ft;
+               else
+                       return tracker_motion_values_m;
+       }
+
+       void set_tracker_motion_values() {
+               String[]        v = tracker_motion_values();
+               while (tracker_motion_value.getItemCount() > 0)
+                       tracker_motion_value.removeItemAt(0);
+               for (int i = 0; i < v.length; i++)
+                       tracker_motion_value.addItem(v[i]);
+               tracker_motion_value.setMaximumRowCount(v.length);
+       }
+
+       String get_tracker_motion_label() {
+               return String.format("Logging Trigger Motion (%s):", AltosConvert.height.show_units());
+       }
+
+       void set_tracker_tool_tip() {
+               if (tracker_motion_value.isEnabled())
+                       tracker_motion_value.setToolTipText("How far the device must move before logging");
+               else
+                       tracker_motion_value.setToolTipText("This device doesn't disable logging when stationary");
+               if (tracker_interval_value.isEnabled())
+                       tracker_interval_value.setToolTipText("How often to report GPS position");
+               else
+                       tracker_interval_value.setToolTipText("This device can't configure interval");
+       }
+
+       public void set_tracker_motion(int tracker_motion) {
+               if (tracker_motion < 0) {
+                       tracker_motion_label.setVisible(false);
+                       tracker_motion_value.setVisible(false);
+               } else {
+                       tracker_motion_label.setVisible(true);
+                       tracker_motion_value.setVisible(true);
+                       tracker_motion_value.setSelectedItem(AltosConvert.height.say(tracker_motion));
+               }
+       }
+
+       public int tracker_motion() throws AltosConfigDataException {
+               return (int) AltosConvert.height.parse(tracker_motion_value.getSelectedItem().toString());
+       }
+
+       public void set_tracker_interval(int tracker_interval) {
+               if (tracker_interval< 0) {
+                       tracker_interval_label.setVisible(false);
+                       tracker_interval_value.setVisible(false);
+               } else {
+                       tracker_interval_label.setVisible(true);
+                       tracker_interval_value.setVisible(true);
+                       tracker_interval_value.setSelectedItem(String.format("%d", tracker_interval));
+               }
+       }
+
+       public int tracker_interval() throws AltosConfigDataException {
+               return parse_int ("tracker interval", tracker_interval_value.getSelectedItem().toString(), false);
+       }
+
        public void set_pyros(AltosPyro[] new_pyros) {
                pyros = new_pyros;
                pyro.setVisible(pyros != null);
@@ -908,12 +1139,25 @@ public class AltosConfigUI
                        pyro_ui.set_pyros(pyros);
        }
 
-       public AltosPyro[] pyros() {
+       public AltosPyro[] pyros() throws AltosConfigDataException {
                if (pyro_ui != null)
                        pyros = pyro_ui.get_pyros();
                return pyros;
        }
 
+       public void set_pyro_firing_time(double new_pyro_firing_time) {
+               pyro_firing_time = new_pyro_firing_time;
+               pyro.setVisible(pyro_firing_time >= 0);
+               if (pyro_firing_time >= 0 && pyro_ui != null)
+                       pyro_ui.set_pyro_firing_time(pyro_firing_time);
+       }
+
+       public double pyro_firing_time() throws AltosConfigDataException {
+               if (pyro_ui != null)
+                       pyro_firing_time = pyro_ui.get_pyro_firing_time();
+               return pyro_firing_time;
+       }
+
        public void set_aprs_interval(int new_aprs_interval) {
                String  s;
 
@@ -926,11 +1170,11 @@ public class AltosConfigUI
                set_aprs_interval_tool_tip();
        }
 
-       public int aprs_interval() {
+       public int aprs_interval() throws AltosConfigDataException {
                String  s = aprs_interval_value.getSelectedItem().toString();
 
                if (s.equals("Disabled"))
                        return 0;
-               return Integer.parseInt(s);
+               return parse_int("aprs interval", s, false);
        }
 }
index 5e42f43055ec55d9b13dabe3044f789d04693785..e61a4a5b191200115596d4c10c5b8090aa86cf84 100644 (file)
@@ -22,7 +22,7 @@ import java.awt.event.*;
 import java.beans.*;
 import javax.swing.*;
 import javax.swing.event.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class AltosConfigureUI
        extends AltosUIConfigure
@@ -31,7 +31,7 @@ public class AltosConfigureUI
        AltosVoice      voice;
 
        public JTextField       callsign_value;
-       public JComboBox        position_value;
+       public JComboBox<String>        position_value;
 
        /* DocumentListener interface methods */
        public void insertUpdate(DocumentEvent e) {
@@ -123,11 +123,11 @@ public class AltosConfigureUI
                "Bottom",
                "Bottom right",
        };
-               
+
        public void add_position() {
                pane.add(new JLabel ("Menu position"), constraints(0, 1));
-               
-               position_value = new JComboBox (position_names);
+
+               position_value = new JComboBox<String>(position_names);
                position_value.setMaximumRowCount(position_names.length);
                int position = AltosUIPreferences.position();
                position_value.setSelectedIndex(position);
diff --git a/altosui/AltosDataChooser.java b/altosui/AltosDataChooser.java
deleted file mode 100644 (file)
index a9344a0..0000000
+++ /dev/null
@@ -1,83 +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 javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import java.io.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosDataChooser extends JFileChooser {
-       JFrame  frame;
-       String  filename;
-       File    file;
-
-       public String filename() {
-               return filename;
-       }
-
-       public File file() {
-               return file;
-       }
-
-       public AltosStateIterable runDialog() {
-               int     ret;
-
-               ret = showOpenDialog(frame);
-               if (ret == APPROVE_OPTION) {
-                       file = getSelectedFile();
-                       if (file == null)
-                               return null;
-                       filename = file.getName();
-                       try {
-                               if (filename.endsWith("eeprom")) {
-                                       FileInputStream in = new FileInputStream(file);
-                                       return new AltosEepromFile(in);
-                               } else if (filename.endsWith("telem")) {
-                                       FileInputStream in = new FileInputStream(file);
-                                       return new AltosTelemetryFile(in);
-                               } else {
-                                       throw new FileNotFoundException();
-                               }
-                       } catch (FileNotFoundException fe) {
-                               JOptionPane.showMessageDialog(frame,
-                                                             fe.getMessage(),
-                                                             "Cannot open file",
-                                                             JOptionPane.ERROR_MESSAGE);
-                       }
-               }
-               return null;
-       }
-
-       public AltosDataChooser(JFrame in_frame) {
-               frame = in_frame;
-               setDialogTitle("Select Flight Record File");
-               setFileFilter(new FileNameExtensionFilter("TeleMetrum eeprom file",
-                                                         "eeprom"));
-               setFileFilter(new FileNameExtensionFilter("Telemetry file",
-                                                         "telem"));
-               setFileFilter(new FileNameExtensionFilter("TeleMega eeprom file",
-                                                         "mega"));
-               setFileFilter(new FileNameExtensionFilter("EasyMini eeprom file",
-                                                         "mini"));
-               setFileFilter(new FileNameExtensionFilter("Flight data file",
-                                                         "telem", "eeprom", "mega", "mini"));
-               setCurrentDirectory(AltosUIPreferences.logdir());
-       }
-}
index d1379083feed0d11f9e5bb18ac17612bcb762b79..36fc16138c2b81c4c285eb842d4e32c571707c65 100644 (file)
 
 package altosui;
 
+import java.util.*;
 import java.awt.*;
+import java.awt.event.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
-public class AltosDescent extends JComponent implements AltosFlightDisplay {
-       GridBagLayout   layout;
+public class AltosDescent extends AltosUIFlightTab {
 
-       public abstract class DescentStatus {
-               JLabel          label;
-               JTextField      value;
-               AltosLights     lights;
-
-               abstract void show(AltosState state, AltosListenerState listener_state);
-
-               void show() {
-                       label.setVisible(true);
-                       value.setVisible(true);
-                       lights.setVisible(true);
-               }
-
-               void show(String s) {
-                       show();
-                       value.setText(s);
-               }
-
-               void show(String format, double value) {
-                       show(String.format(format, value));
-               }
-
-               void hide() {
-                       label.setVisible(false);
-                       value.setVisible(false);
-                       lights.setVisible(false);
-               }
-
-               void reset() {
-                       value.setText("");
-                       lights.set(false);
-               }
-
-               void set_font() {
-                       label.setFont(Altos.label_font);
-                       value.setFont(Altos.value_font);
-               }
-
-               public DescentStatus (GridBagLayout layout, int y, String text) {
-                       GridBagConstraints      c = new GridBagConstraints();
-                       c.weighty = 1;
-
-                       lights = new AltosLights();
-                       c.gridx = 0; c.gridy = y;
-                       c.anchor = GridBagConstraints.CENTER;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       layout.setConstraints(lights, c);
-                       add(lights);
-
-                       label = new JLabel(text);
-                       label.setFont(Altos.label_font);
-                       label.setHorizontalAlignment(SwingConstants.LEFT);
-                       c.gridx = 1; c.gridy = y;
-                       c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.gridwidth = 3;
-                       c.weightx = 0;
-                       layout.setConstraints(label, c);
-                       add(label);
-
-                       value = new JTextField(Altos.text_width);
-                       value.setFont(Altos.value_font);
-                       value.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = 4; c.gridy = y;
-                       c.gridwidth = 1;
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.BOTH;
-                       c.weightx = 1;
-                       layout.setConstraints(value, c);
-                       add(value);
+       class Height extends AltosUIUnitsIndicator {
+               public double value(AltosState state, int i) { return state.height(); }
 
+               public Height (Container container, int x, int y) {
+                       super (container, x, y, AltosConvert.height, "Height");
                }
        }
 
-       public abstract class DescentValue {
-               JLabel          label;
-               JTextField      value;
-
-               void reset() {
-                       value.setText("");
-               }
-
-               abstract void show(AltosState state, AltosListenerState listener_state);
-
-               void show() {
-                       label.setVisible(true);
-                       value.setVisible(true);
-               }
-
-               void hide() {
-                       label.setVisible(false);
-                       value.setVisible(false);
-               }
+       class Speed extends AltosUIUnitsIndicator {
+               public double value(AltosState state, int i) { return state.speed(); }
 
-               void show(String v) {
-                       show();
-                       value.setText(v);
-               }
-
-               void show(AltosUnits units, double v) {
-                       show(units.show(8, v));
-               }
-
-               void show(String format, double v) {
-                       show(String.format(format, v));
-               }
-
-               void set_font() {
-                       label.setFont(Altos.label_font);
-                       value.setFont(Altos.value_font);
-               }
-
-               public DescentValue (GridBagLayout layout, int x, int y, String text) {
-                       GridBagConstraints      c = new GridBagConstraints();
-                       c.weighty = 1;
-
-                       label = new JLabel(text);
-                       label.setFont(Altos.label_font);
-                       label.setHorizontalAlignment(SwingConstants.LEFT);
-                       c.gridx = x + 1; c.gridy = y;
-                       c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       add(label, c);
-
-                       value = new JTextField(Altos.text_width);
-                       value.setFont(Altos.value_font);
-                       value.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = x + 2; c.gridy = y;
-                       c.gridwidth = 1;
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.BOTH;
-                       c.weightx = 1;
-                       add(value, c);
+               public Speed (Container container, int x, int y) {
+                       super (container, x, y, AltosConvert.speed, "Speed");
                }
        }
 
-       public abstract class DescentDualValue {
-               JLabel          label;
-               JTextField      value1;
-               JTextField      value2;
-
-               void reset() {
-                       value1.setText("");
-                       value2.setText("");
-               }
-
-               void show() {
-                       label.setVisible(true);
-                       value1.setVisible(true);
-                       value2.setVisible(true);
-               }
-
-               void hide() {
-                       label.setVisible(false);
-                       value1.setVisible(false);
-                       value2.setVisible(false);
-               }
-
-               void set_font() {
-                       label.setFont(Altos.label_font);
-                       value1.setFont(Altos.value_font);
-                       value2.setFont(Altos.value_font);
-               }
-
-               abstract void show(AltosState state, AltosListenerState listener_state);
-
-               void show(String v1, String v2) {
-                       show();
-                       value1.setText(v1);
-                       value2.setText(v2);
-               }
-               void show(String f1, double v1, String f2, double v2) {
-                       show();
-                       value1.setText(String.format(f1, v1));
-                       value2.setText(String.format(f2, v2));
-               }
-
-               public DescentDualValue (GridBagLayout layout, int x, int y, String text) {
-                       GridBagConstraints      c = new GridBagConstraints();
-                       c.weighty = 1;
-
-                       label = new JLabel(text);
-                       label.setFont(Altos.label_font);
-                       label.setHorizontalAlignment(SwingConstants.LEFT);
-                       c.gridx = x + 1; c.gridy = y;
-                       c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       layout.setConstraints(label, c);
-                       add(label);
+       class Lat extends AltosUIUnitsIndicator {
 
-                       value1 = new JTextField(Altos.text_width);
-                       value1.setFont(Altos.value_font);
-                       value1.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = x + 2; c.gridy = y;
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.BOTH;
-                       c.weightx = 1;
-                       layout.setConstraints(value1, c);
-                       add(value1);
+               public boolean hide (AltosState state, int i) { return state.gps == null || !state.gps.connected; }
 
-                       value2 = new JTextField(Altos.text_width);
-                       value2.setFont(Altos.value_font);
-                       value2.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = x + 4; c.gridy = y;
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.BOTH;
-                       c.weightx = 1;
-                       c.gridwidth = 1;
-                       layout.setConstraints(value2, c);
-                       add(value2);
+               public double value(AltosState state, int i) {
+                       if (state.gps == null)
+                               return AltosLib.MISSING;
+                       if (!state.gps.connected)
+                               return AltosLib.MISSING;
+                       return state.gps.lat;
                }
-       }
 
-       class Height extends DescentValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.height, state.height());
-               }
-               public Height (GridBagLayout layout, int x, int y) {
-                       super (layout, x, y, "Height");
+               public Lat (Container container, int x, int y) {
+                       super (container, x, y, AltosConvert.latitude, "Latitude");
                }
        }
 
-       Height  height;
+       class Lon extends AltosUIUnitsIndicator {
+               public boolean hide (AltosState state, int i) { return state.gps == null || !state.gps.connected; }
 
-       class Speed extends DescentValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.speed, state.speed());
-               }
-               public Speed (GridBagLayout layout, int x, int y) {
-                       super (layout, x, y, "Speed");
+               public double value(AltosState state, int i) {
+                       if (state.gps == null)
+                               return AltosLib.MISSING;
+                       if (!state.gps.connected)
+                               return AltosLib.MISSING;
+                       return state.gps.lon;
                }
-       }
-
-       Speed   speed;
 
-       String pos(double p, String pos, String neg) {
-               String  h = pos;
-               if (p < 0) {
-                       h = neg;
-                       p = -p;
+               public Lon (Container container, int x, int y) {
+                       super (container, x, y, AltosConvert.longitude, "Longitude");
                }
-               int deg = (int) Math.floor(p);
-               double min = (p - Math.floor(p)) * 60.0;
-               return String.format("%s %d° %9.6f", h, deg, min);
        }
 
-       class Lat extends DescentValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
-                               show(pos(state.gps.lat,"N", "S"));
-                       else
-                               show("???");
-               }
-               public Lat (GridBagLayout layout, int x, int y) {
-                       super (layout, x, y, "Latitude");
+       class Apogee extends AltosUIUnitsIndicator {
+               public boolean hide(double v) { return v == AltosLib.MISSING; }
+               public double value(AltosState state, int i) { return state.apogee_voltage; }
+               public double good() { return AltosLib.ao_igniter_good; }
+
+               public Apogee (Container container, int y) {
+                       super(container, 0, y, 3, AltosConvert.voltage, "Apogee Igniter Voltage", 1, true, 3);
                }
        }
 
-       Lat lat;
+       class Main extends AltosUIUnitsIndicator {
+               public boolean hide(double v) { return v == AltosLib.MISSING; }
+               public double value(AltosState state, int i) { return state.main_voltage; }
+               public double good() { return AltosLib.ao_igniter_good; }
 
-       class Lon extends DescentValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
-                               show(pos(state.gps.lon,"W", "E"));
-                       else
-                               show("???");
-               }
-               public Lon (GridBagLayout layout, int x, int y) {
-                       super (layout, x, y, "Longitude");
+               public Main (Container container, int y) {
+                       super(container, 0, y, 3, AltosConvert.voltage, "Main Igniter Voltage", 1, true, 3);
                }
        }
 
-       Lon lon;
-
-       class Distance extends DescentValue {
-               void show(AltosState state, AltosListenerState listener_state) {
+       class Distance extends AltosUIUnitsIndicator {
+               public double value(AltosState state, int i) {
                        if (state.from_pad != null)
-                               show(AltosConvert.distance, state.from_pad.distance);
+                               return state.from_pad.distance;
                        else
-                               show("???");
-               }
-
-               public Distance (GridBagLayout layout, int x, int y) {
-                       super(layout, x, y, "Ground Distance");
+                               return AltosLib.MISSING;
                }
-       }
-
-       Distance distance;
-               
 
-       class Apogee extends DescentStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       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");
+               public Distance(Container container, int x, int y) {
+                       super(container, x, y, AltosConvert.distance, "Ground Distance");
                }
        }
 
-       Apogee apogee;
-
-       class Main extends DescentStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show("%4.2f V", state.main_voltage);
-                       lights.set(state.main_voltage >= AltosLib.ao_igniter_good);
+       class Range extends AltosUIUnitsIndicator {
+               public double value(AltosState state, int i) {
+                       return state.range;
                }
-               public Main (GridBagLayout layout, int y) {
-                       super(layout, y, "Main Igniter Voltage");
+               public Range (Container container, int x, int y) {
+                       super (container, x, y, AltosConvert.distance, "Range");
                }
        }
 
-       Main main;
-
-       class Bearing extends DescentDualValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       if (state.from_pad != null) {
+       class Bearing extends AltosUIIndicator {
+               public void show (AltosState state, AltosListenerState listener_state) {
+                       if (state.from_pad != null && state.from_pad.bearing != AltosLib.MISSING) {
                                show( String.format("%3.0f°", state.from_pad.bearing),
                                      state.from_pad.bearing_words(
                                              AltosGreatCircle.BEARING_LONG));
                        } else {
-                               show("???", "???");
+                               show("Missing", "Missing");
                        }
                }
-               public Bearing (GridBagLayout layout, int x, int y) {
-                       super (layout, x, y, "Bearing");
+               public Bearing (Container container, int x, int y) {
+                       super (container, x, y, 1, "Bearing", 2, false, 1, 2);
                }
        }
 
-       Bearing bearing;
-
-       class Range extends DescentValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.distance, state.range);
-               }
-               public Range (GridBagLayout layout, int x, int y) {
-                       super (layout, x, y, "Range");
-               }
-       }
-
-       Range range;
-
-       class Elevation extends DescentValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show("%3.0f°", state.elevation);
+       class Elevation extends AltosUIIndicator {
+               public void show (AltosState state, AltosListenerState listener_state) {
+                       if (state.elevation == AltosLib.MISSING)
+                               show("Missing");
+                       else
+                               show("%3.0f°", state.elevation);
                }
-               public Elevation (GridBagLayout layout, int x, int y) {
-                       super (layout, x, y, "Elevation");
+               public Elevation (Container container, int x, int y) {
+                       super (container, x, y, "Elevation", 1, false, 1);
                }
        }
 
-       Elevation elevation;
-
-       public void reset() {
-               lat.reset();
-               lon.reset();
-               height.reset();
-               speed.reset();
-               bearing.reset();
-               range.reset();
-               distance.reset();
-               elevation.reset();
-               main.reset();
-               apogee.reset();
-       }
-
-       public void set_font() {
-               lat.set_font();
-               lon.set_font();
-               height.set_font();
-               speed.set_font();
-               bearing.set_font();
-               range.set_font();
-               distance.set_font();
-               elevation.set_font();
-               main.set_font();
-               apogee.set_font();
-       }
-
-       public void show(AltosState state, AltosListenerState listener_state) {
-               height.show(state, listener_state);
-               speed.show(state, listener_state);
-               if (state.gps != null && state.gps.connected) {
-                       bearing.show(state, listener_state);
-                       range.show(state, listener_state);
-                       distance.show(state, listener_state);
-                       elevation.show(state, listener_state);
-                       lat.show(state, listener_state);
-                       lon.show(state, listener_state);
-               } else {
-                       bearing.hide();
-                       range.hide();
-                       distance.hide();
-                       elevation.hide();
-                       lat.hide();
-                       lon.hide();
-               }
-               if (state.main_voltage != AltosLib.MISSING)
-                       main.show(state, listener_state);
-               else
-                       main.hide();
-               if (state.apogee_voltage != AltosLib.MISSING)
-                       apogee.show(state, listener_state);
-               else
-                       apogee.hide();
-       }
-
        public String getName() {
                return "Descent";
        }
 
        public AltosDescent() {
-               layout = new GridBagLayout();
-
-               setLayout(layout);
-
                /* Elements in descent display */
-               speed = new Speed(layout, 0, 0);
-               height = new Height(layout, 2, 0);
-               elevation = new Elevation(layout, 0, 1);
-               range = new Range(layout, 2, 1);
-               bearing = new Bearing(layout, 0, 2);
-               distance = new Distance(layout, 0, 3);
-               lat = new Lat(layout, 0, 4);
-               lon = new Lon(layout, 2, 4);
-
-               apogee = new Apogee(layout, 5);
-               main = new Main(layout, 6);
+               add(new Speed(this, 0, 0));
+               add(new Height(this, 2, 0));
+               add(new Elevation(this, 0, 1));
+               add(new Range(this, 2, 1));
+               add(new Bearing(this, 0, 2));
+               add(new Distance(this, 0, 3));
+               add(new Lat(this, 0, 4));
+               add(new Lon(this, 2, 4));
+               add(new Apogee(this, 5));
+               add(new Main(this, 6));
        }
 }
diff --git a/altosui/AltosDeviceUIDialog.java b/altosui/AltosDeviceUIDialog.java
deleted file mode 100644 (file)
index ceabe84..0000000
+++ /dev/null
@@ -1,70 +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 javax.swing.*;
-import java.awt.*;
-import java.awt.event.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosDeviceUIDialog extends AltosDeviceDialog {
-
-       public AltosDevice[] devices() {
-               java.util.List<AltosDevice>     usb_devices = AltosUSBDevice.list(product);
-               int                             num_devices = usb_devices.size();
-               java.util.List<AltosDevice>     bt_devices = AltosBTKnown.bt_known().list(product);
-               num_devices += bt_devices.size();
-               AltosDevice[]                   devices = new AltosDevice[num_devices];
-
-               for (int i = 0; i < usb_devices.size(); i++)
-                       devices[i] = usb_devices.get(i);
-               int off = usb_devices.size();
-               for (int j = 0; j < bt_devices.size(); j++)
-                       devices[off + j] = bt_devices.get(j);
-               return devices;
-       }
-
-       public void add_bluetooth() {
-               JButton manage_bluetooth_button = new JButton("Manage Bluetooth");
-               manage_bluetooth_button.setActionCommand("manage");
-               manage_bluetooth_button.addActionListener(this);
-               buttonPane.add(manage_bluetooth_button);
-               buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
-       }
-       
-       public void actionPerformed(ActionEvent e) {
-               super.actionPerformed(e);
-               if ("manage".equals(e.getActionCommand())) {
-                       AltosBTManage.show(frame, AltosBTKnown.bt_known());
-                       update_devices();
-               }
-       }
-
-       public AltosDeviceUIDialog (Frame in_frame, Component location, int in_product) {
-               super(in_frame, location, in_product);
-       }
-
-       public static AltosDevice show (Component frameComp, int product) {
-               Frame                   frame = JOptionPane.getFrameForComponent(frameComp);
-               AltosDeviceUIDialog     dialog;
-
-               dialog = new AltosDeviceUIDialog(frame, frameComp, product);
-               dialog.setVisible(true);
-               return dialog.getValue();
-       }
-}
diff --git a/altosui/AltosDisplayThread.java b/altosui/AltosDisplayThread.java
deleted file mode 100644 (file)
index 2a33f99..0000000
+++ /dev/null
@@ -1,259 +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.*;
-import javax.swing.*;
-import java.io.*;
-import java.text.*;
-import org.altusmetrum.altoslib_3.*;
-
-public class AltosDisplayThread extends Thread {
-
-       Frame                   parent;
-       IdleThread              idle_thread;
-       AltosVoice              voice;
-       AltosFlightReader       reader;
-       AltosState              old_state, state;
-       AltosListenerState      listener_state;
-       AltosFlightDisplay      display;
-
-       synchronized void show_safely() {
-               final AltosState my_state = state;
-               final AltosListenerState my_listener_state = listener_state;
-               Runnable r = new Runnable() {
-                               public void run() {
-                                       try {
-                                               display.show(my_state, my_listener_state);
-                                       } catch (Exception ex) {
-                                       }
-                               }
-                       };
-               SwingUtilities.invokeLater(r);
-       }
-
-       void reading_error_internal() {
-               JOptionPane.showMessageDialog(parent,
-                                             String.format("Error reading from \"%s\"", reader.name),
-                                             "Telemetry Read Error",
-                                             JOptionPane.ERROR_MESSAGE);
-       }
-
-       void reading_error_safely() {
-               Runnable r = new Runnable() {
-                               public void run() {
-                                       try {
-                                               reading_error_internal();
-                                       } catch (Exception ex) {
-                                       }
-                               }
-                       };
-               SwingUtilities.invokeLater(r);
-       }
-
-       class IdleThread extends Thread {
-
-               boolean started;
-               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 < Altos.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 (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()),
-                                           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()));
-                       } 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 >= Altos.ao_flight_drogue &&
-                           (last ||
-                            System.currentTimeMillis() - state.received_time >= 15000 ||
-                            state.state == Altos.ao_flight_landed))
-                       {
-                               if (Math.abs(state.speed()) < 20 && state.height() < 100)
-                                       voice.speak("rocket landed safely");
-                               else
-                                       voice.speak("rocket may have crashed");
-                               if (state.from_pad != null)
-                                       voice.speak("Bearing %d degrees, range %s.",
-                                                   (int) (state.from_pad.bearing + 0.5),
-                                                   AltosConvert.distance.say_units(state.from_pad.distance));
-                               ++reported_landing;
-                               if (state.state != Altos.ao_flight_landed) {
-                                       state.state = Altos.ao_flight_landed;
-                                       show_safely();
-                               }
-                       }
-               }
-
-               long now () {
-                       return System.currentTimeMillis();
-               }
-
-               void set_report_time() {
-                       report_time = now() + report_interval;
-               }
-
-               public void run () {
-                       try {
-                               for (;;) {
-                                       if (reader.has_monitor_battery()) {
-                                               listener_state.battery = reader.monitor_battery();
-                                               show_safely();
-                                       }
-                                       set_report_time();
-                                       for (;;) {
-                                               voice.drain();
-                                               synchronized (this) {
-                                                       long    sleep_time = report_time - now();
-                                                       if (sleep_time <= 0)
-                                                               break;
-                                                       wait(sleep_time);
-                                               }
-                                       }
-                                       
-                                       report(false);
-                               }
-                       } catch (InterruptedException ie) {
-                               try {
-                                       voice.drain();
-                               } catch (InterruptedException iie) { }
-                       }
-               }
-
-               public synchronized void notice(boolean spoken) {
-                       if (old_state != null && old_state.state != state.state) {
-                               report_time = now();
-                               this.notify();
-                       } else if (spoken)
-                               set_report_time();
-               }
-
-               public IdleThread() {
-                       reported_landing = 0;
-                       report_interval = 10000;
-               }
-       }
-
-       synchronized boolean tell() {
-               boolean ret = false;
-               if (old_state == null || old_state.state != state.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_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));
-                               ret = true;
-                       }
-               }
-               if (old_state == null || old_state.gps_ready != state.gps_ready) {
-                       if (state.gps_ready) {
-                               voice.speak("GPS ready");
-                               ret = true;
-                       }
-                       else if (old_state != null) {
-                               voice.speak("GPS lost");
-                               ret = true;
-                       }
-               }
-               old_state = state;
-               return ret;
-       }
-
-       public void run() {
-               boolean         interrupted = false;
-               boolean         told;
-
-               idle_thread = new IdleThread();
-               idle_thread.start();
-
-               try {
-                       for (;;) {
-                               try {
-                                       state = reader.read();
-                                       if (state == null)
-                                               break;
-                                       reader.update(state);
-                                       show_safely();
-                                       told = tell();
-                                       idle_thread.notice(told);
-                               } catch (ParseException pp) {
-                                       System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage());
-                               } catch (AltosCRCException ce) {
-                                       ++listener_state.crc_errors;
-                                       show_safely();
-                               }
-                       }
-               } catch (InterruptedException ee) {
-                       interrupted = true;
-               } catch (IOException ie) {
-                       reading_error_safely();
-               } finally {
-                       if (!interrupted)
-                               idle_thread.report(true);
-                       reader.close(interrupted);
-                       idle_thread.interrupt();
-                       try {
-                               idle_thread.join();
-                       } catch (InterruptedException ie) {}
-               }
-       }
-
-       public AltosDisplayThread(Frame in_parent, AltosVoice in_voice, AltosFlightDisplay in_display, AltosFlightReader in_reader) {
-               listener_state = new AltosListenerState();
-               parent = in_parent;
-               voice = in_voice;
-               display = in_display;
-               reader = in_reader;
-               display.reset();
-       }
-}
diff --git a/altosui/AltosEepromDelete.java b/altosui/AltosEepromDelete.java
deleted file mode 100644 (file)
index b2d2e29..0000000
+++ /dev/null
@@ -1,143 +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.awt.event.*;
-import javax.swing.*;
-import java.io.*;
-import java.util.concurrent.*;
-import org.altusmetrum.altoslib_3.*;
-
-public class AltosEepromDelete implements Runnable {
-       AltosEepromList         flights;
-       Thread                  eeprom_thread;
-       AltosSerial             serial_line;
-       boolean                 remote;
-       JFrame                  frame;
-       ActionListener          listener;
-       boolean                 success;
-
-       private void DeleteLog (AltosEepromLog log)
-               throws IOException, InterruptedException, TimeoutException {
-
-               if (flights.config_data.flight_log_max != 0 || flights.config_data.log_format != 0) {
-
-                       /* Devices with newer firmware can erase the
-                        * flash blocks containing each flight
-                        */
-                       serial_line.flush_input();
-                       serial_line.printf("d %d\n", log.flight);
-                       for (;;) {
-                               /* It can take a while to erase the flash... */
-                               String line = serial_line.get_reply(20000);
-                               if (line == null)
-                                       throw new TimeoutException();
-                               if (line.equals("Erased"))
-                                       break;
-                               if (line.startsWith("No such"))
-                                       throw new IOException(line);
-                       }
-               }
-       }
-
-       private void show_error_internal(String message, String title) {
-               JOptionPane.showMessageDialog(frame,
-                                             message,
-                                             title,
-                                             JOptionPane.ERROR_MESSAGE);
-       }
-
-       private void show_error(String in_message, String in_title) {
-               final String message = in_message;
-               final String title = in_title;
-               Runnable r = new Runnable() {
-                               public void run() {
-                                       try {
-                                               show_error_internal(message, title);
-                                       } catch (Exception ex) {
-                                       }
-                               }
-                       };
-               SwingUtilities.invokeLater(r);
-       }
-
-       public void run () {
-               success = false;
-               try {
-                       if (remote)
-                               serial_line.start_remote();
-
-                       for (AltosEepromLog log : flights) {
-                               if (log.selected) {
-                                       DeleteLog(log);
-                               }
-                       }
-                       success = true;
-               } catch (IOException ee) {
-                       show_error (ee.getLocalizedMessage(),
-                                   serial_line.device.toShortString());
-               } catch (InterruptedException ie) {
-               } catch (TimeoutException te) {
-                       show_error (String.format("Connection to \"%s\" failed",
-                                                 serial_line.device.toShortString()),
-                                   "Connection Failed");
-               } finally {
-                       try {
-                               if (remote)
-                                       serial_line.stop_remote();
-                       } catch (InterruptedException ie) {
-                       } finally {
-                               serial_line.flush_output();
-                               serial_line.close();
-                       }
-               }
-               if (listener != null) {
-                       Runnable r = new Runnable() {
-                                       public void run() {
-                                               try {
-                                                       listener.actionPerformed(new ActionEvent(this,
-                                                                                                success ? 1 : 0,
-                                                                                                "delete"));
-                                               } 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 AltosEepromDelete(JFrame given_frame,
-                                AltosSerial given_serial_line,
-                                boolean given_remote,
-                                AltosEepromList given_flights) {
-               frame = given_frame;
-               serial_line = given_serial_line;
-               remote = given_remote;
-               flights = given_flights;
-               success = false;
-       }
-}
\ No newline at end of file
diff --git a/altosui/AltosEepromManage.java b/altosui/AltosEepromManage.java
deleted file mode 100644 (file)
index e363557..0000000
+++ /dev/null
@@ -1,242 +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.awt.event.*;
-import javax.swing.*;
-import java.io.*;
-import java.util.concurrent.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosEepromManage implements ActionListener {
-
-       JFrame                  frame;
-       boolean                 remote;
-       AltosDevice             device;
-       AltosSerial             serial_line;
-       AltosEepromList         flights;
-       AltosEepromDownload     download;
-       AltosEepromDelete       delete;
-
-       public void finish() {
-               if (serial_line != null) {
-                       try {
-                               serial_line.flush_input();
-                       } catch (InterruptedException ie) {
-                       }
-                       serial_line.close();
-                       serial_line = null;
-               }
-       }
-
-       private int countDeletedFlights() {
-               int count = 0;
-               for (AltosEepromLog flight : flights) {
-                       if (flight.selected)
-                               count++;
-               }
-               return count;
-       }
-
-       private String showDeletedFlights() {
-               String  result = "";
-
-               for (AltosEepromLog flight : flights) {
-                       if (flight.selected) {
-                               if (result.equals(""))
-                                       result = String.format("%d", flight.flight);
-                               else
-                                       result = String.format("%s, %d", result, flight.flight);
-                       }
-               }
-               return result;
-       }
-
-       public boolean download_done() {
-               AltosEepromSelect       select = new AltosEepromSelect(frame, flights, "Delete");
-
-               if (select.run()) {
-                       boolean any_selected = false;
-                       for (AltosEepromLog flight : flights)
-                               any_selected = any_selected || flight.selected;
-                       if (any_selected) {
-                               delete = new AltosEepromDelete(frame,
-                                                              serial_line,
-                                                              remote,
-                                                              flights);
-                               delete.addActionListener(this);
-                               /*
-                                * Start flight log delete
-                                */
-
-                               delete.start();
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       public void actionPerformed(ActionEvent e) {
-               String  cmd = e.getActionCommand();
-               boolean success = e.getID() != 0;
-               boolean running = false;
-
-               if (cmd.equals("download")) {
-                       if (success)
-                               running = download_done();
-               } else if (cmd.equals("delete")) {
-                       if (success) {
-                               JOptionPane.showMessageDialog(frame,
-                                                             String.format("%d flights erased: %s",
-                                                                           countDeletedFlights(),
-                                                                           showDeletedFlights()),
-                                                             serial_line.device.toShortString(),
-                                                             JOptionPane.INFORMATION_MESSAGE);
-                       }
-               }
-               if (!running)
-                       finish();
-       }
-
-       public void got_flights(AltosEepromList in_flights) {
-               boolean running = false;;
-
-               flights = in_flights;
-               try {
-                       if (flights.size() == 0) {
-                               JOptionPane.showMessageDialog(frame,
-                                                             String.format("No flights available on %d",
-                                                                           device.getSerial()),
-                                                             serial_line.device.toShortString(),
-                                                             JOptionPane.INFORMATION_MESSAGE);
-                       } else {
-                               AltosEepromSelect       select = new AltosEepromSelect(frame, flights, "Download");
-
-                               if (select.run()) {
-                                       boolean any_selected = false;
-                                       for (AltosEepromLog flight : flights)
-                                               any_selected = any_selected || flight.selected;
-                                       if (any_selected) {
-                                               AltosEepromMonitorUI monitor = new AltosEepromMonitorUI(frame);
-                                               monitor.addActionListener(this);
-                                               serial_line.set_frame(frame);
-                                               download = new AltosEepromDownload(monitor,
-                                                                                  serial_line,
-                                                                                  remote,
-                                                                                  flights);
-                                               /*
-                                                * Start flight log download
-                                                */
-
-                                               download.start();
-                                               running = true;
-                                       } else {
-                                               running = download_done();
-                                       }
-                               }
-                       }
-                       if (!running)
-                               finish();
-               } catch (Exception e) {
-                       got_exception(e);
-               }
-       }
-
-       public void got_exception(Exception e) {
-               if (e instanceof IOException) {
-                       IOException     ee = (IOException) e;
-                       JOptionPane.showMessageDialog(frame,
-                                                     device.toShortString(),
-                                                     ee.getLocalizedMessage(),
-                                                     JOptionPane.ERROR_MESSAGE);
-               } else if (e instanceof TimeoutException) {
-                       //TimeoutException te = (TimeoutException) e;
-                       JOptionPane.showMessageDialog(frame,
-                                                     String.format("Communications failed with \"%s\"",
-                                                                   device.toShortString()),
-                                                     "Cannot open target device",
-                                                     JOptionPane.ERROR_MESSAGE);
-               }
-               finish();
-       }
-
-       class EepromGetList implements Runnable {
-
-               AltosEepromManage       manage;
-
-               public void run () {
-                       Runnable r;
-                       try {
-                               flights = new AltosEepromList(serial_line, remote);
-                               r = new Runnable() {
-                                               public void run() {
-                                                       got_flights(flights);
-                                               }
-                                       };
-                       } catch (Exception e) {
-                               final Exception f_e = e;
-                               r = new Runnable() {
-                                               public void run() {
-                                                       got_exception(f_e);
-                                               }
-                                       };
-                       }
-                       SwingUtilities.invokeLater(r);
-               }
-
-               public EepromGetList(AltosEepromManage in_manage) {
-                       manage = in_manage;
-               }
-       }
-
-       public AltosEepromManage(JFrame given_frame) {
-
-               //boolean       running = false;
-
-               frame = given_frame;
-               device = AltosDeviceUIDialog.show(frame, Altos.product_any);
-
-               remote = false;
-
-               if (device != null) {
-                       try {
-                               serial_line = new AltosSerial(device);
-                               if (device.matchProduct(Altos.product_basestation))
-                                       remote = true;
-
-                               serial_line.set_frame(frame);
-
-                               EepromGetList   get_list = new EepromGetList(this);
-                               Thread          t = new Thread(get_list);
-                               t.start();
-                       } catch (FileNotFoundException ee) {
-                               JOptionPane.showMessageDialog(frame,
-                                                             ee.getMessage(),
-                                                             "Cannot open target device",
-                                                             JOptionPane.ERROR_MESSAGE);
-                       } catch (AltosSerialInUseException si) {
-                               JOptionPane.showMessageDialog(frame,
-                                                             String.format("Device \"%s\" already in use",
-                                                                           device.toShortString()),
-                                                             "Device in use",
-                                                             JOptionPane.ERROR_MESSAGE);
-                       }
-               }
-       }
-}
diff --git a/altosui/AltosEepromMonitor.java b/altosui/AltosEepromMonitor.java
deleted file mode 100644 (file)
index 50921da..0000000
+++ /dev/null
@@ -1,252 +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.*;
-import java.awt.event.*;
-import javax.swing.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosEepromMonitor extends AltosUIDialog {
-
-       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;
-
-       public AltosEepromMonitor(JFrame owner, int in_min_state, int in_max_state) {
-               super (owner, "Download Flight Data", false);
-
-               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);
-
-               min_state = in_min_state;
-               max_state = in_max_state;
-               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);
-               setVisible(true);
-       }
-
-       public void addActionListener (ActionListener l) {
-               cancel.addActionListener(l);
-       }
-
-       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_file_internal(String file) {
-               file_value.setText(String.format("%s", file));
-       }
-
-       public void set_file(String in_file) {
-               final String file = in_file;
-               Runnable r = new Runnable() {
-                               public void run() {
-                                       try {
-                                               set_file_internal(file);
-                                       } catch (Exception ex) {
-                                       }
-                               }
-                       };
-               SwingUtilities.invokeLater(r);
-       }
-
-       private void done_internal() {
-               setVisible(false);
-               dispose();
-       }
-
-       public void done() {
-               Runnable r = new Runnable() {
-                               public void run() {
-                                       try {
-                                               done_internal();
-                                       } catch (Exception ex) {
-                                       }
-                               }
-                       };
-               SwingUtilities.invokeLater(r);
-       }
-
-       private void reset_internal() {
-               set_value_internal("startup",min_state,0, 0);
-               set_flight_internal(0);
-               set_file_internal("");
-       }
-
-       public void reset() {
-               Runnable r = new Runnable() {
-                               public void run() {
-                                       try {
-                                               reset_internal();
-                                       } catch (Exception ex) {
-                                       }
-                               }
-                       };
-               SwingUtilities.invokeLater(r);
-       }
-}
diff --git a/altosui/AltosEepromMonitorUI.java b/altosui/AltosEepromMonitorUI.java
deleted file mode 100644 (file)
index c2e925a..0000000
+++ /dev/null
@@ -1,311 +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.*;
-import java.awt.event.*;
-import javax.swing.*;
-import org.altusmetrum.altosuilib_1.*;
-import org.altusmetrum.altoslib_3.*;
-
-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);
-       }
-}
diff --git a/altosui/AltosEepromSelect.java b/altosui/AltosEepromSelect.java
deleted file mode 100644 (file)
index b7cdbb7..0000000
+++ /dev/null
@@ -1,184 +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 javax.swing.*;
-import javax.swing.border.*;
-import java.awt.*;
-import java.awt.event.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-class AltosEepromItem implements ActionListener {
-       AltosEepromLog  log;
-       JLabel          label;
-       JCheckBox       action;
-       JCheckBox       delete;
-
-       public void actionPerformed(ActionEvent e) {
-               log.selected = action.isSelected();
-       }
-
-       public AltosEepromItem(AltosEepromLog in_log) {
-               log = in_log;
-
-               String  text;
-               if (log.year != 0)
-                       text = String.format("Flight #%02d - %04d-%02d-%02d",
-                                            log.flight, log.year, log.month, log.day);
-               else
-                       text = String.format("Flight #%02d", log.flight);
-
-               label = new JLabel(text);
-
-               action = new JCheckBox("", log.selected);
-               action.addActionListener(this);
-       }
-}
-
-public class AltosEepromSelect extends AltosUIDialog implements ActionListener {
-       //private JList                 list;
-       private JFrame                  frame;
-       JButton                         ok;
-       JButton                         cancel;
-       boolean                         success;
-
-       /* Listen for events from our buttons */
-       public void actionPerformed(ActionEvent e) {
-               String  cmd = e.getActionCommand();
-
-               if (cmd.equals("ok"))
-                       success = true;
-               setVisible(false);
-       }
-
-       public boolean run() {
-               success = false;
-               setLocationRelativeTo(frame);
-               setVisible(true);
-               return success;
-       }
-
-       public AltosEepromSelect (JFrame in_frame,
-                                 AltosEepromList flights,
-                                 String action) {
-
-               super(in_frame, String.format("Flight list for serial %d", flights.config_data.serial), true);
-               frame = in_frame;
-
-               /* Create the container for the dialog */
-               Container contentPane = getContentPane();
-
-               /* First, we create a pane containing the dialog's header/title */
-               JLabel  selectLabel = new JLabel(String.format ("Select flights to %s", action), SwingConstants.CENTER);
-
-               JPanel  labelPane = new JPanel();
-               labelPane.setLayout(new BoxLayout(labelPane, BoxLayout.X_AXIS));
-               labelPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
-               labelPane.add(Box.createHorizontalGlue());
-               labelPane.add(selectLabel);
-               labelPane.add(Box.createHorizontalGlue());
-
-               /* Add the header to the container. */
-               contentPane.add(labelPane, BorderLayout.PAGE_START);
-
-
-               /* Now we create the evilness that is a GridBag for the flight details */
-               GridBagConstraints c;
-               Insets i = new Insets(4,4,4,4);
-               JPanel flightPane = new JPanel();
-               flightPane.setLayout(new GridBagLayout());
-               flightPane.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
-
-               /* Flight Header */
-               c = new GridBagConstraints();
-               c.gridx = 0; c.gridy = 0;
-               c.fill = GridBagConstraints.NONE;
-               c.weightx = 0.5;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               JLabel flightHeaderLabel = new JLabel("Flight");
-               flightPane.add(flightHeaderLabel, c);
-
-               /* Download Header */
-               c = new GridBagConstraints();
-               c.gridx = 1; c.gridy = 0;
-               c.fill = GridBagConstraints.NONE;
-               c.weightx = 0.5;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               JLabel downloadHeaderLabel = new JLabel(action);
-               flightPane.add(downloadHeaderLabel, c);
-
-               /* Add the flights to the GridBag */
-               AltosEepromItem item;
-               int itemNumber = 1;
-               for (AltosEepromLog flight : flights) {
-                       /* Create a flight object with handlers and
-                        * appropriate UI items
-                        */
-                       item = new AltosEepromItem(flight);
-
-                       /* Add a decriptive label for the flight */
-                       c = new GridBagConstraints();
-                       c.gridx = 0; c.gridy = itemNumber;
-                       c.fill = GridBagConstraints.NONE;
-                       c.weightx = 0.5;
-                       c.anchor = GridBagConstraints.CENTER;
-                       c.insets = i;
-                       flightPane.add(item.label, c);
-
-                       /* Add action checkbox for the flight */
-                       c = new GridBagConstraints();
-                       c.gridx = 1; c.gridy = itemNumber;
-                       c.fill = GridBagConstraints.NONE;
-                       c.weightx = 0.5;
-                       c.anchor = GridBagConstraints.CENTER;
-                       c.insets = i;
-                       flightPane.add(item.action, c);
-
-                       itemNumber++;
-               }
-
-               /* Add the GridBag to the container */
-               contentPane.add(flightPane, BorderLayout.CENTER);
-
-               /* Create the dialog buttons */
-               ok = new JButton("OK");
-               ok.addActionListener(this);
-               ok.setActionCommand("ok");
-
-               cancel = new JButton("Cancel");
-               cancel.addActionListener(this);
-               cancel.setActionCommand("cancel");
-
-               JPanel  buttonPane = new JPanel();
-               buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS));
-               buttonPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
-               buttonPane.add(Box.createHorizontalGlue());
-               buttonPane.add(cancel);
-               buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
-               buttonPane.add(ok);
-
-               /* Add the buttons to the container */
-               contentPane.add(buttonPane, BorderLayout.PAGE_END);
-
-               /* Pack the window! */
-               pack();
-       }
-}
diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java
deleted file mode 100644 (file)
index 5913e50..0000000
+++ /dev/null
@@ -1,432 +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.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import java.io.*;
-import java.util.concurrent.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosFlashUI
-       extends AltosUIDialog
-       implements ActionListener
-{
-       Container       pane;
-       Box             box;
-       JLabel          serial_label;
-       JLabel          serial_value;
-       JLabel          file_label;
-       JLabel          file_value;
-       JProgressBar    pbar;
-       JButton         cancel;
-
-       JFrame          frame;
-
-       // Hex file with rom image
-       File            file;
-
-       // Debug connection
-       AltosDevice     device;
-
-       AltosLink       link;
-
-       // Desired Rom configuration
-       AltosRomconfig  rom_config;
-
-       // Flash controller
-       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 (programmer != null)
-                               programmer.abort();
-                       setVisible(false);
-                       dispose();
-               } else {
-                       String  cmd = e.getActionCommand();
-                       if (e.getID() == -1) {
-                               JOptionPane.showMessageDialog(frame,
-                                                             e.getActionCommand(),
-                                                             file.toString(),
-                                                             JOptionPane.ERROR_MESSAGE);
-                               setVisible(false);
-                               dispose();
-                       } else if (cmd.equals("done")) {
-                               setVisible(false);
-                               dispose();
-                       } else if (cmd.equals("start")) {
-                               setVisible(true);
-                       } else {
-                               pbar.setValue(e.getID());
-                               pbar.setString(cmd);
-                       }
-               }
-       }
-
-       public void build_dialog() {
-               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;
-               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 = 1;
-               c.anchor = GridBagConstraints.LINE_START;
-               c.insets = ir;
-               file_value = new JLabel(file.toString());
-               pane.add(file_value, c);
-
-               pbar = new JProgressBar();
-               pbar.setMinimum(0);
-               pbar.setMaximum(100);
-               pbar.setValue(0);
-               pbar.setString("");
-               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 = 2;
-               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 = 3;
-               c.gridwidth = GridBagConstraints.REMAINDER;
-               Insets ic = new Insets(4,4,4,4);
-               c.insets = ic;
-               pane.add(cancel, c);
-               cancel.addActionListener(this);
-               pack();
-               setLocationRelativeTo(frame);
-       }
-
-       void set_serial(int serial_number) {
-               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();
-
-               File firmwaredir = AltosUIPreferences.firmwaredir();
-               if (firmwaredir != null)
-                       hexfile_chooser.setCurrentDirectory(firmwaredir);
-
-               hexfile_chooser.setDialogTitle("Select Flash Image");
-
-               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)
-                       return false;
-               file = hexfile_chooser.getSelectedFile();
-               if (file == null)
-                       return false;
-               AltosUIPreferences.set_firmwaredir(file.getParentFile());
-               
-               return true;
-       }
-
-       boolean select_device() {
-               int     product = Altos.product_any;
-
-               device = AltosDeviceUIDialog.show(frame, Altos.product_any);
-
-               if (device == null)
-                       return false;
-               return true;
-       }
-
-       boolean update_rom_config_info(AltosRomconfig existing_config) {
-               AltosRomconfig  new_config;
-               new_config = AltosRomconfigUI.show(frame, existing_config);
-               if (new_config == null)
-                       return false;
-               rom_config = new_config;
-               set_serial(rom_config.serial_number);
-               setVisible(true);
-               return true;
-       }
-
-       void exception (Exception e) {
-               if (e instanceof FileNotFoundException) {
-                       JOptionPane.showMessageDialog(frame,
-                                                     ((FileNotFoundException) e).getMessage(),
-                                                     "Cannot open file",
-                                                     JOptionPane.ERROR_MESSAGE);
-               } else if (e instanceof AltosSerialInUseException) {
-                       JOptionPane.showMessageDialog(frame,
-                                                     String.format("Device \"%s\" already in use",
-                                                                   device.toShortString()),
-                                                     "Device in use",
-                                                     JOptionPane.ERROR_MESSAGE);
-               } else if (e instanceof IOException) {
-                       JOptionPane.showMessageDialog(frame,
-                                                     e.getMessage(),
-                                                     file.toString(),
-                                                     JOptionPane.ERROR_MESSAGE);
-               }
-       }
-
-       class flash_task implements Runnable, AltosFlashListener {
-               AltosFlashUI    ui;
-               Thread          t;
-               AltosProgrammer programmer;
-
-               public void position(String in_s, int in_percent) {
-                       final String s = in_s;
-                       final int percent = in_percent;
-                       Runnable r = new Runnable() {
-                                       public void run() {
-                                               try {
-                                                       ui.actionPerformed(new ActionEvent(this,
-                                                                                          percent,
-                                                                                          s));
-                                               } catch (Exception ex) {
-                                               }
-                                       }
-                               };
-                       SwingUtilities.invokeLater(r);
-               }
-
-               public void run () {
-                       try {
-                               if (ui.is_pair_programmed())
-                                       programmer = new AltosFlash(ui.file, link, this);
-                               else
-                                       programmer = new AltosSelfFlash(ui.file, link, this);
-
-                               final AltosRomconfig    current_config = programmer.romconfig();
-
-                               final Semaphore await_rom_config = new Semaphore(0);
-                               SwingUtilities.invokeLater(new Runnable() {
-                                               public void run() {
-                                                       ui.programmer = programmer;
-                                                       ui.update_rom_config_info(current_config);
-                                                       await_rom_config.release();
-                                               }
-                                       });
-                               await_rom_config.acquire();
-
-                               if (ui.rom_config != null) {
-                                       programmer.set_romconfig(ui.rom_config);
-                                       programmer.flash();
-                               }
-                       } catch (InterruptedException ee) {
-                               final Exception e = ee;
-                               SwingUtilities.invokeLater(new Runnable() {
-                                               public void run() {
-                                                       ui.exception(e);
-                                               }
-                                       });
-                       } catch (IOException ee) {
-                               final Exception e = ee;
-                               SwingUtilities.invokeLater(new Runnable() {
-                                               public void run() {
-                                                       ui.exception(e);
-                                               }
-                                       });
-                       } finally {
-                               if (programmer != null)
-                                       programmer.close();
-                       }
-               }
-
-               public flash_task(AltosFlashUI in_ui) {
-                       ui = in_ui;
-                       t = new Thread(this);
-                       t.start();
-               }
-       }
-
-       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_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);
-       }
-
-       static void show(JFrame frame) {
-               AltosFlashUI    ui = new AltosFlashUI(frame);
-
-               ui.showDialog();
-       }
-
-       public AltosFlashUI(JFrame in_frame) {
-               super(in_frame, "Program Altusmetrum Device", false);
-
-               frame = in_frame;
-       }
-}
\ No newline at end of file
diff --git a/altosui/AltosFlightDisplay.java b/altosui/AltosFlightDisplay.java
deleted file mode 100644 (file)
index c126425..0000000
+++ /dev/null
@@ -1,28 +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 org.altusmetrum.altoslib_3.*;
-
-public interface AltosFlightDisplay {
-       void reset();
-
-       void show(AltosState state, AltosListenerState listener_state);
-
-       void set_font();
-}
diff --git a/altosui/AltosFlightInfoTableModel.java b/altosui/AltosFlightInfoTableModel.java
deleted file mode 100644 (file)
index 249f649..0000000
+++ /dev/null
@@ -1,75 +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 javax.swing.table.*;
-
-public class AltosFlightInfoTableModel extends AbstractTableModel {
-       final static private String[] columnNames = {"Field", "Value"};
-
-       int     rows;
-       int     cols;
-       private String[][] data;
-
-       public int getColumnCount() { return cols; }
-       public int getRowCount() { return rows; }
-       public String getColumnName(int col) { return columnNames[col & 1]; }
-
-       public Object getValueAt(int row, int col) {
-               if (row >= rows || col >= cols)
-                       return "";
-               return data[row][col];
-       }
-
-       int[]   current_row;
-
-       public void reset() {
-               for (int i = 0; i < cols / 2; i++)
-                       current_row[i] = 0;
-       }
-
-       public void clear() {
-               reset();
-               for (int c = 0; c < cols; c++)
-                       for (int r = 0; r < rows; r++)
-                               data[r][c] = "";
-               fireTableDataChanged();
-       }
-
-       public void addRow(int col, String name, String value) {
-               if (current_row[col] < rows) {
-                       data[current_row[col]][col * 2] = name;
-                       data[current_row[col]][col * 2 + 1] = value;
-               }
-               current_row[col]++;
-       }
-
-       public void finish() {
-               for (int c = 0; c < cols / 2; c++)
-                       while (current_row[c] < rows)
-                               addRow(c, "", "");
-               fireTableDataChanged();
-       }
-
-       public AltosFlightInfoTableModel (int in_rows, int in_cols) {
-               rows = in_rows;
-               cols = in_cols * 2;
-               data = new String[rows][cols];
-               current_row = new int[in_cols];
-       }
-}
diff --git a/altosui/AltosFlightStats.java b/altosui/AltosFlightStats.java
deleted file mode 100644 (file)
index 0be49c2..0000000
+++ /dev/null
@@ -1,186 +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 org.altusmetrum.altoslib_3.*;
-
-public class AltosFlightStats {
-       double          max_height;
-       double          max_gps_height;
-       double          max_speed;
-       double          max_acceleration;
-       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];
-       double[]        state_end = new double[Altos.ao_flight_invalid + 1];
-       int             serial;
-       int             flight;
-       int             year, month, day;
-       int             hour, minute, second;
-       double          lat, lon;
-       double          pad_lat, pad_lon;
-       boolean         has_gps;
-       boolean         has_other_adc;
-       boolean         has_rssi;
-       boolean         has_imu;
-       boolean         has_mag;
-       boolean         has_orient;
-
-       double landed_time(AltosStateIterable states) {
-               AltosState state = null;
-
-               for (AltosState s : states) {
-                       state = s;
-                       if (state.state == Altos.ao_flight_landed)
-                               break;
-               }
-
-               if (state == null)
-                       return 0;
-
-               double  landed_height = state.height();
-
-               state = null;
-
-               boolean above = true;
-
-               double  landed_time = -1000;
-
-               for (AltosState s : states) {
-                       state = s;
-
-                       if (state.height() > landed_height + 10) {
-                               above = true;
-                       } else {
-                               if (above && state.height() < landed_height + 2) {
-                                       above = false;
-                                       landed_time = state.time;
-                               }
-                       }
-               }
-               if (landed_time == -1000)
-                       landed_time = state.time;
-               return landed_time;
-       }
-
-       double boost_time(AltosStateIterable states) {
-               double boost_time = AltosLib.MISSING;
-               AltosState      state = null;
-
-               for (AltosState s : states) {
-                       state = s;
-                       if (state.acceleration() < 1)
-                               boost_time = state.time;
-                       if (state.state >= AltosLib.ao_flight_boost && state.state <= AltosLib.ao_flight_landed)
-                               break;
-               }
-               if (state == null)
-                       return 0;
-
-               if (boost_time == AltosLib.MISSING)
-                       boost_time = state.time;
-               return boost_time;
-       }
-
-
-       public AltosFlightStats(AltosStateIterable states) throws InterruptedException, IOException {
-               double          boost_time = boost_time(states);
-               double          end_time = 0;
-               double          landed_time = landed_time(states);
-
-               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;
-               has_imu = false;
-               has_mag = false;
-               has_orient = false;
-               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 (state.rssi != AltosLib.MISSING)
-                               has_rssi = true;
-                       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]++;
-                               }
-                               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();
-                               max_gps_height = state.max_gps_height();
-                       }
-                       if (state.gps != null && state.gps.locked && state.gps.nsat >= 4) {
-                               if (state_id <= Altos.ao_flight_pad) {
-                                       pad_lat = state.gps.lat;
-                                       pad_lon = state.gps.lon;
-                               }
-                               lat = state.gps.lat;
-                               lon = state.gps.lon;
-                               has_gps = true;
-                       }
-                       if (state.imu != null)
-                               has_imu = true;
-                       if (state.mag != null)
-                               has_mag = true;
-                       if (state.orient() != AltosLib.MISSING)
-                               has_orient = true;
-               }
-               for (int s = Altos.ao_flight_startup; s <= Altos.ao_flight_landed; s++) {
-                       if (state_count[s] > 0) {
-                               state_speed[s] /= state_count[s];
-                               state_accel[s] /= state_count[s];
-                       }
-                       if (state_start[s] == 0)
-                               state_start[s] = end_time;
-                       if (state_end[s] == 0)
-                               state_end[s] = end_time;
-               }
-       }
-}
diff --git a/altosui/AltosFlightStatsTable.java b/altosui/AltosFlightStatsTable.java
deleted file mode 100644 (file)
index cb0c156..0000000
+++ /dev/null
@@ -1,144 +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.awt.*;
-import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
-
-public class AltosFlightStatsTable extends JComponent {
-       GridBagLayout   layout;
-
-       class FlightStat {
-               JLabel          label;
-               JTextField      value;
-
-               public FlightStat(GridBagLayout layout, int y, String label_text, String ... values) {
-                       GridBagConstraints      c = new GridBagConstraints();
-                       c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
-                       c.weighty = 1;
-
-                       label = new JLabel(label_text);
-                       label.setFont(Altos.label_font);
-                       label.setHorizontalAlignment(SwingConstants.LEFT);
-                       c.gridx = 0; c.gridy = y;
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       layout.setConstraints(label, c);
-                       add(label);
-
-                       for (int j = 0; j < values.length; j++) {
-                               value = new JTextField(values[j]);
-                               value.setFont(Altos.value_font);
-                               value.setHorizontalAlignment(SwingConstants.RIGHT);
-                               c.gridx = j+1; c.gridy = y;
-                               c.anchor = GridBagConstraints.EAST;
-                               c.fill = GridBagConstraints.BOTH;
-                               c.weightx = 1;
-                               layout.setConstraints(value, c);
-                               add(value);
-                       }
-               }
-
-       }
-
-       static String pos(double p, String pos, String neg) {
-               String  h = pos;
-               if (p < 0) {
-                       h = neg;
-                       p = -p;
-               }
-               int deg = (int) Math.floor(p);
-               double min = (p - Math.floor(p)) * 60.0;
-               return String.format("%s %4d° %9.6f'", h, deg, min);
-       }
-
-       public AltosFlightStatsTable(AltosFlightStats stats) {
-               layout = new GridBagLayout();
-
-               setLayout(layout);
-               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 != 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 != AltosLib.MISSING)
-                               new FlightStat(layout, y++, "Date",
-                                              String.format("%04d-%02d-%02d", stats.year, stats.month, stats.day));
-                       if (stats.hour != AltosLib.MISSING)
-                               new FlightStat(layout, y++, "Time",
-                                              String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
-               }
-               new FlightStat(layout, y++, "Maximum height",
-                              String.format("%5.0f m", stats.max_height),
-                              String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height)));
-               if (stats.max_gps_height != AltosLib.MISSING) {
-                       new FlightStat(layout, y++, "Maximum GPS height",
-                                      String.format("%5.0f m", stats.max_gps_height),
-                                      String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_gps_height)));
-               }
-               new FlightStat(layout, y++, "Maximum speed",
-                              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 != 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)),
-                                      String.format("%5.0f G", AltosConvert.meters_to_g(stats.max_acceleration)));
-                       new FlightStat(layout, y++, "Average boost acceleration",
-                                      String.format("%5.0f m/s²", stats.state_accel[Altos.ao_flight_boost]),
-                                      String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[Altos.ao_flight_boost])),
-                                      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_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_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)),
-                              String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_fast] - stats.state_start[AltosLib.ao_flight_fast],
-                                            AltosLib.state_name(Altos.ao_flight_fast)),
-                              String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_coast] - stats.state_start[AltosLib.ao_flight_coast],
-                                            AltosLib.state_name(Altos.ao_flight_coast)));
-               new FlightStat(layout, y++, "Descent time",
-                              String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_drogue] - stats.state_start[AltosLib.ao_flight_drogue],
-                                            AltosLib.state_name(Altos.ao_flight_drogue)),
-                              String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_main] - stats.state_start[AltosLib.ao_flight_main],
-                                            AltosLib.state_name(Altos.ao_flight_main)));
-               new FlightStat(layout, y++, "Flight time",
-                              String.format("%6.1f s", stats.state_end[Altos.ao_flight_main] -
-                                            stats.state_start[Altos.ao_flight_boost]));
-               if (stats.has_gps) {
-                       new FlightStat(layout, y++, "Pad location",
-                                      pos(stats.pad_lat,"N","S"),
-                                      pos(stats.pad_lon,"E","W"));
-                       new FlightStat(layout, y++, "Last reported location",
-                                      pos(stats.lat,"N","S"),
-                                      pos(stats.lon,"E","W"));
-               }
-       }
-       
-}
\ No newline at end of file
index c6d75420fba38af29e9f237097e53481f56ad610..46c0b38736d5c9d4c53bf1c1519634ebee9765b4 100644 (file)
@@ -19,16 +19,27 @@ package altosui;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class AltosFlightStatus extends JComponent implements AltosFlightDisplay {
        GridBagLayout   layout;
 
-       public class FlightValue {
+       public abstract class FlightValue {
                JLabel          label;
                JTextField      value;
 
-               void show(AltosState state, AltosListenerState listener_state) {}
+               void show() {
+                       label.setVisible(true);
+                       value.setVisible(true);
+               }
+
+               void hide() {
+                       label.setVisible(false);
+                       value.setVisible(false);
+               }
+
+               abstract void show(AltosState state, AltosListenerState listener_state);
 
                void reset() {
                        value.setText("");
@@ -39,6 +50,11 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
                        value.setFont(Altos.status_font);
                }
 
+               void setVisible(boolean visible) {
+                       label.setVisible(visible);
+                       value.setVisible(visible);
+               }
+
                public FlightValue (GridBagLayout layout, int x, String text) {
                        GridBagConstraints      c = new GridBagConstraints();
                        c.insets = new Insets(5, 5, 5, 5);
@@ -55,6 +71,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
                        add(label);
 
                        value = new JTextField("");
+                       value.setEditable(false);
                        value.setFont(Altos.status_font);
                        value.setHorizontalAlignment(SwingConstants.CENTER);
                        c.gridx = x; c.gridy = 1;
@@ -64,9 +81,33 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
        }
 
        class Call extends FlightValue {
+
+               String last_call = "";
+
+               boolean same_call(String call) {
+                       if (last_call == null)
+                               return call == null;
+                       else
+                               return last_call.equals(call);
+               }
+
                void show(AltosState state, AltosListenerState listener_state) {
-                       value.setText(state.callsign);
+                       if (!same_call(state.callsign)) {
+                               show();
+                               value.setText(state.callsign);
+                               if (state.callsign == null)
+                                       setVisible(false);
+                               else
+                                       setVisible(true);
+                               last_call = state.callsign;
+                       }
                }
+
+               public void reset() {
+                       super.reset();
+                       last_call = "";
+               }
+
                public Call (GridBagLayout layout, int x) {
                        super (layout, x, "Callsign");
                }
@@ -75,12 +116,24 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
        Call call;
 
        class Serial extends FlightValue {
+
+               int     last_serial = -1;
                void show(AltosState state, AltosListenerState listener_state) {
-                       if (state.serial == AltosLib.MISSING)
-                               value.setText("none");
-                       else
-                               value.setText(String.format("%d", state.serial));
+                       if (state.serial != last_serial) {
+                               show();
+                               if (state.serial == AltosLib.MISSING)
+                                       value.setText("none");
+                               else
+                                       value.setText(String.format("%d", state.serial));
+                               last_serial = state.serial;
+                       }
                }
+
+               public void reset() {
+                       super.reset();
+                       last_serial = -1;
+               }
+
                public Serial (GridBagLayout layout, int x) {
                        super (layout, x, "Serial");
                }
@@ -89,12 +142,25 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
        Serial serial;
 
        class Flight extends FlightValue {
+
+               int     last_flight = -1;
+
                void show(AltosState state, AltosListenerState listener_state) {
-                       if (state.flight == AltosLib.MISSING)
-                               value.setText("none");
-                       else
-                               value.setText(String.format("%d", state.flight));
+                       if (state.flight != last_flight) {
+                               show();
+                               if (state.flight == AltosLib.MISSING)
+                                       value.setText("none");
+                               else
+                                       value.setText(String.format("%d", state.flight));
+                               last_flight = state.flight;
+                       }
                }
+
+               public void reset() {
+                       super.reset();
+                       last_flight = -1;
+               }
+
                public Flight (GridBagLayout layout, int x) {
                        super (layout, x, "Flight");
                }
@@ -103,9 +169,26 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
        Flight flight;
 
        class FlightState extends FlightValue {
+
+               int     last_state = -1;
+
                void show(AltosState state, AltosListenerState listener_state) {
-                       value.setText(state.state_name());
+                       if (state.state != last_state) {
+                               if (state.state == AltosLib.ao_flight_stateless)
+                                       hide();
+                               else {
+                                       show();
+                                       value.setText(state.state_name());
+                               }
+                               last_state = state.state;
+                       }
                }
+
+               public void reset() {
+                       super.reset();
+                       last_state = -1;
+               }
+
                public FlightState (GridBagLayout layout, int x) {
                        super (layout, x, "State");
                }
@@ -114,9 +197,26 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
        FlightState flight_state;
 
        class RSSI extends FlightValue {
+
+               int     last_rssi = 10000;
+
                void show(AltosState state, AltosListenerState listener_state) {
-                       value.setText(String.format("%d", state.rssi()));
+                       if (state.rssi() != last_rssi) {
+                               show();
+                               value.setText(String.format("%d", state.rssi()));
+                               if (state.rssi == AltosLib.MISSING)
+                                       setVisible(false);
+                               else
+                                       setVisible(true);
+                               last_rssi = state.rssi();
+                       }
                }
+
+               public void reset() {
+                       super.reset();
+                       last_rssi = 10000;
+               }
+
                public RSSI (GridBagLayout layout, int x) {
                        super (layout, x, "RSSI");
                }
@@ -125,10 +225,22 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
        RSSI rssi;
 
        class LastPacket extends FlightValue {
+
+               long    last_secs = -1;
+
                void show(AltosState state, AltosListenerState listener_state) {
                        long secs = (System.currentTimeMillis() - state.received_time + 500) / 1000;
-                       value.setText(String.format("%d", secs));
+                       if (secs != last_secs) {
+                               value.setText(String.format("%d", secs));
+                               last_secs = secs;
+                       }
+               }
+
+               public void reset() {
+                       super.reset();
+                       last_secs = -1;
                }
+
                public LastPacket(GridBagLayout layout, int x) {
                        super (layout, x, "Age");
                }
@@ -145,7 +257,7 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
                last_packet.reset();
        }
 
-       public void set_font () {
+       public void font_size_changed(int font_size) {
                call.set_font();
                serial.set_font();
                flight.set_font();
@@ -154,6 +266,9 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
                last_packet.set_font();
        }
 
+       public void units_changed(boolean imperial_units) {
+       }
+
        public void show (AltosState state, AltosListenerState listener_state) {
                call.show(state, listener_state);
                serial.show(state, listener_state);
@@ -168,6 +283,8 @@ public class AltosFlightStatus extends JComponent implements AltosFlightDisplay
                return d.height;
        }
 
+       public String getName() { return "Flight Status"; }
+
        public AltosFlightStatus() {
                layout = new GridBagLayout();
 
index e372d40197ade4bc31063fba71dc92e1d75f61c2..b33f40a4a9cbe760ea1ccc724c7c4782bc7dd290 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_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 public class AltosFlightStatusTableModel extends AbstractTableModel {
        private String[] columnNames = {
index 93399a13791e2094fb6be49a658670821eac4ae8..0daec04e87d7c4ac7e952fc463f347f96162bcfa 100644 (file)
@@ -18,7 +18,7 @@
 package altosui;
 
 import java.awt.event.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 public class AltosFlightStatusUpdate implements ActionListener {
 
index e8cf7f081a06c3a5827f9f260395a5629dbb620c..43deb631705f86abc30dd5f072570daeb6e3a7ba 100644 (file)
@@ -20,26 +20,31 @@ package altosui;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
+import java.util.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
-public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, AltosFontListener {
+public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay {
        AltosVoice              voice;
        AltosFlightReader       reader;
        AltosDisplayThread      thread;
 
+       LinkedList<AltosFlightDisplay> displays;
+
        JTabbedPane     pane;
 
        AltosPad        pad;
+       AltosIgnitor    ignitor;
        AltosAscent     ascent;
        AltosDescent    descent;
        AltosLanded     landed;
        AltosCompanionInfo      companion;
-       AltosSiteMap    sitemap;
+       AltosUIMap      sitemap;
        boolean         has_map;
        boolean         has_companion;
        boolean         has_state;
+       boolean         has_ignitor;
 
        private AltosFlightStatus flightStatus;
        private AltosInfoTable flightInfo;
@@ -54,6 +59,8 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
                        return ascent;
                if (state.state <= Altos.ao_flight_main)
                        return descent;
+               if (state.state == AltosLib.ao_flight_stateless)
+                       return descent;
                return landed;
        }
 
@@ -72,29 +79,19 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
        }
 
        public void reset() {
-               pad.reset();
-               ascent.reset();
-               descent.reset();
-               landed.reset();
-               flightInfo.clear();
-               sitemap.reset();
-       }
-
-       public void set_font() {
-               pad.set_font();
-               ascent.set_font();
-               descent.set_font();
-               landed.set_font();
-               flightStatus.set_font();
-               flightInfo.set_font();
-               sitemap.set_font();
-               companion.set_font();
+               for (AltosFlightDisplay d : displays)
+                       d.reset();
        }
 
        public void font_size_changed(int font_size) {
-               set_font();
+               for (AltosFlightDisplay d : displays)
+                       d.font_size_changed(font_size);
        }
 
+       public void units_changed(boolean imperial_units) {
+               for (AltosFlightDisplay d : displays)
+                       d.units_changed(imperial_units);
+       }
 
        AltosFlightStatusUpdate status_update;
 
@@ -104,8 +101,6 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
                if (state == null)
                        state = new AltosState();
 
-               pad.show(state, listener_state);
-
                if (state.state != Altos.ao_flight_startup) {
                        if (!has_state) {
                                pane.setTitleAt(0, "Launch Pad");
@@ -116,10 +111,6 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
                        }
                }
 
-               ascent.show(state, listener_state);
-               descent.show(state, listener_state);
-               landed.show(state, listener_state);
-
                JComponent tab = which_tab(state);
                if (tab != cur_tab) {
                        if (cur_tab == pane.getSelectedComponent()) {
@@ -127,33 +118,51 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
                        }
                        cur_tab = tab;
                }
-               flightStatus.show(state, listener_state);
-               flightInfo.show(state, listener_state);
+
+               if (ignitor.should_show(state)) {
+                       if (!has_ignitor) {
+                               pane.add("Ignitor", ignitor);
+                               has_ignitor = true;
+                       }
+               } else {
+                       if (has_ignitor) {
+                               pane.remove(ignitor);
+                               has_ignitor = false;
+                       }
+               }
 
                if (state.companion != null) {
                        if (!has_companion) {
                                pane.add("Companion", companion);
                                has_companion= true;
                        }
-                       companion.show(state, listener_state);
                } else {
                        if (has_companion) {
                                pane.remove(companion);
                                has_companion = false;
                        }
                }
+
                if (state.gps != null && state.gps.connected) {
                        if (!has_map) {
                                pane.add("Site Map", sitemap);
                                has_map = true;
                        }
-                       sitemap.show(state, listener_state);
                } else {
                        if (has_map) {
                                pane.remove(sitemap);
                                has_map = false;
                        }
                }
+
+               for (AltosFlightDisplay d : displays) {
+                       try {
+                               d.show(state, listener_state);
+                       } catch (Exception e) {
+                               System.out.printf("Exception showing %s\n", d.getName());
+                               e.printStackTrace();
+                       }
+               }
        }
 
        public void set_exit_on_close() {
@@ -162,7 +171,7 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
 
        Container       bag;
        AltosFreqList   frequencies;
-       JComboBox       telemetries;
+       JComboBox<String>       telemetries;
        JLabel          telemetry;
 
        ActionListener  show_timer;
@@ -170,6 +179,8 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
        public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) {
                AltosUIPreferences.set_component(this);
 
+               displays = new LinkedList<AltosFlightDisplay>();
+
                voice = in_voice;
                reader = in_reader;
 
@@ -208,8 +219,8 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
 
                        // Telemetry format menu
                        if (reader.supports_telemetry(Altos.ao_telemetry_standard)) {
-                               telemetries = new JComboBox();
-                               for (int i = 1; i <= Altos.ao_telemetry_max; i++) 
+                               telemetries = new JComboBox<String>();
+                               for (int i = 1; i <= Altos.ao_telemetry_max; i++)
                                        telemetries.addItem(Altos.telemetry_name(i));
                                int telemetry = AltosPreferences.telemetry(serial);
                                if (telemetry <= Altos.ao_telemetry_off ||
@@ -258,6 +269,7 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
 
                /* Flight status is always visible */
                flightStatus = new AltosFlightStatus();
+               displays.add(flightStatus);
                c.gridx = 0;
                c.gridy = 1;
                c.fill = GridBagConstraints.HORIZONTAL;
@@ -272,20 +284,29 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
                pane = new JTabbedPane();
 
                pad = new AltosPad();
+               displays.add(pad);
                pane.add("Status", pad);
 
+               ignitor = new AltosIgnitor();
+               displays.add(ignitor);
                ascent = new AltosAscent();
+               displays.add(ascent);
                descent = new AltosDescent();
+               displays.add(descent);
                landed = new AltosLanded(reader);
+               displays.add(landed);
 
                flightInfo = new AltosInfoTable();
+               displays.add(flightInfo);
                pane.add("Table", new JScrollPane(flightInfo));
 
                companion = new AltosCompanionInfo();
+               displays.add(companion);
                has_companion = false;
                has_state = false;
 
-               sitemap = new AltosSiteMap();
+               sitemap = new AltosUIMap();
+               displays.add(sitemap);
                has_map = false;
 
                /* Make the tabbed pane use the rest of the window space */
@@ -300,6 +321,7 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
                setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
 
                AltosUIPreferences.register_font_listener(this);
+               AltosPreferences.register_units_listener(this);
 
                addWindowListener(new WindowAdapter() {
                                @Override
@@ -308,6 +330,7 @@ public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay, A
                                        setVisible(false);
                                        dispose();
                                        AltosUIPreferences.unregister_font_listener(AltosFlightUI.this);
+                                       AltosPreferences.unregister_units_listener(AltosFlightUI.this);
                                        if (exit_on_close)
                                                System.exit(0);
                                }
diff --git a/altosui/AltosFreqList.java b/altosui/AltosFreqList.java
deleted file mode 100644 (file)
index 039b5f2..0000000
+++ /dev/null
@@ -1,86 +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 javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosFreqList extends JComboBox {
-
-       String  product;
-       int     serial;
-       int     calibrate;
-
-       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);
-                       
-                       if (f.close(new_frequency)) {
-                               setSelectedIndex(i);
-                               return;
-                       }
-               }
-               for (i = 0; i < getItemCount(); i++) {
-                       AltosFrequency  f = (AltosFrequency) getItemAt(i);
-                       
-                       if (new_frequency < f.frequency)
-                               break;
-               }
-               String  description = String.format("%s serial %d", product, serial);
-               AltosFrequency  frequency = new AltosFrequency(new_frequency, description);
-               AltosUIPreferences.add_common_frequency(frequency);
-               insertItemAt(frequency, i);
-               setMaximumRowCount(getItemCount());
-       }
-
-       public void set_product(String new_product) {
-               product = new_product;
-       }
-               
-       public void set_serial(int new_serial) {
-               serial = new_serial;
-       }
-
-       public double frequency() {
-               AltosFrequency  f = (AltosFrequency) getSelectedItem();
-               if (f != null)
-                       return f.frequency;
-               return 434.550;
-       }
-
-       public AltosFreqList () {
-               super(AltosUIPreferences.common_frequencies());
-               setMaximumRowCount(getItemCount());
-               setEditable(false);
-               product = "Unknown";
-               serial = 0;
-       }
-
-       public AltosFreqList(double in_frequency) {
-               this();
-               set_frequency(in_frequency);
-       }
-}
diff --git a/altosui/AltosGraph.java b/altosui/AltosGraph.java
deleted file mode 100644 (file)
index 42334e3..0000000
+++ /dev/null
@@ -1,395 +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.
- */
-
-package altosui;
-
-import java.io.*;
-import java.util.ArrayList;
-
-import java.awt.*;
-import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-import org.jfree.ui.*;
-import org.jfree.chart.*;
-import org.jfree.chart.plot.*;
-import org.jfree.chart.axis.*;
-import org.jfree.chart.renderer.*;
-import org.jfree.chart.renderer.xy.*;
-import org.jfree.chart.labels.*;
-import org.jfree.data.xy.*;
-import org.jfree.data.*;
-
-class AltosVoltage extends AltosUnits {
-
-       public double value(double v, boolean imperial_units) {
-               return v;
-       }
-
-       public double inverse(double v, boolean imperial_units) {
-               return v;
-       }
-
-       public String show_units(boolean imperial_units) {
-               return "V";
-       }
-
-       public String say_units(boolean imperial_units) {
-               return "volts";
-       }
-
-       public int show_fraction(int width, boolean imperial_units) {
-               return width / 2;
-       }
-}
-
-class AltosNsat extends AltosUnits {
-
-       public double value(double v, boolean imperial_units) {
-               return v;
-       }
-
-       public double inverse(double v, boolean imperial_units) {
-               return v;
-       }
-
-       public String show_units(boolean imperial_units) {
-               return "Sats";
-       }
-
-       public String say_units(boolean imperial_units) {
-               return "Satellites";
-       }
-
-       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 d, boolean imperial_units) {
-               return d;
-       }
-
-       public double inverse(double d, boolean imperial_units) {
-               return d;
-       }
-
-       public String show_units(boolean imperial_units) {
-               return "dBm";
-       }
-
-       public String say_units(boolean imperial_units) {
-               return "D B M";
-       }
-
-       public int show_fraction(int width, boolean imperial_units) {
-               return 0;
-       }
-}
-
-class AltosGyroUnits 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 "°/sec";
-       }
-
-       public String say_units(boolean imperial_units) {
-               return "degrees per second";
-       }
-
-       public int show_fraction(int width, boolean imperial_units) {
-               return 1;
-       }
-}
-
-class AltosMagUnits 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 "Ga";
-       }
-
-       public String say_units(boolean imperial_units) {
-               return "gauss";
-       }
-
-       public int show_fraction(int width, boolean imperial_units) {
-               return 2;
-       }
-}
-
-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);
-       static final private Color accel_color = new Color(31,31,194);
-       static final private Color voltage_color = new Color(194, 194, 31);
-       static final private Color battery_voltage_color = new Color(194, 194, 31);
-       static final private Color drogue_voltage_color = new Color(150, 150, 31);
-       static final private Color main_voltage_color = new Color(100, 100, 31);
-       static final private Color gps_nsat_color = new Color (194, 31, 194);
-       static final private Color gps_nsat_solution_color = new Color (194, 31, 194);
-       static final private Color gps_nsat_view_color = new Color (150, 31, 150);
-       static final private Color temperature_color = new Color (31, 194, 194);
-       static final private Color dbm_color = new Color(31, 100, 100);
-       static final private Color state_color = new Color(0,0,0);
-       static final private Color accel_x_color = new Color(255, 0, 0);
-       static final private Color accel_y_color = new Color(0, 255, 0);
-       static final private Color accel_z_color = new Color(0, 0, 255);
-       static final private Color gyro_x_color = new Color(192, 0, 0);
-       static final private Color gyro_y_color = new Color(0, 192, 0);
-       static final private Color gyro_z_color = new Color(0, 0, 192);
-       static final private Color mag_x_color = new Color(128, 0, 0);
-       static final private Color mag_y_color = new Color(0, 128, 0);
-       static final private Color mag_z_color = new Color(0, 0, 128);
-       static final private Color orient_color = new Color(31, 31, 31);
-
-       static AltosVoltage voltage_units = new AltosVoltage();
-       static AltosPressure pressure_units = new AltosPressure();
-       static AltosNsat nsat_units = new AltosNsat();
-       static AltosDbm dbm_units = new AltosDbm();
-       static AltosGyroUnits gyro_units = new AltosGyroUnits();
-       static AltosOrient orient_units = new AltosOrient();
-       static AltosMagUnits mag_units = new AltosMagUnits();
-
-       AltosUIAxis     height_axis, speed_axis, accel_axis, voltage_axis, temperature_axis, nsat_axis, dbm_axis;
-       AltosUIAxis     distance_axis, pressure_axis;
-       AltosUIAxis     gyro_axis, orient_axis, mag_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);
-               temperature_axis = newAxis("Temperature", AltosConvert.temperature, temperature_color, 0);
-               nsat_axis = newAxis("Satellites", nsat_units, gps_nsat_color,
-                                   AltosUIAxis.axis_include_zero | AltosUIAxis.axis_integer);
-               dbm_axis = newAxis("Signal Strength", dbm_units, dbm_color, 0);
-               distance_axis = newAxis("Distance", AltosConvert.distance, range_color);
-
-               gyro_axis = newAxis("Rotation Rate", gyro_units, gyro_z_color, 0);
-               orient_axis = newAxis("Tilt Angle", orient_units, orient_color, 0);
-               mag_axis = newAxis("Magnetic Field", mag_units, mag_x_color, 0);
-
-               addMarker("State", AltosGraphDataPoint.data_state, state_color);
-               addSeries("Height",
-                         AltosGraphDataPoint.data_height,
-                         AltosConvert.height,
-                         height_color,
-                         true,
-                         height_axis);
-               addSeries("Pressure",
-                         AltosGraphDataPoint.data_pressure,
-                         pressure_units,
-                         pressure_color,
-                         false,
-                         pressure_axis);
-               addSeries("Speed",
-                         AltosGraphDataPoint.data_speed,
-                         AltosConvert.speed,
-                         speed_color,
-                         true,
-                         speed_axis);
-               addSeries("Acceleration",
-                         AltosGraphDataPoint.data_accel,
-                         AltosConvert.accel,
-                         accel_color,
-                         true,
-                         accel_axis);
-               if (stats.has_gps) {
-                       addSeries("Range",
-                                 AltosGraphDataPoint.data_range,
-                                 AltosConvert.distance,
-                                 range_color,
-                                 false,
-                                 distance_axis);
-                       addSeries("Distance",
-                                 AltosGraphDataPoint.data_distance,
-                                 AltosConvert.distance,
-                                 distance_color,
-                                 false,
-                                 distance_axis);
-                       addSeries("GPS Height",
-                                 AltosGraphDataPoint.data_gps_height,
-                                 AltosConvert.height,
-                                 gps_height_color,
-                                 false,
-                                 height_axis);
-                       addSeries("GPS Satellites in Solution",
-                                 AltosGraphDataPoint.data_gps_nsat_solution,
-                                 nsat_units,
-                                 gps_nsat_solution_color,
-                                 false,
-                                 nsat_axis);
-                       addSeries("GPS Satellites in View",
-                                 AltosGraphDataPoint.data_gps_nsat_view,
-                                 nsat_units,
-                                 gps_nsat_view_color,
-                                 false,
-                         nsat_axis);
-               }
-               if (stats.has_rssi)
-                       addSeries("Received Signal Strength",
-                                 AltosGraphDataPoint.data_rssi,
-                                 dbm_units,
-                                 dbm_color,
-                                 false,
-                                 dbm_axis);
-               if (stats.has_other_adc) {
-                       addSeries("Temperature",
-                                 AltosGraphDataPoint.data_temperature,
-                                 AltosConvert.temperature,
-                                 temperature_color,
-                                 false,
-                                 temperature_axis);
-                       addSeries("Battery Voltage",
-                                 AltosGraphDataPoint.data_battery_voltage,
-                                 voltage_units,
-                                 battery_voltage_color,
-                                 false,
-                                 voltage_axis);
-                       addSeries("Drogue Voltage",
-                                 AltosGraphDataPoint.data_drogue_voltage,
-                                 voltage_units,
-                                 drogue_voltage_color,
-                                 false,
-                                 voltage_axis);
-                       addSeries("Main Voltage",
-                                 AltosGraphDataPoint.data_main_voltage,
-                                 voltage_units,
-                                 main_voltage_color,
-                                 false,
-                                 voltage_axis);
-               }
-
-               if (stats.has_imu) {
-                       addSeries("Acceleration X",
-                                 AltosGraphDataPoint.data_accel_x,
-                                 AltosConvert.accel,
-                                 accel_x_color,
-                                 false,
-                                 accel_axis);
-                       addSeries("Acceleration Y",
-                                 AltosGraphDataPoint.data_accel_y,
-                                 AltosConvert.accel,
-                                 accel_y_color,
-                                 false,
-                                 accel_axis);
-                       addSeries("Acceleration Z",
-                                 AltosGraphDataPoint.data_accel_z,
-                                 AltosConvert.accel,
-                                 accel_z_color,
-                                 false,
-                                 accel_axis);
-                       addSeries("Rotation Rate X",
-                                 AltosGraphDataPoint.data_gyro_x,
-                                 gyro_units,
-                                 gyro_x_color,
-                                 false,
-                                 gyro_axis);
-                       addSeries("Rotation Rate Y",
-                                 AltosGraphDataPoint.data_gyro_y,
-                                 gyro_units,
-                                 gyro_y_color,
-                                 false,
-                                 gyro_axis);
-                       addSeries("Rotation Rate Z",
-                                 AltosGraphDataPoint.data_gyro_z,
-                                 gyro_units,
-                                 gyro_z_color,
-                                 false,
-                                 gyro_axis);
-               }
-               if (stats.has_mag) {
-                       addSeries("Magnetometer X",
-                                 AltosGraphDataPoint.data_mag_x,
-                                 mag_units,
-                                 mag_x_color,
-                                 false,
-                                 mag_axis);
-                       addSeries("Magnetometer Y",
-                                 AltosGraphDataPoint.data_mag_y,
-                                 mag_units,
-                                 mag_y_color,
-                                 false,
-                                 mag_axis);
-                       addSeries("Magnetometer Z",
-                                 AltosGraphDataPoint.data_mag_z,
-                                 mag_units,
-                                 mag_z_color,
-                                 false,
-                                 mag_axis);
-               }
-               if (stats.has_orient)
-                       addSeries("Tilt Angle",
-                                 AltosGraphDataPoint.data_orient,
-                                 orient_units,
-                                 orient_color,
-                                 false,
-                                 orient_axis);
-
-               setDataSet(dataSet);
-       }
-}
\ No newline at end of file
diff --git a/altosui/AltosGraphDataPoint.java b/altosui/AltosGraphDataPoint.java
deleted file mode 100644 (file)
index 61a1a22..0000000
+++ /dev/null
@@ -1,189 +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.
- */
-
-package altosui;
-
-import org.altusmetrum.altosuilib_1.*;
-import org.altusmetrum.altoslib_3.*;
-
-public class AltosGraphDataPoint implements AltosUIDataPoint {
-
-       AltosState      state;
-
-       public static final int data_height = 0;
-       public static final int data_speed = 1;
-       public static final int data_accel = 2;
-       public static final int data_temp = 3;
-       public static final int data_battery_voltage = 4;
-       public static final int data_drogue_voltage = 5;
-       public static final int data_main_voltage = 6;
-       public static final int data_rssi = 7;
-       public static final int data_state = 8;
-       public static final int data_gps_height = 9;
-       public static final int data_gps_nsat_solution = 10;
-       public static final int data_gps_nsat_view = 11;
-       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 static final int data_accel_x = 16;
-       public static final int data_accel_y = 17;
-       public static final int data_accel_z = 18;
-       public static final int data_gyro_x = 19;
-       public static final int data_gyro_y = 20;
-       public static final int data_gyro_z = 21;
-       public static final int data_mag_x = 22;
-       public static final int data_mag_y = 23;
-       public static final int data_mag_z = 24;
-       public static final int data_orient = 25;
-
-       public double x() throws AltosUIDataMissing {
-               double  time = state.time_since_boost();
-               if (time < -2)
-                       throw new AltosUIDataMissing(-1);
-               return time;
-       }
-
-       public double y(int index) throws AltosUIDataMissing {
-               double y = AltosLib.MISSING;
-               switch (index) {
-               case data_height:
-                       y = state.height();
-                       break;
-               case data_speed:
-                       y = state.speed();
-                       break;
-               case data_accel:
-                       y = state.acceleration();
-                       break;
-               case data_temp:
-                       y = state.temperature;
-                       break;
-               case data_battery_voltage:
-                       y = state.battery_voltage;
-                       break;
-               case data_drogue_voltage:
-                       y = state.apogee_voltage;
-                       break;
-               case data_main_voltage:
-                       y = state.main_voltage;
-                       break;
-               case data_rssi:
-                       y = state.rssi;
-                       break;
-               case data_gps_height:
-                       y = state.gps_height;
-                       break;  
-               case data_gps_nsat_solution:
-                       if (state.gps != null)
-                               y = state.gps.nsat;
-                       break;
-               case data_gps_nsat_view:
-                       if (state.gps != null && state.gps.cc_gps_sat != null)
-                               y = state.gps.cc_gps_sat.length;
-                       break;
-               case data_temperature:
-                       y = state.temperature;
-                       break;
-               case data_range:
-                       y = state.range;
-                       break;
-               case data_distance:
-                       if (state.from_pad != null)
-                               y = state.from_pad.distance;
-                       break;
-               case data_pressure:
-                       y = state.pressure();
-                       break;
-                       
-               case data_accel_x:
-               case data_accel_y:
-               case data_accel_z:
-               case data_gyro_x:
-               case data_gyro_y:
-               case data_gyro_z:
-                       AltosIMU        imu = state.imu;
-                       if (imu == null)
-                               break;
-                       switch (index) {
-                       case data_accel_x:
-                               y = imu.accel_x;
-                               break;
-                       case data_accel_y:
-                               y = imu.accel_y;
-                               break;
-                       case data_accel_z:
-                               y = imu.accel_z;
-                               break;
-                       case data_gyro_x:
-                               y = imu.gyro_x;
-                               break;
-                       case data_gyro_y:
-                               y = imu.gyro_y;
-                               break;
-                       case data_gyro_z:
-                               y = imu.gyro_z;
-                               break;
-                       }
-                       break;
-               case data_mag_x:
-               case data_mag_y:
-               case data_mag_z:
-                       AltosMag        mag = state.mag;
-                       if (mag == null)
-                               break;
-                       switch (index) {
-                       case data_mag_x:
-                               y = mag.x;
-                               break;
-                       case data_mag_y:
-                               y = mag.y;
-                               break;
-                       case data_mag_z:
-                               y = mag.z;
-                               break;
-                       }
-                       break;
-               case data_orient:
-                       y = state.orient();
-                       break;
-               }
-               if (y == AltosLib.MISSING)
-                       throw new AltosUIDataMissing(index);
-               return y;
-       }
-
-       public int id(int index) {
-               if (index == data_state) {
-                       int s = state.state;
-                       if (s < Altos.ao_flight_boost || s > Altos.ao_flight_landed)
-                               return -1;
-                       return s;
-               }
-               return 0;
-       }
-
-       public String id_name(int index) {
-               if (index == data_state)
-                       return state.state_name();
-               return "";
-       }
-
-       public AltosGraphDataPoint (AltosState state) {
-               this.state = state;
-       }
-}
\ No newline at end of file
diff --git a/altosui/AltosGraphDataSet.java b/altosui/AltosGraphDataSet.java
deleted file mode 100644 (file)
index d2773a3..0000000
+++ /dev/null
@@ -1,95 +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.
- */
-
-package altosui;
-
-import java.lang.*;
-import java.io.*;
-import java.util.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-class AltosGraphIterator implements Iterator<AltosUIDataPoint> {
-       AltosGraphDataSet       dataSet;
-       Iterator<AltosState>    iterator;
-
-       public boolean hasNext() {
-               return iterator.hasNext();
-       }
-
-       public AltosUIDataPoint next() {
-               AltosState      state = iterator.next();
-
-               if (state.flight != AltosLib.MISSING) {
-                       if (dataSet.callsign == null && state.callsign != null)
-                               dataSet.callsign = state.callsign;
-
-                       if (dataSet.serial == 0 && state.serial != 0)
-                               dataSet.serial = state.serial;
-
-                       if (dataSet.flight == 0 && state.flight != 0)
-                               dataSet.flight = state.flight;
-               }
-
-               return new AltosGraphDataPoint(state);
-       }
-
-       public AltosGraphIterator (Iterator<AltosState> iterator, AltosGraphDataSet dataSet) {
-               this.iterator = iterator;
-               this.dataSet = dataSet;
-       }
-
-       public void remove() {
-       }
-}
-
-class AltosGraphIterable implements Iterable<AltosUIDataPoint> {
-       AltosGraphDataSet       dataSet;
-
-       public Iterator<AltosUIDataPoint> iterator() {
-               return new AltosGraphIterator(dataSet.states.iterator(), dataSet);
-       }
-
-       public AltosGraphIterable(AltosGraphDataSet dataSet) {
-               this.dataSet = dataSet;
-       }
-}
-
-public class AltosGraphDataSet implements AltosUIDataSet {
-       String                  callsign;
-       int                     serial;
-       int                     flight;
-       AltosStateIterable      states;
-
-       public String name() {
-               if (callsign != null)
-                       return String.format("%s - %d/%d", callsign, serial, flight);
-               else
-                       return String.format("%d/%d", serial, flight);
-       }
-
-       public Iterable<AltosUIDataPoint> dataPoints() {
-               return new AltosGraphIterable(this);
-       }
-
-       public AltosGraphDataSet (AltosStateIterable states) {
-               this.states = states;
-               this.callsign = null;
-               this.serial = 0;
-               this.flight = 0;
-       }
-}
index 40d2f7f4bc40dc83f091ba95e6250ddb740376e7..07fe93176c33dd68d71bfec4f47e7ff8a9222c6a 100644 (file)
@@ -1,6 +1,19 @@
-
-// Copyright (c) 2010 Anthony Towns
-// GPL v2 or later
+/*
+ * Copyright © 2010 Anthony Towns
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 or any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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;
 
@@ -8,20 +21,21 @@ import java.io.*;
 import java.util.ArrayList;
 
 import java.awt.*;
+import java.awt.event.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 import org.jfree.chart.ChartPanel;
 import org.jfree.chart.JFreeChart;
 import org.jfree.ui.RefineryUtilities;
 
-public class AltosGraphUI extends AltosUIFrame 
+public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener
 {
        JTabbedPane             pane;
        AltosGraph              graph;
        AltosUIEnable           enable;
-       AltosSiteMap            map;
+       AltosUIMap              map;
        AltosState              state;
        AltosGraphDataSet       graphDataSet;
        AltosFlightStats        stats;
@@ -33,13 +47,22 @@ public class AltosGraphUI extends AltosUIFrame
                for (AltosState state : states) {
                        if (state.gps != null && state.gps.locked && state.gps.nsat >= 4) {
                                if (map == null)
-                                       map = new AltosSiteMap();
+                                       map = new AltosUIMap();
                                map.show(state, null);
                                has_gps = true;
                        }
                }
        }
 
+       public void font_size_changed(int font_size) {
+               map.font_size_changed(font_size);
+               statsTable.font_size_changed(font_size);
+       }
+
+       public void units_changed(boolean imperial_units) {
+               map.units_changed(imperial_units);
+       }
+
        AltosGraphUI(AltosStateIterable states, File file) throws InterruptedException, IOException {
                super(file.getName());
                state = null;
@@ -66,9 +89,20 @@ public class AltosGraphUI extends AltosUIFrame
 
                setContentPane (pane);
 
+               AltosUIPreferences.register_font_listener(this);
+               AltosPreferences.register_units_listener(this);
+
+               addWindowListener(new WindowAdapter() {
+                               @Override
+                               public void windowClosing(WindowEvent e) {
+                                       setVisible(false);
+                                       dispose();
+                                       AltosUIPreferences.unregister_font_listener(AltosGraphUI.this);
+                                       AltosPreferences.unregister_units_listener(AltosGraphUI.this);
+                               }
+                       });
                pack();
 
-               setDefaultCloseOperation(DISPOSE_ON_CLOSE);
                setVisible(true);
                if (state != null && has_gps)
                        map.centre(state);
index 7ca935b654ee4a0a66444a7196297f60dc97d1b0..042111ec44347c5eb7803aa5fd477ffc6db41c4a 100644 (file)
@@ -24,10 +24,10 @@ import javax.swing.event.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.Arrays;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
-public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDisplay, AltosFontListener, AltosIdleMonitorListener, DocumentListener {
+public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDisplay, AltosIdleMonitorListener, DocumentListener {
        AltosDevice             device;
        JTabbedPane             pane;
        AltosPad                pad;
@@ -56,13 +56,14 @@ public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDispl
                flightInfo.clear();
        }
 
-       public void set_font() {
-               pad.set_font();
-               flightInfo.set_font();
+       public void font_size_changed(int font_size) {
+               pad.font_size_changed(font_size);
+               flightInfo.font_size_changed(font_size);
        }
 
-       public void font_size_changed(int font_size) {
-               set_font();
+       public void units_changed(boolean imperial_units) {
+               pad.units_changed(imperial_units);
+               flightInfo.units_changed(imperial_units);
        }
 
        AltosFlightStatusUpdate status_update;
@@ -234,7 +235,9 @@ public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDispl
                                        try {
                                                disconnect();
                                        } catch (Exception ex) {
-                                               System.out.println(Arrays.toString(ex.getStackTrace()));
+                                               System.out.printf("Exception %s\n", ex.toString());
+                                               for (StackTraceElement el : ex.getStackTrace())
+                                                       System.out.printf("%s\n", el.toString());
                                        }
                                        setVisible(false);
                                        dispose();
index 2e69249f42771db2c9d5854e5d64da8583002def..c251bbe219e90a92d7fbaf378c8c4e4ad9a677ac 100644 (file)
@@ -24,8 +24,8 @@ import java.io.*;
 import java.text.*;
 import java.util.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class AltosIgniteUI
        extends AltosUIDialog
@@ -486,7 +486,7 @@ public class AltosIgniteUI
                pane.add(close, c);
                close.addActionListener(this);
                close.setActionCommand("close");
-                       
+
                pack();
                setLocationRelativeTo(owner);
 
diff --git a/altosui/AltosIgnitor.java b/altosui/AltosIgnitor.java
new file mode 100644 (file)
index 0000000..990a87e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
+
+public class AltosIgnitor extends AltosUIFlightTab {
+
+       public class Ignitor extends AltosUIUnitsIndicator {
+               int             ignitor;
+
+               public double value(AltosState state, int i) {
+                       if (state.ignitor_voltage == null ||
+                           state.ignitor_voltage.length < ignitor)
+                               return AltosLib.MISSING;
+                       return state.ignitor_voltage[ignitor];
+               }
+
+               public double good() { return AltosLib.ao_igniter_good; }
+
+               public Ignitor (AltosUIFlightTab container, int y) {
+                       super(container, y, AltosConvert.voltage, String.format ("%s Voltage", AltosLib.ignitor_name(y)), 1, true, 1);
+                       ignitor = y;
+               }
+       }
+
+       Ignitor[] ignitors;
+
+       public void show(AltosState state, AltosListenerState listener_state) {
+               if (isShowing())
+                       make_ignitors(state);
+               super.show(state, listener_state);
+       }
+
+       public boolean should_show(AltosState state) {
+               if (state == null)
+                       return false;
+               if (state.ignitor_voltage == null)
+                       return false;
+               return state.ignitor_voltage.length > 0;
+       }
+
+       void make_ignitors(AltosState state) {
+               int n = (state == null || state.ignitor_voltage == null) ? 0 : state.ignitor_voltage.length;
+               int old_n = ignitors == null ? 0 : ignitors.length;
+
+               if (n != old_n) {
+
+                       if (ignitors != null) {
+                               for (int i = 0; i < ignitors.length; i++) {
+                                       remove(ignitors[i]);
+                                       ignitors[i].remove(this);
+                                       ignitors = null;
+                               }
+                       }
+
+                       if (n > 0) {
+                               setVisible(true);
+                               ignitors = new Ignitor[n];
+                               for (int i = 0; i < n; i++) {
+                                       ignitors[i] = new Ignitor(this, i);
+                                       add(ignitors[i]);
+                               }
+                       } else
+                               setVisible(false);
+               }
+       }
+
+       public String getName() {
+               return "Ignitors";
+       }
+}
diff --git a/altosui/AltosInfoTable.java b/altosui/AltosInfoTable.java
deleted file mode 100644 (file)
index 158b61f..0000000
+++ /dev/null
@@ -1,236 +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.*;
-import javax.swing.*;
-import javax.swing.table.*;
-import org.altusmetrum.altoslib_3.*;
-
-public class AltosInfoTable extends JTable {
-       private AltosFlightInfoTableModel model;
-
-       static final int info_columns = 3;
-       static final int info_rows = 17;
-
-       int desired_row_height() {
-               FontMetrics     infoValueMetrics = getFontMetrics(Altos.table_value_font);
-               return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10;
-       }
-
-       int text_width(String t) {
-               FontMetrics     infoValueMetrics = getFontMetrics(Altos.table_value_font);
-
-               return infoValueMetrics.stringWidth(t);
-       }
-
-       void set_layout() {
-               setRowHeight(desired_row_height());
-               for (int i = 0; i < info_columns * 2; i++)
-               {
-                       TableColumn column = getColumnModel().getColumn(i);
-
-                       if ((i & 1) == 0)
-                               column.setPreferredWidth(text_width(" Satellites Visible"));
-                       else
-                               column.setPreferredWidth(text_width("W 179°59.99999' "));
-               }
-       }
-
-       public AltosInfoTable() {
-               super(new AltosFlightInfoTableModel(info_rows, info_columns));
-               model = (AltosFlightInfoTableModel) getModel();
-               setFont(Altos.table_value_font);
-               setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS);
-               setShowGrid(true);
-               set_layout();
-               doLayout();
-       }
-
-       public void set_font() {
-               setFont(Altos.table_value_font);
-               set_layout();
-               doLayout();
-       }
-
-       public Dimension getPreferredScrollableViewportSize() {
-               return getPreferredSize();
-       }
-
-       void info_reset() {
-               model.reset();
-       }
-
-       void info_add_row(int col, String name, String value) {
-               model.addRow(col, name, value);
-       }
-
-       void info_add_row(int col, String name, String format, Object... parameters) {
-               info_add_row (col, name, String.format(format, parameters));
-       }
-
-       void info_add_deg(int col, String name, double v, int pos, int neg) {
-               int     c = pos;
-               if (v < 0) {
-                       c = neg;
-                       v = -v;
-               }
-               double  deg = Math.floor(v);
-               double  min = (v - deg) * 60;
-
-               info_add_row(col, name, String.format("%c %3.0f°%08.5f'", c, deg, min));
-       }
-
-       void info_finish() {
-               model.finish();
-       }
-
-       public void clear() {
-               model.clear();
-       }
-
-       public void show(AltosState state, AltosListenerState listener_state) {
-               info_reset();
-               if (state != null) {
-                       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.max_speed() != AltosLib.MISSING)
-                               info_add_row(0, "Max Speed", "%8.1f  m/s", state.max_speed());
-                       if (state.orient() != AltosLib.MISSING)
-                               info_add_row(0, "Tilt", "%4.0f °", state.orient());
-                       if (state.max_orient() != AltosLib.MISSING)
-                               info_add_row(0, "Max Tilt", "%4.0f °", state.max_orient());
-                       if (state.temperature != AltosLib.MISSING)
-                               info_add_row(0, "Temperature", "%9.2f °C", state.temperature);
-                       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 != AltosLib.MISSING)
-                               info_add_row(0, "Receiver Battery", "%9.2f", listener_state.battery);
-               }
-
-               if (state != null) {
-                       if (state.gps == null || !state.gps.connected) {
-                               info_add_row(1, "GPS", "not available");
-                       } else {
-                               if (state.gps_ready)
-                                       info_add_row(1, "GPS state", "%s", "ready");
-                               else
-                                       info_add_row(1, "GPS state", "wait (%d)",
-                                                    state.gps_waiting);
-                               if (state.gps.locked)
-                                       info_add_row(1, "GPS", "   locked");
-                               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.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 */
-                               /*
-                                 if (false) {
-                                 info_add_row(1, "GPS ground speed", "%8.1f m/s %3d°",
-                                 state.gps.ground_speed,
-                                 state.gps.course);
-                                 info_add_row(1, "GPS climb rate", "%8.1f m/s",
-                                 state.gps.climb_rate);
-                                 info_add_row(1, "GPS error", "%6d m(h)%3d m(v)",
-                                 state.gps.h_error, state.gps.v_error);
-                                 }
-                               */
-
-                               info_add_row(1, "GPS hdop", "%8.1f", state.gps.hdop);
-
-                               if (state.npad > 0) {
-                                       if (state.from_pad != null) {
-                                               info_add_row(1, "Distance from pad", "%6d m",
-                                                            (int) (state.from_pad.distance + 0.5));
-                                               info_add_row(1, "Direction from pad", "%6d°",
-                                                            (int) (state.from_pad.bearing + 0.5));
-                                               info_add_row(1, "Elevation from pad", "%6d°",
-                                                            (int) (state.elevation + 0.5));
-                                               info_add_row(1, "Range from pad", "%6d m",
-                                                            (int) (state.range + 0.5));
-                                       } else {
-                                               info_add_row(1, "Distance from pad", "unknown");
-                                               info_add_row(1, "Direction from pad", "unknown");
-                                               info_add_row(1, "Elevation from pad", "unknown");
-                                               info_add_row(1, "Range from pad", "unknown");
-                                       }
-                                       info_add_deg(1, "Pad latitude", state.pad_lat, 'N', 'S');
-                                       info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W');
-                                       info_add_row(1, "Pad GPS alt", "%6.0f m", state.pad_alt);
-                               }
-                               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;
-
-                               if (state.gps.cc_gps_sat == null)
-                                       info_add_row(2, "Satellites Visible", "%4d", 0);
-                               else {
-                                       info_add_row(2, "Satellites Visible", "%4d", state.gps.cc_gps_sat.length);
-                                       for (c = 0; c < state.gps.cc_gps_sat.length; c++) {
-                                               info_add_row(2, "Satellite id,C/N0",
-                                                            "%4d, %4d",
-                                                            state.gps.cc_gps_sat[c].svid,
-                                                            state.gps.cc_gps_sat[c].c_n0);
-                                       }
-                               }
-                       }
-               }
-               info_finish();
-       }
-}
diff --git a/altosui/AltosKML.java b/altosui/AltosKML.java
deleted file mode 100644 (file)
index ae1f825..0000000
+++ /dev/null
@@ -1,179 +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.io.*;
-import org.altusmetrum.altoslib_3.*;
-
-public class AltosKML implements AltosWriter {
-
-       File                    name;
-       PrintStream             out;
-       int                     flight_state = -1;
-       AltosState              prev = null;
-       double                  gps_start_altitude;
-
-       static final String[] kml_state_colors = {
-               "FF000000",
-               "FF000000",
-               "FF000000",
-               "FF0000FF",
-               "FF4080FF",
-               "FF00FFFF",
-               "FFFF0000",
-               "FF00FF00",
-               "FF000000",
-               "FFFFFFFF"
-       };
-
-       static final String kml_header_start =
-               "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
-               "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n" +
-               "<Document>\n" +
-               "  <name>AO Flight#%d S/N: %03d</name>\n" +
-               "  <description>\n";
-       static final String kml_header_end =
-               "  </description>\n" +
-               "  <open>0</open>\n";
-
-       static final String kml_style_start =
-               "  <Style id=\"ao-flightstate-%s\">\n" +
-               "    <LineStyle><color>%s</color><width>4</width></LineStyle>\n" +
-               "    <BalloonStyle>\n" +
-               "      <text>\n";
-
-       static final String kml_style_end =
-               "      </text>\n" +
-               "    </BalloonStyle>\n" +
-               "  </Style>\n";
-
-       static final String kml_placemark_start =
-               "  <Placemark>\n" +
-               "    <name>%s</name>\n" +
-               "    <styleUrl>#ao-flightstate-%s</styleUrl>\n" +
-               "    <LineString>\n" +
-               "      <tessellate>1</tessellate>\n" +
-               "      <altitudeMode>absolute</altitudeMode>\n" +
-               "      <coordinates>\n";
-
-       static final String kml_coord_fmt =
-       "        %.7f,%.7f,%.7f <!-- alt %12.7f time %12.7f sats %d -->\n";
-
-       static final String kml_placemark_end =
-               "      </coordinates>\n" +
-               "    </LineString>\n" +
-               "  </Placemark>\n";
-
-       static final String kml_footer =
-               "</Document>\n" +
-               "</kml>\n";
-
-       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);
-               out.printf("Time:     %2d:%02d:%02d\n",
-                          record.gps.hour, record.gps.minute, record.gps.second);
-               out.printf("%s", kml_header_end);
-       }
-
-       boolean started = false;
-
-       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(AltosState state) {
-               out.printf("%s", kml_placemark_end);
-       }
-
-       void coord(AltosState state) {
-               AltosGPS        gps = state.gps;
-               double          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,
-                          state.time, gps.nsat);
-       }
-
-       void end() {
-               out.printf("%s", kml_footer);
-       }
-
-       public void close() {
-               if (prev != null) {
-                       state_end(prev);
-                       end();
-                       prev = null;
-               }
-       }
-
-       public void write(AltosState state) {
-               AltosGPS        gps = state.gps;
-
-               if (gps == null)
-                       return;
-
-               if (gps.lat == AltosLib.MISSING)
-                       return;
-               if (gps.lon == AltosLib.MISSING)
-                       return;
-               if (!started) {
-                       start(state);
-                       started = true;
-                       gps_start_altitude = gps.alt;
-               }
-               if (prev != null && prev.gps_sequence == state.gps_sequence)
-                       return;
-               if (state.state != flight_state) {
-                       flight_state = state.state;
-                       if (prev != null) {
-                               coord(state);
-                               state_end(prev);
-                       }
-                       state_start(state);
-               }
-               coord(state);
-               prev = state;
-       }
-
-       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 {
-               name = in_name;
-               out = new PrintStream(name);
-       }
-
-       public AltosKML(String in_string) throws FileNotFoundException {
-               this(new File(in_string));
-       }
-}
index 74177753c6dbfe31cd9275dd370b4e30b3170964..dd5cf9ab827842aae003d620eeadadb944f6436c 100644 (file)
@@ -21,216 +21,94 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.io.*;
-import org.altusmetrum.altoslib_3.*;
-
-public class AltosLanded extends JComponent implements AltosFlightDisplay, ActionListener {
-       GridBagLayout   layout;
-
-       public class LandedValue {
-               JLabel          label;
-               JTextField      value;
-               void show(AltosState state, AltosListenerState listener_state) {}
-
-               void reset() {
-                       value.setText("");
-               }
-
-               void show() {
-                       label.setVisible(true);
-                       value.setVisible(true);
-               }
-
-               void show(String s) {
-                       show();
-                       value.setText(s);
-               }
-               
-               void show(AltosUnits units, double v) {
-                       show(units.show(8, v));
-               }
-
-               void show(String format, double v) {
-                       show(String.format(format, v));
-               }
-
-               public void set_font() {
-                       label.setFont(Altos.label_font);
-                       value.setFont(Altos.value_font);
-               }
-
-               void hide() {
-                       label.setVisible(false);
-                       value.setVisible(false);
-               }
-
-               public LandedValue (GridBagLayout layout, int y, String text) {
-                       GridBagConstraints      c = new GridBagConstraints();
-                       c.weighty = 1;
-
-                       label = new JLabel(text);
-                       label.setFont(Altos.label_font);
-                       label.setHorizontalAlignment(SwingConstants.LEFT);
-                       c.gridx = 0; c.gridy = y;
-                       c.insets = new Insets(10, 10, 10, 10);
-                       c.anchor = GridBagConstraints.WEST;
-                       c.weightx = 0;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       layout.setConstraints(label, c);
-                       add(label);
-
-                       value = new JTextField(Altos.text_width);
-                       value.setFont(Altos.value_font);
-                       value.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = 1; c.gridy = y;
-                       c.anchor = GridBagConstraints.WEST;
-                       c.weightx = 1;
-                       c.fill = GridBagConstraints.BOTH;
-                       layout.setConstraints(value, c);
-                       add(value);
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
+
+public class AltosLanded extends AltosUIFlightTab implements ActionListener {
+
+       class Bearing extends AltosUIIndicator {
+               public void show (AltosState state, AltosListenerState listener_state) {
+                       if (state.from_pad != null && state.from_pad.bearing != AltosLib.MISSING) {
+                               show( String.format("%3.0f°", state.from_pad.bearing),
+                                     state.from_pad.bearing_words(
+                                             AltosGreatCircle.BEARING_LONG));
+                       } else {
+                               show("Missing", "Missing");
+                       }
                }
-       }
-
-       String pos(double p, String pos, String neg) {
-               String  h = pos;
-               if (p < 0) {
-                       h = neg;
-                       p = -p;
+               public Bearing (Container container, int y) {
+                       super (container, y, "Bearing", 2);
                }
-               int deg = (int) Math.floor(p);
-               double min = (p - Math.floor(p)) * 60.0;
-               return String.format("%s %4d° %9.6f", h, deg, min);
        }
 
-       class Lat extends LandedValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show();
-                       if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
-                               show(pos(state.gps.lat,"N", "S"));
+       class Distance extends AltosUIUnitsIndicator {
+               public double value(AltosState state, int i) {
+                       if (state.from_pad != null)
+                               return state.from_pad.distance;
                        else
-                               show("???");
-               }
-               public Lat (GridBagLayout layout, int y) {
-                       super (layout, y, "Latitude");
+                               return AltosLib.MISSING;
                }
-       }
-
-       Lat lat;
 
-       class Lon extends LandedValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show();
-                       if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
-                               show(pos(state.gps.lon,"E", "W"));
-                       else
-                               show("???");
-               }
-               public Lon (GridBagLayout layout, int y) {
-                       super (layout, y, "Longitude");
+               public Distance(Container container, int y) {
+                       super(container, y, AltosConvert.distance, "Ground Distance", 2);
                }
        }
 
-       Lon lon;
+       class Lat extends AltosUIUnitsIndicator {
 
-       class Bearing extends LandedValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show();
-                       if (state.from_pad != null)
-                               show("%3.0f°", state.from_pad.bearing);
-                       else
-                               show("???");
-               }
-               public Bearing (GridBagLayout layout, int y) {
-                       super (layout, y, "Bearing");
-               }
-       }
+               public boolean hide (AltosState state, int i) { return state.gps == null || !state.gps.connected; }
 
-       Bearing bearing;
-
-       class Distance extends LandedValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show();
-                       if (state.from_pad != null)
-                               show(AltosConvert.distance, state.from_pad.distance);
-                       else
-                               show("???");
-               }
-               public Distance (GridBagLayout layout, int y) {
-                       super (layout, y, "Distance");
+               public double value(AltosState state, int i) {
+                       if (state.gps == null)
+                               return AltosLib.MISSING;
+                       if (!state.gps.connected)
+                               return AltosLib.MISSING;
+                       return state.gps.lat;
                }
-       }
 
-       Distance distance;
-
-       class Height extends LandedValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.height, state.max_height());
-               }
-               public Height (GridBagLayout layout, int y) {
-                       super (layout, y, "Maximum Height");
+               public Lat (Container container, int y) {
+                       super (container, y, AltosConvert.latitude, "Latitude", 2);
                }
        }
 
-       Height  height;
+       class Lon extends AltosUIUnitsIndicator {
+               public boolean hide (AltosState state, int i) { return state.gps == null || !state.gps.connected; }
 
-       class Speed extends LandedValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.speed, state.max_speed());
+               public double value(AltosState state, int i) {
+                       if (state.gps == null)
+                               return AltosLib.MISSING;
+                       if (!state.gps.connected)
+                               return AltosLib.MISSING;
+                       return state.gps.lon;
                }
-               public Speed (GridBagLayout layout, int y) {
-                       super (layout, y, "Maximum Speed");
+
+               public Lon (Container container, int y) {
+                       super (container, y, AltosConvert.longitude, "Longitude", 2);
                }
        }
 
-       Speed   speed;
+       class MaxHeight extends AltosUIUnitsIndicator {
+               public double value(AltosState state, int i) { return state.max_height(); }
 
-       class Accel extends LandedValue {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       show(AltosConvert.accel, state.max_acceleration());
-               }
-               public Accel (GridBagLayout layout, int y) {
-                       super (layout, y, "Maximum Acceleration");
+               public MaxHeight (Container container, int y) {
+                       super (container, y, AltosConvert.height, "Maximum Height", 2);
                }
        }
 
-       Accel   accel;
+       class MaxSpeed extends AltosUIUnitsIndicator {
+               public double value(AltosState state, int i) { return state.max_speed(); }
 
-       public void reset() {
-               lat.reset();
-               lon.reset();
-               bearing.reset();
-               distance.reset();
-               height.reset();
-               speed.reset();
-               accel.reset();
+               public MaxSpeed (Container container, int y) {
+                       super (container, y, AltosConvert.speed, "Maximum Speed", 2);
+               }
        }
 
-       public void set_font() {
-               lat.set_font();
-               lon.set_font();
-               bearing.set_font();
-               distance.set_font();
-               height.set_font();
-               speed.set_font();
-               accel.set_font();
-       }
+       class MaxAccel extends AltosUIUnitsIndicator {
+               public double value(AltosState state, int i) { return state.max_acceleration(); }
 
-       public void show(AltosState state, AltosListenerState listener_state) {
-               if (state.gps != null && state.gps.connected) {
-                       bearing.show(state, listener_state);
-                       distance.show(state, listener_state);
-                       lat.show(state, listener_state);
-                       lon.show(state, listener_state);
-               } else {
-                       bearing.hide();
-                       distance.hide();
-                       lat.hide();
-                       lon.hide();
+               public MaxAccel (Container container, int y) {
+                       super (container, y, AltosConvert.speed, "Maximum acceleration", 2);
                }
-               height.show(state, listener_state);
-               speed.show(state, listener_state);
-               accel.show(state, listener_state);
-               if (reader.backing_file() != null)
-                       graph.setEnabled(true);
        }
 
        JButton graph;
@@ -274,20 +152,16 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
        }
 
        public AltosLanded(AltosFlightReader in_reader) {
-               layout = new GridBagLayout();
-
                reader = in_reader;
 
-               setLayout(layout);
-
                /* Elements in descent display */
-               bearing = new Bearing(layout, 0);
-               distance = new Distance(layout, 1);
-               lat = new Lat(layout, 2);
-               lon = new Lon(layout, 3);
-               height = new Height(layout, 4);
-               speed = new Speed(layout, 5);
-               accel = new Accel(layout, 6);
+               add(new Bearing(this, 0));
+               add(new Distance(this, 1));
+               add(new Lat(this, 2));
+               add(new Lon(this, 3));
+               add(new MaxHeight(this, 4));
+               add(new MaxSpeed(this, 5));
+               add(new MaxAccel(this, 6));
 
                graph = new JButton ("Graph Flight");
                graph.setActionCommand("graph");
@@ -296,12 +170,13 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
 
                GridBagConstraints      c = new GridBagConstraints();
 
-               c.gridx = 0; c.gridy = 7;
+               c.gridx = 1; c.gridy = 7;
                c.insets = new Insets(10, 10, 10, 10);
                c.anchor = GridBagConstraints.WEST;
                c.weightx = 0;
                c.weighty = 0;
                c.fill = GridBagConstraints.VERTICAL;
                add(graph, c);
+               addHierarchyListener(this);
        }
 }
index 04948ee6647baedbe1222ec9b4f96ceba85ca28e..9ac1e44c3a11b0fd1c88a6a03f244a56982a7048 100644 (file)
@@ -20,7 +20,7 @@ package altosui;
 import java.io.*;
 import java.util.concurrent.*;
 import java.awt.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class AltosLaunch {
        AltosDevice     device;
index 4d9fbda563c552c86331524a860d7bdaab584060..cc082542b6f853543e998d20b68258b1171634fd 100644 (file)
@@ -23,7 +23,7 @@ import javax.swing.*;
 import java.io.*;
 import java.text.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altosuilib_2.*;
 
 class FireButton extends JButton {
        protected void processMouseEvent(MouseEvent e) {
diff --git a/altosui/AltosLed.java b/altosui/AltosLed.java
deleted file mode 100644 (file)
index 93064f1..0000000
+++ /dev/null
@@ -1,45 +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 javax.swing.*;
-
-public class AltosLed extends JLabel {
-       ImageIcon       on, off;
-
-       ImageIcon create_icon(String path) {
-               java.net.URL imgURL = AltosUI.class.getResource(path);
-               if (imgURL != null)
-                       return new ImageIcon(imgURL);
-               System.err.printf("Cannot find icon \"%s\"\n", path);
-               return null;
-       }
-
-       public void set(boolean set) {
-               if (set)
-                       setIcon(on);
-               else
-                       setIcon(off);
-       }
-
-       public AltosLed(String on_path, String off_path) {
-               on = create_icon(on_path);
-               off = create_icon(off_path);
-               setIcon(off);
-       }
-}
diff --git a/altosui/AltosLights.java b/altosui/AltosLights.java
deleted file mode 100644 (file)
index 7ad22f3..0000000
+++ /dev/null
@@ -1,65 +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.*;
-import javax.swing.*;
-
-public class AltosLights extends JComponent {
-
-       GridBagLayout   gridbag;
-
-       AltosLed        red, green;
-
-       ImageIcon create_icon(String path, String description) {
-               java.net.URL imgURL = AltosUI.class.getResource(path);
-               if (imgURL != null)
-                       return new ImageIcon(imgURL, description);
-               System.err.printf("Cannot find icon \"%s\"\n", path);
-               return null;
-       }
-
-       public void set (boolean on) {
-               if (on) {
-                       red.set(false);
-                       green.set(true);
-               } else {
-                       red.set(true);
-                       green.set(false);
-               }
-       }
-
-       public AltosLights() {
-               GridBagConstraints c;
-               gridbag = new GridBagLayout();
-               setLayout(gridbag);
-
-               c = new GridBagConstraints();
-               red = new AltosLed("/redled.png", "/grayled.png");
-               c.gridx = 0; c.gridy = 0;
-               c.insets = new Insets (0, 5, 0, 5);
-               gridbag.setConstraints(red, c);
-               add(red);
-               red.set(true);
-               green = new AltosLed("/greenled.png", "/grayled.png");
-               c.gridx = 1; c.gridy = 0;
-               gridbag.setConstraints(green, c);
-               add(green);
-               green.set(false);
-       }
-}
index 7baf0eb214cadac7a4361af3ee6370dfc08aa183..6b5fd1500618edf63a4f8fc818bd90b11b1db57a 100644 (file)
 
 package altosui;
 
-import java.awt.*;
-import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import java.util.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
-public class AltosPad extends JComponent implements AltosFlightDisplay {
-       GridBagLayout   layout;
+public class AltosPad extends AltosUIFlightTab {
 
-       public class LaunchStatus {
-               JLabel          label;
-               JTextField      value;
-               AltosLights     lights;
-
-               void show(AltosState state, AltosListenerState listener_state) {}
-
-               void reset() {
-                       value.setText("");
-                       lights.set(false);
-               }
-
-               public void show() {
-                       label.setVisible(true);
-                       value.setVisible(true);
-                       lights.setVisible(true);
-               }
-
-               void show(String s) {
-                       show();
-                       value.setText(s);
-               }
-
-               void show(String format, double value) {
-                       show(String.format(format, value));
-               }
-
-               void show(String format, int value) {
-                       show(String.format(format, value));
-               }
-
-               public void hide() {
-                       label.setVisible(false);
-                       value.setVisible(false);
-                       lights.setVisible(false);
-               }
-
-               public void set_font() {
-                       label.setFont(Altos.label_font);
-                       value.setFont(Altos.value_font);
-               }
-
-               public void set_label(String text) {
-                       label.setText(text);
-               }
-               
-               public LaunchStatus (GridBagLayout layout, int y, String text) {
-                       GridBagConstraints      c = new GridBagConstraints();
-                       c.weighty = 1;
-
-                       lights = new AltosLights();
-                       c.gridx = 0; c.gridy = y;
-                       c.anchor = GridBagConstraints.CENTER;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       layout.setConstraints(lights, c);
-                       add(lights);
-
-                       label = new JLabel(text);
-                       label.setFont(Altos.label_font);
-                       label.setHorizontalAlignment(SwingConstants.LEFT);
-                       c.gridx = 1; c.gridy = y;
-                       c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       layout.setConstraints(label, c);
-                       add(label);
-
-                       value = new JTextField(Altos.text_width);
-                       value.setFont(Altos.value_font);
-                       value.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = 2; c.gridy = y;
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.BOTH;
-                       c.weightx = 1;
-                       layout.setConstraints(value, c);
-                       add(value);
-
-               }
+       class Battery extends AltosUIVoltageIndicator {
+               public double voltage(AltosState state) { return state.battery_voltage; }
+               public double good() { return AltosLib.ao_battery_good; }
+               public Battery (AltosUIFlightTab container, int y) { super(container, y, "Battery Voltage", 2); }
        }
 
-       public class LaunchValue {
-               JLabel          label;
-               JTextField      value;
-               void show(AltosState state, AltosListenerState listener_state) {}
-
-               void show() {
-                       label.setVisible(true);
-                       value.setVisible(true);
-               }
-
-               void hide() {
-                       label.setVisible(false);
-                       value.setVisible(false);
-               }
-
-               public void set_font() {
-                       label.setFont(Altos.label_font);
-                       value.setFont(Altos.value_font);
-               }
-
-               void show(String s) {
-                       show();
-                       value.setText(s);
-               }
-
-               void show(AltosUnits units, double v) {
-                       show(units.show(8, v));
-               }
-
-               void show(String format, double v) {
-                       show(String.format(format, v));
-               }
-
-               public void set_label(String text) {
-                       label.setText(text);
-               }
-               
-               void reset() {
-                       value.setText("");
-               }
-
-               public LaunchValue (GridBagLayout layout, int y, String text) {
-                       GridBagConstraints      c = new GridBagConstraints();
-                       c.insets = new Insets(Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad, Altos.tab_elt_pad);
-                       c.weighty = 1;
-
-                       label = new JLabel(text);
-                       label.setFont(Altos.label_font);
-                       label.setHorizontalAlignment(SwingConstants.LEFT);
-                       c.gridx = 1; c.gridy = y;
-                       c.anchor = GridBagConstraints.WEST;
-                       c.fill = GridBagConstraints.VERTICAL;
-                       c.weightx = 0;
-                       layout.setConstraints(label, c);
-                       add(label);
-
-                       value = new JTextField(Altos.text_width);
-                       value.setFont(Altos.value_font);
-                       value.setHorizontalAlignment(SwingConstants.RIGHT);
-                       c.gridx = 2; c.gridy = y;
-                       c.anchor = GridBagConstraints.EAST;
-                       c.fill = GridBagConstraints.BOTH;
-                       c.weightx = 1;
-                       layout.setConstraints(value, c);
-                       add(value);
-               }
+       class Apogee extends AltosUIVoltageIndicator {
+               public boolean hide(double v) { return v == AltosLib.MISSING; }
+               public double voltage(AltosState state) { return state.apogee_voltage; }
+               public double good() { return AltosLib.ao_igniter_good; }
+               public Apogee (AltosUIFlightTab container, int y) { super(container, y, "Apogee Igniter Voltage", 2); }
        }
 
-       class Battery extends LaunchStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       if (state == null || state.battery_voltage == AltosLib.MISSING)
-                               hide();
-                       else {
-                               show("%4.2f V", state.battery_voltage);
-                               lights.set(state.battery_voltage >= AltosLib.ao_battery_good);
-                       }
-               }
-               public Battery (GridBagLayout layout, int y) {
-                       super(layout, y, "Battery Voltage");
-               }
+       class Main extends AltosUIVoltageIndicator {
+               public boolean hide(double v) { return v == AltosLib.MISSING; }
+               public double voltage(AltosState state) { return state.main_voltage; }
+               public double good() { return AltosLib.ao_igniter_good; }
+               public Main (AltosUIFlightTab container, int y) { super(container, y, "Main Igniter Voltage", 2); }
        }
 
-       Battery battery;
-
-       class Apogee extends LaunchStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       if (state == null || state.apogee_voltage == AltosLib.MISSING)
-                               hide();
-                       else {
-                               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");
-               }
-       }
-
-       Apogee apogee;
-
-       class Main extends LaunchStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       if (state == null || state.main_voltage == AltosLib.MISSING)
-                               hide();
-                       else {
-                               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");
-               }
-       }
-
-       Main main;
-
-       class LoggingReady extends LaunchStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
+       class LoggingReady extends AltosUIIndicator {
+               public void show (AltosState state, AltosListenerState listener_state) {
                        if (state == null || state.flight == AltosLib.MISSING) {
                                hide();
                        } else {
                                if (state.flight != 0) {
                                        if (state.state <= Altos.ao_flight_pad)
                                                show("Ready to record");
-                                       else if (state.state < Altos.ao_flight_landed)
+                                       else if (state.state < Altos.ao_flight_landed ||
+                                                state.state == AltosLib.ao_flight_stateless)
                                                show("Recording data");
                                        else
                                                show("Recorded data");
                                } else
                                        show("Storage full");
-                               lights.set(state.flight != 0);
+                               set_lights(state.flight != 0);
                        }
                }
-               public LoggingReady (GridBagLayout layout, int y) {
-                       super(layout, y, "On-board Data Logging");
+               public LoggingReady (AltosUIFlightTab container, int y) {
+                       super(container, y, "On-board Data Logging", 1, true, 2);
                }
        }
 
-       LoggingReady logging_ready;
-
-       class GPSLocked extends LaunchStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
+       class GPSLocked extends AltosUIIndicator {
+               public void show (AltosState state, AltosListenerState listener_state) {
                        if (state == null || state.gps == null)
                                hide();
                        else {
-                               show("%4d sats", state.gps.nsat);
-                               lights.set(state.gps.locked && state.gps.nsat >= 4);
+                               int     sol = state.gps.nsat;
+                               int     sat = state.gps.cc_gps_sat == null ? 0 : state.gps.cc_gps_sat.length;
+                               show("%d in solution", sol, "%d in view", sat);
+                               set_lights(state.gps.locked && sol >= 4);
                        }
                }
-               public GPSLocked (GridBagLayout layout, int y) {
-                       super (layout, y, "GPS Locked");
+               public GPSLocked (AltosUIFlightTab container, int y) {
+                       super (container, y, "GPS Locked", 2, true, 1);
                }
        }
 
-       GPSLocked gps_locked;
-
-       class GPSReady extends LaunchStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
+       class GPSReady extends AltosUIIndicator {
+               public void show (AltosState state, AltosListenerState listener_state) {
                        if (state == null || state.gps == null)
                                hide();
                        else {
@@ -271,45 +91,37 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
                                        show("Ready");
                                else
                                        show("Waiting %d", state.gps_waiting);
-                               lights.set(state.gps_ready);
+                               set_lights(state.gps_ready);
                        }
                }
-               public GPSReady (GridBagLayout layout, int y) {
-                       super (layout, y, "GPS Ready");
+               public GPSReady (AltosUIFlightTab container, int y) {
+                       super (container, y, "GPS Ready", 1, true, 2);
                }
        }
 
-       GPSReady gps_ready;
+       class ReceiverBattery extends AltosUIVoltageIndicator {
 
-       class ReceiverBattery extends LaunchStatus {
-               void show (AltosState state, AltosListenerState listener_state) {
-                       if (listener_state == null || listener_state.battery == AltosLib.MISSING)
-                               hide();
-                       else {
-                               show("%4.2f V", listener_state.battery);
-                               lights.set(listener_state.battery > AltosLib.ao_battery_good);
-                       }
+               public double voltage(AltosState state) { return AltosLib.MISSING; }
+
+               public boolean hide(double v) { return v == AltosLib.MISSING; }
+               public double good() { return AltosLib.ao_battery_good; }
+
+               public double value(AltosState state, AltosListenerState listener_state, int i) {
+                       if (listener_state == null)
+                               return AltosLib.MISSING;
+                       return listener_state.battery;
                }
-               public ReceiverBattery (GridBagLayout layout, int y) {
-                       super(layout, y, "Receiver Battery");
+
+               public ReceiverBattery (AltosUIFlightTab container, int y) {
+                       super(container, y, "Receiver Battery", 2);
                }
        }
 
-       ReceiverBattery receiver_battery;
+       class PadLat extends AltosUIIndicator {
 
-       String pos(double p, String pos, String neg) {
-               String  h = pos;
-               if (p < 0) {
-                       h = neg;
-                       p = -p;
-               }
-               int deg = (int) Math.floor(p);
-               double min = (p - Math.floor(p)) * 60.0;
-               return String.format("%s %4d° %9.6f", h, deg, min);
-       }
+               double  last_lat = AltosLib.MISSING - 1;
 
-       class PadLat extends LaunchValue {
-               void show (AltosState state, AltosListenerState listener_state) {
+               public void show (AltosState state, AltosListenerState listener_state) {
                        double lat = AltosLib.MISSING;
                        String label = null;
 
@@ -322,21 +134,31 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
                                        label = "Pad Latitude";
                                }
                        }
-                       if (lat != AltosLib.MISSING) {
-                               show(pos(lat,"N", "S"));
-                               set_label(label);
-                       } else
-                               hide();
+                       if (lat != last_lat) {
+                               if (lat != AltosLib.MISSING) {
+                                       show(AltosConvert.latitude.show(10, lat));
+                                       set_label(label);
+                               } else
+                                       hide();
+                               last_lat = lat;
+                       }
+               }
+
+               public void reset() {
+                       super.reset();
+                       last_lat = AltosLib.MISSING - 1;
                }
-               public PadLat (GridBagLayout layout, int y) {
-                       super (layout, y, "Pad Latitude");
+
+               public PadLat (AltosUIFlightTab container, int y) {
+                       super (container, y, "Pad Latitude", 1, false, 2);
                }
        }
 
-       PadLat pad_lat;
+       class PadLon extends AltosUIIndicator {
+
+               double last_lon = AltosLib.MISSING - 1;
 
-       class PadLon extends LaunchValue {
-               void show (AltosState state, AltosListenerState listener_state) {
+               public void show (AltosState state, AltosListenerState listener_state) {
                        double lon = AltosLib.MISSING;
                        String label = null;
 
@@ -349,21 +171,31 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
                                        label = "Pad Longitude";
                                }
                        }
-                       if (lon != AltosLib.MISSING) {
-                               show(pos(lon,"E", "W"));
-                               set_label(label);
-                       } else
-                               hide();
+                       if (lon != last_lon) {
+                               if (lon != AltosLib.MISSING) {
+                                       show(AltosConvert.longitude.show(10, lon));
+                                       set_label(label);
+                               } else
+                                       hide();
+                               last_lon = lon;
+                       }
+               }
+
+               public void reset() {
+                       super.reset();
+                       last_lon = AltosLib.MISSING - 1;
                }
-               public PadLon (GridBagLayout layout, int y) {
-                       super (layout, y, "Pad Longitude");
+
+               public PadLon (AltosUIFlightTab container, int y) {
+                       super (container, y, "Pad Longitude", 1, false, 2);
                }
        }
 
-       PadLon pad_lon;
+       class PadAlt extends AltosUIIndicator {
+
+               double  last_alt = AltosLib.MISSING - 1;
 
-       class PadAlt extends LaunchValue {
-               void show (AltosState state, AltosListenerState listener_state) {
+               public void show (AltosState state, AltosListenerState listener_state) {
                        double alt = AltosLib.MISSING;
                        String label = null;
 
@@ -376,83 +208,38 @@ public class AltosPad extends JComponent implements AltosFlightDisplay {
                                        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");
+                       if (alt != last_alt) {
+                               if (alt != AltosLib.MISSING) {
+                                       show(AltosConvert.height.show(5, alt));
+                                       set_label(label);
+                               } else
+                                       hide();
+                               last_alt = alt;
+                       }
                }
-       }
 
-       PadAlt pad_alt;
-
-       public void reset() {
-               battery.reset();
-               apogee.reset();
-               main.reset();
-               logging_ready.reset();
-               gps_locked.reset();
-               gps_ready.reset();
-               receiver_battery.reset();
-               pad_lat.reset();
-               pad_lon.reset();
-               pad_alt.reset();
-       }
+               public void reset() {
+                       super.reset();
+                       last_alt =  AltosLib.MISSING - 1;
+               }
 
-       public void set_font() {
-               battery.set_font();
-               apogee.set_font();
-               main.set_font();
-               logging_ready.set_font();
-               gps_locked.set_font();
-               gps_ready.set_font();
-               receiver_battery.set_font();
-               pad_lat.set_font();
-               pad_lon.set_font();
-               pad_alt.set_font();
-       }
-       
-       public void show(AltosState state, AltosListenerState listener_state) {
-               battery.show(state, listener_state);
-               apogee.show(state, listener_state);
-               main.show(state, listener_state);
-               logging_ready.show(state, listener_state);
-               pad_alt.show(state, listener_state);
-               receiver_battery.show(state, listener_state);
-               gps_locked.show(state, listener_state);
-               gps_ready.show(state, listener_state);
-               pad_lat.show(state, listener_state);
-               pad_lon.show(state, listener_state);
+               public PadAlt (AltosUIFlightTab container, int y) {
+                       super (container, y, "Pad Altitude", 1, false, 2);
+               }
        }
+       public String getName() { return "Pad"; }
 
        public AltosPad() {
-               layout = new GridBagLayout();
-
-               setLayout(layout);
-
-               /* Elements in pad display:
-                *
-                * Battery voltage
-                * Igniter continuity
-                * GPS lock status
-                * GPS ready status
-                * GPS location
-                * Pad altitude
-                * RSSI
-                */
-               battery = new Battery(layout, 0);
-               apogee = new Apogee(layout, 1);
-               main = new Main(layout, 2);
-               logging_ready = new LoggingReady(layout, 3);
-               gps_locked = new GPSLocked(layout, 4);
-               gps_ready = new GPSReady(layout, 5);
-               receiver_battery = new ReceiverBattery(layout, 6);
-               pad_lat = new PadLat(layout, 7);
-               pad_lon = new PadLon(layout, 8);
-               pad_alt = new PadAlt(layout, 9);
-               show(null, null);
+               int y = 0;
+               add(new Battery(this, y++));
+               add(new Apogee(this, y++));
+               add(new Main(this, y++));
+               add(new LoggingReady(this, y++));
+               add(new GPSLocked(this, y++));
+               add(new GPSReady(this, y++));
+               add(new ReceiverBattery(this, y++));
+               add(new PadLat(this, y++));
+               add(new PadLon(this, y++));
+               add(new PadAlt(this, y++));
        }
 }
diff --git a/altosui/AltosRomconfigUI.java b/altosui/AltosRomconfigUI.java
deleted file mode 100644 (file)
index 8999467..0000000
+++ /dev/null
@@ -1,191 +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.*;
-import java.awt.event.*;
-import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosRomconfigUI
-       extends AltosUIDialog
-       implements ActionListener
-{
-       Container       pane;
-       Box             box;
-       JLabel          serial_label;
-       JLabel          radio_calibration_label;
-
-       JFrame          owner;
-       JTextField      serial_value;
-       JTextField      radio_calibration_value;
-
-       JButton         ok;
-       JButton         cancel;
-
-       /* Build the UI using a grid bag */
-       public AltosRomconfigUI(JFrame in_owner) {
-               super (in_owner, "Configure TeleMetrum Rom Values", true);
-
-               owner = in_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());
-
-               /* Serial */
-               c = new GridBagConstraints();
-               c.gridx = 0; c.gridy = 0;
-               c.gridwidth = 3;
-               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 = 3; c.gridy = 0;
-               c.gridwidth = 3;
-               c.fill = GridBagConstraints.HORIZONTAL;
-               c.weightx = 1;
-               c.anchor = GridBagConstraints.LINE_START;
-               c.insets = ir;
-               serial_value = new JTextField("00000000");
-               pane.add(serial_value, c);
-
-               /* Radio calibration value */
-               c = new GridBagConstraints();
-               c.gridx = 0; c.gridy = 1;
-               c.gridwidth = 3;
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.LINE_START;
-               c.insets = il;
-               c.ipady = 5;
-               radio_calibration_label = new JLabel("Radio Calibration:");
-               pane.add(radio_calibration_label, c);
-
-               c = new GridBagConstraints();
-               c.gridx = 3; c.gridy = 1;
-               c.gridwidth = 3;
-               c.fill = GridBagConstraints.HORIZONTAL;
-               c.weightx = 1;
-               c.anchor = GridBagConstraints.LINE_START;
-               c.insets = ir;
-               c.ipady = 5;
-               radio_calibration_value = new JTextField("00000000");
-               pane.add(radio_calibration_value, c);
-
-               /* Buttons */
-               c = new GridBagConstraints();
-               c.gridx = 0; c.gridy = 2;
-               c.gridwidth = 3;
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = il;
-               ok = new JButton("OK");
-               pane.add(ok, c);
-               ok.addActionListener(this);
-               ok.setActionCommand("ok");
-
-               c = new GridBagConstraints();
-               c.gridx = 3; c.gridy = 2;
-               c.gridwidth = 3;
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = il;
-               cancel = new JButton("Cancel");
-               pane.add(cancel, c);
-               cancel.addActionListener(this);
-               cancel.setActionCommand("cancel");
-
-               pack();
-               setLocationRelativeTo(owner);
-       }
-
-       public AltosRomconfigUI(JFrame frame, AltosRomconfig config) {
-               this(frame);
-               set(config);
-       }
-
-       boolean selected;
-
-       /* Listen for events from our buttons */
-       public void actionPerformed(ActionEvent e) {
-               String  cmd = e.getActionCommand();
-
-               if (cmd.equals("ok")) {
-                       AltosRomconfig  romconfig = romconfig();
-                       if (romconfig == null || !romconfig.valid()) {
-                               JOptionPane.showMessageDialog(this,
-                                                             "Invalid serial number or radio calibration value",
-                                                             "Invalid rom configuration",
-                                                             JOptionPane.ERROR_MESSAGE);
-                               return;
-                       }
-                       selected = true;
-               }
-               setVisible(false);
-       }
-
-       int serial() {
-               return Integer.parseInt(serial_value.getText());
-       }
-
-       void set_serial(int serial) {
-               serial_value.setText(String.format("%d", serial));
-       }
-
-       int radio_calibration() {
-               return Integer.parseInt(radio_calibration_value.getText());
-       }
-
-       void set_radio_calibration(int calibration) {
-               radio_calibration_value.setText(String.format("%d", calibration));
-       }
-
-       public void set(AltosRomconfig config) {
-               if (config != null && config.valid()) {
-                       set_serial(config.serial_number);
-                       set_radio_calibration(config.radio_calibration);
-               }
-       }
-
-       AltosRomconfig romconfig() {
-               try {
-                       return new AltosRomconfig(serial(), radio_calibration());
-               } catch (NumberFormatException ne) {
-                       return null;
-               }
-       }
-
-       public AltosRomconfig showDialog() {
-               setVisible(true);
-               if (selected)
-                       return romconfig();
-               return null;
-       }
-
-       public static AltosRomconfig show(JFrame frame, AltosRomconfig config) {
-               AltosRomconfigUI ui = new AltosRomconfigUI(frame, config);
-               return ui.showDialog();
-       }
-}
diff --git a/altosui/AltosScanUI.java b/altosui/AltosScanUI.java
deleted file mode 100644 (file)
index e4a9336..0000000
+++ /dev/null
@@ -1,551 +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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.event.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.util.concurrent.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-class AltosScanResult {
-       String          callsign;
-       int             serial;
-       int             flight;
-       AltosFrequency  frequency;
-       int             telemetry;
-       
-       boolean interrupted = false;
-       
-       public String toString() {
-               return String.format("%-9.9s serial %-4d flight %-4d (%s %s)",
-                                    callsign, serial, flight, frequency.toShortString(), Altos.telemetry_name(telemetry));
-       }
-
-       public String toShortString() {
-               return String.format("%s %d %d %7.3f %d",
-                                    callsign, serial, flight, frequency, telemetry);
-       }
-
-       public AltosScanResult(String in_callsign, int in_serial,
-                              int in_flight, AltosFrequency in_frequency, int in_telemetry) {
-               callsign = in_callsign;
-               serial = in_serial;
-               flight = in_flight;
-               frequency = in_frequency;
-               telemetry = in_telemetry;
-       }
-
-       public boolean equals(AltosScanResult other) {
-               return (serial == other.serial &&
-                       frequency.frequency == other.frequency.frequency &&
-                       telemetry == other.telemetry);
-       }
-
-       public boolean up_to_date(AltosScanResult other) {
-               if (flight == 0 && other.flight != 0) {
-                       flight = other.flight;
-                       return false;
-               }
-               if (callsign.equals("N0CALL") && !other.callsign.equals("N0CALL")) {
-                       callsign = other.callsign;
-                       return false;
-               }
-               return true;
-       }
-}
-
-class AltosScanResults extends LinkedList<AltosScanResult> implements ListModel {
-       
-       LinkedList<ListDataListener>    listeners = new LinkedList<ListDataListener>();
-
-       void changed(ListDataEvent de) {
-               for (ListDataListener l : listeners)
-                       l.contentsChanged(de);
-       }
-
-       public boolean add(AltosScanResult r) {
-               int i = 0;
-               for (AltosScanResult old : this) {
-                       if (old.equals(r)) {
-                               if (!old.up_to_date(r))
-                                       changed (new ListDataEvent(this,
-                                                                  ListDataEvent.CONTENTS_CHANGED,
-                                                                  i, i));
-                               return true;
-                       }
-                       i++;
-               }
-
-               super.add(r);
-               changed(new ListDataEvent(this,
-                                         ListDataEvent.INTERVAL_ADDED,
-                                         this.size() - 2, this.size() - 1));
-               return true;
-       }
-
-       public void addListDataListener(ListDataListener l) {
-               listeners.add(l);
-       }
-       
-       public void removeListDataListener(ListDataListener l) {
-               listeners.remove(l);
-       }
-
-       public AltosScanResult getElementAt(int i) {
-               return this.get(i);
-       }
-
-       public int getSize() {
-               return this.size();
-       }
-}
-
-public class AltosScanUI
-       extends AltosUIDialog
-       implements ActionListener
-{
-       AltosUI                         owner;
-       AltosDevice                     device;
-       AltosConfigData                 config_data;
-       AltosTelemetryReader            reader;
-       private JList                   list;
-       private JLabel                  scanning_label;
-       private JLabel                  frequency_label;
-       private JLabel                  telemetry_label;
-       private JButton                 cancel_button;
-       private JButton                 monitor_button;
-       private JCheckBox[]             telemetry_boxes;
-       javax.swing.Timer               timer;
-       AltosScanResults                results = new AltosScanResults();
-
-       int                             telemetry;
-
-       final static int                timeout = 1200;
-       TelemetryHandler                handler;
-       Thread                          thread;
-       AltosFrequency[]                frequencies;
-       int                             frequency_index;
-
-       void scan_exception(Exception e) {
-               if (e instanceof FileNotFoundException) {
-                       JOptionPane.showMessageDialog(owner,
-                                                     ((FileNotFoundException) e).getMessage(),
-                                                     "Cannot open target device",
-                                                     JOptionPane.ERROR_MESSAGE);
-               } else if (e instanceof AltosSerialInUseException) {
-                       JOptionPane.showMessageDialog(owner,
-                                                     String.format("Device \"%s\" already in use",
-                                                                   device.toShortString()),
-                                                     "Device in use",
-                                                     JOptionPane.ERROR_MESSAGE);
-               } else if (e instanceof IOException) {
-                       IOException ee = (IOException) e;
-                       JOptionPane.showMessageDialog(owner,
-                                                     device.toShortString(),
-                                                     ee.getLocalizedMessage(),
-                                                     JOptionPane.ERROR_MESSAGE);
-               } else {
-                       JOptionPane.showMessageDialog(owner,
-                                                     String.format("Connection to \"%s\" failed",
-                                                                   device.toShortString()),
-                                                     "Connection Failed",
-                                                     JOptionPane.ERROR_MESSAGE);
-               }
-               close();
-       }
-
-       class TelemetryHandler implements Runnable {
-
-               public void run() {
-
-                       boolean interrupted = false;
-
-                       try {
-                               for (;;) {
-                                       try {
-                                               AltosState      state = reader.read();
-                                               if (state == null)
-                                                       continue;
-                                               if (state.flight != AltosLib.MISSING) {
-                                                       final AltosScanResult   result = new AltosScanResult(state.callsign,
-                                                                                                    state.serial,
-                                                                                                    state.flight,
-                                                                                                    frequencies[frequency_index],
-                                                                                                    telemetry);
-                                                       Runnable r = new Runnable() {
-                                                                       public void run() {
-                                                                               results.add(result);
-                                                                       }
-                                                               };
-                                                       SwingUtilities.invokeLater(r);
-                                               }
-                                       } catch (ParseException pp) {
-                                       } catch (AltosCRCException ce) {
-                                       }
-                               }
-                       } catch (InterruptedException ee) {
-                               interrupted = true;
-                       } catch (IOException ie) {
-                       } finally {
-                               reader.close(interrupted);
-                       }
-               }
-       }
-
-       void set_label() {
-               frequency_label.setText(String.format("Frequency: %s", frequencies[frequency_index].toString()));
-               telemetry_label.setText(String.format("Telemetry: %s", Altos.telemetry_name(telemetry)));
-       }
-
-       void set_telemetry() {
-               reader.set_telemetry(telemetry);
-       }
-       
-       void set_frequency() throws InterruptedException, TimeoutException {
-               reader.set_frequency(frequencies[frequency_index].frequency);
-               reader.reset();
-       }
-       
-       void next() throws InterruptedException, TimeoutException {
-               reader.set_monitor(false);
-               Thread.sleep(100);
-               ++frequency_index;
-               if (frequency_index >= frequencies.length ||
-                   !telemetry_boxes[telemetry - Altos.ao_telemetry_min].isSelected())
-               {
-                       frequency_index = 0;
-                       do {
-                               ++telemetry;
-                               if (telemetry > Altos.ao_telemetry_max)
-                                       telemetry = Altos.ao_telemetry_min;
-                       } while (!telemetry_boxes[telemetry - Altos.ao_telemetry_min].isSelected());
-                       set_telemetry();
-               }
-               set_frequency();
-               set_label();
-               reader.set_monitor(true);
-       }
-
-
-       void close() {
-               if (thread != null && thread.isAlive()) {
-                       thread.interrupt();
-                       try {
-                               thread.join();
-                       } catch (InterruptedException ie) {}
-               }
-               thread = null;
-               if (timer != null)
-                       timer.stop();
-               setVisible(false);
-               dispose();
-       }
-
-       void tick_timer() throws InterruptedException, TimeoutException {
-               next();
-       }
-
-       public void actionPerformed(ActionEvent e) {
-               String cmd = e.getActionCommand();
-
-               try {
-                       if (cmd.equals("cancel"))
-                               close();
-
-                       if (cmd.equals("tick"))
-                               tick_timer();
-
-                       if (cmd.equals("telemetry")) {
-                               int k;
-                               int scanning_telemetry = 0;
-                               for (k = Altos.ao_telemetry_min; k <= Altos.ao_telemetry_max; k++) {
-                                       int j = k - Altos.ao_telemetry_min;
-                                       if (telemetry_boxes[j].isSelected())
-                                               scanning_telemetry |= (1 << k);
-                               }
-                               if (scanning_telemetry == 0) {
-                                       scanning_telemetry |= (1 << Altos.ao_telemetry_standard);
-                                       telemetry_boxes[Altos.ao_telemetry_standard - Altos.ao_telemetry_min].setSelected(true);
-                               }
-                               AltosUIPreferences.set_scanning_telemetry(scanning_telemetry);
-                       }
-
-                       if (cmd.equals("monitor")) {
-                               close();
-                               AltosScanResult r = (AltosScanResult) (list.getSelectedValue());
-                               if (r != null) {
-                                       if (device != null) {
-                                               if (reader != null) {
-                                                       reader.set_telemetry(r.telemetry);
-                                                       reader.set_frequency(r.frequency.frequency);
-                                                       reader.save_frequency();
-                                                       owner.telemetry_window(device);
-                                               }
-                                       }
-                               }
-                       }
-               } catch (TimeoutException te) {
-                       close();
-               } catch (InterruptedException ie) {
-                       close();
-               }
-       }
-
-       /* A window listener to catch closing events and tell the config code */
-       class ConfigListener extends WindowAdapter {
-               AltosScanUI     ui;
-
-               public ConfigListener(AltosScanUI this_ui) {
-                       ui = this_ui;
-               }
-
-               public void windowClosing(WindowEvent e) {
-                       ui.actionPerformed(new ActionEvent(e.getSource(),
-                                                          ActionEvent.ACTION_PERFORMED,
-                                                          "close"));
-               }
-       }
-
-       private boolean open() {
-               device = AltosDeviceUIDialog.show(owner, Altos.product_basestation);
-               if (device == null)
-                       return false;
-               try {
-                       reader = new AltosTelemetryReader(new AltosSerial(device));
-                       set_frequency();
-                       set_telemetry();
-                       try {
-                               Thread.sleep(100);
-                       } catch (InterruptedException ie) {
-                       }
-                       reader.flush();
-                       handler = new TelemetryHandler();
-                       thread = new Thread(handler);
-                       thread.start();
-                       return true;
-               } catch (FileNotFoundException ee) {
-                       JOptionPane.showMessageDialog(owner,
-                                                     ee.getMessage(),
-                                                     "Cannot open target device",
-                                                     JOptionPane.ERROR_MESSAGE);
-               } catch (AltosSerialInUseException si) {
-                       JOptionPane.showMessageDialog(owner,
-                                                     String.format("Device \"%s\" already in use",
-                                                                   device.toShortString()),
-                                                     "Device in use",
-                                                     JOptionPane.ERROR_MESSAGE);
-               } catch (IOException ee) {
-                       JOptionPane.showMessageDialog(owner,
-                                                     device.toShortString(),
-                                                     "Unkonwn I/O error",
-                                                     JOptionPane.ERROR_MESSAGE);
-               } catch (TimeoutException te) {
-                       JOptionPane.showMessageDialog(owner,
-                                                     device.toShortString(),
-                                                     "Timeout error",
-                                                     JOptionPane.ERROR_MESSAGE);
-               } catch (InterruptedException ie) {
-                       JOptionPane.showMessageDialog(owner,
-                                                     device.toShortString(),
-                                                     "Interrupted exception",
-                                                     JOptionPane.ERROR_MESSAGE);
-               }
-               if (reader != null)
-                       reader.close(false);
-               return false;
-       }
-
-       public AltosScanUI(AltosUI in_owner) {
-
-               owner = in_owner;
-
-               frequencies = AltosUIPreferences.common_frequencies();
-               frequency_index = 0;
-               telemetry = Altos.ao_telemetry_min;
-
-               if (!open())
-                       return;
-
-               Container               pane = getContentPane();
-               GridBagConstraints      c = new GridBagConstraints();
-               Insets                  i = new Insets(4,4,4,4);
-
-               timer = new javax.swing.Timer(timeout, this);
-               timer.setActionCommand("tick");
-               timer.restart();
-
-               owner = in_owner;
-
-               pane.setLayout(new GridBagLayout());
-
-               scanning_label = new JLabel("Scanning:");
-               frequency_label = new JLabel("");
-               telemetry_label = new JLabel("");
-               
-               set_label();
-
-               c.fill = GridBagConstraints.HORIZONTAL;
-               c.anchor = GridBagConstraints.WEST;
-               c.insets = i;
-               c.weightx = 1;
-               c.weighty = 1;
-
-               c.gridx = 0;
-               c.gridy = 0;
-               c.gridwidth = 2;
-
-               pane.add(scanning_label, c);
-               c.gridy = 1;
-               pane.add(frequency_label, c);
-               c.gridy = 2;
-               pane.add(telemetry_label, c);
-
-               int     scanning_telemetry = AltosUIPreferences.scanning_telemetry();
-               telemetry_boxes = new JCheckBox[Altos.ao_telemetry_max - Altos.ao_telemetry_min + 1];
-               for (int k = Altos.ao_telemetry_min; k <= Altos.ao_telemetry_max; k++) {
-                       int j = k - Altos.ao_telemetry_min;
-                       telemetry_boxes[j] = new JCheckBox(AltosLib.telemetry_name(k));
-                       c.gridy = 3 + j;
-                       pane.add(telemetry_boxes[j], c);
-                       telemetry_boxes[j].setActionCommand("telemetry");
-                       telemetry_boxes[j].addActionListener(this);
-                       telemetry_boxes[j].setSelected((scanning_telemetry & (1 << k)) != 0);
-               }
-
-               int     y_offset = 3 + (Altos.ao_telemetry_max - Altos.ao_telemetry_min + 1);
-                               
-               list = new JList(results) {
-                               //Subclass JList to workaround bug 4832765, which can cause the
-                               //scroll pane to not let the user easily scroll up to the beginning
-                               //of the list.  An alternative would be to set the unitIncrement
-                               //of the JScrollBar to a fixed value. You wouldn't get the nice
-                               //aligned scrolling, but it should work.
-                               public int getScrollableUnitIncrement(Rectangle visibleRect,
-                                                                     int orientation,
-                                                                     int direction) {
-                                       int row;
-                                       if (orientation == SwingConstants.VERTICAL &&
-                                           direction < 0 && (row = getFirstVisibleIndex()) != -1) {
-                                               Rectangle r = getCellBounds(row, row);
-                                               if ((r.y == visibleRect.y) && (row != 0))  {
-                                                       Point loc = r.getLocation();
-                                                       loc.y--;
-                                                       int prevIndex = locationToIndex(loc);
-                                                       Rectangle prevR = getCellBounds(prevIndex, prevIndex);
-
-                                                       if (prevR == null || prevR.y >= r.y) {
-                                                               return 0;
-                                                       }
-                                                       return prevR.height;
-                                               }
-                                       }
-                                       return super.getScrollableUnitIncrement(
-                                               visibleRect, orientation, direction);
-                               }
-                       };
-
-               list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-               list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
-               list.setVisibleRowCount(-1);
-
-               list.addMouseListener(new MouseAdapter() {
-                                public void mouseClicked(MouseEvent e) {
-                                        if (e.getClickCount() == 2) {
-                                                monitor_button.doClick(); //emulate button click
-                                        }
-                                }
-                       });
-               JScrollPane listScroller = new JScrollPane(list);
-               listScroller.setPreferredSize(new Dimension(400, 80));
-               listScroller.setAlignmentX(LEFT_ALIGNMENT);
-
-               //Create a container so that we can add a title around
-               //the scroll pane.  Can't add a title directly to the
-               //scroll pane because its background would be white.
-               //Lay out the label and scroll pane from top to bottom.
-               JPanel listPane = new JPanel();
-               listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
-
-               JLabel label = new JLabel("Select Device");
-               label.setLabelFor(list);
-               listPane.add(label);
-               listPane.add(Box.createRigidArea(new Dimension(0,5)));
-               listPane.add(listScroller);
-               listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
-
-               c.fill = GridBagConstraints.BOTH;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 1;
-               c.weighty = 1;
-
-               c.gridx = 0;
-               c.gridy = y_offset;
-               c.gridwidth = 2;
-               c.anchor = GridBagConstraints.CENTER;
-
-               pane.add(listPane, c);
-
-               cancel_button = new JButton("Cancel");
-               cancel_button.addActionListener(this);
-               cancel_button.setActionCommand("cancel");
-
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 1;
-               c.weighty = 1;
-
-               c.gridx = 0;
-               c.gridy = y_offset + 1;
-               c.gridwidth = 1;
-               c.anchor = GridBagConstraints.CENTER;
-
-               pane.add(cancel_button, c);
-
-               monitor_button = new JButton("Monitor");
-               monitor_button.addActionListener(this);
-               monitor_button.setActionCommand("monitor");
-
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 1;
-               c.weighty = 1;
-
-               c.gridx = 1;
-               c.gridy = y_offset + 1;
-               c.gridwidth = 1;
-               c.anchor = GridBagConstraints.CENTER;
-
-               pane.add(monitor_button, c);
-
-               pack();
-               setLocationRelativeTo(owner);
-
-               addWindowListener(new ConfigListener(this));
-
-               setVisible(true);
-       }
-}
\ No newline at end of file
diff --git a/altosui/AltosSerial.java b/altosui/AltosSerial.java
deleted file mode 100644 (file)
index 2c5d2df..0000000
+++ /dev/null
@@ -1,210 +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.
- */
-
-/*
- * Deal with TeleDongle on a serial port
- */
-
-package altosui;
-
-import java.io.*;
-import java.util.*;
-import java.awt.*;
-import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-import libaltosJNI.*;
-
-/*
- * This class reads from the serial port and places each received
- * line in a queue. Dealing with that queue is left up to other
- * threads.
- */
-
-public class AltosSerial extends AltosLink  {
-
-       static java.util.List<String> devices_opened = Collections.synchronizedList(new LinkedList<String>());
-
-       AltosDevice device;
-       SWIGTYPE_p_altos_file altos;
-       Thread input_thread;
-       String line;
-       byte[] line_bytes;
-       int line_count;
-       Frame frame;
-
-       public int getchar() {
-               if (altos == null)
-                       return ERROR;
-               return libaltos.altos_getchar(altos, 0);
-       }
-
-       public void flush_output() {
-               super.flush_output();
-               if (altos != null) {
-                       if (libaltos.altos_flush(altos) != 0)
-                               close_serial();
-               }
-       }
-
-       JDialog         timeout_dialog;
-
-       private void start_timeout_dialog_internal() {
-
-               Object[] options = { "Cancel" };
-
-               JOptionPane     pane = new JOptionPane();
-               pane.setMessage(String.format("Connecting to %s, %7.3f MHz as %s", device.toShortString(), frequency, callsign));
-               pane.setOptions(options);
-               pane.setInitialValue(null);
-
-               timeout_dialog = pane.createDialog(frame, "Connecting...");
-
-               timeout_dialog.setVisible(true);
-
-               Object o = pane.getValue();
-               if (o == null)
-                       return;
-               if (options[0].equals(o))
-                       reply_abort = true;
-               timeout_dialog.dispose();
-               timeout_dialog = null;
-       }
-
-       /*
-        * These are required by the AltosLink implementation
-        */
-
-       public boolean can_cancel_reply() {
-               /*
-                * Can cancel any replies not called from the dispatch thread
-                */
-               return !SwingUtilities.isEventDispatchThread();
-       }
-
-       public boolean show_reply_timeout() {
-               if (!SwingUtilities.isEventDispatchThread() && frame != null) {
-                       Runnable r = new Runnable() {
-                                       public void run() {
-                                               start_timeout_dialog_internal();
-                                       }
-                               };
-                       SwingUtilities.invokeLater(r);
-                       return true;
-               }
-               return false;
-       }
-
-       public void hide_reply_timeout() {
-               Runnable r = new Runnable() {
-                               public void run() {
-                                       timeout_dialog.setVisible(false);
-                               }
-                       };
-               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 {
-                               stop_remote();
-                       } catch (InterruptedException ie) {
-                       }
-               }
-               if (in_reply != 0)
-                       System.out.printf("Uh-oh. Closing active serial device\n");
-
-               close_serial();
-
-               if (input_thread != null) {
-                       try {
-                               input_thread.interrupt();
-                               input_thread.join();
-                       } catch (InterruptedException ie) {
-                       }
-                       input_thread = null;
-               }
-               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)
-                               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) {
-               for (int i = 0; i < data.length(); i++)
-                       putc(data.charAt(i));
-       }
-
-       private void open() throws FileNotFoundException, AltosSerialInUseException {
-               synchronized (devices_opened) {
-                       if (devices_opened.contains(device.getPath()))
-                               throw new AltosSerialInUseException(device);
-                       devices_opened.add(device.getPath());
-               }
-               altos = device.open();
-               if (altos == null) {
-                       final String    message = device.getErrorString();
-                       close();
-                       throw new FileNotFoundException(String.format("%s (%s)",
-                                                                     device.toShortString(), message));
-               }
-               if (debug)
-                       System.out.printf("Open %s\n", device.getPath());
-               input_thread = new Thread(this);
-               input_thread.start();
-               print("~\nE 0\n");
-               set_monitor(false);
-               flush_output();
-       }
-
-       public void set_frame(Frame in_frame) {
-               frame = in_frame;
-       }
-
-       public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
-               device = in_device;
-               frame = null;
-               serial = device.getSerial();
-               name = device.toShortString();
-               open();
-       }
-}
diff --git a/altosui/AltosSerialInUseException.java b/altosui/AltosSerialInUseException.java
deleted file mode 100644 (file)
index b45d915..0000000
+++ /dev/null
@@ -1,27 +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 org.altusmetrum.altosuilib_1.*;
-
-public class AltosSerialInUseException extends Exception {
-       public AltosDevice      device;
-
-       public AltosSerialInUseException (AltosDevice in_device) {
-               device = in_device;
-       }
-}
diff --git a/altosui/AltosSiteMap.java b/altosui/AltosSiteMap.java
deleted file mode 100644 (file)
index 105afad..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public 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 javax.swing.*;
-import java.io.*;
-import java.lang.Math;
-import java.awt.geom.Point2D;
-import java.util.concurrent.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosSiteMap extends JScrollPane implements AltosFlightDisplay {
-       // preferred vertical step in a tile in naut. miles
-       // will actually choose a step size between x and 2x, where this
-       // is 1.5x
-       static final double tile_size_nmi = 0.75;
-
-       static final int px_size = 512;
-
-       static final int MAX_TILE_DELTA = 100;
-
-       private static Point2D.Double translatePoint(Point2D.Double p,
-                       Point2D.Double d)
-       {
-               return new Point2D.Double(p.x + d.x, p.y + d.y);
-       }
-
-       static class LatLng {
-               public double lat, lng;
-               public LatLng(double lat, double lng) {
-                       this.lat = lat;
-                       this.lng = lng;
-               }
-       }
-
-       // based on google js
-       //  http://maps.gstatic.com/intl/en_us/mapfiles/api-3/2/10/main.js
-       // search for fromLatLngToPoint and fromPointToLatLng
-       /*
-       private static Point2D.Double pt(LatLng latlng, int zoom) {
-               double scale_x = 256/360.0 * Math.pow(2, zoom);
-               double scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom);
-               return pt(latlng, scale_x, scale_y);
-       }
-       */
-
-       private static Point2D.Double pt(LatLng latlng,
-                                        double scale_x, double scale_y)
-       {
-               Point2D.Double res = new Point2D.Double();
-               double e;
-
-               res.x = latlng.lng * scale_x;
-
-               e = Math.sin(Math.toRadians(latlng.lat));
-               e = Math.max(e,-(1-1.0E-15));
-               e = Math.min(e,  1-1.0E-15 );
-
-               res.y = 0.5*Math.log((1+e)/(1-e))*-scale_y;
-               return res;
-       }
-
-       static private LatLng latlng(Point2D.Double pt,
-                                    double scale_x, double scale_y)
-       {
-               double lat, lng;
-               double rads;
-
-               lng = pt.x/scale_x;
-               rads = 2 * Math.atan(Math.exp(-pt.y/scale_y));
-               lat = Math.toDegrees(rads - Math.PI/2);
-
-               return new LatLng(lat,lng);
-       }
-
-       int zoom;
-       double scale_x, scale_y;
-
-       int radius;     /* half width/height of tiles to load */
-
-       private Point2D.Double pt(double lat, double lng) {
-               return pt(new LatLng(lat, lng), scale_x, scale_y);
-       }
-
-       private LatLng latlng(double x, double y) {
-               return latlng(new Point2D.Double(x,y), scale_x, scale_y);
-       }
-       /*
-       private LatLng latlng(Point2D.Double pt) {
-               return latlng(pt, scale_x, scale_y);
-       }
-       */
-
-       ConcurrentHashMap<Point,AltosSiteMapTile> mapTiles = new ConcurrentHashMap<Point,AltosSiteMapTile>();
-       Point2D.Double centre;
-
-       private Point2D.Double tileCoordOffset(Point p) {
-               return new Point2D.Double(centre.x - p.x*px_size,
-                                         centre.y - p.y * px_size);
-       }
-
-       private Point tileOffset(Point2D.Double p) {
-               return new Point((int)Math.floor((centre.x+p.x)/px_size),
-                                (int)Math.floor((centre.y+p.y)/px_size));
-       }
-
-       private Point2D.Double getBaseLocation(double lat, double lng) {
-               Point2D.Double locn, north_step;
-
-               zoom = 2;
-               // stupid loop structure to please Java's control flow analysis
-               do {
-                       zoom++;
-                       scale_x = 256/360.0 * Math.pow(2, zoom);
-                       scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom);
-                       locn = pt(lat, lng);
-                       north_step = pt(lat+tile_size_nmi*4/3/60.0, lng);
-                       if (locn.y - north_step.y > px_size)
-                               break;
-               } while (zoom < 22);
-               locn.x = -px_size * Math.floor(locn.x/px_size);
-               locn.y = -px_size * Math.floor(locn.y/px_size);
-               return locn;
-       }
-
-       public void reset() {
-               // nothing
-       }
-
-       public void set_font() {
-               // nothing
-       }
-
-       private void loadMap(final AltosSiteMapTile tile,
-                            File pngfile, String pngurl)
-       {
-               final ImageIcon res = AltosSiteMapCache.fetchAndLoadMap(pngfile, pngurl);
-               if (res != null) {
-                       SwingUtilities.invokeLater(new Runnable() {
-                                       public void run() {
-                                               tile.loadMap(res);
-                                       }
-                               });
-               } else {
-                       System.out.printf("# Failed to fetch file %s\n", pngfile);
-                       System.out.printf(" wget -O '%s' '%s'\n", pngfile, pngurl);
-               }
-       }
-
-       File pngfile;
-       String pngurl;
-
-       public int prefetchMap(int x, int y) {
-               LatLng map_latlng = latlng(
-                       -centre.x + x*px_size + px_size/2,
-                       -centre.y + y*px_size + px_size/2);
-               pngfile = MapFile(map_latlng.lat, map_latlng.lng, zoom);
-               pngurl = MapURL(map_latlng.lat, map_latlng.lng, zoom);
-               if (pngfile.exists()) {
-                       return 1;
-               } else if (AltosSiteMapCache.fetchMap(pngfile, pngurl)) {
-                       return 0;
-               } else {
-                       return -1;
-               }
-       }
-
-       public static void prefetchMaps(double lat, double lng) {
-               int w = AltosSiteMapPreload.width;
-               int h = AltosSiteMapPreload.height;
-               AltosSiteMap asm = new AltosSiteMap(true);
-               asm.centre = asm.getBaseLocation(lat, lng);
-
-               //Point2D.Double p = new Point2D.Double();
-               //Point2D.Double p2;
-               int dx = -w/2, dy = -h/2;
-               for (int y = dy; y < h+dy; y++) {
-                       for (int x = dx; x < w+dx; x++) {
-                               int r = asm.prefetchMap(x, y);
-                               switch (r) {
-                               case 1:
-                                       System.out.printf("Already have %s\n", asm.pngfile);
-                                       break;
-                               case 0:
-                                       System.out.printf("Fetched map %s\n", asm.pngfile);
-                                       break;
-                               case -1:
-                                       System.out.printf("# Failed to fetch file %s\n", asm.pngfile);
-                                       System.out.printf(" wget -O '%s' ''\n", asm.pngfile, asm.pngurl);
-                                       break;
-                               }
-                       }
-               }
-       }
-
-       public String initMap(Point offset) {
-               AltosSiteMapTile tile = mapTiles.get(offset);
-               Point2D.Double coord = tileCoordOffset(offset);
-
-               LatLng map_latlng = latlng(px_size/2-coord.x, px_size/2-coord.y);
-
-               File pngfile = MapFile(map_latlng.lat, map_latlng.lng, zoom);
-               String pngurl = MapURL(map_latlng.lat, map_latlng.lng, zoom);
-               loadMap(tile, pngfile, pngurl);
-               return pngfile.toString();
-       }
-
-       public void initAndFinishMapAsync (final AltosSiteMapTile tile, final Point offset) {
-               Thread thread = new Thread() {
-                               public void run() {
-                                       initMap(offset);
-                                       finishTileLater(tile, offset);
-                               }
-                       };
-               thread.start();
-       }
-
-       public void setBaseLocation(double lat, double lng) {
-               for (Point k : mapTiles.keySet()) {
-                       AltosSiteMapTile tile = mapTiles.get(k);
-                       tile.clearMap();
-               }
-                       
-               centre = getBaseLocation(lat, lng);
-               scrollRocketToVisible(pt(lat,lng));
-       }
-
-       private void initMaps(double lat, double lng) {
-               setBaseLocation(lat, lng);
-
-               Thread thread = new Thread() {
-                               public void run() {
-                                       for (Point k : mapTiles.keySet())
-                                               initMap(k);
-                               }
-                       };
-               thread.start();
-       }
-
-       private static File MapFile(double lat, double lng, int zoom) {
-               char chlat = lat < 0 ? 'S' : 'N';
-               char chlng = lng < 0 ? 'W' : 'E';
-               if (lat < 0) lat = -lat;
-               if (lng < 0) lng = -lng;
-               return new File(AltosUIPreferences.mapdir(),
-                               String.format("map-%c%.6f,%c%.6f-%d.png",
-                                             chlat, lat, chlng, lng, zoom));
-       }
-
-       private static String MapURL(double lat, double lng, int zoom) {
-               return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=hybrid&format=png32", lat, lng, zoom, px_size, px_size);
-       }
-
-       boolean initialised = false;
-       Point2D.Double last_pt = null;
-       int last_state = -1;
-
-       public void show(double lat, double 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
-               AltosGPS        gps = state.gps;
-
-               if (gps == null)
-                       return;
-
-               if (!gps.locked && gps.nsat < 4)
-                       return;
-
-               if (!initialised) {
-                       if (state.pad_lat != AltosLib.MISSING && state.pad_lon != AltosLib.MISSING) {
-                               initMaps(state.pad_lat, state.pad_lon);
-                               initialised = true;
-                       } else if (gps.lat != AltosLib.MISSING && gps.lon != AltosLib.MISSING) {
-                               initMaps(gps.lat, gps.lon);
-                               initialised = true;
-                       } else {
-                               return;
-                       }
-               }
-
-               final Point2D.Double pt = pt(gps.lat, gps.lon);
-               if (last_pt == pt && last_state == state.state)
-                       return;
-
-               if (last_pt == null) {
-                       last_pt = pt;
-               }
-               boolean in_any = false;
-               for (Point offset : mapTiles.keySet()) {
-                       AltosSiteMapTile tile = mapTiles.get(offset);
-                       Point2D.Double ref, lref;
-                       ref = translatePoint(pt, tileCoordOffset(offset));
-                       lref = translatePoint(last_pt, tileCoordOffset(offset));
-                       tile.show(state, listener_state, lref, ref);
-                       if (0 <= ref.x && ref.x < px_size)
-                               if (0 <= ref.y && ref.y < px_size)
-                                       in_any = true;
-               }
-
-               Point offset = tileOffset(pt);
-               if (!in_any) {
-                       Point2D.Double ref, lref;
-                       ref = translatePoint(pt, tileCoordOffset(offset));
-                       lref = translatePoint(last_pt, tileCoordOffset(offset));
-
-                       AltosSiteMapTile tile = createTile(offset);
-                       tile.show(state, listener_state, lref, ref);
-                       initAndFinishMapAsync(tile, offset);
-               }
-
-               scrollRocketToVisible(pt);
-
-               if (offset != tileOffset(last_pt)) {
-                       ensureTilesAround(offset);
-               }
-
-               last_pt = pt;
-               last_state = state.state;
-       }
-
-       public void centre(Point2D.Double pt) {
-               Rectangle r = comp.getVisibleRect();
-               Point2D.Double copt = translatePoint(pt, tileCoordOffset(topleft));
-               int dx = (int)copt.x - r.width/2 - r.x;
-               int dy = (int)copt.y - r.height/2 - r.y;
-               r.x += dx;
-               r.y += dy;
-               comp.scrollRectToVisible(r);
-       }
-
-       public void centre(AltosState state) {
-               if (!state.gps.locked && state.gps.nsat < 4)
-                       return;
-               centre(pt(state.gps.lat, state.gps.lon));
-       }
-
-       public void draw_circle(double lat, double lon) {
-               final Point2D.Double pt = pt(lat, lon);
-
-               for (Point offset : mapTiles.keySet()) {
-                       AltosSiteMapTile tile = mapTiles.get(offset);
-                       Point2D.Double ref = translatePoint(pt, tileCoordOffset(offset));
-                       tile.draw_circle(ref);
-               }
-       }
-
-       private AltosSiteMapTile createTile(Point offset) {
-               AltosSiteMapTile tile = new AltosSiteMapTile(px_size);
-               mapTiles.put(offset, tile);
-               return tile;
-       }
-       private void finishTileLater(final AltosSiteMapTile tile,
-                                    final Point offset)
-       {
-               SwingUtilities.invokeLater( new Runnable() {
-                       public void run() {
-                               addTileAt(tile, offset);
-                       }
-               } );
-       }
-
-       private void ensureTilesAround(Point base_offset) {
-               for (int x = -radius; x <= radius; x++) {
-                       for (int y = -radius; y <= radius; y++) {
-                               Point offset = new Point(base_offset.x + x, base_offset.y + y);
-                               if (mapTiles.containsKey(offset))
-                                       continue;
-                               AltosSiteMapTile tile = createTile(offset);
-                               initAndFinishMapAsync(tile, offset);
-                       }
-               }
-       }
-
-       private Point topleft = new Point(0,0);
-       private void scrollRocketToVisible(Point2D.Double pt) {
-               Rectangle r = comp.getVisibleRect();
-               Point2D.Double copt = translatePoint(pt, tileCoordOffset(topleft));
-               int dx = (int)copt.x - r.width/2 - r.x;
-               int dy = (int)copt.y - r.height/2 - r.y;
-               if (Math.abs(dx) > r.width/4 || Math.abs(dy) > r.height/4) {
-                       r.x += dx;
-                       r.y += dy;
-                       comp.scrollRectToVisible(r);
-               }
-       }
-
-       private void addTileAt(AltosSiteMapTile tile, Point offset) {
-               if (Math.abs(offset.x) >= MAX_TILE_DELTA ||
-                               Math.abs(offset.y) >= MAX_TILE_DELTA)
-               {
-                       System.out.printf("Rocket too far away from pad (tile %d,%d)\n",
-                                         offset.x, offset.y);
-                       return;
-               }
-
-               boolean review = false;
-               Rectangle r = comp.getVisibleRect();
-               if (offset.x < topleft.x) {
-                       r.x += (topleft.x - offset.x) * px_size;
-                       topleft.x = offset.x;
-                       review = true;
-               }
-               if (offset.y < topleft.y) {
-                       r.y += (topleft.y - offset.y) * px_size;
-                       topleft.y = offset.y;
-                       review = true;
-               }
-               GridBagConstraints c = new GridBagConstraints();
-               c.anchor = GridBagConstraints.CENTER;
-               c.fill = GridBagConstraints.BOTH;
-               // put some space between the map tiles, debugging only
-               // c.insets = new Insets(5, 5, 5, 5);
-
-               c.gridx = offset.x + MAX_TILE_DELTA;
-               c.gridy = offset.y + MAX_TILE_DELTA;
-               layout.setConstraints(tile, c);
-
-               comp.add(tile);
-               if (review) {
-                       comp.scrollRectToVisible(r);
-               }
-       }
-
-       private AltosSiteMap(boolean knowWhatYouAreDoing) {
-               if (!knowWhatYouAreDoing) {
-                       throw new RuntimeException("Arggh.");
-               }
-       }
-
-       JComponent comp = new JComponent() { };
-       private GridBagLayout layout = new GridBagLayout();
-
-       public AltosSiteMap(int in_radius) {
-               radius = in_radius;
-
-               GrabNDrag scroller = new GrabNDrag(comp);
-
-               comp.setLayout(layout);
-
-               for (int x = -radius; x <= radius; x++) {
-                       for (int y = -radius; y <= radius; y++) {
-                               Point offset = new Point(x, y);
-                               AltosSiteMapTile t = createTile(offset);
-                               addTileAt(t, offset);
-                       }
-               }
-               setViewportView(comp);
-               setPreferredSize(new Dimension(500,500));
-       }
-
-       public AltosSiteMap() {
-               this(1);
-       }
-}
diff --git a/altosui/AltosSiteMapCache.java b/altosui/AltosSiteMapCache.java
deleted file mode 100644 (file)
index 03dc3cf..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public 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 javax.swing.*;
-import javax.imageio.ImageIO;
-import java.awt.image.*;
-import java.io.*;
-import java.net.URL;
-import java.net.URLConnection;
-
-public class AltosSiteMapCache extends JLabel {
-       static final long google_maps_ratelimit_ms = 1200;
-       // Google limits static map queries to 50 per minute per IP, so
-       // each query should take at least 1.2 seconds.
-
-       public static boolean fetchMap(File file, String url) {
-               URL u;
-               long startTime = System.nanoTime();
-
-               try {
-                       u = new URL(url);
-               } catch (java.net.MalformedURLException e) {
-                       return false;
-               }
-
-               byte[] data;
-               try {
-                       URLConnection uc = u.openConnection();
-                       int contentLength = uc.getContentLength();
-                       InputStream in = new BufferedInputStream(uc.getInputStream());
-                       int bytesRead = 0;
-                       int offset = 0;
-                       data = new byte[contentLength];
-                       while (offset < contentLength) {
-                               bytesRead = in.read(data, offset, data.length - offset);
-                               if (bytesRead == -1)
-                                       break;
-                               offset += bytesRead;
-                       }
-                       in.close();
-
-                       if (offset != contentLength) {
-                               return false;
-                       }
-               } catch (IOException e) {
-                       return false;
-               }
-
-               try {
-                       FileOutputStream out = new FileOutputStream(file);
-                       out.write(data);
-                       out.flush();
-                       out.close();
-               } catch (FileNotFoundException e) {
-                       return false;
-               } catch (IOException e) {
-                       if (file.exists()) {
-                               file.delete();
-                       }
-                       return false;
-               }
-
-               long duration_ms = (System.nanoTime() - startTime) / 1000000;
-               if (duration_ms < google_maps_ratelimit_ms) {
-                       try {
-                               Thread.sleep(google_maps_ratelimit_ms - duration_ms);
-                       } catch (InterruptedException e) {
-                               Thread.currentThread().interrupt();
-                       }
-               }
-
-               return true;
-       }
-
-       public static ImageIcon fetchAndLoadMap(File pngfile, String url) {
-               if (!pngfile.exists()) {
-                       if (!fetchMap(pngfile, url)) {
-                               return null;
-                       }
-               }
-               return loadMap(pngfile, url);
-       }
-
-       public static ImageIcon loadMap(File pngfile, String url) {
-               if (!pngfile.exists()) {
-                       return null;
-               }
-
-               try {
-                       BufferedImage   img;
-
-                       img = ImageIO.read(pngfile);
-                       if (img == null) {
-                               System.out.printf("# Can't read pngfile %s\n", pngfile);
-                               return null;
-                       }
-                       return new ImageIcon(img);
-               } catch (IOException e) {
-                       System.out.printf("# IO error trying to load %s\n", pngfile);
-                       return null;
-               }
-       }
-}
diff --git a/altosui/AltosSiteMapPreload.java b/altosui/AltosSiteMapPreload.java
deleted file mode 100644 (file)
index 6639955..0000000
+++ /dev/null
@@ -1,467 +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.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import java.io.*;
-import java.util.*;
-import java.text.*;
-import java.lang.Math;
-import java.net.URL;
-import java.net.URLConnection;
-import org.altusmetrum.altosuilib_1.*;
-
-class AltosMapPos extends Box {
-       AltosUI         owner;
-       JLabel          label;
-       JComboBox       hemi;
-       JTextField      deg;
-       JLabel          deg_label;
-       JTextField      min;
-       JLabel          min_label;
-
-       public void set_value(double new_value) {
-               double  d, m;
-               int     h;
-
-               h = 0;
-               if (new_value < 0) {
-                       h = 1;
-                       new_value = -new_value;
-               }
-               d = Math.floor(new_value);
-               deg.setText(String.format("%3.0f", d));
-               m = (new_value - d) * 60.0;
-               min.setText(String.format("%7.4f", m));
-               hemi.setSelectedIndex(h);
-       }
-
-       public double get_value() throws NumberFormatException {
-               int     h = hemi.getSelectedIndex();
-               String  d_t = deg.getText();
-               String  m_t = min.getText();
-               double  d, m, v;
-               try {
-                       d = Double.parseDouble(d_t);
-               } catch (NumberFormatException ne) {
-                       JOptionPane.showMessageDialog(owner,
-                                                     String.format("Invalid degrees \"%s\"",
-                                                                   d_t),
-                                                     "Invalid number",
-                                                     JOptionPane.ERROR_MESSAGE);
-                       throw ne;
-               }
-               try {
-                       if (m_t.equals(""))
-                               m = 0;
-                       else
-                               m = Double.parseDouble(m_t);
-               } catch (NumberFormatException ne) {
-                       JOptionPane.showMessageDialog(owner,
-                                                     String.format("Invalid minutes \"%s\"",
-                                                                   m_t),
-                                                     "Invalid number",
-                                                     JOptionPane.ERROR_MESSAGE);
-                       throw ne;
-               }
-               v = d + m/60.0;
-               if (h == 1)
-                       v = -v;
-               return v;
-       }
-
-       public AltosMapPos(AltosUI in_owner,
-                          String label_value,
-                          String[] hemi_names,
-                          double default_value) {
-               super(BoxLayout.X_AXIS);
-               owner = in_owner;
-               label = new JLabel(label_value);
-               hemi = new JComboBox(hemi_names);
-               hemi.setEditable(false);
-               deg = new JTextField(5);
-               deg.setMinimumSize(deg.getPreferredSize());
-               deg.setHorizontalAlignment(JTextField.RIGHT);
-               deg_label = new JLabel("°");
-               min = new JTextField(9);
-               min.setMinimumSize(min.getPreferredSize());
-               min_label = new JLabel("'");
-               set_value(default_value);
-               add(label);
-               add(Box.createRigidArea(new Dimension(5, 0)));
-               add(hemi);
-               add(Box.createRigidArea(new Dimension(5, 0)));
-               add(deg);
-               add(Box.createRigidArea(new Dimension(5, 0)));
-               add(deg_label);
-               add(Box.createRigidArea(new Dimension(5, 0)));
-               add(min);
-               add(Box.createRigidArea(new Dimension(5, 0)));
-               add(min_label);
-       }
-}
-
-class AltosSite {
-       String  name;
-       double  latitude;
-       double  longitude;
-
-       public String toString() {
-               return name;
-       }
-
-       public AltosSite(String in_name, double in_latitude, double in_longitude) {
-               name = in_name;
-               latitude = in_latitude;
-               longitude = in_longitude;
-       }
-
-       public AltosSite(String line) throws ParseException {
-               String[]        elements = line.split(":");
-
-               if (elements.length < 3)
-                       throw new ParseException(String.format("Invalid site line %s", line), 0);
-
-               name = elements[0];
-
-               try {
-                       latitude = Double.parseDouble(elements[1]);
-                       longitude = Double.parseDouble(elements[2]);
-               } catch (NumberFormatException ne) {
-                       throw new ParseException(String.format("Invalid site line %s", line), 0);
-               }
-       }
-}
-
-class AltosSites extends Thread {
-       AltosSiteMapPreload     preload;
-       URL                     url;
-       LinkedList<AltosSite>   sites;
-
-       void notify_complete() {
-               SwingUtilities.invokeLater(new Runnable() {
-                               public void run() {
-                                       preload.set_sites();
-                               }
-                       });
-       }
-
-       void add(AltosSite site) {
-               sites.add(site);
-       }
-
-       void add(String line) {
-               try {
-                       add(new AltosSite(line));
-               } catch (ParseException pe) {
-               }
-       }
-
-       public void run() {
-               try {
-                       URLConnection uc = url.openConnection();
-                       //int length = uc.getContentLength();
-                       
-                       InputStreamReader in_stream = new InputStreamReader(uc.getInputStream(), Altos.unicode_set);
-                       BufferedReader in = new BufferedReader(in_stream);
-
-                       for (;;) {
-                               String line = in.readLine();
-                               if (line == null)
-                                       break;
-                               add(line);
-                       }
-               } catch (IOException e) {
-               } finally {
-                       notify_complete();
-               }
-       }
-
-       public AltosSites(AltosSiteMapPreload in_preload) {
-               sites = new LinkedList<AltosSite>();
-               preload = in_preload;
-               try {
-                       url = new URL(Altos.launch_sites_url);
-               } catch (java.net.MalformedURLException e) {
-                       notify_complete();
-               }
-               start();
-       }
-}
-
-public class AltosSiteMapPreload extends AltosUIDialog implements ActionListener, ItemListener {
-       AltosUI         owner;
-       AltosSiteMap    map;
-
-       AltosMapPos     lat;
-       AltosMapPos     lon;
-
-       final static int        radius = 5;
-       final static int        width = (radius * 2 + 1);
-       final static int        height = (radius * 2 + 1);
-
-       JProgressBar    pbar;
-
-       AltosSites      sites;
-       JLabel          site_list_label;
-       JComboBox       site_list;
-               
-       JToggleButton   load_button;
-       boolean         loading;
-       JButton         close_button;
-
-       static final String[]   lat_hemi_names = { "N", "S" };
-       static final String[]   lon_hemi_names = { "E", "W" };
-
-       class updatePbar implements Runnable {
-               int             n;
-               String          s;
-
-               public updatePbar(int x, int y, String in_s) {
-                       n = (x + radius) + (y + radius) * width + 1;
-                       s = in_s;
-               }
-
-               public void run() {
-                       pbar.setValue(n);
-                       pbar.setString(s);
-                       if (n < width * height) {
-                               pbar.setValue(n);
-                               pbar.setString(s);
-                       } else {
-                               pbar.setValue(0);
-                               pbar.setString("");
-                               load_button.setSelected(false);
-                               loading = false;
-                       }
-               }
-       }
-
-       class bgLoad extends Thread {
-
-               AltosSiteMap    map;
-
-               public bgLoad(AltosSiteMap in_map) {
-                       map = in_map;
-               }
-
-               public void run() {
-                       for (int y = -map.radius; y <= map.radius; y++) {
-                               for (int x = -map.radius; x <= map.radius; x++) {
-                                       String  pngfile;
-                                       pngfile = map.initMap(new Point(x,y));
-                                       SwingUtilities.invokeLater(new updatePbar(x, y, pngfile));
-                               }
-                       }
-               }
-       }
-
-       public void set_sites() {
-               int     i = 1;
-               for (AltosSite site : sites.sites) {
-                       site_list.insertItemAt(site, i);
-                       i++;
-               }
-       }
-
-       public void itemStateChanged(ItemEvent e) {
-               int             state = e.getStateChange();
-
-               if (state == ItemEvent.SELECTED) {
-                       Object  o = e.getItem();
-                       if (o instanceof AltosSite) {
-                               AltosSite       site = (AltosSite) o;
-                               lat.set_value(site.latitude);
-                               lon.set_value(site.longitude);
-                       }
-               }
-       }
-
-       public void actionPerformed(ActionEvent e) {
-               String  cmd = e.getActionCommand();
-
-               if (cmd.equals("close"))
-                       setVisible(false);
-
-               if (cmd.equals("load")) {
-                       if (!loading) {
-                               try {
-                                       final double    latitude = lat.get_value();
-                                       final double    longitude = lon.get_value();
-                                       map.setBaseLocation(latitude,longitude);
-                                       map.draw_circle(latitude,longitude);
-                                       loading = true;
-                                       bgLoad thread = new bgLoad(map);
-                                       thread.start();
-                               } catch (NumberFormatException ne) {
-                                       load_button.setSelected(false);
-                               }
-                       }
-               }
-       }
-
-       public AltosSiteMapPreload(AltosUI in_owner) {
-               owner = in_owner;
-
-               Container               pane = getContentPane();
-               GridBagConstraints      c = new GridBagConstraints();
-               Insets                  i = new Insets(4,4,4,4);
-
-               pane.setLayout(new GridBagLayout());
-
-               map = new AltosSiteMap(radius);
-
-               c.fill = GridBagConstraints.BOTH;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 1;
-               c.weighty = 1;
-
-               c.gridx = 0;
-               c.gridy = 0;
-               c.gridwidth = 2;
-               c.anchor = GridBagConstraints.CENTER;
-
-               pane.add(map, c);
-
-               pbar = new JProgressBar();
-               pbar.setMinimum(0);
-               pbar.setMaximum(width * height);
-               pbar.setValue(0);
-               pbar.setString("");
-               pbar.setStringPainted(true);
-               
-               c.fill = GridBagConstraints.HORIZONTAL;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 1;
-               c.weighty = 0;
-
-               c.gridx = 0;
-               c.gridy = 1;
-               c.gridwidth = 2;
-
-               pane.add(pbar, c);
-
-               site_list_label = new JLabel ("Known Launch Sites:");
-
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 1;
-               c.weighty = 0;
-
-               c.gridx = 0;
-               c.gridy = 2;
-               c.gridwidth = 1;
-
-               pane.add(site_list_label, c);
-               
-               site_list = new JComboBox(new String[] { "Site List" });
-               site_list.addItemListener(this);
-
-               sites = new AltosSites(this);
-
-               c.fill = GridBagConstraints.HORIZONTAL;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 1;
-               c.weighty = 0;
-
-               c.gridx = 1;
-               c.gridy = 2;
-               c.gridwidth = 1;
-
-               pane.add(site_list, c);
-               
-               lat = new AltosMapPos(owner,
-                                     "Latitude:",
-                                     lat_hemi_names,
-                                     37.167833333);
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 0;
-               c.weighty = 0;
-
-               c.gridx = 0;
-               c.gridy = 3;
-               c.gridwidth = 1;
-               c.anchor = GridBagConstraints.CENTER;
-
-               pane.add(lat, c);
-               
-               lon = new AltosMapPos(owner,
-                                     "Longitude:",
-                                     lon_hemi_names,
-                                     -97.73975);
-
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 0;
-               c.weighty = 0;
-
-               c.gridx = 1;
-               c.gridy = 3;
-               c.gridwidth = 1;
-               c.anchor = GridBagConstraints.CENTER;
-
-               pane.add(lon, c);
-
-               load_button = new JToggleButton("Load Map");
-               load_button.addActionListener(this);
-               load_button.setActionCommand("load");
-               
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 1;
-               c.weighty = 0;
-
-               c.gridx = 0;
-               c.gridy = 4;
-               c.gridwidth = 1;
-               c.anchor = GridBagConstraints.CENTER;
-
-               pane.add(load_button, c);
-
-               close_button = new JButton("Close");
-               close_button.addActionListener(this);
-               close_button.setActionCommand("close");
-               
-               c.fill = GridBagConstraints.NONE;
-               c.anchor = GridBagConstraints.CENTER;
-               c.insets = i;
-               c.weightx = 1;
-               c.weighty = 0;
-
-               c.gridx = 1;
-               c.gridy = 4;
-               c.gridwidth = 1;
-               c.anchor = GridBagConstraints.CENTER;
-
-               pane.add(close_button, c);
-
-               pack();
-               setLocationRelativeTo(owner);
-               setVisible(true);
-       }
-}
diff --git a/altosui/AltosSiteMapTile.java b/altosui/AltosSiteMapTile.java
deleted file mode 100644 (file)
index 7d5b65e..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public 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.image.*;
-import javax.swing.*;
-import java.awt.geom.Point2D;
-import java.awt.geom.Line2D;
-import org.altusmetrum.altoslib_3.*;
-
-public class AltosSiteMapTile extends JLayeredPane {
-       JLabel mapLabel;
-       JLabel draw;
-       Graphics2D g2d;
-       int px_size;
-
-       public void loadMap(ImageIcon icn) {
-               mapLabel.setIcon(icn);
-       }
-
-       public void clearMap() {
-               fillLabel(mapLabel, Color.GRAY, px_size);
-               g2d = fillLabel(draw, new Color(127,127,127,0), px_size);
-               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-                                    RenderingHints.VALUE_ANTIALIAS_ON);
-               g2d.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
-       }
-
-       static Color stateColors[] = {
-               Color.WHITE,  // startup
-               Color.WHITE,  // idle
-               Color.WHITE,  // pad
-               Color.RED,    // boost
-               Color.PINK,   // fast
-               Color.YELLOW, // coast
-               Color.CYAN,   // drogue
-               Color.BLUE,   // main
-               Color.BLACK   // landed
-       };
-
-       private boolean drawn_landed_circle = false;
-       private boolean drawn_boost_circle = false;
-       public synchronized void show(AltosState state, AltosListenerState listener_state,
-                                     Point2D.Double last_pt, Point2D.Double pt)
-       {
-               if (0 <= state.state && state.state < stateColors.length) {
-                       g2d.setColor(stateColors[state.state]);
-               }
-               g2d.draw(new Line2D.Double(last_pt, pt));
-
-               if (state.state == 3 && !drawn_boost_circle) {
-                       drawn_boost_circle = true;
-                       g2d.setColor(Color.RED);
-                       g2d.drawOval((int)last_pt.x-5, (int)last_pt.y-5, 10, 10);
-                       g2d.drawOval((int)last_pt.x-20, (int)last_pt.y-20, 40, 40);
-                       g2d.drawOval((int)last_pt.x-35, (int)last_pt.y-35, 70, 70);
-               }
-               if (state.state == 8 && !drawn_landed_circle) {
-                       drawn_landed_circle = true;
-                       g2d.setColor(Color.BLACK);
-                       g2d.drawOval((int)pt.x-5, (int)pt.y-5, 10, 10);
-                       g2d.drawOval((int)pt.x-20, (int)pt.y-20, 40, 40);
-                       g2d.drawOval((int)pt.x-35, (int)pt.y-35, 70, 70);
-               }
-
-               repaint();
-       }
-
-       public void draw_circle(Point2D.Double pt) {
-               g2d.setColor(Color.RED);
-               g2d.drawOval((int)pt.x-5, (int)pt.y-5, 10, 10);
-               g2d.drawOval((int)pt.x-20, (int)pt.y-20, 40, 40);
-               g2d.drawOval((int)pt.x-35, (int)pt.y-35, 70, 70);
-       }
-
-       public static Graphics2D fillLabel(JLabel l, Color c, int px_size) {
-               BufferedImage img = new BufferedImage(px_size, px_size,
-                                                     BufferedImage.TYPE_INT_ARGB);
-               Graphics2D g = img.createGraphics();
-               g.setColor(c);
-               g.fillRect(0, 0, px_size, px_size);
-               l.setIcon(new ImageIcon(img));
-               return g;
-       }
-
-       public AltosSiteMapTile(int in_px_size) {
-               px_size = in_px_size;
-               setPreferredSize(new Dimension(px_size, px_size));
-
-               mapLabel = new JLabel();
-               fillLabel(mapLabel, Color.GRAY, px_size);
-               mapLabel.setOpaque(true);
-               mapLabel.setBounds(0, 0, px_size, px_size);
-               add(mapLabel, new Integer(0));
-
-               draw = new JLabel();
-               g2d = fillLabel(draw, new Color(127, 127, 127, 0), px_size);
-               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-                                    RenderingHints.VALUE_ANTIALIAS_ON);
-               g2d.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
-               draw.setBounds(0, 0, px_size, px_size);
-               draw.setOpaque(false);
-
-               add(draw, new Integer(1));
-       }
-}
diff --git a/altosui/AltosUI.app/Contents/Resources/AltosUIIcon.icns b/altosui/AltosUI.app/Contents/Resources/AltosUIIcon.icns
deleted file mode 100644 (file)
index fe49f36..0000000
Binary files a/altosui/AltosUI.app/Contents/Resources/AltosUIIcon.icns and /dev/null differ
index 5d4599476ba44bd988e0b57a1f792fe12fd5dd6f..6137487c418cb0bf8fc414c292a00b2e77516dde 100644 (file)
@@ -22,8 +22,8 @@ import java.awt.event.*;
 import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class AltosUI extends AltosUIFrame {
        public AltosVoice voice = new AltosVoice();
@@ -74,6 +74,10 @@ public class AltosUI extends AltosUIFrame {
                }
        }
 
+       public void scan_device_selected(AltosDevice device) {
+               telemetry_window(device);
+       }
+
        Container       pane;
        GridBagLayout   gridbag;
 
@@ -233,7 +237,7 @@ public class AltosUI extends AltosUIFrame {
                });
 
                setLocationByPlatform(false);
-               
+
                /* Insets aren't set before the window is visible */
                setVisible(true);
        }
@@ -272,11 +276,11 @@ public class AltosUI extends AltosUIFrame {
        }
 
        void ScanChannels() {
-               new AltosScanUI(AltosUI.this);
+               new AltosScanUI(AltosUI.this, true);
        }
 
        void LoadMaps() {
-               new AltosSiteMapPreload(AltosUI.this);
+               new AltosUIMapPreload(AltosUI.this);
        }
 
        void LaunchController() {
@@ -302,7 +306,7 @@ public class AltosUI extends AltosUIFrame {
         * a TeleDongle over the packet link
         */
        private void SaveFlightData() {
-               new AltosEepromManage(AltosUI.this);
+               new AltosEepromManage(AltosUI.this, AltosLib.product_any);
        }
 
        /* Load a flight log file and write out a CSV file containing
@@ -468,7 +472,7 @@ public class AltosUI extends AltosUIFrame {
                }
                return false;
        }
-       
+
        static boolean process_summary(File file) {
                AltosStateIterable states = record_iterable(file);
                if (states == null)
@@ -547,7 +551,7 @@ public class AltosUI extends AltosUIFrame {
                System.out.printf("    --kml\tgenerate KML output for use with Google Earth\n");
                System.exit(code);
        }
-       
+
        public static void main(final String[] args) {
                int     errors = 0;
                load_library(null);
@@ -574,7 +578,7 @@ public class AltosUI extends AltosUIFrame {
                                        } else {
                                                double lat = Double.parseDouble(args[i+1]);
                                                double lon = Double.parseDouble(args[i+2]);
-                                               AltosSiteMap.prefetchMaps(lat, lon);
+//                                             AltosSiteMap.prefetchMaps(lat, lon);
                                                i += 2;
                                        }
                                } else if (args[i].equals("--replay"))
index 697d9902ff40bc545b48971fcf425b46e76ade25..280470866a4f22df99e45ca6de87158be04991ff 100644 (file)
@@ -19,13 +19,13 @@ package altosui;
 
 import java.io.File;
 import java.util.prefs.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 import javax.swing.filechooser.FileSystemView;
 
 public class AltosUIPreferencesBackend implements AltosPreferencesBackend {
 
        private Preferences _preferences = null;
-       
+
        public AltosUIPreferencesBackend() {
                _preferences = Preferences.userRoot().node("/org/altusmetrum/altosui");
        }
diff --git a/altosui/AltosVoice.java b/altosui/AltosVoice.java
deleted file mode 100644 (file)
index 2ed6a8c..0000000
+++ /dev/null
@@ -1,95 +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 com.sun.speech.freetts.Voice;
-import com.sun.speech.freetts.VoiceManager;
-import java.util.concurrent.LinkedBlockingQueue;
-import org.altusmetrum.altosuilib_1.*;
-
-public class AltosVoice implements Runnable {
-       VoiceManager                    voice_manager;
-       Voice                           voice;
-       LinkedBlockingQueue<String>     phrases;
-       Thread                          thread;
-       boolean                         busy;
-
-       final static String voice_name = "kevin16";
-
-       public void run() {
-               try {
-                       for (;;) {
-                               String s = phrases.take();
-                               voice.speak(s);
-                               synchronized(this) {
-                                       if (phrases.isEmpty()) {
-                                               busy = false;
-                                               notifyAll();
-                                       }
-                               }
-                       }
-               } catch (InterruptedException e) {
-               }
-       }
-
-       public synchronized void drain() throws InterruptedException {
-               while (busy)
-                       wait();
-       }
-
-       public void speak_always(String s) {
-               try {
-                       if (voice != null) {
-                               synchronized(this) {
-                                       busy = true;
-                                       phrases.put(s);
-                               }
-                       }
-               } catch (InterruptedException e) {
-               }
-       }
-
-       public void speak(String s) {
-               if (AltosUIPreferences.voice())
-                       speak_always(s);
-       }
-
-       public void speak(String format, Object... parameters) {
-               speak(String.format(format, parameters));
-       }
-
-       public AltosVoice () {
-               busy = false;
-               voice_manager = VoiceManager.getInstance();
-               voice = voice_manager.getVoice(voice_name);
-               if (voice != null) {
-                       voice.allocate();
-                       phrases = new LinkedBlockingQueue<String> ();
-                       thread = new Thread(this);
-                       thread.start();
-               } else {
-                       System.out.printf("Voice manager failed to open %s\n", voice_name);
-                       Voice[] voices = voice_manager.getVoices();
-                       System.out.printf("Available voices:\n");
-                       for (int i = 0; i < voices.length; i++) {
-                               System.out.println("    " + voices[i].getName()
-                                                  + " (" + voices[i].getDomain() + " domain)");
-                       }
-               }
-       }
-}
diff --git a/altosui/AltosWriter.java b/altosui/AltosWriter.java
deleted file mode 100644 (file)
index 5ff4458..0000000
+++ /dev/null
@@ -1,30 +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 org.altusmetrum.altoslib_3.*;
-
-
-public interface AltosWriter {
-
-       public void write(AltosState state);
-
-       public void write(AltosStateIterable states);
-
-       public void close();
-}
diff --git a/altosui/GrabNDrag.java b/altosui/GrabNDrag.java
deleted file mode 100644 (file)
index 2fd6c4d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public 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 javax.swing.event.MouseInputAdapter;
-
-class GrabNDrag extends MouseInputAdapter {
-       private JComponent scroll;
-       private Point startPt = new Point();
-
-       public GrabNDrag(JComponent scroll) {
-               this.scroll = scroll;
-               scroll.addMouseMotionListener(this);
-               scroll.addMouseListener(this);
-               scroll.setAutoscrolls(true);
-       }
-
-       public void mousePressed(MouseEvent e) {
-               startPt.setLocation(e.getPoint());
-       }
-       public void mouseDragged(MouseEvent e) {
-               int xd = e.getX() - startPt.x;
-               int yd = e.getY() - startPt.y;
-
-               Rectangle r = scroll.getVisibleRect();
-               r.x -= xd;
-               r.y -= yd;
-               scroll.scrollRectToVisible(r);
-       }
-}
index 23163e40278dbb63f68333d3df861cfc8c0b46f6..cbaf97433c546175151c22b6a213d86063637c4b 100644 (file)
@@ -181,7 +181,7 @@ $(DARWIN_ZIP): $(DARWIN_FILES)
        cp $(DARWIN_EXTRA) darwin/AltOS
        cd darwin && zip -r ../$@ AltosUI.app AltOS
 
-WINDOWS_FILES = $(FAT_FILES) libaltos/altos.dll ../telemetrum.inf $(WINDOWS_ICON)
+WINDOWS_FILES = $(FAT_FILES) libaltos/altos.dll ../altusmetrum.inf $(WINDOWS_ICON)
 
 $(WINDOWS_EXE): $(WINDOWS_FILES) altos-windows.nsi
        rm -f $@
index 32a3df97ba9187d9704feebca4b22c9b20066742..98a5e193ba900c69d7ae9329efd2535d39567ed4 100644 (file)
@@ -1,6 +1,6 @@
 
 JAVAROOT=classes
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
 
 man_MANS=altosui.1
 
@@ -10,71 +10,31 @@ CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="$(JAVAROOT):../altoslib/*:../alto
 
 bin_SCRIPTS=altosui
 
-altosui_BT = \
-       AltosBTDevice.java \
-       AltosBTDeviceIterator.java \
-       AltosBTManage.java \
-       AltosBTKnown.java
-
 altosui_JAVA = \
-       GrabNDrag.java \
        AltosAscent.java \
        AltosChannelMenu.java \
        AltosCompanionInfo.java \
        AltosConfig.java \
-       AltosConfigFreqUI.java \
        AltosConfigUI.java \
        AltosConfigPyroUI.java \
        AltosConfigureUI.java \
        AltosConfigTD.java \
        AltosConfigTDUI.java \
-       AltosCSV.java \
-       AltosCSVUI.java \
        AltosDescent.java \
-       AltosDeviceUIDialog.java \
-       AltosDisplayThread.java \
-       AltosEepromDelete.java \
-       AltosEepromManage.java \
-       AltosEepromMonitorUI.java \
-       AltosEepromSelect.java \
-       AltosFlashUI.java \
-       AltosFlightDisplay.java \
-       AltosFlightInfoTableModel.java \
-       AltosFlightStats.java \
-       AltosFlightStatsTable.java \
        AltosFlightStatus.java \
        AltosFlightStatusUpdate.java \
        AltosFlightUI.java \
-       AltosFreqList.java \
        Altos.java \
        AltosIdleMonitorUI.java \
        AltosIgniteUI.java \
+       AltosIgnitor.java \
        AltosLaunch.java \
        AltosLaunchUI.java \
-       AltosInfoTable.java \
-       AltosKML.java \
        AltosLanded.java \
-       AltosLed.java \
-       AltosLights.java \
        AltosPad.java \
        AltosUIPreferencesBackend.java \
-       AltosRomconfigUI.java \
-       AltosScanUI.java \
-       AltosSerial.java \
-       AltosSerialInUseException.java \
-       AltosSiteMap.java \
-       AltosSiteMapPreload.java \
-       AltosSiteMapCache.java \
-       AltosSiteMapTile.java \
        AltosUI.java \
-       AltosWriter.java \
-       AltosGraph.java \
-       AltosGraphDataPoint.java \
-       AltosGraphDataSet.java \
-       AltosGraphUI.java \
-       AltosDataChooser.java \
-       AltosVoice.java \
-       $(altosui_BT)
+       AltosGraphUI.java
 
 JFREECHART_CLASS= \
     jfreechart.jar
@@ -103,6 +63,10 @@ LIBALTOS= \
        libaltos.dylib \
        altos.dll
 
+desktopdir = $(datadir)/applications
+desktop_file = altos.desktop
+desktop_SCRIPTS = $(desktop_file)
+
 JAR=altosui.jar
 
 FATJAR=altosui-fat.jar
@@ -118,22 +82,16 @@ JAVA_ICONS=\
        $(ICONDIR)/altus-metrum-128.png \
        $(ICONDIR)/altus-metrum-256.png
 
-ICONS= $(ICONDIR)/redled.png $(ICONDIR)/redoff.png \
-       $(ICONDIR)/greenled.png $(ICONDIR)/greenoff.png \
-       $(ICONDIR)/grayled.png $(ICONDIR)/grayoff.png
-
 # icon base names for jar
 ICONJAR= -C $(ICONDIR) altus-metrum-16.png \
        -C $(ICONDIR) altus-metrum-32.png \
        -C $(ICONDIR) altus-metrum-48.png \
        -C $(ICONDIR) altus-metrum-64.png \
        -C $(ICONDIR) altus-metrum-128.png \
-       -C $(ICONDIR) altus-metrum-256.png \
-       -C $(ICONDIR) redled.png -C $(ICONDIR) redoff.png \
-       -C $(ICONDIR) greenled.png -C $(ICONDIR) greenoff.png \
-       -C $(ICONDIR) grayon.png -C $(ICONDIR) grayled.png
+       -C $(ICONDIR) altus-metrum-256.png
 
 WINDOWS_ICON=$(ICONDIR)/altus-metrum.ico
+MACOSX_ICON=$(ICONDIR)/AltosUIIcon.icns
 
 # Firmware
 FIRMWARE_TD_0_2=$(top_srcdir)/src/teledongle-v0.2/teledongle-v0.2-$(VERSION).ihx
@@ -156,7 +114,10 @@ FIRMWARE_TMEGA=$(FIRMWARE_TMEGA_1_0)
 FIRMWARE_EMINI_1_0=$(top_srcdir)/src/easymini-v1.0/easymini-v1.0-$(VERSION).ihx
 FIRMWARE_EMINI=$(FIRMWARE_EMINI_1_0)
 
-FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT) $(FIRMWARE_TMEGA) $(FIRMWARE_EMINI)
+FIRMWARE_TGPS_1_0=$(top_srcdir)/src/telegps-v1.0/telegps-v1.0-$(VERSION).ihx
+FIRMWARE_TGPS=$(FIRMWARE_TGPS_1_0)
+
+FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT) $(FIRMWARE_TMEGA) $(FIRMWARE_EMINI) $(FIRMWARE_TGPS)
 
 ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf
 ALTOS_DOC=$(top_srcdir)/doc/altos.pdf
@@ -171,6 +132,7 @@ DOC=$(ALTUSMETRUM_DOC) $(ALTOS_DOC) $(TELEMETRY_DOC) $(TEMPLATE_DOC)
 
 # Distribution targets
 LINUX_DIST=Altos-Linux-$(VERSION).tar.bz2
+LINUX_SH=Altos-Linux-$(VERSION).sh
 MACOSX_DIST=Altos-Mac-$(VERSION).dmg
 WINDOWS_DIST=Altos-Windows-$(VERSION_DASH).exe
 
@@ -178,37 +140,48 @@ FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFR
 
 LINUX_LIBS=libaltos32.so libaltos64.so
 
-LINUX_FILES=$(FAT_FILES) $(LINUX_LIBS) $(FIRMWARE) $(DOC)
+LINUX_FILES=$(FAT_FILES) $(LINUX_LIBS) $(FIRMWARE) $(DOC) altos.desktop.in ../icon/altusmetrum.svg
 LINUX_EXTRA=altosui-fat
 
 MACOSX_INFO_PLIST=Info.plist
-MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(DOC) ReadMe-Mac.rtf
+MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(DOC) ReadMe-Mac.rtf $(MACOSX_ICON)
 MACOSX_EXTRA=$(FIRMWARE)
 
-WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/telemetrum.inf $(WINDOWS_ICON)
+WINDOWS_FILES=$(FAT_FILES) $(FIRMWARE) altos.dll altos64.dll $(top_srcdir)/altusmetrum.inf $(top_srcdir)/altusmetrum.cat $(WINDOWS_ICON)
 
 all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb
 
 clean-local:
        -rm -rf classes $(JAR) $(FATJAR) \
-               $(LINUX_DIST) $(MACOSX_DIST) windows $(WINDOWS_DIST) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) \
+               $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) windows $(WINDOWS_DIST) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) \
                $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt altos-windows.log altos-windows.nsi \
                altosui altosui-test altosui-jdb macosx linux
 
+EXTRA_DIST = $(desktop_file).in
+
+$(desktop_file): $(desktop_file).in
+       sed -e 's#%bindir%#@bindir@#' -e 's#%icondir%#$(datadir)/icons/hicolor/scalable/apps#' ${srcdir}/altos.desktop.in > $@
+       chmod +x $@
+
 if FATINSTALL
 
 FATTARGET=$(FATDIR)/$(VERSION)
 
 LINUX_DIST_TARGET=$(FATTARGET)/$(LINUX_DIST)
+LINUX_SH_TARGET=$(FATTARGET)/$(LINUX_SH)
 MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST)
 WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST)
 
-fat: $(LINUX_DIST_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
+fat: $(LINUX_DIST_TARGET) $(LINUX_SH_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
 
 $(LINUX_DIST_TARGET): $(LINUX_DIST)
        mkdir -p $(FATTARGET)
        cp -p $< $@
 
+$(LINUX_SH_TARGET): $(LINUX_SH)
+       mkdir -p $(FATTARGET)
+       cp -p $< $@
+
 $(MACOSX_DIST_TARGET): $(MACOSX_DIST)
        mkdir -p $(FATTARGET)
        cp -p $< $@
@@ -218,7 +191,7 @@ $(WINDOWS_DIST_TARGET): $(WINDOWS_DIST)
        cp -p $< $@
 
 else
-fat: $(LINUX_DIST) $(MACOSX_DIST) $(WINDOWS_DIST)
+fat: $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) $(WINDOWS_DIST)
 endif
 
 
@@ -259,8 +232,12 @@ altosui: Makefile
        chmod +x $@
 
 altosui-test: Makefile
-       echo "#!/bin/sh" > $@
-       echo 'exec java -Djava.library.path="../libaltos/.libs" -jar altosui.jar "$$@"' >> $@
+       echo '#!/bin/sh' > $@
+       echo 'dir="$$(dirname $$0)"' >> $@
+       echo 'cd "$$dir"' >> $@
+       echo 'altosui="$$(pwd -P)"' >> $@
+       echo 'altos="$$(dirname $$altosui)"' >> $@
+       echo 'exec java -Djava.library.path="$$altos/libaltos/.libs" -jar "$$altosui/altosui.jar" "$$@"' >> $@
        chmod +x $@
 
 altosui-jdb: Makefile
@@ -333,6 +310,10 @@ $(LINUX_DIST): $(LINUX_FILES) $(LINUX_EXTRA)
        chmod +x linux/AltOS/altosui
        tar cjf $@ -C linux AltOS
 
+$(LINUX_SH): $(LINUX_DIST) linux-install.sh
+       cat linux-install.sh $(LINUX_DIST) > $@
+       chmod +x $@
+
 $(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) Makefile
        -rm -f $@
        -rm -rf macosx
@@ -343,6 +324,7 @@ $(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) Makefile
        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 $(MACOSX_ICON) macosx/AltosUI.app/Contents/Resources
        cp -p $(FATJAR) macosx/AltosUI.app/Contents/Resources/Java/altosui.jar
        cp -p libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java
        cp -p $(ALTOSLIB_CLASS) macosx/AltosUI.app/Contents/Resources/Java
@@ -355,5 +337,4 @@ $(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) Makefile
 
 $(WINDOWS_DIST): $(WINDOWS_FILES) altos-windows.nsi
        -rm -f $@
-       makensis -Oaltos-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" altos-windows.nsi
-
+       makensis -Oaltos-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" altos-windows.nsi || (cat altos-windows.log && exit 1)
index 3832e9019dea30de2ddb735f3e75955ce1af1bf6..b72772e290b786fd1777c6e609504f91bfb8852e 100644 (file)
@@ -1,8 +1,10 @@
 !addplugindir Instdrv/NSIS/Plugins
-; Definitions for Java 1.6 Detection
-!define JRE_VERSION "1.6"
-!define JRE_ALTERNATE "1.7"
-!define JRE_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=52247&/jre-6u27-windows-i586-p.exe"
+!include x64.nsh
+; Definitions for Java 1.7 Detection
+!define JRE_VERSION "1.7"
+!define JRE_ALTERNATE "1.6"
+!define JRE32_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=83383&/jre-7u51-windows-i586.exe"
+!define JRE64_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=83385&/jre-7u51-windows-x64.exe"
 !define PRODUCT_NAME "Altus Metrum Windows Software"
 
 Name "Altus Metrum Installer"
@@ -23,12 +25,34 @@ ShowInstDetails Show
 
 ComponentText "Altus Metrum Software and Driver Installer"
 
+Function .onInit
+       DetailPrint "Checking host operating system"
+       ${If} ${RunningX64}
+               DetailPrint "Installer running on 64-bit host"
+               SetRegView 64
+               StrCpy $INSTDIR "$PROGRAMFILES64\AltusMetrum"
+               ${DisableX64FSRedirection}
+       ${EndIf}
+FunctionEnd
+
+Var JavaDownload
+Var JavaBits
+
 Function GetJRE
-        MessageBox MB_OK "${PRODUCT_NAME} uses Java ${JRE_VERSION} 32-bit, it will now \
-                         be downloaded and installed"
+       ${If} ${RunningX64}
+          StrCpy $JavaDownload ${JRE64_URL}
+          StrCpy $JavaBits "64"
+       ${Else}
+          StrCpy $JavaDownload ${JRE32_URL}
+          StrCpy $JavaBits "32"
+       ${EndIf}
+
+        MessageBox MB_OK "${PRODUCT_NAME} uses Java ${JRE_VERSION}, \
+                       $JavaBits bits, it will now \
+                        be downloaded and installed"
 
         StrCpy $2 "$TEMP\Java Runtime Environment.exe"
-        nsisdl::download /TIMEOUT=30000 ${JRE_URL} $2
+        nsisdl::download /TIMEOUT=30000 $JavaDownload $2
         Pop $R0 ;Get the return value
                 StrCmp $R0 "success" +3
                 MessageBox MB_OK "Download failed: $R0"
@@ -37,10 +61,10 @@ Function GetJRE
         Delete $2
 FunctionEnd
 
-
 Function DetectJRE
   ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" \
              "CurrentVersion"
+
   StrCmp $2 ${JRE_VERSION} done
 
   StrCmp $2 ${JRE_ALTERNATE} done
@@ -70,15 +94,18 @@ Section "Install Driver" InstDriver
        InstDrv::DeleteOemInfFiles /NOUNLOAD
        InstDrv::CreateDevice /NOUNLOAD
 
-       SetOutPath $TEMP
-       File "../telemetrum.inf"
-       InstDrv::InstallDriver /NOUNLOAD "$TEMP\telemetrum.inf"
-
        SetOutPath $INSTDIR
-       File "../telemetrum.inf"
-
-       SetOutPath $WINDIR\Inf
-       File "../telemetrum.inf"
+       File "../altusmetrum.inf"
+       File "../altusmetrum.cat"
+
+       ${DisableX64FSRedirection}
+       IfFileExists $WINDIR\System32\PnPutil.exe 0 nopnp
+               ${DisableX64FSRedirection}
+               nsExec::ExecToLog '"$WINDIR\System32\PnPutil.exe" -i -a "$INSTDIR\altusmetrum.inf"'
+               Goto done
+nopnp:
+               InstDrv::InstallDriver /NOUNLOAD "$INSTDIR\altusmetrum.inf"
+done:
 
 SectionEnd
 
@@ -119,6 +146,7 @@ Section "TeleMetrum, TeleDongle and TeleBT Firmware"
        File "../src/telemetrum-v1.1/telemetrum-v1.1-${VERSION}.ihx"
        File "../src/telemetrum-v1.2/telemetrum-v1.2-${VERSION}.ihx"
        File "../src/telemini-v1.0/telemini-v1.0-${VERSION}.ihx"
+       File "../src/telegps-v1.0/telegps-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"
@@ -164,9 +192,6 @@ Section "Uninstall"
        Delete "$INSTDIR\*.*"
        RMDir "$INSTDIR"
 
-       ; Remove .inf file
-       Delete "$WINDIR\Inf\telemetrum.inf"
-
        ; Remove devices
        InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} AltusMetrumSerial
        InstDrv::DeleteOemInfFiles /NOUNLOAD
diff --git a/altosui/altos.desktop.in b/altosui/altos.desktop.in
new file mode 100644 (file)
index 0000000..6611434
--- /dev/null
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Type=Application
+Name=AltOS UI
+GenericName=Altus Metrum Ground Station
+Comment=View and log downlink data from Altus Metrum products
+Icon=%icondir%/altusmetrum.svg
+Exec=%bindir%/altosui %f
+Terminal=false
+MimeType=text/plain;
+Categories=Education;Electronics;Science;
diff --git a/altosui/linux-install.sh b/altosui/linux-install.sh
new file mode 100644 (file)
index 0000000..957b1aa
--- /dev/null
@@ -0,0 +1,239 @@
+#!/bin/sh
+
+can_ask=y
+
+finish()
+{
+    if [ "$can_ask" = "y" ]; then
+       echo ""
+       echo -n "Press enter to continue..."
+       read foo
+    fi
+    exit $1
+}
+
+#
+# Make sure we have a terminal to talk to
+#
+
+if tty -s; then
+    :
+else
+    case "$DISPLAY" in
+       "")
+       echo 'No user input available'
+       can_ask=n
+       ;;
+       *)
+       GUESS_XTERMS="x-terminal-emulator xterm rxvt roxterm gnome-terminal dtterm eterm Eterm kvt konsole aterm"
+        for a in $GUESS_XTERMS; do
+            if type $a >/dev/null 2>&1; then
+                XTERM=$a
+                break
+            fi
+        done
+       case "$XTERM" in
+           "")
+           echo 'No terminal emulator available'
+           can_ask=n
+           ;;
+           *)
+           exec "$XTERM" -e "sh '$0'"
+           ;;
+       esac
+       ;;
+    esac
+fi
+
+#
+# Make sure we can run java
+#
+
+echo -n "Checking for java..."
+
+if java -version > /dev/null 2>&1; then
+    echo " found it."
+else
+    echo " java isn't working."
+    echo ""
+    echo "You'll need to install a java runtime system"
+    echo "on this computer before AltOS will work properly."
+    finish 1
+fi
+    
+#
+# Pick an installation target
+# 
+
+if [ '(' -d /opt -a -w /opt ')' -o '(' -d /opt/AltOS -a -w /opt/AltOS ')' ]; then
+    target_default=/opt
+else
+    target_default="$HOME"
+fi
+
+case "$#" in
+0)
+    echo -n "Installation location [default: $target_default] "
+    if [ "$can_ask" = "y" ]; then
+       read target
+    else
+       echo ""
+       target=""
+    fi
+    case "$target" in
+       "")
+       target="$target_default"
+       ;;
+    esac
+    ;;
+*)
+    target="$1"
+    ;;
+esac
+
+target_altos="$target"/AltOS
+
+echo -n "Installing to $target..."
+
+#
+# Make sure the target exists
+#
+mkdir -p "$target_altos"
+
+if [ ! -d "$target_altos" ]; then
+    echo "$target_altos does not exist and cannot be created"
+    finish 1
+fi
+
+if [ ! -w "$target_altos" ]; then
+    echo "$target_altos cannot be written"
+    finish 1
+fi
+
+#
+# Unpack the tar archive appended to the end of this script
+#
+archive_line=`awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' "$0"`
+
+tail -n+$archive_line "$0" | tar xjf - -C "$target"
+
+case $? in
+0)
+    echo " done."
+    ;;
+*)
+    echo "Install failed."
+    finish 1
+    ;;
+esac
+
+#
+# Create the .desktop file by editing the paths
+#
+case "$target" in
+/*)
+    target_abs="$target"
+    ;;
+*)
+    target_abs=`pwd`/$target
+    ;;
+esac
+
+BIN="$target_abs"/AltOS
+
+for infile in "$target"/AltOS/*.desktop.in; do
+    desktop="$target"/AltOS/`basename "$infile" .in`
+    rm -f "$desktop"
+    sed -e "s;%bindir%;$BIN;" -e "s;%icondir%;$BIN;" "$infile" > "$desktop"
+    chmod +x "$desktop"
+done
+
+#
+# Figure out where to install the .desktop files. If we can, write it
+# to the public /usr/share/applications, otherwise, write it to the
+# per-user ~/.local/share/applications
+#
+
+public=/usr/share/applications
+private=$HOME/.local/share/applications
+apps=""
+
+if [ -d "$public" -a -w "$public" ]; then
+    apps="$public"
+else
+    mkdir -p "$private" >/dev/null 2>&1 
+    if [ -d "$private" -a -w "$private" ]; then
+       apps="$private"
+    fi
+fi
+       
+case "$apps" in
+"")
+    echo "Cannot install application icon"
+    finish 1
+    ;;
+esac
+
+echo -n "Installing .desktop files to $apps..."
+
+cp "$target"/AltOS/*.desktop "$apps"
+
+case "$?" in
+0)
+    echo " done."
+    ;;
+*)
+    echo " failed."
+    ;;
+esac
+
+#
+# Install icon to desktop if desired
+#
+
+if [ -d $HOME/Desktop ]; then
+    default_desktop=n
+    if [ "$can_ask" = "y" ]; then
+       :
+    else
+       default_desktop=y
+    fi
+
+    answered=n
+    while [ "$answered" = "n" ]; do
+       echo -n "Install icons to desktop? [default: $default_desktop] "
+       if [ "$can_ask" = "y" ]; then
+           read do_desktop
+       else
+           echo
+           do_desktop=""
+       fi
+
+       case "$do_desktop" in
+           "")
+           do_desktop=$default_desktop
+           ;;
+       esac
+
+       case "$do_desktop" in
+       [yYnN]*)
+           answered=y
+           ;;
+       esac
+    done
+
+    echo -n "Installing desktop icons..."
+    case "$do_desktop" in
+    [yY]*)
+       for d in "$target"/AltOS/*.desktop; do
+           ln -f -s "$d" "$HOME/Desktop/"
+       done
+       ;;
+    esac
+
+    echo " done."
+fi
+
+finish 0
+
+__ARCHIVE_BELOW__
diff --git a/altosuilib/AltosBTDevice.java b/altosuilib/AltosBTDevice.java
new file mode 100644 (file)
index 0000000..beefa53
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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.altosuilib_2;
+
+import libaltosJNI.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosBTDevice extends altos_bt_device implements AltosDevice {
+
+       public String getProductName() {
+               String  name = getName();
+               if (name == null)
+                       return "Altus Metrum";
+               int     dash = name.lastIndexOf("-");
+               if (dash < 0)
+                       return name;
+               return name.substring(0,dash);
+       }
+
+       public int getProduct() {
+               if (AltosLib.bt_product_telebt.equals(getProductName()))
+                       return AltosLib.product_telebt;
+               return 0;
+       }
+
+       public String getPath() {
+               return getAddr();
+       }
+
+       public String getErrorString() {
+               altos_error     error = new altos_error();
+
+               libaltos.altos_get_last_error(error);
+               return String.format("%s (%d)", error.getString(), error.getCode());
+       }
+
+       public int getSerial() {
+               String name = getName();
+               if (name == null)
+                       return 0;
+               int dash = name.lastIndexOf("-");
+               if (dash < 0 || dash >= name.length())
+                       return 0;
+               String sn = name.substring(dash + 1, name.length());
+               try {
+                       return Integer.parseInt(sn);
+               } catch (NumberFormatException ne) {
+                       return 0;
+               }
+       }
+
+       public String toString() {
+               return String.format("%-20.20s %4d %s",
+                                    getProductName(), getSerial(), getAddr());
+       }
+
+       public String toShortString() {
+               return String.format("%s %d %s",
+                                    getProductName(), getSerial(), getAddr());
+
+       }
+
+       public SWIGTYPE_p_altos_file open() {
+               return libaltos.altos_bt_open(this);
+       }
+
+       /*
+       private boolean isAltusMetrum() {
+               if (getName().startsWith(Altos.bt_product_telebt))
+                       return true;
+               return false;
+       }
+       */
+
+       public boolean matchProduct(int want_product) {
+
+//             if (!isAltusMetrum())
+//                     return false;
+
+               if (want_product == AltosLib.product_any)
+                       return true;
+
+               if (want_product == AltosLib.product_basestation)
+                       return matchProduct(AltosLib.product_telebt);
+
+               if (want_product == getProduct())
+                       return true;
+
+               return false;
+       }
+
+       public boolean equals(Object o) {
+               if (!(o instanceof AltosBTDevice))
+                       return false;
+               AltosBTDevice other = (AltosBTDevice) o;
+               return getName().equals(other.getName()) && getAddr().equals(other.getAddr());
+       }
+
+       public int hashCode() {
+               return getName().hashCode() ^ getAddr().hashCode();
+       }
+
+       public AltosBTDevice(String name, String addr) {
+               AltosUILib.load_library();
+               libaltos.altos_bt_fill_in(name, addr,this);
+       }
+
+       public AltosBTDevice() {
+       }
+}
diff --git a/altosuilib/AltosBTDeviceIterator.java b/altosuilib/AltosBTDeviceIterator.java
new file mode 100644 (file)
index 0000000..cad60ff
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.altosuilib_2;
+
+import java.util.*;
+import libaltosJNI.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosBTDeviceIterator implements Iterator<AltosBTDevice> {
+       AltosBTDevice   current;
+       boolean         done;
+       SWIGTYPE_p_altos_bt_list list;
+
+       public boolean hasNext() {
+               if (list == null)
+                       return false;
+               if (current != null)
+                       return true;
+               if (done)
+                       return false;
+               current = new AltosBTDevice();
+               while (libaltos.altos_bt_list_next(list, current) != 0) {
+//                     if (current.matchProduct(product))
+                               return true;
+               }
+               current = null;
+               done = true;
+               return false;
+       }
+
+       public AltosBTDevice next() {
+               if (hasNext()) {
+                       AltosBTDevice   next = current;
+                       current = null;
+                       return next;
+               }
+               return null;
+       }
+
+       public void remove() {
+               throw new UnsupportedOperationException();
+       }
+
+       public AltosBTDeviceIterator(int inquiry_time) {
+               done = false;
+               current = null;
+               list = libaltos.altos_bt_list_start(inquiry_time);
+       }
+}
diff --git a/altosuilib/AltosBTKnown.java b/altosuilib/AltosBTKnown.java
new file mode 100644 (file)
index 0000000..02883c7
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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.altosuilib_2;
+
+import java.util.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosBTKnown implements Iterable<AltosBTDevice> {
+       LinkedList<AltosBTDevice>       devices = new LinkedList<AltosBTDevice>();
+       AltosPreferencesBackend         bt_pref = AltosUIPreferences.bt_devices();
+
+       private String get_address(String name) {
+               return bt_pref.getString(name, "");
+       }
+
+       private void set_address(String name, String addr) {
+               bt_pref.putString(name, addr);
+       }
+
+       private void remove(String name) {
+               bt_pref.remove(name);
+       }
+
+       private void load() {
+               try {
+                       String[] names = bt_pref.keys();
+                       for (int i = 0; i < names.length; i++) {
+                               String  name = names[i];
+                               String  addr = get_address(name);
+                               devices.add(new AltosBTDevice(name, addr));
+                       }
+               } catch (IllegalStateException ie) {
+               }
+       }
+
+       public Iterator<AltosBTDevice> iterator() {
+               return devices.iterator();
+       }
+
+       private void flush() {
+               AltosUIPreferences.flush_preferences();
+       }
+
+       public void set(Iterable<AltosBTDevice> new_devices) {
+               for (AltosBTDevice old : devices) {
+                       boolean found = false;
+                       for (AltosBTDevice new_device : new_devices) {
+                               if (new_device.equals(old)) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+                       if (!found)
+                               remove(old.getName());
+               }
+               devices = new LinkedList<AltosBTDevice>();
+               for (AltosBTDevice new_device : new_devices) {
+                       devices.add(new_device);
+                       set_address(new_device.getName(), new_device.getAddr());
+               }
+               flush();
+       }
+
+       public List<AltosDevice> list(int product) {
+               LinkedList<AltosDevice> list = new LinkedList<AltosDevice>();
+               for (AltosBTDevice device : devices) {
+                       if (device.matchProduct(product))
+                               list.add(device);
+               }
+               return list;
+       }
+
+       public AltosBTKnown() {
+               devices = new LinkedList<AltosBTDevice>();
+               bt_pref = AltosUIPreferences.bt_devices();
+               load();
+       }
+
+       static AltosBTKnown     known;
+
+       static public AltosBTKnown bt_known() {
+               if (known == null)
+                       known = new AltosBTKnown();
+               return known;
+       }
+}
diff --git a/altosuilib/AltosBTManage.java b/altosuilib/AltosBTManage.java
new file mode 100644 (file)
index 0000000..6da0a3e
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.plaf.basic.*;
+import java.util.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosBTManage extends AltosUIDialog implements ActionListener, Iterable<AltosBTDevice> {
+       LinkedBlockingQueue<AltosBTDevice> found_devices;
+       Frame frame;
+       LinkedList<ActionListener> listeners;
+       AltosBTKnown    bt_known;
+
+       class DeviceList extends JList<AltosBTDevice> implements Iterable<AltosBTDevice> {
+               LinkedList<AltosBTDevice>       devices;
+               DefaultListModel<AltosBTDevice> list_model;
+
+               public void add (AltosBTDevice device) {
+                       if (!devices.contains(device)) {
+                               devices.add(device);
+                               list_model.addElement(device);
+                       }
+               }
+
+               public void remove (AltosBTDevice device) {
+                       if (devices.contains(device)) {
+                               devices.remove(device);
+                               list_model.removeElement(device);
+                       }
+               }
+
+               public boolean contains(AltosBTDevice device) {
+                       return devices.contains(device);
+               }
+
+               //Subclass JList to workaround bug 4832765, which can cause the
+               //scroll pane to not let the user easily scroll up to the beginning
+               //of the list.  An alternative would be to set the unitIncrement
+               //of the JScrollBar to a fixed value. You wouldn't get the nice
+               //aligned scrolling, but it should work.
+               public int getScrollableUnitIncrement(Rectangle visibleRect,
+                                                     int orientation,
+                                                     int direction) {
+                       int row;
+                       if (orientation == SwingConstants.VERTICAL &&
+                           direction < 0 && (row = getFirstVisibleIndex()) != -1) {
+                               Rectangle r = getCellBounds(row, row);
+                               if ((r.y == visibleRect.y) && (row != 0))  {
+                                       Point loc = r.getLocation();
+                                       loc.y--;
+                                       int prevIndex = locationToIndex(loc);
+                                       Rectangle prevR = getCellBounds(prevIndex, prevIndex);
+
+                                       if (prevR == null || prevR.y >= r.y) {
+                                               return 0;
+                                       }
+                                       return prevR.height;
+                               }
+                       }
+                       return super.getScrollableUnitIncrement(
+                               visibleRect, orientation, direction);
+               }
+
+               public Iterator<AltosBTDevice> iterator() {
+                       return devices.iterator();
+               }
+
+               public java.util.List<AltosBTDevice> selected_list() throws InterruptedException {
+                       return getSelectedValuesList();
+               }
+
+               public DeviceList() {
+                       devices = new LinkedList<AltosBTDevice>();
+                       list_model = new DefaultListModel<AltosBTDevice>();
+                       setModel(list_model);
+                       setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+                       setLayoutOrientation(JList.HORIZONTAL_WRAP);
+                       setVisibleRowCount(-1);
+               }
+       }
+
+       DeviceList      visible_devices;
+
+       DeviceList      known_devices;
+       Thread          bt_thread;
+
+       public Iterator<AltosBTDevice> iterator() {
+               return known_devices.iterator();
+       }
+
+       public void commit() {
+               bt_known.set(this);
+       }
+
+       public void add_known() {
+               try {
+                       for (AltosBTDevice device : visible_devices.selected_list()) {
+                               known_devices.add(device);
+                               visible_devices.remove(device);
+                       }
+               } catch (InterruptedException ie) {
+               }
+       }
+
+       public void remove_known() {
+               try {
+                       for (AltosBTDevice device : known_devices.selected_list()) {
+                               known_devices.remove(device);
+                               visible_devices.add(device);
+                       }
+               } catch (InterruptedException ie) {
+               }
+       }
+
+       public void addActionListener(ActionListener l) {
+               listeners.add(l);
+       }
+
+       private void forwardAction(ActionEvent e) {
+               for (ActionListener l : listeners)
+                       l.actionPerformed(e);
+       }
+
+       public void actionPerformed(ActionEvent e) {
+               String  command = e.getActionCommand();
+               if ("ok".equals(command)) {
+                       bt_thread.interrupt();
+                       commit();
+                       setVisible(false);
+                       forwardAction(e);
+               } else if ("cancel".equals(command)) {
+                       bt_thread.interrupt();
+                       setVisible(false);
+                       forwardAction(e);
+               } else if ("select".equals(command)) {
+                       add_known();
+               } else if ("deselect".equals(command)) {
+                       remove_known();
+               }
+       }
+
+       public void got_visible_device() {
+               while (!found_devices.isEmpty()) {
+                       AltosBTDevice   device = found_devices.remove();
+                       if (!known_devices.contains(device))
+                               visible_devices.add(device);
+               }
+       }
+
+       class BTGetVisibleDevices implements Runnable {
+               public void run () {
+                       for (;;)
+                               for (int time = 1; time <= 8; time <<= 1) {
+                                       AltosBTDeviceIterator   i = new AltosBTDeviceIterator(time);
+                                       AltosBTDevice           device;
+
+                                       if (Thread.interrupted())
+                                               return;
+                                       try {
+                                               while ((device = i.next()) != null) {
+                                                       Runnable r;
+
+                                                       if (Thread.interrupted())
+                                                               return;
+                                                       found_devices.add(device);
+                                                       r = new Runnable() {
+                                                                       public void run() {
+                                                                               got_visible_device();
+                                                                       }
+                                                               };
+                                                       SwingUtilities.invokeLater(r);
+                                               }
+                                       } catch (Exception e) {
+                                               System.out.printf("uh-oh, exception %s\n", e.toString());
+                                       }
+                               }
+               }
+       }
+
+       public static void show(Component frameComp, AltosBTKnown known) {
+               Frame   frame = JOptionPane.getFrameForComponent(frameComp);
+               AltosBTManage   dialog;
+
+               dialog = new AltosBTManage(frame, known);
+               dialog.setVisible(true);
+       }
+
+       public AltosBTManage(Frame in_frame, AltosBTKnown in_known) {
+               super(in_frame, "Manage Bluetooth Devices", true);
+
+               frame = in_frame;
+               bt_known = in_known;
+               BTGetVisibleDevices     get_visible_devices = new BTGetVisibleDevices();
+               bt_thread = new Thread(get_visible_devices);
+               bt_thread.start();
+
+               listeners = new LinkedList<ActionListener>();
+
+               found_devices = new LinkedBlockingQueue<AltosBTDevice>();
+
+               Container pane = getContentPane();
+               pane.setLayout(new GridBagLayout());
+
+               GridBagConstraints c = new GridBagConstraints();
+               c.insets = new Insets(4,4,4,4);
+
+               /*
+                * Known devices label and list
+                */
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 0;
+               c.gridy = 0;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(new JLabel("Known Devices"), c);
+
+               known_devices = new DeviceList();
+               for (AltosBTDevice device : bt_known)
+                       known_devices.add(device);
+
+               JScrollPane known_list_scroller = new JScrollPane(known_devices);
+               known_list_scroller.setPreferredSize(new Dimension(400, 80));
+               known_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 0;
+               c.gridy = 1;
+               c.gridwidth = 1;
+               c.gridheight = 2;
+               c.weightx = 1;
+               c.weighty = 1;
+               pane.add(known_list_scroller, c);
+
+               /*
+                * Visible devices label and list
+                */
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 2;
+               c.gridy = 0;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+
+               pane.add(new JLabel("Visible Devices"), c);
+
+               visible_devices = new DeviceList();
+               JScrollPane visible_list_scroller = new JScrollPane(visible_devices);
+               visible_list_scroller.setPreferredSize(new Dimension(400, 80));
+               visible_list_scroller.setAlignmentX(LEFT_ALIGNMENT);
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 2;
+               c.gridy = 1;
+               c.gridheight = 2;
+               c.gridwidth = 1;
+               c.weightx = 1;
+               c.weighty = 1;
+               pane.add(visible_list_scroller, c);
+
+               /*
+                * Arrows between the two lists
+                */
+               BasicArrowButton select_arrow = new BasicArrowButton(SwingConstants.WEST);
+               select_arrow.setActionCommand("select");
+               select_arrow.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.SOUTH;
+               c.gridx = 1;
+               c.gridy = 1;
+               c.gridheight = 1;
+               c.gridwidth = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(select_arrow, c);
+
+               BasicArrowButton deselect_arrow = new BasicArrowButton(SwingConstants.EAST);
+               deselect_arrow.setActionCommand("deselect");
+               deselect_arrow.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.NORTH;
+               c.gridx = 1;
+               c.gridy = 2;
+               c.gridheight = 1;
+               c.gridwidth = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(deselect_arrow, c);
+
+               JButton cancel_button = new JButton("Cancel");
+               cancel_button.setActionCommand("cancel");
+               cancel_button.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 0;
+               c.gridy = 3;
+               c.gridheight = 1;
+               c.gridwidth = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(cancel_button, c);
+
+               JButton ok_button = new JButton("OK");
+               ok_button.setActionCommand("ok");
+               ok_button.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 2;
+               c.gridy = 3;
+               c.gridheight = 1;
+               c.gridwidth = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(ok_button, c);
+
+               getRootPane().setDefaultButton(ok_button);
+
+               pack();
+               setLocationRelativeTo(frame);
+               setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+               addWindowListener(new WindowAdapter() {
+                       @Override
+                       public void windowClosing(WindowEvent e) {
+                               bt_thread.interrupt();
+                               setVisible(false);
+                       }
+               });
+       }
+}
diff --git a/altosuilib/AltosCSVUI.java b/altosuilib/AltosCSVUI.java
new file mode 100644 (file)
index 0000000..0a5e4fa
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosCSVUI
+       extends AltosUIDialog
+       implements ActionListener
+{
+       JFileChooser            csv_chooser;
+       JPanel                  accessory;
+       JComboBox<String>       combo_box;
+       Iterable<AltosState>    states;
+       AltosWriter             writer;
+
+       static String[]         combo_box_items = { "Comma Separated Values (.CSV)", "Googleearth Data (.KML)" };
+
+       void set_default_file() {
+               File    current = csv_chooser.getSelectedFile();
+               String  current_name = current.getName();
+               String  new_name = null;
+               String  selected = (String) combo_box.getSelectedItem();
+
+               if (selected.contains("CSV"))
+                       new_name = AltosLib.replace_extension(current_name, ".csv");
+               else if (selected.contains("KML"))
+                       new_name = AltosLib.replace_extension(current_name, ".kml");
+               if (new_name != null)
+                       csv_chooser.setSelectedFile(new File(new_name));
+       }
+
+       public void actionPerformed(ActionEvent e) {
+               if (e.getActionCommand().equals("comboBoxChanged"))
+                       set_default_file();
+       }
+
+       public AltosCSVUI(JFrame frame, AltosStateIterable states, File source_file) {
+               this.states = states;
+               csv_chooser = new JFileChooser(source_file);
+
+               accessory = new JPanel();
+               accessory.setLayout(new GridBagLayout());
+
+               GridBagConstraints      c = new GridBagConstraints();
+               c.fill = GridBagConstraints.NONE;
+               c.weightx = 1;
+               c.weighty = 0;
+               c.insets = new Insets (4, 4, 4, 4);
+
+               JLabel accessory_label = new JLabel("Export File Type");
+               c.gridx = 0;
+               c.gridy = 0;
+               accessory.add(accessory_label, c);
+
+               combo_box = new JComboBox<String>(combo_box_items);
+               combo_box.addActionListener(this);
+               c.gridx = 0;
+               c.gridy = 1;
+               accessory.add(combo_box, c);
+
+               csv_chooser.setAccessory(accessory);
+               csv_chooser.setSelectedFile(source_file);
+               set_default_file();
+               int ret = csv_chooser.showSaveDialog(frame);
+               if (ret == JFileChooser.APPROVE_OPTION) {
+                       File file = csv_chooser.getSelectedFile();
+                       String type = (String) combo_box.getSelectedItem();
+                       try {
+                               if (type.contains("CSV"))
+                                       writer = new AltosCSV(file);
+                               else
+                                       writer = new AltosKML(file);
+                               writer.write(states);
+                               writer.close();
+                       } catch (FileNotFoundException ee) {
+                               JOptionPane.showMessageDialog(frame,
+                                                             ee.getMessage(),
+                                                             "Cannot open file",
+                                                             JOptionPane.ERROR_MESSAGE);
+                       }
+               }
+       }
+}
diff --git a/altosuilib/AltosConfigFreqUI.java b/altosuilib/AltosConfigFreqUI.java
new file mode 100644 (file)
index 0000000..6dcd63b
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.util.*;
+import org.altusmetrum.altoslib_4.*;
+
+class AltosEditFreqUI extends AltosUIDialog implements ActionListener {
+       Frame           frame;
+       JTextField      frequency;
+       JTextField      description;
+       JButton         ok_button, cancel_button;
+       boolean         got_ok;
+
+       public void actionPerformed(ActionEvent e) {
+               String  cmd = e.getActionCommand();
+
+               if ("ok".equals(cmd)) {
+                       got_ok = true;
+                       setVisible(false);
+               }
+               if ("cancel".equals(cmd)) {
+                       got_ok = false;
+                       setVisible(false);
+               }
+       }
+
+       public AltosFrequency get() {
+               if (!got_ok)
+                       return null;
+
+               String  f_s = frequency.getText();
+               String  d_s = description.getText();
+
+               try {
+                       double  f_d = Double.parseDouble(f_s);
+
+                       return new AltosFrequency(f_d, d_s);
+               } catch (NumberFormatException ne) {
+               }
+               return null;
+       }
+
+       public AltosEditFreqUI(Frame in_frame, AltosFrequency existing) {
+               super(in_frame, true);
+
+               got_ok = false;
+               frame = in_frame;
+
+               Container pane = getContentPane();
+               pane.setLayout(new GridBagLayout());
+
+               GridBagConstraints c = new GridBagConstraints();
+               c.insets = new Insets (4,4,4,4);
+
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 0;
+               c.gridy = 0;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(new JLabel("Frequency"), c);
+
+               frequency = new JTextField(12);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 1;
+               c.gridy = 0;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(frequency, c);
+
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 0;
+               c.gridy = 1;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(new JLabel("Description"), c);
+
+               description = new JTextField(12);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 1;
+               c.gridy = 1;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(description, c);
+
+               ok_button = new JButton("OK");
+               ok_button.setActionCommand("ok");
+               ok_button.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 0;
+               c.gridy = 2;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(ok_button, c);
+
+               cancel_button = new JButton("Cancel");
+               cancel_button.setActionCommand("cancel");
+               cancel_button.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 1;
+               c.gridy = 2;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(cancel_button, c);
+
+               if (existing == null)
+                       setTitle("Add New Frequency");
+               else {
+                       setTitle("Edit Existing Frequency");
+                       frequency.setText(String.format("%7.3f", existing.frequency));
+                       description.setText(existing.description);
+               }
+               getRootPane().setDefaultButton(ok_button);
+
+               pack();
+               setLocationRelativeTo(frame);
+
+       }
+
+       public AltosEditFreqUI(Frame in_frame) {
+               this(in_frame, (AltosFrequency) null);
+       }
+}
+
+public class AltosConfigFreqUI extends AltosUIDialog implements ActionListener {
+
+       Frame frame;
+       LinkedList<ActionListener> listeners;
+
+       class FrequencyList extends JList<AltosFrequency> {
+               DefaultListModel<AltosFrequency> list_model;
+
+               public void add(AltosFrequency frequency) {
+                       int i;
+                       for (i = 0; i < list_model.size(); i++) {
+                               AltosFrequency  f = (AltosFrequency) list_model.get(i);
+                               if (frequency.frequency == f.frequency)
+                                       return;
+                               if (frequency.frequency < f.frequency)
+                                       break;
+                       }
+                       list_model.insertElementAt(frequency, i);
+               }
+
+               public void remove(AltosFrequency frequency) {
+                       list_model.removeElement(frequency);
+               }
+
+               //Subclass JList to workaround bug 4832765, which can cause the
+               //scroll pane to not let the user easily scroll up to the beginning
+               //of the list.  An alternative would be to set the unitIncrement
+               //of the JScrollBar to a fixed value. You wouldn't get the nice
+               //aligned scrolling, but it should work.
+               public int getScrollableUnitIncrement(Rectangle visibleRect,
+                                                     int orientation,
+                                                     int direction) {
+                       int row;
+                       if (orientation == SwingConstants.VERTICAL &&
+                           direction < 0 && (row = getFirstVisibleIndex()) != -1) {
+                               Rectangle r = getCellBounds(row, row);
+                               if ((r.y == visibleRect.y) && (row != 0))  {
+                                       Point loc = r.getLocation();
+                                       loc.y--;
+                                       int prevIndex = locationToIndex(loc);
+                                       Rectangle prevR = getCellBounds(prevIndex, prevIndex);
+
+                                       if (prevR == null || prevR.y >= r.y) {
+                                               return 0;
+                                       }
+                                       return prevR.height;
+                               }
+                       }
+                       return super.getScrollableUnitIncrement(
+                               visibleRect, orientation, direction);
+               }
+
+               public AltosFrequency selected() {
+                       AltosFrequency  f = (AltosFrequency) getSelectedValue();
+                       return f;
+               }
+
+               public AltosFrequency[] frequencies() {
+                       AltosFrequency[]        ret;
+
+                       ret = new AltosFrequency[list_model.size()];
+                       for (int i = 0; i < list_model.size(); i++)
+                               ret[i] = (AltosFrequency) list_model.get(i);
+                       return ret;
+               }
+
+               public FrequencyList(AltosFrequency[] in_frequencies) {
+                       list_model = new DefaultListModel<AltosFrequency>();
+                       setModel(list_model);
+                       setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+                       setLayoutOrientation(JList.HORIZONTAL_WRAP);
+                       for (int i = 0; i < in_frequencies.length; i++) {
+                               add(in_frequencies[i]);
+                       }
+                       setVisibleRowCount(in_frequencies.length);
+               }
+       }
+
+       FrequencyList   frequencies;
+
+       void save_frequencies() {
+               AltosUIPreferences.set_common_frequencies(frequencies.frequencies());
+       }
+
+       JButton add, edit, remove;
+
+       JButton cancel, ok;
+
+       public void actionPerformed(ActionEvent e) {
+               String  cmd = e.getActionCommand();
+
+               if ("ok".equals(cmd)) {
+                       save_frequencies();
+                       setVisible(false);
+               } else if ("cancel".equals(cmd)) {
+                       setVisible(false);
+               } else if ("add".equals(cmd)) {
+                       AltosEditFreqUI ui = new AltosEditFreqUI(frame);
+                       ui.setVisible(true);
+                       AltosFrequency  f = ui.get();
+                       if (f != null)
+                               frequencies.add(f);
+               } else if ("edit".equals(cmd)) {
+                       AltosFrequency  old_f = frequencies.selected();
+                       if (old_f == null)
+                               return;
+                       AltosEditFreqUI ui = new AltosEditFreqUI(frame, old_f);
+                       ui.setVisible(true);
+                       AltosFrequency  new_f = ui.get();
+                       if (new_f != null) {
+                               if (old_f != null)
+                                       frequencies.remove(old_f);
+                               frequencies.add(new_f);
+                       }
+               } else if ("remove".equals(cmd)) {
+                       AltosFrequency  old_f = frequencies.selected();
+                       if (old_f == null)
+                               return;
+                       int ret = JOptionPane.showConfirmDialog(this,
+                                                               String.format("Remove frequency \"%s\"?",
+                                                                             old_f.toShortString()),
+                                                               "Remove Frequency",
+                                                               JOptionPane.YES_NO_OPTION);
+                       if (ret == JOptionPane.YES_OPTION)
+                               frequencies.remove(old_f);
+               }
+       }
+
+       public AltosFrequency[] frequencies() {
+               return frequencies.frequencies();
+       }
+
+       public AltosConfigFreqUI(Frame in_frame,
+                                AltosFrequency[] in_frequencies) {
+               super(in_frame, "Manage Frequencies", true);
+
+               frame = in_frame;
+
+               listeners = new LinkedList<ActionListener>();
+
+               frequencies = new FrequencyList(in_frequencies);
+
+               Container pane = getContentPane();
+               pane.setLayout(new GridBagLayout());
+
+               GridBagConstraints c = new GridBagConstraints();
+               c.insets = new Insets(4,4,4,4);
+
+               /*
+                * Frequencies label and list
+                */
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 0;
+               c.gridy = 0;
+               c.gridwidth = 1;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(new JLabel("Frequencies"), c);
+
+               JScrollPane list_scroller = new JScrollPane(frequencies);
+               list_scroller.setAlignmentX(LEFT_ALIGNMENT);
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.WEST;
+               c.gridx = 0;
+               c.gridy = 1;
+               c.gridwidth = 6;
+               c.gridheight = 2;
+               c.weightx = 1;
+               c.weighty = 1;
+               pane.add(list_scroller, c);
+
+               add = new JButton("Add");
+               add.setActionCommand("add");
+               add.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 0;
+               c.gridy = 3;
+               c.gridwidth = 2;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(add, c);
+
+               edit = new JButton("Edit");
+               edit.setActionCommand("edit");
+               edit.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 2;
+               c.gridy = 3;
+               c.gridwidth = 2;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(edit, c);
+
+               remove = new JButton("Remove");
+               remove.setActionCommand("remove");
+               remove.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 4;
+               c.gridy = 3;
+               c.gridwidth = 2;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(remove, c);
+
+               ok = new JButton("OK");
+               ok.setActionCommand("ok");
+               ok.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 0;
+               c.gridy = 4;
+               c.gridwidth = 3;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(ok, c);
+
+               cancel = new JButton("Cancel");
+               cancel.setActionCommand("cancel");
+               cancel.addActionListener(this);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.gridx = 3;
+               c.gridy = 4;
+               c.gridwidth = 3;
+               c.gridheight = 1;
+               c.weightx = 0;
+               c.weighty = 0;
+               pane.add(cancel, c);
+
+               pack();
+               setLocationRelativeTo(frame);
+       }
+
+       public static void show(Component frameComp) {
+               Frame   frame = JOptionPane.getFrameForComponent(frameComp);
+               AltosConfigFreqUI       dialog;
+
+               dialog = new AltosConfigFreqUI(frame, AltosUIPreferences.common_frequencies());
+               dialog.setVisible(true);
+       }
+
+}
diff --git a/altosuilib/AltosDataChooser.java b/altosuilib/AltosDataChooser.java
new file mode 100644 (file)
index 0000000..59891c4
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.altosuilib_2;
+
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import java.io.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosDataChooser extends JFileChooser {
+       JFrame  frame;
+       String  filename;
+       File    file;
+
+       public String filename() {
+               return filename;
+       }
+
+       public File file() {
+               return file;
+       }
+
+       public AltosStateIterable runDialog() {
+               int     ret;
+
+               ret = showOpenDialog(frame);
+               if (ret == APPROVE_OPTION) {
+                       file = getSelectedFile();
+                       if (file == null)
+                               return null;
+                       filename = file.getName();
+                       try {
+                               if (filename.endsWith("eeprom")) {
+                                       FileInputStream in = new FileInputStream(file);
+                                       return new AltosEepromFile(in);
+                               } else if (filename.endsWith("telem")) {
+                                       FileInputStream in = new FileInputStream(file);
+                                       return new AltosTelemetryFile(in);
+                               } else {
+                                       throw new FileNotFoundException();
+                               }
+                       } catch (FileNotFoundException fe) {
+                               JOptionPane.showMessageDialog(frame,
+                                                             fe.getMessage(),
+                                                             "Cannot open file",
+                                                             JOptionPane.ERROR_MESSAGE);
+                       }
+               }
+               return null;
+       }
+
+       public AltosDataChooser(JFrame in_frame) {
+               frame = in_frame;
+               setDialogTitle("Select Flight Record File");
+               setFileFilter(new FileNameExtensionFilter("On-board Log file",
+                                                         "eeprom"));
+               setFileFilter(new FileNameExtensionFilter("Telemetry file",
+                                                         "telem"));
+               setFileFilter(new FileNameExtensionFilter("Flight data file",
+                                                         "telem", "eeprom"));
+               setCurrentDirectory(AltosUIPreferences.logdir());
+       }
+}
index 2461df1b08f8f04bb519e020750d637453c8467d..251ae994cb21087c417ebd31ae8e96061289bb8e 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import libaltosJNI.*;
 
index 73bc0b2f5141cd117b15c0c2d7d2e3f458556bc4..0bedea97b75019ea597cf160a493491fb8ffae7f 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import javax.swing.*;
 import java.awt.*;
@@ -23,14 +23,14 @@ import java.awt.event.*;
 
 public abstract class AltosDeviceDialog extends AltosUIDialog implements ActionListener {
 
-       private AltosDevice     value;
-       private JList           list;
-       private JButton         cancel_button;
-       private JButton         select_button;
-       public Frame            frame;
-       public int              product;
-       public JPanel           buttonPane;
-       
+       private AltosDevice             value;
+       private JList<AltosDevice>      list;
+       private JButton                 cancel_button;
+       private JButton                 select_button;
+       public Frame                    frame;
+       public int                      product;
+       public JPanel                   buttonPane;
+
        public AltosDevice getValue() {
                return value;
        }
@@ -65,7 +65,7 @@ public abstract class AltosDeviceDialog extends AltosUIDialog implements ActionL
                        select_button.setEnabled(false);
                getRootPane().setDefaultButton(select_button);
 
-               list = new JList(devices) {
+               list = new JList<AltosDevice>(devices) {
                                //Subclass JList to workaround bug 4832765, which can cause the
                                //scroll pane to not let the user easily scroll up to the beginning
                                //of the list.  An alternative would be to set the unitIncrement
diff --git a/altosuilib/AltosDeviceUIDialog.java b/altosuilib/AltosDeviceUIDialog.java
new file mode 100644 (file)
index 0000000..3013612
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.altosuilib_2;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+
+public class AltosDeviceUIDialog extends AltosDeviceDialog {
+
+       public AltosDevice[] devices() {
+               java.util.List<AltosDevice>     usb_devices = AltosUSBDevice.list(product);
+               int                             num_devices = usb_devices.size();
+               java.util.List<AltosDevice>     bt_devices = AltosBTKnown.bt_known().list(product);
+               num_devices += bt_devices.size();
+               AltosDevice[]                   devices = new AltosDevice[num_devices];
+
+               for (int i = 0; i < usb_devices.size(); i++)
+                       devices[i] = usb_devices.get(i);
+               int off = usb_devices.size();
+               for (int j = 0; j < bt_devices.size(); j++)
+                       devices[off + j] = bt_devices.get(j);
+               return devices;
+       }
+
+       public void add_bluetooth() {
+               JButton manage_bluetooth_button = new JButton("Manage Bluetooth");
+               manage_bluetooth_button.setActionCommand("manage");
+               manage_bluetooth_button.addActionListener(this);
+               buttonPane.add(manage_bluetooth_button);
+               buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
+       }
+
+       public void actionPerformed(ActionEvent e) {
+               super.actionPerformed(e);
+               if ("manage".equals(e.getActionCommand())) {
+                       AltosBTManage.show(frame, AltosBTKnown.bt_known());
+                       update_devices();
+               }
+       }
+
+       public AltosDeviceUIDialog (Frame in_frame, Component location, int in_product) {
+               super(in_frame, location, in_product);
+       }
+
+       public static AltosDevice show (Component frameComp, int product) {
+               Frame                   frame = JOptionPane.getFrameForComponent(frameComp);
+               AltosDeviceUIDialog     dialog;
+
+               dialog = new AltosDeviceUIDialog(frame, frameComp, product);
+               dialog.setVisible(true);
+               return dialog.getValue();
+       }
+}
diff --git a/altosuilib/AltosDisplayThread.java b/altosuilib/AltosDisplayThread.java
new file mode 100644 (file)
index 0000000..06bc68a
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import javax.swing.*;
+import java.io.*;
+import java.text.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosDisplayThread extends Thread {
+
+       Frame                   parent;
+       IdleThread              idle_thread;
+       AltosVoice              voice;
+       AltosFlightReader       reader;
+       AltosState              old_state, state;
+       AltosListenerState      listener_state;
+       AltosFlightDisplay      display;
+
+       synchronized void show_safely() {
+               final AltosState my_state = state;
+               final AltosListenerState my_listener_state = listener_state;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               display.show(my_state, my_listener_state);
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       void reading_error_internal() {
+               JOptionPane.showMessageDialog(parent,
+                                             String.format("Error reading from \"%s\"", reader.name),
+                                             "Telemetry Read Error",
+                                             JOptionPane.ERROR_MESSAGE);
+       }
+
+       void reading_error_safely() {
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               reading_error_internal();
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       class IdleThread extends Thread {
+
+               boolean started;
+               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.from_pad != null &&
+                           state.range >= 0)
+                       {
+                               voice.speak("Height %s, bearing %s %d, elevation %d, range %s.\n",
+                                           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 > AltosLib.ao_flight_pad && state.height() != AltosLib.MISSING) {
+                               voice.speak(AltosConvert.height.say_units(state.height()));
+                       } 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_stateless &&
+                           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)
+                                       voice.speak("rocket landed safely");
+                               else
+                                       voice.speak("rocket may have crashed");
+                               if (state.from_pad != null)
+                                       voice.speak("Bearing %d degrees, range %s.",
+                                                   (int) (state.from_pad.bearing + 0.5),
+                                                   AltosConvert.distance.say_units(state.from_pad.distance));
+                               ++reported_landing;
+                               if (state.state != AltosLib.ao_flight_landed) {
+                                       state.state = AltosLib.ao_flight_landed;
+                                       show_safely();
+                               }
+                       }
+               }
+
+               long now () {
+                       return System.currentTimeMillis();
+               }
+
+               void set_report_time() {
+                       report_time = now() + report_interval;
+               }
+
+               public void run () {
+                       try {
+                               for (;;) {
+                                       if (reader.has_monitor_battery()) {
+                                               listener_state.battery = reader.monitor_battery();
+                                               show_safely();
+                                       }
+                                       set_report_time();
+                                       for (;;) {
+                                               voice.drain();
+                                               synchronized (this) {
+                                                       long    sleep_time = report_time - now();
+                                                       if (sleep_time <= 0)
+                                                               break;
+                                                       wait(sleep_time);
+                                               }
+                                       }
+
+                                       report(false);
+                               }
+                       } catch (InterruptedException ie) {
+                               try {
+                                       voice.drain();
+                               } catch (InterruptedException iie) { }
+                       }
+               }
+
+               public synchronized void notice(boolean spoken) {
+                       if (old_state != null && old_state.state != state.state) {
+                               report_time = now();
+                               this.notify();
+                       } else if (spoken)
+                               set_report_time();
+               }
+
+               public IdleThread() {
+                       reported_landing = 0;
+                       report_interval = 10000;
+               }
+       }
+
+       synchronized boolean tell() {
+               boolean ret = false;
+               if (old_state == null || old_state.state != state.state) {
+                       if (state.state != AltosLib.ao_flight_stateless)
+                               voice.speak(state.state_name());
+                       if ((old_state == null || old_state.state <= AltosLib.ao_flight_boost) &&
+                           state.state > AltosLib.ao_flight_boost) {
+                               if (state.max_speed() != AltosLib.MISSING)
+                                       voice.speak("max speed: %s.",
+                                                   AltosConvert.speed.say_units(state.max_speed() + 0.5));
+                               ret = true;
+                       } else if ((old_state == null || old_state.state < AltosLib.ao_flight_drogue) &&
+                                  state.state >= AltosLib.ao_flight_drogue) {
+                               if (state.max_height() != AltosLib.MISSING)
+                                       voice.speak("max height: %s.",
+                                                   AltosConvert.height.say_units(state.max_height() + 0.5));
+                               ret = true;
+                       }
+               }
+               if (old_state == null || old_state.gps_ready != state.gps_ready) {
+                       if (state.gps_ready) {
+                               voice.speak("GPS ready");
+                               ret = true;
+                       }
+                       else if (old_state != null) {
+                               voice.speak("GPS lost");
+                               ret = true;
+                       }
+               }
+               old_state = state;
+               return ret;
+       }
+
+       public void run() {
+               boolean         interrupted = false;
+               boolean         told;
+
+               idle_thread = new IdleThread();
+               idle_thread.start();
+
+               try {
+                       for (;;) {
+                               try {
+                                       state = reader.read();
+                                       if (state == null)
+                                               break;
+                                       reader.update(state);
+                                       show_safely();
+                                       told = tell();
+                                       idle_thread.notice(told);
+                               } catch (ParseException pp) {
+                                       System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage());
+                               } catch (AltosCRCException ce) {
+                                       ++listener_state.crc_errors;
+                                       show_safely();
+                               }
+                       }
+               } catch (InterruptedException ee) {
+                       interrupted = true;
+               } catch (IOException ie) {
+                       reading_error_safely();
+               } finally {
+                       if (!interrupted)
+                               idle_thread.report(true);
+                       reader.close(interrupted);
+                       idle_thread.interrupt();
+                       try {
+                               idle_thread.join();
+                       } catch (InterruptedException ie) {}
+               }
+       }
+
+       public AltosDisplayThread(Frame in_parent, AltosVoice in_voice, AltosFlightDisplay in_display, AltosFlightReader in_reader) {
+               listener_state = new AltosListenerState();
+               parent = in_parent;
+               voice = in_voice;
+               display = in_display;
+               reader = in_reader;
+               display.reset();
+       }
+}
diff --git a/altosuilib/AltosEepromDelete.java b/altosuilib/AltosEepromDelete.java
new file mode 100644 (file)
index 0000000..981dadd
--- /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.
+ */
+
+package org.altusmetrum.altosuilib_2;
+
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosEepromDelete implements Runnable {
+       AltosEepromList         flights;
+       Thread                  eeprom_thread;
+       AltosSerial             serial_line;
+       boolean                 remote;
+       JFrame                  frame;
+       ActionListener          listener;
+       boolean                 success;
+
+       private void DeleteLog (AltosEepromLog log)
+               throws IOException, InterruptedException, TimeoutException {
+
+               if (flights.config_data.flight_log_max != 0 || flights.config_data.log_format != 0) {
+
+                       /* Devices with newer firmware can erase the
+                        * flash blocks containing each flight
+                        */
+                       serial_line.flush_input();
+                       serial_line.printf("d %d\n", log.flight);
+                       for (;;) {
+                               /* It can take a while to erase the flash... */
+                               String line = serial_line.get_reply(20000);
+                               if (line == null)
+                                       throw new TimeoutException();
+                               if (line.equals("Erased"))
+                                       break;
+                               if (line.startsWith("No such"))
+                                       throw new IOException(line);
+                       }
+               }
+       }
+
+       private void show_error_internal(String message, String title) {
+               JOptionPane.showMessageDialog(frame,
+                                             message,
+                                             title,
+                                             JOptionPane.ERROR_MESSAGE);
+       }
+
+       private void show_error(String in_message, String in_title) {
+               final String message = in_message;
+               final String title = in_title;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               show_error_internal(message, title);
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       public void run () {
+               success = false;
+               try {
+                       if (remote)
+                               serial_line.start_remote();
+
+                       for (AltosEepromLog log : flights) {
+                               if (log.selected) {
+                                       DeleteLog(log);
+                               }
+                       }
+                       success = true;
+               } catch (IOException ee) {
+                       show_error (ee.getLocalizedMessage(),
+                                   serial_line.device.toShortString());
+               } catch (InterruptedException ie) {
+               } catch (TimeoutException te) {
+                       show_error (String.format("Connection to \"%s\" failed",
+                                                 serial_line.device.toShortString()),
+                                   "Connection Failed");
+               } finally {
+                       try {
+                               if (remote)
+                                       serial_line.stop_remote();
+                       } catch (InterruptedException ie) {
+                       } finally {
+                               serial_line.flush_output();
+                               serial_line.close();
+                       }
+               }
+               if (listener != null) {
+                       Runnable r = new Runnable() {
+                                       public void run() {
+                                               try {
+                                                       listener.actionPerformed(new ActionEvent(this,
+                                                                                                success ? 1 : 0,
+                                                                                                "delete"));
+                                               } 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 AltosEepromDelete(JFrame given_frame,
+                                AltosSerial given_serial_line,
+                                boolean given_remote,
+                                AltosEepromList given_flights) {
+               frame = given_frame;
+               serial_line = given_serial_line;
+               remote = given_remote;
+               flights = given_flights;
+               success = false;
+       }
+}
diff --git a/altosuilib/AltosEepromManage.java b/altosuilib/AltosEepromManage.java
new file mode 100644 (file)
index 0000000..2b96733
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosEepromManage implements ActionListener {
+
+       JFrame                  frame;
+       boolean                 remote;
+       AltosDevice             device;
+       AltosSerial             serial_line;
+       AltosEepromList         flights;
+       AltosEepromDownload     download;
+       AltosEepromDelete       delete;
+
+       public void finish() {
+               if (serial_line != null) {
+                       try {
+                               serial_line.flush_input();
+                       } catch (InterruptedException ie) {
+                       }
+                       serial_line.close();
+                       serial_line = null;
+               }
+       }
+
+       private int countDeletedFlights() {
+               int count = 0;
+               for (AltosEepromLog flight : flights) {
+                       if (flight.selected)
+                               count++;
+               }
+               return count;
+       }
+
+       private String showDeletedFlights() {
+               String  result = "";
+
+               for (AltosEepromLog flight : flights) {
+                       if (flight.selected) {
+                               if (result.equals(""))
+                                       result = String.format("%d", flight.flight);
+                               else
+                                       result = String.format("%s, %d", result, flight.flight);
+                       }
+               }
+               return result;
+       }
+
+       public boolean download_done() {
+               AltosEepromSelect       select = new AltosEepromSelect(frame, flights, "Delete");
+
+               if (select.run()) {
+                       boolean any_selected = false;
+                       for (AltosEepromLog flight : flights)
+                               any_selected = any_selected || flight.selected;
+                       if (any_selected) {
+                               delete = new AltosEepromDelete(frame,
+                                                              serial_line,
+                                                              remote,
+                                                              flights);
+                               delete.addActionListener(this);
+                               /*
+                                * Start flight log delete
+                                */
+
+                               delete.start();
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       public void actionPerformed(ActionEvent e) {
+               String  cmd = e.getActionCommand();
+               boolean success = e.getID() != 0;
+               boolean running = false;
+
+               if (cmd.equals("download")) {
+                       if (success)
+                               running = download_done();
+               } else if (cmd.equals("delete")) {
+                       if (success) {
+                               JOptionPane.showMessageDialog(frame,
+                                                             String.format("%d flights erased: %s",
+                                                                           countDeletedFlights(),
+                                                                           showDeletedFlights()),
+                                                             serial_line.device.toShortString(),
+                                                             JOptionPane.INFORMATION_MESSAGE);
+                       }
+               }
+               if (!running)
+                       finish();
+       }
+
+       public void got_flights(AltosEepromList in_flights) {
+               boolean running = false;;
+
+               flights = in_flights;
+               try {
+                       if (flights.size() == 0) {
+                               JOptionPane.showMessageDialog(frame,
+                                                             String.format("No flights available on %d",
+                                                                           device.getSerial()),
+                                                             serial_line.device.toShortString(),
+                                                             JOptionPane.INFORMATION_MESSAGE);
+                       } else {
+                               AltosEepromSelect       select = new AltosEepromSelect(frame, flights, "Download");
+
+                               if (select.run()) {
+                                       boolean any_selected = false;
+                                       for (AltosEepromLog flight : flights)
+                                               any_selected = any_selected || flight.selected;
+                                       if (any_selected) {
+                                               AltosEepromMonitorUI monitor = new AltosEepromMonitorUI(frame);
+                                               monitor.addActionListener(this);
+                                               serial_line.set_frame(frame);
+                                               download = new AltosEepromDownload(monitor,
+                                                                                  serial_line,
+                                                                                  remote,
+                                                                                  flights);
+                                               /*
+                                                * Start flight log download
+                                                */
+
+                                               download.start();
+                                               running = true;
+                                       } else {
+                                               running = download_done();
+                                       }
+                               }
+                       }
+                       if (!running)
+                               finish();
+               } catch (Exception e) {
+                       got_exception(e);
+               }
+       }
+
+       public void got_exception(Exception e) {
+               if (e instanceof IOException) {
+                       IOException     ee = (IOException) e;
+                       JOptionPane.showMessageDialog(frame,
+                                                     device.toShortString(),
+                                                     ee.getLocalizedMessage(),
+                                                     JOptionPane.ERROR_MESSAGE);
+               } else if (e instanceof TimeoutException) {
+                       //TimeoutException te = (TimeoutException) e;
+                       JOptionPane.showMessageDialog(frame,
+                                                     String.format("Communications failed with \"%s\"",
+                                                                   device.toShortString()),
+                                                     "Cannot open target device",
+                                                     JOptionPane.ERROR_MESSAGE);
+               }
+               finish();
+       }
+
+       class EepromGetList implements Runnable {
+
+               AltosEepromManage       manage;
+
+               public void run () {
+                       Runnable r;
+                       try {
+                               flights = new AltosEepromList(serial_line, remote);
+                               r = new Runnable() {
+                                               public void run() {
+                                                       got_flights(flights);
+                                               }
+                                       };
+                       } catch (Exception e) {
+                               final Exception f_e = e;
+                               r = new Runnable() {
+                                               public void run() {
+                                                       got_exception(f_e);
+                                               }
+                                       };
+                       }
+                       SwingUtilities.invokeLater(r);
+               }
+
+               public EepromGetList(AltosEepromManage in_manage) {
+                       manage = in_manage;
+               }
+       }
+
+       public AltosEepromManage(JFrame given_frame, int product) {
+
+               //boolean       running = false;
+
+               frame = given_frame;
+               device = AltosDeviceUIDialog.show(frame, product);
+
+               remote = false;
+
+               if (device != null) {
+                       try {
+                               serial_line = new AltosSerial(device);
+                               if (device.matchProduct(AltosLib.product_basestation))
+                                       remote = true;
+
+                               serial_line.set_frame(frame);
+
+                               EepromGetList   get_list = new EepromGetList(this);
+                               Thread          t = new Thread(get_list);
+                               t.start();
+                       } catch (FileNotFoundException ee) {
+                               JOptionPane.showMessageDialog(frame,
+                                                             ee.getMessage(),
+                                                             "Cannot open target device",
+                                                             JOptionPane.ERROR_MESSAGE);
+                       } catch (AltosSerialInUseException si) {
+                               JOptionPane.showMessageDialog(frame,
+                                                             String.format("Device \"%s\" already in use",
+                                                                           device.toShortString()),
+                                                             "Device in use",
+                                                             JOptionPane.ERROR_MESSAGE);
+                       }
+               }
+       }
+}
diff --git a/altosuilib/AltosEepromMonitor.java b/altosuilib/AltosEepromMonitor.java
new file mode 100644 (file)
index 0000000..b1e8562
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+public class AltosEepromMonitor extends AltosUIDialog {
+
+       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;
+
+       public AltosEepromMonitor(JFrame owner, int in_min_state, int in_max_state) {
+               super (owner, "Download Flight Data", false);
+
+               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);
+
+               min_state = in_min_state;
+               max_state = in_max_state;
+               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);
+               setVisible(true);
+       }
+
+       public void addActionListener (ActionListener l) {
+               cancel.addActionListener(l);
+       }
+
+       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_file_internal(String file) {
+               file_value.setText(String.format("%s", file));
+       }
+
+       public void set_file(String in_file) {
+               final String file = in_file;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               set_file_internal(file);
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       private void done_internal() {
+               setVisible(false);
+               dispose();
+       }
+
+       public void done() {
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               done_internal();
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       private void reset_internal() {
+               set_value_internal("startup",min_state,0, 0);
+               set_flight_internal(0);
+               set_file_internal("");
+       }
+
+       public void reset() {
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               reset_internal();
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+}
diff --git a/altosuilib/AltosEepromMonitorUI.java b/altosuilib/AltosEepromMonitorUI.java
new file mode 100644 (file)
index 0000000..02c71cd
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+
+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);
+       }
+}
diff --git a/altosuilib/AltosEepromSelect.java b/altosuilib/AltosEepromSelect.java
new file mode 100644 (file)
index 0000000..293d304
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * 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.altosuilib_2;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import java.awt.*;
+import java.awt.event.*;
+import org.altusmetrum.altoslib_4.*;
+
+class AltosEepromItem implements ActionListener {
+       AltosEepromLog  log;
+       JLabel          label;
+       JCheckBox       action;
+       JCheckBox       delete;
+
+       public void actionPerformed(ActionEvent e) {
+               log.selected = action.isSelected();
+       }
+
+       public AltosEepromItem(AltosEepromLog in_log) {
+               log = in_log;
+
+               String  text;
+               if (log.year != 0)
+                       text = String.format("Flight #%02d - %04d-%02d-%02d",
+                                            log.flight, log.year, log.month, log.day);
+               else
+                       text = String.format("Flight #%02d", log.flight);
+
+               label = new JLabel(text);
+
+               action = new JCheckBox("", log.selected);
+               action.addActionListener(this);
+       }
+}
+
+public class AltosEepromSelect extends AltosUIDialog implements ActionListener {
+       //private JList                 list;
+       private JFrame                  frame;
+       JButton                         ok;
+       JButton                         cancel;
+       boolean                         success;
+
+       /* Listen for events from our buttons */
+       public void actionPerformed(ActionEvent e) {
+               String  cmd = e.getActionCommand();
+
+               if (cmd.equals("ok"))
+                       success = true;
+               setVisible(false);
+       }
+
+       public boolean run() {
+               success = false;
+               setLocationRelativeTo(frame);
+               setVisible(true);
+               return success;
+       }
+
+       public AltosEepromSelect (JFrame in_frame,
+                                 AltosEepromList flights,
+                                 String action) {
+
+               super(in_frame, String.format("Flight list for serial %d", flights.config_data.serial), true);
+               frame = in_frame;
+
+               /* Create the container for the dialog */
+               Container contentPane = getContentPane();
+
+               /* First, we create a pane containing the dialog's header/title */
+               JLabel  selectLabel = new JLabel(String.format ("Select flights to %s", action), SwingConstants.CENTER);
+
+               JPanel  labelPane = new JPanel();
+               labelPane.setLayout(new BoxLayout(labelPane, BoxLayout.X_AXIS));
+               labelPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
+               labelPane.add(Box.createHorizontalGlue());
+               labelPane.add(selectLabel);
+               labelPane.add(Box.createHorizontalGlue());
+
+               /* Add the header to the container. */
+               contentPane.add(labelPane, BorderLayout.PAGE_START);
+
+
+               /* Now we create the evilness that is a GridBag for the flight details */
+               GridBagConstraints c;
+               Insets i = new Insets(4,4,4,4);
+               JPanel flightPane = new JPanel();
+               flightPane.setLayout(new GridBagLayout());
+               flightPane.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+
+               /* Flight Header */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 0;
+               c.fill = GridBagConstraints.NONE;
+               c.weightx = 0.5;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               JLabel flightHeaderLabel = new JLabel("Flight");
+               flightPane.add(flightHeaderLabel, c);
+
+               /* Download Header */
+               c = new GridBagConstraints();
+               c.gridx = 1; c.gridy = 0;
+               c.fill = GridBagConstraints.NONE;
+               c.weightx = 0.5;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               JLabel downloadHeaderLabel = new JLabel(action);
+               flightPane.add(downloadHeaderLabel, c);
+
+               /* Add the flights to the GridBag */
+               AltosEepromItem item;
+               int itemNumber = 1;
+               for (AltosEepromLog flight : flights) {
+                       /* Create a flight object with handlers and
+                        * appropriate UI items
+                        */
+                       item = new AltosEepromItem(flight);
+
+                       /* Add a decriptive label for the flight */
+                       c = new GridBagConstraints();
+                       c.gridx = 0; c.gridy = itemNumber;
+                       c.fill = GridBagConstraints.NONE;
+                       c.weightx = 0.5;
+                       c.anchor = GridBagConstraints.CENTER;
+                       c.insets = i;
+                       flightPane.add(item.label, c);
+
+                       /* Add action checkbox for the flight */
+                       c = new GridBagConstraints();
+                       c.gridx = 1; c.gridy = itemNumber;
+                       c.fill = GridBagConstraints.NONE;
+                       c.weightx = 0.5;
+                       c.anchor = GridBagConstraints.CENTER;
+                       c.insets = i;
+                       flightPane.add(item.action, c);
+
+                       itemNumber++;
+               }
+
+               /* Add the GridBag to the container */
+               contentPane.add(flightPane, BorderLayout.CENTER);
+
+               /* Create the dialog buttons */
+               ok = new JButton("OK");
+               ok.addActionListener(this);
+               ok.setActionCommand("ok");
+
+               cancel = new JButton("Cancel");
+               cancel.addActionListener(this);
+               cancel.setActionCommand("cancel");
+
+               JPanel  buttonPane = new JPanel();
+               buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS));
+               buttonPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+               buttonPane.add(Box.createHorizontalGlue());
+               buttonPane.add(cancel);
+               buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
+               buttonPane.add(ok);
+
+               /* Add the buttons to the container */
+               contentPane.add(buttonPane, BorderLayout.PAGE_END);
+
+               /* Pack the window! */
+               pack();
+       }
+}
diff --git a/altosuilib/AltosFlashUI.java b/altosuilib/AltosFlashUI.java
new file mode 100644 (file)
index 0000000..3f12061
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import java.io.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosFlashUI
+       extends AltosUIDialog
+       implements ActionListener
+{
+       Container       pane;
+       Box             box;
+       JLabel          serial_label;
+       JLabel          serial_value;
+       JLabel          file_label;
+       JLabel          file_value;
+       JProgressBar    pbar;
+       JButton         cancel;
+
+       AltosUIFrame    frame;
+
+       // Hex file with rom image
+       File            file;
+
+       // Debug connection
+       AltosDevice     device;
+
+       AltosLink       link;
+
+       // Desired Rom configuration
+       AltosRomconfig  rom_config;
+
+       // Flash controller
+       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 (programmer != null)
+                               programmer.abort();
+                       setVisible(false);
+                       dispose();
+               } else {
+                       String  cmd = e.getActionCommand();
+                       if (e.getID() == -1) {
+                               JOptionPane.showMessageDialog(frame,
+                                                             e.getActionCommand(),
+                                                             file.toString(),
+                                                             JOptionPane.ERROR_MESSAGE);
+                               setVisible(false);
+                               dispose();
+                       } else if (cmd.equals("done")) {
+                               setVisible(false);
+                               dispose();
+                       } else if (cmd.equals("start")) {
+                               setVisible(true);
+                       } else {
+                               pbar.setValue(e.getID());
+                               pbar.setString(cmd);
+                       }
+               }
+       }
+
+       public void build_dialog() {
+               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;
+               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 = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               file_value = new JLabel(file.toString());
+               pane.add(file_value, c);
+
+               pbar = new JProgressBar();
+               pbar.setMinimum(0);
+               pbar.setMaximum(100);
+               pbar.setValue(0);
+               pbar.setString("");
+               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 = 2;
+               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 = 3;
+               c.gridwidth = GridBagConstraints.REMAINDER;
+               Insets ic = new Insets(4,4,4,4);
+               c.insets = ic;
+               pane.add(cancel, c);
+               cancel.addActionListener(this);
+               pack();
+               setLocationRelativeTo(frame);
+       }
+
+       void set_serial(int serial_number) {
+               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();
+
+               File firmwaredir = AltosUIPreferences.firmwaredir();
+               if (firmwaredir != null)
+                       hexfile_chooser.setCurrentDirectory(firmwaredir);
+
+               hexfile_chooser.setDialogTitle("Select Flash Image");
+
+               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)
+                       return false;
+               file = hexfile_chooser.getSelectedFile();
+               if (file == null)
+                       return false;
+               AltosUIPreferences.set_firmwaredir(file.getParentFile());
+
+               return true;
+       }
+
+       boolean select_device() {
+               int     product = AltosLib.product_any;
+
+               device = AltosDeviceUIDialog.show(frame, AltosLib.product_any);
+
+               if (device == null)
+                       return false;
+               return true;
+       }
+
+       boolean update_rom_config_info(AltosRomconfig existing_config) {
+               AltosRomconfig  new_config;
+               new_config = AltosRomconfigUI.show(frame, existing_config);
+               if (new_config == null)
+                       return false;
+               rom_config = new_config;
+               set_serial(rom_config.serial_number);
+               setVisible(true);
+               return true;
+       }
+
+       void exception (Exception e) {
+               if (e instanceof FileNotFoundException) {
+                       JOptionPane.showMessageDialog(frame,
+                                                     ((FileNotFoundException) e).getMessage(),
+                                                     "Cannot open file",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } else if (e instanceof AltosSerialInUseException) {
+                       JOptionPane.showMessageDialog(frame,
+                                                     String.format("Device \"%s\" already in use",
+                                                                   device.toShortString()),
+                                                     "Device in use",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } else if (e instanceof IOException) {
+                       JOptionPane.showMessageDialog(frame,
+                                                     e.getMessage(),
+                                                     file.toString(),
+                                                     JOptionPane.ERROR_MESSAGE);
+               }
+       }
+
+       class flash_task implements Runnable, AltosFlashListener {
+               AltosFlashUI    ui;
+               Thread          t;
+               AltosProgrammer programmer;
+
+               public void position(String in_s, int in_percent) {
+                       final String s = in_s;
+                       final int percent = in_percent;
+                       Runnable r = new Runnable() {
+                                       public void run() {
+                                               try {
+                                                       ui.actionPerformed(new ActionEvent(this,
+                                                                                          percent,
+                                                                                          s));
+                                               } catch (Exception ex) {
+                                               }
+                                       }
+                               };
+                       SwingUtilities.invokeLater(r);
+               }
+
+               public void run () {
+                       try {
+                               if (ui.is_pair_programmed())
+                                       programmer = new AltosFlash(ui.file, link, this);
+                               else
+                                       programmer = new AltosSelfFlash(ui.file, link, this);
+
+                               final AltosRomconfig    current_config = programmer.romconfig();
+
+                               final Semaphore await_rom_config = new Semaphore(0);
+                               SwingUtilities.invokeLater(new Runnable() {
+                                               public void run() {
+                                                       ui.programmer = programmer;
+                                                       ui.update_rom_config_info(current_config);
+                                                       await_rom_config.release();
+                                               }
+                                       });
+                               await_rom_config.acquire();
+
+                               if (ui.rom_config != null) {
+                                       programmer.set_romconfig(ui.rom_config);
+                                       programmer.flash();
+                               }
+                       } catch (InterruptedException ee) {
+                               final Exception e = ee;
+                               SwingUtilities.invokeLater(new Runnable() {
+                                               public void run() {
+                                                       ui.exception(e);
+                                               }
+                                       });
+                       } catch (IOException ee) {
+                               final Exception e = ee;
+                               SwingUtilities.invokeLater(new Runnable() {
+                                               public void run() {
+                                                       ui.exception(e);
+                                               }
+                                       });
+                       } finally {
+                               if (programmer != null)
+                                       programmer.close();
+                       }
+               }
+
+               public flash_task(AltosFlashUI in_ui) {
+                       ui = in_ui;
+                       t = new Thread(this);
+                       t.start();
+               }
+       }
+
+       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 = null;
+
+                               for (int tries = 0; tries < 10; tries++) {
+                                       Thread.sleep(100);
+                                       devices = AltosUSBDevice.list(AltosLib.product_altusmetrum);
+                                       if (devices.size() != 0)
+                                               break;
+                               }
+
+                               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_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);
+       }
+
+       public static void show(AltosUIFrame frame) {
+               AltosFlashUI    ui = new AltosFlashUI(frame);
+               ui.showDialog();
+       }
+
+       public AltosFlashUI(AltosUIFrame in_frame) {
+               super(in_frame, "Program Altusmetrum Device", false);
+
+               frame = in_frame;
+       }
+}
diff --git a/altosuilib/AltosFlightDisplay.java b/altosuilib/AltosFlightDisplay.java
new file mode 100644 (file)
index 0000000..55b7403
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.altosuilib_2;
+
+import org.altusmetrum.altoslib_4.*;
+
+public interface AltosFlightDisplay extends AltosUnitsListener, AltosFontListener {
+       void reset();
+
+       void show(AltosState state, AltosListenerState listener_state);
+
+       String getName();
+}
diff --git a/altosuilib/AltosFlightInfoTableModel.java b/altosuilib/AltosFlightInfoTableModel.java
new file mode 100644 (file)
index 0000000..3995efb
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.altosuilib_2;
+
+import javax.swing.table.*;
+
+public class AltosFlightInfoTableModel extends AbstractTableModel {
+       final static private String[] columnNames = {"Field", "Value"};
+
+       int     rows;
+       int     cols;
+       private String[][] data;
+
+       public int getColumnCount() { return cols; }
+       public int getRowCount() { return rows; }
+       public String getColumnName(int col) { return columnNames[col & 1]; }
+
+       public Object getValueAt(int row, int col) {
+               if (row >= rows || col >= cols)
+                       return "";
+               return data[row][col];
+       }
+
+       int[]   current_row;
+
+       public void reset() {
+               for (int i = 0; i < cols / 2; i++)
+                       current_row[i] = 0;
+       }
+
+       public void clear() {
+               reset();
+               for (int c = 0; c < cols; c++)
+                       for (int r = 0; r < rows; r++)
+                               data[r][c] = "";
+               fireTableDataChanged();
+       }
+
+       public void addRow(int col, String name, String value) {
+               if (current_row[col] < rows) {
+                       data[current_row[col]][col * 2] = name;
+                       data[current_row[col]][col * 2 + 1] = value;
+               }
+               current_row[col]++;
+       }
+
+       public void finish() {
+               for (int c = 0; c < cols / 2; c++)
+                       while (current_row[c] < rows)
+                               addRow(c, "", "");
+               fireTableDataChanged();
+       }
+
+       public AltosFlightInfoTableModel (int in_rows, int in_cols) {
+               rows = in_rows;
+               cols = in_cols * 2;
+               data = new String[rows][cols];
+               current_row = new int[in_cols];
+       }
+}
diff --git a/altosuilib/AltosFlightStatsTable.java b/altosuilib/AltosFlightStatsTable.java
new file mode 100644 (file)
index 0000000..703dfb9
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import javax.swing.*;
+import java.util.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosFlightStatsTable extends JComponent implements AltosFontListener {
+       GridBagLayout   layout;
+
+       LinkedList<FlightStat> flight_stats = new LinkedList<FlightStat>();
+
+       class FlightStat implements AltosFontListener {
+               JLabel          label;
+               JTextField[]    value;
+
+               public void font_size_changed(int font_size) {
+                       label.setFont(AltosUILib.label_font);
+                       for (int i = 0; i < value.length; i++)
+                               value[i].setFont(AltosUILib.value_font);
+               }
+
+               public FlightStat(GridBagLayout layout, int y, String label_text, String ... values) {
+                       GridBagConstraints      c = new GridBagConstraints();
+                       c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad);
+                       c.weighty = 1;
+
+                       label = new JLabel(label_text);
+                       label.setFont(AltosUILib.label_font);
+                       label.setHorizontalAlignment(SwingConstants.LEFT);
+                       c.gridx = 0; c.gridy = y;
+                       c.anchor = GridBagConstraints.WEST;
+                       c.fill = GridBagConstraints.VERTICAL;
+                       c.weightx = 0;
+                       layout.setConstraints(label, c);
+                       add(label);
+
+                       value = new JTextField[values.length];
+                       for (int j = 0; j < values.length; j++) {
+                               value[j] = new JTextField(values[j]);
+                               value[j].setEditable(false);
+                               value[j].setFont(AltosUILib.value_font);
+                               value[j].setHorizontalAlignment(SwingConstants.RIGHT);
+                               c.gridx = j+1; c.gridy = y;
+                               c.anchor = GridBagConstraints.EAST;
+                               c.fill = GridBagConstraints.BOTH;
+                               c.weightx = 1;
+                               layout.setConstraints(value[j], c);
+                               add(value[j]);
+                       }
+                       flight_stats.add(this);
+               }
+
+       }
+
+       public void font_size_changed(int font_size) {
+               for (FlightStat f : flight_stats)
+                       f.font_size_changed(font_size);
+       }
+
+       static String pos(double p, String pos, String neg) {
+               String  h = pos;
+               if (p < 0) {
+                       h = neg;
+                       p = -p;
+               }
+               int deg = (int) Math.floor(p);
+               double min = (p - Math.floor(p)) * 60.0;
+               return String.format("%s %4d° %9.6f'", h, deg, min);
+       }
+
+       public AltosFlightStatsTable(AltosFlightStats stats) {
+               layout = new GridBagLayout();
+
+               setLayout(layout);
+               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 != 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 != AltosLib.MISSING)
+                               new FlightStat(layout, y++, "Date",
+                                              String.format("%04d-%02d-%02d", stats.year, stats.month, stats.day));
+                       if (stats.hour != AltosLib.MISSING)
+                               new FlightStat(layout, y++, "Time",
+                                              String.format("%02d:%02d:%02d UTC", stats.hour, stats.minute, stats.second));
+               }
+               if (stats.max_height != AltosLib.MISSING) {
+                       new FlightStat(layout, y++, "Maximum height",
+                                      String.format("%5.0f m", stats.max_height),
+                                      String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_height)));
+               }
+               if (stats.max_gps_height != AltosLib.MISSING) {
+                       new FlightStat(layout, y++, "Maximum GPS height",
+                                      String.format("%5.0f m", stats.max_gps_height),
+                                      String.format("%5.0f ft", AltosConvert.meters_to_feet(stats.max_gps_height)));
+               }
+               new FlightStat(layout, y++, "Maximum speed",
+                              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 != 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)),
+                                      String.format("%5.0f G", AltosConvert.meters_to_g(stats.max_acceleration)));
+                       new FlightStat(layout, y++, "Average boost acceleration",
+                                      String.format("%5.0f m/s²", stats.state_accel[AltosLib.ao_flight_boost]),
+                                      String.format("%5.0f ft/s²", AltosConvert.meters_to_feet(stats.state_accel[AltosLib.ao_flight_boost])),
+                                      String.format("%5.0f G", AltosConvert.meters_to_g(stats.state_accel[AltosLib.ao_flight_boost])));
+               }
+               if (stats.state_speed[AltosLib.ao_flight_drogue] != AltosLib.MISSING)
+                       new FlightStat(layout, y++, "Drogue descent rate",
+                                      String.format("%5.0f m/s", stats.state_speed[AltosLib.ao_flight_drogue]),
+                                      String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_drogue])));
+               if (stats.state_speed[AltosLib.ao_flight_main] != AltosLib.MISSING)
+                       new FlightStat(layout, y++, "Main descent rate",
+                                      String.format("%5.0f m/s", stats.state_speed[AltosLib.ao_flight_main]),
+                                      String.format("%5.0f ft/s", AltosConvert.meters_to_feet(stats.state_speed[AltosLib.ao_flight_main])));
+               if (stats.state_start[AltosLib.ao_flight_boost] < stats.state_end[AltosLib.ao_flight_coast])
+                       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(AltosLib.ao_flight_boost)),
+                                      String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_fast] - stats.state_start[AltosLib.ao_flight_fast],
+                                                    AltosLib.state_name(AltosLib.ao_flight_fast)),
+                                      String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_coast] - stats.state_start[AltosLib.ao_flight_coast],
+                                                    AltosLib.state_name(AltosLib.ao_flight_coast)));
+               if (stats.state_start[AltosLib.ao_flight_drogue] < stats.state_end[AltosLib.ao_flight_main])
+                       new FlightStat(layout, y++, "Descent time",
+                                      String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_drogue] - stats.state_start[AltosLib.ao_flight_drogue],
+                                                    AltosLib.state_name(AltosLib.ao_flight_drogue)),
+                                      String.format("%6.1f s %s", stats.state_end[AltosLib.ao_flight_main] - stats.state_start[AltosLib.ao_flight_main],
+                                                    AltosLib.state_name(AltosLib.ao_flight_main)));
+               if (stats.state_start[AltosLib.ao_flight_boost] < stats.state_end[AltosLib.ao_flight_main])
+                       new FlightStat(layout, y++, "Flight time",
+                                      String.format("%6.1f s", stats.state_end[AltosLib.ao_flight_main] -
+                                                    stats.state_start[AltosLib.ao_flight_boost]));
+               if (stats.has_gps) {
+                       new FlightStat(layout, y++, "Pad location",
+                                      pos(stats.pad_lat,"N","S"),
+                                      pos(stats.pad_lon,"E","W"));
+                       new FlightStat(layout, y++, "Last reported location",
+                                      pos(stats.lat,"N","S"),
+                                      pos(stats.lon,"E","W"));
+               }
+       }
+}
index da9033525976225311d84822f292c67656ec7c18..a98cc13179c1122f7bfd0ab0a9f7d121172d6b3d 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 public interface AltosFontListener {
        void font_size_changed(int font_size);
diff --git a/altosuilib/AltosFreqList.java b/altosuilib/AltosFreqList.java
new file mode 100644 (file)
index 0000000..e1299aa
--- /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.altosuilib_2;
+
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosFreqList extends JComboBox<AltosFrequency> {
+
+       String  product;
+       int     serial;
+       int     calibrate;
+
+       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);
+
+                       if (f.close(new_frequency)) {
+                               setSelectedIndex(i);
+                               return;
+                       }
+               }
+               for (i = 0; i < getItemCount(); i++) {
+                       AltosFrequency  f = (AltosFrequency) getItemAt(i);
+
+                       if (new_frequency < f.frequency)
+                               break;
+               }
+               String  description = String.format("%s serial %d", product, serial);
+               AltosFrequency  frequency = new AltosFrequency(new_frequency, description);
+               AltosUIPreferences.add_common_frequency(frequency);
+               insertItemAt(frequency, i);
+               setMaximumRowCount(getItemCount());
+       }
+
+       public void set_product(String new_product) {
+               product = new_product;
+       }
+
+       public void set_serial(int new_serial) {
+               serial = new_serial;
+       }
+
+       public double frequency() {
+               AltosFrequency  f = (AltosFrequency) getSelectedItem();
+               if (f != null)
+                       return f.frequency;
+               return 434.550;
+       }
+
+       public AltosFreqList () {
+               super(AltosUIPreferences.common_frequencies());
+               setMaximumRowCount(getItemCount());
+               setEditable(false);
+               product = "Unknown";
+               serial = 0;
+       }
+
+       public AltosFreqList(double in_frequency) {
+               this();
+               set_frequency(in_frequency);
+       }
+}
diff --git a/altosuilib/AltosGraph.java b/altosuilib/AltosGraph.java
new file mode 100644 (file)
index 0000000..f8c8b27
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * 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.altosuilib_2;
+
+import java.io.*;
+import java.util.ArrayList;
+
+import java.awt.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+
+import org.jfree.ui.*;
+import org.jfree.chart.*;
+import org.jfree.chart.plot.*;
+import org.jfree.chart.axis.*;
+import org.jfree.chart.renderer.*;
+import org.jfree.chart.renderer.xy.*;
+import org.jfree.chart.labels.*;
+import org.jfree.data.xy.*;
+import org.jfree.data.*;
+
+class AltosVoltage extends AltosUnits {
+
+       public double value(double v, boolean imperial_units) {
+               return v;
+       }
+
+       public double inverse(double v, boolean imperial_units) {
+               return v;
+       }
+
+       public String show_units(boolean imperial_units) {
+               return "V";
+       }
+
+       public String say_units(boolean imperial_units) {
+               return "volts";
+       }
+
+       public int show_fraction(int width, boolean imperial_units) {
+               return width / 2;
+       }
+}
+
+class AltosNsat extends AltosUnits {
+
+       public double value(double v, boolean imperial_units) {
+               return v;
+       }
+
+       public double inverse(double v, boolean imperial_units) {
+               return v;
+       }
+
+       public String show_units(boolean imperial_units) {
+               return "Sats";
+       }
+
+       public String say_units(boolean imperial_units) {
+               return "Satellites";
+       }
+
+       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 d, boolean imperial_units) {
+               return d;
+       }
+
+       public double inverse(double d, boolean imperial_units) {
+               return d;
+       }
+
+       public String show_units(boolean imperial_units) {
+               return "dBm";
+       }
+
+       public String say_units(boolean imperial_units) {
+               return "D B M";
+       }
+
+       public int show_fraction(int width, boolean imperial_units) {
+               return 0;
+       }
+}
+
+class AltosGyroUnits 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 "°/sec";
+       }
+
+       public String say_units(boolean imperial_units) {
+               return "degrees per second";
+       }
+
+       public int show_fraction(int width, boolean imperial_units) {
+               return 1;
+       }
+}
+
+class AltosMagUnits 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 "Ga";
+       }
+
+       public String say_units(boolean imperial_units) {
+               return "gauss";
+       }
+
+       public int show_fraction(int width, boolean imperial_units) {
+               return 2;
+       }
+}
+
+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);
+       static final private Color accel_color = new Color(31,31,194);
+       static final private Color voltage_color = new Color(194, 194, 31);
+       static final private Color battery_voltage_color = new Color(194, 194, 31);
+       static final private Color drogue_voltage_color = new Color(150, 150, 31);
+       static final private Color main_voltage_color = new Color(100, 100, 31);
+       static final private Color gps_nsat_color = new Color (194, 31, 194);
+       static final private Color gps_nsat_solution_color = new Color (194, 31, 194);
+       static final private Color gps_nsat_view_color = new Color (150, 31, 150);
+       static final private Color gps_course_color = new Color (100, 31, 112);
+       static final private Color gps_ground_speed_color = new Color (31, 112, 100);
+       static final private Color gps_climb_rate_color = new Color (31, 31, 112);
+       static final private Color temperature_color = new Color (31, 194, 194);
+       static final private Color dbm_color = new Color(31, 100, 100);
+       static final private Color state_color = new Color(0,0,0);
+       static final private Color accel_x_color = new Color(255, 0, 0);
+       static final private Color accel_y_color = new Color(0, 255, 0);
+       static final private Color accel_z_color = new Color(0, 0, 255);
+       static final private Color gyro_x_color = new Color(192, 0, 0);
+       static final private Color gyro_y_color = new Color(0, 192, 0);
+       static final private Color gyro_z_color = new Color(0, 0, 192);
+       static final private Color mag_x_color = new Color(128, 0, 0);
+       static final private Color mag_y_color = new Color(0, 128, 0);
+       static final private Color mag_z_color = new Color(0, 0, 128);
+       static final private Color orient_color = new Color(31, 31, 31);
+
+       static AltosVoltage voltage_units = new AltosVoltage();
+       static AltosPressure pressure_units = new AltosPressure();
+       static AltosNsat nsat_units = new AltosNsat();
+       static AltosDbm dbm_units = new AltosDbm();
+       static AltosGyroUnits gyro_units = new AltosGyroUnits();
+       static AltosOrient orient_units = new AltosOrient();
+       static AltosMagUnits mag_units = new AltosMagUnits();
+
+       AltosUIAxis     height_axis, speed_axis, accel_axis, voltage_axis, temperature_axis, nsat_axis, dbm_axis;
+       AltosUIAxis     distance_axis, pressure_axis;
+       AltosUIAxis     gyro_axis, orient_axis, mag_axis;
+       AltosUIAxis     course_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);
+               temperature_axis = newAxis("Temperature", AltosConvert.temperature, temperature_color, 0);
+               nsat_axis = newAxis("Satellites", nsat_units, gps_nsat_color,
+                                   AltosUIAxis.axis_include_zero | AltosUIAxis.axis_integer);
+               dbm_axis = newAxis("Signal Strength", dbm_units, dbm_color, 0);
+               distance_axis = newAxis("Distance", AltosConvert.distance, range_color);
+
+               gyro_axis = newAxis("Rotation Rate", gyro_units, gyro_z_color, 0);
+               orient_axis = newAxis("Tilt Angle", orient_units, orient_color, 0);
+               mag_axis = newAxis("Magnetic Field", mag_units, mag_x_color, 0);
+               course_axis = newAxis("Course", orient_units, gps_course_color, 0);
+
+               addMarker("State", AltosGraphDataPoint.data_state, state_color);
+
+               if (stats.has_flight_data) {
+                       addSeries("Height",
+                                 AltosGraphDataPoint.data_height,
+                                 AltosConvert.height,
+                                 height_color,
+                                 true,
+                                 height_axis);
+                       addSeries("Pressure",
+                                 AltosGraphDataPoint.data_pressure,
+                                 pressure_units,
+                                 pressure_color,
+                                 false,
+                                 pressure_axis);
+                       addSeries("Speed",
+                                 AltosGraphDataPoint.data_speed,
+                                 AltosConvert.speed,
+                                 speed_color,
+                                 true,
+                                 speed_axis);
+                       addSeries("Acceleration",
+                                 AltosGraphDataPoint.data_accel,
+                                 AltosConvert.accel,
+                                 accel_color,
+                                 true,
+                                 accel_axis);
+               }
+               if (stats.has_gps) {
+                       boolean enable_gps = false;
+
+                       if (!stats.has_flight_data)
+                               enable_gps = true;
+
+                       addSeries("Range",
+                                 AltosGraphDataPoint.data_range,
+                                 AltosConvert.distance,
+                                 range_color,
+                                 false,
+                                 distance_axis);
+                       addSeries("Distance",
+                                 AltosGraphDataPoint.data_distance,
+                                 AltosConvert.distance,
+                                 distance_color,
+                                 enable_gps,
+                                 distance_axis);
+                       addSeries("GPS Height",
+                                 AltosGraphDataPoint.data_gps_height,
+                                 AltosConvert.height,
+                                 gps_height_color,
+                                 enable_gps,
+                                 height_axis);
+                       addSeries("GPS Altitude",
+                                 AltosGraphDataPoint.data_gps_altitude,
+                                 AltosConvert.height,
+                                 gps_height_color,
+                                 false,
+                                 height_axis);
+                       addSeries("GPS Satellites in Solution",
+                                 AltosGraphDataPoint.data_gps_nsat_solution,
+                                 nsat_units,
+                                 gps_nsat_solution_color,
+                                 false,
+                                 nsat_axis);
+                       addSeries("GPS Satellites in View",
+                                 AltosGraphDataPoint.data_gps_nsat_view,
+                                 nsat_units,
+                                 gps_nsat_view_color,
+                                 false,
+                                 nsat_axis);
+                       addSeries("GPS Course",
+                                 AltosGraphDataPoint.data_gps_course,
+                                 orient_units,
+                                 gps_course_color,
+                                 false,
+                                 course_axis);
+                       addSeries("GPS Ground Speed",
+                                 AltosGraphDataPoint.data_gps_ground_speed,
+                                 AltosConvert.speed,
+                                 gps_ground_speed_color,
+                                 enable_gps,
+                                 speed_axis);
+                       addSeries("GPS Climb Rate",
+                                 AltosGraphDataPoint.data_gps_climb_rate,
+                                 AltosConvert.speed,
+                                 gps_climb_rate_color,
+                                 enable_gps,
+                                 speed_axis);
+               }
+               if (stats.has_rssi)
+                       addSeries("Received Signal Strength",
+                                 AltosGraphDataPoint.data_rssi,
+                                 dbm_units,
+                                 dbm_color,
+                                 false,
+                                 dbm_axis);
+
+               if (stats.has_battery)
+                       addSeries("Battery Voltage",
+                                 AltosGraphDataPoint.data_battery_voltage,
+                                 voltage_units,
+                                 battery_voltage_color,
+                                 false,
+                                 voltage_axis);
+
+               if (stats.has_flight_adc) {
+                       addSeries("Temperature",
+                                 AltosGraphDataPoint.data_temperature,
+                                 AltosConvert.temperature,
+                                 temperature_color,
+                                 false,
+                                 temperature_axis);
+                       addSeries("Drogue Voltage",
+                                 AltosGraphDataPoint.data_drogue_voltage,
+                                 voltage_units,
+                                 drogue_voltage_color,
+                                 false,
+                                 voltage_axis);
+                       addSeries("Main Voltage",
+                                 AltosGraphDataPoint.data_main_voltage,
+                                 voltage_units,
+                                 main_voltage_color,
+                                 false,
+                                 voltage_axis);
+               }
+
+               if (stats.has_imu) {
+                       addSeries("Acceleration X",
+                                 AltosGraphDataPoint.data_accel_x,
+                                 AltosConvert.accel,
+                                 accel_x_color,
+                                 false,
+                                 accel_axis);
+                       addSeries("Acceleration Y",
+                                 AltosGraphDataPoint.data_accel_y,
+                                 AltosConvert.accel,
+                                 accel_y_color,
+                                 false,
+                                 accel_axis);
+                       addSeries("Acceleration Z",
+                                 AltosGraphDataPoint.data_accel_z,
+                                 AltosConvert.accel,
+                                 accel_z_color,
+                                 false,
+                                 accel_axis);
+                       addSeries("Rotation Rate X",
+                                 AltosGraphDataPoint.data_gyro_x,
+                                 gyro_units,
+                                 gyro_x_color,
+                                 false,
+                                 gyro_axis);
+                       addSeries("Rotation Rate Y",
+                                 AltosGraphDataPoint.data_gyro_y,
+                                 gyro_units,
+                                 gyro_y_color,
+                                 false,
+                                 gyro_axis);
+                       addSeries("Rotation Rate Z",
+                                 AltosGraphDataPoint.data_gyro_z,
+                                 gyro_units,
+                                 gyro_z_color,
+                                 false,
+                                 gyro_axis);
+               }
+               if (stats.has_mag) {
+                       addSeries("Magnetometer X",
+                                 AltosGraphDataPoint.data_mag_x,
+                                 mag_units,
+                                 mag_x_color,
+                                 false,
+                                 mag_axis);
+                       addSeries("Magnetometer Y",
+                                 AltosGraphDataPoint.data_mag_y,
+                                 mag_units,
+                                 mag_y_color,
+                                 false,
+                                 mag_axis);
+                       addSeries("Magnetometer Z",
+                                 AltosGraphDataPoint.data_mag_z,
+                                 mag_units,
+                                 mag_z_color,
+                                 false,
+                                 mag_axis);
+               }
+               if (stats.has_orient)
+                       addSeries("Tilt Angle",
+                                 AltosGraphDataPoint.data_orient,
+                                 orient_units,
+                                 orient_color,
+                                 false,
+                                 orient_axis);
+               if (stats.num_ignitor > 0) {
+                       for (int i = 0; i < stats.num_ignitor; i++)
+                               addSeries(AltosLib.ignitor_name(i),
+                                         AltosGraphDataPoint.data_ignitor_0 + i,
+                                         voltage_units,
+                                         main_voltage_color,
+                                         false,
+                                         voltage_axis);
+                       for (int i = 0; i < stats.num_ignitor; i++)
+                               addMarker(AltosLib.ignitor_name(i), AltosGraphDataPoint.data_ignitor_fired_0 + i, state_color);
+               }
+
+               setDataSet(dataSet);
+       }
+}
diff --git a/altosuilib/AltosGraphDataPoint.java b/altosuilib/AltosGraphDataPoint.java
new file mode 100644 (file)
index 0000000..3aff1e8
--- /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.
+ */
+
+package org.altusmetrum.altosuilib_2;
+
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosGraphDataPoint implements AltosUIDataPoint {
+
+       AltosState      state;
+
+       public static final int data_height = 0;
+       public static final int data_speed = 1;
+       public static final int data_accel = 2;
+       public static final int data_temp = 3;
+       public static final int data_battery_voltage = 4;
+       public static final int data_drogue_voltage = 5;
+       public static final int data_main_voltage = 6;
+       public static final int data_rssi = 7;
+       public static final int data_state = 8;
+       public static final int data_gps_height = 9;
+       public static final int data_gps_nsat_solution = 10;
+       public static final int data_gps_nsat_view = 11;
+       public static final int data_gps_altitude = 12;
+       public static final int data_temperature = 13;
+       public static final int data_range = 14;
+       public static final int data_distance = 15;
+       public static final int data_pressure = 16;
+       public static final int data_accel_x = 17;
+       public static final int data_accel_y = 18;
+       public static final int data_accel_z = 19;
+       public static final int data_gyro_x = 20;
+       public static final int data_gyro_y = 21;
+       public static final int data_gyro_z = 22;
+       public static final int data_mag_x = 23;
+       public static final int data_mag_y = 24;
+       public static final int data_mag_z = 25;
+       public static final int data_orient = 26;
+       public static final int data_gps_course = 27;
+       public static final int data_gps_ground_speed = 28;
+       public static final int data_gps_climb_rate = 29;
+       public static final int data_ignitor_0 = 30;
+       public static final int data_ignitor_num = 32;
+       public static final int data_ignitor_max = data_ignitor_0 + data_ignitor_num - 1;
+       public static final int data_ignitor_fired_0 = data_ignitor_0 + data_ignitor_num;
+       public static final int data_ignitor_fired_max = data_ignitor_fired_0 + data_ignitor_num - 1;
+
+       public double x() throws AltosUIDataMissing {
+               double  time = state.time_since_boost();
+               if (time < -2)
+                       throw new AltosUIDataMissing(-1);
+               return time;
+       }
+
+       public double y(int index) throws AltosUIDataMissing {
+               double y = AltosLib.MISSING;
+               switch (index) {
+               case data_height:
+                       y = state.height();
+                       break;
+               case data_speed:
+                       y = state.speed();
+                       break;
+               case data_accel:
+                       y = state.acceleration();
+                       break;
+               case data_temp:
+                       y = state.temperature;
+                       break;
+               case data_battery_voltage:
+                       y = state.battery_voltage;
+                       break;
+               case data_drogue_voltage:
+                       y = state.apogee_voltage;
+                       break;
+               case data_main_voltage:
+                       y = state.main_voltage;
+                       break;
+               case data_rssi:
+                       y = state.rssi;
+                       break;
+               case data_gps_height:
+                       y = state.gps_height;
+                       break;
+               case data_gps_nsat_solution:
+                       if (state.gps != null)
+                               y = state.gps.nsat;
+                       break;
+               case data_gps_nsat_view:
+                       if (state.gps != null) {
+                               if (state.gps.cc_gps_sat != null)
+                                       y = state.gps.cc_gps_sat.length;
+                               else
+                                       y = 0;
+                       }
+                       break;
+               case data_gps_altitude:
+                       y = state.gps_altitude();
+                       break;
+               case data_temperature:
+                       y = state.temperature;
+                       break;
+               case data_range:
+                       y = state.range;
+                       break;
+               case data_distance:
+                       if (state.from_pad != null)
+                               y = state.from_pad.distance;
+                       break;
+               case data_pressure:
+                       y = state.pressure();
+                       break;
+
+               case data_accel_x:
+               case data_accel_y:
+               case data_accel_z:
+               case data_gyro_x:
+               case data_gyro_y:
+               case data_gyro_z:
+                       AltosIMU        imu = state.imu;
+                       if (imu == null)
+                               break;
+                       switch (index) {
+                       case data_accel_x:
+                               y = imu.accel_x;
+                               break;
+                       case data_accel_y:
+                               y = imu.accel_y;
+                               break;
+                       case data_accel_z:
+                               y = imu.accel_z;
+                               break;
+                       case data_gyro_x:
+                               y = imu.gyro_x;
+                               break;
+                       case data_gyro_y:
+                               y = imu.gyro_y;
+                               break;
+                       case data_gyro_z:
+                               y = imu.gyro_z;
+                               break;
+                       }
+                       break;
+               case data_mag_x:
+               case data_mag_y:
+               case data_mag_z:
+                       AltosMag        mag = state.mag;
+                       if (mag == null)
+                               break;
+                       switch (index) {
+                       case data_mag_x:
+                               y = mag.x;
+                               break;
+                       case data_mag_y:
+                               y = mag.y;
+                               break;
+                       case data_mag_z:
+                               y = mag.z;
+                               break;
+                       }
+                       break;
+               case data_orient:
+                       y = state.orient();
+                       break;
+               case data_gps_course:
+                       if (state.gps != null)
+                               y = state.gps.course;
+                       else
+                               y = AltosLib.MISSING;
+                       break;
+               case data_gps_ground_speed:
+                       if (state.gps != null)
+                               y = state.gps.ground_speed;
+                       else
+                               y = AltosLib.MISSING;
+                       break;
+               case data_gps_climb_rate:
+                       if (state.gps != null)
+                               y = state.gps.climb_rate;
+                       else
+                               y = AltosLib.MISSING;
+                       break;
+               default:
+                       if (data_ignitor_0 <= index && index <= data_ignitor_max) {
+                               int ignitor = index - data_ignitor_0;
+                               if (state.ignitor_voltage != null && ignitor < state.ignitor_voltage.length)
+                                       y = state.ignitor_voltage[ignitor];
+                       } else if (data_ignitor_fired_0 <= index && index <= data_ignitor_fired_max) {
+                               int ignitor = index - data_ignitor_fired_0;
+                               if (state.ignitor_voltage != null && ignitor < state.ignitor_voltage.length) {
+                                       if ((state.pyro_fired & (1 << ignitor)) != 0)
+                                               y = 1;
+                                       else
+                                               y = 0;
+                               }
+                       }
+                       break;
+               }
+               if (y == AltosLib.MISSING)
+                       throw new AltosUIDataMissing(index);
+               return y;
+       }
+
+       public int id(int index) {
+               if (index == data_state) {
+                       int s = state.state;
+                       if (AltosLib.ao_flight_boost <= s && s <= AltosLib.ao_flight_landed)
+                               return s;
+               } else if (data_ignitor_fired_0 <= index && index <= data_ignitor_fired_max) {
+                       int ignitor = index - data_ignitor_fired_0;
+                       if (state.ignitor_voltage != null && ignitor < state.ignitor_voltage.length) {
+                               if (state.ignitor_voltage != null && ignitor < state.ignitor_voltage.length) {
+                                       if ((state.pyro_fired & (1 << ignitor)) != 0)
+                                               return 1;
+                               }
+                       }
+               }
+               return -1;
+       }
+
+       public String id_name(int index) {
+               if (index == data_state) {
+                       return state.state_name();
+               } else if (data_ignitor_fired_0 <= index && index <= data_ignitor_fired_max) {
+                       int ignitor = index - data_ignitor_fired_0;
+                       if (state.ignitor_voltage != null && ignitor < state.ignitor_voltage.length)
+                               return AltosLib.ignitor_name(ignitor);
+               }
+               return "";
+       }
+
+       public AltosGraphDataPoint (AltosState state) {
+               this.state = state;
+       }
+}
diff --git a/altosuilib/AltosGraphDataSet.java b/altosuilib/AltosGraphDataSet.java
new file mode 100644 (file)
index 0000000..36933e9
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.altosuilib_2;
+
+import java.lang.*;
+import java.io.*;
+import java.util.*;
+import org.altusmetrum.altoslib_4.*;
+
+class AltosGraphIterator implements Iterator<AltosUIDataPoint> {
+       AltosGraphDataSet       dataSet;
+       Iterator<AltosState>    iterator;
+
+       public boolean hasNext() {
+               return iterator.hasNext();
+       }
+
+       public AltosUIDataPoint next() {
+               AltosState      state = iterator.next();
+
+               if (state.flight != AltosLib.MISSING) {
+                       if (dataSet.callsign == null && state.callsign != null)
+                               dataSet.callsign = state.callsign;
+
+                       if (dataSet.serial == 0 && state.serial != 0)
+                               dataSet.serial = state.serial;
+
+                       if (dataSet.flight == 0 && state.flight != 0)
+                               dataSet.flight = state.flight;
+               }
+
+               return new AltosGraphDataPoint(state);
+       }
+
+       public AltosGraphIterator (Iterator<AltosState> iterator, AltosGraphDataSet dataSet) {
+               this.iterator = iterator;
+               this.dataSet = dataSet;
+       }
+
+       public void remove() {
+       }
+}
+
+class AltosGraphIterable implements Iterable<AltosUIDataPoint> {
+       AltosGraphDataSet       dataSet;
+
+       public Iterator<AltosUIDataPoint> iterator() {
+               return new AltosGraphIterator(dataSet.states.iterator(), dataSet);
+       }
+
+       public AltosGraphIterable(AltosGraphDataSet dataSet) {
+               this.dataSet = dataSet;
+       }
+}
+
+public class AltosGraphDataSet implements AltosUIDataSet {
+       String                  callsign;
+       int                     serial;
+       int                     flight;
+       AltosStateIterable      states;
+
+       public String name() {
+               if (callsign != null)
+                       return String.format("%s - %d/%d", callsign, serial, flight);
+               else
+                       return String.format("%d/%d", serial, flight);
+       }
+
+       public Iterable<AltosUIDataPoint> dataPoints() {
+               return new AltosGraphIterable(this);
+       }
+
+       public AltosGraphDataSet (AltosStateIterable states) {
+               this.states = states;
+               this.callsign = null;
+               this.serial = 0;
+               this.flight = 0;
+       }
+}
diff --git a/altosuilib/AltosInfoTable.java b/altosuilib/AltosInfoTable.java
new file mode 100644 (file)
index 0000000..23ae4ae
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.table.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosInfoTable extends JTable implements AltosFlightDisplay, HierarchyListener {
+       private AltosFlightInfoTableModel model;
+
+       static final int info_columns = 3;
+       static final int info_rows = 17;
+
+       private AltosState              last_state;
+       private AltosListenerState      last_listener_state;
+
+       int desired_row_height() {
+               FontMetrics     infoValueMetrics = getFontMetrics(AltosUILib.table_value_font);
+               return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10;
+       }
+
+       int text_width(String t) {
+               FontMetrics     infoValueMetrics = getFontMetrics(AltosUILib.table_value_font);
+
+               return infoValueMetrics.stringWidth(t);
+       }
+
+       void set_layout() {
+               setRowHeight(desired_row_height());
+               for (int i = 0; i < info_columns * 2; i++)
+               {
+                       TableColumn column = getColumnModel().getColumn(i);
+
+                       if ((i & 1) == 0)
+                               column.setPreferredWidth(text_width(" Satellites Visible"));
+                       else
+                               column.setPreferredWidth(text_width("W 179°59.99999' "));
+               }
+       }
+
+       public AltosInfoTable() {
+               super(new AltosFlightInfoTableModel(info_rows, info_columns));
+               model = (AltosFlightInfoTableModel) getModel();
+               setFont(AltosUILib.table_value_font);
+               addHierarchyListener(this);
+               setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS);
+               setShowGrid(true);
+               set_layout();
+               doLayout();
+       }
+
+       public void font_size_changed(int font_size) {
+               setFont(AltosUILib.table_value_font);
+               set_layout();
+               doLayout();
+       }
+
+       public void units_changed(boolean imperial_units) {
+       }
+
+       public void hierarchyChanged(HierarchyEvent e) {
+               if (last_state != null && isShowing()) {
+                       AltosState              state = last_state;
+                       AltosListenerState      listener_state = last_listener_state;
+
+                       last_state = null;
+                       last_listener_state = null;
+                       show(state, listener_state);
+               }
+       }
+
+       public Dimension getPreferredScrollableViewportSize() {
+               return getPreferredSize();
+       }
+
+       public void reset() {
+               model.reset();
+       }
+
+       void info_add_row(int col, String name, String value) {
+               model.addRow(col, name, value);
+       }
+
+       void info_add_row(int col, String name, String format, Object... parameters) {
+               info_add_row (col, name, String.format(format, parameters));
+       }
+
+       void info_add_deg(int col, String name, double v, int pos, int neg) {
+               int     c = pos;
+               if (v < 0) {
+                       c = neg;
+                       v = -v;
+               }
+               double  deg = Math.floor(v);
+               double  min = (v - deg) * 60;
+
+               info_add_row(col, name, String.format("%c %3.0f°%08.5f'", c, deg, min));
+       }
+
+       void info_finish() {
+               model.finish();
+       }
+
+       public void clear() {
+               model.clear();
+       }
+
+       public String getName() { return "Table"; }
+
+       public void show(AltosState state, AltosListenerState listener_state) {
+
+               if (!isShowing()) {
+                       last_state = state;
+                       last_listener_state = listener_state;
+                       return;
+               }
+
+               reset();
+               if (state != null) {
+                       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.max_speed() != AltosLib.MISSING)
+                               info_add_row(0, "Max Speed", "%8.1f  m/s", state.max_speed());
+                       if (state.orient() != AltosLib.MISSING)
+                               info_add_row(0, "Tilt", "%4.0f °", state.orient());
+                       if (state.max_orient() != AltosLib.MISSING)
+                               info_add_row(0, "Max Tilt", "%4.0f °", state.max_orient());
+                       if (state.temperature != AltosLib.MISSING)
+                               info_add_row(0, "Temperature", "%9.2f °C", state.temperature);
+                       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 != AltosLib.MISSING)
+                               info_add_row(0, "Receiver Battery", "%9.2f", listener_state.battery);
+               }
+
+               if (state != null) {
+                       if (state.gps == null || !state.gps.connected) {
+                               info_add_row(1, "GPS", "not available");
+                       } else {
+                               if (state.gps_ready)
+                                       info_add_row(1, "GPS state", "%s", "ready");
+                               else
+                                       info_add_row(1, "GPS state", "wait (%d)",
+                                                    state.gps_waiting);
+                               if (state.gps.locked)
+                                       info_add_row(1, "GPS", "   locked");
+                               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.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 */
+                               /*
+                                 if (false) {
+                                 info_add_row(1, "GPS ground speed", "%8.1f m/s %3d°",
+                                 state.gps.ground_speed,
+                                 state.gps.course);
+                                 info_add_row(1, "GPS climb rate", "%8.1f m/s",
+                                 state.gps.climb_rate);
+                                 info_add_row(1, "GPS error", "%6d m(h)%3d m(v)",
+                                 state.gps.h_error, state.gps.v_error);
+                                 }
+                               */
+
+                               info_add_row(1, "GPS hdop", "%8.1f", state.gps.hdop);
+
+                               if (state.npad > 0) {
+                                       if (state.from_pad != null) {
+                                               info_add_row(1, "Distance from pad", "%6d m",
+                                                            (int) (state.from_pad.distance + 0.5));
+                                               info_add_row(1, "Direction from pad", "%6d°",
+                                                            (int) (state.from_pad.bearing + 0.5));
+                                               info_add_row(1, "Elevation from pad", "%6d°",
+                                                            (int) (state.elevation + 0.5));
+                                               info_add_row(1, "Range from pad", "%6d m",
+                                                            (int) (state.range + 0.5));
+                                       } else {
+                                               info_add_row(1, "Distance from pad", "unknown");
+                                               info_add_row(1, "Direction from pad", "unknown");
+                                               info_add_row(1, "Elevation from pad", "unknown");
+                                               info_add_row(1, "Range from pad", "unknown");
+                                       }
+                                       info_add_deg(1, "Pad latitude", state.pad_lat, 'N', 'S');
+                                       info_add_deg(1, "Pad longitude", state.pad_lon, 'E', 'W');
+                                       info_add_row(1, "Pad GPS alt", "%6.0f m", state.pad_alt);
+                               }
+                               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;
+
+                               if (state.gps.cc_gps_sat == null)
+                                       info_add_row(2, "Satellites Visible", "%4d", 0);
+                               else {
+                                       info_add_row(2, "Satellites Visible", "%4d", state.gps.cc_gps_sat.length);
+                                       for (c = 0; c < state.gps.cc_gps_sat.length; c++) {
+                                               info_add_row(2, "Satellite id,C/N0",
+                                                            "%4d, %4d",
+                                                            state.gps.cc_gps_sat[c].svid,
+                                                            state.gps.cc_gps_sat[c].c_n0);
+                                       }
+                               }
+                       }
+               }
+               info_finish();
+       }
+}
diff --git a/altosuilib/AltosLed.java b/altosuilib/AltosLed.java
new file mode 100644 (file)
index 0000000..2debb62
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.altosuilib_2;
+
+import javax.swing.*;
+
+public class AltosLed extends JLabel {
+       ImageIcon       on, off;
+
+       ImageIcon create_icon(String path) {
+               java.net.URL imgURL = AltosUILib.class.getResource(path);
+               if (imgURL != null)
+                       return new ImageIcon(imgURL);
+               System.err.printf("Cannot find icon \"%s\"\n", path);
+               return null;
+       }
+
+       public void set(boolean set) {
+               if (set)
+                       setIcon(on);
+               else
+                       setIcon(off);
+       }
+
+       public AltosLed(String on_path, String off_path) {
+               on = create_icon(on_path);
+               off = create_icon(off_path);
+               setIcon(off);
+       }
+}
diff --git a/altosuilib/AltosLights.java b/altosuilib/AltosLights.java
new file mode 100644 (file)
index 0000000..c91b70e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import javax.swing.*;
+
+public class AltosLights extends JComponent {
+
+       GridBagLayout   gridbag;
+
+       AltosLed        red, green;
+
+       ImageIcon create_icon(String path, String description) {
+               java.net.URL imgURL = AltosUILib.class.getResource(path);
+               if (imgURL != null)
+                       return new ImageIcon(imgURL, description);
+               System.err.printf("Cannot find icon \"%s\"\n", path);
+               return null;
+       }
+
+       public void set (boolean on) {
+               if (on) {
+                       red.set(false);
+                       green.set(true);
+               } else {
+                       red.set(true);
+                       green.set(false);
+               }
+       }
+
+       public AltosLights() {
+               GridBagConstraints c;
+               gridbag = new GridBagLayout();
+               setLayout(gridbag);
+
+               c = new GridBagConstraints();
+               red = new AltosLed("/redled.png", "/grayled.png");
+               c.gridx = 0; c.gridy = 0;
+               c.insets = new Insets (0, 5, 0, 5);
+               gridbag.setConstraints(red, c);
+               add(red);
+               red.set(true);
+               green = new AltosLed("/greenled.png", "/grayled.png");
+               c.gridx = 1; c.gridy = 0;
+               gridbag.setConstraints(green, c);
+               add(green);
+               green.set(false);
+       }
+}
index e75d2de566a9bdcb009e80ab14a1656aaf01c930..34cf1650179cb3e95aad061fb56d0679fa06f6ab 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 public interface AltosPositionListener {
        public void position_changed(int position);
diff --git a/altosuilib/AltosRomconfigUI.java b/altosuilib/AltosRomconfigUI.java
new file mode 100644 (file)
index 0000000..8f002c4
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosRomconfigUI
+       extends AltosUIDialog
+       implements ActionListener
+{
+       Container       pane;
+       Box             box;
+       JLabel          serial_label;
+       JLabel          radio_calibration_label;
+
+       JFrame          owner;
+       JTextField      serial_value;
+       JTextField      radio_calibration_value;
+
+       JButton         ok;
+       JButton         cancel;
+
+       /* Build the UI using a grid bag */
+       public AltosRomconfigUI(JFrame in_owner) {
+               super (in_owner, "Configure TeleMetrum Rom Values", true);
+
+               owner = in_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());
+
+               /* Serial */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 0;
+               c.gridwidth = 3;
+               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 = 3; c.gridy = 0;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               serial_value = new JTextField("00000000");
+               pane.add(serial_value, c);
+
+               /* Radio calibration value */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 1;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               radio_calibration_label = new JLabel("Radio Calibration:");
+               pane.add(radio_calibration_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 3; c.gridy = 1;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               radio_calibration_value = new JTextField("00000000");
+               pane.add(radio_calibration_value, c);
+
+               /* Buttons */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = 2;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = il;
+               ok = new JButton("OK");
+               pane.add(ok, c);
+               ok.addActionListener(this);
+               ok.setActionCommand("ok");
+
+               c = new GridBagConstraints();
+               c.gridx = 3; c.gridy = 2;
+               c.gridwidth = 3;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = il;
+               cancel = new JButton("Cancel");
+               pane.add(cancel, c);
+               cancel.addActionListener(this);
+               cancel.setActionCommand("cancel");
+
+               pack();
+               setLocationRelativeTo(owner);
+       }
+
+       public AltosRomconfigUI(JFrame frame, AltosRomconfig config) {
+               this(frame);
+               set(config);
+       }
+
+       boolean selected;
+
+       /* Listen for events from our buttons */
+       public void actionPerformed(ActionEvent e) {
+               String  cmd = e.getActionCommand();
+
+               if (cmd.equals("ok")) {
+                       AltosRomconfig  romconfig = romconfig();
+                       if (romconfig == null || !romconfig.valid()) {
+                               JOptionPane.showMessageDialog(this,
+                                                             "Invalid serial number or radio calibration value",
+                                                             "Invalid rom configuration",
+                                                             JOptionPane.ERROR_MESSAGE);
+                               return;
+                       }
+                       selected = true;
+               }
+               setVisible(false);
+       }
+
+       int serial() {
+               return Integer.parseInt(serial_value.getText());
+       }
+
+       void set_serial(int serial) {
+               serial_value.setText(String.format("%d", serial));
+       }
+
+       int radio_calibration() {
+               return Integer.parseInt(radio_calibration_value.getText());
+       }
+
+       void set_radio_calibration(int calibration) {
+               radio_calibration_value.setText(String.format("%d", calibration));
+       }
+
+       public void set(AltosRomconfig config) {
+               if (config != null && config.valid()) {
+                       set_serial(config.serial_number);
+                       set_radio_calibration(config.radio_calibration);
+               }
+       }
+
+       AltosRomconfig romconfig() {
+               try {
+                       return new AltosRomconfig(serial(), radio_calibration());
+               } catch (NumberFormatException ne) {
+                       return null;
+               }
+       }
+
+       public AltosRomconfig showDialog() {
+               setVisible(true);
+               if (selected)
+                       return romconfig();
+               return null;
+       }
+
+       public static AltosRomconfig show(JFrame frame, AltosRomconfig config) {
+               AltosRomconfigUI ui = new AltosRomconfigUI(frame, config);
+               return ui.showDialog();
+       }
+}
diff --git a/altosuilib/AltosScanUI.java b/altosuilib/AltosScanUI.java
new file mode 100644 (file)
index 0000000..b0cde05
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+class AltosScanResult {
+       String          callsign;
+       int             serial;
+       int             flight;
+       AltosFrequency  frequency;
+       int             telemetry;
+
+       boolean interrupted = false;
+
+       public String toString() {
+               return String.format("%-9.9s serial %-4d flight %-4d (%s %s)",
+                                    callsign, serial, flight, frequency.toShortString(), AltosLib.telemetry_name(telemetry));
+       }
+
+       public String toShortString() {
+               return String.format("%s %d %d %7.3f %d",
+                                    callsign, serial, flight, frequency, telemetry);
+       }
+
+       public AltosScanResult(String in_callsign, int in_serial,
+                              int in_flight, AltosFrequency in_frequency, int in_telemetry) {
+               callsign = in_callsign;
+               serial = in_serial;
+               flight = in_flight;
+               frequency = in_frequency;
+               telemetry = in_telemetry;
+       }
+
+       public boolean equals(AltosScanResult other) {
+               return (serial == other.serial &&
+                       frequency.frequency == other.frequency.frequency &&
+                       telemetry == other.telemetry);
+       }
+
+       public boolean up_to_date(AltosScanResult other) {
+               if (flight == 0 && other.flight != 0) {
+                       flight = other.flight;
+                       return false;
+               }
+               if (callsign.equals("N0CALL") && !other.callsign.equals("N0CALL")) {
+                       callsign = other.callsign;
+                       return false;
+               }
+               return true;
+       }
+}
+
+class AltosScanResults extends LinkedList<AltosScanResult> implements ListModel<AltosScanResult> {
+
+       LinkedList<ListDataListener>    listeners = new LinkedList<ListDataListener>();
+
+       void changed(ListDataEvent de) {
+               for (ListDataListener l : listeners)
+                       l.contentsChanged(de);
+       }
+
+       public boolean add(AltosScanResult r) {
+               int i = 0;
+               for (AltosScanResult old : this) {
+                       if (old.equals(r)) {
+                               if (!old.up_to_date(r))
+                                       changed (new ListDataEvent(this,
+                                                                  ListDataEvent.CONTENTS_CHANGED,
+                                                                  i, i));
+                               return true;
+                       }
+                       i++;
+               }
+
+               super.add(r);
+               changed(new ListDataEvent(this,
+                                         ListDataEvent.INTERVAL_ADDED,
+                                         this.size() - 2, this.size() - 1));
+               return true;
+       }
+
+       public void addListDataListener(ListDataListener l) {
+               listeners.add(l);
+       }
+
+       public void removeListDataListener(ListDataListener l) {
+               listeners.remove(l);
+       }
+
+       public AltosScanResult getElementAt(int i) {
+               return this.get(i);
+       }
+
+       public int getSize() {
+               return this.size();
+       }
+}
+
+public class AltosScanUI
+       extends AltosUIDialog
+       implements ActionListener
+{
+       AltosUIFrame                    owner;
+       AltosDevice                     device;
+       AltosConfigData                 config_data;
+       AltosTelemetryReader            reader;
+       private JList<AltosScanResult>  list;
+       private JLabel                  scanning_label;
+       private JLabel                  frequency_label;
+       private JLabel                  telemetry_label;
+       private JButton                 cancel_button;
+       private JButton                 monitor_button;
+       private JCheckBox[]             telemetry_boxes;
+       javax.swing.Timer               timer;
+       AltosScanResults                results = new AltosScanResults();
+
+       int                             telemetry;
+       boolean                         select_telemetry = false;
+
+       final static int                timeout = 1200;
+       TelemetryHandler                handler;
+       Thread                          thread;
+       AltosFrequency[]                frequencies;
+       int                             frequency_index;
+
+       void scan_exception(Exception e) {
+               if (e instanceof FileNotFoundException) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     ((FileNotFoundException) e).getMessage(),
+                                                     "Cannot open target device",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } else if (e instanceof AltosSerialInUseException) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     String.format("Device \"%s\" already in use",
+                                                                   device.toShortString()),
+                                                     "Device in use",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } else if (e instanceof IOException) {
+                       IOException ee = (IOException) e;
+                       JOptionPane.showMessageDialog(owner,
+                                                     device.toShortString(),
+                                                     ee.getLocalizedMessage(),
+                                                     JOptionPane.ERROR_MESSAGE);
+               } else {
+                       JOptionPane.showMessageDialog(owner,
+                                                     String.format("Connection to \"%s\" failed",
+                                                                   device.toShortString()),
+                                                     "Connection Failed",
+                                                     JOptionPane.ERROR_MESSAGE);
+               }
+               close();
+       }
+
+       class TelemetryHandler implements Runnable {
+
+               public void run() {
+
+                       boolean interrupted = false;
+
+                       try {
+                               for (;;) {
+                                       try {
+                                               AltosState      state = reader.read();
+                                               if (state == null)
+                                                       continue;
+                                               if (state.flight != AltosLib.MISSING) {
+                                                       final AltosScanResult   result = new AltosScanResult(state.callsign,
+                                                                                                    state.serial,
+                                                                                                    state.flight,
+                                                                                                    frequencies[frequency_index],
+                                                                                                    telemetry);
+                                                       Runnable r = new Runnable() {
+                                                                       public void run() {
+                                                                               results.add(result);
+                                                                       }
+                                                               };
+                                                       SwingUtilities.invokeLater(r);
+                                               }
+                                       } catch (ParseException pp) {
+                                       } catch (AltosCRCException ce) {
+                                       }
+                               }
+                       } catch (InterruptedException ee) {
+                               interrupted = true;
+                       } catch (IOException ie) {
+                       } finally {
+                               reader.close(interrupted);
+                       }
+               }
+       }
+
+       void set_label() {
+               frequency_label.setText(String.format("Frequency: %s", frequencies[frequency_index].toString()));
+               if (select_telemetry)
+                       telemetry_label.setText(String.format("Telemetry: %s", AltosLib.telemetry_name(telemetry)));
+       }
+
+       void set_telemetry() {
+               reader.set_telemetry(telemetry);
+       }
+
+       void set_frequency() throws InterruptedException, TimeoutException {
+               reader.set_frequency(frequencies[frequency_index].frequency);
+               reader.reset();
+       }
+
+       void next() throws InterruptedException, TimeoutException {
+               reader.set_monitor(false);
+               Thread.sleep(100);
+               ++frequency_index;
+               if (select_telemetry) {
+                       if (frequency_index >= frequencies.length ||
+                           !telemetry_boxes[telemetry - AltosLib.ao_telemetry_min].isSelected())
+                       {
+                               frequency_index = 0;
+                               do {
+                                       ++telemetry;
+                                       if (telemetry > AltosLib.ao_telemetry_max)
+                                               telemetry = AltosLib.ao_telemetry_min;
+                               } while (!telemetry_boxes[telemetry - AltosLib.ao_telemetry_min].isSelected());
+                               set_telemetry();
+                       }
+               } else {
+                       if (frequency_index >= frequencies.length)
+                               frequency_index = 0;
+               }
+               set_frequency();
+               set_label();
+               reader.set_monitor(true);
+       }
+
+
+       void close() {
+               if (thread != null && thread.isAlive()) {
+                       thread.interrupt();
+                       try {
+                               thread.join();
+                       } catch (InterruptedException ie) {}
+               }
+               thread = null;
+               if (timer != null)
+                       timer.stop();
+               setVisible(false);
+               dispose();
+       }
+
+       void tick_timer() throws InterruptedException, TimeoutException {
+               next();
+       }
+
+       public void actionPerformed(ActionEvent e) {
+               String cmd = e.getActionCommand();
+
+               try {
+                       if (cmd.equals("cancel"))
+                               close();
+
+                       if (cmd.equals("tick"))
+                               tick_timer();
+
+                       if (cmd.equals("telemetry")) {
+                               int k;
+                               int scanning_telemetry = 0;
+                               for (k = AltosLib.ao_telemetry_min; k <= AltosLib.ao_telemetry_max; k++) {
+                                       int j = k - AltosLib.ao_telemetry_min;
+                                       if (telemetry_boxes[j].isSelected())
+                                               scanning_telemetry |= (1 << k);
+                               }
+                               if (scanning_telemetry == 0) {
+                                       scanning_telemetry |= (1 << AltosLib.ao_telemetry_standard);
+                                       telemetry_boxes[AltosLib.ao_telemetry_standard - AltosLib.ao_telemetry_min].setSelected(true);
+                               }
+                               AltosUIPreferences.set_scanning_telemetry(scanning_telemetry);
+                       }
+
+                       if (cmd.equals("monitor")) {
+                               close();
+                               AltosScanResult r = (AltosScanResult) (list.getSelectedValue());
+                               if (r != null) {
+                                       if (device != null) {
+                                               if (reader != null) {
+                                                       reader.set_telemetry(r.telemetry);
+                                                       reader.set_frequency(r.frequency.frequency);
+                                                       reader.save_frequency();
+                                                       owner.scan_device_selected(device);
+                                               }
+                                       }
+                               }
+                       }
+               } catch (TimeoutException te) {
+                       close();
+               } catch (InterruptedException ie) {
+                       close();
+               }
+       }
+
+       /* A window listener to catch closing events and tell the config code */
+       class ConfigListener extends WindowAdapter {
+               AltosScanUI     ui;
+
+               public ConfigListener(AltosScanUI this_ui) {
+                       ui = this_ui;
+               }
+
+               public void windowClosing(WindowEvent e) {
+                       ui.actionPerformed(new ActionEvent(e.getSource(),
+                                                          ActionEvent.ACTION_PERFORMED,
+                                                          "close"));
+               }
+       }
+
+       private boolean open() {
+               device = AltosDeviceUIDialog.show(owner, AltosLib.product_basestation);
+               if (device == null)
+                       return false;
+               try {
+                       reader = new AltosTelemetryReader(new AltosSerial(device));
+                       set_frequency();
+                       set_telemetry();
+                       try {
+                               Thread.sleep(100);
+                       } catch (InterruptedException ie) {
+                       }
+                       reader.flush();
+                       handler = new TelemetryHandler();
+                       thread = new Thread(handler);
+                       thread.start();
+                       return true;
+               } catch (FileNotFoundException ee) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     ee.getMessage(),
+                                                     "Cannot open target device",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (AltosSerialInUseException si) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     String.format("Device \"%s\" already in use",
+                                                                   device.toShortString()),
+                                                     "Device in use",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (IOException ee) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     device.toShortString(),
+                                                     "Unkonwn I/O error",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (TimeoutException te) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     device.toShortString(),
+                                                     "Timeout error",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (InterruptedException ie) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     device.toShortString(),
+                                                     "Interrupted exception",
+                                                     JOptionPane.ERROR_MESSAGE);
+               }
+               if (reader != null)
+                       reader.close(false);
+               return false;
+       }
+
+       public AltosScanUI(AltosUIFrame in_owner, boolean in_select_telemetry) {
+
+               owner = in_owner;
+               select_telemetry = in_select_telemetry;
+
+               frequencies = AltosUIPreferences.common_frequencies();
+               frequency_index = 0;
+
+               telemetry = AltosLib.ao_telemetry_standard;
+
+               if (!open())
+                       return;
+
+               Container               pane = getContentPane();
+               GridBagConstraints      c = new GridBagConstraints();
+               Insets                  i = new Insets(4,4,4,4);
+
+               timer = new javax.swing.Timer(timeout, this);
+               timer.setActionCommand("tick");
+               timer.restart();
+
+               owner = in_owner;
+
+               pane.setLayout(new GridBagLayout());
+
+               scanning_label = new JLabel("Scanning:");
+               frequency_label = new JLabel("");
+
+               if (select_telemetry) {
+                       telemetry_label = new JLabel("");
+                       telemetry = AltosLib.ao_telemetry_min;
+               } else {
+                       telemetry = AltosLib.ao_telemetry_standard;
+               }
+
+               set_label();
+
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.anchor = GridBagConstraints.WEST;
+               c.insets = i;
+               c.weightx = 1;
+               c.weighty = 1;
+
+               c.gridx = 0;
+               c.gridy = 0;
+               c.gridwidth = 2;
+
+               pane.add(scanning_label, c);
+               c.gridy = 1;
+               pane.add(frequency_label, c);
+
+               int     y_offset = 3;
+
+               if (select_telemetry) {
+                       c.gridy = 2;
+                       pane.add(telemetry_label, c);
+
+                       int     scanning_telemetry = AltosUIPreferences.scanning_telemetry();
+                       telemetry_boxes = new JCheckBox[AltosLib.ao_telemetry_max - AltosLib.ao_telemetry_min + 1];
+                       for (int k = AltosLib.ao_telemetry_min; k <= AltosLib.ao_telemetry_max; k++) {
+                               int j = k - AltosLib.ao_telemetry_min;
+                               telemetry_boxes[j] = new JCheckBox(AltosLib.telemetry_name(k));
+                               c.gridy = 3 + j;
+                               pane.add(telemetry_boxes[j], c);
+                               telemetry_boxes[j].setActionCommand("telemetry");
+                               telemetry_boxes[j].addActionListener(this);
+                               telemetry_boxes[j].setSelected((scanning_telemetry & (1 << k)) != 0);
+                       }
+                       y_offset += (AltosLib.ao_telemetry_max - AltosLib.ao_telemetry_min + 1);
+               }
+
+               list = new JList<AltosScanResult>(results) {
+                               //Subclass JList to workaround bug 4832765, which can cause the
+                               //scroll pane to not let the user easily scroll up to the beginning
+                               //of the list.  An alternative would be to set the unitIncrement
+                               //of the JScrollBar to a fixed value. You wouldn't get the nice
+                               //aligned scrolling, but it should work.
+                               public int getScrollableUnitIncrement(Rectangle visibleRect,
+                                                                     int orientation,
+                                                                     int direction) {
+                                       int row;
+                                       if (orientation == SwingConstants.VERTICAL &&
+                                           direction < 0 && (row = getFirstVisibleIndex()) != -1) {
+                                               Rectangle r = getCellBounds(row, row);
+                                               if ((r.y == visibleRect.y) && (row != 0))  {
+                                                       Point loc = r.getLocation();
+                                                       loc.y--;
+                                                       int prevIndex = locationToIndex(loc);
+                                                       Rectangle prevR = getCellBounds(prevIndex, prevIndex);
+
+                                                       if (prevR == null || prevR.y >= r.y) {
+                                                               return 0;
+                                                       }
+                                                       return prevR.height;
+                                               }
+                                       }
+                                       return super.getScrollableUnitIncrement(
+                                               visibleRect, orientation, direction);
+                               }
+                       };
+
+               list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+               list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
+               list.setVisibleRowCount(-1);
+
+               list.addMouseListener(new MouseAdapter() {
+                                public void mouseClicked(MouseEvent e) {
+                                        if (e.getClickCount() == 2) {
+                                                monitor_button.doClick(); //emulate button click
+                                        }
+                                }
+                       });
+               JScrollPane listScroller = new JScrollPane(list);
+               listScroller.setPreferredSize(new Dimension(400, 80));
+               listScroller.setAlignmentX(LEFT_ALIGNMENT);
+
+               //Create a container so that we can add a title around
+               //the scroll pane.  Can't add a title directly to the
+               //scroll pane because its background would be white.
+               //Lay out the label and scroll pane from top to bottom.
+               JPanel listPane = new JPanel();
+               listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
+
+               JLabel label = new JLabel("Select Device");
+               label.setLabelFor(list);
+               listPane.add(label);
+               listPane.add(Box.createRigidArea(new Dimension(0,5)));
+               listPane.add(listScroller);
+               listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
+
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 1;
+               c.weighty = 1;
+
+               c.gridx = 0;
+               c.gridy = y_offset;
+               c.gridwidth = 2;
+               c.anchor = GridBagConstraints.CENTER;
+
+               pane.add(listPane, c);
+
+               cancel_button = new JButton("Cancel");
+               cancel_button.addActionListener(this);
+               cancel_button.setActionCommand("cancel");
+
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 1;
+               c.weighty = 1;
+
+               c.gridx = 0;
+               c.gridy = y_offset + 1;
+               c.gridwidth = 1;
+               c.anchor = GridBagConstraints.CENTER;
+
+               pane.add(cancel_button, c);
+
+               monitor_button = new JButton("Monitor");
+               monitor_button.addActionListener(this);
+               monitor_button.setActionCommand("monitor");
+
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 1;
+               c.weighty = 1;
+
+               c.gridx = 1;
+               c.gridy = y_offset + 1;
+               c.gridwidth = 1;
+               c.anchor = GridBagConstraints.CENTER;
+
+               pane.add(monitor_button, c);
+
+               pack();
+               setLocationRelativeTo(owner);
+
+               addWindowListener(new ConfigListener(this));
+
+               setVisible(true);
+       }
+}
diff --git a/altosuilib/AltosSerial.java b/altosuilib/AltosSerial.java
new file mode 100644 (file)
index 0000000..60e15bd
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+/*
+ * Deal with TeleDongle on a serial port
+ */
+
+package org.altusmetrum.altosuilib_2;
+
+import java.io.*;
+import java.util.*;
+import java.awt.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+import libaltosJNI.*;
+
+/*
+ * This class reads from the serial port and places each received
+ * line in a queue. Dealing with that queue is left up to other
+ * threads.
+ */
+
+public class AltosSerial extends AltosLink  {
+
+       static java.util.List<String> devices_opened = Collections.synchronizedList(new LinkedList<String>());
+
+       public AltosDevice device;
+       SWIGTYPE_p_altos_file altos;
+       Thread input_thread;
+       String line;
+       byte[] line_bytes;
+       int line_count;
+       Frame frame;
+
+       public int getchar() {
+               if (altos == null)
+                       return ERROR;
+               return libaltos.altos_getchar(altos, 0);
+       }
+
+       public void flush_output() {
+               super.flush_output();
+               if (altos != null) {
+                       if (libaltos.altos_flush(altos) != 0)
+                               close_serial();
+               }
+       }
+
+       JDialog         timeout_dialog;
+
+       private void start_timeout_dialog_internal() {
+
+               Object[] options = { "Cancel" };
+
+               JOptionPane     pane = new JOptionPane();
+               pane.setMessage(String.format("Connecting to %s, %7.3f MHz as %s", device.toShortString(), frequency, callsign));
+               pane.setOptions(options);
+               pane.setInitialValue(null);
+
+               timeout_dialog = pane.createDialog(frame, "Connecting...");
+
+               timeout_dialog.setVisible(true);
+
+               Object o = pane.getValue();
+               if (o == null)
+                       return;
+               if (options[0].equals(o))
+                       reply_abort = true;
+               timeout_dialog.dispose();
+               timeout_dialog = null;
+       }
+
+       /*
+        * These are required by the AltosLink implementation
+        */
+
+       public boolean can_cancel_reply() {
+               /*
+                * Can cancel any replies not called from the dispatch thread
+                */
+               return !SwingUtilities.isEventDispatchThread();
+       }
+
+       public boolean show_reply_timeout() {
+               if (!SwingUtilities.isEventDispatchThread() && frame != null) {
+                       Runnable r = new Runnable() {
+                                       public void run() {
+                                               start_timeout_dialog_internal();
+                                       }
+                               };
+                       SwingUtilities.invokeLater(r);
+                       return true;
+               }
+               return false;
+       }
+
+       public void hide_reply_timeout() {
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       timeout_dialog.setVisible(false);
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       private synchronized 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 {
+                               stop_remote();
+                       } catch (InterruptedException ie) {
+                       }
+               }
+               if (in_reply != 0)
+                       System.out.printf("Uh-oh. Closing active serial device\n");
+
+               close_serial();
+
+               if (input_thread != null) {
+                       try {
+                               input_thread.interrupt();
+                               input_thread.join();
+                       } catch (InterruptedException ie) {
+                       }
+                       input_thread = null;
+               }
+               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)
+                               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) {
+               for (int i = 0; i < data.length(); i++)
+                       putc(data.charAt(i));
+       }
+
+       private void open() throws FileNotFoundException, AltosSerialInUseException {
+               synchronized (devices_opened) {
+                       if (devices_opened.contains(device.getPath()))
+                               throw new AltosSerialInUseException(device);
+                       devices_opened.add(device.getPath());
+               }
+               altos = device.open();
+               if (altos == null) {
+                       final String    message = device.getErrorString();
+                       close();
+                       throw new FileNotFoundException(String.format("%s (%s)",
+                                                                     device.toShortString(), message));
+               }
+               if (debug)
+                       System.out.printf("Open %s\n", device.getPath());
+               input_thread = new Thread(this);
+               input_thread.start();
+               print("~\nE 0\n");
+               set_monitor(false);
+               flush_output();
+       }
+
+       public void set_frame(Frame in_frame) {
+               frame = in_frame;
+       }
+
+       public AltosSerial(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
+               device = in_device;
+               frame = null;
+               serial = device.getSerial();
+               name = device.toShortString();
+               open();
+       }
+}
diff --git a/altosuilib/AltosSerialInUseException.java b/altosuilib/AltosSerialInUseException.java
new file mode 100644 (file)
index 0000000..1e8207d
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.altosuilib_2;
+
+public class AltosSerialInUseException extends Exception {
+       public AltosDevice      device;
+
+       public AltosSerialInUseException (AltosDevice in_device) {
+               device = in_device;
+       }
+}
index 1638ea290512fdb9d62473e9cd696d6a64686380..74561673fde97f92cb53eee15353d3765259b5a3 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.io.*;
 import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
@@ -50,7 +50,7 @@ public class AltosUIAxis extends NumberAxis {
        public void set_units() {
                setLabel(String.format("%s (%s)", label, units.show_units()));
        }
-       
+
        public void set_enable(boolean enable) {
                if (enable) {
                        visible++;
index 9e72e403a877abf8c5677588530f110a08291836..920ed8e287a10c126c930cc3f41a2ac3376e1e9e 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.awt.*;
 import java.awt.event.*;
@@ -23,10 +23,10 @@ import java.beans.*;
 import javax.swing.*;
 import javax.swing.event.*;
 
-class DelegatingRenderer implements ListCellRenderer {
+class DelegatingRenderer implements ListCellRenderer<Object> {
 
        // ...
-       public static void install(JComboBox comboBox) {
+       public static void install(JComboBox<Object> comboBox) {
                DelegatingRenderer renderer = new DelegatingRenderer(comboBox);
                renderer.initialise();
                comboBox.setRenderer(renderer);
@@ -36,7 +36,7 @@ class DelegatingRenderer implements ListCellRenderer {
        private final JComboBox comboBox;
 
        // ...
-       private ListCellRenderer delegate;
+       private ListCellRenderer<? super Object> delegate;
 
        // ...
        private DelegatingRenderer(JComboBox comboBox) {
@@ -45,21 +45,22 @@ class DelegatingRenderer implements ListCellRenderer {
 
        // ...
        private void initialise() {
-               delegate = new JComboBox().getRenderer();
+               JComboBox<Object> c = new JComboBox<Object>();
+               delegate = c.getRenderer();
                comboBox.addPropertyChangeListener("UI", new PropertyChangeListener() {
 
                                public void propertyChange(PropertyChangeEvent evt) {
-                                       delegate = new JComboBox().getRenderer();
+                                       delegate = new JComboBox<Object>().getRenderer();
                                }
                        });
        }
 
        // ...
-       public Component getListCellRendererComponent(JList list,
+       public Component getListCellRendererComponent(JList<?> list,
                                                      Object value, int index, boolean isSelected, boolean cellHasFocus) {
 
                return delegate.getListCellRendererComponent(list,
-                                                            ((UIManager.LookAndFeelInfo) value).getName(),
+                                                            ((UIManager.LookAndFeelInfo)value).getName(),
                                                             index, isSelected, cellHasFocus);
        }
 }
@@ -139,7 +140,7 @@ public class AltosUIConfigure
                /* Font size setting */
                pane.add(new JLabel("Font size"), constraints(0, 1));
 
-               final JComboBox font_size_value = new JComboBox(font_size_names);
+               final JComboBox<String> font_size_value = new JComboBox<String>(font_size_names);
                int font_size = AltosUIPreferences.font_size();
                font_size_value.setSelectedIndex(font_size - AltosUILib.font_size_small);
                font_size_value.addActionListener(new ActionListener() {
@@ -181,7 +182,7 @@ public class AltosUIConfigure
 
                final UIManager.LookAndFeelInfo[] look_and_feels = UIManager.getInstalledLookAndFeels();
 
-               final JComboBox look_and_feel_value = new JComboBox(look_and_feels);
+               final JComboBox<Object> look_and_feel_value = new JComboBox<Object>(look_and_feels);
 
                DelegatingRenderer.install(look_and_feel_value);
 
@@ -228,8 +229,8 @@ public class AltosUIConfigure
        public void add_frequencies() {
        }
 
-       public AltosUIConfigure(JFrame in_owner) {
-               super(in_owner, "Configure AltosUI", false);
+       public AltosUIConfigure(JFrame in_owner, String name, String label) {
+               super(in_owner, name, false);
 
                owner = in_owner;
                pane = getContentPane();
@@ -238,7 +239,7 @@ public class AltosUIConfigure
                row = 0;
 
                /* Nice label at the top */
-               pane.add(new JLabel ("Configure AltOS UI"),
+               pane.add(new JLabel (label),
                         constraints(0, 3));
                row++;
 
@@ -270,4 +271,8 @@ public class AltosUIConfigure
                setLocationRelativeTo(owner);
                setVisible(true);
        }
+
+       public AltosUIConfigure(JFrame in_owner) {
+               this(in_owner, "Configure AltosUI", "Configure AltOS UI");
+       }
 }
index c7b01859532bccc2a5026e5453574a2bc920dd6c..353ff30ff308b4b33117a37ad4234099c6614ff3 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 public class AltosUIDataMissing extends Exception {
        public int      id;
index d3020410c2348614893a774f7ff2ae42017a52d6..3f16500e1d17ce5d619ca1225b702ff7e437f859 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 public interface AltosUIDataPoint {
        public abstract double x() throws AltosUIDataMissing;
index 6f23ef9a606ba924135e20a81962c5e5c88b03df..ee70a3fd6a57ac52f013bc47c51dcff00e30280c 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 public interface AltosUIDataSet {
        public abstract String name();
index e1e699a78cd4e66adae92c0eea170b168410d07b..dc737414532718a14c236925f0ce442be200ed2c 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.awt.*;
 import java.awt.event.*;
index ea4bd00ab6b4874b12355e0de196ac2184a8929c..da98797a7cfd7ae54f78cc6fe0fa5941bb5c6eab 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.awt.*;
 import java.awt.event.*;
@@ -23,7 +23,7 @@ import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
@@ -45,7 +45,7 @@ public class AltosUIEnable extends Container {
 
        class GraphElement implements ActionListener {
                AltosUIGrapher  grapher;
-               JRadioButton    enable;
+               JCheckBox       enable;
                String          name;
 
                public void actionPerformed(ActionEvent ae) {
@@ -55,8 +55,8 @@ public class AltosUIEnable extends Container {
                GraphElement (String name, AltosUIGrapher grapher, boolean enabled) {
                        this.name = name;
                        this.grapher = grapher;
-                       enable = new JRadioButton(name, enabled);
-                       grapher.set_enable(enabled);                      
+                       enable = new JCheckBox(name, enabled);
+                       grapher.set_enable(enabled);
                        enable.addActionListener(this);
                }
        }
@@ -86,10 +86,10 @@ public class AltosUIEnable extends Container {
                /* Imperial units setting */
 
                /* Add label */
-               JRadioButton imperial_units = new JRadioButton("Imperial Units", AltosUIPreferences.imperial_units());
+               JCheckBox imperial_units = new JCheckBox("Imperial Units", AltosUIPreferences.imperial_units());
                imperial_units.addActionListener(new ActionListener() {
                                public void actionPerformed(ActionEvent e) {
-                                       JRadioButton item = (JRadioButton) e.getSource();
+                                       JCheckBox item = (JCheckBox) e.getSource();
                                        boolean enabled = item.isSelected();
                                        AltosUIPreferences.set_imperial_units(enabled);
                                }
diff --git a/altosuilib/AltosUIFlightTab.java b/altosuilib/AltosUIFlightTab.java
new file mode 100644 (file)
index 0000000..039d83e
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+
+public abstract class AltosUIFlightTab extends JComponent implements AltosFlightDisplay, HierarchyListener {
+       public GridBagLayout    layout;
+
+       AltosState              last_state;
+       AltosListenerState      last_listener_state;
+
+       LinkedList<AltosUIIndicator>    indicators = new LinkedList<AltosUIIndicator>();
+
+       public void add (AltosUIIndicator indicator) {
+               indicators.add(indicator);
+       }
+
+       public void remove(AltosUIIndicator indicator) {
+               indicators.remove(indicator);
+       }
+
+       public void reset() {
+               for (AltosUIIndicator i : indicators)
+                       i.reset();
+       }
+
+       public void font_size_changed(int font_size) {
+               for (AltosUIIndicator i : indicators)
+                       i.font_size_changed(font_size);
+       }
+
+       public void units_changed(boolean imperial_units) {
+               for (AltosUIIndicator i : indicators)
+                       i.units_changed(imperial_units);
+       }
+
+       public void show(AltosState state, AltosListenerState listener_state) {
+               if (!isShowing()) {
+                       last_state = state;
+                       last_listener_state = listener_state;
+                       return;
+               }
+
+               for (AltosUIIndicator i : indicators)
+                       i.show(state, listener_state);
+       }
+
+       public void hierarchyChanged(HierarchyEvent e) {
+               if (last_state != null && isShowing()) {
+                       AltosState              state = last_state;
+                       AltosListenerState      listener_state = last_listener_state;
+
+                       last_state = null;
+                       last_listener_state = null;
+                       show(state, listener_state);
+               }
+       }
+
+       abstract public String getName();
+
+       public AltosUIFlightTab() {
+               layout = new GridBagLayout();
+
+               setLayout(layout);
+
+               addHierarchyListener(this);
+       }
+}
index 3fc99910d8c6f016d4770311146cf923dc7345b0..6e62c762948d83578814c5b26d4534a0c92ff352 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.awt.*;
 import java.awt.event.*;
@@ -45,7 +45,7 @@ public class AltosUIFrame extends JFrame implements AltosUIListener, AltosPositi
        };
 
        static public String[] icon_names;
-       
+
        static public void set_icon_names(String[] new_icon_names) { icon_names = new_icon_names; }
 
        public String[] icon_names() {
@@ -57,7 +57,7 @@ public class AltosUIFrame extends JFrame implements AltosUIListener, AltosPositi
        public void set_icon() {
                ArrayList<Image> icons = new ArrayList<Image>();
                String[] icon_names = icon_names();
-               
+
                for (int i = 0; i < icon_names.length; i++) {
                        java.net.URL imgURL = AltosUIFrame.class.getResource(icon_names[i]);
                        if (imgURL != null)
@@ -65,14 +65,17 @@ public class AltosUIFrame extends JFrame implements AltosUIListener, AltosPositi
                }
                setIconImages(icons);
        }
-                       
+
        private boolean location_by_platform = true;
 
        public void setLocationByPlatform(boolean lbp) {
                location_by_platform = lbp;
                super.setLocationByPlatform(lbp);
        }
-               
+
+       public void scan_device_selected(AltosDevice device) {
+       }
+
        public void setSize() {
                /* Smash sizes around so that the window comes up in the right shape */
                Insets i = getInsets();
@@ -153,7 +156,7 @@ public class AltosUIFrame extends JFrame implements AltosUIListener, AltosPositi
                                setPosition(position);
                }
        }
-               
+
        void init() {
                AltosUIPreferences.register_ui_listener(this);
                AltosUIPreferences.register_position_listener(this);
index 061a76295a0b0fd5214ada2b6cfee4ea8b489cce..9cca088de48cfd38d23262f3e26d36618ee90522 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.io.*;
 import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
@@ -82,11 +82,9 @@ public class AltosUIGraph implements AltosUnitsListener {
        public void addSeries(String label, int fetch, AltosUnits units, Color color) {
                addSeries(label, fetch, units, color, true, newAxis(label, units, color));
        }
-       
+
        public void addMarker(String label, int fetch, Color color) {
                AltosUIMarker           marker = new AltosUIMarker(fetch, color, plot);
-               if (enable != null)
-                       enable.add(label, marker, true);
                this.graphers.add(marker);
        }
 
@@ -131,7 +129,7 @@ public class AltosUIGraph implements AltosUnitsListener {
                this.axis_index = 0;
 
                xAxis = new NumberAxis("Time (s)");
-               
+
                xAxis.setAutoRangeIncludesZero(true);
 
                plot = new XYPlot();
@@ -158,4 +156,4 @@ public class AltosUIGraph implements AltosUnitsListener {
 
                AltosPreferences.register_units_listener(this);
        }
-}
\ No newline at end of file
+}
index 23e7d9f09ccdfc39437208b2046f9d68ed4c4d8a..724fac18de3a9ef39bfb89b8920c81e039fe3e9d 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.io.*;
 import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
@@ -37,7 +37,7 @@ import org.jfree.data.*;
 interface AltosUIGrapher {
 
        public abstract void set_units();
-       
+
        public abstract void clear();
 
        public abstract void add(AltosUIDataPoint dataPoint);
diff --git a/altosuilib/AltosUIIndicator.java b/altosuilib/AltosUIIndicator.java
new file mode 100644 (file)
index 0000000..b1626cb
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+
+public abstract class AltosUIIndicator implements AltosFontListener, AltosUnitsListener {
+       JLabel          label;
+       JTextField[]    values;
+       AltosLights     lights;
+       int             number_values;
+       boolean         has_lights;
+       int             value_width;
+
+       abstract public void show(AltosState state, AltosListenerState listener_state);
+
+       public void set_lights(boolean on) {
+               lights.set(on);
+       }
+
+       public void setVisible(boolean visible) {
+               if (lights != null)
+                       lights.setVisible(visible);
+               label.setVisible(visible);
+               for (int i = 0; i < values.length; i++)
+                       values[i].setVisible(visible);
+       }
+
+       public void reset() {
+               for (int i = 0; i < values.length; i++)
+                       values[i].setText("");
+               if (lights != null)
+                       lights.set(false);
+       }
+
+       public void show() {
+               if (lights != null)
+                       lights.setVisible(true);
+               label.setVisible(true);
+               for (int i = 0; i < values.length; i++)
+                       values[i].setVisible(true);
+       }
+
+       public void show(String... s) {
+               int     n = Math.min(s.length, values.length);
+
+               show();
+               for (int i = 0; i < n; i++)
+                       values[i].setText(s[i]);
+       }
+
+       public void show(String format, double value) {
+               show(String.format(format, value));
+       }
+
+       public void show(String format, int value) {
+               show(String.format(format, value));
+       }
+
+       public void show(String format1, double value1, String format2, double value2) {
+               show(String.format(format1, value1), String.format(format2, value2));
+       }
+
+       public void show(String format1, int value1, String format2, int value2) {
+               show(String.format(format1, value1), String.format(format2, value2));
+       }
+
+       public void hide() {
+               if (lights != null)
+                       lights.setVisible(false);
+               label.setVisible(false);
+               for (int i = 0; i < values.length; i++)
+                       values[i].setVisible(false);
+       }
+
+       public void font_size_changed(int font_size) {
+               label.setFont(AltosUILib.label_font);
+               for (int i = 0; i < values.length; i++)
+                       values[i].setFont(AltosUILib.value_font);
+       }
+
+       public void units_changed(boolean imperial_units) {
+       }
+
+       public void set_label(String text) {
+               label.setText(text);
+       }
+
+       public void remove(Container container) {
+               if (lights != null)
+                       container.remove(lights);
+               container.remove(label);
+               for (int i = 0; i < values.length; i++)
+                       container.remove(values[i]);
+       }
+
+       public AltosUIIndicator (Container container, int x, int y, int label_width, String text, int number_values, boolean has_lights, int value_width, int value_space) {
+               GridBagLayout           layout = (GridBagLayout)(container.getLayout());
+
+               GridBagConstraints      c = new GridBagConstraints();
+               c.weighty = 1;
+
+               if (has_lights) {
+                       lights = new AltosLights();
+                       c.gridx = x; c.gridy = y;
+                       c.anchor = GridBagConstraints.CENTER;
+                       c.fill = GridBagConstraints.VERTICAL;
+                       c.weightx = 0;
+                       layout.setConstraints(lights, c);
+                       container.add(lights);
+               }
+
+               label = new JLabel(text);
+               label.setFont(AltosUILib.label_font);
+               label.setHorizontalAlignment(SwingConstants.LEFT);
+               c.gridx = x + 1; c.gridy = y;
+               c.gridwidth = label_width;
+               c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad);
+               c.anchor = GridBagConstraints.WEST;
+               c.fill = GridBagConstraints.VERTICAL;
+               c.weightx = 0;
+               layout.setConstraints(label, c);
+               container.add(label);
+
+               values = new JTextField[number_values];
+               for (int i = 0; i < values.length; i++) {
+                       values[i] = new JTextField(AltosUILib.text_width);
+                       values[i].setEditable(false);
+                       values[i].setFont(AltosUILib.value_font);
+                       values[i].setHorizontalAlignment(SwingConstants.RIGHT);
+                       c.gridx = 1 + label_width + x + i * value_space; c.gridy = y;
+                       c.anchor = GridBagConstraints.WEST;
+                       c.fill = GridBagConstraints.BOTH;
+                       c.weightx = 1;
+                       c.gridwidth = value_width;
+                       layout.setConstraints(values[i], c);
+                       container.add(values[i]);
+               }
+       }
+
+       public AltosUIIndicator (Container container, int x, int y, int label_width, String text, int number_values, boolean has_lights, int value_width) {
+               this(container, x, y, label_width, text, number_values, has_lights, value_width, 1);
+       }
+
+       public AltosUIIndicator (Container container, int x, int y, String text, int number_values, boolean has_lights, int value_width) {
+               this(container, x, y, 1, text, number_values, has_lights, value_width);
+       }
+
+       public AltosUIIndicator (Container container, int y, String text, int number_values, boolean has_lights, int value_width) {
+               this(container, 0, y, text, number_values, has_lights, value_width);
+       }
+
+       public AltosUIIndicator (Container container, int y, String text, int number_values, boolean has_lights) {
+               this(container, 0, y, text, number_values, has_lights, 1);
+       }
+
+       public AltosUIIndicator (Container container, int y, String text, int number_values) {
+               this(container, 0, y, text, number_values, false, 1);
+       }
+
+       public AltosUIIndicator (Container container, int y, String text) {
+               this(container, 0, y, text, 1, false, 1);
+       }
+}
diff --git a/altosuilib/AltosUILatLon.java b/altosuilib/AltosUILatLon.java
new file mode 100644 (file)
index 0000000..688dd58
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.lang.Math;
+import java.awt.geom.*;
+import java.util.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosUILatLon {
+       public double   lat;
+       public double   lon;
+
+       public boolean equals(AltosUILatLon other) {
+               if (other == null)
+                       return false;
+               return lat == other.lat && lon == other.lon;
+       }
+
+       public AltosUILatLon(double lat, double lon) {
+               this.lat = lat;
+               this.lon = lon;
+       }
+}
index 76782e2e565743072940d96f63c6f90cbfe9793e..b51c5963314a41dc57d794a86e99b66d26d905c2 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.awt.*;
 import libaltosJNI.*;
 
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 public class AltosUILib extends AltosLib {
 
index 450dc0bfc8701fb2b51152b035563932d8af064c..75a0ad949cc7e6b1555acae2874777f7792d29e6 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 public interface AltosUIListener {
        public void ui_changed(String look_and_feel);
diff --git a/altosuilib/AltosUIMap.java b/altosuilib/AltosUIMap.java
new file mode 100644 (file)
index 0000000..aaa68f2
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.lang.Math;
+import java.awt.geom.*;
+import java.util.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosUIMap extends JComponent implements AltosFlightDisplay, AltosUIMapZoomListener {
+
+       static final int px_size = 512;
+
+       static final int maptype_hybrid = 0;
+       static final int maptype_roadmap = 1;
+       static final int maptype_satellite = 2;
+       static final int maptype_terrain = 3;
+       static final int maptype_default = maptype_hybrid;
+
+       static final String[] maptype_names = {
+               "hybrid",
+               "roadmap",
+               "satellite",
+               "terrain"
+       };
+
+       public static final String[] maptype_labels = {
+               "Hybrid",
+               "Roadmap",
+               "Satellite",
+               "Terrain"
+       };
+
+       public static final Color stateColors[] = {
+               Color.WHITE,  // startup
+               Color.WHITE,  // idle
+               Color.WHITE,  // pad
+               Color.RED,    // boost
+               Color.PINK,   // fast
+               Color.YELLOW, // coast
+               Color.CYAN,   // drogue
+               Color.BLUE,   // main
+               Color.BLACK,  // landed
+               Color.BLACK,  // invalid
+               Color.CYAN,   // stateless
+       };
+
+       public void reset() {
+               // nothing
+       }
+
+       public void font_size_changed(int font_size) {
+               view.set_font();
+       }
+
+       public void units_changed(boolean imperial_units) {
+               view.set_units();
+       }
+
+       JLabel  zoom_label;
+
+       private void set_zoom_label() {
+               zoom_label.setText(String.format("Zoom %d", view.zoom() - view.default_zoom));
+       }
+
+       public void zoom_changed(int zoom) {
+               set_zoom_label();
+       }
+
+       public void set_zoom(int zoom) {
+               view.set_zoom(zoom);
+       }
+
+       public int get_zoom() {
+               return view.zoom();
+       }
+
+       public void set_maptype(int type) {
+               view.set_maptype(type);
+               maptype_combo.setSelectedIndex(type);
+       }
+
+       public void show(AltosState state, AltosListenerState listener_state) {
+               view.show(state, listener_state);
+       }
+
+       public void centre(double lat, double lon) {
+               view.centre(lat, lon);
+       }
+
+       public void centre(AltosState state) {
+               if (!state.gps.locked && state.gps.nsat < 4)
+                       return;
+               centre(state.gps.lat, state.gps.lon);
+       }
+
+       public void add_mark(double lat, double lon, int state) {
+               view.add_mark(lat, lon, state);
+       }
+
+       public void clear_marks() {
+               view.clear_marks();
+       }
+
+       AltosUIMapView  view;
+
+       private GridBagLayout layout = new GridBagLayout();
+
+       JComboBox<String>       maptype_combo;
+
+       public void set_load_params(double lat, double lon, int radius, AltosUIMapTileListener listener) {
+               view.set_load_params(lat, lon, radius, listener);
+       }
+
+       public boolean all_fetched() {
+               return view.all_fetched();
+       }
+
+       public static void prefetch_maps(double lat, double lon) {
+       }
+
+       public String getName() {
+               return "Map";
+       }
+
+       public AltosUIMap() {
+
+               view = new AltosUIMapView();
+
+               view.setPreferredSize(new Dimension(500,500));
+               view.setVisible(true);
+               view.setEnabled(true);
+               view.add_zoom_listener(this);
+
+               GridBagLayout   my_layout = new GridBagLayout();
+
+               setLayout(my_layout);
+
+               GridBagConstraints c = new GridBagConstraints();
+               c.anchor = GridBagConstraints.CENTER;
+               c.fill = GridBagConstraints.BOTH;
+               c.gridx = 0;
+               c.gridy = 0;
+               c.gridwidth = 1;
+               c.gridheight = 10;
+               c.weightx = 1;
+               c.weighty = 1;
+               add(view, c);
+
+               int     y = 0;
+
+               zoom_label = new JLabel("", JLabel.CENTER);
+               set_zoom_label();
+
+               c = new GridBagConstraints();
+               c.anchor = GridBagConstraints.CENTER;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.gridx = 1;
+               c.gridy = y++;
+               c.weightx = 0;
+               c.weighty = 0;
+               add(zoom_label, c);
+
+               JButton zoom_reset = new JButton("0");
+               zoom_reset.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       set_zoom(view.default_zoom);
+                               }
+                       });
+
+               c = new GridBagConstraints();
+               c.anchor = GridBagConstraints.CENTER;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.gridx = 1;
+               c.gridy = y++;
+               c.weightx = 0;
+               c.weighty = 0;
+               add(zoom_reset, c);
+
+               JButton zoom_in = new JButton("+");
+               zoom_in.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       set_zoom(get_zoom() + 1);
+                               }
+                       });
+
+               c = new GridBagConstraints();
+               c.anchor = GridBagConstraints.CENTER;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.gridx = 1;
+               c.gridy = y++;
+               c.weightx = 0;
+               c.weighty = 0;
+               add(zoom_in, c);
+
+               JButton zoom_out = new JButton("-");
+               zoom_out.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       set_zoom(get_zoom() - 1);
+                               }
+                       });
+               c = new GridBagConstraints();
+               c.anchor = GridBagConstraints.CENTER;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.gridx = 1;
+               c.gridy = y++;
+               c.weightx = 0;
+               c.weighty = 0;
+               add(zoom_out, c);
+
+               maptype_combo = new JComboBox<String>(maptype_labels);
+
+               maptype_combo.setEditable(false);
+               maptype_combo.setMaximumRowCount(maptype_combo.getItemCount());
+               maptype_combo.addItemListener(new ItemListener() {
+                               public void itemStateChanged(ItemEvent e) {
+                                       view.set_maptype(maptype_combo.getSelectedIndex());
+                               }
+                       });
+
+               c = new GridBagConstraints();
+               c.anchor = GridBagConstraints.CENTER;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.gridx = 1;
+               c.gridy = y++;
+               c.weightx = 0;
+               c.weighty = 0;
+               add(maptype_combo, c);
+       }
+}
diff --git a/altosuilib/AltosUIMapCache.java b/altosuilib/AltosUIMapCache.java
new file mode 100644 (file)
index 0000000..55311d8
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import javax.swing.*;
+import javax.imageio.ImageIO;
+import java.awt.image.*;
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+
+public class AltosUIMapCache {
+       static final int        success = 0;
+       static final int        loading = 1;
+       static final int        failed = 2;
+       static final int        bad_request = 3;
+       static final int        forbidden = 4;
+
+       static final int        min_cache_size = 9;
+       static final int        max_cache_size = 24;
+
+       private Object          fetch_lock = new Object();
+       private Object          cache_lock = new Object();
+
+       int                     cache_size = min_cache_size;
+
+       AltosUIMapImage[]       images = new AltosUIMapImage[cache_size];
+
+       long                    used;
+
+       public void set_cache_size(int new_size) {
+               if (new_size < min_cache_size)
+                       new_size = min_cache_size;
+               if (new_size > max_cache_size)
+                       new_size = max_cache_size;
+               if (new_size == cache_size)
+                       return;
+
+               synchronized(cache_lock) {
+                       AltosUIMapImage[]       new_images = new AltosUIMapImage[new_size];
+
+                       for (int i = 0; i < cache_size; i++) {
+                               if (i < new_size)
+                                       new_images[i] = images[i];
+                               else if (images[i] != null)
+                                       images[i].flush();
+                       }
+                       images = new_images;
+                       cache_size = new_size;
+               }
+       }
+
+       public Image get(AltosUIMapTile tile, AltosUIMapStore store, int width, int height) {
+               int             oldest = -1;
+               long            age = used;
+
+               synchronized(cache_lock) {
+                       AltosUIMapImage image = null;
+                       for (int i = 0; i < cache_size; i++) {
+                               image = images[i];
+
+                               if (image == null) {
+                                       oldest = i;
+                                       break;
+                               }
+                               if (store.equals(image.store)) {
+                                       image.used = used++;
+                                       return image.image;
+                               }
+                               if (image.used < age) {
+                                       oldest = i;
+                                       age = image.used;
+                               }
+                       }
+
+                       try {
+                               image = new AltosUIMapImage(tile, store);
+                               image.used = used++;
+                               if (images[oldest] != null)
+                                       images[oldest].flush();
+
+                               images[oldest] = image;
+
+                               if (image.image == null)
+                                       tile.set_status(loading);
+                               else
+                                       tile.set_status(success);
+
+                               return image.image;
+                       } catch (IOException e) {
+                               tile.set_status(failed);
+                               return null;
+                       }
+               }
+       }
+
+       public AltosUIMapCache() {
+       }
+}
diff --git a/altosuilib/AltosUIMapImage.java b/altosuilib/AltosUIMapImage.java
new file mode 100644 (file)
index 0000000..3819d07
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import javax.swing.*;
+import javax.imageio.ImageIO;
+import java.awt.image.*;
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+
+public class AltosUIMapImage implements AltosUIMapStoreListener {
+       static final long google_maps_ratelimit_ms = 1200;
+       // Google limits static map queries to 50 per minute per IP, so
+       // each query should take at least 1.2 seconds.
+
+       static final int        success = 0;
+       static final int        loading = 1;
+       static final int        failed = 2;
+       static final int        bad_request = 3;
+       static final int        forbidden = 4;
+
+       static long             forbidden_time;
+       static boolean          forbidden_set = false;
+       static final long       forbidden_interval = 60l * 1000l * 1000l * 1000l;
+
+       AltosUIMapTile          tile;           /* Notify when image has been loaded */
+       Image                   image;
+       AltosUIMapStore         store;
+       long                    used;
+
+       class loader implements Runnable {
+               public void run() {
+                       if (image != null)
+                               tile.notify_image(image);
+                       try {
+                               image = ImageIO.read(store.file);
+                       } catch (Exception ex) {
+                       }
+                       if (image == null)
+                               tile.set_status(failed);
+                       else
+                               tile.set_status(success);
+                       tile.notify_image(image);
+               }
+       }
+
+       private void load() {
+               loader  l = new loader();
+               Thread  lt = new Thread(l);
+               lt.start();
+       }
+
+       public void flush() {
+               if (image != null) {
+                       image.flush();
+                       image = null;
+               }
+       }
+
+       public boolean has_map() {
+               return store.status() == AltosUIMapStore.success;
+       }
+
+       public synchronized void notify_store(AltosUIMapStore store, int status) {
+               switch (status) {
+               case AltosUIMapStore.loading:
+                       break;
+               case AltosUIMapStore.success:
+                       load();
+                       break;
+               default:
+                       tile.set_status(status);
+                       tile.notify_image(null);
+               }
+       }
+
+       public AltosUIMapImage(AltosUIMapTile tile, AltosUIMapStore store) throws IOException {
+               this.tile = tile;
+               this.image = null;
+               this.store = store;
+               this.used = 0;
+
+               int status = store.status();
+               switch (status) {
+               case AltosUIMapStore.loading:
+                       store.add_listener(this);
+                       break;
+               case AltosUIMapStore.success:
+                       load();
+                       break;
+               default:
+                       tile.set_status(status);
+                       tile.notify_image(null);
+                       break;
+               }
+       }
+}
diff --git a/altosuilib/AltosUIMapLine.java b/altosuilib/AltosUIMapLine.java
new file mode 100644 (file)
index 0000000..e09a2d9
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.lang.Math;
+import java.awt.geom.*;
+import java.util.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosUIMapLine {
+       AltosUILatLon   start, end;
+
+       private Font    font = null;
+
+       public void set_font(Font font) {
+               this.font = font;
+       }
+
+       private AltosUILatLon lat_lon(MouseEvent e, AltosUIMapTransform t) {
+               return t.screen_lat_lon(e.getPoint());
+       }
+
+       public void dragged(MouseEvent e, AltosUIMapTransform t) {
+               end = lat_lon(e, t);
+       }
+
+       public void pressed(MouseEvent e, AltosUIMapTransform t) {
+               start = lat_lon(e, t);
+               end = null;
+       }
+
+       private String line_dist() {
+               String  format;
+               AltosGreatCircle        g = new AltosGreatCircle(start.lat, start.lon,
+                                                                end.lat, end.lon);
+               double  distance = g.distance;
+
+               if (AltosConvert.imperial_units) {
+                       distance = AltosConvert.meters_to_feet(distance);
+                       if (distance < 10000) {
+                               format = "%4.0fft";
+                       } else {
+                               distance /= 5280;
+                               if (distance < 10)
+                                       format = "%5.3fmi";
+                               else if (distance < 100)
+                                       format = "%5.2fmi";
+                               else if (distance < 1000)
+                                       format = "%5.1fmi";
+                               else
+                                       format = "%5.0fmi";
+                       }
+               } else {
+                       if (distance < 10000) {
+                               format = "%4.0fm";
+                       } else {
+                               distance /= 1000;
+                               if (distance < 100)
+                                       format = "%5.2fkm";
+                               else if (distance < 1000)
+                                       format = "%5.1fkm";
+                               else
+                                       format = "%5.0fkm";
+                       }
+               }
+               return String.format(format, distance);
+       }
+
+       public void paint(Graphics2D g, AltosUIMapTransform t) {
+               g.setColor(Color.BLUE);
+
+               if (start == null || end == null)
+                       return;
+
+               Line2D.Double line = new Line2D.Double(t.screen(start),
+                                                      t.screen(end));
+
+               g.draw(line);
+
+               String  message = line_dist();
+               g.setFont(font);
+               g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+               Rectangle2D     bounds;
+               bounds = font.getStringBounds(message, g.getFontRenderContext());
+
+               float x = (float) line.x1;
+               float y = (float) line.y1 + (float) bounds.getHeight() / 2.0f;
+
+               if (line.x1 < line.x2) {
+                       x -= (float) bounds.getWidth() + 2.0f;
+               } else {
+                       x += 2.0f;
+               }
+               g.drawString(message, x, y);
+       }
+}
diff --git a/altosuilib/AltosUIMapMark.java b/altosuilib/AltosUIMapMark.java
new file mode 100644 (file)
index 0000000..8c640e5
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.lang.Math;
+import java.awt.geom.*;
+import java.util.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosUIMapMark {
+
+       AltosUILatLon   lat_lon;
+       int             state;
+
+       static public int stroke_width = 6;
+
+       public void paint(Graphics2D g, AltosUIMapTransform t) {
+
+               Point2D.Double pt = t.screen(lat_lon);
+
+               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                                  RenderingHints.VALUE_ANTIALIAS_ON);
+               g.setStroke(new BasicStroke(stroke_width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+
+               if (0 <= state && state < AltosUIMap.stateColors.length)
+                       g.setColor(AltosUIMap.stateColors[state]);
+               else
+                       g.setColor(AltosUIMap.stateColors[AltosLib.ao_flight_invalid]);
+
+               g.drawOval((int)pt.x-5, (int)pt.y-5, 10, 10);
+               g.drawOval((int)pt.x-20, (int)pt.y-20, 40, 40);
+               g.drawOval((int)pt.x-35, (int)pt.y-35, 70, 70);
+       }
+
+       public AltosUIMapMark (double lat, double lon, int state) {
+               lat_lon = new AltosUILatLon(lat, lon);
+               this.state = state;
+       }
+}
diff --git a/altosuilib/AltosUIMapPath.java b/altosuilib/AltosUIMapPath.java
new file mode 100644 (file)
index 0000000..ff17be6
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.lang.Math;
+import java.awt.geom.*;
+import java.util.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+class PathPoint {
+       AltosUILatLon   lat_lon;
+       int             state;
+
+       public PathPoint(AltosUILatLon lat_lon, int state) {
+               this.lat_lon = lat_lon;
+               this.state = state;
+       }
+
+       public boolean equals(PathPoint other) {
+               if (other == null)
+                       return false;
+
+               return lat_lon.equals(other.lat_lon) && state == other.state;
+       }
+}
+
+public class AltosUIMapPath {
+
+       LinkedList<PathPoint>   points = new LinkedList<PathPoint>();
+       PathPoint               last_point = null;
+
+       static public int stroke_width = 6;
+
+       public void paint(Graphics2D g, AltosUIMapTransform t) {
+               Point2D.Double  prev = null;
+
+               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                                  RenderingHints.VALUE_ANTIALIAS_ON);
+               g.setStroke(new BasicStroke(stroke_width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+
+               for (PathPoint point : points) {
+                       Point2D.Double  cur = t.screen(point.lat_lon);
+                       if (prev != null) {
+                               Line2D.Double   line = new Line2D.Double (prev, cur);
+                               Rectangle       bounds = line.getBounds();
+
+                               if (g.hitClip(bounds.x, bounds.y, bounds.width, bounds.height)) {
+                                       if (0 <= point.state && point.state < AltosUIMap.stateColors.length)
+                                               g.setColor(AltosUIMap.stateColors[point.state]);
+                                       else
+                                               g.setColor(AltosUIMap.stateColors[AltosLib.ao_flight_invalid]);
+
+                                       g.draw(line);
+                               }
+                       }
+                       prev = cur;
+               }
+       }
+
+       public AltosUIMapRectangle add(double lat, double lon, int state) {
+               PathPoint               point = new PathPoint(new AltosUILatLon (lat, lon), state);
+               AltosUIMapRectangle     rect = null;
+
+               if (!point.equals(last_point)) {
+                       if (last_point != null)
+                               rect = new AltosUIMapRectangle(last_point.lat_lon, point.lat_lon);
+                       points.add (point);
+                       last_point = point;
+               }
+               return rect;
+       }
+
+       public void clear () {
+               points = new LinkedList<PathPoint>();
+       }
+}
diff --git a/altosuilib/AltosUIMapPreload.java b/altosuilib/AltosUIMapPreload.java
new file mode 100644 (file)
index 0000000..56066d7
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ * 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+import java.lang.Math;
+import java.net.URL;
+import java.net.URLConnection;
+import org.altusmetrum.altoslib_4.*;
+
+class AltosUIMapPos extends Box {
+       AltosUIFrame    owner;
+       JLabel          label;
+       JComboBox       hemi;
+       JTextField      deg;
+       JLabel          deg_label;
+       JTextField      min;
+       JLabel          min_label;
+
+       public void set_value(double new_value) {
+               double  d, m;
+               int     h;
+
+               h = 0;
+               if (new_value < 0) {
+                       h = 1;
+                       new_value = -new_value;
+               }
+               d = Math.floor(new_value);
+               deg.setText(String.format("%3.0f", d));
+               m = (new_value - d) * 60.0;
+               min.setText(String.format("%7.4f", m));
+               hemi.setSelectedIndex(h);
+       }
+
+       public double get_value() throws NumberFormatException {
+               int     h = hemi.getSelectedIndex();
+               String  d_t = deg.getText();
+               String  m_t = min.getText();
+               double  d, m, v;
+               try {
+                       d = Double.parseDouble(d_t);
+               } catch (NumberFormatException ne) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     String.format("Invalid degrees \"%s\"",
+                                                                   d_t),
+                                                     "Invalid number",
+                                                     JOptionPane.ERROR_MESSAGE);
+                       throw ne;
+               }
+               try {
+                       if (m_t.equals(""))
+                               m = 0;
+                       else
+                               m = Double.parseDouble(m_t);
+               } catch (NumberFormatException ne) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     String.format("Invalid minutes \"%s\"",
+                                                                   m_t),
+                                                     "Invalid number",
+                                                     JOptionPane.ERROR_MESSAGE);
+                       throw ne;
+               }
+               v = d + m/60.0;
+               if (h == 1)
+                       v = -v;
+               return v;
+       }
+
+       public AltosUIMapPos(AltosUIFrame in_owner,
+                          String label_value,
+                          String[] hemi_names,
+                          double default_value) {
+               super(BoxLayout.X_AXIS);
+               owner = in_owner;
+               label = new JLabel(label_value);
+               hemi = new JComboBox<String>(hemi_names);
+               hemi.setEditable(false);
+               deg = new JTextField(5);
+               deg.setMinimumSize(deg.getPreferredSize());
+               deg.setHorizontalAlignment(JTextField.RIGHT);
+               deg_label = new JLabel("°");
+               min = new JTextField(9);
+               min.setMinimumSize(min.getPreferredSize());
+               min_label = new JLabel("'");
+               set_value(default_value);
+               add(label);
+               add(Box.createRigidArea(new Dimension(5, 0)));
+               add(hemi);
+               add(Box.createRigidArea(new Dimension(5, 0)));
+               add(deg);
+               add(Box.createRigidArea(new Dimension(5, 0)));
+               add(deg_label);
+               add(Box.createRigidArea(new Dimension(5, 0)));
+               add(min);
+               add(Box.createRigidArea(new Dimension(5, 0)));
+               add(min_label);
+       }
+}
+
+class AltosUISite {
+       String  name;
+       double  latitude;
+       double  longitude;
+
+       public String toString() {
+               return name;
+       }
+
+       public AltosUISite(String in_name, double in_latitude, double in_longitude) {
+               name = in_name;
+               latitude = in_latitude;
+               longitude = in_longitude;
+       }
+
+       public AltosUISite(String line) throws ParseException {
+               String[]        elements = line.split(":");
+
+               if (elements.length < 3)
+                       throw new ParseException(String.format("Invalid site line %s", line), 0);
+
+               name = elements[0];
+
+               try {
+                       latitude = Double.parseDouble(elements[1]);
+                       longitude = Double.parseDouble(elements[2]);
+               } catch (NumberFormatException ne) {
+                       throw new ParseException(String.format("Invalid site line %s", line), 0);
+               }
+       }
+}
+
+class AltosUISites extends Thread {
+       AltosUIMapPreload       preload;
+       URL                     url;
+       LinkedList<AltosUISite> sites;
+
+       void notify_complete() {
+               SwingUtilities.invokeLater(new Runnable() {
+                               public void run() {
+                                       preload.set_sites();
+                               }
+                       });
+       }
+
+       void add(AltosUISite site) {
+               sites.add(site);
+       }
+
+       void add(String line) {
+               try {
+                       add(new AltosUISite(line));
+               } catch (ParseException pe) {
+               }
+       }
+
+       public void run() {
+               try {
+                       URLConnection uc = url.openConnection();
+                       //int length = uc.getContentLength();
+
+                       InputStreamReader in_stream = new InputStreamReader(uc.getInputStream(), AltosLib.unicode_set);
+                       BufferedReader in = new BufferedReader(in_stream);
+
+                       for (;;) {
+                               String line = in.readLine();
+                               if (line == null)
+                                       break;
+                               add(line);
+                       }
+               } catch (IOException e) {
+               } finally {
+                       notify_complete();
+               }
+       }
+
+       public AltosUISites(AltosUIMapPreload in_preload) {
+               sites = new LinkedList<AltosUISite>();
+               preload = in_preload;
+               try {
+                       url = new URL(AltosLib.launch_sites_url);
+               } catch (java.net.MalformedURLException e) {
+                       notify_complete();
+               }
+               start();
+       }
+}
+
+public class AltosUIMapPreload extends AltosUIFrame implements ActionListener, ItemListener, AltosUIMapTileListener {
+       AltosUIFrame    owner;
+       AltosUIMap      map;
+       AltosUIMapCache cache = new AltosUIMapCache();
+
+       AltosUIMapPos   lat;
+       AltosUIMapPos   lon;
+
+       JProgressBar    pbar;
+       int             pbar_max;
+       int             pbar_cur;
+
+       AltosUISites    sites;
+       JLabel          site_list_label;
+       JComboBox<AltosUISite>  site_list;
+
+       JToggleButton   load_button;
+       boolean         loading;
+       JButton         close_button;
+
+       JCheckBox[]     maptypes = new JCheckBox[AltosUIMap.maptype_terrain - AltosUIMap.maptype_hybrid + 1];
+
+       JComboBox<Integer>      min_zoom;
+       JComboBox<Integer>      max_zoom;
+       JComboBox<Integer>      radius;
+
+       Integer[]               zooms = { -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6 };
+       Integer[]               radii = { 1, 2, 3, 4, 5 };
+
+       static final String[]   lat_hemi_names = { "N", "S" };
+       static final String[]   lon_hemi_names = { "E", "W" };
+
+       class updatePbar implements Runnable {
+               String          s;
+
+               public updatePbar(String in_s) {
+                       s = in_s;
+               }
+
+               public void run() {
+                       int     n = ++pbar_cur;
+
+                       pbar.setMaximum(pbar_max);
+                       pbar.setValue(n);
+                       pbar.setString(s);
+               }
+       }
+
+       double  latitude, longitude;
+       int     min_z;
+       int     max_z;
+       int     cur_z;
+       int     all_types;
+       int     cur_type;
+       int     r;
+
+       int     tiles_per_layer;
+       int     tiles_loaded;
+       int     layers_total;
+       int     layers_loaded;
+
+
+       private void do_load() {
+               tiles_loaded = 0;
+               map.set_zoom(cur_z + AltosUIMapView.default_zoom);
+               map.set_maptype(cur_type);
+               map.set_load_params(latitude, longitude, r, this);
+       }
+
+       private int next_type(int start) {
+               int next_type;
+               for (next_type = start;
+                    next_type <= AltosUIMap.maptype_terrain && (all_types & (1 << next_type)) == 0;
+                    next_type++)
+                       ;
+               return next_type;
+       }
+
+       private void next_load() {
+               int next_type = next_type(cur_type + 1);
+
+               if (next_type > AltosUIMap.maptype_terrain) {
+                       if (cur_z == max_z) {
+                               return;
+                       } else {
+                               cur_z++;
+                       }
+                       next_type = next_type(0);
+               }
+               cur_type = next_type;
+               do_load();
+       }
+
+       private void start_load() {
+               cur_z = min_z;
+               int ntype = 0;
+               all_types = 0;
+               for (int t = AltosUIMap.maptype_hybrid; t <= AltosUIMap.maptype_terrain; t++)
+                       if (maptypes[t].isSelected()) {
+                               all_types |= (1 << t);
+                               ntype++;
+                       }
+               if (ntype == 0) {
+                       all_types |= (1 << AltosUIMap.maptype_hybrid);
+                       ntype = 1;
+               }
+
+               cur_type = next_type(0);
+               tiles_per_layer = (r * 2 + 1) * (r * 2 + 1);
+               layers_total = (max_z - min_z + 1) * ntype;
+               layers_loaded = 0;
+               pbar_max = layers_total * tiles_per_layer;
+               pbar_cur = 0;
+
+               map.clear_marks();
+               map.add_mark(latitude,longitude, AltosLib.ao_flight_boost);
+               do_load();
+       }
+
+       /* AltosUIMapTileListener methods */
+
+       public synchronized void notify_tile(AltosUIMapTile tile, int status) {
+               if (status == AltosUIMapStore.loading)
+                       return;
+
+               SwingUtilities.invokeLater(new updatePbar(tile.store.file.toString()));
+               ++tiles_loaded;
+               if (tiles_loaded == tiles_per_layer) {
+                       ++layers_loaded;
+                       if (layers_loaded == layers_total) {
+                               SwingUtilities.invokeLater(new Runnable() {
+                                               public void run() {
+                                                       pbar.setValue(0);
+                                                       pbar.setString("");
+                                                       load_button.setSelected(false);
+                                                       loading = false;
+                                               }
+                                       });
+                       } else {
+                               SwingUtilities.invokeLater(new Runnable() {
+                                               public void run() {
+                                                       next_load();
+                                               }
+                                       });
+                       }
+               }
+       }
+
+       public AltosUIMapCache cache() { return cache; }
+
+       public void set_sites() {
+               int     i = 1;
+               for (AltosUISite site : sites.sites) {
+                       site_list.insertItemAt(site, i);
+                       i++;
+               }
+       }
+
+       public void itemStateChanged(ItemEvent e) {
+               int             state = e.getStateChange();
+
+               if (state == ItemEvent.SELECTED) {
+                       Object  o = e.getItem();
+                       if (o instanceof AltosUISite) {
+                               AltosUISite     site = (AltosUISite) o;
+                               lat.set_value(site.latitude);
+                               lon.set_value(site.longitude);
+                       }
+               }
+       }
+
+       public void actionPerformed(ActionEvent e) {
+               String  cmd = e.getActionCommand();
+
+               if (cmd.equals("close"))
+                       setVisible(false);
+
+               if (cmd.equals("load")) {
+                       if (!loading) {
+                               try {
+                                       latitude = lat.get_value();
+                                       longitude = lon.get_value();
+                                       min_z = (Integer) min_zoom.getSelectedItem();
+                                       max_z = (Integer) max_zoom.getSelectedItem();
+                                       if (max_z < min_z)
+                                               max_z = min_z;
+                                       r = (Integer) radius.getSelectedItem();
+                                       loading = true;
+                               } catch (NumberFormatException ne) {
+                                       load_button.setSelected(false);
+                               }
+                               start_load();
+                       }
+               }
+       }
+
+       public AltosUIMapPreload(AltosUIFrame in_owner) {
+               owner = in_owner;
+
+               Container               pane = getContentPane();
+               GridBagConstraints      c = new GridBagConstraints();
+               Insets                  i = new Insets(4,4,4,4);
+
+               setTitle("AltOS Load Maps");
+
+               pane.setLayout(new GridBagLayout());
+
+               map = new AltosUIMap();
+
+               c.fill = GridBagConstraints.BOTH;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 1;
+               c.weighty = 1;
+
+               c.gridx = 0;
+               c.gridy = 0;
+               c.gridwidth = 10;
+               c.anchor = GridBagConstraints.CENTER;
+
+               pane.add(map, c);
+
+               pbar = new JProgressBar();
+               pbar.setMinimum(0);
+               pbar.setMaximum(1);
+               pbar.setValue(0);
+               pbar.setString("");
+               pbar.setStringPainted(true);
+
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 1;
+               c.weighty = 0;
+
+               c.gridx = 0;
+               c.gridy = 1;
+               c.gridwidth = 10;
+
+               pane.add(pbar, c);
+
+               site_list_label = new JLabel ("Known Launch Sites:");
+
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 1;
+               c.weighty = 0;
+
+               c.gridx = 0;
+               c.gridy = 2;
+               c.gridwidth = 1;
+
+               pane.add(site_list_label, c);
+
+               site_list = new JComboBox<AltosUISite>(new AltosUISite[] { new AltosUISite("Site List", 0, 0) });
+               site_list.addItemListener(this);
+
+               sites = new AltosUISites(this);
+
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 1;
+               c.weighty = 0;
+
+               c.gridx = 1;
+               c.gridy = 2;
+               c.gridwidth = 1;
+
+               pane.add(site_list, c);
+
+               lat = new AltosUIMapPos(owner,
+                                       "Latitude:",
+                                       lat_hemi_names,
+                                       37.167833333);
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 0;
+               c.weighty = 0;
+
+               c.gridx = 0;
+               c.gridy = 3;
+               c.gridwidth = 1;
+               c.anchor = GridBagConstraints.CENTER;
+
+               pane.add(lat, c);
+
+               lon = new AltosUIMapPos(owner,
+                                       "Longitude:",
+                                       lon_hemi_names,
+                                       -97.73975);
+
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 0;
+               c.weighty = 0;
+
+               c.gridx = 1;
+               c.gridy = 3;
+               c.gridwidth = 1;
+               c.anchor = GridBagConstraints.CENTER;
+
+               pane.add(lon, c);
+
+               load_button = new JToggleButton("Load Map");
+               load_button.addActionListener(this);
+               load_button.setActionCommand("load");
+
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 1;
+               c.weighty = 0;
+
+               c.gridx = 0;
+               c.gridy = 4;
+               c.gridwidth = 1;
+               c.anchor = GridBagConstraints.CENTER;
+
+               pane.add(load_button, c);
+
+               close_button = new JButton("Close");
+               close_button.addActionListener(this);
+               close_button.setActionCommand("close");
+
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = i;
+               c.weightx = 1;
+               c.weighty = 0;
+
+               c.gridx = 1;
+               c.gridy = 4;
+               c.gridwidth = 1;
+               c.anchor = GridBagConstraints.CENTER;
+
+               pane.add(close_button, c);
+
+               JLabel  types_label = new JLabel("Map Types");
+               c.gridx = 2;
+               c.gridwidth = 2;
+               c.gridy = 2;
+               pane.add(types_label, c);
+
+               c.gridwidth = 1;
+
+               for (int type = AltosUIMap.maptype_hybrid; type <= AltosUIMap.maptype_terrain; type++) {
+                       maptypes[type] = new JCheckBox(AltosUIMap.maptype_labels[type],
+                                                      type == AltosUIMap.maptype_hybrid);
+                       c.gridx = 2 + (type >> 1);
+                       c.fill = GridBagConstraints.HORIZONTAL;
+                       c.gridy = (type & 1) + 3;
+                       pane.add(maptypes[type], c);
+               }
+
+               JLabel  min_zoom_label = new JLabel("Minimum Zoom");
+               c.gridx = 4;
+               c.gridy = 2;
+               pane.add(min_zoom_label, c);
+
+               min_zoom = new JComboBox<Integer>(zooms);
+               min_zoom.setSelectedItem(zooms[10]);
+               min_zoom.setEditable(false);
+               c.gridx = 5;
+               c.gridy = 2;
+               pane.add(min_zoom, c);
+
+               JLabel  max_zoom_label = new JLabel("Maximum Zoom");
+               c.gridx = 4;
+               c.gridy = 3;
+               pane.add(max_zoom_label, c);
+
+               max_zoom = new JComboBox<Integer>(zooms);
+               max_zoom.setSelectedItem(zooms[14]);
+               max_zoom.setEditable(false);
+               c.gridx = 5;
+               c.gridy = 3;
+               pane.add(max_zoom, c);
+
+               JLabel radius_label = new JLabel("Tile Radius");
+               c.gridx = 4;
+               c.gridy = 4;
+               pane.add(radius_label, c);
+
+               radius = new JComboBox<Integer>(radii);
+               radius.setSelectedItem(radii[4]);
+               radius.setEditable(true);
+               c.gridx = 5;
+               c.gridy = 4;
+               pane.add(radius, c);
+
+               pack();
+               setLocationRelativeTo(owner);
+               setVisible(true);
+       }
+}
diff --git a/altosuilib/AltosUIMapRectangle.java b/altosuilib/AltosUIMapRectangle.java
new file mode 100644 (file)
index 0000000..8a5b16e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+public class AltosUIMapRectangle {
+       AltosUILatLon   ul, lr;
+
+       public AltosUIMapRectangle(AltosUILatLon a, AltosUILatLon b) {
+               double  ul_lat, ul_lon;
+               double  lr_lat, lr_lon;
+
+               if (a.lat > b.lat) {
+                       ul_lat = a.lat;
+                       lr_lat = b.lat;
+               } else {
+                       ul_lat = b.lat;
+                       lr_lat = a.lat;
+               }
+               if (a.lon < b.lon) {
+                       ul_lon = a.lon;
+                       lr_lon = b.lon;
+               } else {
+                       ul_lon = b.lon;
+                       lr_lon = a.lon;
+               }
+
+               ul = new AltosUILatLon(ul_lat, ul_lon);
+               lr = new AltosUILatLon(lr_lat, lr_lon);
+       }
+}
diff --git a/altosuilib/AltosUIMapStore.java b/altosuilib/AltosUIMapStore.java
new file mode 100644 (file)
index 0000000..4cecb54
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+public class AltosUIMapStore {
+       String                                  url;
+       File                                    file;
+       LinkedList<AltosUIMapStoreListener>     listeners = new LinkedList<AltosUIMapStoreListener>();
+
+       static final int                        success = 0;
+       static final int                        loading = 1;
+       static final int                        failed = 2;
+       static final int                        bad_request = 3;
+       static final int                        forbidden = 4;
+
+       int                                     status;
+
+       public int status() {
+               return status;
+       }
+
+       public synchronized void add_listener(AltosUIMapStoreListener listener) {
+               if (!listeners.contains(listener))
+                       listeners.add(listener);
+       }
+
+       public synchronized void remove_listener(AltosUIMapStoreListener listener) {
+               listeners.remove(listener);
+       }
+
+       private synchronized void notify_listeners(int status) {
+               this.status = status;
+               for (AltosUIMapStoreListener listener : listeners)
+                       listener.notify_store(this, status);
+       }
+
+       static Object   forbidden_lock = new Object();
+       static long     forbidden_time;
+       static boolean  forbidden_set;
+
+       private int fetch_url() {
+               URL u;
+
+               try {
+                       u = new URL(url);
+               } catch (java.net.MalformedURLException e) {
+                       return bad_request;
+               }
+
+               byte[] data;
+               URLConnection uc = null;
+               try {
+                       uc = u.openConnection();
+                       String type = uc.getContentType();
+                       int contentLength = uc.getContentLength();
+                       if (uc instanceof HttpURLConnection) {
+                               int response = ((HttpURLConnection) uc).getResponseCode();
+                               switch (response) {
+                               case HttpURLConnection.HTTP_FORBIDDEN:
+                               case HttpURLConnection.HTTP_PAYMENT_REQUIRED:
+                               case HttpURLConnection.HTTP_UNAUTHORIZED:
+                                       synchronized (forbidden_lock) {
+                                               forbidden_time = System.nanoTime();
+                                               forbidden_set = true;
+                                               return forbidden;
+                                       }
+                               }
+                       }
+                       InputStream in = new BufferedInputStream(uc.getInputStream());
+                       int bytesRead = 0;
+                       int offset = 0;
+                       data = new byte[contentLength];
+                       while (offset < contentLength) {
+                               bytesRead = in.read(data, offset, data.length - offset);
+                               if (bytesRead == -1)
+                                       break;
+                               offset += bytesRead;
+                       }
+                       in.close();
+
+                       if (offset != contentLength)
+                               return failed;
+
+               } catch (IOException e) {
+                       return failed;
+               }
+
+               try {
+                       FileOutputStream out = new FileOutputStream(file);
+                       out.write(data);
+                       out.flush();
+                       out.close();
+               } catch (FileNotFoundException e) {
+                       return bad_request;
+               } catch (IOException e) {
+                       if (file.exists())
+                               file.delete();
+                       return bad_request;
+               }
+               return success;
+       }
+
+       static Object   fetch_lock = new Object();
+
+       static final long       forbidden_interval = 60l * 1000l * 1000l * 1000l;
+       static final long       google_maps_ratelimit_ms = 1200;
+
+       class loader implements Runnable {
+
+               public void run() {
+                       if (file.exists()) {
+                               notify_listeners(success);
+                               return;
+                       }
+
+                       synchronized(forbidden_lock) {
+                               if (forbidden_set && (System.nanoTime() - forbidden_time) < forbidden_interval) {
+                                       notify_listeners(forbidden);
+                                       return;
+                               }
+                       }
+
+                       int new_status;
+
+                       if (!AltosUIVersion.has_google_maps_api_key()) {
+                               synchronized (fetch_lock) {
+                                       long startTime = System.nanoTime();
+                                       new_status = fetch_url();
+                                       if (new_status == success) {
+                                               long duration_ms = (System.nanoTime() - startTime) / 1000000;
+                                               if (duration_ms < google_maps_ratelimit_ms) {
+                                                       try {
+                                                               Thread.sleep(google_maps_ratelimit_ms - duration_ms);
+                                                       } catch (InterruptedException e) {
+                                                               Thread.currentThread().interrupt();
+                                                       }
+                                               }
+                                       }
+                               }
+                       } else {
+                               new_status = fetch_url();
+                       }
+                       notify_listeners(new_status);
+               }
+       }
+
+       private void load() {
+               loader  l = new loader();
+               Thread  lt = new Thread(l);
+               lt.start();
+       }
+
+       private AltosUIMapStore (String url, File file) {
+               this.url = url;
+               this.file = file;
+
+               if (file.exists())
+                       status = success;
+               else {
+                       status = loading;
+                       load();
+               }
+       }
+
+       public boolean equals(AltosUIMapStore other) {
+               return url.equals(other.url);
+       }
+
+       static HashMap<String,AltosUIMapStore> stores = new HashMap<String,AltosUIMapStore>();
+
+       public static AltosUIMapStore get(String url, File file) {
+               AltosUIMapStore store;
+               synchronized(stores) {
+                       if (stores.containsKey(url)) {
+                               store = stores.get(url);
+                       } else {
+                               store = new AltosUIMapStore(url, file);
+                               stores.put(url, store);
+                       }
+               }
+               return store;
+       }
+
+}
diff --git a/altosuilib/AltosUIMapStoreListener.java b/altosuilib/AltosUIMapStoreListener.java
new file mode 100644 (file)
index 0000000..91aff00
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+public interface AltosUIMapStoreListener {
+       abstract void notify_store(AltosUIMapStore store, int status);
+}
diff --git a/altosuilib/AltosUIMapTile.java b/altosuilib/AltosUIMapTile.java
new file mode 100644 (file)
index 0000000..7c82318
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.image.*;
+import javax.swing.*;
+import javax.imageio.*;
+import java.awt.geom.*;
+import java.io.*;
+import java.util.*;
+import java.awt.RenderingHints.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosUIMapTile {
+       AltosUIMapTileListener  listener;
+       AltosUILatLon   upper_left, center;
+       int             px_size;
+       int             zoom;
+       int             maptype;
+       AltosUIMapStore store;
+       AltosUIMapCache cache;
+       int             status;
+
+       private File map_file() {
+               double lat = center.lat;
+               double lon = center.lon;
+               char chlat = lat < 0 ? 'S' : 'N';
+               char chlon = lon < 0 ? 'W' : 'E';
+
+               if (lat < 0) lat = -lat;
+               if (lon < 0) lon = -lon;
+               String maptype_string = String.format("%s-", AltosUIMap.maptype_names[maptype]);
+               String format_string;
+               if (maptype == AltosUIMap.maptype_hybrid || maptype == AltosUIMap.maptype_satellite || maptype == AltosUIMap.maptype_terrain)
+                       format_string = "jpg";
+               else
+                       format_string = "png";
+               return new File(AltosUIPreferences.mapdir(),
+                               String.format("map-%c%.6f,%c%.6f-%s%d.%s",
+                                             chlat, lat, chlon, lon, maptype_string, zoom, format_string));
+       }
+
+       private String map_url() {
+               String format_string;
+               if (maptype == AltosUIMap.maptype_hybrid || maptype == AltosUIMap.maptype_satellite || maptype == AltosUIMap.maptype_terrain)
+                       format_string = "jpg";
+               else
+                       format_string = "png32";
+
+               if (AltosUIVersion.has_google_maps_api_key())
+                       return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=%s&format=%s&key=%s",
+                                            center.lat, center.lon, zoom, px_size, px_size, AltosUIMap.maptype_names[maptype], format_string, AltosUIVersion.google_maps_api_key);
+               else
+                       return String.format("http://maps.google.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&sensor=false&maptype=%s&format=%s",
+                                            center.lat, center.lon, zoom, px_size, px_size, AltosUIMap.maptype_names[maptype], format_string);
+       }
+       private Font    font = null;
+
+       public void set_font(Font font) {
+               this.font = font;
+       }
+
+       int     painting_serial;
+       int     painted_serial;
+
+       Image   image;
+
+       public void paint_graphics(Graphics2D g2d, AltosUIMapTransform t, int serial) {
+               if (serial < painted_serial)
+                       return;
+
+               Point2D.Double  point_double = t.screen(upper_left);
+               Point           point = new Point((int) (point_double.x + 0.5),
+                                                 (int) (point_double.y + 0.5));
+
+               painted_serial = serial;
+
+               if (!g2d.hitClip(point.x, point.y, px_size, px_size))
+                       return;
+
+               if (image != null) {
+                       g2d.drawImage(image, point.x, point.y, null);
+                       image = null;
+               } else {
+                       g2d.setColor(Color.GRAY);
+                       g2d.fillRect(point.x, point.y, px_size, px_size);
+
+                       if (t.has_location()) {
+                               String  message = null;
+                               switch (status) {
+                               case AltosUIMapCache.loading:
+                                       message = "Loading...";
+                                       break;
+                               case AltosUIMapCache.bad_request:
+                                       message = "Internal error";
+                                       break;
+                               case AltosUIMapCache.failed:
+                                       message = "Network error, check connection";
+                                       break;
+                               case AltosUIMapCache.forbidden:
+                                       message = "Too many requests, try later";
+                                       break;
+                               }
+                               if (message != null && font != null) {
+                                       g2d.setFont(font);
+                                       g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+                                       Rectangle2D bounds = font.getStringBounds(message, g2d.getFontRenderContext());
+
+                                       float x = px_size / 2.0f;
+                                       float y = px_size / 2.0f;
+                                       x = x - (float) bounds.getWidth() / 2.0f;
+                                       y = y + (float) bounds.getHeight() / 2.0f;
+                                       g2d.setColor(Color.BLACK);
+                                       g2d.drawString(message, (float) point_double.x + x, (float) point_double.y + y);
+                               }
+                       }
+               }
+       }
+
+       public void set_status(int status) {
+               this.status = status;
+               listener.notify_tile(this, status);
+       }
+
+       public void notify_image(Image image) {
+               listener.notify_tile(this, status);
+       }
+
+       public void paint(Graphics g, AltosUIMapTransform t) {
+               Graphics2D              g2d = (Graphics2D) g;
+               boolean                 queued = false;
+
+               Point2D.Double  point = t.screen(upper_left);
+
+               if (!g.hitClip((int) (point.x + 0.5), (int) (point.y + 0.5), px_size, px_size))
+                       return;
+
+               ++painting_serial;
+
+               if (image == null && t.has_location())
+                       image = cache.get(this, store, px_size, px_size);
+
+               paint_graphics(g2d, t, painting_serial);
+       }
+
+       public int store_status() {
+               return store.status();
+       }
+
+       public void add_store_listener(AltosUIMapStoreListener listener) {
+               store.add_listener(listener);
+       }
+
+       public void remove_store_listener(AltosUIMapStoreListener listener) {
+               store.remove_listener(listener);
+       }
+
+       public AltosUIMapTile(AltosUIMapTileListener listener, AltosUILatLon upper_left, AltosUILatLon center, int zoom, int maptype, int px_size, Font font) {
+               this.listener = listener;
+               this.upper_left = upper_left;
+               cache = listener.cache();
+
+               while (center.lon < -180.0)
+                       center.lon += 360.0;
+               while (center.lon > 180.0)
+                       center.lon -= 360.0;
+
+               this.center = center;
+               this.zoom = zoom;
+               this.maptype = maptype;
+               this.px_size = px_size;
+               this.font = font;
+               status = AltosUIMapCache.loading;
+               store = AltosUIMapStore.get(map_url(), map_file());
+       }
+}
diff --git a/altosuilib/AltosUIMapTileListener.java b/altosuilib/AltosUIMapTileListener.java
new file mode 100644 (file)
index 0000000..4ca1353
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+public interface AltosUIMapTileListener {
+       abstract public void notify_tile(AltosUIMapTile tile, int status);
+
+       abstract public AltosUIMapCache cache();
+}
diff --git a/altosuilib/AltosUIMapTransform.java b/altosuilib/AltosUIMapTransform.java
new file mode 100644 (file)
index 0000000..e6f1ffe
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.lang.Math;
+import java.awt.geom.*;
+import java.util.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosUIMapTransform {
+
+       double  scale_x, scale_y;
+
+       double  offset_x, offset_y;
+
+       public AltosUILatLon lat_lon (Point2D.Double point) {
+               double lat, lon;
+               double rads;
+
+               lon = point.x/scale_x;
+               rads = 2 * Math.atan(Math.exp(-point.y/scale_y));
+               lat = Math.toDegrees(rads - Math.PI/2);
+
+               return new AltosUILatLon(lat,lon);
+       }
+
+       public Point2D.Double screen_point(Point screen) {
+               return new Point2D.Double(screen.x + offset_x, screen.y + offset_y);
+       }
+
+       public AltosUILatLon screen_lat_lon(Point screen) {
+               return lat_lon(screen_point(screen));
+       }
+
+       public Point2D.Double point(AltosUILatLon lat_lon) {
+               double x, y;
+               double e;
+
+               x = lat_lon.lon * scale_x;
+
+               e = Math.sin(Math.toRadians(lat_lon.lat));
+               e = Math.max(e,-(1-1.0E-15));
+               e = Math.min(e,  1-1.0E-15 );
+
+               y = 0.5*Math.log((1+e)/(1-e))*-scale_y;
+
+               return new Point2D.Double(x, y);
+       }
+
+       public Point2D.Double screen(Point2D.Double point) {
+               return new Point2D.Double(point.x - offset_x, point.y - offset_y);
+       }
+
+       public Point screen(Point point) {
+               return new Point((int) (point.x - offset_x + 0.5),
+                                (int) (point.y - offset_y + 0.5));
+       }
+
+       public Rectangle screen(AltosUIMapRectangle map_rect) {
+               Point2D.Double  ul = screen(map_rect.ul);
+               Point2D.Double  lr = screen(map_rect.lr);
+
+               return new Rectangle((int) ul.x, (int) ul.y, (int) (lr.x - ul.x), (int) (lr.y - ul.y));
+       }
+
+       public Point2D.Double screen(AltosUILatLon lat_lon) {
+               return screen(point(lat_lon));
+       }
+
+       private boolean has_location;
+
+       public boolean has_location() {
+               return has_location;
+       }
+
+       public AltosUIMapTransform(int width, int height, int zoom, AltosUILatLon centre_lat_lon) {
+               scale_x = 256/360.0 * Math.pow(2, zoom);
+               scale_y = 256/(2.0*Math.PI) * Math.pow(2, zoom);
+
+               Point2D.Double centre_pt = point(centre_lat_lon);
+
+               has_location = (centre_lat_lon.lat != 0 || centre_lat_lon.lon != 0);
+               offset_x = centre_pt.x - width / 2.0;
+               offset_y = centre_pt.y - height / 2.0;
+       }
+}
diff --git a/altosuilib/AltosUIMapView.java b/altosuilib/AltosUIMapView.java
new file mode 100644 (file)
index 0000000..a14fde6
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import javax.swing.*;
+import java.io.*;
+import java.lang.*;
+import java.awt.geom.*;
+import java.util.*;
+import java.util.concurrent.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class AltosUIMapView extends Component implements MouseMotionListener, MouseListener, MouseWheelListener, ComponentListener, AltosUIMapTileListener, AltosUIMapStoreListener {
+
+       AltosUIMapPath  path = new AltosUIMapPath();
+
+       AltosUIMapLine  line = new AltosUIMapLine();
+
+       AltosUIMapCache cache = new AltosUIMapCache();
+
+       LinkedList<AltosUIMapMark> marks = new LinkedList<AltosUIMapMark>();
+
+       LinkedList<AltosUIMapZoomListener> zoom_listeners = new LinkedList<AltosUIMapZoomListener>();
+
+       boolean         have_boost = false;
+       boolean         have_landed = false;
+
+       ConcurrentHashMap<Point,AltosUIMapTile> tiles = new ConcurrentHashMap<Point,AltosUIMapTile>();
+
+       static final int default_zoom = 15;
+       static final int min_zoom = 3;
+       static final int max_zoom = 21;
+       static final int px_size = 512;
+
+       int             load_radius;
+       AltosUILatLon   load_centre = null;
+       AltosUIMapTileListener  load_listener;
+
+       int             zoom = default_zoom;
+       int             maptype = AltosUIMap.maptype_default;
+
+       long            user_input_time;
+
+       /* Milliseconds to wait after user action before auto-scrolling
+        */
+       static final long auto_scroll_delay = 20 * 1000;
+
+       AltosUIMapTransform     transform;
+       AltosUILatLon           centre;
+
+       public void set_font() {
+               line.set_font(AltosUILib.value_font);
+               for (AltosUIMapTile tile : tiles.values())
+                       tile.set_font(AltosUILib.value_font);
+               repaint();
+       }
+
+       public void set_units() {
+               repaint();
+       }
+
+       private boolean is_drag_event(MouseEvent e) {
+               return e.getModifiers() == InputEvent.BUTTON1_MASK;
+       }
+
+       Point   drag_start;
+
+       private void drag(MouseEvent e) {
+               if (drag_start == null)
+                       return;
+
+               int dx = e.getPoint().x - drag_start.x;
+               int dy = e.getPoint().y - drag_start.y;
+
+               AltosUILatLon   new_centre = transform.screen_lat_lon(new Point(getWidth() / 2 - dx, getHeight() / 2 - dy));
+               centre (new_centre.lat, new_centre.lon);
+               drag_start = e.getPoint();
+       }
+
+       private void drag_start(MouseEvent e) {
+               drag_start = e.getPoint();
+       }
+
+       private void notice_user_input() {
+               user_input_time = System.currentTimeMillis();
+       }
+
+       private boolean recent_user_input() {
+               return (System.currentTimeMillis() - user_input_time) < auto_scroll_delay;
+       }
+
+       /* MouseMotionListener methods */
+
+       public void mouseDragged(MouseEvent e) {
+               notice_user_input();
+               if (is_drag_event(e))
+                       drag(e);
+               else {
+                       line.dragged(e, transform);
+                       repaint();
+               }
+       }
+
+       public void mouseMoved(MouseEvent e) {
+       }
+
+       /* MouseListener methods */
+       public void mouseClicked(MouseEvent e) {
+       }
+
+       public void mouseEntered(MouseEvent e) {
+       }
+
+       public void mouseExited(MouseEvent e) {
+       }
+
+       public void mousePressed(MouseEvent e) {
+               notice_user_input();
+               if (is_drag_event(e))
+                       drag_start(e);
+               else {
+                       line.pressed(e, transform);
+                       repaint();
+               }
+       }
+
+       public void mouseReleased(MouseEvent e) {
+       }
+
+       /* MouseWheelListener methods */
+
+       public void mouseWheelMoved(MouseWheelEvent e) {
+               int     zoom_change = e.getWheelRotation();
+
+               notice_user_input();
+               AltosUILatLon   mouse_lat_lon = transform.screen_lat_lon(e.getPoint());
+               set_zoom(zoom() - zoom_change);
+
+               Point2D.Double  new_mouse = transform.screen(mouse_lat_lon);
+
+               int     dx = getWidth()/2 - e.getPoint().x;
+               int     dy = getHeight()/2 - e.getPoint().y;
+
+               AltosUILatLon   new_centre = transform.screen_lat_lon(new Point((int) new_mouse.x + dx, (int) new_mouse.y + dy));
+
+               centre(new_centre.lat, new_centre.lon);
+       }
+
+       /* ComponentListener methods */
+
+       public void componentHidden(ComponentEvent e) {
+       }
+
+       public void componentMoved(ComponentEvent e) {
+       }
+
+       public void componentResized(ComponentEvent e) {
+               set_transform();
+       }
+
+       public void componentShown(ComponentEvent e) {
+               set_transform();
+       }
+
+       public void repaint(Rectangle r, int pad) {
+               repaint(r.x - pad, r.y - pad, r.width + pad*2, r.height + pad*2);
+       }
+
+       public void repaint(AltosUIMapRectangle rect, int pad) {
+               repaint (transform.screen(rect), pad);
+       }
+
+       private boolean far_from_centre(AltosUILatLon lat_lon) {
+
+               if (centre == null || transform == null)
+                       return true;
+
+               Point2D.Double  screen = transform.screen(lat_lon);
+
+               int             width = getWidth();
+               int             dx = Math.abs ((int) screen.x - width/2);
+
+               if (dx > width / 4)
+                       return true;
+
+               int             height = getHeight();
+               int             dy = Math.abs ((int) screen.y - height/2);
+
+               if (dy > height / 4)
+                       return true;
+
+               return false;
+       }
+
+       public void show(AltosState state, AltosListenerState listener_state) {
+
+               /* If insufficient gps data, nothing to update
+                */
+               AltosGPS        gps = state.gps;
+
+               if (gps == null)
+                       return;
+
+               if (!gps.locked && gps.nsat < 4)
+                       return;
+
+               AltosUIMapRectangle     damage = path.add(gps.lat, gps.lon, state.state);
+
+               switch (state.state) {
+               case AltosLib.ao_flight_boost:
+                       if (!have_boost) {
+                               add_mark(gps.lat, gps.lon, state.state);
+                               have_boost = true;
+                       }
+                       break;
+               case AltosLib.ao_flight_landed:
+                       if (!have_landed) {
+                               add_mark(gps.lat, gps.lon, state.state);
+                               have_landed = true;
+                       }
+                       break;
+               }
+
+               if (damage != null)
+                       repaint(damage, AltosUIMapPath.stroke_width);
+               maybe_centre(gps.lat, gps.lon);
+       }
+
+       private void set_transform() {
+               Rectangle       bounds = getBounds();
+
+               transform = new AltosUIMapTransform(bounds.width, bounds.height, zoom, centre);
+               repaint();
+       }
+
+       public boolean set_zoom(int zoom) {
+               if (min_zoom <= zoom && zoom <= max_zoom && zoom != this.zoom) {
+                       this.zoom = zoom;
+                       tiles.clear();
+                       set_transform();
+
+                       for (AltosUIMapZoomListener listener : zoom_listeners)
+                               listener.zoom_changed(this.zoom);
+
+                       return true;
+               }
+               return false;
+       }
+
+       public void add_zoom_listener(AltosUIMapZoomListener listener) {
+               if (!zoom_listeners.contains(listener))
+                       zoom_listeners.add(listener);
+       }
+
+       public void remove_zoom_listener(AltosUIMapZoomListener listener) {
+               zoom_listeners.remove(listener);
+       }
+
+       public void set_load_params(double lat, double lon, int radius, AltosUIMapTileListener listener) {
+               load_centre = new AltosUILatLon(lat, lon);
+               load_radius = radius;
+               load_listener = listener;
+               centre(lat, lon);
+               make_tiles();
+               for (AltosUIMapTile tile : tiles.values()) {
+                       tile.add_store_listener(this);
+                       if (tile.store_status() != AltosUIMapStore.loading)
+                               listener.notify_tile(tile, tile.store_status());
+               }
+               repaint();
+       }
+
+       public boolean all_fetched() {
+               for (AltosUIMapTile tile : tiles.values()) {
+                       if (tile.store_status() == AltosUIMapStore.loading)
+                               return false;
+               }
+               return true;
+       }
+
+       public boolean set_maptype(int maptype) {
+               if (maptype != this.maptype) {
+                       this.maptype = maptype;
+                       tiles.clear();
+                       repaint();
+                       return true;
+               }
+               return false;
+       }
+
+       public int get_maptype() {
+               return maptype;
+       }
+
+       public int zoom() {
+               return zoom;
+       }
+
+       public void centre(AltosUILatLon lat_lon) {
+               centre = lat_lon;
+               set_transform();
+       }
+
+       public void centre(double lat, double lon) {
+               centre(new AltosUILatLon(lat, lon));
+       }
+
+       public void maybe_centre(double lat, double lon) {
+               AltosUILatLon   lat_lon = new AltosUILatLon(lat, lon);
+               if (centre == null || (!recent_user_input() && far_from_centre(lat_lon)))
+                       centre(lat_lon);
+       }
+
+       private VolatileImage create_back_buffer() {
+               return getGraphicsConfiguration().createCompatibleVolatileImage(getWidth(), getHeight());
+       }
+
+       private Point floor(Point2D.Double point) {
+               return new Point ((int) Math.floor(point.x / px_size) * px_size,
+                                 (int) Math.floor(point.y / px_size) * px_size);
+       }
+
+       private Point ceil(Point2D.Double point) {
+               return new Point ((int) Math.ceil(point.x / px_size) * px_size,
+                                 (int) Math.ceil(point.y / px_size) * px_size);
+       }
+
+       private void make_tiles() {
+               Point   upper_left;
+               Point   lower_right;
+
+               if (load_centre != null) {
+                       Point centre = floor(transform.point(load_centre));
+
+                       upper_left = new Point(centre.x - load_radius * px_size,
+                                              centre.y - load_radius * px_size);
+                       lower_right = new Point(centre.x + load_radius * px_size,
+                                              centre.y + load_radius * px_size);
+               } else {
+                       upper_left = floor(transform.screen_point(new Point(0, 0)));
+                       lower_right = floor(transform.screen_point(new Point(getWidth(), getHeight())));
+               }
+               LinkedList<Point> to_remove = new LinkedList<Point>();
+
+               for (Point point : tiles.keySet()) {
+                       if (point.x < upper_left.x || lower_right.x < point.x ||
+                           point.y < upper_left.y || lower_right.y < point.y) {
+                               to_remove.add(point);
+                       }
+               }
+
+               for (Point point : to_remove)
+                       tiles.remove(point);
+
+               cache.set_cache_size(((lower_right.y - upper_left.y) / px_size + 1) * ((lower_right.x - upper_left.x) / px_size + 1));
+               for (int y = upper_left.y; y <= lower_right.y; y += px_size) {
+                       for (int x = upper_left.x; x <= lower_right.x; x += px_size) {
+                               Point point = new Point(x, y);
+
+                               if (!tiles.containsKey(point)) {
+                                       AltosUILatLon   ul = transform.lat_lon(new Point2D.Double(x, y));
+                                       AltosUILatLon   center = transform.lat_lon(new Point2D.Double(x + px_size/2, y + px_size/2));
+                                       AltosUIMapTile tile = new AltosUIMapTile(this, ul, center, zoom, maptype,
+                                                                                px_size, AltosUILib.value_font);
+                                       tiles.put(point, tile);
+                               }
+                       }
+               }
+       }
+
+       /* AltosUIMapTileListener methods */
+       public synchronized void notify_tile(AltosUIMapTile tile, int status) {
+               for (Point point : tiles.keySet()) {
+                       if (tile == tiles.get(point)) {
+                               Point   screen = transform.screen(point);
+                               repaint(screen.x, screen.y, px_size, px_size);
+                       }
+               }
+       }
+
+       public AltosUIMapCache cache() { return cache; }
+
+       /* AltosUIMapStoreListener methods */
+       public synchronized void notify_store(AltosUIMapStore store, int status) {
+               if (load_listener != null) {
+                       for (AltosUIMapTile tile : tiles.values())
+                               if (store.equals(tile.store))
+                                       load_listener.notify_tile(tile, status);
+               }
+       }
+
+       private void do_paint(Graphics g) {
+               Graphics2D      g2d = (Graphics2D) g;
+
+               make_tiles();
+
+               for (AltosUIMapTile tile : tiles.values())
+                       tile.paint(g2d, transform);
+
+               synchronized(marks) {
+                       for (AltosUIMapMark mark : marks)
+                               mark.paint(g2d, transform);
+               }
+
+               path.paint(g2d, transform);
+
+               line.paint(g2d, transform);
+       }
+
+       public void paint(Graphics g) {
+               VolatileImage   back_buffer = create_back_buffer();
+               do {
+                       GraphicsConfiguration gc = getGraphicsConfiguration();
+                       int code = back_buffer.validate(gc);
+                       if (code == VolatileImage.IMAGE_INCOMPATIBLE)
+                               back_buffer = create_back_buffer();
+
+                       Graphics g_back = back_buffer.getGraphics();
+                       g_back.setClip(g.getClip());
+                       do_paint(g_back);
+                       g_back.dispose();
+
+                       g.drawImage(back_buffer, 0, 0, this);
+               } while (back_buffer.contentsLost());
+               back_buffer.flush();
+       }
+
+       public void update(Graphics g) {
+               paint(g);
+       }
+
+       public void add_mark(double lat, double lon, int state) {
+               synchronized(marks) {
+                       marks.add(new AltosUIMapMark(lat, lon, state));
+               }
+               repaint();
+       }
+
+       public void clear_marks() {
+               synchronized(marks) {
+                       marks.clear();
+               }
+       }
+
+       public AltosUIMapView() {
+               centre(0, 0);
+
+               addComponentListener(this);
+               addMouseMotionListener(this);
+               addMouseListener(this);
+               addMouseWheelListener(this);
+               set_font();
+       }
+}
diff --git a/altosuilib/AltosUIMapZoomListener.java b/altosuilib/AltosUIMapZoomListener.java
new file mode 100644 (file)
index 0000000..02e8bb5
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+public interface AltosUIMapZoomListener {
+       abstract public void zoom_changed(int zoom);
+}
index ae8eb0344ae6a6e7aa29516731e3520523dcba43..cd6fa589a90dbc33593f4a92347c972f2168aa0e 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.io.*;
 import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
@@ -41,7 +41,7 @@ public class AltosUIMarker implements AltosUIGrapher {
        boolean                 enabled;
        int                     fetch;
        Color                   color;
-       
+
        private void remove_markers() {
                for (ValueMarker marker : markers)
                        plot.removeDomainMarker(marker);
index 4c995f80848a15bfd7033e64bcaf54df25a0964f..7a582a7d5d3d25bb84f77dd3159a1402378aaabf 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.io.*;
 import java.util.*;
 import java.awt.Component;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 public class AltosUIPreferences extends AltosPreferences {
 
index 64d3e3dfa8b184d4174670e8f5e2cc1262732f68..da29253dc9e57149eb8c6da774f18df865c70f64 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.io.File;
 import java.util.prefs.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 import javax.swing.filechooser.FileSystemView;
 
 public class AltosUIPreferencesBackend implements AltosPreferencesBackend {
 
        private Preferences _preferences = null;
-       
+
        public AltosUIPreferencesBackend() {
                _preferences = Preferences.userRoot().node("/org/altusmetrum/altosui");
        }
index 1f2a1c3f6a18c528a5ebd70802283ec0e3bfdb17..b0632d18937bb2840efbb2cc7fd2c522e59f4f7c 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.io.*;
 import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
+import org.altusmetrum.altoslib_4.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
@@ -38,7 +38,7 @@ 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"; }
@@ -60,7 +60,7 @@ public class AltosUISeries extends XYSeries implements AltosUIGrapher {
        XYItemRenderer  renderer;
        int             fetch;
        boolean         enable;
-       
+
        public void set_units() {
                axis.set_units();
                StandardXYToolTipGenerator      ttg;
@@ -104,6 +104,7 @@ public class AltosUISeries extends XYSeries implements AltosUIGrapher {
 
                renderer = new XYLineAndShapeRenderer(true, false);
                renderer.setSeriesPaint(0, color);
+               renderer.setSeriesStroke(0, new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
                renderer.setSeriesVisible(0, enable);
                set_units();
        }
diff --git a/altosuilib/AltosUIUnitsIndicator.java b/altosuilib/AltosUIUnitsIndicator.java
new file mode 100644 (file)
index 0000000..2285b6f
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+
+public abstract class AltosUIUnitsIndicator extends AltosUIIndicator {
+
+       AltosUnits      units;
+
+       abstract public double value(AltosState state, int i);
+       public double good() { return 0; }
+       public boolean good(double value) { return value != AltosLib.MISSING && value >= good(); }
+       public boolean hide(double value) { return false; }
+
+       public boolean hide(AltosState state, int i) {
+               if (state == null)
+                       return hide(AltosLib.MISSING);
+               return hide(value(state, i));
+       }
+
+       public double value (AltosState state, AltosListenerState listener_state, int i) {
+               return value(state, i);
+       }
+
+       public double[] last_values;
+
+       public void show(double... v) {
+               show();
+               for (int i = 0; i < values.length; i++) {
+                       if (v[i] != last_values[i]) {
+                               String  value_text;
+                               boolean good = false;
+
+                               if (v[i] == AltosLib.MISSING) {
+                                       value_text = "Missing";
+                               } else {
+                                       value_text = units.show(8, v[i]);
+                                       if (i == 0)
+                                               good = good(v[i]);
+                               }
+                               last_values[i] = v[i];
+                               if (i == 0 && lights != null)
+                                       set_lights(good);
+                               values[i].setText(value_text);
+                       }
+               }
+       }
+
+       public void units_changed(boolean imperial_units) {
+               show(last_values);
+       }
+
+       public void show (AltosState state, AltosListenerState listener_state) {
+               double[] v = new double[values.length];
+               boolean hide = false;
+
+               for (int i = 0; i < values.length; i++) {
+                       if (state != null)
+                               v[i] = value(state, listener_state, i);
+                       else
+                               v[i] = AltosLib.MISSING;
+                       if (hide(state, i))
+                               hide = true;
+               }
+
+               if (hide)
+                       hide();
+               else
+                       show(v);
+       }
+
+       public void reset() {
+               for (int i = 0; i < last_values.length; i++)
+                       last_values[i] = AltosLib.MISSING - 1;
+       }
+
+       public AltosUIUnitsIndicator (Container container, int x, int y, int label_width, AltosUnits units, String name, int number_values, boolean has_lights, int width) {
+               super(container, x, y, label_width, name, number_values, has_lights, width);
+               this.units = units;
+               last_values = new double[values.length];
+               for (int i = 0; i < last_values.length; i++)
+                       last_values[i] = AltosLib.MISSING - 1;
+       }
+
+       public AltosUIUnitsIndicator (Container container, int x, int y, AltosUnits units, String name, int number_values, boolean has_lights, int width) {
+               this(container, x, y, 1, units, name, number_values, has_lights, width);
+       }
+
+       public AltosUIUnitsIndicator (Container container, int y, AltosUnits units, String name, int number_values, boolean has_lights, int width) {
+               this(container, 0, y, units, name, number_values, has_lights, width);
+       }
+
+       public AltosUIUnitsIndicator (Container container, int y, AltosUnits units, String name, int width) {
+               this(container, 0, y, units, name, 1, false, width);
+       }
+
+       public AltosUIUnitsIndicator (Container container, int y, AltosUnits units, String name) {
+               this(container, 0, y, units, name, 1, false, 1); 
+       }
+
+       public AltosUIUnitsIndicator (Container container, int x,int y, AltosUnits units, String name) {
+               this(container, x, y, units, name, 1, false, 1); 
+       }
+}
index 169cca1b91c8997edcc281298b2481ced3888d06..0edb5c04b3ae2fd7d58fea4452a23bf57e7a1ced 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 public class AltosUIVersion {
        public final static String version = "@VERSION@";
+
+       public final static String google_maps_api_key = @GOOGLEKEY@;
+
+       static boolean has_google_maps_api_key() {
+               return google_maps_api_key != null && google_maps_api_key.length() > 1;
+       }
 }
diff --git a/altosuilib/AltosUIVoltageIndicator.java b/altosuilib/AltosUIVoltageIndicator.java
new file mode 100644 (file)
index 0000000..3ff1721
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+
+public abstract class AltosUIVoltageIndicator extends AltosUIUnitsIndicator {
+
+       abstract public double voltage(AltosState state);
+       abstract public double good();
+
+       public double value(AltosState state, int i) {
+               return voltage(state);
+       }
+
+       double last_voltage = -1;
+
+       public AltosUIVoltageIndicator (Container container, int x, int y, String name, int width) {
+               super(container, x, y, AltosConvert.voltage, name, 1, true, width);
+       }
+
+       public AltosUIVoltageIndicator (Container container, int y, String name, int width) {
+               this(container, 0, y, name, width);
+       }
+}
index 4f329840bdbe88aba6b33305ee43a9e808b8e405..b70b5e83bd18911da0862c79c97df48dba93f53f 100644 (file)
@@ -15,7 +15,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altosuilib_1;
+package org.altusmetrum.altosuilib_2;
 
 import java.util.*;
 import libaltosJNI.*;
diff --git a/altosuilib/AltosVoice.java b/altosuilib/AltosVoice.java
new file mode 100644 (file)
index 0000000..a3995f6
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.altosuilib_2;
+
+import com.sun.speech.freetts.Voice;
+import com.sun.speech.freetts.VoiceManager;
+import java.util.concurrent.LinkedBlockingQueue;
+
+public class AltosVoice implements Runnable {
+       VoiceManager                    voice_manager;
+       Voice                           voice;
+       LinkedBlockingQueue<String>     phrases;
+       Thread                          thread;
+       boolean                         busy;
+
+       final static String voice_name = "kevin16";
+
+       public void run() {
+               try {
+                       for (;;) {
+                               String s = phrases.take();
+                               voice.speak(s);
+                               synchronized(this) {
+                                       if (phrases.isEmpty()) {
+                                               busy = false;
+                                               notifyAll();
+                                       }
+                               }
+                       }
+               } catch (InterruptedException e) {
+               }
+       }
+
+       public synchronized void drain() throws InterruptedException {
+               while (busy)
+                       wait();
+       }
+
+       public void speak_always(String s) {
+               try {
+                       if (voice != null) {
+                               synchronized(this) {
+                                       busy = true;
+                                       phrases.put(s);
+                               }
+                       }
+               } catch (InterruptedException e) {
+               }
+       }
+
+       public void speak(String s) {
+               if (AltosUIPreferences.voice())
+                       speak_always(s);
+       }
+
+       public void speak(String format, Object... parameters) {
+               speak(String.format(format, parameters));
+       }
+
+       public AltosVoice () {
+               busy = false;
+               voice_manager = VoiceManager.getInstance();
+               voice = voice_manager.getVoice(voice_name);
+               if (voice != null) {
+                       voice.allocate();
+                       phrases = new LinkedBlockingQueue<String> ();
+                       thread = new Thread(this);
+                       thread.start();
+               } else {
+                       System.out.printf("Voice manager failed to open %s\n", voice_name);
+                       Voice[] voices = voice_manager.getVoices();
+                       System.out.printf("Available voices:\n");
+                       for (int i = 0; i < voices.length; i++) {
+                               System.out.println("    " + voices[i].getName()
+                                                  + " (" + voices[i].getDomain() + " domain)");
+                       }
+               }
+       }
+}
diff --git a/altosuilib/GrabNDrag.java b/altosuilib/GrabNDrag.java
new file mode 100644 (file)
index 0000000..4426f7a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.altosuilib_2;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.MouseInputAdapter;
+
+class GrabNDrag extends MouseInputAdapter {
+       private JComponent scroll;
+       private Point startPt = new Point();
+
+       public GrabNDrag(JComponent scroll) {
+               this.scroll = scroll;
+               scroll.addMouseMotionListener(this);
+               scroll.addMouseListener(this);
+               scroll.setAutoscrolls(true);
+       }
+
+       public static boolean grab_n_drag(MouseEvent e) {
+               return e.getModifiers() == InputEvent.BUTTON1_MASK;
+       }
+
+       public void mousePressed(MouseEvent e) {
+               if (grab_n_drag(e))
+                       startPt.setLocation(e.getPoint());
+       }
+       public void mouseDragged(MouseEvent e) {
+               if (grab_n_drag(e)) {
+                       int xd = e.getX() - startPt.x;
+                       int yd = e.getY() - startPt.y;
+
+                       Rectangle r = scroll.getVisibleRect();
+                       r.x -= xd;
+                       r.y -= yd;
+                       scroll.scrollRectToVisible(r);
+               }
+       }
+}
index 4b22af1f8eda6fab2ed14cc710c7ce16db3cbfee..e08fbe7443e74acbb04814ae03b4ed077607e91f 100644 (file)
@@ -1,4 +1,4 @@
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
 
 JAVAROOT=bin
 
@@ -9,8 +9,10 @@ SRC=.
 altosuilibdir = $(datadir)/java
 
 altosuilib_JAVA = \
+       GrabNDrag.java \
        AltosDevice.java \
        AltosDeviceDialog.java \
+       AltosFlightDisplay.java \
        AltosFontListener.java \
        AltosPositionListener.java \
        AltosUIConfigure.java \
@@ -30,10 +32,70 @@ altosuilib_JAVA = \
        AltosUIPreferences.java \
        AltosUISeries.java \
        AltosUIVersion.java \
-       AltosUSBDevice.java
+       AltosUSBDevice.java \
+       AltosVoice.java \
+       AltosDisplayThread.java \
+       AltosDeviceUIDialog.java \
+       AltosFreqList.java \
+       AltosSerial.java \
+       AltosSerialInUseException.java \
+       AltosConfigFreqUI.java \
+       AltosScanUI.java \
+       AltosEepromDelete.java \
+       AltosEepromManage.java \
+       AltosEepromMonitorUI.java \
+       AltosEepromSelect.java \
+       AltosCSVUI.java \
+       AltosDataChooser.java \
+       AltosLights.java \
+       AltosLed.java \
+       AltosFlashUI.java \
+       AltosRomconfigUI.java \
+       AltosInfoTable.java \
+       AltosFlightInfoTableModel.java \
+       AltosFlightStatsTable.java \
+       AltosGraph.java \
+       AltosGraphDataPoint.java \
+       AltosGraphDataSet.java \
+       AltosBTDevice.java \
+       AltosBTDeviceIterator.java \
+       AltosBTManage.java \
+       AltosBTKnown.java \
+       AltosUIMap.java \
+       AltosUIMapView.java \
+       AltosUIMapLine.java \
+       AltosUIMapMark.java \
+       AltosUIMapPath.java \
+       AltosUIMapTile.java \
+       AltosUIMapCache.java \
+       AltosUIMapImage.java \
+       AltosUIMapTransform.java \
+       AltosUIMapRectangle.java \
+       AltosUIMapZoomListener.java \
+       AltosUIMapTileListener.java \
+       AltosUIMapPreload.java \
+       AltosUIMapStore.java \
+       AltosUIMapStoreListener.java \
+       AltosUILatLon.java \
+       AltosUIFlightTab.java \
+       AltosUIIndicator.java \
+       AltosUIUnitsIndicator.java \
+       AltosUIVoltageIndicator.java
 
 JAR=altosuilib_$(ALTOSUILIB_VERSION).jar
 
+# Icons
+ICONDIR=$(top_srcdir)/icon
+
+ICONS= $(ICONDIR)/redled.png $(ICONDIR)/redoff.png \
+       $(ICONDIR)/greenled.png $(ICONDIR)/greenoff.png \
+       $(ICONDIR)/grayon.png $(ICONDIR)/grayled.png
+
+# icon base names for jar
+ICONJAR= -C $(ICONDIR) redled.png -C $(ICONDIR) redoff.png \
+       -C $(ICONDIR) greenled.png -C $(ICONDIR) greenoff.png \
+       -C $(ICONDIR) grayon.png -C $(ICONDIR) grayled.png
+
 all-local: $(JAR)
 
 clean-local:
@@ -48,5 +110,5 @@ install-altosuilibJAVA: $(JAR)
 $(JAVAROOT):
        mkdir -p $(JAVAROOT)
 
-$(JAR): classaltosuilib.stamp
-       jar cf $@ -C $(JAVAROOT) .
+$(JAR): classaltosuilib.stamp $(ICONS)
+       jar cf $@ $(ICONJAR) -C $(JAVAROOT) .
diff --git a/altusmetrum.cat b/altusmetrum.cat
new file mode 100644 (file)
index 0000000..2d7e8b2
Binary files /dev/null and b/altusmetrum.cat differ
diff --git a/altusmetrum.inf b/altusmetrum.inf
new file mode 100755 (executable)
index 0000000..45905cc
--- /dev/null
@@ -0,0 +1,170 @@
+; Copyright (C) 2010 Keith Packard (keithp@keithp.com)\r
+; released under GNU General Public License version 2\r
+\r
+[Version]\r
+Signature      = "$Windows NT$"\r
+Class          = Modem\r
+ClassGUID      = {4D36E96D-E325-11CE-BFC1-08002BE10318}\r
+Provider       = %Mfg%\r
+DriverVer      = 06/15/2014,7.1.1.0\r
+PnpLockDown    = 0\r
+DriverPackageDisplayName = %DriverName%\r
+CatalogFile    = altusmetrum.cat\r
+\r
+[DestinationDirs]\r
+FakeModemCopyFileSection = 12\r
+DefaultDestDir = 12\r
+\r
+[ControlFlags]\r
+\r
+[Manufacturer]\r
+%Mfg% = Models, NTx86, NTamd64, NTia64\r
+\r
+[Models]\r
+%AltusMetrum%  = AltusMetrum.Install, USB\VID_FFFE&PID_000A, AltusMetrumSerial\r
+%TeleMetrum%   = AltusMetrum.Install, USB\VID_FFFE&PID_000B, AltusMetrumSerial\r
+%TeleDongle%   = AltusMetrum.Install, USB\VID_FFFE&PID_000C, AltusMetrumSerial\r
+%TeleTerra%    = AltusMetrum.Install, USB\VID_FFFE&PID_000D, AltusMetrumSerial\r
+%TeleBT%       = AltusMetrum.Install, USB\VID_FFFE&PID_000e, AltusMetrumSerial\r
+%TeleLaunch%   = AltusMetrum.Install, USB\VID_FFFE&PID_000f, AltusMetrumSerial\r
+%TeleLCO%      = AltusMetrum.Install, USB\VID_FFFE&PID_0010, AltusMetrumSerial\r
+%TeleScience%  = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial\r
+%TelePyro%     = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial\r
+%TeleShield%   = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial\r
+%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
+%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
+%AltusMetrum2b%        = AltusMetrum.Install, USB\VID_FFFE&PID_002b, AltusMetrumSerial\r
+%AltusMetrum2c%        = AltusMetrum.Install, USB\VID_FFFE&PID_002c, AltusMetrumSerial\r
+\r
+[Models.NTx86]\r
+%AltusMetrum%  = AltusMetrum.Install, USB\VID_FFFE&PID_000A, AltusMetrumSerial\r
+%TeleMetrum%   = AltusMetrum.Install, USB\VID_FFFE&PID_000B, AltusMetrumSerial\r
+%TeleDongle%   = AltusMetrum.Install, USB\VID_FFFE&PID_000C, AltusMetrumSerial\r
+%TeleTerra%    = AltusMetrum.Install, USB\VID_FFFE&PID_000D, AltusMetrumSerial\r
+%TeleBT%       = AltusMetrum.Install, USB\VID_FFFE&PID_000e, AltusMetrumSerial\r
+%TeleLaunch%   = AltusMetrum.Install, USB\VID_FFFE&PID_000f, AltusMetrumSerial\r
+%TeleLCO%      = AltusMetrum.Install, USB\VID_FFFE&PID_0010, AltusMetrumSerial\r
+%TeleScience%  = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial\r
+%TelePyro%     = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial\r
+%TeleShield%   = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial\r
+%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
+%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
+%AltusMetrum2b%        = AltusMetrum.Install, USB\VID_FFFE&PID_002b, AltusMetrumSerial\r
+%AltusMetrum2c%        = AltusMetrum.Install, USB\VID_FFFE&PID_002c, AltusMetrumSerial\r
+\r
+[Models.NTamd64]\r
+%AltusMetrum%  = AltusMetrum.Install, USB\VID_FFFE&PID_000A, AltusMetrumSerial\r
+%TeleMetrum%   = AltusMetrum.Install, USB\VID_FFFE&PID_000B, AltusMetrumSerial\r
+%TeleDongle%   = AltusMetrum.Install, USB\VID_FFFE&PID_000C, AltusMetrumSerial\r
+%TeleTerra%    = AltusMetrum.Install, USB\VID_FFFE&PID_000D, AltusMetrumSerial\r
+%TeleBT%       = AltusMetrum.Install, USB\VID_FFFE&PID_000e, AltusMetrumSerial\r
+%TeleLaunch%   = AltusMetrum.Install, USB\VID_FFFE&PID_000f, AltusMetrumSerial\r
+%TeleLCO%      = AltusMetrum.Install, USB\VID_FFFE&PID_0010, AltusMetrumSerial\r
+%TeleScience%  = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial\r
+%TelePyro%     = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial\r
+%TeleShield%   = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial\r
+%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
+%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
+%AltusMetrum2b%        = AltusMetrum.Install, USB\VID_FFFE&PID_002b, AltusMetrumSerial\r
+%AltusMetrum2c%        = AltusMetrum.Install, USB\VID_FFFE&PID_002c, AltusMetrumSerial\r
+\r
+[Models.NTia64]\r
+%AltusMetrum%  = AltusMetrum.Install, USB\VID_FFFE&PID_000A, AltusMetrumSerial\r
+%TeleMetrum%   = AltusMetrum.Install, USB\VID_FFFE&PID_000B, AltusMetrumSerial\r
+%TeleDongle%   = AltusMetrum.Install, USB\VID_FFFE&PID_000C, AltusMetrumSerial\r
+%TeleTerra%    = AltusMetrum.Install, USB\VID_FFFE&PID_000D, AltusMetrumSerial\r
+%TeleBT%       = AltusMetrum.Install, USB\VID_FFFE&PID_000e, AltusMetrumSerial\r
+%TeleLaunch%   = AltusMetrum.Install, USB\VID_FFFE&PID_000f, AltusMetrumSerial\r
+%TeleLCO%      = AltusMetrum.Install, USB\VID_FFFE&PID_0010, AltusMetrumSerial\r
+%TeleScience%  = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial\r
+%TelePyro%     = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial\r
+%TeleShield%   = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial\r
+%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
+%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
+%AltusMetrum2b%        = AltusMetrum.Install, USB\VID_FFFE&PID_002b, AltusMetrumSerial\r
+%AltusMetrum2c%        = AltusMetrum.Install, USB\VID_FFFE&PID_002c, AltusMetrumSerial\r
+\r
+;----------------------------------------------------------------------------\r
+; Installation sections\r
+;----------------------------------------------------------------------------\r
+\r
+[AltusMetrum.Install.NT]\r
+include                = mdmcpq.inf\r
+CopyFiles      = FakeModemCopyFileSection\r
+AddReg         = All.AddReg, Modem.AddReg, Uninstall.AddReg\r
+\r
+[AltusMetrum.Install.NT.Services]\r
+include                = mdmcpq.inf\r
+AddService     = usbser, 0x00000000, LowerFilter_Service_Inst\r
+\r
+[AltusMetrum.Install.NT.HW]\r
+include                = mdmcpq.inf\r
+AddReg         = LowerFilterAddReg\r
+\r
+;----------------------------------------------------------------------------\r
+; AddReg sections\r
+;----------------------------------------------------------------------------\r
+\r
+[All.AddReg]\r
+HKR,,FriendlyDriver,,          Unimodem.vxd\r
+HKR,,DevLoader,,               *vcomm\r
+HKR,,ConfigDialog,,            modemui.dll\r
+HKR,,EnumPropPages,,           "modemui.dll,EnumPropPages"\r
+HKR,,PortSubClass, 1,          02\r
+HKR,,DeviceType, 1,            01\r
+\r
+[Modem.AddReg]\r
+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\%AltusMetrum%,DisplayName,,"%AltusMetrum%"\r
+\r
+[Strings]\r
+Mfg            = "altusmetrum.org"\r
+AltusMetrum    = "AltusMetrum"\r
+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
index dc2f2212983c4508680bcf6d65bc48b6ff96bc6a..68a8ebf2f56928924d70839535bf28799e4c35fc 100755 (executable)
@@ -21,6 +21,7 @@ while true; do
 
        case "$FREQ" in
        "")
+               echo $SERIAL","$CAL_VALUE >> cal_values
                exit 0
                ;;
        *)
@@ -44,3 +45,4 @@ EOF
                ;;
        esac
 done
+
diff --git a/ao-bringup/test-baro b/ao-bringup/test-baro
new file mode 100755 (executable)
index 0000000..ce5b7f8
--- /dev/null
@@ -0,0 +1,99 @@
+#!/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[*] baro(file f) {
+       string[...] x = {};
+
+       flush_input(f);
+       fprintf (f, "B\n");
+       flush(f);
+       for (;;) {
+               string l = timed_read(f, 1000);
+               if (l == "") {
+                       File::fprintf(stderr, "read timedout\n");
+                       exit(1);
+               }
+               x[dim(x)] = l;
+               if (String::index(l, "Altitude:") == 0)
+                       break;
+       }
+       return x;
+}
+
+string[*] find_baro(string[*] s, string match) {
+       for (int i = 0; i < dim(s); i++)
+               if (String::index(s[i], match) >= 0)
+                       return String::wordsplit(s[i], " ");
+       return (string[*]) {};
+}
+
+bool
+do_baro(file f) {
+       string[*] i = baro(f);
+       string[*] temp = find_baro(i, "Temperature");
+       string[*] alt = find_baro(i, "Altitude");
+
+       real temperature = string_to_integer(temp[2]) / 100.0;
+       real altitude = string_to_integer(alt[1]);
+
+       if (altitude < -50 || 3000 < altitude) {
+               printf ("weird altitude %f\n", altitude);
+               return false;
+       }
+
+       if (temperature < 20 || 30 < temperature) {
+               printf ("weird temperature %f\n", temperature);
+               return false;
+       }
+
+       printf ("altitude %f temperature %f\n", altitude, temperature);
+
+       return true;
+}
+
+void main () {
+       string  name = argv[1];
+       file    f = open(name, "r+");
+       bool ret = true;
+
+       if (!do_baro(f))
+               ret = false;
+       exit (ret? 0 : 1);
+}
+
+main();
diff --git a/ao-bringup/test-easymini b/ao-bringup/test-easymini
new file mode 100755 (executable)
index 0000000..2913938
--- /dev/null
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+VERSION=1.0
+PRODUCT=EasyMini
+BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
+
+echo "$PRODUCT-v$VERSION Test Program"
+echo "Copyright 2014 by Keith Packard.  Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\t$PRODUCT v$VERSION powered from USB"
+echo
+
+ret=1
+ao-list | while read product serial dev; do
+    case "$product" in
+       "$PRODUCT-v$VERSION")
+
+           echo "Testing $product $serial $dev"
+
+           echo "Testing igniters. Both should flash"
+           ./test-igniter "$dev" drogue main
+
+           case $? in
+               0)
+                   ;;
+               *)
+                   echo "failed"
+                   exit 1
+           esac
+
+           echo "Testing baro sensor"
+           ./test-baro "$dev"
+
+           case $? in
+               0)
+                   ;;
+               *)
+                   echo "failed"
+                   exit 1
+           esac
+
+           FLASHSIZE=1048576
+
+           echo "Testing flash"
+           ./test-flash "$dev" "$FLASHSIZE"
+
+           case $? in
+               0)
+                   ;;
+               *)
+                   echo "failed"
+                   exit 1
+           esac
+
+           echo "$PRODUCT-v$VERSION" serial "$serial" is ready to ship
+           ret=0
+           ;;
+       *)
+           echo "Skipping $product $serial $dev"
+           ;;
+    esac
+done
diff --git a/ao-bringup/test-flash b/ao-bringup/test-flash
new file mode 100755 (executable)
index 0000000..d79de32
--- /dev/null
@@ -0,0 +1,101 @@
+#!/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[*] flash(file f) {
+       string[...] x = {};
+
+       flush_input(f);
+       fprintf (f, "f\nv\n");
+       flush(f);
+       for (;;) {
+               string l = timed_read(f, 1000);
+               if (l == "") {
+                       File::fprintf(stderr, "Read timedout\n");
+                       exit(1);
+               }
+               x[dim(x)] = l;
+               if (String::index(l, "software-version") == 0)
+                       break;
+       }
+       return x;
+}
+
+string[*] find_flash(string[*] s, string match) {
+       for (int i = 0; i < dim(s); i++)
+               if (String::index(s[i], match) >= 0)
+                       return String::wordsplit(s[i], " ");
+       return (string[*]) {};
+}
+
+bool
+do_flash(file f, int expected_size) {
+       string[*] i = flash(f);
+       string[*] size = find_flash(i, "Storage size:");
+       string[*] erase = find_flash(i, "Storage erase unit:");
+
+       int actual_size = string_to_integer(size[2]);
+
+       if (actual_size != expected_size) {
+               printf ("weird flash size %d != %d\n", actual_size, expected_size);
+               return false;
+       }
+
+       int actual_erase = string_to_integer(erase[3]);
+
+       if (actual_erase != 65536) {
+               printf ("weird erase size %d\n", actual_erase);
+               return false;
+       }
+
+       printf ("flash size %d erase block %d\n", actual_size, actual_erase);
+
+       return true;
+}
+
+void main () {
+       string  name = argv[1];
+       string  size = argv[2];
+       file    f = open(name, "r+");
+       bool ret = true;
+
+       if (!do_flash(f, string_to_integer(size)))
+               ret = false;
+       exit (ret? 0 : 1);
+}
+
+main();
diff --git a/ao-bringup/test-gps b/ao-bringup/test-gps
new file mode 100755 (executable)
index 0000000..a1e2162
--- /dev/null
@@ -0,0 +1,102 @@
+#!/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[*] gps(file f) {
+       string[...] x = {};
+
+       flush_input(f);
+       fprintf (f, "g\nv\n");
+       flush(f);
+       for (;;) {
+               string l = timed_read(f, 1000);
+               if (l == "") {
+                       File::fprintf(stderr, "Read timedout\n");
+                       exit(1);
+               }
+               x[dim(x)] = l;
+               if (String::index(l, "software-version") == 0)
+                       break;
+       }
+       return x;
+}
+
+string[*] find_gps(string[*] s, string match) {
+       for (int i = 0; i < dim(s); i++)
+               if (String::index(s[i], match) >= 0)
+                       return String::wordsplit(s[i], " ");
+       return (string[*]) {};
+}
+
+bool
+do_gps(file f) {
+
+       string[*] i = gps(f);
+       string[*] flags = find_gps(i, "Flags:");
+       string[*] sats = find_gps(i, "Sats:");
+
+       int actual_flags = string_to_integer(flags[1]);
+
+       while ((actual_flags & (1 << 4)) == 0) {
+               printf("Flags: %s\n", flags[1]);
+               printf("Sats: %s\n", sats[1]);
+
+               sleep(1000);
+               i = gps(f);
+               flags = find_gps(i, "Flags:");
+               sats = find_gps(i, "Sats:");
+
+               actual_flags = string_to_integer(flags[1]);
+       }
+
+       printf("Flags: %s\n", flags[1]);
+       printf("Sats: %s\n", sats[1]);
+       printf("GPS locked\n");
+       return true;
+}
+
+void main () {
+       string  name = argv[1];
+       file    f = open(name, "r+");
+       bool ret = true;
+
+       if (!do_gps(f))
+               ret = false;
+       exit (ret? 0 : 1);
+}
+
+main();
diff --git a/ao-bringup/test-igniter b/ao-bringup/test-igniter
new file mode 100755 (executable)
index 0000000..454f632
--- /dev/null
@@ -0,0 +1,136 @@
+#!/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::wordsplit(s[i], " ");
+       return (string[*]) {};
+}
+
+string[*] igniters(file f) {
+       string[...] x = {};
+
+       flush_input(f);
+       fprintf (f, "t\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_igniter(string[*] s, string match) {
+       for (int i = 0; i < dim(s); i++)
+               if (String::index(s[i], match) >= 0)
+                       return String::wordsplit(s[i], " ");
+       return (string[*]) {};
+}
+
+bool
+do_igniter(file f, string igniter) {
+       string[*] i = igniters(f);
+       string[*] status = find_igniter(i, igniter);
+       if (dim(status) < 4) {
+               printf ("no igniter %s found in %v\n", igniter, i);
+               return false;
+       }
+       if (String::index(status[3], "ready") < 0) {
+               printf("igniter %s status is \"%s\"\n", igniter, status[3]);
+               return false;
+       }
+       fprintf(f, "i DoIt %s\n", igniter);
+       flush(f);
+       flush_input(f);
+       return true;
+}
+
+file
+open_tty(string name)
+{
+       int i = 0;
+       for (;;) {
+               try {
+                       return open (name, "r+");
+               } catch open_error(string error, File::error_type error, string name) {
+                       if (error == File::error_type.BUSY) {
+                               if (i < 30) {
+                                       printf ("waiting for %s to be usable\n", name);
+                                       sleep(2000);
+                                       continue;
+                               }
+                       } else {
+                               printf ("%s: %s\n", name, error);
+                               exit(1);
+                       }
+               }
+       }
+}
+
+void main () {
+       string  name = argv[1];
+       string[dim(argv)-2]     igniters = { [i] = argv[i+2] };
+       file    f = open_tty(name);
+       bool ret = true;
+
+       for (int i = 0; i < dim(igniters); i++) {
+               if (!do_igniter(f, igniters[i]))
+                       ret = false;
+       }
+       exit (ret? 0 : 1);
+}
+
+main();
diff --git a/ao-bringup/test-telegps b/ao-bringup/test-telegps
new file mode 100755 (executable)
index 0000000..f317448
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+VERSION=1.0
+PRODUCT=TeleGPS
+BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
+
+echo "$PRODUCT-v$VERSION Test Program"
+echo "Copyright 2014 by Bdale Garbee.  Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\t$PRODUCT v$VERSION powered from USB"
+echo
+
+ret=1
+ao-list | while read product serial dev; do
+    case "$product" in
+       "$PRODUCT-v$VERSION")
+
+           echo "Testing $product $serial $dev"
+
+           FLASHSIZE=2097152
+
+           echo "Testing flash"
+           ./test-flash "$dev" "$FLASHSIZE"
+
+           case $? in
+               0)
+                   ;;
+               *)
+                   echo "failed"
+                   exit 1
+           esac
+
+           echo "Testing GPS"
+           ./test-gps "$dev"
+
+           case $? in
+               0)
+                   ;;
+               *)
+                   echo "failed"
+                   exit 1
+           esac
+
+           echo "$PRODUCT-v$VERSION" serial "$serial" is ready to ship
+           ret=0
+           ;;
+       *)
+           echo "Skipping $product $serial $dev"
+           ;;
+    esac
+done
diff --git a/ao-bringup/turnon_easymini b/ao-bringup/turnon_easymini
new file mode 100755 (executable)
index 0000000..0b915c5
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+if [ -x ../ao-tools/ao-flash/ao-flash-lpc ]; then
+       FLASH_LPC=../ao-tools/ao-flash/ao-flash-lpc
+elif [ -x /usr/bin/ao-flash-lpc ]; then
+       FLASH_LPC=/usr/bin/ao-flash-lpc
+else
+       echo "Can't find ao-flash-lpc!  Aborting."
+       exit 1
+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
+PRODUCT=EasyMini
+BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
+echo $FILE
+
+echo "$PRODUCT v$VERSION Turn-On and Calibration Program"
+echo "Copyright 2010 by Bdale Garbee.  Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\t$PRODUCT v$VERSION powered from USB"
+echo "\t\twith ST-Link-V2 cabled to debug header"
+echo
+
+case $# in
+    1)
+       SERIAL="$1"
+       echo "$PRODUCT-$VERSION serial number: $SERIAL" 
+       ;;
+    0)
+       echo -n "$PRODUCT-$VERSION serial number: "
+       read SERIAL
+       ;;
+    *)
+       echo "Usage: $0 <serial-number>" 1>&2
+       exit 1;
+       ;;
+esac
+
+#
+# Use released versions of everything
+#
+FLASH_FILE=~/altusmetrumllc/Binaries/loaders/easymini-v1.0-altos-flash-*.elf
+ALTOS_FILE=~/altusmetrumllc/Binaries/easymini-v1.0-*.elf
+
+#FLASH_FILE=../src/$BASE-v$VERSION/flash-loader/$BASE-v$VERSION-altos-flash-*.elf
+#ALTOS_FILE=../src/$BASE-v$VERSION/*.ihx
+
+echo $FLASH_LPC $FLASH_FILE
+
+$FLASH_LPC $FLASH_FILE || exit 1
+
+sleep 1
+
+echo $USBLOAD $ALTOS_FILE
+
+$USBLOAD --serial=$SERIAL $ALTOS_FILE || exit 1
+
+sleep 2
+
+./test-easymini
+
+exit $?
index ef20e915f863ec1494bf624595b3e3b3bd898263..c4902f31ff68e5f938148cc9db6bddaf364f2bb9 100755 (executable)
@@ -45,7 +45,8 @@ read FREQ
 CAL_VALUE=`nickle -e "floor(434.55 / $FREQ * 1186611 + 0.5)"`
 
 echo "Programming flash with cal value " $CAL_VALUE
-$AOLOAD -D $DONGLE --cal $CAL_VALUE /usr/share/altos/stable/telebt-v1.0*.ihx $SERIAL
+$AOLOAD -D $DONGLE --cal $CAL_VALUE /usr/share/altos/telebt-v1.0*.ihx $SERIAL
 
 echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
+echo $SERIAL","$CAL_VALUE >> cal_values
 echo "Unplug debug cable, power cycle, cu to the board, confirm freq and record power"
index a11683dbb5eada2d6f294468a09172cb44c8c699..ddee5ee81e6fc89091c838554c6b6b5371b421b6 100755 (executable)
@@ -45,4 +45,5 @@ echo "Programming flash with cal value " $CAL_VALUE
 $AOLOAD -D 100 --cal $CAL_VALUE /usr/share/altos/teledongle-v0.2*.ihx $SERIAL
 
 echo "Serial number "$SERIAL" programmed with RF cal value "$CAL_VALUE
+echo $SERIAL","$CAL_VALUE >> cal_values
 echo "Unplug and replug USB, cu to the board, confirm freq and record power"
diff --git a/ao-bringup/turnon_telegps b/ao-bringup/turnon_telegps
new file mode 100755 (executable)
index 0000000..123f0b5
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+if [ -x /usr/bin/ao-flash-lpc ]; then
+       FLASH_LPC=/usr/bin/ao-flash-lpc
+else
+       echo "Can't find ao-flash-lpc!  Aborting."
+       exit 1
+fi
+
+if [ -x /usr/bin/ao-usbload ]; then
+       USBLOAD=/usr/bin/ao-usbload
+else
+       echo "Can't find ao-usbload!  Aborting."
+       exit 1
+fi
+
+VERSION=1.0
+PRODUCT=TeleGPS
+BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'`
+echo $FILE
+
+echo "$PRODUCT v$VERSION Turn-On and Calibration Program"
+echo "Copyright 2014 by Bdale Garbee.  Released under GPL v2"
+echo
+echo "Expectations:"
+echo "\t$PRODUCT v$VERSION powered from USB"
+echo "\t\twith ST-Link-V2 cabled to debug header"
+echo
+
+case $# in
+    1)
+       SERIAL="$1"
+       echo "$PRODUCT-$VERSION serial number: $SERIAL" 
+       ;;
+    0)
+       echo -n "$PRODUCT-$VERSION serial number: "
+       read SERIAL
+       ;;
+    *)
+       echo "Usage: $0 <serial-number>" 1>&2
+       exit 1;
+       ;;
+esac
+
+#
+# Use released versions of everything
+#
+FLASH_FILE=~/altusmetrumllc/Binaries/loaders/telegps-v1.0-altos-flash-*.elf
+ALTOS_FILE=~/altusmetrumllc/Binaries/telegps-v1.0-*.elf
+
+echo $FLASH_LPC $FLASH_FILE
+
+$FLASH_LPC $FLASH_FILE || exit 1
+
+sleep 2
+
+echo $USBLOAD $ALTOS_FILE
+
+$USBLOAD --serial=$SERIAL $ALTOS_FILE || exit 1
+
+sleep 2
+
+dev=`ao-list | awk '/TeleGPS-v'"$VERSION"'/ { print $3; exit(0); }'`
+
+case "$dev" in
+/dev/tty*)
+        echo "TeleGPS found on $dev"
+        ;;
+*)
+        echo 'No TeleGPS-v'"$VERSION"' found'
+        exit 1
+        ;;
+esac
+
+echo 'E 0' > $dev
+
+./test-telegps
+
+SERIAL=$SERIAL ./cal-freq $dev
+
+exit $?
index 3880b197f62183aa04e67f7bb12e56cb9d99f4e9..39a636420a5ada339aff493498526073208413ac 100755 (executable)
@@ -1,17 +1,13 @@
 #!/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
+if [ -x /usr/bin/ao-flash-stm ]; then
+       STMLOAD=/usr/bin/ao-flash-stm
 else
-       echo "Can't find ao-stmload!  Aborting."
+       echo "Can't find ao-flash-stm!  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
+if [ -x /usr/bin/ao-usbload ]; then
        USBLOAD=/usr/bin/ao-usbload
 else
        echo "Can't find ao-usbload!  Aborting."
@@ -19,10 +15,10 @@ else
 fi
 
 VERSION=1.0
-#VERSION=0.1
+REPO=~/altusmetrumllc/Binaries
 
 echo "TeleMega v$VERSION Turn-On and Calibration Program"
-echo "Copyright 2010 by Bdale Garbee.  Released under GPL v2"
+echo "Copyright 2014 by Bdale Garbee.  Released under GPL v2"
 echo
 echo "Expectations:"
 echo "\tTeleMega v$VERSIOn powered from USB"
@@ -34,12 +30,11 @@ read SERIAL
 
 echo $STMLOAD
 
-$STMLOAD --raw ../src/telemega-v$VERSION/flash-loader/*.elf || exit 1
+$STMLOAD $REPO/loaders/telemega-v$VERSION*.elf || exit 1
 
 sleep 2
 
-#$USBLOAD --serial=$SERIAL ../src/telemega-v$VERSION/*.ihx || exit 1
-$USBLOAD --serial=$SERIAL /usr/share/altos/telemega-v$VERSION*.ihx || exit 1
+$USBLOAD --serial=$SERIAL $REPO/telemega-v$VERSION*.elf || exit 1
 
 sleep 2
 
index bcf6239fafa62f7baf65f9fe071efec676769466..80193c4c448f98700f074d5eff3a211f2fe6ced6 100755 (executable)
@@ -39,7 +39,7 @@ sleep 2
 
 $USBLOAD --serial=$SERIAL /usr/share/altos/telemetrum-v$VERSION*.ihx || exit 1
 
-sleep 2
+sleep 5
 
 dev=`ao-list | awk '/TeleMetrum-v'"$VERSION"'/ { print $3; exit(0); }'`
 
old mode 100644 (file)
new mode 100755 (executable)
index 57f632b..7ac5b52
@@ -7,15 +7,10 @@ case "$#" in
 esac
 cmds=/tmp/flash$$
 trap "rm $cmds" 0 1 15
-for file in "$@"; do
-       echo "flash write_image $file"
-done > $cmds
+file="$1"
+echo "program $file verify reset" > $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
index c1f551499ceac969b76072f417bb3f66f49e3e31..0cf03772073c5a503ea5e8364547b42e143e8115 100644 (file)
@@ -26,7 +26,7 @@
 
 #define AO_USB_DESC_STRING             3
 
-struct sym {
+static struct sym {
        unsigned        addr;
        char            *name;
        int             required;
index f1755b824f82ef233a89d6ec9312bdea623700c9..da873838a7f79ad4b06e45be9815510234e8ea1f 100644 (file)
@@ -158,7 +158,8 @@ main (int argc, char **argv)
                                        printf ("\n");
                                        break;
                                case AO_TELEMETRY_MEGA_SENSOR:
-                                       printf ("accel %5d pres %9d temp %5d accel_x %5d accel_y %5d accel_z %5d gyro_x %5d gyro_y %5d gyro_z %5d mag_x %5d mag_y %5d mag_z %5d\n",
+                                       printf ("orient %3d accel %5d pres %9d temp %5d accel_x %5d accel_y %5d accel_z %5d gyro_x %5d gyro_y %5d gyro_z %5d mag_x %5d mag_y %5d mag_z %5d\n",
+                                               telem.mega_sensor.orient,
                                                telem.mega_sensor.accel,
                                                telem.mega_sensor.pres,
                                                telem.mega_sensor.temp,
index 0c8a23dfc60115786aa0be0c57c243cc6d0c159a..fd34fbdcfad8f21f7c0443a89fe312f4c500527e 100644 (file)
@@ -142,6 +142,8 @@ main (int argc, char **argv)
        int                     verbose = 0;
        struct ao_sym           *file_symbols;
        int                     num_file_symbols;
+       uint32_t                flash_base, flash_bound;
+       int                     has_flash_size = 0;
 
        while ((c = getopt_long(argc, argv, "rT:D:c:s:v:", options, NULL)) != -1) {
                switch (c) {
@@ -222,6 +224,14 @@ main (int argc, char **argv)
                                cc_usb_getline(cc, line, sizeof(line));
                                if (!strncmp(line, "altos-loader", 12))
                                        is_loader = 1;
+                               if (!strncmp(line, "flash-range", 11)) {
+                                       int i;
+                                       for (i = 11; i < strlen(line); i++)
+                                               if (line[i] != ' ')
+                                                       break;
+                                       if (sscanf(line + i, "%x %x", &flash_base, &flash_bound) == 2)
+                                               has_flash_size = 1;
+                               }
                                if (!strncmp(line, "software-version", 16))
                                        break;
                        }
@@ -262,6 +272,22 @@ main (int argc, char **argv)
 #endif
        }
 
+       /* If the device can tell us the size of flash, make sure
+        * the image fits in that
+        */
+       if (has_flash_size) {
+               if (load->address < flash_base ||
+                   load->address + load->length > flash_bound)
+               {
+                       fprintf(stderr, "Image does not fit on device.\n");
+                       fprintf(stderr, "  Image base:  %08x bounds %08x\n",
+                               load->address, load->address + load->length);
+                       fprintf(stderr, "  Device base: %08x bounds %08x\n",
+                               flash_base, flash_bound);
+                       done(cc, 1);
+               }
+       }
+
        if (!raw) {
                /* Go fetch existing config values
                 * if available
@@ -295,7 +321,7 @@ main (int argc, char **argv)
        /* 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);
index a8b64098b80602909636a6fdf135efad6a49b0d0..7547c82c69690eda8de608238b4a6e920f9ba4f5 100644 (file)
 #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 },
+       {
+               .name = "ao_romconfig_version",
+               .required = 1
+       },
+       {
+               .name = "ao_romconfig_check",
+               .required = 1
+       },
+       {
+               .name = "ao_serial_number",
+               .required = 1
+       },
+       {
+               .name = "ao_radio_cal",
+               .required = 0
+       },
+       {
+               .name = "ao_usb_descriptors",
+               .required = 0
+       },
 };
 
 #define NUM_SYMBOLS            5
index 9849746091f7c1c866d01992fbc15b2a51c5bc9e..eb510ba2a18321dc2614f8ac17a3adcb3f14e7b4 100644 (file)
@@ -51,7 +51,6 @@ struct ao_hex_image {
 
 struct ao_sym {
        unsigned        addr;
-       unsigned        default_addr;
        char            *name;
        bool            required;
        bool            found;
index c28aceb895d2385eef28bceb8a0ae1514398a2d3..d64c4b30d3d0395cc6ce593d675dfc1ed0fa20b3 100644 (file)
@@ -157,7 +157,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 */
index d7ac138c6e1210b87c6bae203d76569c23812e26..38dfff04936c87e6fbed2b8df73b5286edd92987 100644 (file)
@@ -53,6 +53,7 @@ struct cc_usb {
 
        struct cc_hex_read      hex_buf[CC_NUM_HEX_READ];
        int                     hex_count;
+       int                     show_input;
 
        int                     remote;
 };
@@ -156,7 +157,7 @@ cc_usb_dbg(int indent, uint8_t *bytes, int len)
  */
 
 static int
-_cc_usb_sync(struct cc_usb *cc, int wait_for_input)
+_cc_usb_sync(struct cc_usb *cc, int wait_for_input, int write_timeout)
 {
        int             ret;
        struct pollfd   fds;
@@ -165,7 +166,7 @@ _cc_usb_sync(struct cc_usb *cc, int wait_for_input)
        fds.fd = cc->fd;
        for (;;) {
                if (cc->hex_count || cc->out_count)
-                       timeout = 5000;
+                       timeout = write_timeout;
                else if (wait_for_input && cc->in_pos == cc->in_count)
                        timeout = wait_for_input;
                else
@@ -200,6 +201,10 @@ _cc_usb_sync(struct cc_usb *cc, int wait_for_input)
                                cc->in_count += ret;
                                if (cc->hex_count)
                                        cc_handle_hex_read(cc);
+                               if (cc->show_input && cc->in_count) {
+                                       write(2, cc->in_buf, cc->in_count);
+                                       cc->in_count = 0;
+                               }
                        } else if (ret < 0)
                                perror("read");
                }
@@ -222,7 +227,7 @@ _cc_usb_sync(struct cc_usb *cc, int wait_for_input)
 void
 cc_usb_sync(struct cc_usb *cc)
 {
-       if (_cc_usb_sync(cc, 0) < 0) {
+       if (_cc_usb_sync(cc, 0, 5000) < 0) {
                fprintf(stderr, "USB link timeout\n");
                exit(1);
        }
@@ -263,7 +268,7 @@ int
 cc_usb_getchar_timeout(struct cc_usb *cc, int timeout)
 {
        while (cc->in_pos == cc->in_count) {
-               if (_cc_usb_sync(cc, timeout) < 0) {
+               if (_cc_usb_sync(cc, timeout, 5000) < 0) {
                        fprintf(stderr, "USB link timeout\n");
                        exit(1);
                }
@@ -395,7 +400,7 @@ cc_usb_open_remote(struct cc_usb *cc, int freq, char *call)
                cc_usb_printf(cc, "\nc F %d\nc c %s\np\nE 0\n", freq, call);
                do {
                        cc->in_count = cc->in_pos = 0;
-                       _cc_usb_sync(cc, 100);
+                       _cc_usb_sync(cc, 100, 5000);
                } while (cc->in_count > 0);
                cc->remote = 1;
        }
@@ -412,19 +417,35 @@ cc_usb_close_remote(struct cc_usb *cc)
 
 static struct termios  save_termios;
 
+#include <errno.h>
+
 struct cc_usb *
 cc_usb_open(char *tty)
 {
        struct cc_usb   *cc;
        struct termios  termios;
+       int             i;
 
        if (!tty)
                tty = DEFAULT_TTY;
        cc = calloc (sizeof (struct cc_usb), 1);
        if (!cc)
                return NULL;
-       cc->fd = open(tty, O_RDWR | O_NONBLOCK);
-       if (cc->fd < 0) {
+       i = 0;
+       for (;;) {
+               cc->fd = open(tty, O_RDWR | O_NONBLOCK);
+               if (cc->fd >= 0)
+                       break;
+               i++;
+               if (errno == EBUSY || errno == EPERM || errno == EACCES) {
+                       fprintf(stderr, "open failed, pausing");
+                       perror(tty);
+                       if (i < 20) {
+                               sleep(3);
+                               continue;
+                       }
+               }
+
                perror(tty);
                free (cc);
                return NULL;
@@ -438,7 +459,7 @@ cc_usb_open(char *tty)
        cc_usb_printf(cc, "\nE 0\nm 0\n");
        do {
                cc->in_count = cc->in_pos = 0;
-               _cc_usb_sync(cc, 100);
+               _cc_usb_sync(cc, 100, 5000);
        } while (cc->in_count > 0);
        return cc;
 }
@@ -452,3 +473,26 @@ cc_usb_close(struct cc_usb *cc)
        close (cc->fd);
        free (cc);
 }
+
+int
+cc_usb_write(struct cc_usb *cc, void *buf, int c)
+{
+       uint8_t *b;
+       int this_time;
+
+       b = buf;
+       cc->show_input = 1;
+       while (c > 0) {
+               this_time = c;
+               if (this_time > CC_OUT_BUF - cc->out_count)
+                       this_time = CC_OUT_BUF - cc->out_count;
+               memcpy(cc->out_buf + cc->out_count, b, this_time);
+               cc->out_count += this_time;
+               c -= this_time;
+               b += this_time;
+               while (cc->out_count >= CC_OUT_BUF) {
+                       _cc_usb_sync(cc, 0, -1);
+               }
+       }
+       return 1;
+}
index f11934560a917119a2b6a0d2377e23a412bf1cc5..e08a956b25868747861597bb185ee16c0b066841 100644 (file)
@@ -65,6 +65,9 @@ cc_usb_getline(struct cc_usb *cc, char *line, int max);
 void
 cc_usb_printf(struct cc_usb *cc, char *format, ...);
 
+int
+cc_usb_write(struct cc_usb *cc, void *buf, int c);
+
 void
 cc_usb_open_remote(struct cc_usb *cc, int freq, char *call);
 
index 6be99d1fc5d122152ea92ccca4451383d221ce4f..23dc9d822b20530358a8a9c757b73d3221eb6308 100644 (file)
@@ -18,8 +18,8 @@ dnl
 dnl Process this file with autoconf to create configure.
 
 AC_PREREQ(2.57)
-AC_INIT([altos], 1.3.2)
-AC_CONFIG_SRCDIR([src/core/ao.h])
+AC_INIT([altos], 1.4)
+AC_CONFIG_SRCDIR([src/kernel/ao.h])
 AM_INIT_AUTOMAKE([foreign dist-bzip2])
 AM_MAINTAINER_MODE
 
@@ -29,8 +29,8 @@ AC_SUBST(VERSION_DASH)
 dnl ==========================================================================
 dnl Java library versions
 
-ALTOSUILIB_VERSION=1
-ALTOSLIB_VERSION=3
+ALTOSUILIB_VERSION=2
+ALTOSLIB_VERSION=4
 
 AC_SUBST(ALTOSLIB_VERSION)
 AC_DEFINE(ALTOSLIB_VERSION,$ALTOSLIB_VERSION,[Version of the AltosLib package])
@@ -162,6 +162,20 @@ AM_CONDITIONAL(FATINSTALL, [test "x$FATDIR" != "xnone"])
 
 AC_SUBST(FATDIR)
 
+AC_ARG_WITH(google-key, AS_HELP_STRING([--with-google-key=PATH],
+           [Set the file to read the google maps API key from (defaults to ~/altusmetrumllc/google-maps-api-key)]),
+           [GOOGLEKEYFILE=$withval], [GOOGLEKEYFILE=$HOME/altusmetrumllc/google-maps-api-key])
+
+if test -r "$GOOGLEKEYFILE" -a -s "$GOOGLEKEYFILE"; then
+       GOOGLEKEY='"'`cat "$GOOGLEKEYFILE"`'"'
+       HAVE_GOOGLE_KEY="yes"
+else
+       GOOGLEKEY='null'
+       HAVE_GOOGLE_KEY="no"
+fi
+
+AC_SUBST(GOOGLEKEY)
+
 AC_PROG_CC
 AC_PROG_INSTALL
 AC_PROG_LN_S
@@ -487,6 +501,7 @@ AC_OUTPUT([
 Makefile
 src/Makedefs
 altoslib/Makefile
+icon/Makefile
 altosuilib/Makefile
 altosuilib/AltosUIVersion.java
 altosui/Makefile
@@ -496,6 +511,9 @@ libaltos/Makefile
 micropeak/Makefile
 micropeak/Info.plist
 micropeak/micropeak-windows.nsi
+telegps/Makefile
+telegps/Info.plist
+telegps/telegps-windows.nsi
 altosdroid/Makefile
 altosdroid/local.properties
 ao-tools/Makefile
@@ -536,11 +554,12 @@ echo "    STlink support..............: ${HAVE_STLINK}"
 echo "    Local pdclib................: ${HAVE_PDCLIB}"
 echo "    i386 and amd64 libaltos.....: ${MULTI_ARCH}"
 echo ""
-echo "  Java paths"
+echo "  Java"
 echo "    freetts.....................: ${FREETTS}"
 echo "    jfreechart..................: ${JFREECHART}"
 echo "    jcommon.....................: ${JCOMMON}"
 echo "    JVM include.................: ${JVM_INCLUDE}"
+echo "    Google maps API key.........: ${HAVE_GOOGLE_KEY}"
 if test x${ANDROID_SDK} != "xno"; then
 echo ""
 echo "  Android path"
diff --git a/debian/altos.desktop b/debian/altos.desktop
deleted file mode 100644 (file)
index 88b99f9..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[Desktop Entry]
-Type=Application
-Name=AltOS UI
-GenericName=Altus Metrum Ground Station
-Comment=View and log downlink data from Altus Metrum products
-Icon=/usr/share/pixmaps/altusmetrum.xpm
-Exec=/usr/bin/altosui %f
-Terminal=false
-MimeType=text/plain;
-Categories=Education;Electronics;Science;
index 05f0eec5627eeba39f26b8b8193340ac08e475e0..50f21eb1c5adb35f277b11282b8bd5e7dd12122c 100644 (file)
@@ -1,4 +1,3 @@
-debian/altos.desktop   usr/share/applications
 debian/altusmetrum.xpm usr/share/pixmaps
 src/*/*.ihx            usr/share/altos
 src/*/*.map            usr/share/altos
index f23a841a313241ce0d2c3bc5de1eb04a093d33cf..3c9e8999f4c8e2a80a7104d7a2ddbbd8dfaf683e 100644 (file)
@@ -3,7 +3,7 @@ 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, 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
+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, icoutils, librsvg2-bin, icnsutils, graphicsmagick | imagemagick
 Standards-Version: 3.9.5
 Homepage: http://altusmetrum.org/AltOS
 Vcs-Git: git://git.gag.com/fw/altos
index 83731fbe8f1998378f96c53472da2a76e3e8870c..254e63c43387ee6ecf326049430beb01fd63f2d2 100644 (file)
@@ -14,7 +14,8 @@ RELNOTES=\
        release-notes-1.2.1.html \
        release-notes-1.3.html \
        release-notes-1.3.1.html \
-       release-notes-1.3.2.html
+       release-notes-1.3.2.html \
+       release-notes-1.4.html
 
 PICTURES=\
        altosui.png \
@@ -34,6 +35,19 @@ PICTURES=\
        landed.png \
        launch-pad.png \
        load-maps.png \
+       micropeak-app.png \
+       micropeak-back.jpg \
+       micropeak-device-dialog.png \
+       micropeak-dime.jpg \
+       micropeak-download.png \
+       micropeak-graph-configure.png \
+       micropeak-graph.png \
+       micropeak-preferences.png \
+       micropeak-raw-data.png \
+       micropeak-save-dialog.png \
+       micropeak-statistics.png \
+       MicroPeakUSB-2.0-inuse.jpg \
+       MicroPeakUSB-2.0.jpg \
        scan-channels.png \
        site-map.png \
        table.png \
@@ -41,21 +55,23 @@ PICTURES=\
        telemetrum-v1.1-thside.jpg \
        telemini-v1-top.jpg \
        telemini-v2-top.jpg
+
 SVG=\
-       easymini-outline.svg \
-       telemega-outline.svg \
+       easymini.svg \
+       telemega.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
+HTML=altusmetrum.html altos.html telemetry.html companion.html micropeak.html telegps.html $(RELNOTES)
+PDF=altusmetrum.pdf altos.pdf telemetry.pdf companion.pdf micropeak.pdf telegps.pdf \
+       telemetrum-outline.pdf telemega-outline.pdf easymini-outline.pdf
 HTMLSTYLE=/usr/share/xml/docbook/stylesheet/docbook-xsl/html/docbook.xsl
 FOSTYLE=xorg-fo.xsl
 TEMPLATES=titlepage.templates.xsl
 PDFSTYLE=
 IMAGES=$(PICTURES) $(SVG)
-DOC=$(HTML) $(PDF) $(PICTURES)
+DOC=$(HTML) $(PDF) $(IMAGES)
 
 .SUFFIXES: .xml .xsl .html .pdf
 
index 5b9e12e8fa4b84d63f24558d9f54d9113e6e98b8..6092dfcb9f0155cef0a4436f08df0d896125cad4 100644 (file)
        <title>__sfr, __sfr16, __sfr32, __sbit</title>
        <para>
          Access to physical registers in the device use this mode
-         which declares the variable name, it's type and the
+         which declares the variable name, its type and the
          address it lives at. No memory is allocated for these
          variables.
        </para>
          ao_dma_abort(uint8_t id)
        </programlisting>
        <para>
-         Terminate any in-progress DMA transation, marking its
+         Terminate any in-progress DMA transaction, marking its
          'done' variable with the AO_DMA_ABORTED bit.
        </para>
       </section>
          ao_dma_abort(uint8_t id)
        </programlisting>
        <para>
-         Terminate any in-progress DMA transation, marking its
+         Terminate any in-progress DMA transaction, marking its
          'done' variable with the AO_DMA_ABORTED bit.
        </para>
       </section>
     <title>Stdio interface</title>
     <para>
       AltOS offers a stdio interface over USB, serial and the RF
-      packet link. This provides for control of the device localy or
+      packet link. This provides for control of the device locally or
       remotely. This is hooked up to the stdio functions by providing
       the standard putchar/getchar/flush functions. These
       automatically multiplex the available communication channels;
       <para>
        Flushes the current console device output buffer. Any
        pending characters will be delivered to the target device.
-      xo         </para>
+      </para>
     </section>
     <section>
       <title>ao_add_stdio</title>
index fb08f5c642fa32f284ba2958a14d76a77b762794..5ccbee9f0c0ce10517ce2b65786f55ad9f46c375 100644 (file)
       </para>
     </legalnotice>
     <revhistory>
+      <revision>
+       <revnumber>1.4</revnumber>
+       <date>15 June 2014</date>
+       <revremark>
+         Major release adding TeleGPS support.
+       </revremark>
+      </revision>
       <revision>
        <revnumber>1.3.2</revnumber>
        <date>24 January 2014</date>
@@ -1539,10 +1546,13 @@ NAR #88757, TRA #12200
         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
-        the altimeter completes initialization and self test, and decides 
-       which mode to enter next.
+        At power on, the altimeter will beep out the battery voltage
+        to the nearest tenth of a volt.  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. Then there will be a short pause while the altimeter
+        completes initialization and self test, and decides which mode
+        to enter next.
       </para>
       <para>
        Here's a short summary of all of the modes and the beeping (or
@@ -1570,7 +1580,7 @@ NAR #88757, TRA #12200
              <row>
                <entry>Startup</entry>
                <entry>S</entry>
-               <entry>dit dit dit</entry>
+               <entry>battery voltage in decivolts</entry>
                <entry>
                  <para>
                    Calibrating sensors, detecting orientation.
@@ -2180,6 +2190,20 @@ NAR #88757, TRA #12200
           way quite happily, including Keith's successful L3 cert.
         </para>
       </section>
+      <section>
+       <title>Apogee Lockout</title>
+       <para>
+         Apogee lockout is the number of seconds after boost where
+         the flight computer will not fire the apogee charge, even if
+         the rocket appears to be at apogee. This is often called
+         'Mach Delay', as it is intended to prevent a flight computer
+         from unintentionally firing apogee charges due to the pressure
+         spike that occurrs across a mach transition. Altus Metrum
+         flight computers include a Kalman filter which is not fooled
+         by this sharp pressure increase, and so this setting should
+         be left at the default value of zero to disable it.
+       </para>
+      </section>
       <section>
         <title>Main Deployment Altitude</title>
         <para>
@@ -2755,10 +2779,19 @@ NAR #88757, TRA #12200
           dark blue for main, and black for landed.
         </para>
         <para>
-          The map's scale is approximately 3m (10ft) per pixel. The map
+          The map's default scale is approximately 3m (10ft) per pixel. The map
           can be dragged using the left mouse button. The map will attempt
           to keep the rocket roughly centered while data is being received.
         </para>
+       <para>
+         You can adjust the style of map and the zoom level with
+         buttons on the right side of the map window. You can draw a
+         line on the map by moving the mouse over the map with a
+         button other than the left one pressed, or by pressing the
+         left button while also holding down the shift key. The
+         length of the line in real-world units will be shown at the
+         start of the line.
+       </para>
         <para>
           Images are fetched automatically via the Google Maps Static API,
           and cached on disk for reuse. If map images cannot be downloaded,
@@ -2770,6 +2803,24 @@ NAR #88757, TRA #12200
          before you leave home; check out the 'Preload Maps' section below.
        </para>
       </section>
+      <section>
+        <title>Ignitor</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="ignitor.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+        <para>
+          TeleMega includes four additional programmable pyro
+          channels. The Ignitor tab shows whether each of them has
+          continuity. If an ignitor has a low resistance, then the
+          voltage measured here will be close to the pyro battery
+          voltage. A value greater than 3.2V is required for a 'GO'
+          status.
+       </para>
+      </section>
     </section>
     <section>
       <title>Save Flight Data</title>
@@ -3036,7 +3087,21 @@ NAR #88757, TRA #12200
         </para>
       </section>
       <section>
-        <title>Radio Frequency</title>
+        <title>Apogee Lockoug</title>
+        <para>
+         Apogee lockout is the number of seconds after boost where
+         the flight computer will not fire the apogee charge, even if
+         the rocket appears to be at apogee. This is often called
+         'Mach Delay', as it is intended to prevent a flight computer
+         from unintentionally firing apogee charges due to the pressure
+         spike that occurrs across a mach transition. Altus Metrum
+         flight computers include a Kalman filter which is not fooled
+         by this sharp pressure increase, and so this setting should
+         be left at the default value of zero to disable it.
+        </para>
+      </section>
+      <section>
+        <title>Frequency</title>
         <para>
           This configures which of the frequencies to use for both
           telemetry and packet command mode. Note that if you set this
@@ -3094,12 +3159,11 @@ NAR #88757, TRA #12200
        </para>
       </section>
       <section>
-        <title>Ignite Mode</title>
+        <title>Ignitor Firing Mode</title>
        <para>
-         TeleMetrum and TeleMini provide two igniter channels as they
-         were originally designed as dual-deploy flight
-         computers. This configuration parameter allows the two
-         channels to be used in different configurations.
+         This configuration parameter allows the two standard ignitor
+         channels (Apogee and Main) to be used in different
+         configurations.
        </para>
           <variablelist>
            <varlistentry>
@@ -3169,6 +3233,16 @@ NAR #88757, TRA #12200
          </varlistentry>
        </variablelist>
       </section>
+      <section>
+        <title>Beeper Frequency</title>
+       <para>
+         The beeper on all Altus Metrum flight computers works best
+         at 4000Hz, however if you have more than one flight computer
+         in a single airframe, having all of them sound at the same
+         frequency can be confusing. This parameter lets you adjust
+         the base beeper frequency value.
+       </para>
+      </section>
       <section>
        <title>Configure Pyro Channels</title>
        <informalfigure>
@@ -3194,6 +3268,11 @@ NAR #88757, TRA #12200
          configuration values, so you can use different values for
          the same condition with different channels.
        </para>
+       <para>
+         At the bottom of the window, the 'Pyro Firing Time'
+         configuration sets the length of time (in seconds) which
+         each of these pyro channels will fire for.
+       </para>
        <para>
          Once you have selected the appropriate configuration for all
          of the necessary pyro channels, you can save the pyro
@@ -3481,9 +3560,62 @@ NAR #88757, TRA #12200
        and name of the site. The contents of this list are actually
        downloaded from our server at run-time, so as new sites are sent 
        in, they'll get automatically added to this list.
+       If the launch site isn't in the list, you can manually enter the lat/lon values
       </para>
       <para>
-       If the launch site isn't in the list, you can manually enter the lat/lon values
+       There are four different kinds of maps you can view; you can
+       select which to download by selecting as many as you like from
+       the available types:
+       <variablelist>
+         <varlistentry>
+           <term>Hybrid</term>
+           <listitem>
+             <para>
+               A combination of satellite imagery and road data. This
+               is the default view.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Satellite</term>
+           <listitem>
+             <para>
+               Just the satellite imagery without any annotation.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Roadmap</term>
+           <listitem>
+             <para>
+               Roads, political boundaries and a few geographic features.
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Terrain</term>
+           <listitem>
+             <para>
+               Contour intervals and shading that show hills and
+               valleys.
+             </para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </para>
+      <para>
+       You can specify the range of zoom levels to download; smaller
+       numbers show more area with less resolution. The default
+       level, 0, shows about 3m/pixel. One zoom level change
+       doubles or halves that number.
+      </para>
+      <para>
+       The Tile Radius value sets how large an area around the center
+       point to download. Each tile is 512x512 pixels, and the
+       'radius' value specifies how many tiles away from the center
+       will be downloaded. Specify a radius of 0 and you get only the
+       center tile. A radius of 1 loads a 3x3 grid, centered on the
+       specified location.
       </para>
       <para>
        Clicking the 'Load Map' button will fetch images from Google
@@ -5127,7 +5259,8 @@ NAR #88757, TRA #12200
       <informalfigure>
        <mediaobject id="TeleMegaTemplate">
          <imageobject>
-           <imagedata format="SVG" fileref="telemega-outline.svg"/>
+           <imagedata format="SVG" fileref="telemega.svg"
+                      scalefit="0" scale="100" align="center" />
          </imageobject>
        </mediaobject>
       </informalfigure>
@@ -5141,7 +5274,8 @@ NAR #88757, TRA #12200
       <informalfigure>
        <mediaobject id="TeleMetrumTemplate">
          <imageobject>
-           <imagedata format="SVG" fileref="telemetrum.svg"/>
+           <imagedata format="SVG" fileref="telemetrum.svg"
+                      scalefit="0" scale="100" align="center" />
          </imageobject>
        </mediaobject>
       </informalfigure>
@@ -5155,7 +5289,8 @@ NAR #88757, TRA #12200
       <informalfigure>
        <mediaobject id="MiniTemplate">
          <imageobject>
-           <imagedata format="SVG" fileref="easymini-outline.svg"/>
+           <imagedata format="SVG" fileref="easymini.svg"
+                      scalefit="0" scale="100" align="center" />
          </imageobject>
        </mediaobject>
       </informalfigure>
@@ -5169,7 +5304,8 @@ NAR #88757, TRA #12200
       <informalfigure>
        <mediaobject id="TeleMiniTemplate">
          <imageobject>
-           <imagedata format="SVG" fileref="telemini.svg"/>
+           <imagedata format="SVG" fileref="telemini.svg"
+                      scalefit="0" scale="100" align="center" />
          </imageobject>
        </mediaobject>
       </informalfigure>
@@ -5277,6 +5413,13 @@ NAR #88757, TRA #12200
   </appendix>
   <appendix>
     <title>Release Notes</title>
+    <simplesect>
+      <title>Version 1.4</title>
+      <xi:include
+         xmlns:xi="http://www.w3.org/2001/XInclude"
+         href="release-notes-1.4.xsl"
+         xpointer="xpointer(/article/*)"/>
+    </simplesect>
     <simplesect>
       <title>Version 1.3.2</title>
       <xi:include
index d486d19ca12b3c4ffca6a7ec49b7964b6ca56a0f..2d62f06e51aaafc68ac291dbc54f5a3557c23d79 100644 (file)
Binary files a/doc/ascent.png and b/doc/ascent.png differ
index afb1932566512259d4036692fdd6976ec628f265..514db3eda660b98f93502aa021a311265384f4bb 100644 (file)
Binary files a/doc/configure-altimeter.png and b/doc/configure-altimeter.png differ
index 1c6ae066db5ac7cb7646fb62b804cf8f5b5e5753..599d45b589cb4a1618ea107031a59900e4bac55c 100644 (file)
Binary files a/doc/configure-pyro.png and b/doc/configure-pyro.png differ
index 4ac4b9624635753801724c4e03757ebcd0a498e8..5a7baadd7bb6d80982c4fb9307d308736be0f8ad 100644 (file)
Binary files a/doc/descent.png and b/doc/descent.png differ
diff --git a/doc/easymini-outline.pdf b/doc/easymini-outline.pdf
deleted file mode 100644 (file)
index a1a0b19..0000000
Binary files a/doc/easymini-outline.pdf and /dev/null differ
diff --git a/doc/easymini-outline.svg b/doc/easymini-outline.svg
deleted file mode 100644 (file)
index 40faddb..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-<?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-outline.xsl b/doc/easymini-outline.xsl
new file mode 100644 (file)
index 0000000..8812532
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
+<article>
+    <title>EasyMini Outline and Hole Pattern</title>
+    <para>
+      This image, when printed, provides a precise template for the
+      mounting holes in EasyMini.  EasyMini has 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="EasyMiniTemplate">
+       <imageobject>
+         <imagedata format="SVG" fileref="easymini.svg"
+                    scalefit="0" scale="100" align="center" />
+       </imageobject>
+      </mediaobject>
+    </informalfigure>
+</article>
+
+<!-- LocalWords: Altusmetrum
+-->
diff --git a/doc/easymini.svg b/doc/easymini.svg
new file mode 100644 (file)
index 0000000..8a9cba0
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<svg
+       xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   width="1.75in"
+   height="1.05in"
+   viewBox="0 0 175 105"
+   preserveaspectratio="none"
+   id="svg2"
+   version="1.1">
+  <g transform="translate(12.5,12.5)"
+     style="fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:miter;font-size:20">
+    <!-- outline -->
+    <rect width="150" height="80" x="0" y="0"/>
+    <!-- holes -->
+    <path d="M12.5,12.5 m-6.25,0 a6.25,6.25,0,1,0,12.5,0 a6.25,6.25,0,1,0,-12.5,0 l12.5,0 m-6.25,-6.25 l0,12.5"/>
+    <path d="M137.5,12.5 m-6.25,0 a6.25,6.25,0,1,0,12.5,0 a6.25,6.25,0,1,0,-12.5,0 l12.5,0 m-6.25,-6.25 l0,12.5"/>
+    <path d="M12.5,67.5 m-6.25,0 a6.25,6.25,0,1,0,12.5,0 a6.25,6.25,0,1,0,-12.5,0 l12.5,0 m-6.25,-6.25 l0,12.5"/>
+    <path d="M137.5,67.5 m-6.25,0 a6.25,6.25,0,1,0,12.5,0 a6.25,6.25,0,1,0,-12.5,0 l12.5,0 m-6.25,-6.25 l0,12.5"/>
+    <!-- arrow -->
+    <path d="M25,40 l100,0"/>
+    <path style="fill:#000000;stroke:none" d="M125,35 l10,5 l-10,5 z"/>
+    <!-- label -->
+    <text x="75" y="35" style="fill:#000000;stroke:none" text-anchor="middle">EasyMini</text>
+    <g transform="rotate(90)">
+      <text x="40" y="-133" style="fill:#000000;stroke:none" text-anchor="middle">UP</text>
+    </g>
+  </g>
+</svg>
\ No newline at end of file
index d3374ba84d9b0c81eb5b0c1226fcfe869c89a615..ed0d51124693a83a434ff43534cec68c569a8052 100644 (file)
Binary files a/doc/graph-configure.png and b/doc/graph-configure.png differ
index fd0fb1344b116d5e0734297b5a34db9e8a30010f..bcea5ff845c147c987458d27fa33168ab7fd7112 100644 (file)
Binary files a/doc/graph-map.png and b/doc/graph-map.png differ
diff --git a/doc/ignitor.png b/doc/ignitor.png
new file mode 100644 (file)
index 0000000..d1f5aeb
Binary files /dev/null and b/doc/ignitor.png differ
index 777d2445abb16aa45c4fd73a046059a37df2aa71..a58cfbf431807b6eacb7f838996fbdc86cfb5af6 100644 (file)
Binary files a/doc/landed.png and b/doc/landed.png differ
index a7a05c08acaaea467f5bedb9c90077fe55b51d9b..f2c41e6b2d50b64fe39ecbc8fd525b11fb721dd2 100644 (file)
Binary files a/doc/launch-pad.png and b/doc/launch-pad.png differ
index dc7ea64c087fcadb095f0ed086cfa973bd753218..ae98c9a59a9c084c92b60b75e9763ae1c5f49600 100644 (file)
Binary files a/doc/load-maps.png and b/doc/load-maps.png differ
index 66b04072a7634cc3b047adedab05f411554725cd..dafe36820650fa73f87da3691e7af758d74d2621 100644 (file)
@@ -10,7 +10,7 @@
       <surname>Packard</surname>
     </author>
     <copyright>
-      <year>2012</year>
+      <year>2014</year>
       <holder>Bdale Garbee and Keith Packard</holder>
     </copyright>
     <mediaobject>
diff --git a/doc/release-notes-1.4.xsl b/doc/release-notes-1.4.xsl
new file mode 100644 (file)
index 0000000..2893f1a
--- /dev/null
@@ -0,0 +1,204 @@
+<?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.4 is a major release. It includes support for our new
+    TeleGPS product, new features and bug fixes in in the flight
+    software for all our boards and the AltosUI ground station
+  </para>
+  <para>
+    AltOS New Features
+    <itemizedlist>
+      <listitem>
+       <para>
+         Add support for TeleGPS boards.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Replace the 'dit dit dit' tones at startup with the current
+         battery voltage, measured in tenths of a volt. This lets you
+         check the battery voltage without needing telemetry, which
+         is especially useful on EasyMini.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Change state beeping to "Farnsworth spacing", which means
+         they're quite a bit faster than before, and so they take
+         less time to send.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Make the beeper tone configurable, making it possible to
+         distinguish between two Altus Metrum products in the same ebay.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Make the firing time for extra pyro channels configurable,
+         allowing longer (or shorter) than the default 50ms.  Only relevant
+         for TeleMega at this time.
+       </para>
+      </listitem>
+    </itemizedlist>
+  </para>
+  <para>
+    AltOS Fixes
+    <itemizedlist>
+      <listitem>
+       <para>
+         Fix bug preventing the selection of the 'Flight State After'
+         mode in pyro configuration.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Fix bug where erasing flights would reset the flight number
+         to 2 on TeleMega and TeleMetrum v2.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Fix u-Blox GPS driver to mark course and speed data as being
+         present.
+       </para>
+      </listitem>
+    </itemizedlist>
+  </para>
+  <para>
+    AltosUI New Features
+    <itemizedlist>
+      <listitem>
+       <para>
+         Add zooming and new content types (terrain and road maps) to
+         map view. Change map storage format from PNG to Jpeg, which
+         saves a huge amount of disk space. You will need to
+         re-download all of your pre-loaded map images.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Add a distance measuring device to the maps view. Select
+         this by using any button other than the left one, or by
+         pressing shift or control on the keyboard while using the
+         left button.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Add new 'Ignitor' tab to the flight monitor display for
+         TeleMega's extra ignitors.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Increase the width of data lines in the graphs to make them
+         easier to read.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Add additional ignitor firing marks and voltages to the
+         graph so you can see when the ignitors fired, along with
+         the ignitor voltages.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Add GPS course, ground speed and climb rate as optional
+         graph elements.
+       </para>
+      </listitem>
+    </itemizedlist>
+  </para>
+  <para>
+    AltosUI Fixes
+    <itemizedlist>
+      <listitem>
+       <para>
+         When flashing new firmware, re-try opening the device as
+         sometimes it takes a while for the underlying operating
+         system to recognize that the device has rebooted in
+         preparation for the flashing operation.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Hide Tilt Angle in ascent tab for devices that don't have a gyro.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Filter out speed and acceleration spikes caused by ejection
+         charge firing when computing the maximum values. This
+         provides a more accurate reading of those maximums.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Fix EasyMini voltage displays. Early EasyMini prototypes
+         used a 3.0V regulator, and AltosUI still used that value as
+         the basis of the computation. Production EasyMini boards
+         have always shipped with a 3.3V regulator. Also, purple
+         EasyMini boards sensed the battery voltage past the blocking
+         diode, resulting in a drop of about 150mV from the true
+         battery voltage. Compensate for that when displaying the
+         value.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Display error message when trying to configure maximum
+         flight log size while the flight computer still has flight
+         data stored.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Handle TeleMetrum and TeleMini eeprom files generated with
+         pre-1.0 firmware. Those ancient versions didn't report the
+         log format, so just use the product name instead.
+       </para>
+      </listitem>
+    </itemizedlist>
+  </para>
+  <para>
+    TeleGPS Application
+    <itemizedlist>
+      <listitem>
+       <para>
+         New application designed for use with TeleGPS boards.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Shares code with AltosUI, mostly just trimmed down to focus
+         on TeleGPS-related functions.
+       </para>
+      </listitem>
+    </itemizedlist>
+  </para>
+  <para>
+    Documentation changes
+    <itemizedlist>
+      <listitem>
+       <para>
+         Re-create the drill template images; they should print
+         correctly from Firefox at least. Ship these as individual
+         PDF files so they're easy to print.
+       </para>
+      </listitem>
+      <listitem>
+       <para>
+         Add a description of the 'Apogee Lockout' setting, which
+         prevents the apogee charge from firing for a configurable
+         amount of time after boost.
+       </para>
+      </listitem>
+    </itemizedlist>
+  </para>
+</article>
index 755e73619234966c048d2ac788f134a5cf9a592c..ebac1dfbbc9e22de1de2e4fcd41a39bece03d9a9 100644 (file)
Binary files a/doc/site-map.png and b/doc/site-map.png differ
diff --git a/doc/telegps-configure.png b/doc/telegps-configure.png
new file mode 100644 (file)
index 0000000..56cb203
Binary files /dev/null and b/doc/telegps-configure.png differ
diff --git a/doc/telegps-graph-configure.png b/doc/telegps-graph-configure.png
new file mode 100644 (file)
index 0000000..67eb5d9
Binary files /dev/null and b/doc/telegps-graph-configure.png differ
diff --git a/doc/telegps-graph-graph.png b/doc/telegps-graph-graph.png
new file mode 100644 (file)
index 0000000..443ada0
Binary files /dev/null and b/doc/telegps-graph-graph.png differ
diff --git a/doc/telegps-graph-map.png b/doc/telegps-graph-map.png
new file mode 100644 (file)
index 0000000..dddea22
Binary files /dev/null and b/doc/telegps-graph-map.png differ
diff --git a/doc/telegps-graph-stats.png b/doc/telegps-graph-stats.png
new file mode 100644 (file)
index 0000000..d181ce5
Binary files /dev/null and b/doc/telegps-graph-stats.png differ
diff --git a/doc/telegps-info.png b/doc/telegps-info.png
new file mode 100644 (file)
index 0000000..cc279b8
Binary files /dev/null and b/doc/telegps-info.png differ
diff --git a/doc/telegps-location.png b/doc/telegps-location.png
new file mode 100644 (file)
index 0000000..e32b14c
Binary files /dev/null and b/doc/telegps-location.png differ
diff --git a/doc/telegps-map.png b/doc/telegps-map.png
new file mode 100644 (file)
index 0000000..f5557de
Binary files /dev/null and b/doc/telegps-map.png differ
diff --git a/doc/telegps-preferences.png b/doc/telegps-preferences.png
new file mode 100644 (file)
index 0000000..ad14fd8
Binary files /dev/null and b/doc/telegps-preferences.png differ
diff --git a/doc/telegps-scan.png b/doc/telegps-scan.png
new file mode 100644 (file)
index 0000000..9b19e68
Binary files /dev/null and b/doc/telegps-scan.png differ
diff --git a/doc/telegps-status.png b/doc/telegps-status.png
new file mode 100644 (file)
index 0000000..dc338f0
Binary files /dev/null and b/doc/telegps-status.png differ
diff --git a/doc/telegps-table.png b/doc/telegps-table.png
new file mode 100644 (file)
index 0000000..b3c82e8
Binary files /dev/null and b/doc/telegps-table.png differ
diff --git a/doc/telegps-v1.0-top.jpg b/doc/telegps-v1.0-top.jpg
new file mode 100644 (file)
index 0000000..ac122f2
Binary files /dev/null and b/doc/telegps-v1.0-top.jpg differ
diff --git a/doc/telegps.xsl b/doc/telegps.xsl
new file mode 100644 (file)
index 0000000..836c3d9
--- /dev/null
@@ -0,0 +1,1300 @@
+<?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>TeleGPS Owner's Manual</title>
+  <subtitle>A recording GPS tracker</subtitle>
+  <bookinfo>
+    <author>
+      <firstname>Keith</firstname>
+      <surname>Packard</surname>
+    </author>
+    <copyright>
+      <year>2014</year>
+      <holder>Bdale Garbee and Keith Packard</holder>
+    </copyright>
+    <mediaobject>
+      <imageobject>
+       <imagedata fileref="telegps-v1.0-top.jpg" width="4in"/>
+      </imageobject>
+    </mediaobject>
+    <legalnotice>
+      <para>
+        This document is released under the terms of the
+        <ulink url="http://creativecommons.org/licenses/by-sa/3.0/">
+          Creative Commons ShareAlike 3.0
+        </ulink>
+        license.
+      </para>
+    </legalnotice>
+    <revhistory>
+      <revision>
+       <revnumber>1.4</revnumber>
+       <date>13 June 2014</date>
+       <revremark>
+         Initial release
+       </revremark>
+      </revision>
+    </revhistory>
+  </bookinfo>
+  <dedication>
+    <title>Acknowledgements</title>
+    <para>
+      Have fun using these products, and we hope to meet all of you
+      out on the rocket flight line somewhere.
+      <literallayout>
+Bdale Garbee, KB0G
+NAR #87103, TRA #12201
+
+Keith Packard, KD7SQG
+NAR #88757, TRA #12200
+      </literallayout>
+    </para>
+  </dedication>
+  <chapter>
+    <title>Quick Start Guide</title>
+    <para>
+      TeleGPS is designed to be easy to use. Requiring no external
+      components, flying takes just a few steps.
+    </para>
+    <para>
+      First, download and install the software from <ulink
+      url="http://altusmetrum.org/AltOS"/>. This will make sure that
+      you have the right device drivers installed.
+    </para>
+    <para>
+      Next, plug in the battery and USB cable and connect TeleGPS to
+      your computer. This will charge the battery and allow you to
+      configure the device.
+    </para>
+    <para>
+      Start the TeleGPS application and set the callsign and frequency
+      on your TeleGPS device; refer to the Configure TeleGPS section
+      in the TeleGPS Application chapter for instructions.
+    </para>
+    <para>
+      Unplug TeleGPS when the battery charger light goes green. This
+      will enable the radio and logging portions of the TeleGPS
+      firmware.
+    </para>
+    <para>
+      Connect TeleDongle to your computer and start TeleGPS or start
+      AltosDroid on your android device and connect to TeleBT. Set the
+      frequency to match the TeleGPS and you should be receiving telemetry.
+    </para>
+  </chapter>
+  <chapter>
+    <title>Handling Precautions</title>
+    <para>
+      All Altus Metrum products are sophisticated electronic devices.  
+      When handled gently and properly installed in an air-frame, they
+      will deliver impressive results.  However, as with all electronic 
+      devices, there are some precautions you must take.
+    </para>
+    <para>
+      The Lithium polymer batteries have an
+      extraordinary power density.  This is great because we can fly with
+      much less battery mass... but if they are punctured
+      or their contacts are allowed to short, they can and will release their
+      energy very rapidly!
+      Thus we recommend that you take some care when handling TeleGPS
+      to keep conductive material from coming in contact with the exposed metal elements.
+    </para>
+    <para>
+      As with all other rocketry electronics, Altus Metrum devices must 
+      be protected from exposure to corrosive motor exhaust and ejection 
+      charge gasses.
+    </para>
+  </chapter>
+  <chapter>
+    <title>TeleGPS Hardware</title>
+    <section>
+      <title>Hooking Up Lithium Polymer Batteries</title>
+      <para>
+       TeleGPS has a two pin JST PH series connector to connect up
+       a single-cell Lithium Polymer cell (3.7V nominal). You can
+       purchase matching batteries from the Altus Metrum store, or
+       other vendors, or you can make your own. Pin 1 of the
+       connector is positive, pin 2 is negative. Spark Fun sells a
+       cable with the connector attached, which they call a <ulink
+       url="https://www.sparkfun.com/products/9914">JST Jumper 2
+       Wire Assembly</ulink>.
+      </para>
+      <para>
+       Many RC vendors also sell lithium polymer batteries with
+       this same connector. All that we have found use the opposite
+       polarity, and if you use them that way, you will damage or
+       destroy TeleGPS.
+      </para>
+    </section>
+    <section>
+      <title>On-board Data Recording</title>
+      <para>
+       TeleGPS logs GPS data at a user-configurable rate. Data are
+       logged to a 2MB on-board flash memory part, which can be
+       partitioned into several equal-sized blocks, one for each
+       flight. 64kB of this storage are reserved to hold
+       configuration data, leaving 1984kB for flight 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 you can store more flights.
+      </para>
+      <para>
+       To compute the amount of space needed for a single log, you
+       can divide the expected time (in seconds) by the sample period
+       (by default, 1 second per sample) and then multiply the result
+       by 32 bytes per sample. For instance, a sample period of 1
+       second and a flight lasting one hour will take 32 * 3600 =
+       115200 bytes. TeleGPS does try to reduce log space used by not
+       recording position information when it isn't moving, so actual
+       space consumed may be less than this.
+      </para>
+      <para>
+       The default size allows for four flights of 496kB each, which
+       provides over four hours of logging at 1 sample per second.
+      </para>
+      <para>
+       TeleGPS will not overwrite existing flight data, so be sure to
+       download flight data and erase it from the onboard flash
+       before it fills up. TeleGPS will still report telemetry even
+       if memory is full, so the only thing you will lose is the
+       on-board data log.
+      </para>
+    </section>
+    <section>
+      <title>Installation</title>
+      <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>
+       TeleGPS uses an integrate GPS patch antenna and won't
+       receive GPS signals if installed inside a metal or carbon
+       fiber compartment. Test GPS reception and telemetry
+       transmission with the system installed and all other
+       electronics powered up to verify signal reception and make
+       sure there isn't any interference from other systems.
+      </para>
+    </section>
+  </chapter>
+  <chapter>
+    <title>System Operation</title>
+    <section>
+      <title>GFSK Telemetry</title>
+      <para>
+        TeleGPS's native telemetry system doesn't use a 'normal packet
+        radio' mode like APRS because it's not very efficient.  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.
+      </para>
+    </section>
+    <section>
+      <title>APRS</title>
+      <para>
+       TeleGPS can send APRS if desired, and the
+       interval between APRS packets can be configured. As each APRS
+       packet takes a full second to transmit, we recommend an
+       interval of at least 5 seconds to avoid consuming too much
+       battery power or radio channel bandwidth. You can configure
+       the APRS interval using AltosUI; that process is described in
+       the Configure Altimeter section of the AltosUI chapter.
+      </para>
+      <para>
+       AltOS uses the APRS compressed position report data format,
+       which provides for higher position precision and shorter
+       packets than the original APRS format. It also includes
+       altitude data, which is invaluable when tracking rockets. We
+       haven't found a receiver which doesn't handle compressed
+       positions, but it's just possible that you have one, so if you
+       have an older device that can receive the raw packets but
+       isn't displaying position information, it's possible that this
+       is the cause.
+      </para>
+      <para>
+       The APRS packet format includes a comment field that can have
+       arbitrary text in it. AltOS uses this to send status
+       information about the flight computer. It sends four fields as
+       shown in the following table.
+      </para>
+      <table frame='all'>
+       <title>Altus Metrum APRS Comments</title>
+       <?dbfo keep-together="always"?>
+       <tgroup cols='3' align='center' colsep='1' rowsep='1'>
+         <colspec align='center' colwidth='*' colname='Field'/>
+         <colspec align='center' colwidth='*' colname='Example'/>
+         <colspec align='center' colwidth='4*' colname='Description'/>
+         <thead>
+           <row>
+             <entry align='center'>Field</entry>
+             <entry align='center'>Example</entry>
+             <entry align='center'>Description</entry>
+           </row>
+         </thead>
+         <tbody>
+           <row>
+             <entry>1</entry>
+             <entry>L</entry>
+             <entry>GPS Status U for unlocked, L for locked</entry>
+           </row>
+           <row>
+             <entry>2</entry>
+             <entry>6</entry>
+             <entry>Number of Satellites in View</entry>
+           </row>
+           <row>
+             <entry>3</entry>
+             <entry>B4.0</entry>
+             <entry>Battery Voltage</entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+      <para>
+       Here's an example of an APRS comment showing GPS lock with 6
+       satellites in view and a battery at 4.0V.
+       <screen>
+         L6 B4.0
+       </screen>
+      </para>
+      <para>
+       Make sure your primary battery is above 3.8V and GPS is locked
+       with at least 5 or 6 satellites in view before starting. If GPS
+       is switching between L and U regularly, then it doesn't have a
+       good lock and you should wait until it becomes stable.
+      </para>
+      <para>
+       If the GPS receiver loses lock, the APRS data transmitted will
+       contain the last position for which GPS lock was
+       available. You can tell that this has happened by noticing
+       that the GPS status character switches from 'L' to 'U'. Before
+       GPS has locked, APRS will transmit zero for latitude,
+       longitude and altitude.
+      </para>
+    </section>
+    <section>
+      <title>Configurable Parameters</title>
+      <para>
+        Configuring TeleGPS is very
+        simple; the few configurable parameters can all be set
+        using the TeleGPS application over USB. Read
+       the Configure TeleGPS section in the TeleGPS Software chapter below
+       for more information.
+      </para>
+      <section>
+        <title>Radio Frequency</title>
+        <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
+         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
+         frequency will be used to avoid interference.  And of course, both
+         TeleGPS and the receiver must be configured to the same
+         frequency to successfully communicate with each other.
+        </para>
+      </section>
+      <section>
+       <title>Callsign</title>
+       <para>
+         This sets the callsign used for telemetry and APRS to
+         identify the device.
+       </para>
+      </section>
+      <section>
+       <title>Telemetry/RDF/APRS Enable</title>
+       <para>
+         You can completely disable the radio, if necessary, leaving
+         TeleGPS only logging data to internal memory.
+       </para>
+      </section>
+      <section>
+       <title>APRS Interval</title>
+       <para>
+         This selects how often APRS packets are transmitted. Set
+         this to zero to disable APRS without also disabling the
+         regular telemetry and RDF transmissions. As APRS takes a
+         full second to transmit a single position report, we
+         recommend sending packets no more than once every 5 seconds.
+       </para>
+      </section>
+      <section>
+       <title>Maximum Flight Log</title>
+       <para>
+         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>
+      </section>
+      <section>
+       <title>Logging Trigger Motion</title>
+       <para>
+         If TeleGPS moves less than this distance over a long period
+         of time, it will not log that location, saving storage space.
+       </para>
+      </section>
+      <section>
+       <title>Position Reporting Interval</title>
+       <para>
+         This sets how often TeleGPS reports position information via
+         telemetry and to the on-board log. Reducing this value will
+         save power and logging memory consumption.
+       </para>
+      </section>
+    </section>
+  </chapter>
+  <chapter>
+    <title>TeleGPS Application</title>
+    <para>
+      The TeleGPS application provides a graphical user interface for
+      interacting with the Altus Metrum product family. TeleGPS can
+      monitor telemetry data, configure devices and many other
+      tasks. The primary interface window is for displaying data
+      received over the telemetry link. There are additional
+      tasks available from the main window menu bar. This chapter
+      is split into sections, each of which documents one of the tasks
+      provided from the top-level toolbar.
+    </para>
+    <section>
+      <title>Telemetry Monitoring</title>
+      <para>
+       This is the window brought up when you start the
+       application. If you have a TeleDongle device connected to the
+       computer, it will automatically be selected for telemetry monitoring
+      </para>
+      <para>
+        All telemetry data received are automatically recorded in
+        suitable log files. The name of the files includes the current
+        date and TeleGPS serial and flight numbers.
+      </para>
+      <para>
+        The radio frequency being monitored by the TeleDongle device
+        is displayed at the top of the window. You can configure the
+        frequency by clicking on the frequency box and selecting the
+        desired frequency. The TeleGPS application remembers the last
+        frequency selected for each TeleDongle and selects that
+        automatically the next time you use that device.
+      </para>
+      <para>
+        Below the TeleDongle frequency selector, the window contains a few
+        significant pieces of information about the altimeter providing
+        the telemetry data stream:
+      </para>
+      <itemizedlist>
+        <listitem>
+          <para>The configured call-sign</para>
+        </listitem>
+        <listitem>
+          <para>The device serial number</para>
+        </listitem>
+        <listitem>
+          <para>The flight number. TeleGPS remembers how many
+          times it has flown.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            The Received Signal Strength Indicator value. This lets
+            you know how strong a signal TeleDongle is receiving. The
+            radio inside TeleDongle operates down to about -100dBm;
+            weaker signals may not be receivable. The packet link uses
+            error detection and correction techniques which prevent
+            incorrect data from being reported.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            The age of the displayed data, in seconds since the last 
+           successfully received telemetry packet.  In normal operation
+           this will stay in the low single digits.  If the number starts
+           counting up, then you are no longer receiving data over the radio
+           link from the flight computer.
+          </para>
+        </listitem>
+      </itemizedlist>
+      <para>
+        Finally, the largest portion of the window contains a set of
+        tabs, each of which contain some information about the TeleGPS
+        board. The final 'table' tab displays many of the raw telemetry
+        values in one place in a spreadsheet-like format.
+      </para>
+      <section>
+        <title>Map</title>
+        <para>
+          The Map tab shows the TeleGPS track over time on top of map
+         data making it easy to locate the device.
+        </para>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="telegps-map.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+        <para>
+          The map's default scale is approximately 3m (10ft) per pixel. The map
+          can be dragged using the left mouse button. The map will attempt
+          to keep the rocket roughly centered while data is being received.
+        </para>
+       <para>
+         You can adjust the style of map and the zoom level with
+         buttons on the right side of the map window. You can draw a
+         line on the map by moving the mouse over the map with a
+         button other than the left one pressed, or by pressing the
+         left button while also holding down the shift key. The
+         length of the line in real-world units will be shown at the
+         start of the line.
+       </para>
+        <para>
+          Images are fetched automatically via the Google Maps Static API,
+          and cached on disk for reuse. If map images cannot be downloaded,
+          the rocket's path will be traced on a dark gray background
+          instead.
+        </para>
+       <para>
+         You can pre-load images for your favorite launch sites
+         before you leave home; check out the 'Preload Maps' section below.
+       </para>
+      </section>
+      <section>
+       <title>Location</title>
+       <para>
+         The Location tab shows the raw GPS data received from TeleGPS.
+       </para>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="telegps-location.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+      </section>
+      <section>
+       <title>Status</title>
+       <para>
+         The Status tab shows data relative to the location of
+         TeleGPS when the application first received telemetry from
+         it.
+       </para>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="telegps-status.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+      </section>
+      <section>
+       <title>Table</title>
+       <para>
+         The Table tab shows detailed information about the GPS
+         receiver
+       </para>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="telegps-table.png" width="5.5in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+      </section>
+    </section>
+    <!--
+       <variablelist>
+         <varlistentry>
+           <term></term>
+           <listitem>
+             <para>
+             </para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+    -->
+    <section>
+      <title>TeleGPS Menus</title>
+      <para>
+       TeleGPS has three or four menus at the top of the window:
+       <variablelist>
+         <varlistentry>
+           <term>File</term>
+           <listitem>
+             <para>
+               New Window, Graph Data, Export Data, Load Maps, Preferences, Close and Exit
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Monitor</term>
+           <listitem>
+             <para>
+               Connect Device, Disconnect and Scan Channels
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Device</term>
+           <listitem>
+             <para>
+               Download Data, Configure Device and Flash Device
+             </para>
+           </listitem>
+         </varlistentry>
+         <varlistentry>
+           <term>Frequency</term>
+           <listitem>
+             <para>
+               This shows the current monitoring frequency with a
+               drop-down menu listing other configured
+               frequencies. You can change the set of frequencies
+               shown here from the Preferences dialog. This menu is
+               only shown when the TeleGPS application is connected
+               to a TeleDongle or TeleBT device.
+             </para>
+           </listitem>
+         </varlistentry>
+       </variablelist>
+      </para>
+      <section>
+       <title>New Window</title>
+       <para>
+         This creates another telemetry monitoring window, in case
+         you have multiple TeleDongle devices connected to the
+         computer.
+       </para>
+      </section>
+      <section>
+       <title>Graph Data</title>
+       <para>
+         This brings up a file dialog to load a saved log, either
+         a .telem file of recorded telemetry or .eeprom of saved
+         data from on-board memory. It looks a bit like the flight
+         monitoring window, using a selection of tabs to show
+         different views of the saved data.
+       </para>
+       <section>
+         <title>Graph</title>
+         <para>
+           The Graph tab shows a plot of the the GPS data
+           collected. The X axis is time in seconds; there are a
+           variety of Y axes available for different kinds of data.
+         </para>
+         <informalfigure>
+           <mediaobject>
+             <imageobject>
+               <imagedata fileref="telegps-graph-graph.png" width="6in" scalefit="1"/>
+             </imageobject>
+           </mediaobject>
+         </informalfigure>
+       </section>
+       <section>
+         <title>Configure Graph</title>
+         <informalfigure>
+           <mediaobject>
+             <imageobject>
+               <imagedata fileref="telegps-graph-configure.png" width="6in" scalefit="1"/>
+             </imageobject>
+           </mediaobject>
+         </informalfigure>
+         <para>
+           This selects which graph elements to show, and, at the
+           bottom, lets you switch between metric and imperial units
+         </para>
+       </section>
+       <section>
+         <title>Statistics</title>
+         <informalfigure>
+           <mediaobject>
+             <imageobject>
+               <imagedata fileref="telegps-graph-stats.png" width="6in" scalefit="1"/>
+             </imageobject>
+           </mediaobject>
+         </informalfigure>
+         <para>
+           Shows overall data computed from the flight.
+         </para>
+       </section>
+       <section>
+         <title>Map</title>
+         <informalfigure>
+           <mediaobject>
+             <imageobject>
+               <imagedata fileref="telegps-graph-map.png" width="6in" scalefit="1"/>
+             </imageobject>
+           </mediaobject>
+         </informalfigure>
+         <para>
+           Shows a map of the area overlaid with the GPS track. As with
+           the telemetry monitoring window, you can select the style
+           of map and zoom level using buttons along the side;
+           you can scroll the map by dragging within the map pressing
+           the left button and you can draw a line to measure
+           distances using either the left button with the shift key,
+           or any other button.
+         </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 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>
+       <section>
+          <title>Comma Separated Value Format</title>
+          <para>
+            This is a text file containing the data in a form suitable for
+            import into a spreadsheet or other external data analysis
+            tool. The first few lines of the file contain the version and
+            configuration information from TeleGPS, then
+            there is a single header line which labels all of the
+            fields. All of these lines start with a '#' character which
+            many tools can be configured to skip over.
+          </para>
+          <para>
+            The remaining lines of the file contain the data, with each
+            field separated by a comma and at least one space. All of
+            the sensor values are converted to standard units, with the
+            barometric data reported in both pressure, altitude and
+            height above pad units.
+          </para>
+       </section>
+       <section>
+          <title>Keyhole Markup Language (for Google Earth)</title>
+          <para>
+            This is the format used by Google Earth to provide an overlay 
+           within that application. With this, you can use Google Earth to 
+           see the whole flight path in 3D.
+          </para>
+       </section>
+      </section>
+      <section>
+       <title>Load Maps</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="load-maps.png" width="5.2in" scalefit="1"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+       <para>
+         Before using TeleGPS, you can use Load Maps to load map data
+         in case you don't have access to the internet while
+         receiving telemetry.
+       </para>
+       <para>
+         There's a drop-down menu of rocket 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 from our server at run-time, so as
+         new sites are sent in, they'll get automatically added to
+         this list.  If the launch site isn't in the list, you can
+         manually enter the lat/lon values
+       </para>
+       <para>
+         There are four different kinds of maps you can view; you can
+         select which to download by selecting as many as you like from
+         the available types:
+         <variablelist>
+           <varlistentry>
+             <term>Hybrid</term>
+             <listitem>
+               <para>
+                 A combination of satellite imagery and road data. This
+                 is the default view.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>Satellite</term>
+             <listitem>
+               <para>
+                 Just the satellite imagery without any annotation.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>Roadmap</term>
+             <listitem>
+               <para>
+                 Roads, political boundaries and a few geographic features.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term>Terrain</term>
+             <listitem>
+               <para>
+                 Contour intervals and shading that show hills and
+                 valleys.
+               </para>
+             </listitem>
+           </varlistentry>
+         </variablelist>
+       </para>
+       <para>
+         You can specify the range of zoom levels to download; smaller
+         numbers show more area with less resolution. The default
+         level, 0, shows about 3m/pixel. One zoom level change
+         doubles or halves that number.
+       </para>
+       <para>
+         The Tile Radius value sets how large an area around the center
+         point to download. Each tile is 512x512 pixels, and the
+         'radius' value specifies how many tiles away from the center
+         will be downloaded. Specify a radius of 0 and you get only the
+         center tile. A radius of 1 loads a 3x3 grid, centered on the
+         specified location.
+       </para>
+       <para>
+         Clicking the 'Load Map' button will fetch images from Google
+         Maps; note that Google limits how many images you can fetch at
+         once, so if you load more than one launch site, you may get
+         some gray areas in the map which indicate that Google is tired
+         of sending data to you. Try again later.
+       </para>
+      </section>
+      <section>
+       <title>Preferences</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="telegps-preferences.png" width="2.4in" scalefit="1"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+       <section>
+          <title>Voice Settings</title>
+          <para>
+            AltosUI provides voice announcements during flight so that you
+            can keep your eyes on the sky and still get information about
+            the current flight status. However, sometimes you don't want
+            to hear them.
+          </para>
+          <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>
+          <para>
+            AltosUI logs all telemetry data and saves all TeleMetrum flash
+            data to this directory. This directory is also used as the
+            staring point when selecting data files for display or export.
+          </para>
+          <para>
+            Click on the directory name to bring up a directory choosing
+            dialog, select a new directory and click 'Select Directory' to
+            change where AltosUI reads and writes data files.
+          </para>
+       </section>
+       <section>
+          <title>Callsign</title>
+          <para>
+            This value is transmitted in each command packet sent from 
+           TeleDongle and received from an altimeter.  It is not used in 
+           telemetry mode, as the callsign configured in the altimeter board
+           is included in all telemetry packets.  Configure this
+            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, 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>
+          <title>Serial Debug</title>
+          <para>
+            This causes all communication with a connected device to be
+            dumped to the console from which AltosUI was started. If
+            you've started it from an icon or menu entry, the output
+            will simply be discarded. This mode can be useful to debug
+            various serial communication issues.
+          </para>
+       </section>
+       <section>
+         <title>Font Size</title>
+         <para>
+           Selects the set of fonts used in the flight monitor
+           window. Choose between the small, medium and large sets.
+         </para>
+       </section>
+       <section>
+         <title>Look &amp; Feel</title>
+         <para>
+           Adjust the style of the windows. By default, the TeleGPS
+           application attempts to blend in with the native style.
+         </para>
+       </section>
+       <section>
+         <title>Manage Frequencies</title>
+         <para>
+           This brings up a dialog where you can configure the set of
+           frequencies shown in the various frequency menus. You can
+           add as many as you like, or even reconfigure the default
+           set. Changing this list does not affect the frequency
+           settings of any devices, it only changes the set of
+           frequencies shown in the menus.
+         </para>
+       </section>
+      </section>
+      <section>
+       <title>Close</title>
+       <para>
+         This closes the current window, leaving any other windows
+         open and the application running.
+       </para>
+      </section>
+      <section>
+       <title>Exit</title>
+       <para>
+         This closes all TeleGPS windows and terminates the application.
+       </para>
+      </section>
+      <section>
+       <title>Connect Device</title>
+       <para>
+          Selecting this item brings up a dialog box listing all of
+          the connected TeleDongle devices. When you choose one of
+          these, AltosUI will display telemetry data as received by
+          the selected TeleDongle device.
+       </para>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="device-selection.png" width="3.1in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+      </section>
+      <section>
+       <title>Disconnect</title>
+       <para>
+         Disconnects the currently connected TeleDongle or TeleBT
+       </para>
+      </section>
+      <section>
+       <title>Scan Channels</title>
+       <para>
+         Scans the configured set of frequencies looking for
+         telemetry signals. A list of all of the discovered signals
+         is show; selecting one of those and clicking on 'Monitor'
+         will select that frequency in the associated TeleGPS
+         application window.
+       </para>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="telegps-scan.png" width="3.1in"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+      </section>
+      <section>
+       <title>Download Data</title>
+       <para>
+          TeleGPS records data to its internal flash memory.
+          On-board data is recorded at the same rate as telemetry
+          but is not subject to radio drop-outs. As
+          such, it generally provides a more complete and precise record.
+          The 'Download Data' menu entry allows you to read the
+          flash memory and write it to disk. 
+       </para>
+       <para>
+          Select the 'Download Data' menu entry to bring up a list of
+          connected TeleGPS devices. After the device has been
+          selected, a dialog showing the data stored in the
+          device will be shown allowing you to select which entries to
+          download and which to delete. You must erase flights in order for the space they
+          consume to be reused by another track. This prevents
+          accidentally losing data if you neglect to download
+          data before starting TeleGPS again. Note that if there is no more
+          space available in the device, then no data will be recorded.
+       </para>
+       <para>
+          The file name for each data log is computed automatically
+          from the recorded date, altimeter serial number and flight
+          number information.
+       </para>
+      </section>
+      <section>
+       <title>Configure Device</title>
+       <informalfigure>
+         <mediaobject>
+           <imageobject>
+             <imagedata fileref="telegps-configure.png" width="3.6in" scalefit="1"/>
+           </imageobject>
+         </mediaobject>
+       </informalfigure>
+       <para>
+          Select this button and then select any connected TeleGPS
+          device from the list provided.
+       </para>
+       <para>
+          The first few lines of the dialog provide information about the
+          connected device, including the product name,
+          software version and hardware serial number. Below that are the
+          individual configuration entries.
+       </para>
+       <para>
+          At the bottom of the dialog, there are four buttons:
+       </para>
+       <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. This will restart logging for
+               a new flight number, if any log information has been
+               saved for the current flight.
+             </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>
+       <section>
+          <title>Frequency</title>
+          <para>
+            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, the TeleDongle frequency will
+            also be automatically reconfigured to match so that
+            communication will continue afterwards.
+          </para>
+       </section>
+       <section>
+          <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
+            specified frequency.  If you need to you can adjust the calibration 
+           by changing this value.  Do not do this without understanding what
+           the value means, read the appendix on calibration and/or the source
+           code for more information.  To change a TeleDongle's calibration, 
+           you must reprogram the unit completely.
+          </para>
+       </section>
+       <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 (in
+           seconds). When set to zero, APRS transmission is
+           disabled. 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 Log Size</title>
+          <para>
+            This sets the space (in kilobytes) allocated for each data
+            log. The available space will be divided into chunks of this
+            size. A smaller value will allow more logs to be stored,
+            a larger value will record data for longer times.
+         </para>
+       </section>
+       <section>
+         <title>Logging Trigger Motion</title>
+         <para>
+           If TeleGPS moves less than this distance over a long period
+           of time, it will not log that location, saving storage space.
+         </para>
+       </section>
+       <section>
+         <title>Position Reporting Interval</title>
+         <para>
+           This sets how often TeleGPS reports position information via
+           telemetry and to the on-board log. Reducing this value will
+           save power and logging memory consumption.
+         </para>
+       </section>
+      </section>
+      <section>
+       <title>Flash Device</title>
+       <para>
+          This reprograms TeleGPS devices with new firmware. Please
+          read the directions for flashing devices in the Updating
+          Device Firmware chapter below.
+       </para>
+      </section>
+    </section>
+  </chapter>
+  <chapter>
+    <title>Updating Device Firmware</title>
+    <para>
+      TeleGPS is programmed directly over its USB connectors.
+    </para>
+    <para>
+      You may wish to begin by ensuring you have current firmware images.
+      These are distributed as part of the TeleGPS software bundle that
+      also includes the TeleGPS ground station program.  Newer ground
+      station versions typically work fine with older firmware versions,
+      so you don't need to update your devices just to try out new
+      software features.  You can always download the most recent
+      version from <ulink url="http://www.altusmetrum.org/AltOS/"/>.
+    </para>
+    <section>
+      <title>
+       Updating TeleGPS 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 TeleGPS, and select 'Flash Device' from the Device 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 TeleGPS-v1.0-1.4.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>
+  </chapter>
+  <chapter>
+    <title>Technical Information</title>
+    <section>
+      <title>GPS Receiver</title>
+      <para>
+       TeleGPS uses the u-Blox Max-7Q GPS receiver.
+      </para>
+    </section>
+    <section>
+      <title>Micro-controller</title>
+      <para>
+       TeleGPS uses an NXP LPC11U14 micro-controller. This tiny
+       CPU contains 32kB of flash for the application and 4kB of RAM for
+       temporary data storage.
+      </para>
+    </section>
+    <section>
+      <title>Lithium Polymer Battery</title>
+      <para>
+       Shipping restrictions may prevent us from including a battery
+       battery with TeleGPS.
+      </para>
+    </section>
+    <section>
+      <title>Mechanical Considerations</title>
+      <para>
+       TeleGPS is designed to be rugged enough for typical rocketry
+       applications.  The 4 mounting holes on the board are sized for 
+       use with 4-40 or M3 screws.
+      </para>
+    </section>
+    <section>
+      <title>On-board data storage</title>
+      <para>
+       TeleGPS has 2MB of non-volatile storage, separate from the
+       code storage memory. The TeleGPS firmware uses this to log
+       information during flight.
+      </para>
+    </section>
+  </chapter>
+</book>
+<!--  LocalWords:  Altusmetrum TeleGPS
+-->
diff --git a/doc/telemega-outline.pdf b/doc/telemega-outline.pdf
deleted file mode 100644 (file)
index f8fc26e..0000000
Binary files a/doc/telemega-outline.pdf and /dev/null differ
diff --git a/doc/telemega-outline.svg b/doc/telemega-outline.svg
deleted file mode 100644 (file)
index e8d74d3..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-<?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.3.1 r9886"
-   sodipodi:docname="megametrum-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="2.1783851"
-     inkscape:cx="315.40175"
-     inkscape:cy="122.33575"
-     inkscape:document-units="in"
-     inkscape:current-layer="layer1"
-     showgrid="true"
-     inkscape:window-width="1527"
-     inkscape:window-height="1313"
-     inkscape:window-x="813"
-     inkscape:window-y="166"
-     inkscape:window-maximized="0"
-     units="in"
-     showguides="true"
-     inkscape:guide-bbox="true">
-    <sodipodi:guide
-       position="0,0"
-       orientation="0,427.5"
-       id="guide3005" />
-    <sodipodi:guide
-       position="427.5,0"
-       orientation="-270,0"
-       id="guide3007" />
-    <sodipodi:guide
-       position="427.5,270"
-       orientation="0,-427.5"
-       id="guide3009" />
-    <sodipodi:guide
-       position="0,270"
-       orientation="270,0"
-       id="guide3011" />
-    <inkscape:grid
-       type="xygrid"
-       id="grid3013"
-       empspacing="4"
-       visible="true"
-       enabled="true"
-       snapvisiblegridlinesonly="true"
-       units="in"
-       spacingx="0.025in"
-       spacingy="0.025in" />
-  </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.54555845;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       id="rect2816"
-       width="291.95444"
-       height="111.95444"
-       x="90.272781"
-       y="850.13251" />
-    <g
-       inkscape:tile-y0="681.11218"
-       inkscape:tile-x0="90"
-       id="use3601"
-       transform="matrix(0.97131843,0,0,0.97528987,8.397686,191.32255)">
-      <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="matrix(0.97186116,0,0,0.97241431,278.34851,193.3134)">
-      <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="matrix(0.97475506,0,0,0.97241431,278.08835,283.31323)">
-      <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="matrix(0.97186116,0,0,0.97241431,8.3485628,283.31356)">
-      <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.79999995;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 135,903.85975 157.5,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="888.10974"
-       y="-303.75"
-       id="text4236"
-       sodipodi:linespacing="125%"
-       transform="matrix(0,1,-1,0,0,0)"><tspan
-         sodipodi:role="line"
-         x="888.10974"
-         y="-303.75"
-         id="tspan4242">UP</tspan></text>
-  </g>
-</svg>
diff --git a/doc/telemega-outline.xsl b/doc/telemega-outline.xsl
new file mode 100644 (file)
index 0000000..5d3411e
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
+<article>
+    <title>TeleMega Outline and Hole Pattern</title>
+    <para>
+      This image, when printed, provides a precise template for the
+      mounting holes in TeleMega.  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.svg"
+                    scalefit="0" scale="100" align="center" />
+       </imageobject>
+      </mediaobject>
+    </informalfigure>
+</article>
+
+<!-- LocalWords: Altusmetrum
+-->
diff --git a/doc/telemega.svg b/doc/telemega.svg
new file mode 100644 (file)
index 0000000..40edf69
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+<svg
+       xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   width="3.5in"
+   height="1.5in"
+   viewBox="0 0 350 150"
+   preserveaspectratio="none"
+   id="svg2"
+   version="1.1">
+  <g transform="translate(12.5,12.5)"
+     style="fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:miter;font-size:24">
+    <!-- outline -->
+    <rect width="325" height="125" x="0" y="0"/>
+    <!-- holes -->
+    <path d="M12.5,12.5 m-6.25,0 a6.25,6.25,0,1,0,12.5,0 a6.25,6.25,0,1,0,-12.5,0 l12.5,0 m-6.25,-6.25 l0,12.5"/>
+    <path d="M312.5,12.5 m-6.25,0 a6.25,6.25,0,1,0,12.5,0 a6.25,6.25,0,1,0,-12.5,0 l12.5,0 m-6.25,-6.25 l0,12.5"/>
+    <path d="M12.5,112.5 m-6.25,0 a6.25,6.25,0,1,0,12.5,0 a6.25,6.25,0,1,0,-12.5,0 l12.5,0 m-6.25,-6.25 l0,12.5"/>
+    <path d="M312.5,112.5 m-6.25,0 a6.25,6.25,0,1,0,12.5,0 a6.25,6.25,0,1,0,-12.5,0 l12.5,0 m-6.25,-6.25 l0,12.5"/>
+    <!-- arrow -->
+    <path d="M50,62.5 l225,0"/>
+    <path style="fill:#000000;stroke:none" d="M275,57.5 l10,5 l-10,5 z"/>
+    <!-- label -->
+    <text x="162.5" y="57.5" style="fill:#000000;stroke:none" text-anchor="middle">TeleMega</text>
+    <g transform="rotate(90)">
+      <text x="62.5" y="-290" style="fill:#000000;stroke:none" text-anchor="middle">UP</text>
+    </g>
+  </g>
+</svg>
\ No newline at end of file
diff --git a/doc/telemetrum-outline.pdf b/doc/telemetrum-outline.pdf
deleted file mode 100644 (file)
index 09ce557..0000000
Binary files a/doc/telemetrum-outline.pdf and /dev/null differ
diff --git a/doc/telemetrum-outline.svg b/doc/telemetrum-outline.svg
deleted file mode 100644 (file)
index aee63ed..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-<?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.47 r22583"
-   sodipodi:docname="telemetrum-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="1.1459933"
-     inkscape:cx="182.36411"
-     inkscape:cy="261.60668"
-     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="20"
-     inkscape:window-maximized="0"
-     units="in" />
-  <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></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.44999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       id="rect2816"
-       width="247.38385"
-       height="89.893326"
-       x="90.0625"
-       y="872.40637" />
-    <g
-       inkscape:tile-y0="681.11218"
-       inkscape:tile-x0="90"
-       id="use3601"
-       transform="translate(28.141535,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" />
-      <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" />
-    </g>
-    <g
-       inkscape:tile-y0="681.11218"
-       inkscape:tile-x0="90"
-       id="use3603"
-       transform="translate(230.64154,196.89215)">
-      <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" />
-      <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" />
-    </g>
-    <g
-       inkscape:tile-y0="681.11218"
-       inkscape:tile-x0="90"
-       id="use3605"
-       transform="translate(230.64154,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" />
-      <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" />
-    </g>
-    <g
-       inkscape:tile-y0="681.11218"
-       inkscape:tile-x0="90"
-       id="use3607"
-       transform="translate(28.141535,196.89215)">
-      <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" />
-      <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" />
-    </g>
-    <path
-       style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.80000000000000004;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;marker-end:url(#Arrow2Lend)"
-       d="m 135,135 157.5,0"
-       id="path2829"
-       transform="translate(0,782.35975)"
-       sodipodi:nodetypes="cc" />
-    <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="903.51935"
-       y="-305.87912"
-       id="text4236"
-       sodipodi:linespacing="125%"
-       transform="matrix(0,1,-1,0,0,0)"><tspan
-         sodipodi:role="line"
-         x="903.51935"
-         y="-305.87912"
-         id="tspan4242">UP</tspan></text>
-  </g>
-</svg>
diff --git a/doc/telemetrum-outline.xsl b/doc/telemetrum-outline.xsl
new file mode 100644 (file)
index 0000000..4a0ade4
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd">
+<article>
+    <title>TeleMetrum Outline and Hole Pattern</title>
+    <para>
+      This image, when printed, provides a precise template for the
+      mounting holes in TeleMetrum.  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>
+    <informalfigure>
+      <mediaobject id="TeleMetrumTemplate">
+       <imageobject>
+         <imagedata format="SVG" fileref="telemetrum.svg"
+                    scalefit="0" scale="100" align="center" />
+       </imageobject>
+      </mediaobject>
+    </informalfigure>
+</article>
+
+<!-- LocalWords: Altusmetrum
+-->
index 97c4e4a8edcd9a6b20f302471f4e3cc3913648cd..80ee182da4af51daf629efd2e0edd5525c3b871b 100644 (file)
@@ -6,14 +6,14 @@
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
-   width="5in"
-   height="2.5in"
-   viewBox="0 0 500 250"
+   width="3in"
+   height="1.25in"
+   viewBox="0 0 300 125"
    preserveaspectratio="none"
    id="svg2"
    version="1.1">
-  <g transform="translate(112.5,75)"
-     style="fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:miter;font-family:Frutiger LT Std">
+  <g transform="translate(12.5,12.5)"
+     style="fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:miter;font-size:24">
     <!-- outline -->
     <rect width="275" height="100" x="0" y="0"/>
     <!-- holes -->
index d07b4971d51dc320f9001c14ce3a6a56e2523908..b2e21e3d9e5f56c38e3935fb2685449777710ccf 100644 (file)
@@ -6,26 +6,26 @@
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
-   width="5in"
-   height="2in"
-   viewBox="0 0 500 200"
+   width="1.75in"
+   height=".75in"
+   viewBox="0 0 175 75"
    preserveaspectratio="none"
    id="svg2"
    version="1.1">
-  <g transform="translate(175,75)"
-     style="fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:miter;font-family:Frutiger LT Std">
+  <g transform="translate(12.5,12.5)"
+     style="fill:none;stroke:#000000;stroke-width:1;stroke-linejoin:miter;font-size:20">
     <!-- outline -->
     <rect width="150" height="50" x="0" y="0"/>
     <!-- holes -->
-    <path d="M135,10 A5,5,0,1,0,145,10 A5,5,0,1,0,135,10 M135,10 l10,0 M140,5 l0,10"/>
-    <path d="M135,40 A5,5,0,1,0,145,40 A5,5,0,1,0,135,40 M135,40 l10,0 M140,35 l0,10"/>
+    <path d="M140,10 m-5,0 a5,5,0,1,0,10,0 a5,5,0,1,0,-10,0 l10,0 m-5,-5 l0,10"/>
+    <path d="M140,40 m-5,0 a5,5,0,1,0,10,0 a5,5,0,1,0,-10,0 l10,0 m-5,-5 l0,10"/>
     <!-- arrow -->
-    <path d="M25,25 l90,0"/>
-    <path style="fill:#000000;stroke:none" d="M115,20 l10,5 l-10,5 z"/>
+    <path d="M25,25 l100,0"/>
+    <path style="fill:#000000;stroke:none" d="M125,20 l10,5 l-10,5 z"/>
     <!-- label -->
     <text x="75" y="20" style="fill:#000000;stroke:none" text-anchor="middle">TeleMini</text>
-    <g transform="rotate(90)">
-      <text x="25" y="-130" style="fill:#000000;stroke:none" text-anchor="middle">UP</text>
+    <g transform="rotate(90)" style="font-size:14">
+      <text x="25" y="-133" style="fill:#000000;stroke:none" text-anchor="middle">UP</text>
     </g>
   </g>
 </svg>
\ No newline at end of file
diff --git a/icon/.gitignore b/icon/.gitignore
new file mode 100644 (file)
index 0000000..e89555d
--- /dev/null
@@ -0,0 +1,6 @@
+altus-metrum-*.png
+micropeak-*.png
+telegps-*.png
+*.ico
+*.icns
+*.build
diff --git a/icon/Makefile.am b/icon/Makefile.am
new file mode 100644 (file)
index 0000000..b1c00f4
--- /dev/null
@@ -0,0 +1,73 @@
+JAVA_RES=16 32 48 64 128 256
+MAC_RES=16 32 128 256 512
+WIN_RES=16 24 32 48 64 72 96 128 180 256
+RES=$(shell echo $(JAVA_RES) $(MAC_RES) $(WIN_RES) | awk '{ for (i = 1; i <= NF; i++) printf("%s\n", $$i); }' | sort -n -u)
+
+AM_FILES=$(shell for i in $(RES); do echo altus-metrum-$$i.png; done)
+MP_FILES=$(shell for i in $(RES); do echo micropeak-$$i.png; done)
+TG_FILES=$(shell for i in $(RES); do echo telegps-$$i.png; done)
+
+MAC_TG_FILES=$(shell for i in $(MAC_RES); do echo telegps-$$i.png; done)
+MAC_MP_FILES=$(shell for i in $(MAC_RES); do echo micropeak-$$i.png; done)
+MAC_AM_FILES=$(shell for i in $(MAC_RES); do echo altus-metrum-$$i.png; done)
+
+WIN_TG_FILES=$(shell for i in $(WIN_RES); do echo telegps-$$i.png; done)
+WIN_MP_FILES=$(shell for i in $(WIN_RES); do echo micropeak-$$i.png; done)
+WIN_AM_FILES=$(shell for i in $(WIN_RES); do echo altus-metrum-$$i.png; done)
+
+ICO_FILES=altus-metrum.ico micro-peak.ico telegps.ico
+ICNS_FILES=AltosUIIcon.icns TeleGPS.icns MicroPeak.icns
+
+icondir = $(datadir)/icons/hicolor/scalable/apps
+
+AM_ICON = altusmetrum.svg
+MP_ICON = micropeak.svg
+TG_ICON = telegps.svg
+
+icon_DATA = $(AM_ICON) $(MP_ICON) $(TG_ICON)
+
+EXTRA_DIST = $(icon_DATA) $(AM_FILES) $(MP_FILES) $(TG_FILES)
+
+res:
+       echo $(RES)
+
+all-local: $(ICO_FILES) $(ICNS_FILES)
+
+clean-local:
+       $(RM) altus-metrum-*.png telegps-*.png micropeak-*.png *.build *.ico *.icns
+
+$(AM_FILES): altusmetrum.build
+
+altusmetrum.build: altusmetrum.svg
+       for i in $(RES); do rsvg-convert -w $$i -h $$i -o altus-metrum-$$i.png altusmetrum.svg; done && touch $@
+
+$(TG_FILES): telegps.build
+
+telegps.build: telegps.svg
+       for i in $(RES); do rsvg-convert -w $$i -h $$i -o telegps-$$i.png telegps.svg; done && touch $@
+
+$(MP_FILES): micropeak.build
+
+micropeak.build: micropeak.svg
+       for i in $(RES); do rsvg-convert -w $$i -h $$i -o micropeak-$$i.png micropeak.svg; done && touch $@
+
+#clean-local:
+#      $(RM) -f $(ICO_FILES)
+
+altus-metrum.ico: $(WIN_AM_FILES)
+       icotool -c -o $@ $(WIN_AM_FILES)
+
+micro-peak.ico: $(WIN_MP_FILES)
+       icotool -c -o $@ $(WIN_MP_FILES)
+
+telegps.ico: $(WIN_TG_FILES)
+       icotool -c -o $@ $(WIN_TG_FILES)
+
+AltosUIIcon.icns: $(MAC_AM_FILES)
+       png2icns $@ $(MAC_AM_FILES)
+
+TeleGPS.icns: $(MAC_TG_FILES)
+       png2icns $@ $(MAC_TG_FILES)
+
+MicroPeak.icns: $(MAC_MP_FILES)
+       png2icns $@ $(MAC_MP_FILES)
diff --git a/icon/altus-metrum-128.png b/icon/altus-metrum-128.png
deleted file mode 100644 (file)
index f1343d9..0000000
Binary files a/icon/altus-metrum-128.png and /dev/null differ
diff --git a/icon/altus-metrum-16.png b/icon/altus-metrum-16.png
deleted file mode 100644 (file)
index 5bd4599..0000000
Binary files a/icon/altus-metrum-16.png and /dev/null differ
diff --git a/icon/altus-metrum-256.png b/icon/altus-metrum-256.png
deleted file mode 100644 (file)
index 46e1670..0000000
Binary files a/icon/altus-metrum-256.png and /dev/null differ
diff --git a/icon/altus-metrum-32.png b/icon/altus-metrum-32.png
deleted file mode 100644 (file)
index c858889..0000000
Binary files a/icon/altus-metrum-32.png and /dev/null differ
diff --git a/icon/altus-metrum-48.png b/icon/altus-metrum-48.png
deleted file mode 100644 (file)
index 3bee98e..0000000
Binary files a/icon/altus-metrum-48.png and /dev/null differ
diff --git a/icon/altus-metrum-512.png b/icon/altus-metrum-512.png
deleted file mode 100644 (file)
index 47c4700..0000000
Binary files a/icon/altus-metrum-512.png and /dev/null differ
diff --git a/icon/altus-metrum-64.png b/icon/altus-metrum-64.png
deleted file mode 100644 (file)
index 0ee086a..0000000
Binary files a/icon/altus-metrum-64.png and /dev/null differ
diff --git a/icon/altus-metrum.ico b/icon/altus-metrum.ico
deleted file mode 100644 (file)
index bedf04e..0000000
Binary files a/icon/altus-metrum.ico and /dev/null differ
diff --git a/icon/altusmetrum.svg b/icon/altusmetrum.svg
new file mode 100644 (file)
index 0000000..e8935a6
--- /dev/null
@@ -0,0 +1,250 @@
+<?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:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2"
+   width="214.27165"
+   height="266.00192"
+   version="1.0"
+   sodipodi:version="0.32"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="altusmetrum.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/home/keithp/src/cc1111/altus-logo/bottom.png"
+   inkscape:export-xdpi="119.89881"
+   inkscape:export-ydpi="119.89881">
+  <metadata
+     id="metadata14">
+    <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>
+  <defs
+     id="defs12">
+    <linearGradient
+       id="linearGradient3165">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3167" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop3169" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3177">
+      <stop
+         style="stop-color:#da7000;stop-opacity:1;"
+         offset="0"
+         id="stop3179" />
+      <stop
+         id="stop3447"
+         offset="0.24528302"
+         style="stop-color:#a63852;stop-opacity:1;" />
+      <stop
+         style="stop-color:#7200a4;stop-opacity:1;"
+         offset="1"
+         id="stop3181" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3169">
+      <stop
+         style="stop-color:#ff8a00;stop-opacity:1;"
+         offset="0"
+         id="stop3171" />
+      <stop
+         id="stop3445"
+         offset="0.71698111"
+         style="stop-color:#c24573;stop-opacity:0.98039216;" />
+      <stop
+         style="stop-color:#8500e7;stop-opacity:0.96078432;"
+         offset="1"
+         id="stop3173" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 121 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="191 : 121 : 1"
+       inkscape:persp3d-origin="95.5 : 80.666667 : 1"
+       id="perspective16" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3169"
+       id="radialGradient3175"
+       cx="951.68713"
+       cy="2305.2668"
+       fx="951.68713"
+       fy="2305.2668"
+       r="951.68701"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3165"
+       id="radialGradient3171"
+       cx="951.68713"
+       cy="1205.2668"
+       fx="951.68713"
+       fy="1205.2668"
+       r="951.68701"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3169"
+       id="radialGradient3020"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="2305.2668"
+       fx="951.68713"
+       fy="2305.2668"
+       r="951.68701" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3165"
+       id="radialGradient3022"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="1205.2668"
+       fx="951.68713"
+       fy="1205.2668"
+       r="951.68701" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3169"
+       id="radialGradient3024"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="2305.2668"
+       fx="951.68713"
+       fy="2305.2668"
+       r="951.68701" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3165"
+       id="radialGradient3026"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="1205.2668"
+       fx="951.68713"
+       fy="1205.2668"
+       r="951.68701" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3169"
+       id="radialGradient3028"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="2305.2668"
+       fx="951.68713"
+       fy="2305.2668"
+       r="951.68701" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3165"
+       id="radialGradient3030"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="1205.2668"
+       fx="951.68713"
+       fy="1205.2668"
+       r="951.68701" />
+    <filter
+       id="filter3005"
+       inkscape:label="Drop Shadow"
+       color-interpolation-filters="sRGB">
+      <feFlood
+         id="feFlood3007"
+         flood-opacity="0.604"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3009"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3011"
+         stdDeviation="80"
+         result="blur" />
+      <feOffset
+         id="feOffset3013"
+         dx="100"
+         dy="100"
+         result="offset" />
+      <feComposite
+         id="feComposite3015"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     inkscape:cy="128.91168"
+     inkscape:cx="271.89232"
+     inkscape:zoom="2.4559706"
+     inkscape:window-height="1177"
+     inkscape:window-width="1462"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     guidetolerance="10.0"
+     gridtolerance="10.0"
+     objecttolerance="10.0"
+     borderopacity="1.0"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     showgrid="false"
+     inkscape:window-x="266"
+     inkscape:window-y="43"
+     inkscape:current-layer="svg2"
+     inkscape:window-maximized="0"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="20"
+     fit-margin-bottom="20" />
+  <g
+     transform="matrix(0.1,0,0,0.1,1.967113,2.4742836)"
+     id="g3"
+     style="fill:url(#radialGradient3175);fill-opacity:1;stroke:url(#radialGradient3171);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;filter:url(#filter3005)">
+    <g
+       transform="translate(20.61545,-27.69425)"
+       style="fill:url(#radialGradient3028);fill-opacity:1;fill-rule:evenodd;stroke:url(#radialGradient3030);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+       id="g5">
+      <path
+         d="m 931.07168,1164.597 248.86992,-331.80265 416.1687,1338.32935 286.6484,267.1042 -520.4224,0 -270.2797,-262.2181 0,-1033.0627 -160.98492,106.6818 -160.98492,-106.6818 0,1033.0627 -270.2797,262.2181 -520.4224,0 286.6484,-267.1042 416.1687,-1338.32935 248.86992,331.80265 z"
+         id="path7"
+         style="fill:url(#radialGradient3020);fill-opacity:1;stroke:url(#radialGradient3022);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+         inkscape:connector-curvature="0" />
+      <path
+         d="m 931.07168,27.69425 224.03682,720.46517 -63.341,76.00913 L 931.07168,486.3269 770.37586,824.16855 707.03486,748.15942 931.07168,27.69425 z"
+         id="path9"
+         style="fill:url(#radialGradient3024);fill-opacity:1;stroke:url(#radialGradient3026);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+         inkscape:connector-curvature="0" />
+    </g>
+  </g>
+</svg>
diff --git a/icon/micro-peak.ico b/icon/micro-peak.ico
deleted file mode 100644 (file)
index b672aa0..0000000
Binary files a/icon/micro-peak.ico and /dev/null differ
diff --git a/icon/micropeak-128.png b/icon/micropeak-128.png
deleted file mode 100644 (file)
index f045dc6..0000000
Binary files a/icon/micropeak-128.png and /dev/null differ
diff --git a/icon/micropeak-16.png b/icon/micropeak-16.png
deleted file mode 100644 (file)
index d814080..0000000
Binary files a/icon/micropeak-16.png and /dev/null differ
diff --git a/icon/micropeak-256.png b/icon/micropeak-256.png
deleted file mode 100644 (file)
index b96d470..0000000
Binary files a/icon/micropeak-256.png and /dev/null differ
diff --git a/icon/micropeak-32.png b/icon/micropeak-32.png
deleted file mode 100644 (file)
index d34c5c1..0000000
Binary files a/icon/micropeak-32.png and /dev/null differ
diff --git a/icon/micropeak-48.png b/icon/micropeak-48.png
deleted file mode 100644 (file)
index 86dc4f7..0000000
Binary files a/icon/micropeak-48.png and /dev/null differ
diff --git a/icon/micropeak-64.png b/icon/micropeak-64.png
deleted file mode 100644 (file)
index 6ca7c2e..0000000
Binary files a/icon/micropeak-64.png and /dev/null differ
diff --git a/icon/micropeak.svg b/icon/micropeak.svg
new file mode 100644 (file)
index 0000000..d37130f
--- /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:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="49.03825"
+   height="43.606411"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="micropeak.svg">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient5343">
+      <stop
+         style="stop-color:#7200a4;stop-opacity:1;"
+         offset="0"
+         id="stop5345" />
+      <stop
+         style="stop-color:#da7000;stop-opacity:1;"
+         offset="1"
+         id="stop5347" />
+    </linearGradient>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Send"
+       style="overflow:visible">
+      <path
+         id="path3798"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3780"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path3792"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Lend"
+       style="overflow:visible">
+      <path
+         id="path3768"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Lend"
+       style="overflow:visible">
+      <path
+         id="path3786"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient5343"
+       id="linearGradient5349"
+       x1="255.48561"
+       y1="275.90405"
+       x2="280.61411"
+       y2="275.90405"
+       gradientUnits="userSpaceOnUse" />
+    <filter
+       id="filter3027"
+       inkscape:label="Drop Shadow"
+       color-interpolation-filters="sRGB">
+      <feFlood
+         id="feFlood3029"
+         flood-opacity="0.604"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3031"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3033"
+         stdDeviation="1.6"
+         result="blur" />
+      <feOffset
+         id="feOffset3035"
+         dx="2"
+         dy="2"
+         result="offset" />
+      <feComposite
+         id="feComposite3037"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="8.160856"
+     inkscape:cx="33.152671"
+     inkscape:cy="27.859227"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1277"
+     inkscape:window-height="894"
+     inkscape:window-x="543"
+     inkscape:window-y="242"
+     inkscape:window-maximized="0"
+     fit-margin-top="-3"
+     fit-margin-left="-4"
+     fit-margin-right="-1"
+     fit-margin-bottom="0" />
+  <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(-241.43522,-252.43073)">
+    <g
+       id="g3000"
+       style="filter:url(#filter3027)">
+      <g
+         id="text2985"
+         style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#7200a4;fill-opacity:1;stroke:none;font-family:Minion Pro;-inkscape-font-specification:Minion Pro">
+        <path
+           inkscape:connector-curvature="0"
+           id="path3003"
+           style="font-size:36px;font-weight:500;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#7200a4;font-family:ITC Benguiat Gothic Std;-inkscape-font-specification:ITC Benguiat Gothic Std Medium"
+           d="m 257.20241,268.30647 c 0,-1.07999 -0.396,-1.872 -1.584,-1.872 -1.188,0 -1.584,0.79201 -1.584,1.872 l 0,8.676 c 0,2.88 -2.052,5.112 -4.824,5.112 -3.06,0 -4.104,-1.872 -4.104,-5.076 l 0,-8.712 c 0,-1.07999 -0.396,-1.872 -1.584,-1.872 -1.188,0 -1.584,0.79201 -1.584,1.872 l 0,21.924 c 0,1.08 0.396,1.872 1.584,1.872 1.188,0 1.584,-0.792 1.584,-1.872 l 0,-6.156 c 0.792,0.612 2.088,0.972 3.564,0.972 2.304,0 4.428,-0.792 5.652,-2.988 l 0.072,0.072 0,1.26 c 0,0.864 0.54,1.44 1.404,1.44 0.864,0 1.404,-0.576 1.404,-1.44 l 0,-15.084" />
+      </g>
+      <path
+         sodipodi:nodetypes="cssc"
+         inkscape:connector-curvature="0"
+         id="path2991"
+         d="m 256.93561,290.70327 c 3.04022,-0.24413 4.30317,-2.66932 5.38268,-5.56604 1.68059,-4.50963 3.67214,-15.86904 8.62227,-20.55527 4.0668,-3.85 8.22354,-3.46656 8.22354,-3.46656"
+         style="fill:none;stroke:url(#linearGradient5349);stroke-width:2.9000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none" />
+      <path
+         inkscape:transform-center-y="-0.40889198"
+         inkscape:transform-center-x="-0.29194889"
+         d="m 282.7522,267.42614 -3.93403,-2.77705 -4.51792,1.66641 1.42544,-4.59964 -2.98096,-3.78185 4.815,-0.0657 2.67559,-4.00372 1.55039,4.55904 4.63457,1.30742 -3.85681,2.88333 z"
+         inkscape:randomized="0"
+         inkscape:rounded="0"
+         inkscape:flatsided="false"
+         sodipodi:arg2="1.7014539"
+         sodipodi:arg1="1.0731354"
+         sodipodi:r2="3.6257365"
+         sodipodi:r1="7.2514729"
+         sodipodi:cy="261.05426"
+         sodipodi:cx="279.29056"
+         sodipodi:sides="5"
+         id="path5341"
+         style="fill:none;stroke:#da7000;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         sodipodi:type="star" />
+    </g>
+  </g>
+</svg>
diff --git a/icon/telegps.svg b/icon/telegps.svg
new file mode 100644 (file)
index 0000000..1e390f3
--- /dev/null
@@ -0,0 +1,324 @@
+<?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:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="151.43401"
+   height="144.50209"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="telegps.svg">
+  <defs
+     id="defs4">
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3169"
+       id="radialGradient3175"
+       cx="951.68713"
+       cy="2305.2668"
+       fx="951.68713"
+       fy="2305.2668"
+       r="951.68701"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3169">
+      <stop
+         style="stop-color:#ff8a00;stop-opacity:1;"
+         offset="0"
+         id="stop3171" />
+      <stop
+         id="stop3445"
+         offset="0.71698111"
+         style="stop-color:#c24573;stop-opacity:0.98039216;" />
+      <stop
+         style="stop-color:#8500e7;stop-opacity:0.96078432;"
+         offset="1"
+         id="stop3173" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3165"
+       id="radialGradient3171"
+       cx="951.68713"
+       cy="1205.2668"
+       fx="951.68713"
+       fy="1205.2668"
+       r="951.68701"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3165">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3167" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop3169" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3169"
+       id="radialGradient2838"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="2305.2668"
+       fx="951.68713"
+       fy="2305.2668"
+       r="951.68701" />
+    <linearGradient
+       id="linearGradient3181">
+      <stop
+         style="stop-color:#ff8a00;stop-opacity:1;"
+         offset="0"
+         id="stop3183" />
+      <stop
+         id="stop3185"
+         offset="0.71698111"
+         style="stop-color:#c24573;stop-opacity:0.98039216;" />
+      <stop
+         style="stop-color:#8500e7;stop-opacity:0.96078432;"
+         offset="1"
+         id="stop3187" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3165"
+       id="radialGradient2840"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="1205.2668"
+       fx="951.68713"
+       fy="1205.2668"
+       r="951.68701" />
+    <linearGradient
+       id="linearGradient3190">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3192" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop3194" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3169"
+       id="radialGradient2830"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="2305.2668"
+       fx="951.68713"
+       fy="2305.2668"
+       r="951.68701" />
+    <linearGradient
+       id="linearGradient3197">
+      <stop
+         style="stop-color:#ff8a00;stop-opacity:1;"
+         offset="0"
+         id="stop3199" />
+      <stop
+         id="stop3201"
+         offset="0.71698111"
+         style="stop-color:#c24573;stop-opacity:0.98039216;" />
+      <stop
+         style="stop-color:#8500e7;stop-opacity:0.96078432;"
+         offset="1"
+         id="stop3203" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3165"
+       id="radialGradient2832"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="1205.2668"
+       fx="951.68713"
+       fy="1205.2668"
+       r="951.68701" />
+    <linearGradient
+       id="linearGradient3206">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3208" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop3210" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3169"
+       id="radialGradient2834"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="2305.2668"
+       fx="951.68713"
+       fy="2305.2668"
+       r="951.68701" />
+    <linearGradient
+       id="linearGradient3213">
+      <stop
+         style="stop-color:#ff8a00;stop-opacity:1;"
+         offset="0"
+         id="stop3215" />
+      <stop
+         id="stop3217"
+         offset="0.71698111"
+         style="stop-color:#c24573;stop-opacity:0.98039216;" />
+      <stop
+         style="stop-color:#8500e7;stop-opacity:0.96078432;"
+         offset="1"
+         id="stop3219" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3165"
+       id="radialGradient2836"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       cx="951.68713"
+       cy="1205.2668"
+       fx="951.68713"
+       fy="1205.2668"
+       r="951.68701" />
+    <linearGradient
+       id="linearGradient3222">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3224" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop3226" />
+    </linearGradient>
+    <radialGradient
+       r="951.68701"
+       fy="2305.2668"
+       fx="951.68713"
+       cy="2305.2668"
+       cx="951.68713"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3232"
+       xlink:href="#linearGradient3169"
+       inkscape:collect="always" />
+    <radialGradient
+       r="951.68701"
+       fy="1205.2668"
+       fx="951.68713"
+       cy="1205.2668"
+       cx="951.68713"
+       gradientTransform="matrix(1,0,0,1.2664529,0,-321.14689)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3234"
+       xlink:href="#linearGradient3165"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3169"
+       id="radialGradient4101"
+       cx="194.54575"
+       cy="361.16367"
+       fx="194.54575"
+       fy="361.16367"
+       r="70.597672"
+       gradientTransform="matrix(1,0,0,0.95908583,137.14286,74.776711)"
+       gradientUnits="userSpaceOnUse" />
+    <filter
+       id="filter3238"
+       inkscape:label="Drop Shadow"
+       color-interpolation-filters="sRGB">
+      <feFlood
+         id="feFlood3240"
+         flood-opacity="0.604"
+         flood-color="rgb(0,0,0)"
+         result="flood" />
+      <feComposite
+         id="feComposite3242"
+         in2="SourceGraphic"
+         in="flood"
+         operator="in"
+         result="composite1" />
+      <feGaussianBlur
+         id="feGaussianBlur3244"
+         stdDeviation="4"
+         result="blur" />
+      <feOffset
+         id="feOffset3246"
+         dx="5"
+         dy="5"
+         result="offset" />
+      <feComposite
+         id="feComposite3248"
+         in2="offset"
+         in="SourceGraphic"
+         operator="over"
+         result="composite2" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="3.959798"
+     inkscape:cx="91.754359"
+     inkscape:cy="68.172898"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="-12"
+     fit-margin-left="-12"
+     fit-margin-right="-6"
+     fit-margin-bottom="-6"
+     inkscape:window-width="996"
+     inkscape:window-height="970"
+     inkscape:window-x="930"
+     inkscape:window-y="553"
+     inkscape:window-maximized="0" />
+  <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(-258.97144,-351.91262)">
+    <path
+       style="fill:url(#radialGradient4101);fill-opacity:1;filter:url(#filter3238)"
+       d="m 261.09094,466.61035 1.9122,-1.69399 39.0721,-36.4688 20.74158,22.05252 -40.71991,38.37279 z m 36.24983,1.34654 -14.08636,-15.38433 -15.33887,14.40857 14.50759,15.23741 z m 18.98704,-17.58715 -14.47613,-15.53942 -14.95191,14.42099 14.19976,15.37575 z m 43.2565,3.24033 -5.69326,-6.00917 -2.76929,1.85727 c -5.01515,3.36349 -10.61773,4.75193 -13.55344,3.35884 -0.90785,-0.4308 -11.20677,-10.85557 -16.46128,-16.61505 -6.3177,-6.92484 -17.77225,-18.68338 -18.08204,-21.53696 l -0.25491,-2.34789 -6.68224,-3.00173 -6.68224,-3.00173 -0.12416,-2.54849 c -0.24316,-4.99109 2.61694,-11.66135 7.10652,-16.57368 6.51922,-7.13306 14.23173,-10.81215 21.4071,-10.21178 l 2.49577,0.20881 2.34108,7.3087 2.34109,7.3087 2.0542,0.21626 c 1.12981,0.11895 2.29245,0.36702 2.58364,0.55127 0.29119,0.18424 11.17756,11.55849 16.63562,17.46044 5.67391,6.13537 16.35301,17.71615 16.74619,18.65715 1.36492,3.26672 -0.56522,9.34479 -4.44838,14.00803 -0.92939,1.1161 -1.6875,2.14976 -1.6847,2.29703 0.003,0.14726 2.44601,2.88431 5.42933,6.08233 2.98332,3.19801 5.42421,6.02814 5.42421,6.28919 0,0.66794 -0.91528,1.72591 -1.73982,2.01104 -0.50334,0.17406 -2.27007,-1.42112 -6.38899,-5.76858 z m -13.8944,-6.52384 c 0.96195,-0.49074 2.46683,-1.3673 3.34417,-1.94791 l 1.59519,-1.05564 -1.69025,-1.72225 c -1.71532,-1.74777 -2.09589,-2.99732 -1.1891,-3.90412 0.98407,-0.98406 2.33559,-0.53387 3.9423,1.31314 l 1.57825,1.81431 1.43638,-1.7099 c 1.7115,-2.03742 3.3933,-5.47555 3.39008,-6.9304 -0.0104,-4.68327 -7.01613,-2.68794 -13.36898,3.80766 -4.26282,4.35861 -6.32786,9.57528 -4.26584,10.77629 1.19252,0.69458 3.36009,0.51166 5.2278,-0.44118 z m -37.53066,-44.39022 c 2.23934,-2.70633 7.29399,-6.99375 10.13666,-8.59806 1.69887,-0.95877 2.21231,-1.46174 2.04152,-1.99985 -0.1255,-0.3954 -1.05734,-3.0661 -2.07077,-5.93487 l -1.84259,-5.21596 -1.60649,0.12825 c -4.1301,0.32972 -9.06228,2.86043 -13.29918,6.82384 -4.03277,3.77245 -7.7843,10.20829 -7.89014,13.53572 l -0.0463,1.4539 5.4085,2.47197 5.4085,2.47197 1.02919,-1.54008 c 0.56606,-0.84704 1.79503,-2.46562 2.73105,-3.59683 z m 32.91039,-10.47213 40.55794,-38.76942 c 7.09795,7.71166 14.5366,15.63755 20.65837,22.2503 l -40.53088,38.2414 z m 35.73645,1.02093 -14.2595,-15.3791 -15.29495,14.35785 14.65467,15.14661 z m 18.6801,-17.55816 -14.10162,-15.40128 -15.32812,14.3973 14.52992,15.24342 z"
+       id="path3063"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccccccccccccccccscssascccssscccscasscsssssccssscssssscssscssccccsccccccccccccccccc" />
+  </g>
+</svg>
diff --git a/jenkins.sh b/jenkins.sh
new file mode 100755 (executable)
index 0000000..e6cc7da
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+# jenkins.sh
+# This script is used by Jenkins to perform a complete rebuild of Altos
+
+
+prefix="--prefix=/usr/local"
+ANDROID_SDK="${ANDROID_SDK:-$HOME/android-sdk-linux}"
+android="--with-android=$ANDROID_SDK"
+# use time if we have it
+time=`which time`
+if [ -n "$time" ]; then
+    time="$time -v"
+fi
+# NOTE: the build process may fail on multi-cpu systems. If it fails try setting cpus=1
+# cpus=$(nproc)
+cpus=1
+
+echo "=== starting altos build at $(date) ==="
+env
+echo "======================================="
+set -x
+
+./autogen.sh $prefix $android
+make -j $cpus clean
+$time make -j $cpus all fat
index 969aa8ad95ac483b6967d6df5354d08880a5f997..d2531133d9d1753d4eae555c57a38dbc714fb1a1 100644 (file)
@@ -5,7 +5,7 @@ AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
 altoslibdir=$(libdir)/altos
 
 altoslib_LTLIBRARIES=libaltos.la
-libaltos_la_LDFLAGS=-version-info 1:0:1
+libaltos_la_LDFLAGS=-version-info 1:0:1 -Wl,-znoexecstack
 
 libaltos_la_SOURCES=\
        libaltos.c \
index a623d5ae0b5c187f9b0c5a7bec962b1c73e2451d..b7ec98fc58f5c17994c523955b4e20c6d680f23d 100644 (file)
@@ -817,7 +817,7 @@ get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
                got_string = CFStringGetCString(entry_as_string,
                                                result, result_len,
                                                kCFStringEncodingASCII);
-    
+
                CFRelease(entry_as_string);
                if (got_string)
                        return 1;
@@ -830,7 +830,7 @@ get_number(io_object_t object, CFStringRef entry, int *result)
 {
        CFTypeRef entry_as_number;
        Boolean got_number;
-       
+
        entry_as_number = IORegistryEntrySearchCFProperty (object,
                                                           kIOServicePlane,
                                                           entry,
@@ -885,7 +885,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
                object = IOIteratorNext(list->iterator);
                if (!object)
                        return 0;
-  
+
                if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
                    !get_number (object, CFSTR(kUSBProductID), &device->product))
                        continue;
@@ -989,7 +989,7 @@ log_message(char *fmt, ...)
        if (log) {
                SYSTEMTIME time;
                GetLocalTime(&time);
-               fprintf (log, "%4d-%02d-%02d %2d:%02d:%02d. ", 
+               fprintf (log, "%4d-%02d-%02d %2d:%02d:%02d. ",
                         time.wYear, time.wMonth, time.wDay,
                         time.wHour, time.wMinute, time.wSecond);
                va_start(a, fmt);
@@ -1340,7 +1340,7 @@ altos_open(struct altos_device *device)
                altos_set_last_windows_error();
                Sleep(100);
        }
-       
+
        if (file->handle == INVALID_HANDLE_VALUE) {
                free(file);
                return NULL;
index 6a6475f0b02e83b4833df0588ff58c576bc594ce..f9a61359672ef4d4ce7f1730d8afe76e8a693893 100644 (file)
@@ -11,6 +11,7 @@ micropeak-windows.nsi
 MicroPeak-Linux-*
 MicroPeak-Mac-*
 MicroPeak-Windows-*
+micropeak.desktop
 *.dll
 *.dylib
 *.so
index 1a614cbdcac694719d9678d284572ecc2cb24e10..216874dfb362c5fe0d518a85fd191bfaacdd991f 100644 (file)
@@ -1,5 +1,5 @@
 JAVAROOT=classes
-AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -source 6
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
 
 man_MANS=micropeak.1
 
@@ -72,6 +72,11 @@ ICONJAR= -C $(ICONDIR) micropeak-16.png \
        -C $(ICONDIR) micropeak-256.png
 
 WINDOWS_ICON=$(ICONDIR)/micro-peak.ico
+MACOSX_ICON=$(ICONDIR)/MicroPeak.icns
+
+desktopdir = $(datadir)/applications
+desktop_file = micropeak.desktop
+desktop_SCRIPTS = $(desktop_file)
 
 all-local: micropeak-test micropeak-jdb $(JAR)
 
@@ -84,7 +89,14 @@ clean-local:
                micropeak micropeak-test micropeak-jdb macosx linux windows micropeak-windows.log \
                micropeak-windows.nsi
 
+EXTRA_DIST = $(desktop_file).in
+
+$(desktop_file): $(desktop_file).in
+       sed -e 's#%bindir%#@bindir@#' -e 's#%icondir%#$(datadir)/icons/hicolor/scalable/apps#' ${srcdir}/micropeak.desktop.in > $@
+       chmod +x $@
+
 LINUX_DIST=MicroPeak-Linux-$(VERSION).tar.bz2
+LINUX_SH=MicroPeak-Linux-$(VERSION).sh
 MACOSX_DIST=MicroPeak-Mac-$(VERSION).dmg
 WINDOWS_DIST=MicroPeak-Windows-$(VERSION_DASH).exe
 
@@ -94,14 +106,14 @@ DOC=$(MICROPEAK_DOC)
 
 FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS)
 
-LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) $(DOC)
-LINUX_EXTRA=micropeak-fat
+LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) $(DOC) micropeak.desktop.in ../icon/micropeak.svg
+LINUX_EXTRA=micropeak-fat micropeak.desktop.in
 
 MACOSX_DRIVER_URL=http://www.ftdichip.com/Drivers/VCP/MacOSX/FTDIUSBSerialDriver_v2_2_18.dmg
 MACOSX_DRIVER=FTDIUSBSerialDriver_v2_2_18.dmg
 MACOSX_INFO_PLIST=Info.plist
 MACOSX_README=ReadMe-Mac.rtf
-MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(MACOSX_DRIVER) $(MACOSX_README) $(DOC)
+MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(MACOSX_DRIVER) $(MACOSX_README) $(DOC) $(MACOSX_ICON)
 
 $(MACOSX_DRIVER):
        wget $(MACOSX_DRIVER_URL)
@@ -119,15 +131,20 @@ if FATINSTALL
 FATTARGET=$(FATDIR)/$(VERSION)
 
 LINUX_DIST_TARGET=$(FATTARGET)/$(LINUX_DIST)
+LINUX_SH_TARGET=$(FATTARGET)/$(LINUX_SH)
 MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST)
 WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST)
 
-fat: $(LINUX_DIST_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
+fat: $(LINUX_DIST_TARGET) $(LINUX_SH_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
 
 $(LINUX_DIST_TARGET): $(LINUX_DIST)
        mkdir -p $(FATTARGET)
        cp -p $< $@
 
+$(LINUX_SH_TARGET): $(LINUX_SH)
+       mkdir -p $(FATTARGET)
+       cp -p $< $@
+
 $(MACOSX_DIST_TARGET): $(MACOSX_DIST)
        mkdir -p $(FATTARGET)
        cp -p $< $@
@@ -137,7 +154,7 @@ $(WINDOWS_DIST_TARGET): $(WINDOWS_DIST)
        cp -p $< $@
 
 else
-fat: $(LINUX_DIST) $(MACOSX_DIST) $(WINDOWS_DIST)
+fat: $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) $(WINDOWS_DIST)
 endif
 
 micropeak: Makefile
@@ -230,6 +247,10 @@ $(LINUX_DIST): $(LINUX_FILES) $(LINUX_EXTRA)
        chmod +x linux/MicroPeak/micropeak
        tar cjf $@ -C linux MicroPeak
 
+$(LINUX_SH): $(LINUX_DIST) $(srcdir)/../altosui/linux-install.sh
+       sed 's/AltOS/MicroPeak/g' $(srcdir)/../altosui/linux-install.sh | cat - $(LINUX_DIST) > $@
+       chmod +x $@
+
 $(MACOSX_DIST): $(MACOSX_FILES)
        -rm -f $@
        -rm -rf macosx
@@ -240,6 +261,7 @@ $(MACOSX_DIST): $(MACOSX_FILES)
        cp -p Info.plist macosx/MicroPeak.app/Contents
        cp -p $(MACOSX_DRIVER) macosx
        mkdir -p macosx/MicroPeak.app/Contents/Resources/Java
+       cp -p $(MACOSX_ICON) macosx/MicroPeak.app/Contents/Resources
        cp -p $(FATJAR) macosx/MicroPeak.app/Contents/Resources/Java/micropeak.jar
        cp -p libaltos.dylib macosx/MicroPeak.app/Contents/Resources/Java
        cp -p $(ALTOSLIB_CLASS) macosx/MicroPeak.app/Contents/Resources/Java
index e786ff1ed136de4e6800feb1263094f38af42a30..ca211f16ee33553edfc102a71741582d817ee226 100644 (file)
@@ -20,8 +20,8 @@ package org.altusmetrum.micropeak;
 import java.lang.*;
 import java.io.*;
 import java.util.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 class MicroIterator implements Iterator<MicroDataPoint> {
        int             i;
index 61faf794e1edb10a51339726f3716a7a46230563..5a5e8c372c2d6788cad7be180e784ab0f984fd50 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.altusmetrum.micropeak;
 
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroDataPoint implements AltosUIDataPoint {
        public double           time;
index 533605d6e2a353827ead217c76119460e10836ed..305421a7b377ac45f2833ba11216baf1c3f95db9 100644 (file)
@@ -21,7 +21,7 @@ import javax.swing.*;
 import java.awt.*;
 import java.awt.event.*;
 import java.util.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroDeviceDialog extends AltosDeviceDialog {
 
index 7d2e9eb4b1f42c711eca1f4c6cc1c44e2fd9a05f..1c70e1d1515da21cc94aa9bc951ea9cc123cde94 100644 (file)
@@ -23,8 +23,8 @@ import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroDownload extends AltosUIDialog implements Runnable, ActionListener, MicroSerialLog, WindowListener {
        MicroPeak       owner;
index c170f544a45a08eded6c93524cefd793b5c5ac87..87d5499b70417d5e91c6cc906a856f3705698250 100644 (file)
@@ -23,8 +23,8 @@ import java.util.ArrayList;
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.filechooser.FileNameExtensionFilter;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroExport extends JFileChooser {
 
index b6a9d4013756e4aed96786ad829cdec275e2ee8d..019346aef29637baaafec278776bfc3a8aa55f84 100644 (file)
@@ -19,8 +19,8 @@ package org.altusmetrum.micropeak;
 
 import java.io.*;
 import java.util.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroFile {
 
index 595d1ff7dfad39df3966af0fbb610268bbdb223a..00b6690a37858de5f231315a906667375666c2ac 100644 (file)
@@ -20,8 +20,8 @@ package org.altusmetrum.micropeak;
 import javax.swing.*;
 import javax.swing.filechooser.FileNameExtensionFilter;
 import java.io.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroFileChooser extends JFileChooser {
        JFrame  frame;
index ef8b24cc3a370c88676d6dd4792919453cd56d7b..5bfe5bf7bd18e30851b01153568909bfeced6231 100644 (file)
@@ -21,7 +21,7 @@ import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.util.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroFrame extends AltosUIFrame {
        static String[] micro_icon_names = {
index 5960fe4dfbfc7cfce2a500bfff951997e0357785..f99689197ffa649ba95f70395965eddad149b8f0 100644 (file)
@@ -22,8 +22,8 @@ import java.util.ArrayList;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 import org.jfree.ui.*;
 import org.jfree.chart.*;
index 78bc857ec2818746a3fc9f05a5b5d97556286ce0..19e91660d6226017cddef42640a748108d2e60e4 100644 (file)
@@ -23,8 +23,8 @@ import javax.swing.*;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroPeak extends MicroFrame implements ActionListener, ItemListener {
 
index d64da387c27e6530b91f2ae6cafe7f5c4ad687e7..26d62012982f097df604e45a93a0249edc0f402d 100644 (file)
@@ -20,8 +20,8 @@ package org.altusmetrum.micropeak;
 import java.awt.*;
 import java.io.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroRaw extends JTextArea {
 
index 0addfa8861c8008eacec07e8abf7bd076aea7908..7c5d6abe99dcfb093d848d7e266237fe90126707 100644 (file)
@@ -24,8 +24,8 @@ import javax.swing.filechooser.FileNameExtensionFilter;
 import java.io.*;
 import java.util.concurrent.*;
 import java.util.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroSave extends JFileChooser {
 
index 39f421ec6b7fb3f1ccb7ed3fd6cc4396d90ef550..37b68636b73dd639d3e57445b6e4bf6b6fcd5859 100644 (file)
@@ -20,7 +20,7 @@ package org.altusmetrum.micropeak;
 import java.util.*;
 import java.io.*;
 import libaltosJNI.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroSerial extends InputStream {
        SWIGTYPE_p_altos_file   file;
index 0a5a0b91de84018054ea088158f081da60b11a36..7300f06d33856e8b47a3d43528303a837c29bb96 100644 (file)
@@ -20,7 +20,7 @@ package org.altusmetrum.micropeak;
 import java.util.*;
 import java.io.*;
 import libaltosJNI.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public interface MicroSerialLog {
 
index 765525b0959f48caf277ccd401d45d1730997df4..45c9f225131b5babf3212622a7d85e4d20984e53 100644 (file)
@@ -18,8 +18,8 @@
 package org.altusmetrum.micropeak;
 
 import java.io.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroStats {
        double          coast_height;
index ea1609ac7fac43ef935bdd7fce910261035b8bd7..3b17e731fff1112e1ff093b21e5d0df0d4a946eb 100644 (file)
@@ -19,8 +19,8 @@ package org.altusmetrum.micropeak;
 
 import java.awt.*;
 import javax.swing.*;
-import org.altusmetrum.altoslib_3.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroStatsTable extends JComponent implements AltosFontListener {
        GridBagLayout   layout;
@@ -59,6 +59,7 @@ public class MicroStatsTable extends JComponent implements AltosFontListener {
                        texts = new JTextField[values.length];
                        for (int j = 0; j < values.length; j++) {
                                JTextField value = new JTextField(values[j]);
+                               value.setEditable(false);
                                value.setFont(AltosUILib.value_font);
                                value.setHorizontalAlignment(SwingConstants.RIGHT);
                                texts[j] = value;
@@ -160,4 +161,4 @@ public class MicroStatsTable extends JComponent implements AltosFontListener {
                this(new MicroStats());
        }
        
-}
\ No newline at end of file
+}
index 3bd61470cc847c4eb0d763562014f10c73f23ab7..437fa0bcde45c54374d2591814d0fca144b47460 100644 (file)
@@ -19,7 +19,7 @@ package org.altusmetrum.micropeak;
 
 import java.util.*;
 import libaltosJNI.*;
-import org.altusmetrum.altosuilib_1.*;
+import org.altusmetrum.altosuilib_2.*;
 
 public class MicroUSB extends altos_device implements AltosDevice {
 
index 656f8af3e4757d2e43c83ef5f516a74cb387a384..6dc9d8c15ebedd739ed59cd6a7e4359f62c69cd6 100644 (file)
@@ -1,8 +1,10 @@
 !addplugindir Instdrv/NSIS/Plugins
-; Definitions for Java 1.6 Detection
-!define JRE_VERSION "1.6"
-!define JRE_ALTERNATE "1.7"
-!define JRE_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=52247&/jre-6u27-windows-i586-p.exe"
+!include x64.nsh
+; Definitions for Java 1.7 Detection
+!define JRE_VERSION "1.7"
+!define JRE_ALTERNATE "1.6"
+!define JRE32_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=83383&/jre-7u51-windows-i586.exe"
+!define JRE64_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=83385&/jre-7u51-windows-x64.exe"
 !define PRODUCT_NAME "Altus Metrum Windows Software"
 
 Name "Altus Metrum MicroPeak Installer"
@@ -23,12 +25,34 @@ ShowInstDetails Show
 
 ComponentText "Altus Metrum MicroPeak Software Installer"
 
+Function .onInit
+       DetailPrint "Checking host operating system"
+       ${If} ${RunningX64}
+               DetailPrint "Installer running on 64-bit host"
+               SetRegView 64
+               StrCpy $INSTDIR "$PROGRAMFILES64\AltusMetrum"
+               ${DisableX64FSRedirection}
+       ${EndIf}
+FunctionEnd
+
+Var JavaDownload
+Var JavaBits
+
 Function GetJRE
-        MessageBox MB_OK "${PRODUCT_NAME} uses Java ${JRE_VERSION} 32-bit, it will now \
-                         be downloaded and installed"
+       ${If} ${RunningX64}
+          StrCpy $JavaDownload ${JRE64_URL}
+          StrCpy $JavaBits "64"
+       ${Else}
+          StrCpy $JavaDownload ${JRE32_URL}
+          StrCpy $JavaBits "32"
+       ${EndIf}
+
+        MessageBox MB_OK "${PRODUCT_NAME} uses Java ${JRE_VERSION}, \
+                       $JavaBits bits, it will now \
+                        be downloaded and installed"
 
         StrCpy $2 "$TEMP\Java Runtime Environment.exe"
-        nsisdl::download /TIMEOUT=30000 ${JRE_URL} $2
+        nsisdl::download /TIMEOUT=30000 $JavaDownload $2
         Pop $R0 ;Get the return value
                 StrCmp $R0 "success" +3
                 MessageBox MB_OK "Download failed: $R0"
@@ -37,7 +61,6 @@ Function GetJRE
         Delete $2
 FunctionEnd
 
-
 Function DetectJRE
   ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" \
              "CurrentVersion"
diff --git a/micropeak/micropeak.desktop.in b/micropeak/micropeak.desktop.in
new file mode 100644 (file)
index 0000000..abdf286
--- /dev/null
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Type=Application
+Name=MicroPeak
+GenericName=MicroPeak download and analysis
+Comment=View and log data from MicroPeak altimeters
+Icon=%icondir%/micropeak.svg
+Exec=%bindir%/micropeak %f
+Terminal=false
+MimeType=text/plain;
+Categories=Education;Electronics;Science;
diff --git a/signing-driver b/signing-driver
new file mode 100644 (file)
index 0000000..177c507
--- /dev/null
@@ -0,0 +1,20 @@
+Notes on getting a signing key for driver signing
+
+http://technet.microsoft.com/en-us/library/dd919238%28v=ws.10%29.aspx
+
+# use MMC to add the certificates snap-in for ComputerAccount on Local computer
+
+Run console as Administrator:
+
+makecert -r -n "CN=AltusMetrum" -ss AltusMetrumCertStore -sr LocalMachine
+
+# <path> contains the altusmetrum.inf file we ship. Make sure <path>
+# is otherwise empty or inf2cat will get confused
+
+inf2cat /driver:<path> /os:7_X86,7_X64,8_X86,8_X64
+
+signtool sign /s AltusMetrumCertStore /n “AltusMetrum"
+         /t http://timestamp.verisign.com/scripts/timestamp.dll
+         altusmetrum.cat
+
+pnputil -i -a altusmetrum.inf
index 392262d48db8a66d17ef43a71b36f221285a9896..4e8b3c20c6a94562676cd67fffb28606b5b441b8 100644 (file)
@@ -19,11 +19,10 @@ include Makedefs
 SDCCDIRS=\
        telemetrum-v1.2 telemetrum-v1.1 telemetrum-v1.0 \
        teledongle-v0.2 \
-       telemini-v1.0 \
+       telemini-v1.0 telemini-v2.0 \
        telebt-v1.0 \
        teleterra-v0.2 teleshield-v0.1 \
-       telefire-v0.1 telefire-v0.2 \
-       telemini-v2.0
+       telefire-v0.1 telefire-v0.2
 
 ARMM3DIRS=\
        telemega-v0.1 telemega-v0.1/flash-loader \
@@ -31,8 +30,10 @@ ARMM3DIRS=\
        telemetrum-v2.0 telemetrum-v2.0/flash-loader \
        megadongle-v0.1 megadongle-v0.1/flash-loader \
        telegps-v0.3 telegps-v0.3/flash-loader \
+       telegps-v1.0 telegps-v1.0/flash-loader \
        telelco-v0.2 telelco-v0.2/flash-loader \
-       telescience-v0.2 telescience-v0.2/flash-loader
+       telescience-v0.2 telescience-v0.2/flash-loader \
+       teleballoon-v2.0
 
 ARMM0DIRS=\
        easymini-v1.0 easymini-v1.0/flash-loader
index 3556f54c00d511932baabad43a3d358311233d0f..f64f7bde41e626218669f7cae25d8789c5812f41 100644 (file)
@@ -40,11 +40,98 @@ ao_async_byte(uint8_t byte)
 {
        uint8_t         b;
        uint16_t        w;
+       uint8_t         v;
+       uint8_t         bit;
+       uint8_t         w_hi, w_lo;
 
        /*    start           data           stop */
        w = (0x000 << 0) | (byte << 1) | (0x001 << 9);
 
+       w_hi = w >> 8;
+       w_lo = w;
+
        ao_arch_block_interrupts();
+
+       /* Ok, this is a bit painful.
+        * We need this loop to be precisely timed, which
+        * means knowing exactly how many instructions will
+        * be executed for each bit. It's easy to do that by
+        * compiling the C code and looking at the output,
+        * but we need this code to work even if the compiler
+        * changes. So, just hand-code the whole thing
+        */
+
+       asm volatile (
+               "       ldi     %[b], 10\n"             // loop value
+               "loop:\n"
+               "       in      %[v], %[port]\n"        // read current value
+               "       andi    %[v], %[led_mask]\n"    // mask to clear LED bit
+               "       mov     %[bit], %[w_lo]\n"      // get current data byte
+               "       andi    %[bit], 0x01\n"         // get current data bit
+#if AO_LED_SERIAL >= 1
+               "       add     %[bit],%[bit]\n"        // shift by one
+#else
+               "       nop\n"
+#endif
+#if AO_LED_SERIAL >= 2
+               "       add     %[bit],%[bit]\n"        // shift by one
+#else
+               "       nop\n"
+#endif
+#if AO_LED_SERIAL >= 3
+               "       add     %[bit],%[bit]\n"        // shift by one
+#else
+               "       nop\n"
+#endif
+#if AO_LED_SERIAL >= 4
+               "       add     %[bit],%[bit]\n"        // shift by one
+#else
+               "       nop\n"
+#endif
+#if AO_LED_SERIAL >= 5
+               "       add     %[bit],%[bit]\n"        // shift by one
+#else
+               "       nop\n"
+#endif
+#if AO_LED_SERIAL >= 6
+               "       add     %[bit],%[bit]\n"        // shift by one
+#else
+               "       nop\n"
+#endif
+#if AO_LED_SERIAL >= 7
+               "       add     %[bit],%[bit]\n"        // shift by one
+#else
+               "       nop\n"
+#endif
+               "       or      %[v], %[bit]\n"         // add to register
+               "       out     %[port], %[v]\n"        // write current value
+               "       lsr     %[w_hi]\n"              // shift data
+               "       ror     %[w_lo]\n"              //  ...
+               "       nop\n"
+               "       nop\n"
+               "       nop\n"
+               "       nop\n"
+               "       nop\n"
+
+               "       nop\n"
+               "       nop\n"
+               "       nop\n"
+               "       subi    %[b], 1\n"              // decrement bit count
+               "       brne    loop\n"                 // jump back to top
+               : [v]        "=&r" (v),
+                 [bit]      "=&r" (bit),
+                 [b]        "=&r" (b),
+                 [w_lo]     "+r" (w_lo),
+                 [w_hi]     "+r" (w_hi)
+               : [port]     "I"  (_SFR_IO_ADDR(LED_PORT)),
+                 [led_mask] "M"  ((~(1 << AO_LED_SERIAL)) & 0xff)
+               );
+
+#if 0
+       /*
+        * Here's the equivalent C code to document
+        * what the above assembly code does
+        */
        for (b = 0; b < 10; b++) {
                uint8_t v = LED_PORT & ~(1 << AO_LED_SERIAL);
                v |= (w & 1) << AO_LED_SERIAL;
@@ -54,6 +141,7 @@ ao_async_byte(uint8_t byte)
                /* Carefully timed to hit around 9600 baud */
                asm volatile ("nop");
                asm volatile ("nop");
+               asm volatile ("nop");
 
                asm volatile ("nop");
                asm volatile ("nop");
@@ -67,5 +155,6 @@ ao_async_byte(uint8_t byte)
                asm volatile ("nop");
                asm volatile ("nop");
        }
+#endif
        ao_arch_release_interrupts();
 }
index 6d9bfea2098f9102d4fff464f9f5760ec588a524..e21ad0471ea85465d89838c267830ab70fc6d0f8 100644 (file)
@@ -2,7 +2,7 @@
 # AltOS build
 #
 #
-vpath % ..:../core:../product:../drivers:../avr
+vpath % ..:../kernel:../product:../drivers:../avr
 vpath make-altitude ..
 vpath make-kalman ..
 vpath kalman.5c ../kalman
@@ -46,7 +46,7 @@ PRODUCT=AvrDemo-v0.0
 MCU=atmega32u4
 PRODUCT_DEF=-DAVR_DEMO
 IDPRODUCT=0x000a
-CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I..
+CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../kernel -I..
 CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues
 
 NICKLE=nickle
index bd75b17d7a5cc21638ea2d02c81b04019525a8ad..cb0455c2d1ac6886bad4846c8d0184ed2efeaf00 100644 (file)
@@ -46,7 +46,7 @@ static __xdata uint8_t        ao_usb_ep0_out_len;
 static __xdata uint8_t *__xdata ao_usb_ep0_out_data;
 
 static __xdata uint8_t ao_usb_in_flushed;
-static __xdata uint8_t ao_usb_running;
+__xdata uint8_t                ao_usb_running;
 static __xdata uint8_t ao_usb_configuration;
 static __xdata uint8_t ueienx_0;
 
index 78b653b3049abbbf5cd595802d67e5ced89755e1..0ea30e1dbd4d762e3a44812b6700ccb071bd6cbb 100644 (file)
@@ -3,7 +3,7 @@ CC=$(SDCC)
 
 CFLAGS=--model-small --debug --opt-code-speed -DCODESIZE=$(CODESIZE)
 
-CFLAGS += $(PRODUCT_DEF) -I. -I.. -I../core -I../cc1111 -I../drivers -I../product
+CFLAGS += $(PRODUCT_DEF) -I. -I.. -I../kernel -I../cc1111 -I../drivers -I../product
 
 CODESIZE ?= 0x8000
 
index 34235b085421d3c49d2d86852d57f0ff39b335eb..fcac331be55363d3d9a6a4fffb17432acc546283 100644 (file)
@@ -326,4 +326,6 @@ void
 ao_p0_isr(void) __interrupt(13);
 #endif
 
+#define AO_ADC_MAX     32767
+
 #endif /* _AO_ARCH_H_ */
index 2f0e2884826107ba51ab49166ad3789827ca7e7c..2b19f1f6b4bc20f986443c904e400f6f171f871a 100644 (file)
 #ifndef _AO_PINS_H_
 #define _AO_PINS_H_
 
-#define HAS_RADIO      1
+#define HAS_RADIO              1
+#define DISABLE_LOG_SPACE      1
 
 #if defined(TELEMETRUM_V_1_0)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              1
        #define HAS_USB                 1
        #define HAS_BEEP                1
+       #define HAS_BEEP_CONFIG         0
        #define HAS_GPS                 1
        #define HAS_SERIAL_1            1
        #define HAS_ADC                 1
 #endif
 
 #if defined(TELEMETRUM_V_1_1)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              1
        #define HAS_USB                 1
        #define HAS_BEEP                1
+       #define HAS_BEEP_CONFIG         0
+       #define HAS_BATTERY_REPORT      1
        #define HAS_GPS                 1
        #define HAS_SERIAL_1            1
        #define HAS_ADC                 1
 #endif
 
 #if defined(TELEMETRUM_V_1_2)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              1
        #define HAS_USB                 1
        #define HAS_BEEP                1
+       #define HAS_BEEP_CONFIG         0
+       #define HAS_BATTERY_REPORT      1
        #define HAS_GPS                 1
        #define HAS_SERIAL_1            1
        #define HAS_ADC                 1
 #endif
 
 #if defined(TELEMINI_V_1_0)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              1
        #define HAS_USB                 0
        #define HAS_BEEP                0
 #endif
 
 #if defined(TELENANO_V_0_1)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              1
        #define HAS_USB                 0
        #define HAS_BEEP                0
 #endif
 
 #if defined(TELEMETRUM_V_0_1)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              1
        #define HAS_USB                 1
        #define HAS_BEEP                1
+       #define HAS_BEEP_CONFIG         0
        #define HAS_GPS                 1
        #define HAS_SERIAL_1            1
        #define HAS_ADC                 1
 #endif
 
 #if defined(TELEDONGLE_V_0_1)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              0
        #define HAS_USB                 1
        #define HAS_BEEP                0
 #endif
 
 #if defined(TIDONGLE)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              0
        #define HAS_USB                 1
        #define HAS_BEEP                0
 #endif
 
 #if defined(TELEBT_V_0_0)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              0
        #define HAS_USB                 1
        #define HAS_BEEP                0
 #endif
 
 #if defined(TELEBT_V_0_1)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              0
        #define HAS_USB                 1
        #define HAS_BEEP                1
+       #define HAS_BEEP_CONFIG         0
        #define HAS_SERIAL_1            1
        #define HAS_SERIAL_1_ALT_1      1
        #define HAS_SERIAL_1_ALT_2      0
 #endif
 
 #if defined(TELELAUNCH_V_0_1)
+       /* Discontinued and was never built with CC1111 chips needing this */
+       #define NEEDS_CC1111_CLOCK_HACK 0
        #define HAS_FLIGHT              0
        #define HAS_USB                 1
        #define HAS_BEEP                1
@@ -572,4 +602,21 @@ struct ao_adc {
 #endif
 };
 
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS    5       /* 5k */
+#define AO_BATTERY_DIV_MINUS   10      /* 10k */
+
+/*
+ * Voltage divider on ADC igniter samplers
+ */
+#define AO_IGNITE_DIV_PLUS     100     /* 100k */
+#define AO_IGNITE_DIV_MINUS    27      /* 27k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV    33
+
 #endif /* _AO_PINS_H_ */
index 75cc4ce8b562e6f339d76451a103b9e3bdd73fc0..2fbc6621dfdf43c9b989f5d1cbad0092b8498a9f 100644 (file)
@@ -83,25 +83,57 @@ ao_timer_init(void)
        T1CTL = T1CTL_MODE_MODULO | T1CTL_DIV_8;
 }
 
+#ifndef NEEDS_CC1111_CLOCK_HACK
+#define NEEDS_CC1111_CLOCK_HACK                1
+#endif
+
+#if NEEDS_CC1111_CLOCK_HACK
+static void
+ao_clock_delay(void)
+{
+       uint16_t        i = 0;
+
+       while (--i)
+               ao_arch_nop();
+}
+#endif
+
 /*
  * AltOS always cranks the clock to the max frequency
  */
 void
 ao_clock_init(void)
 {
+#if NEEDS_CC1111_CLOCK_HACK
+       /* Power up both oscillators */
+       SLEEP &= ~(SLEEP_OSC_PD);
+
+       /* Switch to the HFRC oscillator */
+       CLKCON = (CLKCON & ~CLKCON_OSC_MASK) | (CLKCON_OSC_RC);
+
+       /* Wait for the HFRC oscillator to be stable */
+       while (!(SLEEP & SLEEP_HFRC_STB))
+               ;
+
+       /* Delay for 'a while' waiting for the crystal to
+        * stabilize -- the XOSC_STB bit isn't reliable
+        *
+        *  http://www.ti.com/lit/er/swrz022c/swrz022c.pdf
+        */
+
+       ao_clock_delay();
+#endif
+
        /* Switch system clock to crystal oscilator */
        CLKCON = (CLKCON & ~CLKCON_OSC_MASK) | (CLKCON_OSC_XTAL);
 
+       /* Wait for the HFRC oscillator to be stable */
        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 b0ab409d7e72d96bbce7c3aba51231d13771ae89..d9d255f8334838cc9c5c7eb6632624536a77fb34 100644 (file)
@@ -24,7 +24,7 @@ static __xdata uint16_t       ao_usb_in_bytes;
 static __pdata uint16_t ao_usb_in_bytes_last;
 static __xdata uint16_t        ao_usb_out_bytes;
 static __pdata uint8_t ao_usb_iif;
-static __pdata uint8_t ao_usb_running;
+__pdata uint8_t                ao_usb_running;
 
 static void
 ao_usb_set_interrupts(void)
@@ -274,7 +274,7 @@ ao_usb_ep0_setup(void)
                        ao_usb_ep0_in_len = ao_usb_setup.length;
                ao_usb_ep0_flush();
        } else if (ao_usb_ep0_out_len) {
-               
+
                /* Receiving data from the host
                 */
                ao_usb_ep0_state = AO_USB_EP0_DATA_OUT;
@@ -448,6 +448,9 @@ ao_usb_enable(void)
        USBCIF = 0;
        USBOIF = 0;
        USBIIF = 0;
+#if HAS_USB_PULLUP
+       ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 0);
+#endif
 }
 
 void
@@ -459,6 +462,10 @@ ao_usb_disable(void)
        USBCIE = 0;
        IEN2 &= ~IEN2_USBIE;
 
+#if HAS_USB_PULLUP
+       ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, AO_USB_PULLUP, 0);
+#endif
+
        /* Clear any pending interrupts */
        USBCIF = 0;
        USBOIF = 0;
@@ -471,6 +478,9 @@ ao_usb_disable(void)
 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();
 
        ao_add_task(&ao_usb_task, ao_usb_ep0, "usb");
diff --git a/src/core/altitude.h b/src/core/altitude.h
deleted file mode 100644 (file)
index a278bbc..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*max error 3.197865153490684 at   0.782%. Average error 0.260150920474668*/
-#define NALT 129
-#define ALT_FRAC_BITS 8
-    15835, /*  10.56 kPa   0.000% */
-    15332, /*  11.42 kPa   0.781% */
-    14868, /*  12.29 kPa   1.563% */
-    14435, /*  13.16 kPa   2.344% */
-    14030, /*  14.02 kPa   3.125% */
-    13649, /*  14.90 kPa   3.906% */
-    13290, /*  15.76 kPa   4.688% */
-    12950, /*  16.63 kPa   5.469% */
-    12627, /*  17.50 kPa   6.250% */
-    12320, /*  18.37 kPa   7.031% */
-    12027, /*  19.24 kPa   7.813% */
-    11747, /*  20.10 kPa   8.594% */
-    11479, /*  20.97 kPa   9.375% */
-    11222, /*  21.84 kPa  10.156% */
-    10975, /*  22.71 kPa  10.938% */
-    10736, /*  23.58 kPa  11.719% */
-    10504, /*  24.44 kPa  12.500% */
-    10278, /*  25.31 kPa  13.281% */
-    10059, /*  26.18 kPa  14.063% */
-     9846, /*  27.05 kPa  14.844% */
-     9638, /*  27.91 kPa  15.625% */
-     9435, /*  28.78 kPa  16.406% */
-     9237, /*  29.65 kPa  17.188% */
-     9044, /*  30.52 kPa  17.969% */
-     8855, /*  31.39 kPa  18.750% */
-     8670, /*  32.26 kPa  19.531% */
-     8490, /*  33.13 kPa  20.313% */
-     8313, /*  33.99 kPa  21.094% */
-     8140, /*  34.86 kPa  21.875% */
-     7970, /*  35.73 kPa  22.656% */
-     7803, /*  36.60 kPa  23.438% */
-     7640, /*  37.47 kPa  24.219% */
-     7480, /*  38.33 kPa  25.000% */
-     7322, /*  39.20 kPa  25.781% */
-     7168, /*  40.07 kPa  26.563% */
-     7016, /*  40.94 kPa  27.344% */
-     6867, /*  41.80 kPa  28.125% */
-     6720, /*  42.67 kPa  28.906% */
-     6575, /*  43.54 kPa  29.688% */
-     6433, /*  44.41 kPa  30.469% */
-     6294, /*  45.28 kPa  31.250% */
-     6156, /*  46.15 kPa  32.031% */
-     6020, /*  47.01 kPa  32.813% */
-     5887, /*  47.88 kPa  33.594% */
-     5755, /*  48.75 kPa  34.375% */
-     5625, /*  49.62 kPa  35.156% */
-     5497, /*  50.49 kPa  35.938% */
-     5371, /*  51.35 kPa  36.719% */
-     5247, /*  52.22 kPa  37.500% */
-     5124, /*  53.09 kPa  38.281% */
-     5003, /*  53.96 kPa  39.063% */
-     4883, /*  54.83 kPa  39.844% */
-     4765, /*  55.69 kPa  40.625% */
-     4648, /*  56.56 kPa  41.406% */
-     4533, /*  57.43 kPa  42.188% */
-     4419, /*  58.30 kPa  42.969% */
-     4307, /*  59.17 kPa  43.750% */
-     4196, /*  60.03 kPa  44.531% */
-     4086, /*  60.90 kPa  45.313% */
-     3977, /*  61.77 kPa  46.094% */
-     3870, /*  62.63 kPa  46.875% */
-     3764, /*  63.51 kPa  47.656% */
-     3659, /*  64.38 kPa  48.438% */
-     3555, /*  65.24 kPa  49.219% */
-     3453, /*  66.11 kPa  50.000% */
-     3351, /*  66.98 kPa  50.781% */
-     3250, /*  67.85 kPa  51.563% */
-     3151, /*  68.72 kPa  52.344% */
-     3052, /*  69.58 kPa  53.125% */
-     2955, /*  70.45 kPa  53.906% */
-     2858, /*  71.32 kPa  54.688% */
-     2763, /*  72.19 kPa  55.469% */
-     2668, /*  73.06 kPa  56.250% */
-     2574, /*  73.92 kPa  57.031% */
-     2482, /*  74.79 kPa  57.813% */
-     2390, /*  75.66 kPa  58.594% */
-     2298, /*  76.52 kPa  59.375% */
-     2208, /*  77.40 kPa  60.156% */
-     2119, /*  78.26 kPa  60.938% */
-     2030, /*  79.13 kPa  61.719% */
-     1942, /*  80.00 kPa  62.500% */
-     1855, /*  80.87 kPa  63.281% */
-     1769, /*  81.74 kPa  64.063% */
-     1683, /*  82.60 kPa  64.844% */
-     1598, /*  83.47 kPa  65.625% */
-     1514, /*  84.34 kPa  66.406% */
-     1430, /*  85.21 kPa  67.188% */
-     1347, /*  86.08 kPa  67.969% */
-     1265, /*  86.94 kPa  68.750% */
-     1184, /*  87.81 kPa  69.531% */
-     1103, /*  88.68 kPa  70.313% */
-     1023, /*  89.55 kPa  71.094% */
-      943, /*  90.41 kPa  71.875% */
-      864, /*  91.28 kPa  72.656% */
-      786, /*  92.15 kPa  73.438% */
-      708, /*  93.02 kPa  74.219% */
-      631, /*  93.89 kPa  75.000% */
-      554, /*  94.76 kPa  75.781% */
-      478, /*  95.63 kPa  76.563% */
-      403, /*  96.49 kPa  77.344% */
-      328, /*  97.36 kPa  78.125% */
-      254, /*  98.23 kPa  78.906% */
-      180, /*  99.10 kPa  79.688% */
-      106, /*  99.97 kPa  80.469% */
-       34, /* 100.83 kPa  81.250% */
-      -39, /* 101.70 kPa  82.031% */
-     -111, /* 102.57 kPa  82.813% */
-     -182, /* 103.44 kPa  83.594% */
-     -253, /* 104.30 kPa  84.375% */
-     -323, /* 105.17 kPa  85.156% */
-     -393, /* 106.04 kPa  85.938% */
-     -462, /* 106.91 kPa  86.719% */
-     -531, /* 107.78 kPa  87.500% */
-     -600, /* 108.65 kPa  88.281% */
-     -668, /* 109.51 kPa  89.063% */
-     -736, /* 110.38 kPa  89.844% */
-     -803, /* 111.25 kPa  90.625% */
-     -870, /* 112.12 kPa  91.406% */
-     -936, /* 112.99 kPa  92.188% */
-    -1002, /* 113.85 kPa  92.969% */
-    -1068, /* 114.72 kPa  93.750% */
-    -1133, /* 115.59 kPa  94.531% */
-    -1198, /* 116.46 kPa  95.313% */
-    -1262, /* 117.33 kPa  96.094% */
-    -1326, /* 118.19 kPa  96.875% */
-    -1389, /* 119.06 kPa  97.656% */
-    -1453, /* 119.93 kPa  98.438% */
-    -1516, /* 120.80 kPa  99.219% */
-    -1578, /* 121.67 kPa 100.000% */
diff --git a/src/core/ao.h b/src/core/ao.h
deleted file mode 100644 (file)
index 29ad260..0000000
+++ /dev/null
@@ -1,1041 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _AO_H_
-#define _AO_H_
-
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <stddef.h>
-#include <ao_pins.h>
-#include <ao_arch.h>
-
-#define TRUE 1
-#define FALSE 0
-
-/* Convert a __data pointer into an __xdata pointer */
-#ifndef DATA_TO_XDATA
-#define DATA_TO_XDATA(a)       (a)
-#endif
-#ifndef PDATA_TO_XDATA
-#define PDATA_TO_XDATA(a)      (a)
-#endif
-#ifndef CODE_TO_XDATA
-#define CODE_TO_XDATA(a)       (a)
-#endif
-
-#ifndef HAS_TASK
-#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
-#include <ao_notask.h>
-#endif
-
-/*
- * ao_panic.c
- */
-
-#define AO_PANIC_NO_TASK       1       /* AO_NUM_TASKS is not large enough */
-#define AO_PANIC_DMA           2       /* Attempt to start DMA while active */
-#define AO_PANIC_MUTEX         3       /* Mis-using mutex API */
-#define AO_PANIC_EE            4       /* Mis-using eeprom API */
-#define AO_PANIC_LOG           5       /* Failing to read/write log data */
-#define AO_PANIC_CMD           6       /* Too many command sets registered */
-#define AO_PANIC_STDIO         7       /* Too many stdio handlers registered */
-#define AO_PANIC_REBOOT                8       /* Reboot failed */
-#define AO_PANIC_FLASH         9       /* Invalid flash part (or wrong blocksize) */
-#define AO_PANIC_USB           10      /* Trying to send USB packet while busy */
-#define AO_PANIC_BT            11      /* Communications with bluetooth device failed */
-#define AO_PANIC_STACK         12      /* Stack overflow */
-#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 */
-#define AO_PANIC_SELF_TEST_MS5607      0x40 | 4        /* Self test failure */
-
-/* Stop the operating system, beeping and blinking the reason */
-void
-ao_panic(uint8_t reason);
-
-/*
- * ao_timer.c
- */
-
-#ifndef AO_TICK_TYPE
-#define AO_TICK_TYPE   uint16_t
-#define AO_TICK_SIGNED int16_t
-#endif
-
-extern volatile __data AO_TICK_TYPE ao_tick_count;
-
-/* Our timer runs at 100Hz */
-#ifndef AO_HERTZ
-#define AO_HERTZ               100
-#endif
-#define AO_MS_TO_TICKS(ms)     ((ms) / (1000 / AO_HERTZ))
-#define AO_SEC_TO_TICKS(s)     ((s) * AO_HERTZ)
-
-/* Returns the current time in ticks */
-AO_TICK_TYPE
-ao_time(void);
-
-/* Suspend the current task until ticks time has passed */
-void
-ao_delay(uint16_t ticks);
-
-/* Set the ADC interval */
-void
-ao_timer_set_adc_interval(uint8_t interval);
-
-/* Timer interrupt */
-void
-ao_timer_isr(void) ao_arch_interrupt(9);
-
-/* Initialize the timer */
-void
-ao_timer_init(void);
-
-/* Initialize the hardware clock. Must be called first */
-void
-ao_clock_init(void);
-
-/*
- * ao_mutex.c
- */
-
-#ifndef ao_mutex_get
-void
-ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant;
-
-void
-ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant;
-#endif
-
-/*
- * ao_cmd.c
- */
-
-enum ao_cmd_status {
-       ao_cmd_success = 0,
-       ao_cmd_lex_error = 1,
-       ao_cmd_syntax_error = 2,
-};
-
-extern __pdata uint16_t ao_cmd_lex_i;
-extern __pdata uint32_t ao_cmd_lex_u32;
-extern __pdata char    ao_cmd_lex_c;
-extern __pdata enum ao_cmd_status ao_cmd_status;
-
-void
-ao_put_string(__code char *s);
-
-void
-ao_cmd_lex(void);
-
-void
-ao_cmd_put8(uint8_t v);
-
-void
-ao_cmd_put16(uint16_t v);
-
-uint8_t
-ao_cmd_is_white(void);
-
-void
-ao_cmd_white(void);
-
-int8_t
-ao_cmd_hexchar(char c);
-
-void
-ao_cmd_hexbyte(void);
-
-void
-ao_cmd_hex(void);
-
-void
-ao_cmd_decimal(void) __reentrant;
-
-/* Read a single hex nibble off stdin. */
-uint8_t
-ao_getnibble(void);
-
-uint8_t
-ao_match_word(__code char *word);
-
-struct ao_cmds {
-       void            (*func)(void);
-       __code char     *help;
-};
-
-void
-ao_cmd_register(const __code struct ao_cmds *cmds);
-
-void
-ao_cmd_init(void);
-
-#if HAS_CMD_FILTER
-/*
- * Provided by an external module to filter raw command lines
- */
-uint8_t
-ao_cmd_filter(void);
-#endif
-
-/*
- * Various drivers
- */
-#if HAS_ADC
-#include <ao_adc.h>
-#endif
-
-#if HAS_BEEP
-#include <ao_beep.h>
-#endif
-
-#if LEDS_AVAILABLE
-#include <ao_led.h>
-#endif
-
-#if HAS_USB
-#include <ao_usb.h>
-#endif
-
-#if HAS_EEPROM
-#include <ao_storage.h>
-#endif
-
-#if HAS_LOG
-#include <ao_log.h>
-#endif
-
-#if HAS_FLIGHT
-#include <ao_flight.h>
-#include <ao_sample.h>
-#endif
-
-/*
- * ao_report.c
- */
-
-#define AO_RDF_INTERVAL_TICKS  AO_SEC_TO_TICKS(5)
-#define AO_RDF_LENGTH_MS       500
-#define AO_RDF_CONTINUITY_MS   32
-#define AO_RDF_CONTINUITY_PAUSE        96
-#define AO_RDF_CONTINUITY_TOTAL        ((AO_RDF_CONTINUITY_PAUSE + AO_RDF_CONTINUITY_MS) * 3 + AO_RDF_CONTINUITY_PAUSE)
-
-/* This assumes that we're generating a 1kHz tone, which
- * modulates the carrier at 2kbps, or 250kBps
- */
-#define AO_MS_TO_RDF_LEN(ms) ((ms) / 4)
-
-#define AO_RADIO_RDF_LEN       AO_MS_TO_RDF_LEN(AO_RDF_LENGTH_MS)
-#define AO_RADIO_CONT_TONE_LEN AO_MS_TO_RDF_LEN(AO_RDF_CONTINUITY_MS)
-#define AO_RADIO_CONT_PAUSE_LEN        AO_MS_TO_RDF_LEN(AO_RDF_CONTINUITY_PAUSE)
-#define AO_RADIO_CONT_TOTAL_LEN        AO_MS_TO_RDF_LEN(AO_RDF_CONTINUITY_TOTAL)
-
-/* returns a value 0-3 to indicate igniter continuity */
-uint8_t
-ao_report_igniter(void);
-
-void
-ao_report_init(void);
-
-/*
- * ao_convert.c
- *
- * Given raw data, convert to SI units
- */
-
-/* pressure from the sensor to altitude in meters */
-int16_t
-ao_pres_to_altitude(int16_t pres) __reentrant;
-
-int16_t
-ao_altitude_to_pres(int16_t alt) __reentrant;
-
-int16_t
-ao_temp_to_dC(int16_t temp) __reentrant;
-
-/*
- * ao_convert_pa.c
- *
- * Convert between pressure in Pa and altitude in meters
- */
-
-#include <ao_data.h>
-
-alt_t
-ao_pa_to_altitude(int32_t pa);
-
-int32_t
-ao_altitude_to_pa(alt_t alt);
-
-#if HAS_DBG
-#include <ao_dbg.h>
-#endif
-
-#if HAS_SERIAL_0 || HAS_SERIAL_1 || HAS_SERIAL_2 || HAS_SERIAL_3
-#include <ao_serial.h>
-#endif
-
-/*
- * ao_convert_volt.c
- *
- * Convert ADC readings to decivolts
- */
-
-int16_t
-ao_battery_decivolt(int16_t adc);
-
-int16_t
-ao_ignite_decivolt(int16_t adc);
-
-/*
- * ao_spi_slave.c
- */
-
-uint8_t
-ao_spi_slave_recv(void *buf, uint16_t len);
-
-void
-ao_spi_slave_send(void *buf, uint16_t len);
-
-void
-ao_spi_slave_init(void);
-
-/* This must be defined by the product; it will get called when chip
- * select goes low, at which point it should use ao_spi_read and
- * ao_spi_write to deal with the request
- */
-
-void
-ao_spi_slave(void);
-
-#include <ao_telemetry.h>
-/*
- * ao_gps.c
- */
-
-#define AO_GPS_NUM_SAT_MASK    (0xf << 0)
-#define AO_GPS_NUM_SAT_SHIFT   (0)
-
-#define AO_GPS_VALID           (1 << 4)
-#define AO_GPS_RUNNING         (1 << 5)
-#define AO_GPS_DATE_VALID      (1 << 6)
-#define AO_GPS_COURSE_VALID    (1 << 7)
-
-#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;
-extern __xdata struct ao_telemetry_satellite ao_gps_tracking_data;
-
-struct ao_gps_orig {
-       uint8_t                 year;
-       uint8_t                 month;
-       uint8_t                 day;
-       uint8_t                 hour;
-       uint8_t                 minute;
-       uint8_t                 second;
-       uint8_t                 flags;
-       int32_t                 latitude;       /* degrees * 10⁷ */
-       int32_t                 longitude;      /* degrees * 10⁷ */
-       int16_t                 altitude;       /* m */
-       uint16_t                ground_speed;   /* cm/s */
-       uint8_t                 course;         /* degrees / 2 */
-       uint8_t                 hdop;           /* * 5 */
-       int16_t                 climb_rate;     /* cm/s */
-       uint16_t                h_error;        /* m */
-       uint16_t                v_error;        /* m */
-};
-
-struct ao_gps_sat_orig {
-       uint8_t         svid;
-       uint8_t         c_n_1;
-};
-
-#define AO_MAX_GPS_TRACKING    12
-
-struct ao_gps_tracking_orig {
-       uint8_t                 channels;
-       struct ao_gps_sat_orig  sats[AO_MAX_GPS_TRACKING];
-};
-
-void
-ao_gps(void);
-
-void
-ao_gps_print(__xdata struct ao_gps_orig *gps_data);
-
-void
-ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data);
-
-void
-ao_gps_show(void) __reentrant;
-
-void
-ao_gps_init(void);
-
-/*
- * ao_gps_report.c
- */
-
-void
-ao_gps_report(void);
-
-void
-ao_gps_report_init(void);
-
-/*
- * ao_gps_report_mega.c
- */
-
-void
-ao_gps_report_mega(void);
-
-void
-ao_gps_report_mega_init(void);
-
-/*
- * ao_telemetry_orig.c
- */
-
-#if LEGACY_MONITOR
-struct ao_adc_orig {
-       uint16_t        tick;           /* tick when the sample was read */
-       int16_t         accel;          /* accelerometer */
-       int16_t         pres;           /* pressure sensor */
-       int16_t         temp;           /* temperature sensor */
-       int16_t         v_batt;         /* battery voltage */
-       int16_t         sense_d;        /* drogue continuity sense */
-       int16_t         sense_m;        /* main continuity sense */
-};
-
-struct ao_telemetry_orig {
-       uint16_t                serial;
-       uint16_t                flight;
-       uint8_t                 flight_state;
-       int16_t                 accel;
-       int16_t                 ground_accel;
-       union {
-               struct {
-                       int16_t                 speed;
-                       int16_t                 unused;
-               } k;
-               int32_t         flight_vel;
-       } u;
-       int16_t                 height;
-       int16_t                 ground_pres;
-       int16_t                 accel_plus_g;
-       int16_t                 accel_minus_g;
-       struct ao_adc_orig      adc;
-       struct ao_gps_orig      gps;
-       char                    callsign[AO_MAX_CALLSIGN];
-       struct ao_gps_tracking_orig     gps_tracking;
-};
-
-struct ao_telemetry_tiny {
-       uint16_t                serial;
-       uint16_t                flight;
-       uint8_t                 flight_state;
-       int16_t                 height;         /* AGL in meters */
-       int16_t                 speed;          /* in m/s * 16 */
-       int16_t                 accel;          /* in m/s² * 16 */
-       int16_t                 ground_pres;    /* sensor units */
-       struct ao_adc           adc;            /* raw ADC readings */
-       char                    callsign[AO_MAX_CALLSIGN];
-};
-
-struct ao_telemetry_orig_recv {
-       struct ao_telemetry_orig        telemetry_orig;
-       int8_t                          rssi;
-       uint8_t                         status;
-};
-
-struct ao_telemetry_tiny_recv {
-       struct ao_telemetry_tiny        telemetry_tiny;
-       int8_t                          rssi;
-       uint8_t                         status;
-};
-
-#endif /* LEGACY_MONITOR */
-
-/* Unfortunately, we've exposed the CC1111 rssi units as the 'usual' method
- * for reporting RSSI. So, now we use these values everywhere
- */
-#define AO_RSSI_FROM_RADIO(radio)      ((int16_t) ((int8_t) (radio) >> 1) - 74)
-#define AO_RADIO_FROM_RSSI(rssi)       (((int8_t) (rssi) + 74) << 1)
-
-/*
- * ao_radio_recv tacks on rssi and status bytes
- */
-
-struct ao_telemetry_raw_recv {
-       uint8_t                 packet[AO_MAX_TELEMETRY + 2];
-};
-
-/* Set delay between telemetry reports (0 to disable) */
-
-#ifdef AO_SEND_ALL_BARO
-#define AO_TELEMETRY_INTERVAL_PAD      AO_MS_TO_TICKS(100)
-#define AO_TELEMETRY_INTERVAL_FLIGHT   AO_MS_TO_TICKS(100)
-#define AO_TELEMETRY_INTERVAL_RECOVER  AO_MS_TO_TICKS(100)
-#else
-#define AO_TELEMETRY_INTERVAL_PAD      AO_MS_TO_TICKS(1000)
-#define AO_TELEMETRY_INTERVAL_FLIGHT   AO_MS_TO_TICKS(100)
-#define AO_TELEMETRY_INTERVAL_RECOVER  AO_MS_TO_TICKS(1000)
-#endif
-
-void
-ao_telemetry_set_interval(uint16_t interval);
-
-void
-ao_rdf_set(uint8_t rdf);
-
-void
-ao_telemetry_init(void);
-
-void
-ao_telemetry_orig_init(void);
-
-void
-ao_telemetry_tiny_init(void);
-
-/*
- * ao_radio.c
- */
-
-extern __xdata uint8_t ao_radio_dma;
-
-extern __xdata int8_t  ao_radio_rssi;
-
-#ifdef PKT_APPEND_STATUS_1_CRC_OK
-#define AO_RADIO_STATUS_CRC_OK PKT_APPEND_STATUS_1_CRC_OK
-#else
-#include <ao_fec.h>
-#define AO_RADIO_STATUS_CRC_OK AO_FEC_DECODE_CRC_OK
-#endif
-
-#ifndef HAS_RADIO_RECV
-#define HAS_RADIO_RECV HAS_RADIO
-#endif
-#ifndef HAS_RADIO_XMIT
-#define HAS_RADIO_XMIT HAS_RADIO
-#endif
-
-void
-ao_radio_general_isr(void) ao_arch_interrupt(16);
-
-#if HAS_RADIO_XMIT
-void
-ao_radio_send(const __xdata void *d, uint8_t size) __reentrant;
-#endif
-
-#if HAS_RADIO_RECV
-uint8_t
-ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout) __reentrant;
-
-void
-ao_radio_recv_abort(void);
-#endif
-
-void
-ao_radio_test(uint8_t on);
-
-typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len);
-
-void
-ao_radio_send_aprs(ao_radio_fill_func fill);
-
-/*
- * ao_radio_pa
- */
-
-#if HAS_RADIO_AMP
-void
-ao_radio_pa_on(void);
-
-void
-ao_radio_pa_off(void);
-
-void
-ao_radio_pa_init(void);
-#else
-#define ao_radio_pa_on()
-#define ao_radio_pa_off()
-#define ao_radio_pa_init()
-#endif
-
-/*
- * Compute the packet length as follows:
- *
- * 2000 bps (for a 1kHz tone)
- * so, for 'ms' milliseconds, we need
- * 2 * ms bits, or ms / 4 bytes
- */
-
-void
-ao_radio_rdf(void);
-
-void
-ao_radio_continuity(uint8_t c);
-
-void
-ao_radio_rdf_abort(void);
-
-void
-ao_radio_init(void);
-
-/*
- * ao_monitor.c
- */
-
-#if HAS_MONITOR
-
-extern const char const * const ao_state_names[];
-
-#define AO_MONITOR_RING        8
-
-union ao_monitor {
-       struct ao_telemetry_raw_recv    raw;
-       struct ao_telemetry_all_recv    all;
-#if LEGACY_MONITOR
-       struct ao_telemetry_orig_recv   orig;
-       struct ao_telemetry_tiny_recv   tiny;
-#endif
-};
-
-extern __xdata union ao_monitor ao_monitor_ring[AO_MONITOR_RING];
-
-#define ao_monitor_ring_next(n)        (((n) + 1) & (AO_MONITOR_RING - 1))
-
-extern __data uint8_t ao_monitoring;
-extern __data uint8_t ao_monitor_head;
-
-void
-ao_monitor(void);
-
-#define AO_MONITORING_OFF      0
-#define AO_MONITORING_ORIG     1
-
-void
-ao_monitor_set(uint8_t monitoring);
-
-void
-ao_monitor_disable(void);
-
-void
-ao_monitor_enable(void);
-
-void
-ao_monitor_init(void) __reentrant;
-
-#endif
-
-/*
- * ao_stdio.c
- */
-
-#define AO_READ_AGAIN  (-1)
-
-struct ao_stdio {
-       int     (*_pollchar)(void);     /* Called with interrupts blocked */
-       void    (*putchar)(char c) __reentrant;
-       void    (*flush)(void);
-       uint8_t echo;
-};
-
-extern __xdata struct ao_stdio ao_stdios[];
-extern __pdata int8_t ao_cur_stdio;
-extern __pdata int8_t ao_num_stdios;
-
-void
-flush(void);
-
-extern __xdata uint8_t ao_stdin_ready;
-
-uint8_t
-ao_echo(void);
-
-int8_t
-ao_add_stdio(int (*pollchar)(void),
-            void (*putchar)(char) __reentrant,
-            void (*flush)(void)) __reentrant;
-
-/*
- * ao_ignite.c
- */
-
-enum ao_igniter {
-       ao_igniter_drogue = 0,
-       ao_igniter_main = 1
-};
-
-void
-ao_ignite(enum ao_igniter igniter);
-
-enum ao_igniter_status {
-       ao_igniter_unknown,     /* unknown status (ambiguous voltage) */
-       ao_igniter_ready,       /* continuity detected */
-       ao_igniter_active,      /* igniter firing */
-       ao_igniter_open,        /* open circuit detected */
-};
-
-struct ao_ignition {
-       uint8_t request;
-       uint8_t fired;
-       uint8_t firing;
-};
-
-extern __code char * __code ao_igniter_status_names[];
-
-extern __xdata struct ao_ignition ao_ignition[2];
-
-enum ao_igniter_status
-ao_igniter_status(enum ao_igniter igniter);
-
-extern __pdata uint8_t ao_igniter_present;
-
-void
-ao_ignite_set_pins(void);
-
-void
-ao_igniter_init(void);
-
-/*
- * ao_config.c
- */
-
-#if AO_PYRO_NUM
-#include <ao_pyro.h>
-#endif
-
-#if HAS_FORCE_FREQ
-/*
- * Set this to force the frequency to 434.550MHz
- */
-extern __xdata uint8_t ao_force_freq;
-#endif
-
-#define AO_CONFIG_MAJOR        1
-#define AO_CONFIG_MINOR        15
-
-#define AO_AES_LEN 16
-
-extern __xdata uint8_t ao_config_aes_seq;
-
-struct ao_config {
-       uint8_t         major;
-       uint8_t         minor;
-       uint16_t        main_deploy;
-       int16_t         accel_plus_g;           /* changed for minor version 2 */
-       uint8_t         _legacy_radio_channel;
-       char            callsign[AO_MAX_CALLSIGN + 1];
-       uint8_t         apogee_delay;           /* minor version 1 */
-       int16_t         accel_minus_g;          /* minor version 2 */
-       uint32_t        radio_cal;              /* minor version 3 */
-       uint32_t        flight_log_max;         /* minor version 4 */
-       uint8_t         ignite_mode;            /* minor version 5 */
-       uint8_t         pad_orientation;        /* minor version 6 */
-       uint32_t        radio_setting;          /* minor version 7 */
-       uint8_t         radio_enable;           /* minor version 8 */
-       uint8_t         aes_key[AO_AES_LEN];    /* minor version 9 */
-       uint32_t        frequency;              /* minor version 10 */
-       uint16_t        apogee_lockout;         /* minor version 11 */
-#if AO_PYRO_NUM
-       struct ao_pyro  pyro[AO_PYRO_NUM];      /* minor version 12 */
-#endif
-       uint16_t        aprs_interval;          /* minor version 13 */
-#if HAS_RADIO_POWER
-       uint8_t         radio_power;            /* minor version 14 */
-#endif
-#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
-#define AO_IGNITE_MODE_APOGEE          1
-#define AO_IGNITE_MODE_MAIN            2
-
-#define AO_RADIO_ENABLE_CORE           1
-#define AO_RADIO_DISABLE_TELEMETRY     2
-#define AO_RADIO_DISABLE_RDF           4
-
-#define AO_PAD_ORIENTATION_ANTENNA_UP  0
-#define AO_PAD_ORIENTATION_ANTENNA_DOWN        1
-
-extern __xdata struct ao_config ao_config;
-
-#define AO_CONFIG_MAX_SIZE     128
-
-void
-_ao_config_edit_start(void);
-
-void
-_ao_config_edit_finish(void);
-
-void
-ao_config_get(void);
-
-void
-ao_config_put(void);
-
-void
-ao_config_set_radio(void);
-
-void
-ao_config_init(void);
-
-/*
- * ao_rssi.c
- */
-
-void
-ao_rssi_set(int rssi_value);
-
-void
-ao_rssi_init(uint8_t rssi_led);
-
-/*
- * ao_product.c
- *
- * values which need to be defined for
- * each instance of a product
- */
-
-extern const char ao_version[];
-extern const char ao_manufacturer[];
-extern const char ao_product[];
-
-/*
- * Fifos
- */
-
-#define AO_FIFO_SIZE   32
-
-struct ao_fifo {
-       uint8_t insert;
-       uint8_t remove;
-       char    fifo[AO_FIFO_SIZE];
-};
-
-#define ao_fifo_insert(f,c) do { \
-       (f).fifo[(f).insert] = (c); \
-       (f).insert = ((f).insert + 1) & (AO_FIFO_SIZE-1); \
-} while(0)
-
-#define ao_fifo_remove(f,c) do {\
-       c = (f).fifo[(f).remove]; \
-       (f).remove = ((f).remove + 1) & (AO_FIFO_SIZE-1); \
-} while(0)
-
-#define ao_fifo_full(f)                ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove)
-#define ao_fifo_empty(f)       ((f).insert == (f).remove)
-
-#if PACKET_HAS_MASTER || PACKET_HAS_SLAVE
-#include <ao_packet.h>
-#endif
-
-#if HAS_BTM
-#include <ao_btm.h>
-#endif
-
-#if HAS_COMPANION
-#include <ao_companion.h>
-#endif
-
-#if HAS_LCD
-#include <ao_lcd.h>
-#endif
-
-#if HAS_AES
-#include <ao_aes.h>
-#endif
-
-/* ao_launch.c */
-
-struct ao_launch_command {
-       uint16_t        tick;
-       uint16_t        serial;
-       uint8_t         cmd;
-       uint8_t         channel;
-       uint16_t        unused;
-};
-
-#define AO_LAUNCH_QUERY                1
-
-struct ao_launch_query {
-       uint16_t        tick;
-       uint16_t        serial;
-       uint8_t         channel;
-       uint8_t         valid;
-       uint8_t         arm_status;
-       uint8_t         igniter_status;
-};
-
-#define AO_LAUNCH_ARM          2
-#define AO_LAUNCH_FIRE         3
-
-void
-ao_launch_init(void);
-
-/*
- * ao_log_single.c
- */
-
-#define AO_LOG_TELESCIENCE_START       ((uint8_t) 's')
-#define AO_LOG_TELESCIENCE_DATA                ((uint8_t) 'd')
-
-#define AO_LOG_TELESCIENCE_NUM_ADC     12
-
-struct ao_log_telescience {
-       uint8_t         type;
-       uint8_t         csum;
-       uint16_t        tick;
-       uint16_t        tm_tick;
-       uint8_t         tm_state;
-       uint8_t         unused;
-       uint16_t        adc[AO_LOG_TELESCIENCE_NUM_ADC];
-};
-
-#define AO_LOG_SINGLE_SIZE             32
-
-union ao_log_single {
-       struct ao_log_telescience       telescience;
-       union ao_telemetry_all          telemetry;
-       uint8_t                         bytes[AO_LOG_SINGLE_SIZE];
-};
-
-extern __xdata union ao_log_single     ao_log_single_write_data;
-extern __xdata union ao_log_single     ao_log_single_read_data;
-
-void
-ao_log_single_extra_query(void);
-
-void
-ao_log_single_list(void);
-
-void
-ao_log_single_main(void);
-
-uint8_t
-ao_log_single_write(void);
-
-uint8_t
-ao_log_single_read(uint32_t pos);
-
-void
-ao_log_single_start(void);
-
-void
-ao_log_single_stop(void);
-
-void
-ao_log_single_restart(void);
-
-void
-ao_log_single_set(void);
-
-void
-ao_log_single_delete(void);
-
-void
-ao_log_single_init(void);
-
-void
-ao_log_single(void);
-
-/*
- * ao_pyro_slave.c
- */
-
-#define AO_TELEPYRO_NUM_ADC    9
-
-#ifndef ao_xmemcpy
-#define ao_xmemcpy(d,s,c) memcpy(d,s,c)
-#define ao_xmemset(d,v,c) memset(d,v,c)
-#define ao_xmemcmp(d,s,c) memcmp(d,s,c)
-#endif
-
-/*
- * ao_terraui.c
- */
-
-void
-ao_terraui_init(void);
-
-/*
- * ao_battery.c
- */
-
-#ifdef BATTERY_PIN
-void
-ao_battery_isr(void) ao_arch_interrupt(1);
-
-uint16_t
-ao_battery_get(void);
-
-void
-ao_battery_init(void);
-#endif /* BATTERY_PIN */
-
-/*
- * ao_sqrt.c
- */
-
-uint32_t
-ao_sqrt(uint32_t op);
-
-/*
- * ao_freq.c
- */
-
-int32_t ao_freq_to_set(int32_t freq, int32_t cal) __reentrant;
-
-/*
- * ao_ms5607.c
- */
-
-void ao_ms5607_init(void);
-
-#include <ao_arch_funcs.h>
-
-#endif /* _AO_H_ */
diff --git a/src/core/ao_adc.h b/src/core/ao_adc.h
deleted file mode 100644 (file)
index 373db1c..0000000
+++ /dev/null
@@ -1,35 +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_ADC_H_
-#define _AO_ADC_H_
-
-#include <ao_data.h>
-
-/* Trigger a conversion sequence (called from the timer interrupt) */
-void
-ao_adc_poll(void);
-
-/* Suspend the current task until another A/D sample is converted */
-void
-ao_adc_sleep(void);
-
-/* Initialize the A/D converter */
-void
-ao_adc_init(void);
-
-#endif /* _AO_ADC_H_ */
diff --git a/src/core/ao_aes.h b/src/core/ao_aes.h
deleted file mode 100644 (file)
index c47bc2d..0000000
+++ /dev/null
@@ -1,54 +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_AES_H_
-#define _AO_AES_H_
-
-/* ao_aes.c */
-
-extern __xdata uint8_t ao_aes_mutex;
-
-/* AES keys and blocks are 128 bits */
-
-enum ao_aes_mode {
-       ao_aes_mode_cbc_mac
-};
-
-#if HAS_AES
-#ifdef SDCC
-void
-ao_aes_isr(void) __interrupt 4;
-#endif
-#endif
-
-void
-ao_aes_set_mode(enum ao_aes_mode mode);
-
-void
-ao_aes_set_key(__xdata uint8_t *in);
-
-void
-ao_aes_zero_iv(void);
-
-void
-ao_aes_run(__xdata uint8_t *in,
-          __xdata uint8_t *out);
-
-void
-ao_aes_init(void);
-
-#endif /* _AO_AES_H_ */
diff --git a/src/core/ao_beep.h b/src/core/ao_beep.h
deleted file mode 100644 (file)
index 55f6117..0000000
+++ /dev/null
@@ -1,74 +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_BEEP_H_
-#define _AO_BEEP_H_
-
-/*
- * ao_beep.c
- */
-
-/*
- * Various pre-defined beep frequencies
- *
- * frequency = 1/2 (24e6/32) / beep
- */
-
-#define AO_BEEP_LOW    150     /* 2500Hz */
-#define AO_BEEP_MID    94      /* 3989Hz */
-#define AO_BEEP_HIGH   75      /* 5000Hz */
-#define AO_BEEP_OFF    0       /* off */
-
-#define AO_BEEP_g      240     /* 1562.5Hz */
-#define AO_BEEP_gs     227     /* 1652Hz (1655Hz) */
-#define AO_BEEP_aa     214     /* 1752Hz (1754Hz) */
-#define AO_BEEP_bbf    202     /* 1856Hz (1858Hz) */
-#define AO_BEEP_bb     190     /* 1974Hz (1969Hz) */
-#define AO_BEEP_cc     180     /* 2083Hz (2086Hz) */
-#define AO_BEEP_ccs    170     /* 2205Hz (2210Hz) */
-#define AO_BEEP_dd     160     /* 2344Hz (2341Hz) */
-#define AO_BEEP_eef    151     /* 2483Hz (2480Hz) */
-#define AO_BEEP_ee     143     /* 2622Hz (2628Hz) */
-#define AO_BEEP_ff     135     /* 2778Hz (2784Hz) */
-#define AO_BEEP_ffs    127     /* 2953Hz (2950Hz) */
-#define AO_BEEP_gg     120     /* 3125Hz */
-#define AO_BEEP_ggs    113     /* 3319Hz (3311Hz) */
-#define AO_BEEP_aaa    107     /* 3504Hz (3508Hz) */
-#define AO_BEEP_bbbf   101     /* 3713Hz (3716Hz) */
-#define AO_BEEP_bbb    95      /* 3947Hz (3937Hz) */
-#define AO_BEEP_ccc    90      /* 4167Hz (4171Hz) */
-#define AO_BEEP_cccs   85      /* 4412Hz (4419Hz) */
-#define AO_BEEP_ddd    80      /* 4688Hz (4682Hz) */
-#define AO_BEEP_eeef   76      /* 4934Hz (4961Hz) */
-#define AO_BEEP_eee    71      /* 5282Hz (5256Hz) */
-#define AO_BEEP_fff    67      /* 5597Hz (5568Hz) */
-#define AO_BEEP_fffs   64      /* 5859Hz (5899Hz) */
-#define AO_BEEP_ggg    60      /* 6250Hz */
-
-/* Set the beeper to the specified tone */
-void
-ao_beep(uint8_t beep);
-
-/* Turn on the beeper for the specified time */
-void
-ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant;
-
-/* Initialize the beeper */
-void
-ao_beep_init(void);
-
-#endif /* _AO_BEEP_H_ */
diff --git a/src/core/ao_btm.h b/src/core/ao_btm.h
deleted file mode 100644 (file)
index 484e5d7..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.
- */
-
-#ifndef _AO_BTM_H_
-#define _AO_BTM_H_
-
-/* ao_btm.c */
-
-/* If bt_link is on P2, this interrupt is shared by USB, so the USB
- * code calls this function. Otherwise, it's a regular ISR.
- */
-
-void
-ao_btm_isr(void)
-#if BT_LINK_ON_P1
-       __interrupt 15
-#endif
-       ;
-void
-ao_btm_init(void);
-
-#endif /* _AO_BTM_H_ */
diff --git a/src/core/ao_cmd.c b/src/core/ao_cmd.c
deleted file mode 100644 (file)
index 4ebaa60..0000000
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * 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_task.h"
-
-__pdata uint16_t ao_cmd_lex_i;
-__pdata uint32_t ao_cmd_lex_u32;
-__pdata char   ao_cmd_lex_c;
-__pdata enum ao_cmd_status ao_cmd_status;
-
-#define CMD_LEN        48
-
-static __xdata char    cmd_line[CMD_LEN];
-static __pdata uint8_t cmd_len;
-static __pdata uint8_t cmd_i;
-
-void
-ao_put_string(__code char *s)
-{
-       char    c;
-       while ((c = *s++))
-               putchar(c);
-}
-
-static void
-backspace(void)
-{
-       ao_put_string ("\010 \010");
-}
-
-static void
-readline(void)
-{
-       char c;
-       if (ao_echo())
-               ao_put_string("> ");
-       cmd_len = 0;
-       for (;;) {
-               flush();
-               c = getchar();
-               /* backspace/delete */
-               if (c == '\010' || c == '\177') {
-                       if (cmd_len != 0) {
-                               if (ao_echo())
-                                       backspace();
-                               --cmd_len;
-                       }
-                       continue;
-               }
-
-               /* ^U */
-               if (c == '\025') {
-                       while (cmd_len != 0) {
-                               if (ao_echo())
-                                       backspace();
-                               --cmd_len;
-                       }
-                       continue;
-               }
-
-               /* map CR to NL */
-               if (c == '\r')
-                       c = '\n';
-
-               if (c == '\n') {
-                       if (ao_echo())
-                               putchar('\n');
-                       break;
-               }
-
-               if (cmd_len >= CMD_LEN - 2)
-                       continue;
-               cmd_line[cmd_len++] = c;
-               if (ao_echo())
-                       putchar(c);
-       }
-       cmd_line[cmd_len++] = '\n';
-       cmd_line[cmd_len++] = '\0';
-       cmd_i = 0;
-}
-
-void
-ao_cmd_lex(void)
-{
-       ao_cmd_lex_c = '\n';
-       if (cmd_i < cmd_len)
-               ao_cmd_lex_c = cmd_line[cmd_i++];
-}
-
-static void
-putnibble(uint8_t v)
-{
-       if (v < 10)
-               putchar(v + '0');
-       else
-               putchar(v + ('a' - 10));
-}
-
-uint8_t
-ao_getnibble(void)
-{
-       char    c;
-
-       c = getchar();
-       if ('0' <= c && c <= '9')
-               return c - '0';
-       if ('a' <= c && c <= 'f')
-               return c - ('a' - 10);
-       if ('A' <= c && c <= 'F')
-               return c - ('A' - 10);
-       ao_cmd_status = ao_cmd_lex_error;
-       return 0;
-}
-
-void
-ao_cmd_put16(uint16_t v)
-{
-       ao_cmd_put8(v >> 8);
-       ao_cmd_put8(v);
-}
-
-void
-ao_cmd_put8(uint8_t v)
-{
-       putnibble((v >> 4) & 0xf);
-       putnibble(v & 0xf);
-}
-
-uint8_t
-ao_cmd_is_white(void)
-{
-       return ao_cmd_lex_c == ' ' || ao_cmd_lex_c == '\t';
-}
-
-void
-ao_cmd_white(void)
-{
-       while (ao_cmd_is_white())
-               ao_cmd_lex();
-}
-
-int8_t
-ao_cmd_hexchar(char c)
-{
-       if ('0' <= c && c <= '9')
-               return (c - '0');
-       if ('a' <= c && c <= 'f')
-               return (c - 'a' + 10);
-       if ('A' <= c && c <= 'F')
-               return (c - 'A' + 10);
-       return -1;
-}
-
-void
-ao_cmd_hexbyte(void)
-{
-       uint8_t i;
-       int8_t  n;
-
-       ao_cmd_lex_i = 0;
-       ao_cmd_white();
-       for (i = 0; i < 2; i++) {
-               n = ao_cmd_hexchar(ao_cmd_lex_c);
-               if (n < 0) {
-                       ao_cmd_status = ao_cmd_syntax_error;
-                       break;
-               }
-               ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
-               ao_cmd_lex();
-       }
-}
-
-void
-ao_cmd_hex(void)
-{
-       __pdata uint8_t r = ao_cmd_lex_error;
-       int8_t  n;
-
-       ao_cmd_lex_i = 0;
-       ao_cmd_white();
-       for(;;) {
-               n = ao_cmd_hexchar(ao_cmd_lex_c);
-               if (n < 0)
-                       break;
-               ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
-               r = ao_cmd_success;
-               ao_cmd_lex();
-       }
-       if (r != ao_cmd_success)
-               ao_cmd_status = r;
-}
-
-void
-ao_cmd_decimal(void) __reentrant
-{
-       uint8_t r = ao_cmd_lex_error;
-
-       ao_cmd_lex_u32 = 0;
-       ao_cmd_white();
-       for(;;) {
-               if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
-                       ao_cmd_lex_u32 = (ao_cmd_lex_u32 * 10) + (ao_cmd_lex_c - '0');
-               else
-                       break;
-               r = ao_cmd_success;
-               ao_cmd_lex();
-       }
-       if (r != ao_cmd_success)
-               ao_cmd_status = r;
-       ao_cmd_lex_i = (uint16_t) ao_cmd_lex_u32;
-}
-
-uint8_t
-ao_match_word(__code char *word)
-{
-       while (*word) {
-               if (ao_cmd_lex_c != *word) {
-                       ao_cmd_status = ao_cmd_syntax_error;
-                       return 0;
-               }
-               word++;
-               ao_cmd_lex();
-       }
-       return 1;
-}
-
-static void
-echo(void)
-{
-       ao_cmd_hex();
-       if (ao_cmd_status == ao_cmd_success)
-               ao_stdios[ao_cur_stdio].echo = ao_cmd_lex_i != 0;
-}
-
-static void
-ao_reboot(void)
-{
-       ao_cmd_white();
-       if (!ao_match_word("eboot"))
-               return;
-       /* Delay waiting for the packet master to be turned off
-        * so that we don't end up back in idle mode because we
-        * received a packet after boot.
-        */
-       flush();
-       ao_delay(AO_SEC_TO_TICKS(1));
-       ao_arch_reboot();
-       ao_panic(AO_PANIC_REBOOT);
-}
-
-#ifndef HAS_VERSION
-#define HAS_VERSION 1
-#endif
-
-#if HAS_VERSION
-static void
-version(void)
-{
-       printf("manufacturer     %s\n"
-              "product          %s\n"
-              "serial-number    %u\n"
-#if HAS_FLIGHT
-              "current-flight   %u\n"
-#endif
-#if HAS_LOG
-              "log-format       %u\n"
-#endif
-              , ao_manufacturer
-              , ao_product
-              , ao_serial_number
-#if HAS_FLIGHT
-              , ao_flight_number
-#endif
-#if HAS_LOG
-              , ao_log_format
-#endif
-               );
-       printf("software-version %s\n", ao_version);
-}
-#endif
-
-#ifndef NUM_CMDS
-#define NUM_CMDS       11
-#endif
-
-static __code struct ao_cmds   *__xdata (ao_cmds[NUM_CMDS]);
-static __pdata uint8_t         ao_ncmds;
-
-static void
-help(void)
-{
-       __pdata uint8_t cmds;
-       __pdata uint8_t cmd;
-       __code struct ao_cmds * __pdata cs;
-       __code const char *h;
-       uint8_t e;
-
-       for (cmds = 0; cmds < ao_ncmds; cmds++) {
-               cs = ao_cmds[cmds];
-               for (cmd = 0; cs[cmd].func; cmd++) {
-                       h = cs[cmd].help;
-                       ao_put_string(h);
-                       e = strlen(h);
-                       h += e + 1;
-                       e = 45 - e;
-                       while (e--)
-                               putchar(' ');
-                       ao_put_string(h);
-                       putchar('\n');
-               }
-       }
-}
-
-static void
-report(void)
-{
-       switch(ao_cmd_status) {
-       case ao_cmd_lex_error:
-       case ao_cmd_syntax_error:
-               puts("Syntax error");
-               ao_cmd_status = 0;
-       default:
-               break;
-       }
-}
-
-void
-ao_cmd_register(__code struct ao_cmds *cmds)
-{
-       if (ao_ncmds >= NUM_CMDS)
-               ao_panic(AO_PANIC_CMD);
-       ao_cmds[ao_ncmds++] = cmds;
-}
-
-void
-ao_cmd(void)
-{
-       __pdata char    c;
-       uint8_t cmd, cmds;
-       __code struct ao_cmds * __xdata cs;
-       void (*__xdata func)(void);
-
-       for (;;) {
-               readline();
-               ao_cmd_lex();
-               ao_cmd_white();
-               c = ao_cmd_lex_c;
-               ao_cmd_lex();
-               if (c == '\r' || c == '\n')
-                       continue;
-               func = (void (*)(void)) NULL;
-               for (cmds = 0; cmds < ao_ncmds; cmds++) {
-                       cs = ao_cmds[cmds];
-                       for (cmd = 0; cs[cmd].func; cmd++)
-                               if (cs[cmd].help[0] == c) {
-                                       func = cs[cmd].func;
-                                       break;
-                               }
-                       if (func)
-                               break;
-               }
-               if (func)
-                       (*func)();
-               else
-                       ao_cmd_status = ao_cmd_syntax_error;
-               report();
-       }
-}
-
-#if HAS_BOOT_LOADER
-
-#include <ao_boot.h>
-
-static void
-ao_loader(void)
-{
-       flush();
-       ao_boot_loader();
-}
-#endif
-
-__xdata struct ao_task ao_cmd_task;
-
-__code struct ao_cmds  ao_base_cmds[] = {
-       { help,         "?\0Help" },
-#if HAS_TASK_INFO
-       { ao_task_info, "T\0Tasks" },
-#endif
-       { echo,         "E <0 off, 1 on>\0Echo" },
-       { ao_reboot,    "r eboot\0Reboot" },
-#if HAS_VERSION
-       { version,      "v\0Version" },
-#endif
-#if HAS_BOOT_LOADER
-       { ao_loader,    "X\0Switch to boot loader" },
-#endif
-       { 0,    NULL },
-};
-
-void
-ao_cmd_init(void)
-{
-       ao_cmd_register(&ao_base_cmds[0]);
-       ao_add_task(&ao_cmd_task, ao_cmd, "cmd");
-}
diff --git a/src/core/ao_companion.h b/src/core/ao_companion.h
deleted file mode 100644 (file)
index 035325a..0000000
+++ /dev/null
@@ -1,55 +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_COMPANION_H_
-#define _AO_COMPANION_H_
-
-/* ao_companion.c */
-
-#define AO_COMPANION_SETUP             1
-#define AO_COMPANION_FETCH             2
-#define AO_COMPANION_NOTIFY            3
-
-struct ao_companion_command {
-       uint8_t         command;
-       uint8_t         flight_state;
-       uint16_t        tick;
-       uint16_t        serial;
-       uint16_t        flight;
-       int16_t         accel;
-       int16_t         speed;
-       int16_t         height;
-       int16_t         motor_number;
-};
-
-struct ao_companion_setup {
-       uint16_t        board_id;
-       uint16_t        board_id_inverse;
-       uint8_t         update_period;
-       uint8_t         channels;
-};
-
-extern __pdata uint8_t                         ao_companion_running;
-extern __xdata uint8_t                         ao_companion_mutex;
-extern __xdata struct ao_companion_command     ao_companion_command;
-extern __xdata struct ao_companion_setup       ao_companion_setup;
-extern __xdata uint16_t                                ao_companion_data[AO_COMPANION_MAX_CHANNELS];
-
-void
-ao_companion_init(void);
-
-#endif /* _AO_COMPANION_H_ */
diff --git a/src/core/ao_config.c b/src/core/ao_config.c
deleted file mode 100644 (file)
index 4482f67..0000000
+++ /dev/null
@@ -1,805 +0,0 @@
-/*
- * 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"
-#include <ao_config.h>
-#if HAS_FLIGHT
-#include <ao_sample.h>
-#include <ao_data.h>
-#endif
-
-__xdata struct ao_config ao_config;
-__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"
-#define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000
-#define AO_CONFIG_DEFAULT_APOGEE_DELAY 0
-#define AO_CONFIG_DEFAULT_IGNITE_MODE  AO_IGNITE_MODE_DUAL
-#define AO_CONFIG_DEFAULT_PAD_ORIENTATION      AO_PAD_ORIENTATION_ANTENNA_UP
-#if HAS_EEPROM
-#ifndef USE_INTERNAL_FLASH
-#error Please define USE_INTERNAL_FLASH
-#endif
-#endif
-#ifndef AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX
-#if USE_INTERNAL_FLASH
-#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       ao_storage_config
-#else
-#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       ((uint32_t) 192 * (uint32_t) 1024)
-#endif
-#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_config_setup();
-       ao_config_erase();
-       ao_config_write(0, &ao_config, sizeof (ao_config));
-#if HAS_FLIGHT
-       ao_log_write_erase(0);
-#endif
-       ao_config_flush();
-}
-
-void
-ao_config_put(void)
-{
-       ao_mutex_get(&ao_config_mutex);
-       _ao_config_put();
-       ao_mutex_put(&ao_config_mutex);
-}
-#endif
-
-#if HAS_RADIO
-void
-ao_config_set_radio(void)
-{
-       ao_config.radio_setting = ao_freq_to_set(ao_config.frequency, ao_config.radio_cal);
-}
-#endif /* HAS_RADIO */
-
-static void
-_ao_config_get(void)
-{
-       uint8_t minor;
-
-       if (ao_config_loaded)
-               return;
-#if HAS_EEPROM
-       /* Yes, I know ao_storage_read calls ao_storage_setup,
-        * but ao_storage_setup *also* sets ao_storage_config, which we
-        * need before calling ao_storage_read here
-        */
-       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;
-               ao_config.minor = 0;
-
-               /* Version 0 stuff */
-               ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY;
-               ao_xmemset(&ao_config.callsign, '\0', sizeof (ao_config.callsign));
-               ao_xmemcpy(&ao_config.callsign, CODE_TO_XDATA(AO_CONFIG_DEFAULT_CALLSIGN),
-                      sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
-               ao_config._legacy_radio_channel = 0;
-       }
-       minor = ao_config.minor;
-       if (minor != AO_CONFIG_MINOR) {
-               /* Fixups for minor version 1 */
-               if (minor < 1)
-                       ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY;
-               /* Fixups for minor version 2 */
-               if (minor < 2) {
-                       ao_config.accel_plus_g = 0;
-                       ao_config.accel_minus_g = 0;
-               }
-               /* Fixups for minor version 3 */
-#if HAS_RADIO
-               if (minor < 3)
-                       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;
-               if (minor < 6)
-                       ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION;
-               if (minor < 8)
-                       ao_config.radio_enable = AO_RADIO_ENABLE_CORE;
-               if (minor < 9)
-                       ao_xmemset(&ao_config.aes_key, '\0', AO_AES_LEN);
-               if (minor < 10)
-                       ao_config.frequency = 434550 + ao_config._legacy_radio_channel * 100;
-               if (minor < 11)
-                       ao_config.apogee_lockout = 0;
-#if AO_PYRO_NUM
-               if (minor < 12)
-                       memset(&ao_config.pyro, '\0', sizeof (ao_config.pyro));
-#endif
-               if (minor < 13)
-                       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;
-               #endif
-#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;
-       }
-#if HAS_RADIO
-#if HAS_FORCE_FREQ
-       if (ao_force_freq) {
-               ao_config.frequency = 434550;
-               ao_config.radio_cal = ao_radio_cal;
-               ao_xmemcpy(&ao_config.callsign, CODE_TO_XDATA(AO_CONFIG_DEFAULT_CALLSIGN),
-                      sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
-       }
-#endif
-       ao_config_set_radio();
-#endif
-       ao_config_loaded = 1;
-}
-
-void
-_ao_config_edit_start(void)
-{
-       ao_mutex_get(&ao_config_mutex);
-       _ao_config_get();
-}
-
-void
-_ao_config_edit_finish(void)
-{
-       ao_config_dirty = 1;
-       ao_mutex_put(&ao_config_mutex);
-}
-
-void
-ao_config_get(void)
-{
-       _ao_config_edit_start();
-       ao_mutex_put(&ao_config_mutex);
-}
-
-void
-ao_config_callsign_show(void)
-{
-       printf ("Callsign: \"%s\"\n", ao_config.callsign);
-}
-
-void
-ao_config_callsign_set(void) __reentrant
-{
-       uint8_t c;
-       static __xdata char callsign[AO_MAX_CALLSIGN + 1];
-
-       ao_xmemset(callsign, '\0', sizeof callsign);
-       ao_cmd_white();
-       c = 0;
-       while (ao_cmd_lex_c != '\n') {
-               if (c < AO_MAX_CALLSIGN)
-                       callsign[c++] = ao_cmd_lex_c;
-               else
-                       ao_cmd_status = ao_cmd_lex_error;
-               ao_cmd_lex();
-       }
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_xmemcpy(&ao_config.callsign, &callsign,
-              AO_MAX_CALLSIGN + 1);
-       _ao_config_edit_finish();
-}
-
-#if HAS_RADIO
-
-void
-ao_config_frequency_show(void) __reentrant
-{
-       printf("Frequency: %ld\n",
-              ao_config.frequency);
-}
-
-void
-ao_config_frequency_set(void) __reentrant
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_config.frequency = ao_cmd_lex_u32;
-       ao_config_set_radio();
-       _ao_config_edit_finish();
-#if HAS_RADIO_RECV
-       ao_radio_recv_abort();
-#endif
-}
-#endif
-
-#if HAS_FLIGHT
-
-void
-ao_config_main_deploy_show(void) __reentrant
-{
-       printf("Main deploy: %d meters\n",
-              ao_config.main_deploy);
-}
-
-void
-ao_config_main_deploy_set(void) __reentrant
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_config.main_deploy = ao_cmd_lex_i;
-       _ao_config_edit_finish();
-}
-
-#if HAS_ACCEL
-void
-ao_config_accel_calibrate_show(void) __reentrant
-{
-       printf("Accel cal +1g: %d -1g: %d\n",
-              ao_config.accel_plus_g, ao_config.accel_minus_g);
-#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();
-       (void) getchar();
-       puts("\r\n"); flush();
-       puts("Calibrating..."); flush();
-       i = ACCEL_CALIBRATE_SAMPLES;
-       accel_total = 0;
-       cal_data_ring = ao_sample_data;
-       while (i) {
-               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;
-}
-
-void
-ao_config_accel_calibrate_set(void) __reentrant
-{
-       int16_t up, down;
-#if HAS_GYRO
-       int16_t accel_along_up = 0, accel_along_down = 0;
-       int16_t accel_across_up = 0, accel_across_down = 0;
-       int16_t accel_through_up = 0, accel_through_down = 0;
-#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();
-               if (ao_cmd_status != ao_cmd_success)
-                       return;
-               down = ao_cmd_lex_i;
-       }
-       if (up >= down) {
-               printf("Invalid accel: up (%d) down (%d)\n",
-                      up, down);
-               return;
-       }
-       _ao_config_edit_start();
-       ao_config.accel_plus_g = up;
-       ao_config.accel_minus_g = down;
-#if HAS_GYRO
-       if (ao_cmd_lex_i == 0) {
-               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 */
-
-void
-ao_config_apogee_delay_show(void) __reentrant
-{
-       printf("Apogee delay: %d seconds\n",
-              ao_config.apogee_delay);
-}
-
-void
-ao_config_apogee_delay_set(void) __reentrant
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_config.apogee_delay = ao_cmd_lex_i;
-       _ao_config_edit_finish();
-}
-
-void
-ao_config_apogee_lockout_show(void) __reentrant
-{
-       printf ("Apogee lockout: %d seconds\n",
-               ao_config.apogee_lockout);
-}
-
-void
-ao_config_apogee_lockout_set(void) __reentrant
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_config.apogee_lockout = ao_cmd_lex_i;
-       _ao_config_edit_finish();
-}
-
-#endif /* HAS_FLIGHT */
-
-#if HAS_RADIO
-void
-ao_config_radio_cal_show(void) __reentrant
-{
-       printf("Radio cal: %ld\n", ao_config.radio_cal);
-}
-
-void
-ao_config_radio_cal_set(void) __reentrant
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_config.radio_cal = ao_cmd_lex_u32;
-       ao_config_set_radio();
-       _ao_config_edit_finish();
-}
-#endif
-
-#if HAS_LOG
-void
-ao_config_log_show(void) __reentrant
-{
-       printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10));
-}
-
-void
-ao_config_log_set(void) __reentrant
-{
-       uint16_t        block = (uint16_t) (ao_storage_block >> 10);
-       uint16_t        log_max = (uint16_t) (ao_storage_log_max >> 10);
-
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       if (ao_log_present())
-               printf("Storage must be empty before changing log size\n");
-       else if (block > 1024 && (ao_cmd_lex_i & (block - 1)))
-               printf("Flight log size must be multiple of %d kB\n", block);
-       else if (ao_cmd_lex_i > 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;
-               _ao_config_edit_finish();
-       }
-}
-#endif /* HAS_LOG */
-
-#if HAS_IGNITE
-void
-ao_config_ignite_mode_show(void) __reentrant
-{
-       printf("Ignite mode: %d\n", ao_config.ignite_mode);
-}
-
-void
-ao_config_ignite_mode_set(void) __reentrant
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_config.ignite_mode = ao_cmd_lex_i;
-       _ao_config_edit_finish();
-}
-#endif
-
-#if HAS_ACCEL
-void
-ao_config_pad_orientation_show(void) __reentrant
-{
-       printf("Pad orientation: %d\n", ao_config.pad_orientation);
-}
-
-#ifndef AO_ACCEL_INVERT
-#define AO_ACCEL_INVERT        0x7fff
-#endif
-
-void
-ao_config_pad_orientation_set(void) __reentrant
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_cmd_lex_i &= 1;
-       if (ao_config.pad_orientation != ao_cmd_lex_i) {
-               int16_t t;
-               t = ao_config.accel_plus_g;
-               ao_config.accel_plus_g = AO_ACCEL_INVERT - ao_config.accel_minus_g;
-               ao_config.accel_minus_g = AO_ACCEL_INVERT - t;
-       }
-       ao_config.pad_orientation = ao_cmd_lex_i;
-       _ao_config_edit_finish();
-}
-#endif
-
-#if HAS_RADIO
-void
-ao_config_radio_enable_show(void) __reentrant
-{
-       printf("Radio enable: %d\n", ao_config.radio_enable);
-}
-
-void
-ao_config_radio_enable_set(void) __reentrant
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_config.radio_enable = ao_cmd_lex_i;
-       _ao_config_edit_finish();
-}
-#endif /* HAS_RADIO */
-       
-#if HAS_AES
-
-__xdata uint8_t        ao_config_aes_seq = 1;
-
-void
-ao_config_key_show(void) __reentrant
-{
-       uint8_t i;
-       printf("AES key: ");
-       for (i = 0; i < AO_AES_LEN; i++)
-               printf ("%02x", ao_config.aes_key[i]);
-       printf("\n");
-}
-
-void
-ao_config_key_set(void) __reentrant
-{
-       uint8_t i;
-
-       _ao_config_edit_start();
-       for (i = 0; i < AO_AES_LEN; i++) {
-               ao_cmd_hexbyte();
-               if (ao_cmd_status != ao_cmd_success)
-                       break;
-               ao_config.aes_key[i] = ao_cmd_lex_i;
-       }
-       ++ao_config_aes_seq;
-       _ao_config_edit_finish();
-}
-#endif
-
-#if HAS_APRS
-
-void
-ao_config_aprs_show(void)
-{
-       printf ("APRS interval: %d\n", ao_config.aprs_interval);
-}
-
-void
-ao_config_aprs_set(void)
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_config.aprs_interval = ao_cmd_lex_i;
-       _ao_config_edit_finish();
-}
-
-#endif /* HAS_APRS */
-
-#if HAS_RADIO_AMP
-
-void
-ao_config_radio_amp_show(void)
-{
-       printf ("Radio amp setting: %d\n", ao_config.radio_amp);
-}
-
-void
-ao_config_radio_amp_set(void)
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_config.radio_amp = ao_cmd_lex_i;
-       _ao_config_edit_finish();
-}
-
-#endif
-
-#if HAS_RADIO_POWER
-
-void
-ao_config_radio_power_show(void)
-{
-       printf ("Radio power setting: %d\n", ao_config.radio_power);
-}
-
-void
-ao_config_radio_power_set(void)
-{
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       _ao_config_edit_start();
-       ao_config.radio_power = ao_cmd_lex_i;
-       _ao_config_edit_finish();
-}
-
-#endif
-
-struct ao_config_var {
-       __code char     *str;
-       void            (*set)(void) __reentrant;
-       void            (*show)(void) __reentrant;
-};
-
-static void
-ao_config_help(void) __reentrant;
-
-static void
-ao_config_show(void) __reentrant;
-
-#if HAS_EEPROM
-static void
-ao_config_save(void) __reentrant;
-#endif
-
-__code struct ao_config_var ao_config_vars[] = {
-#if HAS_FLIGHT
-       { "m <meters>\0Main deploy (m)",
-         ao_config_main_deploy_set,    ao_config_main_deploy_show, },
-       { "d <delay>\0Apogee delay (s)",
-         ao_config_apogee_delay_set,   ao_config_apogee_delay_show },
-       { "L <seconds>\0Apogee detect lockout (s)",
-         ao_config_apogee_lockout_set, ao_config_apogee_lockout_show, },
-#endif /* HAS_FLIGHT */
-#if HAS_RADIO
-       { "F <freq>\0Frequency (kHz)",
-         ao_config_frequency_set, ao_config_frequency_show },
-       { "c <call>\0Callsign (8 char max)",
-         ao_config_callsign_set,       ao_config_callsign_show },
-       { "e <0 disable, 1 enable>\0Enable telemetry and RDF",
-         ao_config_radio_enable_set, ao_config_radio_enable_show },
-       { "f <cal>\0Radio calib (cal = rf/(xtal/2^16))",
-         ao_config_radio_cal_set,      ao_config_radio_cal_show },
-#if HAS_RADIO_POWER
-       { "p <setting>\0Radio power setting (0-255)",
-         ao_config_radio_power_set,    ao_config_radio_power_show },
-#endif
-#if HAS_RADIO_AMP
-       { "d <setting>\0Radio amplifier setting (0-3)",
-         ao_config_radio_amp_set,      ao_config_radio_amp_show },
-#endif
-#endif /* HAS_RADIO */
-#if HAS_ACCEL
-       { "a <+g> <-g>\0Accel calib (0 for auto)",
-         ao_config_accel_calibrate_set,ao_config_accel_calibrate_show },
-       { "o <0 antenna up, 1 antenna down>\0Set pad orientation",
-         ao_config_pad_orientation_set,ao_config_pad_orientation_show },
-#endif /* HAS_ACCEL */
-#if HAS_LOG
-       { "l <size>\0Flight log size (kB)",
-         ao_config_log_set,            ao_config_log_show },
-#endif
-#if HAS_IGNITE
-       { "i <0 dual, 1 apogee, 2 main>\0Set igniter mode",
-         ao_config_ignite_mode_set,    ao_config_ignite_mode_show },
-#endif
-#if HAS_AES
-       { "k <32 hex digits>\0Set AES encryption key",
-         ao_config_key_set, ao_config_key_show },
-#endif
-#if AO_PYRO_NUM
-       { "P <n,?>\0Configure pyro channels",
-         ao_pyro_set, ao_pyro_show },
-#endif
-#if HAS_APRS
-       { "A <secs>\0APRS packet interval (0 disable)",
-         ao_config_aprs_set, ao_config_aprs_show },
-#endif
-       { "s\0Show",
-         ao_config_show,               0 },
-#if HAS_EEPROM
-       { "w\0Write to eeprom",
-         ao_config_save,               0 },
-#endif
-       { "?\0Help",
-         ao_config_help,               0 },
-       { 0, 0, 0 }
-};
-
-void
-ao_config_set(void)
-{
-       char    c;
-       uint8_t cmd;
-
-       ao_cmd_white();
-       c = ao_cmd_lex_c;
-       ao_cmd_lex();
-       for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
-               if (ao_config_vars[cmd].str[0] == c) {
-                       (*ao_config_vars[cmd].set)();
-                       return;
-               }
-       ao_cmd_status = ao_cmd_syntax_error;
-}
-
-static void
-ao_config_help(void) __reentrant
-{
-       uint8_t cmd;
-       for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
-               printf("%-20s %s\n",
-                      ao_config_vars[cmd].str,
-                      ao_config_vars[cmd].str+1+
-                      strlen(ao_config_vars[cmd].str));
-}
-
-static void
-ao_config_show(void) __reentrant
-{
-       uint8_t cmd;
-       ao_config_get();
-       printf("Config version: %d.%d\n",
-              ao_config.major, ao_config.minor);
-       for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
-               if (ao_config_vars[cmd].show)
-                       (*ao_config_vars[cmd].show)();
-#if HAS_MS5607
-       ao_ms5607_info();
-#endif
-}
-
-#if HAS_EEPROM
-static void
-ao_config_save(void) __reentrant
-{
-       uint8_t saved = 0;
-       ao_mutex_get(&ao_config_mutex);
-       if (ao_config_dirty) {
-               _ao_config_put();
-               ao_config_dirty = 0;
-               saved = 1;
-       }
-       ao_mutex_put(&ao_config_mutex);
-       if (saved)
-               puts("Saved");
-       else
-               puts("Nothing to save");
-}
-#endif
-
-__code struct ao_cmds ao_config_cmds[] = {
-       { ao_config_set,        "c <var> <value>\0Set config (? for help, s to show)" },
-       { 0, NULL },
-};
-
-void
-ao_config_init(void)
-{
-       ao_cmd_register(&ao_config_cmds[0]);
-}
diff --git a/src/core/ao_config.h b/src/core/ao_config.h
deleted file mode 100644 (file)
index e101af8..0000000
+++ /dev/null
@@ -1,53 +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_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_convert.c b/src/core/ao_convert.c
deleted file mode 100644 (file)
index aa9b5f4..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.
- */
-
-#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST)
-#include "ao.h"
-#endif
-
-static const int16_t altitude_table[] = {
-#include "altitude.h"
-};
-
-#define ALT_FRAC_SCALE (1 << ALT_FRAC_BITS)
-#define ALT_FRAC_MASK  (ALT_FRAC_SCALE - 1)
-
-int16_t
-ao_pres_to_altitude(int16_t pres) __reentrant
-{
-       uint8_t o;
-       int16_t part;
-
-       if (pres < 0)
-               pres = 0;
-       o = pres >> ALT_FRAC_BITS;
-       part = pres & ALT_FRAC_MASK;
-
-       return ((int32_t) altitude_table[o] * (ALT_FRAC_SCALE - part) +
-               (int32_t) altitude_table[o+1] * part + (ALT_FRAC_SCALE >> 1)) >> ALT_FRAC_BITS;
-}
-
-#if AO_NEED_ALTITUDE_TO_PRES
-int16_t
-ao_altitude_to_pres(int16_t alt) __reentrant
-{
-       int16_t span, sub_span;
-       uint8_t l, h, m;
-       int32_t pres;
-
-       l = 0;
-       h = NALT - 1;
-       while ((h - l) != 1) {
-               m = (l + h) >> 1;
-               if (altitude_table[m] < alt)
-                       h = m;
-               else
-                       l = m;
-       }
-       span = altitude_table[l] - altitude_table[h];
-       sub_span = altitude_table[l] - alt;
-       pres = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_FRAC_BITS) + (span >> 1)) / span;
-       if (pres > 32767)
-               pres = 32767;
-       if (pres < 0)
-               pres = 0;
-       return (int16_t) pres;
-}
-#endif
-
-#if 0
-int16_t
-ao_temp_to_dC(int16_t temp) __reentrant
-{
-       int16_t ret;
-
-       /* Output voltage at 0°C = 0.755V
-        * Coefficient = 0.00247V/°C
-        * Reference voltage = 1.25V
-        *
-        * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247
-        *      = (value - 19791.268) / 32768 * 1.25 / 0.00247
-        *      ≃ (value - 19791) * 1012 / 65536
-        */
-       ret = ((temp - 19791) * 1012L) >> 16;
-       return ret;
-}
-#endif
diff --git a/src/core/ao_convert_pa.c b/src/core/ao_convert_pa.c
deleted file mode 100644 (file)
index fe6e0ef..0000000
+++ /dev/null
@@ -1,82 +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.
- */
-
-#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST)
-#include "ao.h"
-#endif
-
-#ifndef AO_CONST_ATTRIB
-#define AO_CONST_ATTRIB
-#endif
-
-static const alt_t altitude_table[] AO_CONST_ATTRIB = {
-#include "altitude-pa.h"
-};
-
-#ifndef FETCH_ALT
-#define FETCH_ALT(o)   altitude_table[o]
-#endif
-
-#define ALT_SCALE      (1 << ALT_SHIFT)
-#define ALT_MASK       (ALT_SCALE - 1)
-
-alt_t
-ao_pa_to_altitude(int32_t pa)
-{
-       int16_t o;
-       int16_t part;
-       int32_t low, high;
-
-       if (pa < 0)
-               pa = 0;
-       if (pa > 120000L)
-               pa = 120000L;
-       o = pa >> ALT_SHIFT;
-       part = pa & ALT_MASK;
-
-       low = (int32_t) FETCH_ALT(o) * (ALT_SCALE - part);
-       high = (int32_t) FETCH_ALT(o+1) * part + (ALT_SCALE >> 1);
-       return (low + high) >> ALT_SHIFT;
-}
-
-#ifdef AO_CONVERT_TEST
-int32_t
-ao_altitude_to_pa(int32_t alt)
-{
-       int32_t         span, sub_span;
-       uint16_t        l, h, m;
-       int32_t         pa;
-
-       l = 0;
-       h = NALT - 1;
-       while ((h - l) != 1) {
-               m = (l + h) >> 1;
-               if (altitude_table[m] < alt)
-                       h = m;
-               else
-                       l = m;
-       }
-       span = altitude_table[l] - altitude_table[h];
-       sub_span = altitude_table[l] - alt;
-       pa = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_SHIFT) + (span >> 1)) / span;
-       if (pa > 120000)
-               pa = 120000;
-       if (pa < 0)
-               pa = 0;
-       return pa;
-}
-#endif
diff --git a/src/core/ao_convert_pa_test.c b/src/core/ao_convert_pa_test.c
deleted file mode 100644 (file)
index 7d5b192..0000000
+++ /dev/null
@@ -1,76 +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 <stdint.h>
-#define AO_CONVERT_TEST
-typedef int32_t alt_t;
-#include "ao_host.h"
-#include "ao_convert_pa.c"
-
-#define STEP_P 1
-#define STEP_A 1
-
-static inline int i_abs(int i) { return i < 0 ? -i : i; }
-
-int
-main (int argc, char **argv)
-{
-       int     i;
-       int32_t p_to_a, p_to_a_to_p;
-       int32_t a_to_p, a_to_p_to_a;
-       int max_p_error = 0, max_p_error_p = -1;
-       int max_a_error = 0, max_a_error_a = -1;
-       int p_error;
-       int a_error;
-       int ret = 0;
-
-       for (i = 0; i < 120000 + STEP_P; i += STEP_P) {
-               if (i > 120000)
-                       i = 120000;
-               p_to_a = ao_pa_to_altitude(i);
-               p_to_a_to_p = ao_altitude_to_pa(p_to_a);
-               p_error = i_abs(p_to_a_to_p - i);
-               if (p_error > max_p_error) {
-                       max_p_error = p_error;
-                       max_p_error_p = i;
-               }
-//             printf ("pa %d alt %d pa %d\n",
-//                     i, p_to_a, p_to_a_to_p);
-       }
-       for (i = -1450; i < 40000 + STEP_A; i += STEP_A) {
-               a_to_p = ao_altitude_to_pa(i);
-               a_to_p_to_a = ao_pa_to_altitude(a_to_p);
-               a_error = i_abs(a_to_p_to_a - i);
-               if (a_error > max_a_error) {
-                       max_a_error = a_error;
-                       max_a_error_a = i;
-               }
-//             printf ("alt %d pa %d alt %d\n",
-//                     i, a_to_p, a_to_p_to_a);
-       }
-       if (max_p_error > 2) {
-               printf ("max p error %d at %d\n", max_p_error,
-                       max_p_error_p);
-               ret++;
-       }
-       if (max_a_error > 1) {
-               printf ("max a error %d at %d\n", max_a_error,
-                       max_a_error_a);
-               ret++;
-       }
-       return ret;
-}
diff --git a/src/core/ao_convert_test.c b/src/core/ao_convert_test.c
deleted file mode 100644 (file)
index 87e7684..0000000
+++ /dev/null
@@ -1,76 +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.
- */
-
-#include <stdint.h>
-#define AO_CONVERT_TEST
-#define AO_NEED_ALTITUDE_TO_PRES 1
-#include "ao_host.h"
-#include "ao_convert.c"
-
-#define STEP   1
-
-static inline int i_abs(int i) { return i < 0 ? -i : i; }
-
-int main (int argc, char **argv)
-{
-       int     i;
-       int16_t p_to_a, p_to_a_to_p;
-       int16_t a_to_p, a_to_p_to_a;
-       int max_p_error = 0, max_p_error_p = -1;
-       int max_a_error = 0, max_a_error_a = -1;
-       int p_error;
-       int a_error;
-       int ret = 0;
-
-       for (i = 0; i < 32767 + STEP; i += STEP) {
-               if (i > 32767)
-                       i = 32767;
-               p_to_a = ao_pres_to_altitude(i);
-               p_to_a_to_p = ao_altitude_to_pres(p_to_a);
-               p_error = i_abs(p_to_a_to_p - i);
-               if (p_error > max_p_error) {
-                       max_p_error = p_error;
-                       max_p_error_p = i;
-               }
-//             printf ("pres %d alt %d pres %d\n",
-//                     i, p_to_a, p_to_a_to_p);
-       }
-       for (i = -1578; i < 15835 + STEP; i += STEP) {
-               if (i > 15835)
-                       i = 15835;
-               a_to_p = ao_altitude_to_pres(i);
-               a_to_p_to_a = ao_pres_to_altitude(a_to_p);
-               a_error = i_abs(a_to_p_to_a - i);
-               if (a_error > max_a_error) {
-                       max_a_error = a_error;
-                       max_a_error_a = i;
-               }
-//             printf ("alt %d pres %d alt %d\n",
-//                     i, a_to_p, a_to_p_to_a);
-       }
-       if (max_p_error > 2) {
-               printf ("max p error %d at %d\n", max_p_error,
-                       max_p_error_p);
-               ret++;
-       }
-       if (max_a_error > 1) {
-               printf ("max a error %d at %d\n", max_a_error,
-                       max_a_error_a);
-               ret++;
-       }
-       return ret;
-}
diff --git a/src/core/ao_convert_volt.c b/src/core/ao_convert_volt.c
deleted file mode 100644 (file)
index 8556d42..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright © 2014 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public 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 scale(v,p,m)   ((int32_t) (v) * (AO_ADC_REFERENCE_DV * ((p) + (m))) / (AO_ADC_MAX * (m)))
-
-int16_t
-ao_battery_decivolt(int16_t adc)
-{
-       return scale(adc, AO_BATTERY_DIV_PLUS, AO_BATTERY_DIV_MINUS);
-}
-
-int16_t
-ao_ignite_decivolt(int16_t adc)
-{
-       return scale(adc, AO_IGNITE_DIV_PLUS, AO_IGNITE_DIV_MINUS);
-}
-
diff --git a/src/core/ao_data.c b/src/core/ao_data.c
deleted file mode 100644 (file)
index 6a3d02a..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.
- */
-
-#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
diff --git a/src/core/ao_data.h b/src/core/ao_data.h
deleted file mode 100644 (file)
index c4b062f..0000000
+++ /dev/null
@@ -1,338 +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_DATA_H_
-#define _AO_DATA_H_
-
-#define GRAVITY 9.80665
-
-#if HAS_ADC
-#define AO_DATA_ADC    (1 << 0)
-#else
-#define AO_DATA_ADC    0
-#endif
-
-#if HAS_MS5607
-#include <ao_ms5607.h>
-#define AO_DATA_MS5607 (1 << 1)
-#else
-#define AO_DATA_MS5607 0
-#endif
-
-#if HAS_MPU6000
-#include <ao_mpu6000.h>
-#define AO_DATA_MPU6000        (1 << 2)
-#else
-#define AO_DATA_MPU6000        0
-#endif
-
-#if HAS_HMC5883
-#include <ao_hmc5883.h>
-#define AO_DATA_HMC5883        (1 << 3)
-#else
-#define AO_DATA_HMC5883        0
-#endif
-
-#if HAS_MMA655X
-#include <ao_mma655x.h>
-#define AO_DATA_MMA655X (1 << 4)
-#else
-#define AO_DATA_MMA655X 0
-#endif
-
-#ifdef AO_DATA_RING
-
-#define AO_DATA_ALL    (AO_DATA_ADC|AO_DATA_MS5607|AO_DATA_MPU6000|AO_DATA_HMC5883|AO_DATA_MMA655X)
-
-struct ao_data {
-       uint16_t                        tick;
-#if HAS_ADC
-       struct ao_adc                   adc;
-#endif
-#if HAS_MS5607
-       struct ao_ms5607_sample         ms5607_raw;
-       struct ao_ms5607_value          ms5607_cooked;
-#endif
-#if HAS_MPU6000
-       struct ao_mpu6000_sample        mpu6000;
-#if !HAS_MMA655X
-       int16_t                         z_accel;
-#endif
-#endif
-#if HAS_HMC5883
-       struct ao_hmc5883_sample        hmc5883;
-#endif
-#if HAS_MMA655X
-       uint16_t                        mma655x;
-#endif
-};
-
-#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;
-extern volatile __data uint8_t         ao_data_count;
-
-/*
- * Mark a section of data as ready, check for data complete
- */
-#define AO_DATA_PRESENT(bit)   (ao_data_present |= (bit))
-
-/*
- * Wait until it is time to write a sensor sample; this is
- * signaled by the timer tick
- */
-#define AO_DATA_WAIT() do {                            \
-               ao_sleep(DATA_TO_XDATA ((void *) &ao_data_count));      \
-       } while (0)
-
-#endif /* AO_DATA_RING */
-
-#if !HAS_BARO && HAS_MS5607
-
-/* Either an MS5607 or an MS5611 hooked to a SPI port
- */
-
-#define HAS_BARO       1
-
-typedef int32_t        pres_t;
-
-#ifndef AO_ALT_TYPE
-#define AO_ALT_TYPE    int32_t
-#endif
-
-typedef AO_ALT_TYPE    alt_t;
-
-#define ao_data_pres_cook(packet)      ao_ms5607_convert(&packet->ms5607_raw, &packet->ms5607_cooked)
-
-#define ao_data_pres(packet)   ((packet)->ms5607_cooked.pres)
-#define ao_data_temp(packet)   ((packet)->ms5607_cooked.temp)
-
-#define pres_to_altitude(p)    ao_pa_to_altitude(p)
-
-#endif
-
-#if !HAS_BARO && HAS_ADC
-
-#define HAS_BARO       1
-
-typedef int16_t pres_t;
-typedef int16_t alt_t;
-
-#define ao_data_pres(packet)   ((packet)->adc.pres)
-#define ao_data_temp(packet)   ((packet)->adc.temp)
-#define pres_to_altitude(p)    ao_pres_to_altitude(p)
-#define ao_data_pres_cook(p)
-
-#endif
-
-#if !HAS_BARO
-typedef int16_t alt_t;
-#endif
-
-/*
- * Need a few macros to pull data from the sensors:
- *
- * ao_data_accel_sample        - pull raw sensor and convert to normalized values
- * ao_data_accel       - pull normalized value (lives in the same memory)
- * ao_data_set_accel   - store normalized value back in the sensor location
- * ao_data_accel_invert        - flip rocket ends for positive acceleration
- */
-
-#if HAS_ACCEL
-
-/* This section is for an analog accelerometer hooked to one of the ADC pins. As
- * those are 5V parts, this also requires that the 5V supply be hooked to to anothe ADC
- * pin so that the both can be measured to correct for changes between the 3.3V and 5V rails
- */
-
-typedef int16_t accel_t;
-#define ao_data_accel(packet)                  ((packet)->adc.accel)
-#define ao_data_set_accel(packet, a)           ((packet)->adc.accel = (a))
-#define ao_data_accel_invert(a)                        (0x7fff -(a))
-
-/*
- * Ok, the math here is a bit tricky.
- *
- * ao_sample_accel:  ADC output for acceleration
- * ao_accel_ref:  ADC output for the 5V reference.
- * ao_cook_accel: Corrected acceleration value
- * Vcc:           3.3V supply to the CC1111
- * Vac:           5V supply to the accelerometer
- * accel:         input voltage to accelerometer ADC pin
- * ref:           input voltage to 5V reference ADC pin
- *
- *
- * Measured acceleration is ratiometric to Vcc:
- *
- *     ao_sample_accel   accel
- *     ------------ = -----
- *        32767        Vcc
- *
- * Measured 5v reference is also ratiometric to Vcc:
- *
- *     ao_accel_ref    ref
- *     ------------ = -----
- *        32767        Vcc
- *
- *
- *     ao_accel_ref = 32767 * (ref / Vcc)
- *
- * Acceleration is measured ratiometric to the 5V supply,
- * so what we want is:
- *
- *     ao_cook_accel    accel
- *      ------------- =  -----
- *          32767         ref
- *
- *
- *                     accel    Vcc
- *                    = ----- *  ---
- *                       Vcc     ref
- *
- *                      ao_sample_accel       32767
- *                    = ------------ *  ------------
- *                         32767        ao_accel_ref
- *
- * Multiply through by 32767:
- *
- *                      ao_sample_accel * 32767
- *     ao_cook_accel = --------------------
- *                          ao_accel_ref
- *
- * Now, the tricky part. Getting this to compile efficiently
- * and keeping all of the values in-range.
- *
- * First off, we need to use a shift of 16 instead of * 32767 as SDCC
- * does the obvious optimizations for byte-granularity shifts:
- *
- *     ao_cook_accel = (ao_sample_accel << 16) / ao_accel_ref
- *
- * Next, lets check our input ranges:
- *
- *     0 <= ao_sample_accel <= 0x7fff          (singled ended ADC conversion)
- *     0x7000 <= ao_accel_ref <= 0x7fff        (the 5V ref value is close to 0x7fff)
- *
- * Plugging in our input ranges, we get an output range of 0 - 0x12490,
- * which is 17 bits. That won't work. If we take the accel ref and shift
- * by a bit, we'll change its range:
- *
- *     0xe000 <= ao_accel_ref<<1 <= 0xfffe
- *
- *     ao_cook_accel = (ao_sample_accel << 16) / (ao_accel_ref << 1)
- *
- * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It
- * is, however, one bit too large for our signed computations. So, we
- * take the result and shift that by a bit:
- *
- *     ao_cook_accel = ((ao_sample_accel << 16) / (ao_accel_ref << 1)) >> 1
- *
- * This finally creates an output range of 0 - 0x4924. As the ADC only
- * provides 11 bits of data, we haven't actually lost any precision,
- * just dropped a bit of noise off the low end.
- */
-
-#if HAS_ACCEL_REF
-
-#define ao_data_accel_cook(packet) \
-       ((uint16_t) ((((uint32_t) (packet)->adc.accel << 16) / ((packet)->adc.accel_ref << 1))) >> 1)
-
-#else
-
-#define ao_data_accel_cook(packet) ((packet)->adc.accel)
-
-#endif /* HAS_ACCEL_REF */
-
-#endif /* HAS_ACCEL */
-
-#if !HAS_ACCEL && HAS_MMA655X
-
-#define HAS_ACCEL      1
-
-typedef int16_t accel_t;
-
-/* MMA655X is hooked up so that positive values represent negative acceleration */
-
-#define AO_ACCEL_INVERT                4095
-
-#define ao_data_accel(packet)                  ((packet)->mma655x)
-#if AO_MMA655X_INVERT
-#define ao_data_accel_cook(packet)             (AO_ACCEL_INVERT - (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)            (AO_ACCEL_INVERT - (accel))
-
-#endif
-
-#if !HAS_ACCEL && HAS_MPU6000
-
-#define HAS_ACCEL      1
-
-#define AO_ACCEL_INVERT                0
-
-typedef int16_t accel_t;
-
-/* MPU6000 is hooked up so that positive y is positive acceleration */
-#define ao_data_accel(packet)                  ((packet)->z_accel)
-#define ao_data_accel_cook(packet)             (-(packet)->mpu6000.accel_y)
-#define ao_data_set_accel(packet, accel)       ((packet)->z_accel = (accel))
-#define ao_data_accel_invert(a)                        (-(a))
-
-#endif
-
-#if !HAS_GYRO && HAS_MPU6000
-
-#define HAS_GYRO       1
-
-typedef int16_t        gyro_t;         /* in raw sample units */
-typedef int16_t angle_t;       /* in degrees */
-
-/* Y axis is aligned with the direction of motion (along) */
-/* X axis is aligned in the other board axis (across) */
-/* Z axis is aligned perpendicular to the board (through) */
-
-#define ao_data_along(packet)  ((packet)->mpu6000.accel_y)
-#define ao_data_across(packet) ((packet)->mpu6000.accel_x)
-#define ao_data_through(packet)        ((packet)->mpu6000.accel_z)
-
-#define ao_data_roll(packet)   ((packet)->mpu6000.gyro_y)
-#define ao_data_pitch(packet)  ((packet)->mpu6000.gyro_x)
-#define ao_data_yaw(packet)    ((packet)->mpu6000.gyro_z)
-
-#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_dbg.h b/src/core/ao_dbg.h
deleted file mode 100644 (file)
index 181e6ec..0000000
+++ /dev/null
@@ -1,62 +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_DBG_H_
-#define _AO_DBG_H_
-
-/*
- * ao_dbg.c
- *
- * debug another telemetrum board
- */
-
-/* Send a byte to the dbg target */
-void
-ao_dbg_send_byte(uint8_t byte);
-
-/* Receive a byte from the dbg target */
-uint8_t
-ao_dbg_recv_byte(void);
-
-/* Start a bulk transfer to/from dbg target memory */
-void
-ao_dbg_start_transfer(uint16_t addr);
-
-/* End a bulk transfer to/from dbg target memory */
-void
-ao_dbg_end_transfer(void);
-
-/* Write a byte to dbg target memory */
-void
-ao_dbg_write_byte(uint8_t byte);
-
-/* Read a byte from dbg target memory */
-uint8_t
-ao_dbg_read_byte(void);
-
-/* Enable dbg mode, switching use of the pins */
-void
-ao_dbg_debug_mode(void);
-
-/* Reset the dbg target */
-void
-ao_dbg_reset(void);
-
-void
-ao_dbg_init(void);
-
-#endif /* _AO_DBG_H_ */
diff --git a/src/core/ao_debounce.c b/src/core/ao_debounce.c
deleted file mode 100644 (file)
index b9d6772..0000000
+++ /dev/null
@@ -1,163 +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.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
deleted file mode 100644 (file)
index 19c620f..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_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_ee_fake.c b/src/core/ao_ee_fake.c
deleted file mode 100644 (file)
index 7fcfcab..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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"
-
-/*
- * For hardware without eeprom, the config code still
- * wants to call these functions
- */
-uint8_t
-ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant
-{
-       (void) buf;
-       (void) len;
-       return 1;
-}
-
-uint8_t
-ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant
-{
-       ao_xmemset(buf, '\0', len);
-       return 1;
-}
diff --git a/src/core/ao_eeprom.h b/src/core/ao_eeprom.h
deleted file mode 100644 (file)
index 915522b..0000000
+++ /dev/null
@@ -1,43 +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_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_ */
diff --git a/src/core/ao_fec.h b/src/core/ao_fec.h
deleted file mode 100644 (file)
index 618756c..0000000
+++ /dev/null
@@ -1,84 +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_FEC_H_
-#define _AO_FEC_H_
-
-#include <stdint.h>
-
-#define AO_FEC_CRC_INIT                        0xffff
-#define AO_FEC_TRELLIS_TERMINATOR      0x0b
-#define AO_FEC_PREPARE_EXTRA           4
-
-extern const uint8_t ao_fec_whiten_table[];
-
-#if AO_FEC_DEBUG
-void
-ao_fec_dump_bytes(const uint8_t *bytes, uint16_t len, const char *name);
-#endif
-
-static inline uint16_t
-ao_fec_crc_byte(uint8_t byte, uint16_t crc)
-{
-       uint8_t bit;
-
-       for (bit = 0; bit < 8; bit++) {
-               if (((crc & 0x8000) >> 8) ^ (byte & 0x80))
-                       crc = (crc << 1) ^ 0x8005;
-               else
-                       crc = (crc << 1);
-               byte <<= 1;
-       }
-       return crc;
-}
-
-uint16_t
-ao_fec_crc(const uint8_t *bytes, uint8_t len);
-
-/*
- * 'len' is the length of the original data; 'bytes'
- * must  be four bytes longer than that, and the first
- * two after 'len' must be the received crc
- */
-uint8_t
-ao_fec_check_crc(const uint8_t *bytes, uint8_t len);
-
-/*
- * Compute CRC, whiten, convolve and interleave data. 'out' must be (len + 4) * 2 bytes long
- */
-uint8_t
-ao_fec_encode(const uint8_t *in, uint8_t len, uint8_t *out);
-
-/*
- * Decode data. 'in' is one byte per bit, soft decision
- * 'out' must be len/8 bytes long
- */
-
-#define AO_FEC_DECODE_BLOCK    (32)    /* callback must return multiples of this many bits */
-
-#define AO_FEC_DECODE_CRC_OK   0x80    /* stored in out[out_len-1] */
-
-uint8_t
-ao_fec_decode(const uint8_t *in, uint16_t in_len, uint8_t *out, uint8_t out_len, uint16_t (*callback)(void));
-
-/*
- * Interleave data packed in bytes. 'out' must be 'len' bytes long.
- */
-uint16_t
-ao_fec_interleave_bytes(uint8_t *in, uint16_t len, uint8_t *out);
-
-#endif /* _AO_FEC_H_ */
diff --git a/src/core/ao_fec_rx.c b/src/core/ao_fec_rx.c
deleted file mode 100644 (file)
index c4f5559..0000000
+++ /dev/null
@@ -1,318 +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_fec.h>
-#include <stdio.h>
-
-#ifdef TELEMEGA
-#include <ao.h>
-#endif
-
-#if AO_PROFILE
-#include <ao_profile.h>
-
-uint32_t       ao_fec_decode_start, ao_fec_decode_end;
-#endif
-
-/* 
- * byte order repeats through 3 2 1 0
- *     
- * bit-pair order repeats through
- *
- *  1/0 3/2 5/4 7/6
- *
- * So, the over all order is:
- *
- *     3,1/0   2,1/0   1,1/0   0,1/0
- *     3,3/2   2,3/2   1,3/2   0,3/2
- *     3,5/4   2,5/4   1,5/4   0,5/4
- *     3,7/6   2,7/6   1,7/6   0,7/6
- *
- * The raw bit order is thus
- *
- *     1e/1f   16/17   0e/0f   06/07
- *     1c/1d   14/15   0c/0d   04/05
- *     1a/1b   12/13   0a/0b   02/03
- *     18/19   10/11   08/09   00/01
- */
-
-static const uint8_t ao_interleave_order[] = {
-       0x1e, 0x16, 0x0e, 0x06,
-       0x1c, 0x14, 0x0c, 0x04,
-       0x1a, 0x12, 0x0a, 0x02,
-       0x18, 0x10, 0x08, 0x00
-};
-
-static inline uint16_t ao_interleave_index(uint16_t i) {
-       return (i & ~0x1e) | ao_interleave_order[(i & 0x1e) >> 1];
-}
-
-#define NUM_STATE      8
-#define NUM_HIST       24
-
-typedef uint32_t       bits_t;
-
-#define V_0            0xff
-#define V_1            0x00
-
-/*
- * These are just the 'zero' states; the 'one' states mirror them
- */
-static const uint8_t ao_fec_decode_table[NUM_STATE*2] = {
-       V_0, V_0,       /* 000 */
-       V_0, V_1,       /* 001 */
-       V_1, V_1,       /* 010 */
-       V_1, V_0,       /* 011 */
-       V_1, V_1,       /* 100 */
-       V_1, V_0,       /* 101 */
-       V_0, V_0,       /* 110 */
-       V_0, V_1        /* 111 */
-};
-
-static inline uint8_t
-ao_next_state(uint8_t state, uint8_t bit)
-{
-       return ((state << 1) | bit) & 0x7;
-}
-
-/*
- * 'in' is 8-bits per symbol soft decision data
- * 'len' is input byte length. 'out' must be
- * 'len'/16 bytes long
- */
-
-uint8_t
-ao_fec_decode(const uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t (*callback)(void))
-{
-       static uint32_t cost[2][NUM_STATE];             /* path cost */
-       static bits_t   bits[2][NUM_STATE];             /* save bits to quickly output them */
-
-       uint16_t        i;                              /* input byte index */
-       uint16_t        b;                              /* encoded symbol index (bytes/2) */
-       uint16_t        o;                              /* output bit index */
-       uint8_t         p;                              /* previous cost/bits index */
-       uint8_t         n;                              /* next cost/bits index */
-       uint8_t         state;                          /* state index */
-       const uint8_t   *whiten = ao_fec_whiten_table;
-       uint16_t        interleave;                     /* input byte array index */
-       uint8_t         s0, s1;
-       uint16_t        avail;
-       uint16_t        crc = AO_FEC_CRC_INIT;
-#if AO_PROFILE
-       uint32_t        start_tick;
-#endif
-
-       p = 0;
-       for (state = 0; state < NUM_STATE; state++) {
-               cost[0][state] = 0x7fffffff;
-               bits[0][state] = 0;
-       }
-       cost[0][0] = 0;
-
-       if (callback)
-               avail = 0;
-       else
-               avail = len;
-
-#if AO_PROFILE
-       if (!avail) {
-               avail = callback();
-               if (!avail)
-                       return 0;
-       }
-       start_tick = ao_profile_tick();
-#endif
-       o = 0;
-       for (i = 0; i < len; i += 2) {
-               b = i/2;
-               n = p ^ 1;
-
-               if (!avail) {
-                       avail = callback();
-                       if (!avail)
-                               return 0;
-               }
-
-               /* Fetch one pair of input bytes, de-interleaving
-                * the input.
-                */
-               interleave = ao_interleave_index(i);
-               s0 = in[interleave];
-               s1 = in[interleave+1];
-
-               avail -= 2;
-
-               /* Compute path costs and accumulate output bit path
-                * for each state and encoded bit value. Unrolling
-                * this loop is worth about > 30% performance boost.
-                * Decoding 76-byte remote access packets is reduced
-                * from 14.700ms to 9.3ms. Redoing the loop to
-                * directly compare the two pasts for each future state
-                * reduces this down to 5.7ms
-                */
-
-               /* Ok, of course this is tricky, it's optimized.
-                *
-                * First, it's important to realize that we have 8
-                * states representing the combinations of the three
-                * most recent bits from the encoder. Flipping any
-                * of these three bits flips both output bits.
-                *
-                * 'state<<1' represents the target state for a new
-                * bit value of 0. '(state<<1)+1' represents the
-                * target state for a new bit value of 1.
-                *
-                * 'state' is the previous state with an oldest bit
-                * value of 0. 'state + 4' is the previous state with
-                * an oldest bit value of 1. These two states will
-                * either lead to 'state<<1' or '(state<<1)+1', depending
-                * on whether the next encoded bit was a zero or a one.
-                *
-                * m0 and m1 are the cost of coming to 'state<<1' from
-                * one of the two possible previous states 'state' and
-                * 'state + 4'.
-                *
-                * Because we know the expected values of each
-                * received bit are flipped between these two previous
-                * states:
-                * 
-                *      bitcost(state+4) = 510 - bitcost(state)
-                *
-                * With those two total costs in hand, we then pick
-                * the lower as the cost of the 'state<<1', and compute
-                * the path of bits leading to that state.
-                *
-                * Then, do the same for '(state<<1) + 1'. This time,
-                * instead of computing the m0 and m1 values from
-                * scratch, because the only difference is that we're
-                * expecting a one bit instead of a zero bit, we just
-                * flip the bitcost values around to match the
-                * expected transmitted bits with some tricky
-                * arithmetic which is equivalent to:
-                *
-                *      m0 = cost[p][state] + (510 - bitcost);
-                *      m1 = cost[p][state+4] + bitcost
-                *
-                * Then, the lowest cost and bit trace of the new state
-                * is saved.
-                */
-
-#define DO_STATE(state) {                                              \
-                       uint32_t        bitcost;                        \
-                                                                       \
-                       uint32_t        m0;                             \
-                       uint32_t        m1;                             \
-                       uint32_t        bit;                            \
-                                                                       \
-                       bitcost = ((uint32_t) (s0 ^ ao_fec_decode_table[(state<<1)]) + \
-                                  (uint32_t) (s1 ^ ao_fec_decode_table[(state<<1)|1])); \
-                                                                       \
-                       m0 = cost[p][state] + bitcost;                  \
-                       m1 = cost[p][state+4] + (510 - bitcost);        \
-                       bit = m0 > m1;                                  \
-                       cost[n][state<<1] = bit ? m1 : m0;              \
-                       bits[n][state<<1] = (bits[p][state + (bit<<2)] << 1) | (state&1); \
-                                                                       \
-                       m0 -= (bitcost+bitcost-510);                    \
-                       m1 += (bitcost+bitcost-510);                    \
-                       bit = m0 > m1;                                  \
-                       cost[n][(state<<1)+1] = bit ? m1 : m0;          \
-                       bits[n][(state<<1)+1] = (bits[p][state + (bit<<2)] << 1) | (state&1); \
-               }
-
-               DO_STATE(0);
-               DO_STATE(1);
-               DO_STATE(2);
-               DO_STATE(3);
-
-#if 0
-               printf ("bit %3d symbol %2x %2x:", i/2, s0, s1);
-               for (state = 0; state < NUM_STATE; state++) {
-                       printf (" %8u(%08x)", cost[n][state], bits[n][state]);
-               }
-               printf ("\n");
-#endif
-               p = n;
-
-               /* A loop is needed to handle the last output byte. It
-                * won't have any bits of future data to perform full
-                * error correction, but we might as well give the
-                * best possible answer anyways.
-                */
-               while ((b - o) >= (8 + NUM_HIST) || (i + 2 >= len && b > o)) {
-
-                       /* Compute number of bits to the end of the
-                        * last full byte of data. This is generally
-                        * NUM_HIST, unless we've reached
-                        * the end of the input, in which case
-                        * it will be seven.
-                        */
-                       int8_t          dist = b - (o + 8);     /* distance to last ready-for-writing bit */
-                       uint32_t        min_cost;               /* lowest cost */
-                       uint8_t         min_state;              /* lowest cost state */
-                       uint8_t         byte;
-
-                       /* Find the best fit at the current point
-                        * of the decode.
-                        */
-                       min_cost = cost[p][0];
-                       min_state = 0;
-                       for (state = 1; state < NUM_STATE; state++) {
-                               if (cost[p][state] < min_cost) {
-                                       min_cost = cost[p][state];
-                                       min_state = state;
-                               }
-                       }
-
-                       /* The very last byte of data has the very last bit
-                        * of data left in the state value; just smash the
-                        * bits value in place and reset the 'dist' from
-                        * -1 to 0 so that the full byte is read out
-                        */
-                       if (dist < 0) {
-                               bits[p][min_state] = (bits[p][min_state] << 1) | (min_state & 1);
-                               dist = 0;
-                       }
-
-#if 0
-                       printf ("\tbit %3d min_cost %5d old bit %3d old_state %x bits %02x whiten %0x\n",
-                               i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff, *whiten);
-#endif
-                       byte = (bits[p][min_state] >> dist) ^ *whiten++;
-                       *out++ = byte;
-                       if (out_len > 2)
-                               crc = ao_fec_crc_byte(byte, crc);
-
-                       if (!--out_len) {
-                               if ((out[-2] == (uint8_t) (crc >> 8)) &&
-                                   out[-1] == (uint8_t) crc)
-                                       out[-1] = AO_FEC_DECODE_CRC_OK;
-                               else
-                                       out[-1] = 0;
-                               out[-2] = 0;
-                               goto done;
-                       }
-                       o += 8;
-               }
-       }
-done:
-#if AO_PROFILE
-       ao_fec_decode_start = start_tick;
-       ao_fec_decode_end = ao_profile_tick();
-#endif
-       return 1;
-}
diff --git a/src/core/ao_fec_tx.c b/src/core/ao_fec_tx.c
deleted file mode 100644 (file)
index 4941d74..0000000
+++ /dev/null
@@ -1,134 +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_fec.h>
-#include <stdio.h>
-
-#if AO_FEC_DEBUG
-void
-ao_fec_dump_bytes(const uint8_t *bytes, uint16_t len, const char *name)
-{
-       uint16_t        i;
-
-       printf ("%s (%d):", name, len);
-       for (i = 0; i < len; i++) {
-               if ((i & 7) == 0)
-                       printf ("\n\t%02x:", i);
-               printf(" %02x", bytes[i]);
-       }
-       printf ("\n");
-}
-#endif
-
-uint16_t
-ao_fec_crc(const uint8_t *bytes, uint8_t len)
-{
-       uint16_t        crc = AO_FEC_CRC_INIT;
-
-       while (len--)
-               crc = ao_fec_crc_byte(*bytes++, crc);
-       return crc;
-}
-
-/*
- * len is the length of the data; the crc will be
- * the fist two bytes after that
- */
-
-uint8_t
-ao_fec_check_crc(const uint8_t *bytes, uint8_t len)
-{
-       uint16_t        computed_crc = ao_fec_crc(bytes, len);
-       uint16_t        received_crc = (bytes[len] << 8) | (bytes[len+1]);
-
-       return computed_crc == received_crc;
-}
-
-/*
- * Compute CRC and trellis-terminator/interleave-pad bytes
- */
-static uint8_t
-ao_fec_prepare(const uint8_t *in, uint8_t len, uint8_t *extra)
-{
-       uint16_t        crc = ao_fec_crc (in, len);
-       uint8_t         i = 0;
-       uint8_t         num_fec;
-
-       /* Append CRC */
-       extra[i++] = crc >> 8;
-       extra[i++] = crc;
-
-       /* Append FEC -- 1 byte if odd, two bytes if even */
-       num_fec = 2 - (i & 1);
-       while (num_fec--)
-               extra[i++] = AO_FEC_TRELLIS_TERMINATOR;
-       return i;
-}
-
-const uint8_t ao_fec_whiten_table[] = {
-#include "ao_whiten.h"
-};
-
-static const uint8_t ao_fec_encode_table[16] = {
-/* next 0  1     state */
-       0, 3,   /* 000 */
-       1, 2,   /* 001 */
-       3, 0,   /* 010 */
-       2, 1,   /* 011 */
-       3, 0,   /* 100 */
-       2, 1,   /* 101 */
-       0, 3,   /* 110 */
-       1, 2    /* 111 */
-};
-
-uint8_t
-ao_fec_encode(const uint8_t *in, uint8_t len, uint8_t *out)
-{
-       uint8_t         extra[AO_FEC_PREPARE_EXTRA];
-       uint8_t         extra_len;
-       uint32_t        encode, interleave;
-       uint8_t         pair, byte, bit;
-       uint16_t        fec = 0;
-       const uint8_t   *whiten = ao_fec_whiten_table;
-
-       extra_len = ao_fec_prepare(in, len, extra);
-       for (pair = 0; pair < len + extra_len; pair += 2) {
-               encode = 0;
-               for (byte = 0; byte < 2; byte++) {
-                       if (pair + byte == len)
-                               in = extra;
-                       fec |= *in++ ^ *whiten++;
-                       for (bit = 0; bit < 8; bit++) {
-                               encode = encode << 2 | ao_fec_encode_table[fec >> 7];
-                               fec = (fec << 1) & 0x7ff;
-                       }
-               }
-
-               interleave = 0;
-               for (bit = 0; bit < 4 * 4; bit++) {
-                       uint8_t byte_shift = (bit & 0x3) << 3;
-                       uint8_t bit_shift = (bit & 0xc) >> 1;
-
-                       interleave = (interleave << 2) | ((encode >> (byte_shift + bit_shift)) & 0x3);
-               }
-               *out++ = interleave >> 24;
-               *out++ = interleave >> 16;
-               *out++ = interleave >> 8;
-               *out++ = interleave >> 0;
-       }
-       return (len + extra_len) * 2;
-}
diff --git a/src/core/ao_flight.c b/src/core/ao_flight.c
deleted file mode 100644 (file)
index 702c340..0000000
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AO_FLIGHT_TEST
-#include "ao.h"
-#include <ao_log.h>
-#endif
-
-#if HAS_MPU6000
-#include <ao_quaternion.h>
-#endif
-
-#ifndef HAS_ACCEL
-#error Please define HAS_ACCEL
-#endif
-
-#ifndef HAS_GPS
-#error Please define HAS_GPS
-#endif
-
-#ifndef HAS_USB
-#error Please define HAS_USB
-#endif
-
-#ifndef HAS_TELEMETRY
-#define HAS_TELEMETRY  HAS_RADIO
-#endif
-
-/* Main flight thread. */
-
-__pdata enum ao_flight_state   ao_flight_state;        /* current flight state */
-__pdata uint16_t               ao_boost_tick;          /* time of launch detect */
-__pdata uint16_t               ao_motor_number;        /* number of motors burned so far */
-
-#if HAS_SENSOR_ERRORS
-/* 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
- */
-static __data uint16_t         ao_interval_end;
-static __data int16_t          ao_interval_min_height;
-static __data int16_t          ao_interval_max_height;
-#if HAS_ACCEL
-static __data int16_t          ao_coast_avg_accel;
-#endif
-
-__pdata uint8_t                        ao_flight_force_idle;
-
-/* We also have a clock, which can be used to sanity check things in
- * case of other failures
- */
-
-#define BOOST_TICKS_MAX        AO_SEC_TO_TICKS(15)
-
-/* Landing is detected by getting constant readings from both pressure and accelerometer
- * for a fairly long time (AO_INTERVAL_TICKS)
- */
-#define AO_INTERVAL_TICKS      AO_SEC_TO_TICKS(10)
-
-#define abs(a) ((a) < 0 ? -(a) : (a))
-
-void
-ao_flight(void)
-{
-       ao_sample_init();
-       ao_flight_state = ao_flight_startup;
-       for (;;) {
-
-               /*
-                * Process ADC samples, just looping
-                * until the sensors are calibrated.
-                */
-               if (!ao_sample())
-                       continue;
-
-               switch (ao_flight_state) {
-               case ao_flight_startup:
-
-                       /* Check to see what mode we should go to.
-                        *  - Invalid mode if accel cal appears to be out
-                        *  - pad mode if we're upright,
-                        *  - idle mode otherwise
-                        */
-#if HAS_ACCEL
-                       if (ao_config.accel_plus_g == 0 ||
-                           ao_config.accel_minus_g == 0 ||
-                           ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP ||
-                           ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP ||
-                           ao_ground_height < -1000 ||
-                           ao_ground_height > 7000)
-                       {
-                               /* Detected an accel value outside -1.5g to 1.5g
-                                * (or uncalibrated values), so we go into invalid mode
-                                */
-                               ao_flight_state = ao_flight_invalid;
-
-#if HAS_RADIO && PACKET_HAS_SLAVE
-                               /* Turn on packet system in invalid mode on TeleMetrum */
-                               ao_packet_slave_start();
-#endif
-                       } else
-#endif
-                               if (!ao_flight_force_idle
-#if HAS_ACCEL
-                                   && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP
-#endif
-                                       )
-                       {
-                               /* Set pad mode - we can fly! */
-                               ao_flight_state = ao_flight_pad;
-#if HAS_USB && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE
-                               /* Disable the USB controller in flight mode
-                                * to save power
-                                */
-                               ao_usb_disable();
-#endif
-
-#if !HAS_ACCEL && PACKET_HAS_SLAVE
-                               /* Disable packet mode in pad state on TeleMini */
-                               ao_packet_slave_stop();
-#endif
-
-#if HAS_TELEMETRY
-                               /* Turn on telemetry system */
-                               ao_rdf_set(1);
-                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
-#endif
-#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;
-#if HAS_SENSOR_ERRORS
-                               if (ao_sensor_errors)
-                                       ao_flight_state = ao_flight_invalid;
-#endif
-#if HAS_ACCEL && HAS_RADIO && PACKET_HAS_SLAVE
-                               /* Turn on packet system in idle mode on TeleMetrum */
-                               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));
-
-                       break;
-               case ao_flight_pad:
-
-                       /* pad to boost:
-                        *
-                        * barometer: > 20m vertical motion
-                        *             OR
-                        * accelerometer: > 2g AND velocity > 5m/s
-                        *
-                        * The accelerometer should always detect motion before
-                        * the barometer, but we use both to make sure this
-                        * transition is detected. If the device
-                        * doesn't have an accelerometer, then ignore the
-                        * speed and acceleration as they are quite noisy
-                        * on the pad.
-                        */
-                       if (ao_height > AO_M_TO_HEIGHT(20)
-#if HAS_ACCEL
-                           || (ao_accel > AO_MSS_TO_ACCEL(20) &&
-                               ao_speed > AO_MS_TO_SPEED(5))
-#endif
-                               )
-                       {
-                               ao_flight_state = ao_flight_boost;
-                               ao_boost_tick = ao_sample_tick;
-
-                               /* start logging data */
-                               ao_log_start();
-
-#if HAS_TELEMETRY
-                               /* Increase telemetry rate */
-                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT);
-
-                               /* disable RDF beacon */
-                               ao_rdf_set(0);
-#endif
-
-#if HAS_GPS
-                               /* Record current GPS position by waking up GPS log tasks */
-                               ao_gps_new = AO_GPS_NEW_DATA | AO_GPS_NEW_TRACKING;
-                               ao_wakeup(&ao_gps_new);
-#endif
-
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                       }
-                       break;
-               case ao_flight_boost:
-
-                       /* boost to fast:
-                        *
-                        * accelerometer: start to fall at > 1/4 G
-                        *              OR
-                        * time: boost for more than 15 seconds
-                        *
-                        * Detects motor burn out by the switch from acceleration to
-                        * deceleration, or by waiting until the maximum burn duration
-                        * (15 seconds) has past.
-                        */
-                       if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) ||
-                           (int16_t) (ao_sample_tick - ao_boost_tick) > BOOST_TICKS_MAX)
-                       {
-#if HAS_ACCEL
-                               ao_flight_state = ao_flight_fast;
-                               ao_coast_avg_accel = ao_accel;
-#else
-                               ao_flight_state = ao_flight_coast;
-#endif
-                               ++ao_motor_number;
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                       }
-                       break;
-#if HAS_ACCEL
-               case ao_flight_fast:
-                       /*
-                        * This is essentially the same as coast,
-                        * but the barometer is being ignored as
-                        * it may be unreliable.
-                        */
-                       if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED))
-                       {
-                               ao_flight_state = ao_flight_coast;
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                       } else
-                               goto check_re_boost;
-                       break;
-#endif
-               case ao_flight_coast:
-
-                       /*
-                        * By customer request - allow the user
-                        * to lock out apogee detection for a specified
-                        * number of seconds.
-                        */
-                       if (ao_config.apogee_lockout) {
-                               if ((ao_sample_tick - ao_boost_tick) <
-                                   AO_SEC_TO_TICKS(ao_config.apogee_lockout))
-                                       break;
-                       }
-
-                       /* apogee detect: coast to drogue deploy:
-                        *
-                        * speed: < 0
-                        *
-                        * Also make sure the model altitude is tracking
-                        * the measured altitude reasonably closely; otherwise
-                        * we're probably transsonic.
-                        */
-                       if (ao_speed < 0
-#if !HAS_ACCEL
-                           && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100)
-#endif
-                               )
-                       {
-#if HAS_IGNITE
-                               /* ignite the drogue charge */
-                               ao_ignite(ao_igniter_drogue);
-#endif
-
-#if HAS_TELEMETRY
-                               /* slow down the telemetry system */
-                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER);
-
-                               /* Turn the RDF beacon back on */
-                               ao_rdf_set(1);
-#endif
-
-                               /* and enter drogue state */
-                               ao_flight_state = ao_flight_drogue;
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                       }
-#if HAS_ACCEL
-                       else {
-                       check_re_boost:
-                               ao_coast_avg_accel = ao_coast_avg_accel - (ao_coast_avg_accel >> 6) + (ao_accel >> 6);
-                               if (ao_coast_avg_accel > AO_MSS_TO_ACCEL(20)) {
-                                       ao_boost_tick = ao_sample_tick;
-                                       ao_flight_state = ao_flight_boost;
-                                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                               }
-                       }
-#endif
-
-                       break;
-               case ao_flight_drogue:
-
-                       /* drogue to main deploy:
-                        *
-                        * barometer: reach main deploy altitude
-                        *
-                        * Would like to use the accelerometer for this test, but
-                        * the orientation of the flight computer is unknown after
-                        * drogue deploy, so we ignore it. Could also detect
-                        * high descent rate using the pressure sensor to
-                        * recognize drogue deploy failure and eject the main
-                        * at that point. Perhaps also use the drogue sense lines
-                        * to notice continutity?
-                        */
-                       if (ao_height <= ao_config.main_deploy)
-                       {
-#if HAS_IGNITE
-                               ao_ignite(ao_igniter_main);
-#endif
-
-                               /*
-                                * Start recording min/max height
-                                * to figure out when the rocket has landed
-                                */
-
-                               /* initialize interval values */
-                               ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
-
-                               ao_interval_min_height = ao_interval_max_height = ao_avg_height;
-
-                               ao_flight_state = ao_flight_main;
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                       }
-                       break;
-
-                       /* fall through... */
-               case ao_flight_main:
-
-                       /* main to land:
-                        *
-                        * barometer: altitude stable
-                        */
-
-                       if (ao_avg_height < ao_interval_min_height)
-                               ao_interval_min_height = ao_avg_height;
-                       if (ao_avg_height > ao_interval_max_height)
-                               ao_interval_max_height = ao_avg_height;
-
-                       if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) {
-                               if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4))
-                               {
-                                       ao_flight_state = ao_flight_landed;
-
-                                       /* turn off the ADC capture */
-                                       ao_timer_set_adc_interval(0);
-
-                                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                               }
-                               ao_interval_min_height = ao_interval_max_height = ao_avg_height;
-                               ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
-                       }
-                       break;
-#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;
-               }
-       }
-}
-
-#if HAS_FLIGHT_DEBUG
-static inline int int_part(int16_t i)  { return i >> 4; }
-static inline int frac_part(int16_t i) { return ((i & 0xf) * 100 + 8) / 16; }
-
-static void
-ao_flight_dump(void)
-{
-#if HAS_ACCEL
-       int16_t accel;
-
-       accel = ((ao_config.accel_plus_g - ao_sample_accel) * ao_accel_scale) >> 16;
-#endif
-
-       printf ("sample:\n");
-       printf ("  tick        %d\n", ao_sample_tick);
-       printf ("  raw pres    %d\n", ao_sample_pres);
-#if HAS_ACCEL
-       printf ("  raw accel   %d\n", ao_sample_accel);
-#endif
-       printf ("  ground pres %d\n", ao_ground_pres);
-       printf ("  ground alt  %d\n", ao_ground_height);
-#if HAS_ACCEL
-       printf ("  raw accel   %d\n", ao_sample_accel);
-       printf ("  groundaccel %d\n", ao_ground_accel);
-       printf ("  accel_2g    %d\n", ao_accel_2g);
-#endif
-
-       printf ("  alt         %d\n", ao_sample_alt);
-       printf ("  height      %d\n", ao_sample_height);
-#if HAS_ACCEL
-       printf ("  accel       %d.%02d\n", int_part(accel), frac_part(accel));
-#endif
-
-
-       printf ("kalman:\n");
-       printf ("  height      %d\n", ao_height);
-       printf ("  speed       %d.%02d\n", int_part(ao_speed), frac_part(ao_speed));
-       printf ("  accel       %d.%02d\n", int_part(ao_accel), frac_part(ao_accel));
-       printf ("  max_height  %d\n", ao_max_height);
-       printf ("  avg_height  %d\n", ao_avg_height);
-       printf ("  error_h     %d\n", ao_error_h);
-       printf ("  error_avg   %d\n", ao_error_h_sq_avg);
-}
-
-static void
-ao_gyro_test(void)
-{
-       ao_flight_state = ao_flight_test;
-       ao_getchar();
-       ao_flight_state = ao_flight_idle;
-}
-
-uint8_t ao_orient_test;
-
-static void
-ao_orient_test_select(void)
-{
-       ao_orient_test = !ao_orient_test;
-}
-
-__code struct ao_cmds ao_flight_cmds[] = {
-       { ao_flight_dump,       "F\0Dump flight status" },
-       { ao_gyro_test,         "G\0Test gyro code" },
-       { ao_orient_test_select,"O\0Test orientation code" },
-       { 0, NULL },
-};
-#endif
-
-static __xdata struct ao_task  flight_task;
-
-void
-ao_flight_init(void)
-{
-       ao_flight_state = ao_flight_startup;
-#if HAS_FLIGHT_DEBUG
-       ao_cmd_register(&ao_flight_cmds[0]);
-#endif
-       ao_add_task(&flight_task, ao_flight, "flight");
-}
diff --git a/src/core/ao_flight.h b/src/core/ao_flight.h
deleted file mode 100644 (file)
index 01d21c1..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright © 2012 Keith Packard <keithp@keithp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef _AO_FLIGHT_H_
-#define _AO_FLIGHT_H_
-
-
-/*
- * ao_flight.c
- */
-
-enum ao_flight_state {
-       ao_flight_startup = 0,
-       ao_flight_idle = 1,
-       ao_flight_pad = 2,
-       ao_flight_boost = 3,
-       ao_flight_fast = 4,
-       ao_flight_coast = 5,
-       ao_flight_drogue = 6,
-       ao_flight_main = 7,
-       ao_flight_landed = 8,
-       ao_flight_invalid = 9,
-       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 || HAS_MMA655X
-#define HAS_SENSOR_ERRORS      1
-#endif
-
-#if HAS_SENSOR_ERRORS
-extern __xdata uint8_t                 ao_sensor_errors;
-#endif
-
-extern __pdata uint16_t                        ao_launch_time;
-extern __pdata uint8_t                 ao_flight_force_idle;
-
-/* Flight thread */
-void
-ao_flight(void);
-
-/* Initialize flight thread */
-void
-ao_flight_init(void);
-
-/*
- * ao_flight_nano.c
- */
-
-void
-ao_flight_nano_init(void);
-
-#endif /* _AO_FLIGHT_H_ */
diff --git a/src/core/ao_flight_nano.c b/src/core/ao_flight_nano.c
deleted file mode 100644 (file)
index 406d81a..0000000
+++ /dev/null
@@ -1,120 +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"
-
-/* Main flight thread. */
-
-__pdata enum ao_flight_state   ao_flight_state;        /* current flight state */
-__pdata uint16_t               ao_launch_tick;         /* time of launch detect */
-
-/*
- * track min/max data over a long interval to detect
- * resting
- */
-__pdata uint16_t               ao_interval_end;
-__pdata alt_t                  ao_interval_min_height;
-__pdata alt_t                  ao_interval_max_height;
-
-__pdata uint8_t                        ao_flight_force_idle;
-
-/* Landing is detected by getting constant readings from both pressure and accelerometer
- * for a fairly long time (AO_INTERVAL_TICKS)
- */
-#define AO_INTERVAL_TICKS      AO_SEC_TO_TICKS(5)
-
-static void
-ao_flight_nano(void)
-{
-       ao_sample_init();
-       ao_flight_state = ao_flight_startup;
-
-       for (;;) {
-               /*
-                * Process ADC samples, just looping
-                * until the sensors are calibrated.
-                */
-               if (!ao_sample())
-                       continue;
-
-               switch (ao_flight_state) {
-               case ao_flight_startup:
-                       if (ao_flight_force_idle) {
-                               /* Set idle mode */
-                               ao_flight_state = ao_flight_idle;
-                       } else {
-                               ao_flight_state = ao_flight_pad;
-                               /* Disable packet mode in pad state */
-                               ao_packet_slave_stop();
-
-                               /* Turn on telemetry system */
-                               ao_rdf_set(1);
-                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
-                       }
-                       /* signal successful initialization by turning off the LED */
-                       ao_led_off(AO_LED_RED);
-
-                       /* wakeup threads due to state change */
-                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                       break;
-               case ao_flight_pad:
-                       if (ao_height> AO_M_TO_HEIGHT(20)) {
-                               ao_flight_state = ao_flight_drogue;
-                               ao_launch_tick = ao_sample_tick;
-
-                               /* start logging data */
-                               ao_log_start();
-
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                       }
-                       break;
-               case ao_flight_drogue:
-                       /* drogue/main to land:
-                        *
-                        * barometer: altitude stable
-                        */
-
-                       if (ao_height < ao_interval_min_height)
-                               ao_interval_min_height = ao_height;
-                       if (ao_height > ao_interval_max_height)
-                               ao_interval_max_height = ao_height;
-
-                       if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) {
-                               if (ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5))
-                               {
-                                       ao_flight_state = ao_flight_landed;
-
-                                       /* turn off the ADC capture */
-                                       ao_timer_set_adc_interval(0);
-                                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                               }
-                               ao_interval_min_height = ao_interval_max_height = ao_height;
-                               ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
-                       }
-                       break;
-               }
-       }
-}
-
-static __xdata struct ao_task  flight_task;
-
-void
-ao_flight_nano_init(void)
-{
-       ao_flight_state = ao_flight_startup;
-       ao_add_task(&flight_task, ao_flight_nano, "flight");
-}
diff --git a/src/core/ao_freq.c b/src/core/ao_freq.c
deleted file mode 100644 (file)
index 12496f6..0000000
+++ /dev/null
@@ -1,55 +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>
-
-/*
- * The provided 'calibration' value is
- * that needed to tune the radio to precisely 434550kHz.
- * Use that to 'walk' to the target frequency by following
- * a 'bresenham' line from 434550kHz to the target
- * frequency, and updating the radio setting along the way
- */
-
-int32_t ao_freq_to_set(int32_t freq, int32_t cal) __reentrant
-{
-       static __pdata int32_t  set;
-       static __pdata uint8_t  neg;
-       static __pdata int32_t  error;
-
-       set = 0;
-       neg = 0;
-       error = -434550 / 2;
-
-       if ((freq -= 434550) < 0) {
-               neg = 1;
-               freq = -freq;
-       }
-       for (;;) {
-               if (error > 0) {
-                       error -= 434550;
-                       set++;
-               } else {
-                       error += cal;
-                       if (--freq < 0)
-                               break;
-               }
-       }
-       if (neg)
-               set = -set;
-       return cal + set;
-}
diff --git a/src/core/ao_gps_print.c b/src/core/ao_gps_print.c
deleted file mode 100644 (file)
index 47c945d..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AO_GPS_TEST
-#include "ao.h"
-#endif
-#include "ao_telem.h"
-
-void
-ao_gps_print(__xdata struct ao_gps_orig *gps_data) __reentrant
-{
-       char    state;
-
-       if (gps_data->flags & AO_GPS_VALID)
-               state = AO_TELEM_GPS_STATE_LOCKED;
-       else if (gps_data->flags & AO_GPS_RUNNING)
-               state = AO_TELEM_GPS_STATE_UNLOCKED;
-       else
-               state = AO_TELEM_GPS_STATE_ERROR;
-       printf(AO_TELEM_GPS_STATE " %c "
-              AO_TELEM_GPS_NUM_SAT " %d ",
-              state,
-              (gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);
-       if (!(gps_data->flags & AO_GPS_VALID))
-               return;
-       printf(AO_TELEM_GPS_LATITUDE " %ld "
-              AO_TELEM_GPS_LONGITUDE " %ld "
-              AO_TELEM_GPS_ALTITUDE " %d ",
-              (long) gps_data->latitude,
-              (long) gps_data->longitude,
-              gps_data->altitude);
-
-       if (gps_data->flags & AO_GPS_DATE_VALID)
-               printf(AO_TELEM_GPS_YEAR " %d "
-                      AO_TELEM_GPS_MONTH " %d "
-                      AO_TELEM_GPS_DAY " %d ",
-                      gps_data->year,
-                      gps_data->month,
-                      gps_data->day);
-
-       printf(AO_TELEM_GPS_HOUR " %d "
-              AO_TELEM_GPS_MINUTE " %d "
-              AO_TELEM_GPS_SECOND " %d ",
-              gps_data->hour,
-              gps_data->minute,
-              gps_data->second);
-
-       printf(AO_TELEM_GPS_HDOP " %d ",
-              gps_data->hdop * 2);
-
-       if (gps_data->flags & AO_GPS_COURSE_VALID) {
-               printf(AO_TELEM_GPS_HERROR " %d "
-                      AO_TELEM_GPS_VERROR " %d "
-                      AO_TELEM_GPS_VERTICAL_SPEED " %d "
-                      AO_TELEM_GPS_HORIZONTAL_SPEED " %d "
-                      AO_TELEM_GPS_COURSE " %d ",
-                      gps_data->h_error,
-                      gps_data->v_error,
-                      gps_data->climb_rate,
-                      gps_data->ground_speed,
-                      (int) gps_data->course * 2);
-       }
-}
-
-void
-ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data) __reentrant
-{
-       uint8_t c, n, v;
-       __xdata struct ao_gps_sat_orig  *sat;
-
-       n = gps_tracking_data->channels;
-       if (n == 0)
-               return;
-
-       sat = gps_tracking_data->sats;
-       v = 0;
-       for (c = 0; c < n; c++) {
-               if (sat->svid)
-                       v++;
-               sat++;
-       }
-
-       printf (AO_TELEM_SAT_NUM " %d ",
-               v);
-
-       sat = gps_tracking_data->sats;
-       v = 0;
-       for (c = 0; c < n; c++) {
-               if (sat->svid) {
-                       printf (AO_TELEM_SAT_SVID "%d %d "
-                               AO_TELEM_SAT_C_N_0 "%d %d ",
-                               v, sat->svid,
-                               v, sat->c_n_1);
-                       v++;
-               }
-               sat++;
-       }
-}
diff --git a/src/core/ao_gps_report.c b/src/core/ao_gps_report.c
deleted file mode 100644 (file)
index 07201ac..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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"
-
-void
-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 (;;) {
-               while ((new = ao_gps_new) == 0)
-                       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_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_TRACKING) {
-                       uint8_t c, n;
-
-                       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;
-
-void
-ao_gps_report_init(void)
-{
-       ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report");
-}
diff --git a/src/core/ao_gps_report_mega.c b/src/core/ao_gps_report_mega.c
deleted file mode 100644 (file)
index 5e3c71b..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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_mega(void)
-{
-       static __xdata struct ao_log_mega               gps_log;
-       static __xdata struct ao_telemetry_location     gps_data;
-       static __xdata struct ao_telemetry_satellite    gps_tracking_data;
-       uint8_t new;
-       uint8_t c, n, i;
-
-       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_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;
-                       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++;
-                                       if (i >= 12)
-                                               break;
-                               }
-                       gps_log.u.gps_sat.channels = i;
-                       ao_log_mega(&gps_log);
-               }
-       }
-}
-
-__xdata struct ao_task ao_gps_report_mega_task;
-
-void
-ao_gps_report_mega_init(void)
-{
-       ao_add_task(&ao_gps_report_mega_task,
-                   ao_gps_report_mega,
-                   "gps_report");
-}
diff --git a/src/core/ao_gps_report_metrum.c b/src/core/ao_gps_report_metrum.c
deleted file mode 100644 (file)
index 696a833..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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;
-       uint8_t svid;
-       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
deleted file mode 100644 (file)
index 3a05e35..0000000
+++ /dev/null
@@ -1,39 +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_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);
-}
diff --git a/src/core/ao_host.h b/src/core/ao_host.h
deleted file mode 100644 (file)
index 6eb752c..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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.
- */
-
-#define _GNU_SOURCE
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define AO_ADC_RING    64
-#define ao_adc_ring_next(n)    (((n) + 1) & (AO_ADC_RING - 1))
-#define ao_adc_ring_prev(n)    (((n) - 1) & (AO_ADC_RING - 1))
-
-/*
- * One set of samples read from the A/D converter
- */
-struct ao_adc {
-       uint16_t        tick;           /* tick when the sample was read */
-       int16_t         accel;          /* accelerometer */
-       int16_t         pres;           /* pressure sensor */
-       int16_t         temp;           /* temperature sensor */
-       int16_t         v_batt;         /* battery voltage */
-       int16_t         sense_d;        /* drogue continuity sense */
-       int16_t         sense_m;        /* main continuity sense */
-};
-
-#define __pdata
-#define __data
-#define __xdata
-#define __code
-#define __reentrant
-
-#define DATA_TO_XDATA(a)       (a)
-#define PDATA_TO_XDATA(a)      (a)
-#define CODE_TO_XDATA(a)       (a)
-
-enum ao_flight_state {
-       ao_flight_startup = 0,
-       ao_flight_idle = 1,
-       ao_flight_pad = 2,
-       ao_flight_boost = 3,
-       ao_flight_fast = 4,
-       ao_flight_coast = 5,
-       ao_flight_drogue = 6,
-       ao_flight_main = 7,
-       ao_flight_landed = 8,
-       ao_flight_invalid = 9
-};
-
-struct ao_adc ao_adc_ring[AO_ADC_RING];
-uint8_t ao_adc_head;
-
-#define ao_led_on(l)
-#define ao_led_off(l)
-#define ao_timer_set_adc_interval(i)
-#define ao_wakeup(wchan) ao_dump_state(wchan)
-#define ao_cmd_register(c)
-#define ao_usb_disable()
-#define ao_telemetry_set_interval(x)
-#define ao_delay(x)
-
-enum ao_igniter {
-       ao_igniter_drogue = 0,
-       ao_igniter_main = 1
-};
-
-void
-ao_ignite(enum ao_igniter igniter)
-{
-       printf ("ignite %s\n", igniter == ao_igniter_drogue ? "drogue" : "main");
-}
-
-struct ao_task {
-       int dummy;
-};
-
-#define ao_add_task(t,f,n)
-
-#define ao_log_start()
-#define ao_log_stop()
-
-#define AO_MS_TO_TICKS(ms)     ((ms) / 10)
-#define AO_SEC_TO_TICKS(s)     ((s) * 100)
-
-#define AO_FLIGHT_TEST
-
-struct ao_adc ao_adc_static;
-
-FILE *emulator_in;
-
-void
-ao_dump_state(void *wchan);
-
-void
-ao_sleep(void *wchan);
-
-const char const * const ao_state_names[] = {
-       "startup", "idle", "pad", "boost", "fast",
-       "coast", "drogue", "main", "landed", "invalid"
-};
-
-struct ao_cmds {
-       void            (*func)(void);
-       const char      *help;
-};
-
-
-struct ao_config {
-       uint16_t        main_deploy;
-       int16_t         accel_zero_g;
-};
-
-#define ao_config_get()
-
-struct ao_config ao_config = { 250, 16000 };
-
-#define ao_xmemcpy(d,s,c) memcpy(d,s,c)
-#define ao_xmemset(d,v,c) memset(d,v,c)
-#define ao_xmemcmp(d,s,c) memcmp(d,s,c)
diff --git a/src/core/ao_ignite.c b/src/core/ao_ignite.c
deleted file mode 100644 (file)
index 823d003..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * 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_data.h>
-#if AO_PYRO_NUM
-#include <ao_pyro.h>
-#endif
-
-#if HAS_IGNITE
-__xdata struct ao_ignition ao_ignition[2];
-
-void
-ao_ignite(enum ao_igniter igniter)
-{
-       ao_arch_block_interrupts();
-       ao_ignition[igniter].request = 1;
-       ao_wakeup(&ao_ignition);
-       ao_arch_release_interrupts();
-}
-
-#ifndef AO_SENSE_DROGUE
-#define AO_SENSE_DROGUE(p)     ((p)->adc.sense_d)
-#define AO_SENSE_MAIN(p)       ((p)->adc.sense_m)
-#endif
-
-enum ao_igniter_status
-ao_igniter_status(enum ao_igniter igniter)
-{
-       __xdata struct ao_data packet;
-       __pdata int16_t value;
-       __pdata uint8_t request, firing, fired;
-
-       ao_arch_critical(
-               ao_data_get(&packet);
-               request = ao_ignition[igniter].request;
-               fired = ao_ignition[igniter].fired;
-               firing = ao_ignition[igniter].firing;
-               );
-       if (firing || (request && !fired))
-               return ao_igniter_active;
-
-       value = (AO_IGNITER_CLOSED>>1);
-       switch (igniter) {
-       case ao_igniter_drogue:
-               value = AO_SENSE_DROGUE(&packet);
-               break;
-       case ao_igniter_main:
-               value = AO_SENSE_MAIN(&packet);
-               break;
-       }
-       if (value < AO_IGNITER_OPEN)
-               return ao_igniter_open;
-       else if (value > AO_IGNITER_CLOSED)
-               return ao_igniter_ready;
-       else
-               return ao_igniter_unknown;
-}
-
-#ifndef AO_IGNITER_SET_DROGUE
-#define AO_IGNITER_SET_DROGUE(v)       AO_IGNITER_DROGUE = (v)
-#define AO_IGNITER_SET_MAIN(v)         AO_IGNITER_MAIN = (v)
-#endif
-
-#ifndef AO_IGNITER_FIRE_TIME
-#define AO_IGNITER_FIRE_TIME           AO_MS_TO_TICKS(50)
-#endif
-
-#ifndef AO_IGNITER_CHARGE_TIME
-#define AO_IGNITER_CHARGE_TIME         AO_MS_TO_TICKS(2000)
-#endif
-
-void
-ao_igniter_fire(enum ao_igniter igniter)
-{
-       ao_ignition[igniter].firing = 1;
-       switch(ao_config.ignite_mode) {
-       case AO_IGNITE_MODE_DUAL:
-               switch (igniter) {
-               case ao_igniter_drogue:
-                       AO_IGNITER_SET_DROGUE(1);
-                       ao_delay(AO_IGNITER_FIRE_TIME);
-                       AO_IGNITER_SET_DROGUE(0);
-                       break;
-               case ao_igniter_main:
-                       AO_IGNITER_SET_MAIN(1);
-                       ao_delay(AO_IGNITER_FIRE_TIME);
-                       AO_IGNITER_SET_MAIN(0);
-                       break;
-               }
-               break;
-       case AO_IGNITE_MODE_APOGEE:
-               switch (igniter) {
-               case ao_igniter_drogue:
-                       AO_IGNITER_SET_DROGUE(1);
-                       ao_delay(AO_IGNITER_FIRE_TIME);
-                       AO_IGNITER_SET_DROGUE(0);
-                       ao_delay(AO_IGNITER_CHARGE_TIME);
-                       AO_IGNITER_SET_MAIN(1);
-                       ao_delay(AO_IGNITER_FIRE_TIME);
-                       AO_IGNITER_SET_MAIN(0);
-                       break;
-               default:
-                       break;
-               }
-               break;
-       case AO_IGNITE_MODE_MAIN:
-               switch (igniter) {
-               case ao_igniter_main:
-                       AO_IGNITER_SET_DROGUE(1);
-                       ao_delay(AO_IGNITER_FIRE_TIME);
-                       AO_IGNITER_SET_DROGUE(0);
-                       ao_delay(AO_IGNITER_CHARGE_TIME);
-                       AO_IGNITER_SET_MAIN(1);
-                       ao_delay(AO_IGNITER_FIRE_TIME);
-                       AO_IGNITER_SET_MAIN(0);
-                       break;
-               default:
-                       break;
-               }
-               break;
-       }
-       ao_ignition[igniter].firing = 0;
-}
-
-void
-ao_igniter(void)
-{
-       __xdata enum ao_igniter igniter;
-
-       ao_config_get();
-       for (;;) {
-               ao_sleep(&ao_ignition);
-               for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) {
-                       if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) {
-                               if (igniter == ao_igniter_drogue && ao_config.apogee_delay)
-                                       ao_delay(AO_SEC_TO_TICKS(ao_config.apogee_delay));
-
-                               ao_igniter_fire(igniter);
-                               ao_delay(AO_IGNITER_CHARGE_TIME);
-                               ao_ignition[igniter].fired = 1;
-                       }
-               }
-       }
-}
-
-#endif
-
-void
-ao_ignite_manual(void)
-{
-       ao_cmd_white();
-       if (!ao_match_word("DoIt"))
-               return;
-       ao_cmd_white();
-#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;
-}
-
-__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,
-              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[] = {
-       { ao_ignite_manual,     "i <key> {main|drogue}\0Fire igniter. <key> is doit with D&I" },
-       { ao_ignite_test,       "t\0Test igniter" },
-       { 0,    NULL },
-};
-
-#if HAS_IGNITE
-__xdata struct ao_task ao_igniter_task;
-
-void
-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_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
deleted file mode 100644 (file)
index aa23dbe..0000000
+++ /dev/null
@@ -1,158 +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_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
deleted file mode 100644 (file)
index b16db58..0000000
+++ /dev/null
@@ -1,48 +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_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_ */
diff --git a/src/core/ao_kalman.c b/src/core/ao_kalman.c
deleted file mode 100644 (file)
index 9aea1f1..0000000
+++ /dev/null
@@ -1,295 +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.
- */
-
-#ifndef AO_FLIGHT_TEST
-#include "ao.h"
-#include "ao_flight.h"
-#endif
-
-#include "ao_sample.h"
-#include "ao_kalman.h"
-
-
-static __pdata int32_t         ao_k_height;
-static __pdata int32_t         ao_k_speed;
-static __pdata int32_t         ao_k_accel;
-
-#define AO_K_STEP_100          to_fix16(0.01)
-#define AO_K_STEP_2_2_100      to_fix16(0.00005)
-
-#define AO_K_STEP_10           to_fix16(0.1)
-#define AO_K_STEP_2_2_10       to_fix16(0.005)
-
-#define AO_K_STEP_1            to_fix16(1)
-#define AO_K_STEP_2_2_1                to_fix16(0.5)
-
-__pdata int16_t                        ao_height;
-__pdata int16_t                        ao_speed;
-__pdata int16_t                        ao_accel;
-__xdata int16_t                        ao_max_height;
-static __pdata int32_t         ao_avg_height_scaled;
-__xdata int16_t                        ao_avg_height;
-
-__pdata int16_t                        ao_error_h;
-__pdata int16_t                        ao_error_h_sq_avg;
-
-#if HAS_ACCEL
-__pdata int16_t                        ao_error_a;
-#endif
-
-static void
-ao_kalman_predict(void)
-{
-#ifdef AO_FLIGHT_TEST
-       if (ao_sample_tick - ao_sample_prev_tick > 50) {
-               ao_k_height += ((int32_t) ao_speed * AO_K_STEP_1 +
-                               (int32_t) ao_accel * AO_K_STEP_2_2_1) >> 4;
-               ao_k_speed += (int32_t) ao_accel * AO_K_STEP_1;
-
-               return;
-       }
-       if (ao_sample_tick - ao_sample_prev_tick > 5) {
-               ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 +
-                               (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4;
-               ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10;
-
-               return;
-       }
-       if (ao_flight_debug) {
-               printf ("predict speed %g + (%g * %g) = %g\n",
-                       ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0,
-                       (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0));
-       }
-#endif
-       ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 +
-                       (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4;
-       ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100;
-}
-
-static void
-ao_kalman_err_height(void)
-{
-       int16_t e;
-       int16_t height_distrust;
-#if HAS_ACCEL
-       int16_t speed_distrust;
-#endif
-
-       ao_error_h = ao_sample_height - (int16_t) (ao_k_height >> 16);
-
-       e = ao_error_h;
-       if (e < 0)
-               e = -e;
-       if (e > 127)
-               e = 127;
-#if HAS_ACCEL
-       ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2;
-       ao_error_h_sq_avg += (e * e) >> 2;
-#else
-       ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4;
-       ao_error_h_sq_avg += (e * e) >> 4;
-#endif
-
-       if (ao_flight_state >= ao_flight_drogue)
-               return;
-       height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT;
-#if HAS_ACCEL
-       /* speed is stored * 16, but we need to ramp between 200 and 328, so
-        * we want to multiply by 2. The result is a shift by 3.
-        */
-       speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1);
-       if (speed_distrust <= 0)
-               speed_distrust = 0;
-       else if (speed_distrust > height_distrust)
-               height_distrust = speed_distrust;
-#endif
-       if (height_distrust > 0) {
-#ifdef AO_FLIGHT_TEST
-               int     old_ao_error_h = ao_error_h;
-#endif
-               if (height_distrust > 0x100)
-                       height_distrust = 0x100;
-               ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8);
-#ifdef AO_FLIGHT_TEST
-               if (ao_flight_debug) {
-                       printf("over height %g over speed %g distrust: %g height: error %d -> %d\n",
-                              (double) (ao_sample_alt - AO_MAX_BARO_HEIGHT),
-                              (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0,
-                              height_distrust / 256.0,
-                              old_ao_error_h, ao_error_h);
-               }
-#endif
-       }
-}
-
-static void
-ao_kalman_correct_baro(void)
-{
-       ao_kalman_err_height();
-#ifdef AO_FLIGHT_TEST
-       if (ao_sample_tick - ao_sample_prev_tick > 50) {
-               ao_k_height += (int32_t) AO_BARO_K0_1 * ao_error_h;
-               ao_k_speed  += (int32_t) AO_BARO_K1_1 * ao_error_h;
-               ao_k_accel  += (int32_t) AO_BARO_K2_1 * ao_error_h;
-               return;
-       }
-       if (ao_sample_tick - ao_sample_prev_tick > 5) {
-               ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h;
-               ao_k_speed  += (int32_t) AO_BARO_K1_10 * ao_error_h;
-               ao_k_accel  += (int32_t) AO_BARO_K2_10 * ao_error_h;
-               return;
-       }
-#endif
-       ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h;
-       ao_k_speed  += (int32_t) AO_BARO_K1_100 * ao_error_h;
-       ao_k_accel  += (int32_t) AO_BARO_K2_100 * ao_error_h;
-}
-
-#if HAS_ACCEL
-
-static void
-ao_kalman_err_accel(void)
-{
-       int32_t accel;
-
-       accel = (ao_config.accel_plus_g - ao_sample_accel) * ao_accel_scale;
-
-       /* Can't use ao_accel here as it is the pre-prediction value still */
-       ao_error_a = (accel - ao_k_accel) >> 16;
-}
-
-#ifndef FORCE_ACCEL
-static void
-ao_kalman_correct_both(void)
-{
-       ao_kalman_err_height();
-       ao_kalman_err_accel();
-
-#ifdef AO_FLIGHT_TEST
-       if (ao_sample_tick - ao_sample_prev_tick > 50) {
-               if (ao_flight_debug) {
-                       printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
-                               ao_k_speed / (65536.0 * 16.0),
-                               (double) ao_error_h, AO_BOTH_K10_1 / 65536.0,
-                               (double) ao_error_a, AO_BOTH_K11_1 / 65536.0,
-                               (ao_k_speed +
-                                (int32_t) AO_BOTH_K10_1 * ao_error_h +
-                                (int32_t) AO_BOTH_K11_1 * ao_error_a) / (65536.0 * 16.0));
-               }
-               ao_k_height +=
-                       (int32_t) AO_BOTH_K00_1 * ao_error_h +
-                       (int32_t) AO_BOTH_K01_1 * ao_error_a;
-               ao_k_speed +=
-                       (int32_t) AO_BOTH_K10_1 * ao_error_h +
-                       (int32_t) AO_BOTH_K11_1 * ao_error_a;
-               ao_k_accel +=
-                       (int32_t) AO_BOTH_K20_1 * ao_error_h +
-                       (int32_t) AO_BOTH_K21_1 * ao_error_a;
-               return;
-       }
-       if (ao_sample_tick - ao_sample_prev_tick > 5) {
-               if (ao_flight_debug) {
-                       printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
-                               ao_k_speed / (65536.0 * 16.0),
-                               (double) ao_error_h, AO_BOTH_K10_10 / 65536.0,
-                               (double) ao_error_a, AO_BOTH_K11_10 / 65536.0,
-                               (ao_k_speed +
-                                (int32_t) AO_BOTH_K10_10 * ao_error_h +
-                                (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0));
-               }
-               ao_k_height +=
-                       (int32_t) AO_BOTH_K00_10 * ao_error_h +
-                       (int32_t) AO_BOTH_K01_10 * ao_error_a;
-               ao_k_speed +=
-                       (int32_t) AO_BOTH_K10_10 * ao_error_h +
-                       (int32_t) AO_BOTH_K11_10 * ao_error_a;
-               ao_k_accel +=
-                       (int32_t) AO_BOTH_K20_10 * ao_error_h +
-                       (int32_t) AO_BOTH_K21_10 * ao_error_a;
-               return;
-       }
-       if (ao_flight_debug) {
-               printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
-                       ao_k_speed / (65536.0 * 16.0),
-                       (double) ao_error_h, AO_BOTH_K10_100 / 65536.0,
-                       (double) ao_error_a, AO_BOTH_K11_100 / 65536.0,
-                       (ao_k_speed +
-                        (int32_t) AO_BOTH_K10_100 * ao_error_h +
-                        (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0));
-       }
-#endif
-       ao_k_height +=
-               (int32_t) AO_BOTH_K00_100 * ao_error_h +
-               (int32_t) AO_BOTH_K01_100 * ao_error_a;
-       ao_k_speed +=
-               (int32_t) AO_BOTH_K10_100 * ao_error_h +
-               (int32_t) AO_BOTH_K11_100 * ao_error_a;
-       ao_k_accel +=
-               (int32_t) AO_BOTH_K20_100 * ao_error_h +
-               (int32_t) AO_BOTH_K21_100 * ao_error_a;
-}
-
-#else
-
-static void
-ao_kalman_correct_accel(void)
-{
-       ao_kalman_err_accel();
-
-       if (ao_sample_tick - ao_sample_prev_tick > 5) {
-               ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a;
-               ao_k_speed  += (int32_t) AO_ACCEL_K1_10 * ao_error_a;
-               ao_k_accel  += (int32_t) AO_ACCEL_K2_10 * ao_error_a;
-               return;
-       }
-       ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a;
-       ao_k_speed  += (int32_t) AO_ACCEL_K1_100 * ao_error_a;
-       ao_k_accel  += (int32_t) AO_ACCEL_K2_100 * ao_error_a;
-}
-
-#endif /* else FORCE_ACCEL */
-#endif /* HAS_ACCEL */
-
-void
-ao_kalman(void)
-{
-       ao_kalman_predict();
-#if HAS_ACCEL
-       if (ao_flight_state <= ao_flight_coast) {
-#ifdef FORCE_ACCEL
-               ao_kalman_correct_accel();
-#else
-               ao_kalman_correct_both();
-#endif
-       } else
-#endif
-               ao_kalman_correct_baro();
-       ao_height = from_fix(ao_k_height);
-       ao_speed = from_fix(ao_k_speed);
-       ao_accel = from_fix(ao_k_accel);
-       if (ao_height > ao_max_height)
-               ao_max_height = ao_height;
-       ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height;
-#ifdef AO_FLIGHT_TEST
-       if (ao_sample_tick - ao_sample_prev_tick > 50)
-               ao_avg_height = (ao_avg_height_scaled + 1) >> 1;
-       else if (ao_sample_tick - ao_sample_prev_tick > 5)
-               ao_avg_height = (ao_avg_height_scaled + 7) >> 4;
-       else 
-#endif
-               ao_avg_height = (ao_avg_height_scaled + 63) >> 7;
-}
diff --git a/src/core/ao_lcd.h b/src/core/ao_lcd.h
deleted file mode 100644 (file)
index f7e1391..0000000
+++ /dev/null
@@ -1,60 +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_LCD_H_
-#define _AO_LCD_H_
-
-/* ao_lcd.c */
-  
-void
-ao_lcd_putchar(uint8_t d);
-
-void
-ao_lcd_putstring(char *string);
-
-void
-ao_lcd_contrast_set(uint8_t contrast);
-
-void
-ao_lcd_clear(void);
-
-void
-ao_lcd_cursor_on(void);
-
-void
-ao_lcd_cursor_off(void);
-
-#define AO_LCD_ADDR(row,col)   ((row << 6) | (col))
-
-void
-ao_lcd_goto(uint8_t addr);
-
-void
-ao_lcd_start(void);
-
-void
-ao_lcd_init(void);
-
-/* ao_lcd_port.c */
-
-void
-ao_lcd_port_put_nibble(uint8_t rs, uint8_t d);
-
-void
-ao_lcd_port_init(void);
-
-#endif /* _AO_LCD_H_ */
diff --git a/src/core/ao_led.h b/src/core/ao_led.h
deleted file mode 100644 (file)
index d9a0914..0000000
+++ /dev/null
@@ -1,59 +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_LED_H_
-#define _AO_LED_H_
-
-/*
- * ao_led.c
- */
-
-#define AO_LED_NONE    0
-
-#ifndef AO_LED_TYPE
-#define AO_LED_TYPE uint8_t
-#endif
-
-/* Turn on the specified LEDs */
-void
-ao_led_on(AO_LED_TYPE colors);
-
-/* Turn off the specified LEDs */
-void
-ao_led_off(AO_LED_TYPE colors);
-
-/* Set all of the LEDs to the specified state */
-void
-ao_led_set(AO_LED_TYPE colors);
-
-/* Set all LEDs in 'mask' to the specified state */
-void
-ao_led_set_mask(uint8_t colors, uint8_t mask);
-
-/* Toggle the specified LEDs */
-void
-ao_led_toggle(AO_LED_TYPE colors);
-
-/* Turn on the specified LEDs for the indicated interval */
-void
-ao_led_for(AO_LED_TYPE colors, uint16_t ticks) __reentrant;
-
-/* Initialize the LEDs */
-void
-ao_led_init(AO_LED_TYPE enable);
-
-#endif /* _AO_LED_H_ */
diff --git a/src/core/ao_list.h b/src/core/ao_list.h
deleted file mode 100644 (file)
index 8a6fa4d..0000000
+++ /dev/null
@@ -1,213 +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_LIST_H_
-#define _AO_LIST_H_
-
-#include <stddef.h>
-
-struct ao_list {
-       struct ao_list  *next, *prev;
-};
-
-static inline void
-ao_list_init(struct ao_list *list)
-{
-       list->next = list->prev = list;
-}
-
-static inline void
-__ao_list_add(struct ao_list *list, struct ao_list *prev, struct ao_list *next)
-{
-       next->prev = list;
-       list->next = next;
-       list->prev = prev;
-       prev->next = list;
-}
-
-/**
- * Insert a new element after the given list head. The new element does not
- * need to be initialised as empty list.
- * The list changes from:
- *      head → some element → ...
- * to
- *      head → new element → older element → ...
- *
- * Example:
- * struct foo *newfoo = malloc(...);
- * ao_list_add(&newfoo->entry, &bar->list_of_foos);
- *
- * @param entry The new element to prepend to the list.
- * @param head The existing list.
- */
-static inline void
-ao_list_insert(struct ao_list *entry, struct ao_list *head)
-{
-    __ao_list_add(entry, head, head->next);
-}
-
-/**
- * Append a new element to the end of the list given with this list head.
- *
- * The list changes from:
- *      head → some element → ... → lastelement
- * to
- *      head → some element → ... → lastelement → new element
- *
- * Example:
- * struct foo *newfoo = malloc(...);
- * ao_list_append(&newfoo->entry, &bar->list_of_foos);
- *
- * @param entry The new element to prepend to the list.
- * @param head The existing list.
- */
-static inline void
-ao_list_append(struct ao_list *entry, struct ao_list *head)
-{
-    __ao_list_add(entry, head->prev, head);
-}
-
-static inline void
-__ao_list_del(struct ao_list *prev, struct ao_list *next)
-{
-    next->prev = prev;
-    prev->next = next;
-}
-
-/**
- * Remove the element from the list it is in. Using this function will reset
- * the pointers to/from this element so it is removed from the list. It does
- * NOT free the element itself or manipulate it otherwise.
- *
- * Using ao_list_del on a pure list head (like in the example at the top of
- * this file) will NOT remove the first element from
- * the list but rather reset the list as empty list.
- *
- * Example:
- * ao_list_del(&foo->entry);
- *
- * @param entry The element to remove.
- */
-static inline void
-ao_list_del(struct ao_list *entry)
-{
-    __ao_list_del(entry->prev, entry->next);
-    ao_list_init(entry);
-}
-
-/**
- * Check if the list is empty.
- *
- * Example:
- * ao_list_is_empty(&bar->list_of_foos);
- *
- * @return True if the list contains one or more elements or False otherwise.
- */
-static inline uint8_t
-ao_list_is_empty(struct ao_list *head)
-{
-    return head->next == head;
-}
-
-/**
- * Returns a pointer to the container of this list element.
- *
- * Example:
- * struct foo* f;
- * f = container_of(&foo->entry, struct foo, entry);
- * assert(f == foo);
- *
- * @param ptr Pointer to the struct ao_list.
- * @param type Data type of the list element.
- * @param member Member name of the struct ao_list field in the list element.
- * @return A pointer to the data struct containing the list head.
- */
-#define ao_container_of(ptr, type, member) \
-       ((type *)((char *)(ptr) - offsetof(type, member)))
-
-/**
- * Alias of ao_container_of
- */
-#define ao_list_entry(ptr, type, member) \
-    ao_container_of(ptr, type, member)
-
-/**
- * Retrieve the first list entry for the given list pointer.
- *
- * Example:
- * struct foo *first;
- * first = ao_list_first_entry(&bar->list_of_foos, struct foo, list_of_foos);
- *
- * @param ptr The list head
- * @param type Data type of the list element to retrieve
- * @param member Member name of the struct ao_list field in the list element.
- * @return A pointer to the first list element.
- */
-#define ao_list_first_entry(ptr, type, member) \
-    ao_list_entry((ptr)->next, type, member)
-
-/**
- * Retrieve the last list entry for the given listpointer.
- *
- * Example:
- * struct foo *first;
- * first = ao_list_last_entry(&bar->list_of_foos, struct foo, list_of_foos);
- *
- * @param ptr The list head
- * @param type Data type of the list element to retrieve
- * @param member Member name of the struct ao_list field in the list element.
- * @return A pointer to the last list element.
- */
-#define ao_list_last_entry(ptr, type, member) \
-    ao_list_entry((ptr)->prev, type, member)
-
-/**
- * Loop through the list given by head and set pos to struct in the list.
- *
- * Example:
- * struct foo *iterator;
- * ao_list_for_each_entry(iterator, &bar->list_of_foos, entry) {
- *      [modify iterator]
- * }
- *
- * This macro is not safe for node deletion. Use ao_list_for_each_entry_safe
- * instead.
- *
- * @param pos Iterator variable of the type of the list elements.
- * @param head List head
- * @param member Member name of the struct ao_list in the list elements.
- *
- */
-#define ao_list_for_each_entry(pos, head, type, member)                        \
-    for (pos = ao_container_of((head)->next, type, member);            \
-        &pos->member != (head);                                        \
-        pos = ao_container_of(pos->member.next, type, member))
-
-/**
- * Loop through the list, keeping a backup pointer to the element. This
- * macro allows for the deletion of a list element while looping through the
- * list.
- *
- * See ao_list_for_each_entry for more details.
- */
-#define ao_list_for_each_entry_safe(pos, tmp, head, type, member)              \
-       for ((pos = ao_container_of((head)->next, type, member)),               \
-            (tmp = ao_container_of(pos->member.next, type, member));           \
-            &pos->member != (head);                                            \
-            (pos = tmp), (tmp = ao_container_of(pos->member.next, type, member)))
-
-#endif /* _AO_LIST_H_ */
diff --git a/src/core/ao_log.c b/src/core/ao_log.c
deleted file mode 100644 (file)
index 20febef..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * 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>
-#include <ao_config.h>
-
-__pdata uint32_t ao_log_current_pos;
-__pdata uint32_t ao_log_end_pos;
-__pdata uint32_t ao_log_start_pos;
-__xdata uint8_t        ao_log_running;
-__pdata enum ao_flight_state ao_log_state;
-__xdata uint16_t ao_flight_number;
-
-void
-ao_log_flush(void)
-{
-       ao_storage_flush();
-}
-
-/*
- * When erasing a flight log, make sure the config block
- * has an up-to-date version of the current flight number
- */
-
-struct ao_log_erase {
-       uint8_t unused;
-       uint16_t flight;
-};
-
-static __xdata struct ao_log_erase erase;
-
-#define LOG_MAX_ERASE  16
-
-static uint32_t
-ao_log_erase_pos(uint8_t i)
-{
-       return i * sizeof (struct ao_log_erase) + AO_CONFIG_MAX_SIZE;
-}
-
-void
-ao_log_write_erase(uint8_t pos)
-{
-       erase.unused = 0x00;
-       erase.flight = ao_flight_number;
-       ao_config_write(ao_log_erase_pos(pos),  &erase, sizeof (erase));
-       ao_config_flush();
-}
-
-static void
-ao_log_read_erase(uint8_t pos)
-{
-       ao_config_read(ao_log_erase_pos(pos), &erase, sizeof (erase));
-}
-
-
-static void
-ao_log_erase_mark(void)
-{
-       uint8_t                         i;
-
-       for (i = 0; i < LOG_MAX_ERASE; i++) {
-               ao_log_read_erase(i);
-               if (erase.unused == 0 && erase.flight == ao_flight_number)
-                       return;
-               if (erase.unused == 0xff) {
-                       ao_log_write_erase(i);
-                       return;
-               }
-       }
-       ao_config_put();
-}
-
-static uint8_t
-ao_log_slots()
-{
-       return (uint8_t) (ao_storage_log_max / ao_config.flight_log_max);
-}
-
-uint32_t
-ao_log_pos(uint8_t slot)
-{
-       return ((slot) * ao_config.flight_log_max);
-}
-
-static uint16_t
-ao_log_max_flight(void)
-{
-       uint8_t         log_slot;
-       uint8_t         log_slots;
-       uint16_t        log_flight;
-       uint16_t        max_flight = 0;
-
-       /* Scan the log space looking for the biggest flight number */
-       log_slots = ao_log_slots();
-       for (log_slot = 0; log_slot < log_slots; log_slot++) {
-               log_flight = ao_log_flight(log_slot);
-               if (!log_flight)
-                       continue;
-               if (max_flight == 0 || (int16_t) (log_flight - max_flight) > 0)
-                       max_flight = log_flight;
-       }
-       return max_flight;
-}
-
-void
-ao_log_scan(void) __reentrant
-{
-       uint8_t         log_slot;
-       uint8_t         log_slots;
-       uint8_t         log_want;
-
-       ao_config_get();
-
-       ao_flight_number = ao_log_max_flight();
-       if (ao_flight_number)
-               if (++ao_flight_number == 0)
-                       ao_flight_number = 1;
-
-       /* Now look through the log of flight numbers from erase operations and
-        * see if the last one is bigger than what we found above
-        */
-       for (log_slot = LOG_MAX_ERASE; log_slot-- > 0;) {
-               ao_log_read_erase(log_slot);
-               if (erase.unused == 0) {
-                       if (ao_flight_number == 0 ||
-                           (int16_t) (erase.flight - ao_flight_number) > 0)
-                               ao_flight_number = erase.flight;
-                       break;
-               }
-       }
-       if (ao_flight_number == 0)
-               ao_flight_number = 1;
-
-       /* With a flight number in hand, find a place to write a new log,
-        * use the target flight number to index the available log slots so
-        * that we write logs to each spot about the same number of times.
-        */
-
-       /* Find a log slot for the next flight, if available */
-       ao_log_current_pos = ao_log_end_pos = 0;
-       log_slots = ao_log_slots();
-       log_want = (ao_flight_number - 1) % log_slots;
-       log_slot = log_want;
-       do {
-               if (ao_log_flight(log_slot) == 0) {
-                       ao_log_current_pos = ao_log_pos(log_slot);
-                       ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max;
-                       break;
-               }
-               if (++log_slot >= log_slots)
-                       log_slot = 0;
-       } while (log_slot != log_want);
-
-       ao_wakeup(&ao_flight_number);
-}
-
-void
-ao_log_start(void)
-{
-       /* start logging */
-       ao_log_running = 1;
-       ao_wakeup(&ao_log_running);
-}
-
-void
-ao_log_stop(void)
-{
-       ao_log_running = 0;
-       ao_log_flush();
-}
-
-uint8_t
-ao_log_present(void)
-{
-       return ao_log_max_flight() != 0;
-}
-
-uint8_t
-ao_log_full(void)
-{
-       return ao_log_current_pos == ao_log_end_pos;
-}
-
-#if HAS_ADC
-static __xdata struct ao_task ao_log_task;
-#endif
-
-void
-ao_log_list(void) __reentrant
-{
-       uint8_t slot;
-       uint8_t slots;
-       uint16_t flight;
-
-       slots = ao_log_slots();
-       for (slot = 0; slot < slots; slot++)
-       {
-               flight = ao_log_flight(slot);
-               if (flight)
-                       printf ("flight %d start %x end %x\n",
-                               flight,
-                               (uint16_t) (ao_log_pos(slot) >> 8),
-                               (uint16_t) (ao_log_pos(slot+1) >> 8));
-       }
-       printf ("done\n");
-}
-
-void
-ao_log_delete(void) __reentrant
-{
-       uint8_t slot;
-       uint8_t slots;
-
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-
-       slots = ao_log_slots();
-       /* Look for the flight log matching the requested flight */
-       if (ao_cmd_lex_i) {
-               for (slot = 0; slot < slots; slot++) {
-                       if (ao_log_flight(slot) == ao_cmd_lex_i) {
-                               ao_log_erase_mark();
-                               ao_log_current_pos = ao_log_pos(slot);
-                               ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max;
-                               while (ao_log_current_pos < ao_log_end_pos) {
-                                       uint8_t i;
-                                       static __xdata uint8_t b;
-
-                                       /*
-                                        * Check to see if we've reached the end of
-                                        * the used memory to avoid re-erasing the same
-                                        * memory over and over again
-                                        */
-                                       for (i = 0; i < 16; i++) {
-                                               if (ao_storage_read(ao_log_current_pos + i, &b, 1))
-                                                       if (b != 0xff)
-                                                               break;
-                                       }
-                                       if (i == 16)
-                                               break;
-                                       ao_storage_erase(ao_log_current_pos);
-                                       ao_log_current_pos += ao_storage_block;
-                               }
-                               puts("Erased");
-                               return;
-                       }
-               }
-       }
-       printf("No such flight: %d\n", ao_cmd_lex_i);
-}
-
-__code struct ao_cmds ao_log_cmds[] = {
-       { ao_log_list,  "l\0List logs" },
-       { ao_log_delete,        "d <flight-number>\0Delete flight" },
-       { 0,    NULL },
-};
-
-void
-ao_log_init(void)
-{
-       ao_log_running = 0;
-
-       /* For now, just log the flight starting at the begining of eeprom */
-       ao_log_state = ao_flight_invalid;
-
-       ao_cmd_register(&ao_log_cmds[0]);
-
-#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
-}
diff --git a/src/core/ao_log.h b/src/core/ao_log.h
deleted file mode 100644 (file)
index 09f3118..0000000
+++ /dev/null
@@ -1,386 +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_H_
-#define _AO_LOG_H_
-
-#include <ao_flight.h>
-
-/*
- * ao_log.c
- */
-
-/* We record flight numbers in the first record of
- * the log. Tasks may wait for this to be initialized
- * by sleeping on this variable.
- */
-extern __xdata uint16_t ao_flight_number;
-
-extern __pdata uint32_t ao_log_current_pos;
-extern __pdata uint32_t ao_log_end_pos;
-extern __pdata uint32_t ao_log_start_pos;
-extern __xdata uint8_t ao_log_running;
-extern __pdata enum ao_flight_state ao_log_state;
-
-/* required functions from the underlying log system */
-
-#define AO_LOG_FORMAT_UNKNOWN          0       /* unknown; altosui will have to guess */
-#define AO_LOG_FORMAT_FULL             1       /* 8 byte typed log records */
-#define AO_LOG_FORMAT_TINY             2       /* two byte state/baro records */
-#define AO_LOG_FORMAT_TELEMETRY                3       /* 32 byte ao_telemetry records */
-#define AO_LOG_FORMAT_TELESCIENCE      4       /* 32 byte typed telescience records */
-#define AO_LOG_FORMAT_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;
-
-/* Return the flight number from the given log slot, 0 if none */
-uint16_t
-ao_log_flight(uint8_t slot);
-
-/* Flush the log */
-void
-ao_log_flush(void);
-
-/* Logging thread main routine */
-void
-ao_log(void);
-
-/* functions provided in ao_log.c */
-
-/* Figure out the current flight number */
-void
-ao_log_scan(void) __reentrant;
-
-/* Return the position of the start of the given log slot */
-uint32_t
-ao_log_pos(uint8_t slot);
-
-/* Start logging to eeprom */
-void
-ao_log_start(void);
-
-/* Stop logging */
-void
-ao_log_stop(void);
-
-/* Initialize the logging system */
-void
-ao_log_init(void);
-
-/* Write out the current flight number to the erase log */
-void
-ao_log_write_erase(uint8_t pos);
-
-/* Returns true if there are any logs stored in eeprom */
-uint8_t
-ao_log_present(void);
-
-/* Returns true if there is no more storage space available */
-uint8_t
-ao_log_full(void);
-
-/*
- * ao_log_big.c
- */
-
-/*
- * The data log is recorded in the eeprom as a sequence
- * of data packets.
- *
- * Each packet starts with a 4-byte header that has the
- * packet type, the packet checksum and the tick count. Then
- * they all contain 2 16 bit values which hold packet-specific
- * data.
- *
- * For each flight, the first packet
- * is FLIGHT packet, indicating the serial number of the
- * device and a unique number marking the number of flights
- * recorded by this device.
- *
- * During flight, data from the accelerometer and barometer
- * are recorded in SENSOR packets, using the raw 16-bit values
- * read from the A/D converter.
- *
- * Also during flight, but at a lower rate, the deployment
- * sensors are recorded in DEPLOY packets. The goal here is to
- * detect failure in the deployment circuits.
- *
- * STATE packets hold state transitions as the flight computer
- * transitions through different stages of the flight.
- */
-#define AO_LOG_FLIGHT          'F'
-#define AO_LOG_SENSOR          'A'
-#define AO_LOG_TEMP_VOLT       'T'
-#define AO_LOG_DEPLOY          'D'
-#define AO_LOG_STATE           'S'
-#define AO_LOG_GPS_TIME                'G'
-#define AO_LOG_GPS_LAT         'N'
-#define AO_LOG_GPS_LON         'W'
-#define AO_LOG_GPS_ALT         'H'
-#define AO_LOG_GPS_SAT         'V'
-#define AO_LOG_GPS_DATE                'Y'
-#define AO_LOG_GPS_POS         'P'
-
-#define AO_LOG_POS_NONE                (~0UL)
-
-struct ao_log_record {
-       char                    type;                           /* 0 */
-       uint8_t                 csum;                           /* 1 */
-       uint16_t                tick;                           /* 2 */
-       union {
-               struct {
-                       int16_t         ground_accel;           /* 4 */
-                       uint16_t        flight;                 /* 6 */
-               } flight;
-               struct {
-                       int16_t         accel;                  /* 4 */
-                       int16_t         pres;                   /* 6 */
-               } sensor;
-               struct {
-                       int16_t         temp;
-                       int16_t         v_batt;
-               } temp_volt;
-               struct {
-                       int16_t         drogue;
-                       int16_t         main;
-               } deploy;
-               struct {
-                       uint16_t        state;
-                       uint16_t        reason;
-               } state;
-               struct {
-                       uint8_t         hour;
-                       uint8_t         minute;
-                       uint8_t         second;
-                       uint8_t         flags;
-               } gps_time;
-               int32_t         gps_latitude;
-               int32_t         gps_longitude;
-               struct {
-                       int16_t         altitude;
-                       uint16_t        unused;
-               } gps_altitude;
-               struct {
-                       uint16_t        svid;
-                       uint8_t         unused;
-                       uint8_t         c_n;
-               } gps_sat;
-               struct {
-                       uint8_t         year;
-                       uint8_t         month;
-                       uint8_t         day;
-                       uint8_t         extra;
-               } gps_date;
-               struct {
-                       uint16_t        d0;
-                       uint16_t        d1;
-               } anon;
-       } u;
-};
-
-struct ao_log_mega {
-       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 */
-                       int16_t         ground_accel_along;     /* 16 */
-                       int16_t         ground_accel_across;    /* 12 */
-                       int16_t         ground_accel_through;   /* 14 */
-                       int16_t         ground_roll;            /* 18 */
-                       int16_t         ground_pitch;           /* 20 */
-                       int16_t         ground_yaw;             /* 22 */
-               } flight;                                       /* 24 */
-               /* AO_LOG_STATE */
-               struct {
-                       uint16_t        state;
-                       uint16_t        reason;
-               } state;
-               /* AO_LOG_SENSOR */
-               struct {
-                       uint32_t        pres;           /* 4 */
-                       uint32_t        temp;           /* 8 */
-                       int16_t         accel_x;        /* 12 */
-                       int16_t         accel_y;        /* 14 */
-                       int16_t         accel_z;        /* 16 */
-                       int16_t         gyro_x;         /* 18 */
-                       int16_t         gyro_y;         /* 20 */
-                       int16_t         gyro_z;         /* 22 */
-                       int16_t         mag_x;          /* 24 */
-                       int16_t         mag_y;          /* 26 */
-                       int16_t         mag_z;          /* 28 */
-                       int16_t         accel;          /* 30 */
-               } sensor;       /* 32 */
-               /* AO_LOG_TEMP_VOLT */
-               struct {
-                       int16_t         v_batt;         /* 4 */
-                       int16_t         v_pbatt;        /* 6 */
-                       int16_t         n_sense;        /* 8 */
-                       int16_t         sense[10];      /* 10 */
-                       uint16_t        pyro;           /* 30 */
-               } volt;                                 /* 32 */
-               /* AO_LOG_GPS_TIME */
-               struct {
-                       int32_t         latitude;       /* 4 */
-                       int32_t         longitude;      /* 8 */
-                       int16_t         altitude;       /* 12 */
-                       uint8_t         hour;           /* 14 */
-                       uint8_t         minute;         /* 15 */
-                       uint8_t         second;         /* 16 */
-                       uint8_t         flags;          /* 17 */
-                       uint8_t         year;           /* 18 */
-                       uint8_t         month;          /* 19 */
-                       uint8_t         day;            /* 20 */
-                       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 */
-                       struct {
-                               uint8_t svid;
-                               uint8_t c_n;
-                       } sats[12];                     /* 6 */
-               } gps_sat;                              /* 30 */
-       } 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;
-
-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_ */
diff --git a/src/core/ao_log_big.c b/src/core/ao_log_big.c
deleted file mode 100644 (file)
index db01f46..0000000
+++ /dev/null
@@ -1,162 +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"
-
-static __xdata uint8_t ao_log_mutex;
-static __xdata struct ao_log_record log;
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT_FULL;
-
-static uint8_t
-ao_log_csum(__xdata uint8_t *b) __reentrant
-{
-       uint8_t sum = 0x5a;
-       uint8_t i;
-
-       for (i = 0; i < sizeof (struct ao_log_record); i++)
-               sum += *b++;
-       return -sum;
-}
-
-uint8_t
-ao_log_data(__xdata struct ao_log_record *log) __reentrant
-{
-       uint8_t wrote = 0;
-       /* set checksum */
-       log->csum = 0;
-       log->csum = ao_log_csum((__xdata uint8_t *) log);
-       ao_mutex_get(&ao_log_mutex); {
-               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
-                       ao_log_stop();
-               if (ao_log_running) {
-                       wrote = 1;
-                       ao_storage_write(ao_log_current_pos,
-                                        log,
-                                        sizeof (struct ao_log_record));
-                       ao_log_current_pos += sizeof (struct ao_log_record);
-               }
-       } ao_mutex_put(&ao_log_mutex);
-       return wrote;
-}
-
-static uint8_t
-ao_log_dump_check_data(void)
-{
-       if (ao_log_csum((uint8_t *) &log) != 0)
-               return 0;
-       return 1;
-}
-
-static __data uint8_t  ao_log_data_pos;
-
-/* a hack to make sure that ao_log_records fill the eeprom block in even units */
-typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_record))] ;
-
-#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;
-
-       ao_storage_setup();
-
-       ao_log_scan();
-
-       while (!ao_log_running)
-               ao_sleep(&ao_log_running);
-
-       log.type = AO_LOG_FLIGHT;
-       log.tick = ao_sample_tick;
-#if HAS_ACCEL
-       log.u.flight.ground_accel = ao_ground_accel;
-#endif
-       log.u.flight.flight = ao_flight_number;
-       ao_log_data(&log);
-
-       /* Write the whole contents of the ring to the log
-        * when starting up.
-        */
-       ao_log_data_pos = ao_data_ring_next(ao_sample_data);
-       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_sample_data) {
-                       log.tick = ao_data_ring[ao_log_data_pos].tick;
-                       if ((int16_t) (log.tick - next_sensor) >= 0) {
-                               log.type = AO_LOG_SENSOR;
-                               log.u.sensor.accel = ao_data_ring[ao_log_data_pos].adc.accel;
-                               log.u.sensor.pres = ao_data_ring[ao_log_data_pos].adc.pres;
-                               ao_log_data(&log);
-                               if (ao_log_state <= ao_flight_coast)
-                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
-                               else
-                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
-                       }
-                       if ((int16_t) (log.tick - next_other) >= 0) {
-                               log.type = AO_LOG_TEMP_VOLT;
-                               log.u.temp_volt.temp = ao_data_ring[ao_log_data_pos].adc.temp;
-                               log.u.temp_volt.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
-                               ao_log_data(&log);
-                               log.type = AO_LOG_DEPLOY;
-                               log.u.deploy.drogue = ao_data_ring[ao_log_data_pos].adc.sense_d;
-                               log.u.deploy.main = ao_data_ring[ao_log_data_pos].adc.sense_m;
-                               ao_log_data(&log);
-                               next_other = log.tick + AO_OTHER_INTERVAL;
-                       }
-                       ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
-               }
-               /* Write state change to EEPROM */
-               if (ao_flight_state != ao_log_state) {
-                       ao_log_state = ao_flight_state;
-                       log.type = AO_LOG_STATE;
-                       log.tick = ao_sample_tick;
-                       log.u.state.state = ao_log_state;
-                       log.u.state.reason = 0;
-                       ao_log_data(&log);
-
-                       if (ao_log_state == ao_flight_landed)
-                               ao_log_stop();
-               }
-
-               /* Wait for a while */
-               ao_delay(AO_MS_TO_TICKS(100));
-
-               /* Stop logging when told to */
-               while (!ao_log_running)
-                       ao_sleep(&ao_log_running);
-       }
-}
-
-uint16_t
-ao_log_flight(uint8_t slot)
-{
-       if (!ao_storage_read(ao_log_pos(slot),
-                            &log,
-                            sizeof (struct ao_log_record)))
-               return 0;
-
-       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
-               return log.u.flight.flight;
-       return 0;
-}
diff --git a/src/core/ao_log_mega.c b/src/core/ao_log_mega.c
deleted file mode 100644 (file)
index 768947d..0000000
+++ /dev/null
@@ -1,199 +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_log.h>
-#include <ao_data.h>
-#include <ao_flight.h>
-
-static __xdata uint8_t ao_log_mutex;
-static __xdata struct ao_log_mega log;
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEMEGA;
-
-static uint8_t
-ao_log_csum(__xdata uint8_t *b) __reentrant
-{
-       uint8_t sum = 0x5a;
-       uint8_t i;
-
-       for (i = 0; i < sizeof (struct ao_log_mega); i++)
-               sum += *b++;
-       return -sum;
-}
-
-uint8_t
-ao_log_mega(__xdata struct ao_log_mega *log) __reentrant
-{
-       uint8_t wrote = 0;
-       /* set checksum */
-       log->csum = 0;
-       log->csum = ao_log_csum((__xdata uint8_t *) log);
-       ao_mutex_get(&ao_log_mutex); {
-               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
-                       ao_log_stop();
-               if (ao_log_running) {
-                       wrote = 1;
-                       ao_storage_write(ao_log_current_pos,
-                                        log,
-                                        sizeof (struct ao_log_mega));
-                       ao_log_current_pos += sizeof (struct ao_log_mega);
-               }
-       } ao_mutex_put(&ao_log_mutex);
-       return wrote;
-}
-
-static uint8_t
-ao_log_dump_check_data(void)
-{
-       if (ao_log_csum((uint8_t *) &log) != 0)
-               return 0;
-       return 1;
-}
-
-#if HAS_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 */
-typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_mega))] ;
-
-#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
-#if HAS_GYRO
-       log.u.flight.ground_accel_along = ao_ground_accel_along;
-       log.u.flight.ground_accel_across = ao_ground_accel_across;
-       log.u.flight.ground_accel_through = ao_ground_accel_through;
-       log.u.flight.ground_pitch = ao_ground_pitch;
-       log.u.flight.ground_yaw = ao_ground_yaw;
-       log.u.flight.ground_roll = ao_ground_roll;
-#endif
-       log.u.flight.ground_pres = ao_ground_pres;
-       log.u.flight.flight = ao_flight_number;
-       ao_log_mega(&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
-#if HAS_MPU6000
-                               log.u.sensor.accel_x = ao_data_ring[ao_log_data_pos].mpu6000.accel_x;
-                               log.u.sensor.accel_y = ao_data_ring[ao_log_data_pos].mpu6000.accel_y;
-                               log.u.sensor.accel_z = ao_data_ring[ao_log_data_pos].mpu6000.accel_z;
-                               log.u.sensor.gyro_x = ao_data_ring[ao_log_data_pos].mpu6000.gyro_x;
-                               log.u.sensor.gyro_y = ao_data_ring[ao_log_data_pos].mpu6000.gyro_y;
-                               log.u.sensor.gyro_z = ao_data_ring[ao_log_data_pos].mpu6000.gyro_z;
-#endif
-#if HAS_HMC5883
-                               log.u.sensor.mag_x = ao_data_ring[ao_log_data_pos].hmc5883.x;
-                               log.u.sensor.mag_y = ao_data_ring[ao_log_data_pos].hmc5883.y;
-                               log.u.sensor.mag_z = ao_data_ring[ao_log_data_pos].hmc5883.z;
-#endif
-                               log.u.sensor.accel = ao_data_accel(&ao_data_ring[ao_log_data_pos]);
-                               ao_log_mega(&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.v_pbatt = ao_data_ring[ao_log_data_pos].adc.v_pbatt;
-                               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;
-                       }
-                       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_mega(&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_mega)))
-               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_metrum.c b/src/core/ao_log_metrum.c
deleted file mode 100644 (file)
index 91624d9..0000000
+++ /dev/null
@@ -1,174 +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_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;
-
-       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
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/core/ao_log_micro.h b/src/core/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/core/ao_log_mini.c b/src/core/ao_log_mini.c
deleted file mode 100644 (file)
index 29e3bd9..0000000
+++ /dev/null
@@ -1,162 +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_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;
-
-       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_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;
-}
diff --git a/src/core/ao_log_single.c b/src/core/ao_log_single.c
deleted file mode 100644 (file)
index 3f6235a..0000000
+++ /dev/null
@@ -1,198 +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.
- */
-
-/*
- * ao_log_single.c
- *
- * Stores a sequence of fixed-size (32 byte) chunks
- * without splitting memory up into separate flights
- */
-
-#include "ao.h"
-#include "ao_product.h"
-
-static __xdata struct ao_task ao_log_single_task;
-
-__xdata uint8_t        ao_log_running;
-__xdata uint8_t                ao_log_mutex;
-__pdata uint32_t       ao_log_start_pos;
-__pdata uint32_t       ao_log_end_pos;
-__pdata uint32_t       ao_log_current_pos;
-
-__xdata union ao_log_single ao_log_single_write_data;
-__xdata union ao_log_single ao_log_single_read_data;
-
-uint8_t
-ao_log_single_write(void)
-{
-       uint8_t wrote = 0;
-
-       ao_mutex_get(&ao_log_mutex); {
-               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
-                       ao_log_single_stop();
-               if (ao_log_running) {
-                       wrote = 1;
-                       ao_storage_write(ao_log_current_pos,
-                                        &ao_log_single_write_data,
-                                        AO_LOG_SINGLE_SIZE);
-                       ao_log_current_pos += AO_LOG_SINGLE_SIZE;
-               }
-       } ao_mutex_put(&ao_log_mutex);
-       return wrote;
-}
-
-static uint8_t
-ao_log_single_valid(void)
-{
-       __xdata uint8_t *d = ao_log_single_read_data.bytes;
-       uint8_t i;
-       for (i = 0; i < AO_LOG_SINGLE_SIZE; i++)
-               if (*d++ != 0xff)
-                       return 1;
-       return 0;
-}
-
-uint8_t
-ao_log_single_read(uint32_t pos)
-{
-       if (!ao_storage_read(pos, &ao_log_single_read_data, AO_LOG_SINGLE_SIZE))
-               return 0;
-       return ao_log_single_valid();
-}
-
-void
-ao_log_single_start(void)
-{
-       if (!ao_log_running) {
-               ao_log_running = 1;
-               ao_wakeup(&ao_log_running);
-       }
-}
-
-void
-ao_log_single_stop(void)
-{
-       if (ao_log_running) {
-               ao_log_running = 0;
-       }
-}
-
-void
-ao_log_single_restart(void)
-{
-       /* Find end of data */
-       ao_log_end_pos = ao_storage_config;
-       for (ao_log_current_pos = 0;
-            ao_log_current_pos < ao_storage_config;
-            ao_log_current_pos += ao_storage_block)
-       {
-               if (!ao_log_single_read(ao_log_current_pos))
-                       break;
-       }
-       if (ao_log_current_pos > 0) {
-               ao_log_current_pos -= ao_storage_block;
-               for (; ao_log_current_pos < ao_storage_config;
-                    ao_log_current_pos += sizeof (struct ao_log_telescience))
-               {
-                       if (!ao_log_single_read(ao_log_current_pos))
-                               break;
-               }
-       }
-}
-
-void
-ao_log_single_set(void)
-{
-       printf("Logging currently %s\n", ao_log_running ? "on" : "off");
-       ao_cmd_hex();
-       if (ao_cmd_status == ao_cmd_success) {
-               if (ao_cmd_lex_i) {
-                       printf("Logging from %ld to %ld\n", ao_log_current_pos, ao_log_end_pos);
-                       ao_log_single_start();
-               } else {
-                       printf ("Log stopped at %ld\n", ao_log_current_pos);
-                       ao_log_single_stop();
-               }
-       }
-       ao_cmd_status = ao_cmd_success;
-}
-
-void
-ao_log_single_delete(void)
-{
-       uint32_t        pos;
-
-       ao_cmd_hex();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       if (ao_cmd_lex_i != 1) {
-               ao_cmd_status = ao_cmd_syntax_error;
-               printf("No such flight: %d\n", ao_cmd_lex_i);
-               return;
-       }
-       ao_log_single_stop();
-       for (pos = 0; pos < ao_storage_config; pos += ao_storage_block) {
-               if (!ao_log_single_read(pos))
-                       break;
-               ao_storage_erase(pos);
-       }
-       ao_log_current_pos = ao_log_start_pos = 0;
-       if (pos == 0)
-               printf("No such flight: %d\n", ao_cmd_lex_i);
-       else
-               printf ("Erased\n");
-}
-
-uint8_t
-ao_log_full(void)
-{
-       return ao_log_current_pos >= ao_log_end_pos;
-}
-
-uint8_t
-ao_log_present(void)
-{
-       return ao_log_single_read(0);
-}
-
-static void
-ao_log_single_query(void)
-{
-       printf("Logging enabled: %d\n", ao_log_running);
-       printf("Log start: %ld\n", ao_log_start_pos);
-       printf("Log cur: %ld\n", ao_log_current_pos);
-       printf("Log end: %ld\n", ao_log_end_pos);
-       ao_log_single_extra_query();
-}
-
-const struct ao_cmds ao_log_single_cmds[] = {
-       { ao_log_single_set,    "L <0 off, 1 on>\0Set logging" },
-       { ao_log_single_list,   "l\0List stored logs" },
-       { ao_log_single_delete, "d 1\0Delete all stored logs" },
-       { ao_log_single_query, "q\0Query log status" },
-       { 0,    NULL },
-};
-
-void
-ao_log_single_init(void)
-{
-       ao_log_running = 0;
-
-       ao_cmd_register(&ao_log_single_cmds[0]);
-
-       ao_add_task(&ao_log_single_task, ao_log_single, "log");
-}
diff --git a/src/core/ao_log_telem.c b/src/core/ao_log_telem.c
deleted file mode 100644 (file)
index 095aca3..0000000
+++ /dev/null
@@ -1,131 +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_flight.h>
-#include <ao_sample.h>
-
-__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;
-__xdata int16_t                                ao_max_height;  /* max of ao_height */
-__pdata int16_t                                sense_d, sense_m;
-__pdata uint8_t                                ao_igniter_present;
-
-static void
-ao_log_telem_track() {
-       if (ao_monitoring == sizeof (union ao_telemetry_all)) {
-               switch (ao_log_single_write_data.telemetry.generic.type) {
-               case AO_TELEMETRY_SENSOR_TELEMETRUM:
-               case AO_TELEMETRY_SENSOR_TELEMINI:
-                       /* fall through ... */
-               case AO_TELEMETRY_SENSOR_TELENANO:
-                       if (ao_log_single_write_data.telemetry.generic.type == AO_TELEMETRY_SENSOR_TELENANO) {
-                               ao_igniter_present = 0;
-                       } else {
-                               sense_d = ao_log_single_write_data.telemetry.sensor.sense_d;
-                               sense_m = ao_log_single_write_data.telemetry.sensor.sense_m;
-                               ao_igniter_present = 1;
-                       }
-                       if (ao_log_single_write_data.telemetry.sensor.height > ao_max_height) {
-                               ao_max_height = ao_log_single_write_data.telemetry.sensor.height;
-                       }
-                       if (ao_log_single_write_data.telemetry.sensor.state != ao_flight_state) {
-                               ao_flight_state = ao_log_single_write_data.telemetry.sensor.state;
-                               if (ao_flight_state == ao_flight_pad)
-                                       ao_max_height = 0;
-                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-                       }
-               }
-       }
-}
-
-enum ao_igniter_status
-ao_igniter_status(enum ao_igniter igniter)
-{
-       int16_t value;
-
-       switch (igniter) {
-       case ao_igniter_drogue:
-               value = sense_d;
-               break;
-       case ao_igniter_main:
-               value = sense_m;
-               break;
-       default:
-               value = 0;
-               break;
-       }
-       if (value < AO_IGNITER_OPEN)
-               return ao_igniter_open;
-       else if (value > AO_IGNITER_CLOSED)
-               return ao_igniter_ready;
-       else
-               return ao_igniter_unknown;
-}
-
-void
-ao_log_single(void)
-{
-       ao_storage_setup();
-
-       /* This can take a while, so let the rest
-        * of the system finish booting before we start
-        */
-       ao_delay(AO_SEC_TO_TICKS(2));
-
-       ao_log_running = 1;
-       ao_log_single_restart();
-       ao_flight_state = ao_flight_startup;
-       ao_monitor_set(sizeof(struct ao_telemetry_generic));
-
-       for (;;) {
-               while (!ao_log_running)
-                       ao_sleep(&ao_log_running);
-
-               ao_log_monitor_pos = ao_monitor_head;
-               while (ao_log_running) {
-                       /* Write samples to EEPROM */
-                       while (ao_log_monitor_pos != ao_monitor_head) {
-                               ao_xmemcpy(&ao_log_single_write_data.telemetry,
-                                          &ao_monitor_ring[ao_log_monitor_pos],
-                                          AO_LOG_SINGLE_SIZE);
-                               ao_log_single_write();
-                               ao_log_monitor_pos = ao_monitor_ring_next(ao_log_monitor_pos);
-                               ao_log_telem_track();
-                       }
-                       /* Wait for more telemetry data to arrive */
-                       ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
-               }
-       }
-}
-
-void
-ao_log_single_list(void)
-{
-       if (ao_log_current_pos != 0)
-               printf("flight 1 start %x end %x\n",
-                      0,
-                      (uint16_t) ((ao_log_current_pos + 0xff) >> 8));
-       printf ("done\n");
-}
-
-void
-ao_log_single_extra_query(void)
-{
-}
diff --git a/src/core/ao_log_telescience.c b/src/core/ao_log_telescience.c
deleted file mode 100644 (file)
index 002a10b..0000000
+++ /dev/null
@@ -1,119 +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_product.h"
-#include "ao_log.h"
-#include "ao_companion.h"
-
-static uint8_t ao_log_data_pos;
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT_TELESCIENCE;
-
-static void
-ao_log_telescience_csum(void) __reentrant
-{
-       __xdata uint8_t *b = ao_log_single_write_data.bytes;
-       uint8_t sum = 0x5a;
-       uint8_t i;
-
-       ao_log_single_write_data.telescience.csum = 0;
-       for (i = 0; i < sizeof (struct ao_log_telescience); i++)
-               sum += *b++;
-       ao_log_single_write_data.telescience.csum = -sum;
-}
-
-void
-ao_log_single(void)
-{
-       ao_storage_setup();
-
-       /* This can take a while, so let the rest
-        * of the system finish booting before we start
-        */
-       ao_delay(AO_SEC_TO_TICKS(10));
-
-       ao_log_single_restart();
-       for (;;) {
-               while (!ao_log_running)
-                       ao_sleep(&ao_log_running);
-
-               ao_log_start_pos = ao_log_current_pos;
-               ao_log_single_write_data.telescience.type = AO_LOG_TELESCIENCE_START;
-               ao_log_single_write_data.telescience.tick = ao_time();
-               ao_log_single_write_data.telescience.adc[0] = ao_companion_command.serial;
-               ao_log_single_write_data.telescience.adc[1] = ao_companion_command.flight;
-               ao_log_telescience_csum();
-               ao_log_single_write();
-               /* Write the whole contents of the ring to the log
-                * when starting up.
-                */
-               ao_log_data_pos = ao_data_ring_next(ao_data_head);
-               ao_log_single_write_data.telescience.type = AO_LOG_TELESCIENCE_DATA;
-               while (ao_log_running) {
-                       /* Write samples to EEPROM */
-                       while (ao_log_data_pos != ao_data_head) {
-                               ao_log_single_write_data.telescience.tick = ao_data_ring[ao_log_data_pos].tick;
-                               memcpy(&ao_log_single_write_data.telescience.adc, (void *) ao_data_ring[ao_log_data_pos].adc.adc,
-                                      AO_LOG_TELESCIENCE_NUM_ADC * sizeof (uint16_t));
-                               ao_log_telescience_csum();
-                               ao_log_single_write();
-                               ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
-                       }
-                       /* Wait for more ADC data to arrive */
-                       ao_sleep((void *) &ao_data_head);
-               }
-               memset(&ao_log_single_write_data.telescience.adc, '\0', sizeof (ao_log_single_write_data.telescience.adc));
-       }
-}
-
-void
-ao_log_single_list(void)
-{
-       uint32_t        pos;
-       uint32_t        start = 0;
-       uint8_t         flight = 0;
-
-       for (pos = 0; ; pos += sizeof (struct ao_log_telescience)) {
-               if (pos >= ao_storage_config ||
-                   !ao_log_single_read(pos) ||
-                   ao_log_single_read_data.telescience.type == AO_LOG_TELESCIENCE_START)
-               {
-                       if (pos != start) {
-                               printf("flight %d start %x end %x\n",
-                                      flight,
-                                      (uint16_t) (start >> 8),
-                                      (uint16_t) ((pos + 0xff) >> 8)); flush();
-                       }
-                       if (ao_log_single_read_data.telescience.type != AO_LOG_TELESCIENCE_START)
-                               break;
-                       start = pos;
-                       flight++;
-               }
-       }
-       printf ("done\n");
-}
-
-void
-ao_log_single_extra_query(void)
-{
-       printf("log data tick: %04x\n", ao_log_single_write_data.telescience.tick);
-       printf("TM data tick: %04x\n", ao_log_single_write_data.telescience.tm_tick);
-       printf("TM state: %d\n", ao_log_single_write_data.telescience.tm_state);
-       printf("TM serial: %d\n", ao_companion_command.serial);
-       printf("TM flight: %d\n", ao_companion_command.flight);
-}
diff --git a/src/core/ao_log_tiny.c b/src/core/ao_log_tiny.c
deleted file mode 100644 (file)
index 67767dc..0000000
+++ /dev/null
@@ -1,161 +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"
-
-static __data uint16_t ao_log_tiny_interval;
-
-#define AO_LOG_TINY_INTERVAL_DEFAULT   AO_MS_TO_TICKS(1000)
-#if USE_FAST_ASCENT_LOG
-#define AO_LOG_TINY_INTERVAL_ASCENT    AO_MS_TO_TICKS(100)
-#define AO_PAD_RING    8
-#else
-#define AO_LOG_TINY_INTERVAL_ASCENT    AO_LOG_TINY_INTERVAL_DEFAULT
-#define AO_PAD_RING    2
-#endif
-
-__code uint8_t ao_log_format = AO_LOG_FORMAT_TINY;
-
-void
-ao_log_tiny_set_interval(uint16_t ticks)
-{
-       ao_log_tiny_interval = ticks;
-}
-
-
-static void ao_log_tiny_data(uint16_t d)
-{
-       if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
-               ao_log_stop();
-       if (ao_log_running) {
-               ao_storage_write(ao_log_current_pos, DATA_TO_XDATA(&d), 2);
-               ao_log_current_pos += 2;
-       }
-}
-
-static __xdata uint16_t ao_log_pad_ring[AO_PAD_RING];
-static __pdata uint8_t ao_log_pad_ring_pos;
-
-#define ao_pad_ring_next(n)    (((n) + 1) & (AO_PAD_RING - 1))
-
-static void ao_log_tiny_queue(uint16_t d)
-{
-       ao_log_pad_ring[ao_log_pad_ring_pos] = d;
-       ao_log_pad_ring_pos = ao_pad_ring_next(ao_log_pad_ring_pos);
-}
-
-static void ao_log_tiny_start(void)
-{
-       uint8_t         p;
-       uint16_t        d;
-
-       ao_log_tiny_data(ao_flight_number);
-       ao_log_tiny_data(ao_ground_pres);
-       p = ao_log_pad_ring_pos;
-       do {
-               d = ao_log_pad_ring[p];
-               /*
-                * ignore unwritten slots
-                */
-               if (d)
-                       ao_log_tiny_data(d);
-               p = ao_pad_ring_next(p);
-       } while (p != ao_log_pad_ring_pos);
-}
-
-void
-ao_log(void)
-{
-       uint16_t                last_time;
-       uint16_t                now;
-       enum ao_flight_state    ao_log_tiny_state;
-       int32_t                 sum;
-       int16_t                 count;
-       uint8_t                 ao_log_data;
-       uint8_t                 ao_log_started = 0;
-
-       ao_storage_setup();
-
-       ao_log_scan();
-
-       ao_log_tiny_state = ao_flight_invalid;
-       ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT;
-       sum = 0;
-       count = 0;
-       ao_log_data = ao_sample_data;
-       last_time = ao_time();
-       for (;;) {
-
-               /*
-                * Add in pending sample data
-                */
-               ao_sleep(DATA_TO_XDATA(&ao_sample_data));
-               while (ao_log_data != ao_sample_data) {
-                       sum += ao_data_pres(&ao_data_ring[ao_log_data]);
-                       count++;
-                       ao_log_data = ao_data_ring_next(ao_log_data);
-               }
-               if (ao_log_running) {
-                       if (!ao_log_started) {
-                               ao_log_tiny_start();
-                               ao_log_started = 1;
-                       }
-                       if (ao_flight_state != ao_log_tiny_state) {
-                               ao_log_tiny_data(ao_flight_state | 0x8000);
-                               ao_log_tiny_state = ao_flight_state;
-                               ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_DEFAULT;
-#if AO_LOG_TINY_INTERVAL_ASCENT != AO_LOG_TINY_INTERVAL_DEFAULT
-                               if (ao_log_tiny_state <= ao_flight_coast)
-                                       ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT;
-#endif
-                               if (ao_log_tiny_state == ao_flight_landed)
-                                       ao_log_stop();
-                       }
-               }
-
-               /* Stop logging when told to */
-               if (!ao_log_running && ao_log_started)
-                       ao_exit();
-
-               /*
-                * Write out the sample when finished
-                */
-               now = ao_time();
-               if ((int16_t) (now - (last_time + ao_log_tiny_interval)) >= 0 && count) {
-                       count = sum / count;
-                       if (ao_log_started)
-                               ao_log_tiny_data(count);
-                       else
-                               ao_log_tiny_queue(count);
-                       sum = 0;
-                       count = 0;
-                       last_time = now;
-               }
-       }
-}
-
-uint16_t
-ao_log_flight(uint8_t slot)
-{
-       static __xdata uint16_t flight;
-
-       (void) slot;
-       ao_storage_read(0, &flight, 2);
-       if (flight == 0xffff)
-               flight = 0;
-       return flight;
-}
diff --git a/src/core/ao_microflight.c b/src/core/ao_microflight.c
deleted file mode 100644 (file)
index f680e40..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    (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
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/core/ao_monitor.c b/src/core/ao_monitor.c
deleted file mode 100644 (file)
index 18f170b..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * 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_telem.h"
-#include "ao_flight.h"
-
-#if !HAS_MONITOR
-#error Must define HAS_MONITOR to 1
-#endif
-
-#ifndef LEGACY_MONITOR
-#error Must define LEGACY_MONITOR
-#endif
-
-#ifndef HAS_MONITOR_PUT
-#define HAS_MONITOR_PUT 1
-#endif
-
-#ifndef AO_MONITOR_LED
-#error Must define AO_MONITOR_LED
-#endif
-
-__data uint8_t ao_monitoring;
-static __data uint8_t ao_monitor_disabled;
-static __data uint8_t ao_internal_monitoring;
-static __data uint8_t ao_external_monitoring;
-
-__xdata union ao_monitor ao_monitor_ring[AO_MONITOR_RING];
-
-__data uint8_t ao_monitor_head;
-
-static void
-_ao_monitor_adjust(void)
-{
-       if (ao_monitoring)
-               ao_radio_recv_abort();
-       if (ao_monitor_disabled)
-               ao_monitoring = 0;
-       else {
-               if (ao_external_monitoring)
-                       ao_monitoring = ao_external_monitoring;
-               else
-                       ao_monitoring = ao_internal_monitoring;
-       }
-       ao_wakeup(DATA_TO_XDATA(&ao_monitoring));
-}
-
-void
-ao_monitor_get(void)
-{
-       uint8_t size;
-
-       for (;;) {
-               switch (ao_monitoring) {
-               case 0:
-                       ao_sleep(DATA_TO_XDATA(&ao_monitoring));
-                       continue;
-#if LEGACY_MONITOR
-               case AO_MONITORING_ORIG:
-                       size = sizeof (struct ao_telemetry_orig_recv);
-                       break;
-#endif
-               default:
-                       if (ao_monitoring > AO_MAX_TELEMETRY)
-                               ao_monitoring = AO_MAX_TELEMETRY;
-                       size = ao_monitoring;
-                       break;
-               }
-               if (!ao_radio_recv(&ao_monitor_ring[ao_monitor_head], size + 2, 0))
-                       continue;
-               ao_monitor_head = ao_monitor_ring_next(ao_monitor_head);
-               ao_wakeup(DATA_TO_XDATA(&ao_monitor_head));
-       }
-}
-
-#if AO_MONITOR_LED
-__xdata struct ao_task ao_monitor_blink_task;
-
-void
-ao_monitor_blink(void)
-{
-       for (;;) {
-               ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
-               ao_led_for(AO_MONITOR_LED, AO_MS_TO_TICKS(100));
-       }
-}
-#endif
-
-#if HAS_MONITOR_PUT
-
-static const char xdigit[16] = {
-       '0', '1', '2', '3', '4', '5', '6', '7',
-       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
-};
-
-#define hex(c) do { putchar(xdigit[(c) >> 4]); putchar(xdigit[(c)&0xf]); } while (0)
-
-void
-ao_monitor_put(void)
-{
-#if LEGACY_MONITOR
-       __xdata char callsign[AO_MAX_CALLSIGN+1];
-       int16_t rssi;
-#endif
-       uint8_t ao_monitor_tail;
-       uint8_t state;
-       uint8_t sum, byte;
-       __xdata union ao_monitor        *m;
-
-#define recv_raw       ((m->raw))
-#define recv_orig      ((m->orig))
-#define recv_tiny      ((m->tiny))
-
-       ao_monitor_tail = ao_monitor_head;
-       for (;;) {
-               while (!ao_external_monitoring)
-                       ao_sleep(DATA_TO_XDATA(&ao_external_monitoring));
-               while (ao_monitor_tail == ao_monitor_head && ao_external_monitoring)
-                       ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
-               if (!ao_external_monitoring)
-                       continue;
-               m = &ao_monitor_ring[ao_monitor_tail];
-               ao_monitor_tail = ao_monitor_ring_next(ao_monitor_tail);
-               switch (ao_monitoring) {
-               case 0:
-                       break;
-#if LEGACY_MONITOR
-               case AO_MONITORING_ORIG:
-                       state = recv_orig.telemetry_orig.flight_state;
-
-                       rssi = (int16_t) AO_RSSI_FROM_RADIO(recv_orig.rssi);
-                       ao_xmemcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN);
-                       if (state > ao_flight_invalid)
-                               state = ao_flight_invalid;
-                       if (recv_orig.status & PKT_APPEND_STATUS_1_CRC_OK) {
-
-                               /* General header fields */
-                               printf(AO_TELEM_VERSION " %d "
-                                      AO_TELEM_CALL " %s "
-                                      AO_TELEM_SERIAL " %d "
-                                      AO_TELEM_FLIGHT " %d "
-                                      AO_TELEM_RSSI " %d "
-                                      AO_TELEM_STATE " %s "
-                                      AO_TELEM_TICK " %d ",
-                                      AO_TELEMETRY_VERSION,
-                                      callsign,
-                                      recv_orig.telemetry_orig.serial,
-                                      recv_orig.telemetry_orig.flight,
-                                      rssi,
-                                      ao_state_names[state],
-                                      recv_orig.telemetry_orig.adc.tick);
-
-                               /* Raw sensor values */
-                               printf(AO_TELEM_RAW_ACCEL " %d "
-                                      AO_TELEM_RAW_BARO " %d "
-                                      AO_TELEM_RAW_THERMO " %d "
-                                      AO_TELEM_RAW_BATT " %d "
-                                      AO_TELEM_RAW_DROGUE " %d "
-                                      AO_TELEM_RAW_MAIN " %d ",
-                                      recv_orig.telemetry_orig.adc.accel,
-                                      recv_orig.telemetry_orig.adc.pres,
-                                      recv_orig.telemetry_orig.adc.temp,
-                                      recv_orig.telemetry_orig.adc.v_batt,
-                                      recv_orig.telemetry_orig.adc.sense_d,
-                                      recv_orig.telemetry_orig.adc.sense_m);
-
-                               /* Sensor calibration values */
-                               printf(AO_TELEM_CAL_ACCEL_GROUND " %d "
-                                      AO_TELEM_CAL_BARO_GROUND " %d "
-                                      AO_TELEM_CAL_ACCEL_PLUS " %d "
-                                      AO_TELEM_CAL_ACCEL_MINUS " %d ",
-                                      recv_orig.telemetry_orig.ground_accel,
-                                      recv_orig.telemetry_orig.ground_pres,
-                                      recv_orig.telemetry_orig.accel_plus_g,
-                                      recv_orig.telemetry_orig.accel_minus_g);
-
-                               if (recv_orig.telemetry_orig.u.k.unused == 0x8000) {
-                                       /* Kalman state values */
-                                       printf(AO_TELEM_KALMAN_HEIGHT " %d "
-                                              AO_TELEM_KALMAN_SPEED " %d "
-                                              AO_TELEM_KALMAN_ACCEL " %d ",
-                                              recv_orig.telemetry_orig.height,
-                                              recv_orig.telemetry_orig.u.k.speed,
-                                              recv_orig.telemetry_orig.accel);
-                               } else {
-                                       /* Ad-hoc flight values */
-                                       printf(AO_TELEM_ADHOC_ACCEL " %d "
-                                              AO_TELEM_ADHOC_SPEED " %ld "
-                                              AO_TELEM_ADHOC_BARO " %d ",
-                                              recv_orig.telemetry_orig.accel,
-                                              recv_orig.telemetry_orig.u.flight_vel,
-                                              recv_orig.telemetry_orig.height);
-                               }
-                               ao_gps_print(&recv_orig.telemetry_orig.gps);
-                               ao_gps_tracking_print(&recv_orig.telemetry_orig.gps_tracking);
-                               putchar('\n');
-#if HAS_RSSI
-                               ao_rssi_set(rssi);
-#endif
-                       } else {
-                               printf("CRC INVALID RSSI %3d\n", rssi);
-                       }
-                       break;
-#endif /* LEGACY_MONITOR */
-               default:
-#if AO_PROFILE
-               {
-                       extern uint32_t ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
-                       extern uint32_t ao_fec_decode_start, ao_fec_decode_end;
-
-                       printf ("between packet: %d\n", ao_rx_start_tick - ao_rx_last_done_tick);
-                       printf ("receive start delay: %d\n", ao_rx_packet_tick - ao_rx_start_tick);
-                       printf ("decode time: %d\n", ao_fec_decode_end - ao_fec_decode_start);
-                       printf ("rx cleanup: %d\n", ao_rx_done_tick - ao_fec_decode_end);
-               }
-#endif
-                       printf("TELEM ");
-                       hex((uint8_t) (ao_monitoring + 2));
-                       sum = 0x5a;
-                       for (state = 0; state < ao_monitoring + 2; state++) {
-                               byte = recv_raw.packet[state];
-                               sum += byte;
-                               hex(byte);
-                       }
-                       hex(sum);
-                       putchar ('\n');
-#if HAS_RSSI
-                       if (recv_raw.packet[ao_monitoring + 1] & PKT_APPEND_STATUS_1_CRC_OK) {
-                               rssi = AO_RSSI_FROM_RADIO(recv_raw.packet[ao_monitoring]);
-                               ao_rssi_set(rssi);
-                       }
-#endif
-                       break;
-               }
-               ao_usb_flush();
-       }
-}
-
-__xdata struct ao_task ao_monitor_put_task;
-#endif
-
-__xdata struct ao_task ao_monitor_get_task;
-
-void
-ao_monitor_set(uint8_t monitoring)
-{
-       ao_internal_monitoring = monitoring;
-       _ao_monitor_adjust();
-}
-
-void
-ao_monitor_disable(void)
-{
-       ++ao_monitor_disabled;
-       _ao_monitor_adjust();
-}
-
-void
-ao_monitor_enable(void)
-{
-       --ao_monitor_disabled;
-       _ao_monitor_adjust();
-}
-
-#if HAS_MONITOR_PUT
-static void
-set_monitor(void)
-{
-       ao_cmd_hex();
-       ao_external_monitoring = ao_cmd_lex_i;
-       ao_wakeup(DATA_TO_XDATA(&ao_external_monitoring));
-       ao_wakeup(DATA_TO_XDATA(&ao_monitor_head));
-       _ao_monitor_adjust();
-}
-
-__code struct ao_cmds ao_monitor_cmds[] = {
-       { set_monitor,  "m <0 off, 1 old, 20 std>\0Set radio monitoring" },
-       { 0,    NULL },
-};
-#endif
-
-void
-ao_monitor_init(void) __reentrant
-{
-#if HAS_MONITOR_PUT
-       ao_cmd_register(&ao_monitor_cmds[0]);
-       ao_add_task(&ao_monitor_put_task, ao_monitor_put, "monitor_put");
-#endif
-       ao_add_task(&ao_monitor_get_task, ao_monitor_get, "monitor_get");
-#if AO_MONITOR_LED
-       ao_add_task(&ao_monitor_blink_task, ao_monitor_blink, "monitor_blink");
-#endif
-}
diff --git a/src/core/ao_mutex.c b/src/core/ao_mutex.c
deleted file mode 100644 (file)
index 952ff46..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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"
-
-void
-ao_mutex_get(__xdata uint8_t *mutex) __reentrant
-{
-       if (*mutex == ao_cur_task->task_id)
-               ao_panic(AO_PANIC_MUTEX);
-       ao_arch_critical(
-               while (*mutex)
-                       ao_sleep(mutex);
-               *mutex = ao_cur_task->task_id;
-               );
-}
-
-void
-ao_mutex_put(__xdata uint8_t *mutex) __reentrant
-{
-       if (*mutex != ao_cur_task->task_id)
-               ao_panic(AO_PANIC_MUTEX);
-       ao_arch_critical(
-               *mutex = 0;
-               ao_wakeup(mutex);
-               );
-}
diff --git a/src/core/ao_notask.c b/src/core/ao_notask.c
deleted file mode 100644 (file)
index 6f967e6..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.
- */
-
-#include <ao.h>
-
-static volatile void *ao_wchan;
-
-uint8_t
-ao_sleep(__xdata void *wchan)
-{
-#if 1
-       ao_wchan = wchan;
-       ao_arch_wait_interrupt();
-#else
-       uint8_t sreg;
-
-       ao_wchan = wchan;
-       asm("in %0,__SREG__" : "=&r" (sreg));
-       sei();
-       while (ao_wchan)
-               ao_arch_cpu_idle();
-       asm("out __SREG__,%0" : : "r" (sreg));
-#endif
-       return 0;
-}
-
-void
-ao_wakeup(__xdata void *wchan)
-{
-       (void) wchan;
-       ao_wchan = 0;
-}
diff --git a/src/core/ao_notask.h b/src/core/ao_notask.h
deleted file mode 100644 (file)
index 6b6b5bb..0000000
+++ /dev/null
@@ -1,27 +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_NOTASK_H_
-#define _AO_NOTASK_H_
-
-uint8_t
-ao_sleep(__xdata void *wchan);
-
-void
-ao_wakeup(__xdata void *wchan);
-
-#endif /* _AO_NOTASK_H_ */
diff --git a/src/core/ao_packet.h b/src/core/ao_packet.h
deleted file mode 100644 (file)
index b8426cf..0000000
+++ /dev/null
@@ -1,91 +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_PACKET_H_
-#define _AO_PACKET_H_
-
-/*
- * ao_packet.c
- *
- * Packet-based command interface
- */
-
-#define AO_PACKET_MAX          64
-#define AO_PACKET_SYN          (uint8_t) 0xff
-
-struct ao_packet {
-       uint8_t         addr;
-       uint8_t         len;
-       uint8_t         seq;
-       uint8_t         ack;
-       uint8_t         d[AO_PACKET_MAX];
-       uint8_t         callsign[AO_MAX_CALLSIGN];
-};
-
-struct ao_packet_recv {
-       struct ao_packet        packet;
-       int8_t                  rssi;
-       uint8_t                 status;
-};
-
-extern __xdata struct ao_packet_recv ao_rx_packet;
-extern __xdata struct ao_packet ao_tx_packet;
-extern __xdata struct ao_task  ao_packet_task;
-extern __xdata uint8_t ao_packet_enable;
-extern __xdata uint8_t ao_packet_master_sleeping;
-extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used;
-extern __xdata uint8_t ao_packet_restart;
-
-void
-ao_packet_send(void);
-
-uint8_t
-ao_packet_recv(void);
-
-void
-ao_packet_flush(void);
-
-void
-ao_packet_putchar(char c) __reentrant;
-
-int
-_ao_packet_pollchar(void);
-
-#if PACKET_HAS_MASTER
-/* ao_packet_master.c */
-
-extern __xdata int8_t ao_packet_last_rssi;
-
-void
-ao_packet_master_init(void);
-#endif
-
-#if PACKET_HAS_SLAVE
-/* ao_packet_slave.c */
-
-void
-ao_packet_slave_start(void);
-
-void
-ao_packet_slave_stop(void);
-
-void
-ao_packet_slave_init(uint8_t enable);
-
-#endif
-
-#endif /* _AO_PACKET_H_ */
diff --git a/src/core/ao_panic.c b/src/core/ao_panic.c
deleted file mode 100644 (file)
index c29cd8f..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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"
-
-#ifndef HAS_BEEP
-#error Please define HAS_BEEP
-#endif
-
-#if !HAS_BEEP
-#define ao_beep(x)
-#endif
-#if !LEDS_AVAILABLE
-#define ao_led_on(x)
-#define ao_led_off(x)
-#endif
-
-#ifndef AO_LED_PANIC
-#define AO_LED_PANIC   AO_LED_RED
-#endif
-
-static void
-ao_panic_delay(uint8_t n)
-{
-       uint8_t i = 0, j = 0;
-
-       while (n--)
-               while (--j)
-                       while (--i)
-                               ao_arch_nop();
-}
-
-void
-ao_panic(uint8_t reason)
-{
-       uint8_t n;
-
-#if LOW_LEVEL_DEBUG
-       ao_cur_task = NULL;
-       printf ("panic %d\n", reason);
-#endif
-       ao_arch_block_interrupts();
-       for (;;) {
-               ao_panic_delay(20);
-               for (n = 0; n < 5; n++) {
-                       ao_led_on(AO_LED_PANIC);
-                       ao_beep(AO_BEEP_HIGH);
-                       ao_panic_delay(1);
-                       ao_led_off(AO_LED_PANIC);
-                       ao_beep(AO_BEEP_LOW);
-                       ao_panic_delay(1);
-               }
-               ao_beep(AO_BEEP_OFF);
-               ao_panic_delay(2);
-
-#ifdef SDCC
-#pragma disable_warning 126
-#endif
-               if (reason & 0x40) {
-                       ao_led_on(AO_LED_PANIC);
-                       ao_beep(AO_BEEP_HIGH);
-                       ao_panic_delay(40);
-                       ao_led_off(AO_LED_PANIC);
-                       ao_beep(AO_BEEP_OFF);
-                       ao_panic_delay(10);
-               }
-               for (n = 0; n < (reason & 0x3f); n++) {
-                       ao_led_on(AO_LED_PANIC);
-                       ao_beep(AO_BEEP_MID);
-                       ao_panic_delay(10);
-                       ao_led_off(AO_LED_PANIC);
-                       ao_beep(AO_BEEP_OFF);
-                       ao_panic_delay(10);
-               }
-       }
-}
diff --git a/src/core/ao_product.c b/src/core/ao_product.c
deleted file mode 100644 (file)
index b9327ba..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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_product.h"
-
-/* Defines which mark this particular AltOS product */
-
-const char ao_version[AO_MAX_VERSION] = AO_iVersion_STRING;
-const char ao_manufacturer[] = AO_iManufacturer_STRING;
-const char ao_product[] = AO_iProduct_STRING;
-
-#define LE_WORD(x)    ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
-
-#if HAS_USB
-
-/* 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 [] =
-{
-       /* Device descriptor */
-       0x12,
-       AO_USB_DESC_DEVICE,
-       LE_WORD(0x0110),        /*  bcdUSB */
-       0x02,                   /*  bDeviceClass */
-       0x00,                   /*  bDeviceSubClass */
-       0x00,                   /*  bDeviceProtocol */
-       AO_USB_CONTROL_SIZE,    /*  bMaxPacketSize */
-       LE_WORD(0xFFFE),        /*  idVendor */
-       LE_WORD(AO_idProduct_NUMBER),   /*  idProduct */
-       LE_WORD(0x0100),        /*  bcdDevice */
-       0x01,                   /*  iManufacturer */
-       0x02,                   /*  iProduct */
-       0x03,                   /*  iSerialNumber */
-       0x01,                   /*  bNumConfigurations */
-
-       /* Configuration descriptor */
-       0x09,
-       AO_USB_DESC_CONFIGURATION,
-       LE_WORD(67),            /*  wTotalLength */
-       0x02,                   /*  bNumInterfaces */
-       0x01,                   /*  bConfigurationValue */
-       0x00,                   /*  iConfiguration */
-       0xC0,                   /*  bmAttributes */
-       AO_USB_MAX_POWER >> 1,  /*  bMaxPower, 2mA units */
-
-       /* Control class interface */
-       0x09,
-       AO_USB_DESC_INTERFACE,
-       0x00,                   /*  bInterfaceNumber */
-       0x00,                   /*  bAlternateSetting */
-       0x01,                   /*  bNumEndPoints */
-       0x02,                   /*  bInterfaceClass */
-       0x02,                   /*  bInterfaceSubClass */
-       0x01,                   /*  bInterfaceProtocol, linux requires value of 1 for the cdc_acm module */
-       0x00,                   /*  iInterface */
-
-       /* Header functional descriptor */
-       0x05,
-       AO_USB_CS_INTERFACE,
-       0x00,                   /*  bDescriptor SubType Header */
-       LE_WORD(0x0110),        /*  CDC version 1.1 */
-
-       /* Call management functional descriptor */
-       0x05,
-       AO_USB_CS_INTERFACE,
-       0x01,                   /* bDescriptor SubType Call Management */
-       0x01,                   /* bmCapabilities = device handles call management */
-       0x01,                   /* bDataInterface call management interface number */
-
-       /* ACM functional descriptor */
-       0x04,
-       AO_USB_CS_INTERFACE,
-       0x02,                   /* bDescriptor SubType Abstract Control Management */
-       0x02,                   /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */
-
-       /* Union functional descriptor */
-       0x05,
-       AO_USB_CS_INTERFACE,
-       0x06,                   /* bDescriptor SubType Union Functional descriptor */
-       0x00,                   /* bMasterInterface */
-       0x01,                   /* bSlaveInterface0 */
-
-       /* Notification EP */
-       0x07,
-       AO_USB_DESC_ENDPOINT,
-       AO_USB_INT_EP|0x80,     /* bEndpointAddress */
-       0x03,                   /* bmAttributes = intr */
-       LE_WORD(8),             /* wMaxPacketSize */
-       0xff,                   /* bInterval */
-
-       /* Data class interface descriptor */
-       0x09,
-       AO_USB_DESC_INTERFACE,
-       0x01,                   /* bInterfaceNumber */
-       0x00,                   /* bAlternateSetting */
-       0x02,                   /* bNumEndPoints */
-       0x0A,                   /* bInterfaceClass = data */
-       0x00,                   /* bInterfaceSubClass */
-       0x00,                   /* bInterfaceProtocol */
-       0x00,                   /* iInterface */
-
-       /* Data EP OUT */
-       0x07,
-       AO_USB_DESC_ENDPOINT,
-       AO_USB_OUT_EP,          /* bEndpointAddress */
-       0x02,                   /* bmAttributes = bulk */
-       LE_WORD(AO_USB_OUT_SIZE),/* wMaxPacketSize */
-       0x00,                   /* bInterval */
-
-       /* Data EP in */
-       0x07,
-       AO_USB_DESC_ENDPOINT,
-       AO_USB_IN_EP|0x80,      /* bEndpointAddress */
-       0x02,                   /* bmAttributes = bulk */
-       LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */
-       0x00,                   /* bInterval */
-
-       /* String descriptors */
-       0x04,
-       AO_USB_DESC_STRING,
-       LE_WORD(0x0409),
-
-       /* iManufacturer */
-       AO_iManufacturer_LEN,
-       AO_USB_DESC_STRING,
-       AO_iManufacturer_UCS2,
-
-       /* iProduct */
-       AO_iProduct_LEN,
-       AO_USB_DESC_STRING,
-       AO_iProduct_UCS2,
-
-       /* iSerial */
-       AO_iSerial_LEN,
-       AO_USB_DESC_STRING,
-       AO_iSerial_UCS2,
-
-       /* Terminating zero */
-       0
-};
-#endif
diff --git a/src/core/ao_pyro.c b/src/core/ao_pyro.c
deleted file mode 100644 (file)
index e59f5bc..0000000
+++ /dev/null
@@ -1,518 +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_FLIGHT_TEST
-#include <ao.h>
-#include <ao_sample.h>
-#include <ao_flight.h>
-#endif
-#include <ao_pyro.h>
-
-#if IS_COMPANION
-#include <ao_companion.h>
-#define ao_accel ao_companion_command.accel
-#define ao_speed ao_companion_command.speed
-#define ao_height ao_companion_command.height
-#define ao_flight_state ao_companion_command.flight_state
-#define ao_motor_number ao_companion_command.motor_number
-#endif
-
-#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
- * of the requirements
- */
-static uint8_t
-ao_pyro_ready(struct ao_pyro *pyro)
-{
-       enum ao_pyro_flag flag, flags;
-
-       flags = pyro->flags;
-       while (flags != ao_pyro_none) {
-               flag = ao_lowbit(flags);
-               flags &= ~flag;
-               switch (flag) {
-
-               case ao_pyro_accel_less:
-                       if (ao_accel <= pyro->accel_less)
-                               continue;
-                       break;
-               case ao_pyro_accel_greater:
-                       if (ao_accel >= pyro->accel_greater)
-                               continue;
-                       break;
-
-
-               case ao_pyro_speed_less:
-                       if (ao_speed <= pyro->speed_less)
-                               continue;
-                       break;
-               case ao_pyro_speed_greater:
-                       if (ao_speed >= pyro->speed_greater)
-                               continue;
-                       break;
-
-               case ao_pyro_height_less:
-                       if (ao_height <= pyro->height_less)
-                               continue;
-                       break;
-               case ao_pyro_height_greater:
-                       if (ao_height >= pyro->height_greater)
-                               continue;
-                       break;
-
-#if HAS_GYRO
-               case ao_pyro_orient_less:
-                       if (ao_sample_orient <= pyro->orient_less)
-                               continue;
-                       break;
-               case ao_pyro_orient_greater:
-                       if (ao_sample_orient >= pyro->orient_greater)
-                               continue;
-                       break;
-#endif
-
-               case ao_pyro_time_less:
-                       if ((int16_t) (ao_time() - ao_boost_tick) <= pyro->time_less)
-                               continue;
-                       break;
-               case ao_pyro_time_greater:
-                       if ((int16_t) (ao_time() - ao_boost_tick) >= pyro->time_greater)
-                               continue;
-                       break;
-
-               case ao_pyro_ascending:
-                       if (ao_speed > 0)
-                               continue;
-                       break;
-               case ao_pyro_descending:
-                       if (ao_speed < 0)
-                               continue;
-                       break;
-
-               case ao_pyro_after_motor:
-                       if (ao_motor_number == pyro->motor)
-                               continue;
-                       break;
-
-               case ao_pyro_delay:
-                       /* handled separately */
-                       continue;
-
-               case ao_pyro_state_less:
-                       if (ao_flight_state < pyro->state_less)
-                               continue;
-                       break;
-               case ao_pyro_state_greater_or_equal:
-                       if (ao_flight_state >= pyro->state_greater_or_equal)
-                               continue;
-                       break;
-
-               default:
-                       continue;
-               }
-               return FALSE;
-       }
-       return TRUE;
-}
-
-#ifndef AO_FLIGHT_TEST
-static void
-ao_pyro_pin_set(uint8_t p, uint8_t v)
-{
-       switch (p) {
-#if AO_PYRO_NUM > 0
-       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_gpio_set(AO_PYRO_PORT_1, AO_PYRO_PIN_1, AO_PYRO_1, v); break;
-#endif
-#if AO_PYRO_NUM > 2
-       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_gpio_set(AO_PYRO_PORT_3, AO_PYRO_PIN_3, AO_PYRO_3, v); break;
-#endif
-#if AO_PYRO_NUM > 4
-       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_gpio_set(AO_PYRO_PORT_5, AO_PYRO_PIN_5, AO_PYRO_5, v); break;
-#endif
-#if AO_PYRO_NUM > 6
-       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_gpio_set(AO_PYRO_PORT_7, AO_PYRO_PIN_7, AO_PYRO_7, v); break;
-#endif
-       default: break;
-       }
-}
-#endif
-
-uint8_t        ao_pyro_wakeup;
-
-static void
-ao_pyro_pins_fire(uint16_t fire)
-{
-       uint8_t p;
-
-       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));
-}
-
-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 disabled igniters
-                */
-               if (!pyro->flags)
-                       continue;
-
-               any_waiting = 1;
-               /* Check pyro state to see if it should 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;
-                               if (!pyro->delay_done)
-                                       pyro->delay_done = 1;
-                       }
-               }
-
-               /* 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;
-               }
-
-               fire |= (1 << p);
-       }
-
-       if (fire)
-               ao_pyro_pins_fire(fire);
-
-       return any_waiting;
-}
-
-#define NO_VALUE       0xff
-
-#define AO_PYRO_NAME_LEN       3
-
-#if !DISABLE_HELP
-#define ENABLE_HELP 1
-#endif
-
-#if ENABLE_HELP
-#define HELP(s)        (s)
-#else
-#define HELP(s)
-#endif
-
-const struct {
-       char                    name[AO_PYRO_NAME_LEN];
-       enum ao_pyro_flag       flag;
-       uint8_t                 offset;
-#if ENABLE_HELP
-       char                    *help;
-#endif
-} ao_pyro_values[] = {
-       { "a<", ao_pyro_accel_less,     offsetof(struct ao_pyro, accel_less), HELP("accel less (m/ss * 16)") },
-       { "a>", ao_pyro_accel_greater,  offsetof(struct ao_pyro, accel_greater), HELP("accel greater (m/ss * 16)") },
-
-       { "s<", ao_pyro_speed_less,     offsetof(struct ao_pyro, speed_less), HELP("speed less (m/s * 16)") },
-       { "s>", ao_pyro_speed_greater,  offsetof(struct ao_pyro, speed_greater), HELP("speed greater (m/s * 16)") },
-
-       { "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_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
-
-       { "t<", ao_pyro_time_less,      offsetof(struct ao_pyro, time_less), HELP("time less (s * 100)") },
-       { "t>", ao_pyro_time_greater,   offsetof(struct ao_pyro, time_greater), HELP("time greater (s * 100)")  },
-
-       { "f<", ao_pyro_state_less,     offsetof(struct ao_pyro, state_less), HELP("state less") },
-       { "f>=",ao_pyro_state_greater_or_equal, offsetof(struct ao_pyro, state_greater_or_equal), HELP("state greater or equal")  },
-
-       { "A", ao_pyro_ascending,       NO_VALUE, HELP("ascending") },
-       { "D", ao_pyro_descending,      NO_VALUE, HELP("descending") },
-
-       { "m", ao_pyro_after_motor,     offsetof(struct ao_pyro, motor), HELP("after motor") },
-
-       { "d", ao_pyro_delay,           offsetof(struct ao_pyro, delay), HELP("delay before firing (s * 100)") },
-       { "", 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)
-{
-       const char *s = ao_pyro_values[v].name;
-       printf ("%s%s", s, "   " + strlen(s));
-}
-
-#if ENABLE_HELP
-static void
-ao_pyro_help(void)
-{
-       uint8_t v;
-       for (v = 0; ao_pyro_values[v].flag != ao_pyro_none; v++) {
-               ao_pyro_print_name(v);
-               if (ao_pyro_values[v].offset != NO_VALUE)
-                       printf ("<n> ");
-               else
-                       printf ("    ");
-               printf ("%s\n", ao_pyro_values[v].help);
-       }
-}
-#endif
-
-void
-ao_pyro_show(void)
-{
-       uint8_t         p;
-       uint8_t         v;
-       struct ao_pyro  *pyro;
-
-       printf ("Pyro-count: %d\n", AO_PYRO_NUM);
-       for (p = 0; p < AO_PYRO_NUM; p++) {
-               printf ("Pyro %2d: ", p);
-               pyro = &ao_config.pyro[p];
-               if (!pyro->flags) {
-                       printf ("<disabled>\n");
-                       continue;
-               }
-               for (v = 0; ao_pyro_values[v].flag != ao_pyro_none; v++) {
-                       if (!(pyro->flags & ao_pyro_values[v].flag))
-                               continue;
-                       ao_pyro_print_name(v);
-                       if (ao_pyro_values[v].offset != NO_VALUE) {
-                               int16_t value;
-
-                               value = *((int16_t *) ((char *) pyro + ao_pyro_values[v].offset));
-                               printf ("%6d ", value);
-                       } else {
-                               printf ("       ");
-                       }
-               }
-               printf ("\n");
-       }
-}
-
-void
-ao_pyro_set(void)
-{
-       uint8_t p;
-       struct ao_pyro pyro_tmp;
-       char    name[AO_PYRO_NAME_LEN];
-       uint8_t c;
-       uint8_t v;
-
-       ao_cmd_white();
-
-#if ENABLE_HELP
-       switch (ao_cmd_lex_c) {
-       case '?':
-               ao_pyro_help();
-               return;
-       }
-#endif
-
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       p = ao_cmd_lex_i;
-       if (AO_PYRO_NUM <= p) {
-               printf ("invalid pyro channel %d\n", p);
-               return;
-       }
-       pyro_tmp.flags = 0;
-       for (;;) {
-               ao_cmd_white();
-               if (ao_cmd_lex_c == '\n')
-                       break;
-
-               for (c = 0; c < AO_PYRO_NAME_LEN - 1; c++) {
-                       if (ao_cmd_is_white())
-                               break;
-                       name[c] = ao_cmd_lex_c;
-                       ao_cmd_lex();
-               }
-               name[c] = '\0';
-               for (v = 0; ao_pyro_values[v].flag != ao_pyro_none; v++) {
-                       if (!strcmp (ao_pyro_values[v].name, name))
-                               break;
-               }
-               if (ao_pyro_values[v].flag == ao_pyro_none) {
-                       printf ("invalid pyro field %s\n", name);
-                       ao_cmd_status = ao_cmd_syntax_error;
-                       return;
-               }
-               pyro_tmp.flags |= ao_pyro_values[v].flag;
-               if (ao_pyro_values[v].offset != NO_VALUE) {
-                       ao_cmd_decimal();
-                       if (ao_cmd_status != ao_cmd_success)
-                               return;
-                       *((int16_t *) ((char *) &pyro_tmp + ao_pyro_values[v].offset)) = ao_cmd_lex_i;
-               }
-       }
-       _ao_config_edit_start();
-       ao_config.pyro[p] = pyro_tmp;
-       _ao_config_edit_finish();
-}
-
-void
-ao_pyro_manual(uint8_t p)
-{
-       printf ("ao_pyro_manual %d\n", p);
-       if (p >= AO_PYRO_NUM) {
-               ao_cmd_status = ao_cmd_syntax_error;
-               return;
-       }
-       ao_pyro_pins_fire(1 << p);
-}
-
-void
-ao_pyro_init(void)
-{
-#if AO_PYRO_NUM > 0
-       ao_enable_output(AO_PYRO_PORT_0, AO_PYRO_PIN_0, AO_PYRO_0, 0);
-#endif
-#if AO_PYRO_NUM > 1
-       ao_enable_output(AO_PYRO_PORT_1, AO_PYRO_PIN_1, AO_PYRO_1, 0);
-#endif
-#if AO_PYRO_NUM > 2
-       ao_enable_output(AO_PYRO_PORT_2, AO_PYRO_PIN_2, AO_PYRO_2, 0);
-#endif
-#if AO_PYRO_NUM > 3
-       ao_enable_output(AO_PYRO_PORT_3, AO_PYRO_PIN_3, AO_PYRO_3, 0);
-#endif
-#if AO_PYRO_NUM > 4
-       ao_enable_output(AO_PYRO_PORT_4, AO_PYRO_PIN_4, AO_PYRO_4, 0);
-#endif
-#if AO_PYRO_NUM > 5
-       ao_enable_output(AO_PYRO_PORT_5, AO_PYRO_PIN_5, AO_PYRO_5, 0);
-#endif
-#if AO_PYRO_NUM > 6
-       ao_enable_output(AO_PYRO_PORT_6, AO_PYRO_PIN_6, AO_PYRO_6, 0);
-#endif
-#if AO_PYRO_NUM > 7
-       ao_enable_output(AO_PYRO_PORT_7, AO_PYRO_PIN_7, AO_PYRO_7, 0);
-#endif
-       ao_add_task(&ao_pyro_task, ao_pyro, "pyro");
-}
-#endif
diff --git a/src/core/ao_pyro.h b/src/core/ao_pyro.h
deleted file mode 100644 (file)
index 0c5642d..0000000
+++ /dev/null
@@ -1,83 +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_PYRO_H_
-#define _AO_PYRO_H_
-
-enum ao_pyro_flag {
-       ao_pyro_none                    = 0x00000000,
-
-       ao_pyro_accel_less              = 0x00000001,
-       ao_pyro_accel_greater           = 0x00000002,
-
-       ao_pyro_speed_less              = 0x00000004,
-       ao_pyro_speed_greater           = 0x00000008,
-
-       ao_pyro_height_less             = 0x00000010,
-       ao_pyro_height_greater          = 0x00000020,
-
-       ao_pyro_orient_less             = 0x00000040,
-       ao_pyro_orient_greater          = 0x00000080,
-
-       ao_pyro_time_less               = 0x00000100,
-       ao_pyro_time_greater            = 0x00000200,
-
-       ao_pyro_ascending               = 0x00000400,
-       ao_pyro_descending              = 0x00000800,
-
-       ao_pyro_after_motor             = 0x00001000,
-
-       ao_pyro_delay                   = 0x00002000,
-
-       ao_pyro_state_less              = 0x00004000,
-       ao_pyro_state_greater_or_equal  = 0x00008000,
-};
-
-struct ao_pyro {
-       enum ao_pyro_flag       flags;
-       int16_t                 accel_less, accel_greater;
-       int16_t                 speed_less, speed_greater;
-       int16_t                 height_less, height_greater;
-       int16_t                 orient_less, orient_greater;
-       int16_t                 time_less, time_greater;
-       int16_t                 delay;
-       uint8_t                 state_less, state_greater_or_equal;
-       int16_t                 motor;
-       uint16_t                delay_done;
-       uint8_t                 fired;
-};
-
-extern uint8_t ao_pyro_wakeup;
-
-extern uint16_t        ao_pyro_fired;
-
-void
-ao_pyro_set(void);
-
-void
-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
deleted file mode 100644 (file)
index 044f160..0000000
+++ /dev/null
@@ -1,249 +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_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_radio_cmac.c b/src/core/ao_radio_cmac.c
deleted file mode 100644 (file)
index bff848f..0000000
+++ /dev/null
@@ -1,164 +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_radio_cmac.h>
-
-static __xdata uint8_t ao_radio_cmac_mutex;
-__pdata int8_t ao_radio_cmac_rssi;
-static __xdata uint8_t cmac_data[AO_CMAC_MAX_LEN + AO_CMAC_KEY_LEN + 2 + AO_CMAC_KEY_LEN];
-
-static uint8_t
-round_len(uint8_t len)
-{
-       uint8_t rem;
-
-       /* Make sure we transfer at least one packet, and
-        * then make sure every packet is full. Note that
-        * there is no length encoded, and that the receiver
-        * must deal with any extra bytes in the packet
-        */
-       if (len < AO_CMAC_KEY_LEN)
-               len = AO_CMAC_KEY_LEN;
-       rem = len % AO_CMAC_KEY_LEN;
-       if (rem != 0)
-               len += (AO_CMAC_KEY_LEN - rem);
-       return len;
-}
-
-/*
- * Sign and deliver the data sitting in the cmac buffer
- */
-static void
-radio_cmac_send(uint8_t len) __reentrant
-{
-       uint8_t i;
-
-       len = round_len(len);
-       /* Make sure the AES key is loaded */
-       ao_config_get();
-
-#if HAS_MONITOR
-       ao_monitor_set(0);
-#endif
-
-       ao_mutex_get(&ao_aes_mutex);
-       ao_aes_set_mode(ao_aes_mode_cbc_mac);
-       ao_aes_set_key(ao_config.aes_key);
-       ao_aes_zero_iv();
-       for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
-               if (i + AO_CMAC_KEY_LEN < len)
-                       ao_aes_run(&cmac_data[i], NULL);
-               else
-                       ao_aes_run(&cmac_data[i], &cmac_data[len]);
-       }
-       ao_mutex_put(&ao_aes_mutex);
-
-       ao_radio_send(cmac_data, len + AO_CMAC_KEY_LEN);
-}
-
-/*
- * Receive and validate an incoming packet
- */
-
-static int8_t
-radio_cmac_recv(uint8_t len, uint16_t timeout) __reentrant
-{
-       uint8_t i;
-
-       len = round_len(len);
-#if HAS_MONITOR
-       ao_monitor_set(0);
-#endif
-       i = ao_radio_recv(cmac_data, len + AO_CMAC_KEY_LEN + 2, timeout);
-
-       if (!i) {
-               ao_radio_cmac_rssi = 0;
-               return AO_RADIO_CMAC_TIMEOUT;
-       }
-
-       ao_radio_cmac_rssi = ao_radio_rssi;
-       if (!(cmac_data[len + AO_CMAC_KEY_LEN +1] & AO_RADIO_STATUS_CRC_OK))
-               return AO_RADIO_CMAC_CRC_ERROR;
-
-       ao_config_get();
-
-       /* Compute the packet signature
-        */
-       ao_mutex_get(&ao_aes_mutex);
-       ao_aes_set_mode(ao_aes_mode_cbc_mac);
-       ao_aes_set_key(ao_config.aes_key);
-       ao_aes_zero_iv();
-       for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
-               if (i + AO_CMAC_KEY_LEN < len)
-                       ao_aes_run(&cmac_data[i], NULL);
-               else
-                       ao_aes_run(&cmac_data[i], &cmac_data[len + AO_CMAC_KEY_LEN + 2]);
-       }
-       ao_mutex_put(&ao_aes_mutex);
-
-       /* Check the packet signature against the signature provided
-        * over the link
-        */
-        
-       if (memcmp(&cmac_data[len],
-                  &cmac_data[len + AO_CMAC_KEY_LEN + 2],
-                  AO_CMAC_KEY_LEN) != 0) {
-               return AO_RADIO_CMAC_MAC_ERROR;
-       }
-
-       return AO_RADIO_CMAC_OK;
-}
-
-int8_t
-ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant
-{
-       if (len > AO_CMAC_MAX_LEN)
-               return AO_RADIO_CMAC_LEN_ERROR;
-       ao_mutex_get(&ao_radio_cmac_mutex);
-       ao_xmemcpy(cmac_data, packet, len);
-#if AO_LED_TX
-       ao_led_on(AO_LED_TX);
-#endif
-       radio_cmac_send(len);
-#if AO_LED_TX
-       ao_led_off(AO_LED_TX);
-#endif
-       ao_mutex_put(&ao_radio_cmac_mutex);
-       return AO_RADIO_CMAC_OK;
-}
-
-int8_t
-ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant
-{
-       int8_t  i;
-       if (len > AO_CMAC_MAX_LEN)
-               return AO_RADIO_CMAC_LEN_ERROR;
-       ao_mutex_get(&ao_radio_cmac_mutex);
-#if AO_LED_RX
-       ao_led_on(AO_LED_RX);
-#endif
-       i = radio_cmac_recv(len, timeout);
-#if AO_LED_RX
-       ao_led_off(AO_LED_RX);
-#endif
-       if (i == AO_RADIO_CMAC_OK)
-               ao_xmemcpy(packet, cmac_data, len);
-       ao_mutex_put(&ao_radio_cmac_mutex);
-       return i;
-}
-
diff --git a/src/core/ao_radio_cmac.h b/src/core/ao_radio_cmac.h
deleted file mode 100644 (file)
index e86f31e..0000000
+++ /dev/null
@@ -1,43 +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_RADIO_CMAC_H_
-#define _AO_RADIO_CMAC_H_
-
-#include <ao_aes.h>
-
-#define AO_CMAC_KEY_LEN                AO_AES_LEN
-#define AO_CMAC_MAX_LEN                (128 - AO_CMAC_KEY_LEN)
-
-extern __pdata int8_t ao_radio_cmac_rssi;
-
-int8_t
-ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant;
-
-#define AO_RADIO_CMAC_OK       0
-#define AO_RADIO_CMAC_LEN_ERROR        -1
-#define AO_RADIO_CMAC_CRC_ERROR        -2
-#define AO_RADIO_CMAC_MAC_ERROR        -3
-#define AO_RADIO_CMAC_TIMEOUT  -4
-
-int8_t
-ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant;
-
-void
-ao_radio_cmac_init(void);
-
-#endif /* _AO_RADIO_CMAC_H_ */
diff --git a/src/core/ao_radio_cmac_cmd.c b/src/core/ao_radio_cmac_cmd.c
deleted file mode 100644 (file)
index 6441092..0000000
+++ /dev/null
@@ -1,104 +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_radio_cmac_cmd.h>
-#include <ao_radio_cmac.h>
-
-static __xdata uint8_t cmac_data[AO_CMAC_MAX_LEN];
-
-static uint8_t
-getnibble(void)
-{
-       int8_t  b;
-
-       b = ao_cmd_hexchar(getchar());
-       if (b < 0) {
-               ao_cmd_status = ao_cmd_lex_error;
-               return 0;
-       }
-       return (uint8_t) b;
-}
-
-static uint8_t
-getbyte(void)
-{
-       uint8_t b;
-       b = getnibble() << 4;
-       b |= getnibble();
-       return b;
-}
-       
-static void
-radio_cmac_send_cmd(void) __reentrant
-{
-       uint8_t i;
-       uint8_t len;
-
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       len = ao_cmd_lex_i;
-       if (len > AO_CMAC_MAX_LEN) {
-               ao_cmd_status = ao_cmd_syntax_error;
-               return;
-       }
-       flush();
-       len = ao_cmd_lex_i;
-       for (i = 0; i < len; i++) {
-               cmac_data[i] = getbyte();
-               if (ao_cmd_status != ao_cmd_success)
-                       return;
-       }
-       ao_radio_cmac_send(cmac_data, len);
-}
-
-static void
-radio_cmac_recv_cmd(void) __reentrant
-{
-       uint8_t         len, i;
-       uint16_t        timeout;
-
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       len = ao_cmd_lex_i;
-       ao_cmd_decimal();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       timeout = AO_MS_TO_TICKS(ao_cmd_lex_i);
-       i = ao_radio_cmac_recv(cmac_data, len, timeout);
-       if (i == AO_RADIO_CMAC_OK) {
-               printf ("PACKET ");
-               for (i = 0; i < len; i++)
-                       printf("%02x", cmac_data[i]);
-               printf (" %d\n", ao_radio_cmac_rssi);
-       } else
-               printf ("ERROR %d %d\n", i, ao_radio_cmac_rssi);
-}
-
-static __code struct ao_cmds ao_radio_cmac_cmds[] = {
-       { radio_cmac_send_cmd,  "s <length>\0Send AES-CMAC packet. Bytes to send follow on next line" },
-       { radio_cmac_recv_cmd,  "S <length> <timeout>\0Receive AES-CMAC packet. Timeout in ms" },
-       { 0, NULL },
-};
-
-void
-ao_radio_cmac_cmd_init(void)
-{
-       ao_cmd_register(&ao_radio_cmac_cmds[0]);
-}
diff --git a/src/core/ao_radio_cmac_cmd.h b/src/core/ao_radio_cmac_cmd.h
deleted file mode 100644 (file)
index 6b8782d..0000000
+++ /dev/null
@@ -1,24 +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_RADIO_CMAC_CMD_H_
-#define _AO_RADIO_CMAC_CMD_H_
-
-void
-ao_radio_cmac_cmd_init(void);
-
-#endif /* _AO_RADIO_CMAC_CMD_H_ */
diff --git a/src/core/ao_report.c b/src/core/ao_report.c
deleted file mode 100644 (file)
index 1104cd8..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * 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_flight.h>
-#include <ao_sample.h>
-
-#define BIT(i,x)          ((x) ? (1 << (i)) : 0)
-#define MORSE1(a)          (1 | BIT(3,a))
-#define MORSE2(a,b)        (2 | BIT(3,a) | BIT(4,b))
-#define MORSE3(a,b,c)      (3 | BIT(3,a) | BIT(4,b) | BIT(5,c))
-#define MORSE4(a,b,c,d)    (4 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d))
-#define MORSE5(a,b,c,d,e)  (5 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d) | BIT(7,e))
-
-static const uint8_t flight_reports[] = {
-       MORSE3(0,0,0),          /* startup, 'S' */
-       MORSE2(0,0),            /* idle 'I' */
-       MORSE4(0,1,1,0),        /* pad 'P' */
-       MORSE4(1,0,0,0),        /* boost 'B' */
-       MORSE4(0,0,1,0),        /* fast 'F' */
-       MORSE4(1,0,1,0),        /* coast 'C' */
-       MORSE3(1,0,0),          /* drogue 'D' */
-       MORSE2(1,1),            /* main 'M' */
-       MORSE4(0,1,0,0),        /* landed 'L' */
-       MORSE4(1,0,0,1),        /* invalid 'X' */
-};
-
-#if HAS_BEEP
-#define low(time)      ao_beep_for(AO_BEEP_LOW, time)
-#define mid(time)      ao_beep_for(AO_BEEP_MID, time)
-#define high(time)     ao_beep_for(AO_BEEP_HIGH, time)
-#else
-#define low(time)      ao_led_for(AO_LED_GREEN, time)
-#define mid(time)      ao_led_for(AO_LED_RED, time)
-#define high(time)     ao_led_for(AO_LED_GREEN|AO_LED_RED, time)
-#endif
-#define pause(time)    ao_delay(time)
-
-static __pdata enum ao_flight_state ao_report_state;
-
-static void
-ao_report_beep(void) __reentrant
-{
-       uint8_t r = flight_reports[ao_flight_state];
-       uint8_t l = r & 7;
-
-       if (!r)
-               return;
-       while (l--) {
-               if (r & 8)
-                       mid(AO_MS_TO_TICKS(600));
-               else
-                       mid(AO_MS_TO_TICKS(200));
-               pause(AO_MS_TO_TICKS(200));
-               r >>= 1;
-       }
-       pause(AO_MS_TO_TICKS(400));
-}
-
-static void
-ao_report_digit(uint8_t digit) __reentrant
-{
-       if (!digit) {
-               mid(AO_MS_TO_TICKS(500));
-               pause(AO_MS_TO_TICKS(200));
-       } else {
-               while (digit--) {
-                       mid(AO_MS_TO_TICKS(200));
-                       pause(AO_MS_TO_TICKS(200));
-               }
-       }
-       pause(AO_MS_TO_TICKS(300));
-}
-
-static void
-ao_report_altitude(void)
-{
-       __pdata int16_t agl = ao_max_height;
-       __xdata uint8_t digits[10];
-       __pdata uint8_t ndigits, i;
-
-       if (agl < 0)
-               agl = 0;
-       ndigits = 0;
-       do {
-               digits[ndigits++] = agl % 10;
-               agl /= 10;
-       } while (agl);
-
-       i = ndigits;
-       do
-               ao_report_digit(digits[--i]);
-       while (i != 0);
-}
-
-#if HAS_IGNITE_REPORT
-static uint8_t
-ao_report_igniter_ready(enum ao_igniter igniter)
-{
-       return ao_igniter_status(igniter) == ao_igniter_ready ? 1 : 0;
-}
-
-uint8_t
-ao_report_igniter(void)
-{
-       return (ao_report_igniter_ready(ao_igniter_drogue) |
-                    (ao_report_igniter_ready(ao_igniter_main) << 1));
-}
-
-static void
-ao_report_continuity(void) __reentrant
-{
-       uint8_t c;
-
-#if !HAS_IGNITE
-       if (!ao_igniter_present)
-               return;
-#endif
-       c = ao_report_igniter();
-       if (c) {
-               while (c--) {
-                       high(AO_MS_TO_TICKS(25));
-                       pause(AO_MS_TO_TICKS(100));
-               }
-       } else {
-               c = 10;
-               while (c--) {
-                       high(AO_MS_TO_TICKS(20));
-                       low(AO_MS_TO_TICKS(20));
-               }
-       }
-#if HAS_LOG
-       if (ao_log_full()) {
-               pause(AO_MS_TO_TICKS(100));
-               c = 2;
-               while (c--) {
-                       low(AO_MS_TO_TICKS(100));
-                       mid(AO_MS_TO_TICKS(100));
-                       high(AO_MS_TO_TICKS(100));
-                       mid(AO_MS_TO_TICKS(100));
-               }
-       }
-#endif
-}
-#endif
-
-void
-ao_report(void)
-{
-       ao_report_state = ao_flight_state;
-       for(;;) {
-               ao_report_beep();
-               if (ao_flight_state == ao_flight_landed) {
-                       ao_report_altitude();
-#if HAS_FLIGHT
-                       ao_delay(AO_SEC_TO_TICKS(5));
-                       continue;
-#endif
-               }
-#if HAS_IGNITE_REPORT
-               if (ao_flight_state == ao_flight_idle)
-                       ao_report_continuity();
-               while (ao_flight_state == ao_flight_pad) {
-                       uint8_t c;
-                       ao_report_continuity();
-                       c = 50;
-                       while (c-- && ao_flight_state == ao_flight_pad)
-                               pause(AO_MS_TO_TICKS(100));
-               }
-#endif
-
-               while (ao_report_state == ao_flight_state)
-                       ao_sleep(DATA_TO_XDATA(&ao_flight_state));
-               ao_report_state = ao_flight_state;
-       }
-}
-
-static __xdata struct ao_task ao_report_task;
-
-void
-ao_report_init(void)
-{
-       ao_add_task(&ao_report_task, ao_report, "report");
-}
diff --git a/src/core/ao_report_micro.c b/src/core/ao_report_micro.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/core/ao_rssi.c b/src/core/ao_rssi.c
deleted file mode 100644 (file)
index 244a84f..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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"
-
-static __xdata uint16_t        ao_rssi_time;
-static __pdata uint16_t        ao_rssi_delay;
-static __pdata uint8_t ao_rssi_led;
-
-void
-ao_rssi(void)
-{
-       for (;;) {
-               while ((int16_t) (ao_time() - ao_rssi_time) > AO_SEC_TO_TICKS(3))
-                       ao_sleep(&ao_rssi_time);
-               ao_led_for(ao_rssi_led, AO_MS_TO_TICKS(100));
-               ao_delay(ao_rssi_delay);
-       }
-}
-
-void
-ao_rssi_set(int rssi_value)
-{
-       if (rssi_value > 0)
-               rssi_value = 0;
-       ao_rssi_delay = AO_MS_TO_TICKS((-rssi_value) * 5);
-       ao_rssi_time = ao_time();
-       ao_wakeup(&ao_rssi_time);
-}
-
-__xdata struct ao_task ao_rssi_task;
-
-void
-ao_rssi_init(uint8_t rssi_led)
-{
-       ao_rssi_led = rssi_led;
-       ao_rssi_delay = 0;
-       ao_add_task(&ao_rssi_task, ao_rssi, "rssi");
-}
diff --git a/src/core/ao_sample.c b/src/core/ao_sample.c
deleted file mode 100644 (file)
index 3465895..0000000
+++ /dev/null
@@ -1,372 +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.
- */
-
-#ifndef AO_FLIGHT_TEST
-#include "ao.h"
-#include <ao_data.h>
-#endif
-
-#if HAS_GYRO
-#include <ao_quaternion.h>
-#endif
-
-/*
- * Current sensor values
- */
-
-#ifndef PRES_TYPE
-#define PRES_TYPE int32_t
-#define ALT_TYPE int32_t
-#define ACCEL_TYPE int16_t
-#endif
-
-__pdata uint16_t       ao_sample_tick;         /* time of last data */
-__pdata pres_t         ao_sample_pres;
-__pdata alt_t          ao_sample_alt;
-__pdata alt_t          ao_sample_height;
-#if HAS_ACCEL
-__pdata accel_t                ao_sample_accel;
-#endif
-#if HAS_GYRO
-__pdata accel_t                ao_sample_accel_along;
-__pdata accel_t                ao_sample_accel_across;
-__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_orient;
-#endif
-
-__data uint8_t         ao_sample_data;
-
-/*
- * Sensor calibration values
- */
-
-__pdata pres_t         ao_ground_pres;         /* startup pressure */
-__pdata alt_t          ao_ground_height;       /* MSL of ao_ground_pres */
-
-#if HAS_ACCEL
-__pdata accel_t                ao_ground_accel;        /* startup acceleration */
-__pdata accel_t                ao_accel_2g;            /* factory accel calibration */
-__pdata int32_t                ao_accel_scale;         /* sensor to m/s² conversion */
-#endif
-
-#if HAS_GYRO
-__pdata accel_t                ao_ground_accel_along;
-__pdata accel_t                ao_ground_accel_across;
-__pdata accel_t                ao_ground_accel_through;
-__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 */
-
-static __pdata uint16_t        nsamples;
-__pdata int32_t ao_sample_pres_sum;
-#if HAS_ACCEL
-__pdata int32_t ao_sample_accel_sum;
-#endif
-#if HAS_GYRO
-__pdata int32_t ao_sample_accel_along_sum;
-__pdata int32_t ao_sample_accel_across_sum;
-__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
-
-#if HAS_FLIGHT_DEBUG
-extern uint8_t ao_orient_test;
-#endif
-
-static void
-ao_sample_preflight_add(void)
-{
-#if HAS_ACCEL
-       ao_sample_accel_sum += ao_sample_accel;
-#endif
-       ao_sample_pres_sum += ao_sample_pres;
-#if HAS_GYRO
-       ao_sample_accel_along_sum += ao_sample_accel_along;
-       ao_sample_accel_across_sum += ao_sample_accel_across;
-       ao_sample_accel_through_sum += ao_sample_accel_through;
-       ao_sample_pitch_sum += ao_sample_pitch;
-       ao_sample_yaw_sum += ao_sample_yaw;
-       ao_sample_roll_sum += ao_sample_roll;
-#endif
-       ++nsamples;
-}
-
-static void
-ao_sample_preflight_set(void)
-{
-#if HAS_ACCEL
-       ao_ground_accel = ao_sample_accel_sum >> 9;
-       ao_sample_accel_sum = 0;
-#endif
-       ao_ground_pres = ao_sample_pres_sum >> 9;
-       ao_ground_height = pres_to_altitude(ao_ground_pres);
-       ao_sample_pres_sum = 0;
-#if HAS_GYRO
-       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;
-       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_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);
-#if HAS_FLIGHT_DEBUG
-       if (ao_orient_test)
-               printf("\n\treset\n");
-#endif 
-#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);
-
-#if HAS_FLIGHT_DEBUG
-       if (ao_orient_test) {
-               printf ("rot %d %d %d orient %d     \r",
-                       (int) (x * 1000),
-                       (int) (y * 1000),
-                       (int) (z * 1000),
-                       ao_sample_orient);
-       }
-#endif
-
-}
-#endif
-
-static void
-ao_sample_preflight(void)
-{
-       /* startup state:
-        *
-        * Collect 512 samples of acceleration and pressure
-        * data and average them to find the resting values
-        */
-       if (nsamples < 512) {
-               ao_sample_preflight_add();
-       } else {
-#if HAS_ACCEL
-               ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g;
-               ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g;
-#endif
-               ao_sample_preflight_set();
-               ao_preflight = FALSE;
-       }
-}
-
-/*
- * While in pad mode, constantly update the ground state by
- * re-averaging the data.  This tracks changes in orientation, which
- * might be caused by adjustments to the rocket on the pad and
- * pressure, which might be caused by changes in the weather.
- */
-
-static void
-ao_sample_preflight_update(void)
-{
-       if (nsamples < 512)
-               ao_sample_preflight_add();
-       else if (nsamples < 1024)
-               ++nsamples;
-       else
-               ao_sample_preflight_set();
-}
-
-#if 0
-#if HAS_GYRO
-static int32_t p_filt;
-static int32_t y_filt;
-
-static gyro_t inline ao_gyro(void) {
-       gyro_t  p = ao_sample_pitch - ao_ground_pitch;
-       gyro_t  y = ao_sample_yaw - ao_ground_yaw;
-
-       p_filt = p_filt - (p_filt >> 6) + p;
-       y_filt = y_filt - (y_filt >> 6) + y;
-
-       p = p_filt >> 6;
-       y = y_filt >> 6;
-       return ao_sqrt(p*p + y*y);
-}
-#endif
-#endif
-
-uint8_t
-ao_sample(void)
-{
-       ao_wakeup(DATA_TO_XDATA(&ao_sample_data));
-       ao_sleep((void *) DATA_TO_XDATA(&ao_data_head));
-       while (ao_sample_data != ao_data_head) {
-               __xdata struct ao_data *ao_data;
-
-               /* Capture a sample */
-               ao_data = (struct ao_data *) &ao_data_ring[ao_sample_data];
-               ao_sample_tick = ao_data->tick;
-
-#if HAS_BARO
-               ao_data_pres_cook(ao_data);
-               ao_sample_pres = ao_data_pres(ao_data);
-               ao_sample_alt = pres_to_altitude(ao_sample_pres);
-               ao_sample_height = ao_sample_alt - ao_ground_height;
-#endif
-
-#if HAS_ACCEL
-               ao_sample_accel = ao_data_accel_cook(ao_data);
-               if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
-                       ao_sample_accel = ao_data_accel_invert(ao_sample_accel);
-               ao_data_set_accel(ao_data, ao_sample_accel);
-#endif
-#if HAS_GYRO
-               ao_sample_accel_along = ao_data_along(ao_data);
-               ao_sample_accel_across = ao_data_across(ao_data);
-               ao_sample_accel_through = ao_data_through(ao_data);
-               ao_sample_pitch = ao_data_pitch(ao_data);
-               ao_sample_yaw = ao_data_yaw(ao_data);
-               ao_sample_roll = ao_data_roll(ao_data);
-#endif
-
-               if (ao_preflight)
-                       ao_sample_preflight();
-               else {
-                       if (ao_flight_state < ao_flight_boost)
-                               ao_sample_preflight_update();
-                       ao_kalman();
-#if HAS_GYRO
-                       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;
-}
-
-void
-ao_sample_init(void)
-{
-       ao_config_get();
-       nsamples = 0;
-       ao_sample_pres_sum = 0;
-       ao_sample_pres = 0;
-#if HAS_ACCEL
-       ao_sample_accel_sum = 0;
-       ao_sample_accel = 0;
-#endif
-#if HAS_GYRO
-       ao_sample_accel_along_sum = 0;
-       ao_sample_accel_across_sum = 0;
-       ao_sample_accel_through_sum = 0;
-       ao_sample_accel_along = 0;
-       ao_sample_accel_across = 0;
-       ao_sample_accel_through = 0;
-       ao_sample_pitch_sum = 0;
-       ao_sample_yaw_sum = 0;
-       ao_sample_roll_sum = 0;
-       ao_sample_pitch = 0;
-       ao_sample_yaw = 0;
-       ao_sample_roll = 0;
-       ao_sample_orient = 0;
-#endif
-       ao_sample_data = ao_data_head;
-       ao_preflight = TRUE;
-}
diff --git a/src/core/ao_sample.h b/src/core/ao_sample.h
deleted file mode 100644 (file)
index 16d4c50..0000000
+++ /dev/null
@@ -1,156 +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_SAMPLE_H_
-#define _AO_SAMPLE_H_
-
-#include <ao_data.h>
-
-/*
- * ao_sample.c
- */
-
-/*
- * Barometer calibration
- *
- * We directly sample the barometer. The specs say:
- *
- * Pressure range: 15-115 kPa
- * Voltage at 115kPa: 2.82
- * Output scale: 27mV/kPa
- *
- * If we want to detect launch with the barometer, we need
- * a large enough bump to not be fooled by noise. At typical
- * launch elevations (0-2000m), a 200Pa pressure change cooresponds
- * to about a 20m elevation change. This is 5.4mV, or about 3LSB.
- * As all of our calculations are done in 16 bits, we'll actually see a change
- * of 16 times this though
- *
- * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa
- */
-
-/* Accelerometer calibration
- *
- * We're sampling the accelerometer through a resistor divider which
- * consists of 5k and 10k resistors. This multiplies the values by 2/3.
- * That goes into the cc1111 A/D converter, which is running at 11 bits
- * of precision with the bits in the MSB of the 16 bit value. Only positive
- * values are used, so values should range from 0-32752 for 0-3.3V. The
- * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what
- * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV,
- * for a final computation of:
- *
- * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g
- *
- * Zero g was measured at 16000 (we would expect 16384).
- * Note that this value is only require to tell if the
- * rocket is standing upright. Once that is determined,
- * the value of the accelerometer is averaged for 100 samples
- * to find the resting accelerometer value, which is used
- * for all further flight computations
- */
-
-/*
- * Above this height, the baro sensor doesn't work
- */
-#if HAS_MS5607
-#define AO_MAX_BARO_HEIGHT     30000
-#else
-#define AO_MAX_BARO_HEIGHT     12000
-#endif
-
-/*
- * Above this speed, baro measurements are unreliable
- */
-#define AO_MAX_BARO_SPEED      200
-
-#define ACCEL_NOSE_UP  (ao_accel_2g >> 2)
-
-/*
- * Speed and acceleration are scaled by 16 to provide a bit more
- * resolution while still having reasonable range. Note that this
- * limits speed to 2047m/s (around mach 6) and acceleration to
- * 2047m/s² (over 200g)
- */
-
-#define AO_M_TO_HEIGHT(m)      ((int16_t) (m))
-#define AO_MS_TO_SPEED(ms)     ((int16_t) ((ms) * 16))
-#define AO_MSS_TO_ACCEL(mss)   ((int16_t) ((mss) * 16))
-
-extern __pdata uint16_t        ao_sample_tick;         /* time of last data */
-extern __data uint8_t  ao_sample_adc;          /* Ring position of last processed sample */
-extern __data uint8_t  ao_sample_data;         /* Ring position of last processed sample */
-
-#if HAS_BARO
-extern __pdata pres_t  ao_sample_pres;         /* most recent pressure sensor reading */
-extern __pdata alt_t   ao_sample_alt;          /* MSL of ao_sample_pres */
-extern __pdata alt_t   ao_sample_height;       /* AGL of ao_sample_pres */
-extern __pdata pres_t  ao_ground_pres;         /* startup pressure */
-extern __pdata alt_t   ao_ground_height;       /* MSL of ao_ground_pres */
-#endif
-
-#if HAS_ACCEL
-extern __pdata accel_t ao_sample_accel;        /* most recent accel sensor reading */
-extern __pdata accel_t ao_ground_accel;        /* startup acceleration */
-extern __pdata accel_t         ao_accel_2g;            /* factory accel calibration */
-extern __pdata int32_t ao_accel_scale;         /* sensor to m/s² conversion */
-#endif
-#if HAS_GYRO
-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 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);
-
-/* returns FALSE in preflight mode, TRUE in flight mode */
-uint8_t ao_sample(void);
-
-/*
- * ao_kalman.c
- */
-
-#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
-#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
-#define from_fix(x)    ((x) >> 16)
-
-extern __pdata int16_t                 ao_height;      /* meters */
-extern __pdata int16_t                 ao_speed;       /* m/s * 16 */
-extern __pdata int16_t                 ao_accel;       /* m/s² * 16 */
-extern __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;
-
-#if HAS_ACCEL
-extern __pdata int16_t                 ao_error_a;
-#endif
-
-void ao_kalman(void);
-
-#endif /* _AO_SAMPLE_H_ */
diff --git a/src/core/ao_sample_profile.c b/src/core/ao_sample_profile.c
deleted file mode 100644 (file)
index d3743d1..0000000
+++ /dev/null
@@ -1,173 +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_sample_profile.h>
-#include <ao_task.h>
-
-#ifndef AO_SAMPLE_PROFILE_LOW_PC
-#define AO_SAMPLE_PROFILE_LOW_PC       0x08002000
-#endif
-
-#ifndef AO_SAMPLE_PROFILE_HIGH_PC
-#define AO_SAMPLE_PROFILE_HIGH_PC      0x0800f000
-#endif
-
-#ifndef AO_SAMPLE_PROFILE_SHIFT
-#define AO_SAMPLE_PROFILE_SHIFT                6
-#endif
-
-#define AO_SAMPLE_PROFILE_RANGE                (AO_SAMPLE_PROFILE_HIGH_PC - AO_SAMPLE_PROFILE_LOW_PC)
-#define AO_SAMPLE_PROFILE_NUM          (AO_SAMPLE_PROFILE_RANGE >> AO_SAMPLE_PROFILE_SHIFT)
-
-static uint16_t        prev_tick;
-static uint16_t        samples[AO_SAMPLE_PROFILE_NUM];
-static uint8_t missed[AO_SAMPLE_PROFILE_NUM/8];
-static uint16_t max_miss;
-static uint32_t task, isr, os, idle;
-
-extern uint8_t ao_idle_loc;
-
-void
-ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr)
-{
-       uint16_t        delta = tick - prev_tick;
-
-       if (pc < AO_SAMPLE_PROFILE_LOW_PC)
-               return;
-       if (pc >= AO_SAMPLE_PROFILE_HIGH_PC)
-               return;
-       if (ao_cur_task) {
-               uint8_t         *sp;
-               int32_t         sp_delta;
-               
-               asm("mov %0,sp" : "=&r" (sp));
-               sp_delta = sp - (uint8_t *) ao_cur_task->stack;
-               if (-96 < sp_delta && sp_delta < 16)
-                       ao_panic(AO_PANIC_STACK);
-       }
-
-       if (in_isr)
-               isr += delta;
-       else if (ao_cur_task) {
-               ao_cur_task->ticks += delta;
-               task += delta;
-       } else if (pc == (uint32_t) &ao_idle_loc)
-               idle += delta;
-       else
-               os += delta;
-
-       pc -= AO_SAMPLE_PROFILE_LOW_PC;
-       pc >>= AO_SAMPLE_PROFILE_SHIFT;
-       samples[pc] += delta;
-
-       if (delta > 1)
-               missed[pc >> 3] |= (1 << (pc & 7));
-       if (delta > max_miss)
-               max_miss = delta;
-       prev_tick = tick;
-}
-
-static void
-ao_sample_profile_start(void)
-{
-       prev_tick = ao_sample_profile_timer_start();
-}
-
-static void
-ao_sample_profile_stop(void)
-{
-       ao_sample_profile_timer_stop();
-}
-
-static void
-ao_sample_profile_dump(void)
-{
-       uint16_t        a;
-       uint8_t         t;
-
-       printf ("task %6d\n", task);
-       printf ("isr  %6d\n", isr);
-       printf ("os   %6d\n", os);
-       printf ("idle %6d\n", idle);
-       printf ("irq blocked %d\n", max_miss);
-       for (t = 0; t < ao_num_tasks; t++)
-               printf ("task %6d %6d %6d %s\n",
-                       ao_tasks[t]->ticks,
-                       ao_tasks[t]->yields,
-                       ao_tasks[t]->max_run,
-                       ao_tasks[t]->name);
-       for (a = 0; a < AO_SAMPLE_PROFILE_NUM; a++) {
-               if (samples[a])
-                       printf ("%04x %c %u\n",
-                               (a << AO_SAMPLE_PROFILE_SHIFT) + AO_SAMPLE_PROFILE_LOW_PC,
-                               missed[a >> 3] & (1 << (a & 7)) ? '*' : ' ',
-                               samples[a]);
-       }
-}
-
-static void
-ao_sample_profile_clear(void)
-{
-       int t;
-
-       task = isr = os = idle = 0;
-       max_miss = 0;
-       memset(samples, '\0', sizeof (samples));
-       memset(missed, '\0', sizeof (missed));
-       for (t = 0; t < ao_num_tasks; t++) {
-               ao_tasks[t]->ticks = 0;
-               ao_tasks[t]->yields = 0;
-               ao_tasks[t]->max_run = 0;
-       }
-}
-
-static void
-ao_sample_profile_cmd(void)
-{
-       ao_cmd_white();
-       switch (ao_cmd_lex_c) {
-       case '1':
-               ao_sample_profile_start();
-               break;
-       case '0':
-               ao_sample_profile_stop();
-               break;
-       case 'd':
-               ao_sample_profile_dump();
-               break;
-       case 'c':
-               ao_sample_profile_clear();
-               break;
-       default:
-               ao_cmd_status = ao_cmd_syntax_error;
-               break;
-       }
-}
-
-static __code struct ao_cmds ao_sample_profile_cmds[] = {
-       { ao_sample_profile_cmd,        "S <1 start,0 stop, d dump,c clear>\0Sample profile" },
-       { 0, NULL }
-};
-
-void
-ao_sample_profile_init(void)
-{
-       ao_sample_profile_timer_init();
-       ao_cmd_register(&ao_sample_profile_cmds[0]);
-       ao_sample_profile_clear();
-}
diff --git a/src/core/ao_sample_profile.h b/src/core/ao_sample_profile.h
deleted file mode 100644 (file)
index dbc29d3..0000000
+++ /dev/null
@@ -1,29 +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_SAMPLE_PROFILE_H_
-#define _AO_SAMPLE_PROFILE_H_
-
-#include <ao_sample_profile_timer.h>
-
-void
-ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr);
-
-void
-ao_sample_profile_init(void);
-
-#endif /* _AO_SAMPLE_PROFILE_H_ */
diff --git a/src/core/ao_send_packet.c b/src/core/ao_send_packet.c
deleted file mode 100644 (file)
index 66315d2..0000000
+++ /dev/null
@@ -1,58 +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 AO_MAX_SEND    128
-
-static __xdata uint8_t ao_send[AO_MAX_SEND];
-
-static void
-ao_send_packet(void)
-{
-       __pdata uint16_t count;
-       uint8_t b;
-       __pdata uint8_t i;
-
-       ao_cmd_hex();
-       count = ao_cmd_lex_i;
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       if (count > AO_MAX_SEND - 2) {
-               ao_cmd_status = ao_cmd_syntax_error;
-               return;
-       }
-       for (i = 0; i < count; i++) {
-               b = ao_getnibble() << 4;
-               b |= ao_getnibble();
-               if (ao_cmd_status != ao_cmd_success)
-                       return;
-               ao_send[i] = b;
-       }
-       ao_radio_send(ao_send, count);
-}
-
-static __code struct ao_cmds ao_send_packet_cmds[] = {
-       { ao_send_packet, "S <len>\0Send packet. Data on next line" },
-       { 0, NULL }
-};
-
-void
-ao_send_packet_init(void)
-{
-       ao_cmd_register(&ao_send_packet_cmds[0]);
-}
diff --git a/src/core/ao_send_packet.h b/src/core/ao_send_packet.h
deleted file mode 100644 (file)
index 526f7b5..0000000
+++ /dev/null
@@ -1,24 +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_SEND_PACKET_H_
-#define _AO_SEND_PACKET_H_
-
-void
-ao_send_packet_init(void);
-
-#endif /* _AO_SEND_PACKET_H_ */
diff --git a/src/core/ao_serial.h b/src/core/ao_serial.h
deleted file mode 100644 (file)
index baf213c..0000000
+++ /dev/null
@@ -1,110 +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_SERIAL_H_
-#define _AO_SERIAL_H_
-
-#define AO_SERIAL_SPEED_4800   0
-#define AO_SERIAL_SPEED_9600   1
-#define AO_SERIAL_SPEED_19200  2
-#define AO_SERIAL_SPEED_57600  3
-#define AO_SERIAL_SPEED_115200 4
-
-#if HAS_SERIAL_0
-extern volatile __xdata struct ao_fifo ao_serial0_rx_fifo;
-extern volatile __xdata struct ao_fifo ao_serial0_tx_fifo;
-
-char
-ao_serial0_getchar(void);
-
-int
-_ao_serial0_pollchar(void);
-
-void
-ao_serial0_putchar(char c);
-
-void
-ao_serial0_drain(void);
-
-void
-ao_serial0_set_speed(uint8_t speed);
-#endif
-
-#if HAS_SERIAL_1
-extern volatile __xdata struct ao_fifo ao_serial1_rx_fifo;
-extern volatile __xdata struct ao_fifo ao_serial1_tx_fifo;
-
-char
-ao_serial1_getchar(void);
-
-int
-_ao_serial1_pollchar(void);
-
-void
-ao_serial1_putchar(char c);
-
-void
-ao_serial1_drain(void);
-
-void
-ao_serial1_set_speed(uint8_t speed);
-#endif
-
-#if HAS_SERIAL_2
-extern volatile __xdata struct ao_fifo ao_serial2_rx_fifo;
-extern volatile __xdata struct ao_fifo ao_serial2_tx_fifo;
-
-char
-ao_serial2_getchar(void);
-
-int
-_ao_serial2_pollchar(void);
-
-void
-ao_serial2_putchar(char c);
-
-void
-ao_serial2_drain(void);
-
-void
-ao_serial2_set_speed(uint8_t speed);
-#endif
-
-#if HAS_SERIAL_3
-extern volatile __xdata struct ao_fifo ao_serial3_rx_fifo;
-extern volatile __xdata struct ao_fifo ao_serial3_tx_fifo;
-
-char
-ao_serial3_getchar(void);
-
-int
-_ao_serial3_pollchar(void);
-
-void
-ao_serial3_putchar(char c);
-
-void
-ao_serial3_drain(void);
-
-void
-ao_serial3_set_speed(uint8_t speed);
-#endif
-
-void
-ao_serial_init(void);
-
-#endif /* _AO_SERIAL_H_ */
diff --git a/src/core/ao_sqrt.c b/src/core/ao_sqrt.c
deleted file mode 100644 (file)
index 3a550ea..0000000
+++ /dev/null
@@ -1,48 +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.
- */
-
-#ifndef AO_FLIGHT_TEST
-#include "ao.h"
-#endif
-
-/* Adapted from int_sqrt.c in the linux kernel, which is licensed GPLv2 */
-/**
- * int_sqrt - rough approximation to sqrt
- * @x: integer of which to calculate the sqrt
- *
- * A very rough approximation to the sqrt() function.
- */
-
-uint32_t
-ao_sqrt(uint32_t op)
-{
-       uint32_t        res = 0;
-       uint32_t        one = 1UL << (sizeof (one) * 8 - 2);
-
-       while (one > op)
-               one >>= 2;
-
-       while (one != 0) {
-               if (op >= res + one) {
-                       op = op - (res + one);
-                       res = res +  2 * one;
-               }
-               res /= 2;
-               one /= 4;
-       }
-       return res;
-}
diff --git a/src/core/ao_state.c b/src/core/ao_state.c
deleted file mode 100644 (file)
index ed197aa..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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"
-
-const char const * const ao_state_names[] = {
-       "startup", "idle", "pad", "boost", "fast",
-       "coast", "drogue", "main", "landed", "invalid"
-};
diff --git a/src/core/ao_stdio.c b/src/core/ao_stdio.c
deleted file mode 100644 (file)
index cd144d6..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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"
-
-/*
- * Basic I/O functions to support SDCC stdio package
- */
-
-#ifndef USE_SERIAL_0_STDIN
-#define USE_SERIAL_0_STDIN     0
-#endif
-#ifndef USE_SERIAL_1_STDIN
-#define USE_SERIAL_1_STDIN     0
-#endif
-#ifndef USE_SERIAL_2_STDIN
-#define USE_SERIAL_2_STDIN     0
-#endif
-#ifndef USE_SERIAL_3_STDIN
-#define USE_SERIAL_3_STDIN     0
-#endif
-#ifndef USE_SERIAL_4_STDIN
-#define USE_SERIAL_4_STDIN     0
-#endif
-#ifndef USE_SERIAL_5_STDIN
-#define USE_SERIAL_5_STDIN     0
-#endif
-#ifndef USE_SERIAL_6_STDIN
-#define USE_SERIAL_6_STDIN     0
-#endif
-#ifndef USE_SERIAL_7_STDIN
-#define USE_SERIAL_7_STDIN     0
-#endif
-#ifndef USE_SERIAL_8_STDIN
-#define USE_SERIAL_8_STDIN     0
-#endif
-#ifndef USE_SERIAL_9_STDIN
-#define USE_SERIAL_9_STDIN     0
-#endif
-
-#define USE_SERIAL_STDIN (USE_SERIAL_0_STDIN + \
-                         USE_SERIAL_1_STDIN +  \
-                         USE_SERIAL_2_STDIN +  \
-                         USE_SERIAL_3_STDIN +  \
-                         USE_SERIAL_4_STDIN +  \
-                         USE_SERIAL_5_STDIN +  \
-                         USE_SERIAL_6_STDIN +  \
-                         USE_SERIAL_7_STDIN +  \
-                         USE_SERIAL_8_STDIN +  \
-                         USE_SERIAL_9_STDIN)
-
-#define AO_NUM_STDIOS  (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN)
-
-__xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS];
-
-#if AO_NUM_STDIOS > 1
-__pdata int8_t ao_cur_stdio;
-__pdata int8_t ao_num_stdios;
-#else
-__pdata int8_t ao_cur_stdio;
-#define ao_cur_stdio   0
-#define ao_num_stdios  0
-#endif
-
-void
-putchar(char c)
-{
-#if LOW_LEVEL_DEBUG
-       if (!ao_cur_task) {
-               extern void ao_debug_out(char c);
-               if (c == '\n')
-                       ao_debug_out('\r');
-               ao_debug_out(c);
-               return;
-       }
-#endif
-       if (c == '\n')
-               (*ao_stdios[ao_cur_stdio].putchar)('\r');
-       (*ao_stdios[ao_cur_stdio].putchar)(c);
-}
-
-void
-flush(void)
-{
-       if (ao_stdios[ao_cur_stdio].flush)
-               ao_stdios[ao_cur_stdio].flush();
-}
-
-__xdata uint8_t ao_stdin_ready;
-
-char
-getchar(void) __reentrant
-{
-       int c;
-       int8_t stdio;
-
-       ao_arch_block_interrupts();
-       stdio = ao_cur_stdio;
-       for (;;) {
-               c = ao_stdios[stdio]._pollchar();
-               if (c != AO_READ_AGAIN)
-                       break;
-#if AO_NUM_STDIOS > 1
-               if (++stdio == ao_num_stdios)
-                       stdio = 0;
-               if (stdio == ao_cur_stdio)
-#endif
-                       ao_sleep(&ao_stdin_ready);
-       }
-#if AO_NUM_STDIOS > 1
-       ao_cur_stdio = stdio;
-#endif
-       ao_arch_release_interrupts();
-       return c;
-}
-
-uint8_t
-ao_echo(void)
-{
-       return ao_stdios[ao_cur_stdio].echo;
-}
-
-int8_t
-ao_add_stdio(int (*_pollchar)(void),
-            void (*putchar)(char),
-            void (*flush)(void)) __reentrant
-{
-#if AO_NUM_STDIOS > 1
-       if (ao_num_stdios == AO_NUM_STDIOS)
-               ao_panic(AO_PANIC_STDIO);
-#endif
-       ao_stdios[ao_num_stdios]._pollchar = _pollchar;
-       ao_stdios[ao_num_stdios].putchar = putchar;
-       ao_stdios[ao_num_stdios].flush = flush;
-       ao_stdios[ao_num_stdios].echo = 1;
-#if AO_NUM_STDIOS > 1
-       return ao_num_stdios++;
-#else
-       return 0;
-#endif
-}
diff --git a/src/core/ao_storage.c b/src/core/ao_storage.c
deleted file mode 100644 (file)
index 6eddae7..0000000
+++ /dev/null
@@ -1,186 +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_storage.h>
-
-uint8_t
-ao_storage_read(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant
-{
-       uint16_t this_len;
-       uint16_t this_off;
-
-       ao_storage_setup();
-       if (pos >= ao_storage_total || pos + len > ao_storage_total)
-               return 0;
-       while (len) {
-
-               /* Compute portion of transfer within
-                * a single block
-                */
-               this_off = (uint16_t) pos & (ao_storage_unit - 1);
-               this_len = ao_storage_unit - this_off;
-               if (this_len > len)
-                       this_len = len;
-
-               if (!ao_storage_device_read(pos, buf, this_len))
-                       return 0;
-
-               /* See how much is left */
-               buf += this_len;
-               len -= this_len;
-               pos += this_len;
-       }
-       return 1;
-}
-
-uint8_t
-ao_storage_write(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant
-{
-       uint16_t this_len;
-       uint16_t this_off;
-
-       ao_storage_setup();
-       if (pos >= ao_storage_total || pos + len > ao_storage_total)
-               return 0;
-       while (len) {
-
-               /* Compute portion of transfer within
-                * a single block
-                */
-               this_off = (uint16_t) pos & (ao_storage_unit - 1);
-               this_len = ao_storage_unit - this_off;
-               if (this_len > len)
-                       this_len = len;
-
-               if (!ao_storage_device_write(pos, buf, this_len))
-                       return 0;
-
-               /* See how much is left */
-               buf += this_len;
-               len -= this_len;
-               pos += this_len;
-       }
-       return 1;
-}
-
-static __xdata uint8_t storage_data[8];
-
-static void
-ao_storage_dump(void) __reentrant
-{
-       uint8_t i, j;
-
-       ao_cmd_hex();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       for (i = 0; ; i += 8) {
-               if (ao_storage_read(((uint32_t) (ao_cmd_lex_i) << 8) + i,
-                                 storage_data,
-                                 8)) {
-                       ao_cmd_put16((uint16_t) i);
-                       for (j = 0; j < 8; j++) {
-                               putchar(' ');
-                               ao_cmd_put8(storage_data[j]);
-                       }
-                       putchar ('\n');
-               }
-               if (i == 248)
-                       break;
-       }
-}
-
-#if HAS_STORAGE_DEBUG
-
-/* not enough space for this today
- */
-static void
-ao_storage_store(void) __reentrant
-{
-       uint16_t block;
-       uint8_t i;
-       uint16_t len;
-       static __xdata uint8_t b;
-       uint32_t addr;
-
-       ao_cmd_hex();
-       block = ao_cmd_lex_i;
-       ao_cmd_hex();
-       i = ao_cmd_lex_i;
-       addr = ((uint32_t) block << 8) | i;
-       ao_cmd_hex();
-       len = ao_cmd_lex_i;
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       while (len--) {
-               ao_cmd_hex();
-               if (ao_cmd_status != ao_cmd_success)
-                       return;
-               b = ao_cmd_lex_i;
-               ao_storage_write(addr, &b, 1);
-               addr++;
-       }
-}
-#endif
-
-void
-ao_storage_zap(void) __reentrant
-{
-       ao_cmd_hex();
-       if (ao_cmd_status != ao_cmd_success)
-               return;
-       ao_storage_erase((uint32_t) ao_cmd_lex_i << 8);
-}
-
-void
-ao_storage_zapall(void) __reentrant
-{
-       uint32_t        pos;
-
-       ao_cmd_white();
-       if (!ao_match_word("DoIt"))
-               return;
-       for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block)
-               ao_storage_erase(pos);
-}
-
-void
-ao_storage_info(void) __reentrant
-{
-       ao_storage_setup();
-       printf("Storage size: %ld\n", (long) ao_storage_total);
-       printf("Storage erase unit: %ld\n", (long) ao_storage_block);
-       ao_storage_device_info();
-}
-
-__code struct ao_cmds ao_storage_cmds[] = {
-       { ao_storage_info, "f\0Show storage" },
-       { ao_storage_dump, "e <block>\0Dump flash" },
-#if HAS_STORAGE_DEBUG
-       { ao_storage_store, "w <block> <start> <len> <data> ...\0Write data to flash" },
-#endif
-       { ao_storage_zap, "z <block>\0Erase <block>" },
-       { ao_storage_zapall,"Z <key>\0Erase all. <key> is doit with D&I" },
-       { 0, NULL },
-};
-
-void
-ao_storage_init(void)
-{
-       ao_storage_device_init();
-       ao_cmd_register(&ao_storage_cmds[0]);
-}
diff --git a/src/core/ao_storage.h b/src/core/ao_storage.h
deleted file mode 100644 (file)
index 6cc6fcb..0000000
+++ /dev/null
@@ -1,98 +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_STORAGE_H_
-#define _AO_STORAGE_H_
-
-/*
- * Storage interface, provided by one of the eeprom or flash
- * drivers
- */
-
-#ifndef ao_storage_pos_t
-#define ao_storage_pos_t uint32_t
-#endif
-
-typedef ao_storage_pos_t ao_pos_t;
-
-/* Total bytes of available storage */
-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;
-
-/* Initialize above values. Can only be called once the OS is running */
-void
-ao_storage_setup(void) __reentrant;
-
-/* Write data. Returns 0 on failure, 1 on success */
-uint8_t
-ao_storage_write(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant;
-
-/* Read data. Returns 0 on failure, 1 on success */
-uint8_t
-ao_storage_read(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant;
-
-/* Erase a block of storage. This always clears ao_storage_block bytes */
-uint8_t
-ao_storage_erase(ao_pos_t pos) __reentrant;
-
-/* Flush any pending writes to stable storage */
-void
-ao_storage_flush(void) __reentrant;
-
-/* Initialize the storage code */
-void
-ao_storage_init(void);
-
-/*
- * Low-level functions wrapped by ao_storage.c
- */
-
-/* Read data within a storage unit */
-uint8_t
-ao_storage_device_read(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant;
-
-/* Write data within a storage unit */
-uint8_t
-ao_storage_device_write(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant;
-
-/* Initialize low-level device bits */
-void
-ao_storage_device_init(void);
-
-/* Print out information about flash chips */
-void
-ao_storage_device_info(void) __reentrant;
-
-#endif /* _AO_STORAGE_H_ */
diff --git a/src/core/ao_task.c b/src/core/ao_task.c
deleted file mode 100644 (file)
index bafb494..0000000
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * 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_task.h>
-#if HAS_SAMPLE_PROFILE
-#include <ao_sample_profile.h>
-#endif
-#if HAS_STACK_GUARD
-#include <ao_mpu.h>
-#endif
-
-#define DEBUG  0
-
-#define AO_NO_TASK_INDEX       0xff
-
-__xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS];
-__data uint8_t ao_num_tasks;
-__xdata struct ao_task *__data ao_cur_task;
-
-#if !HAS_TASK_QUEUE
-static __data uint8_t ao_cur_task_index;
-#endif
-
-#ifdef ao_arch_task_globals
-ao_arch_task_globals
-#endif
-
-#define AO_CHECK_STACK 0
-
-#if AO_CHECK_STACK
-static uint8_t in_yield;
-
-static inline void ao_check_stack(void) {
-       uint8_t q;
-       if (!in_yield && ao_cur_task && &q < &ao_cur_task->stack[0])
-               ao_panic(AO_PANIC_STACK);
-}
-#else
-#define ao_check_stack()
-#endif
-
-#if HAS_TASK_QUEUE
-
-#define SLEEP_HASH_SIZE        17
-
-static struct ao_list  run_queue;
-static struct ao_list  alarm_queue;
-static struct ao_list  sleep_queue[SLEEP_HASH_SIZE];
-
-static void
-ao_task_to_run_queue(struct ao_task *task)
-{
-       ao_list_del(&task->queue);
-       ao_list_append(&task->queue, &run_queue);
-}
-
-static struct ao_list *
-ao_task_sleep_queue(void *wchan)
-{
-       return &sleep_queue[(uintptr_t) wchan % SLEEP_HASH_SIZE];
-}
-
-static void
-ao_task_to_sleep_queue(struct ao_task *task, void *wchan)
-{
-       ao_list_del(&task->queue);
-       ao_list_append(&task->queue, ao_task_sleep_queue(wchan));
-}
-
-#if DEBUG
-static void
-ao_task_validate_alarm_queue(void)
-{
-       struct ao_task  *alarm, *prev = NULL;
-       int             i;
-
-       if (ao_list_is_empty(&alarm_queue))
-               return;
-       ao_list_for_each_entry(alarm, &alarm_queue, struct ao_task, alarm_queue) {
-               if (prev) {
-                       if ((int16_t) (alarm->alarm - prev->alarm) < 0) {
-                               ao_panic(1);
-                       }
-               }
-               prev = alarm;
-       }
-       for (i = 0; i < ao_num_tasks; i++) {
-               alarm = ao_tasks[i];
-               if (alarm->alarm) {
-                       if (ao_list_is_empty(&alarm->alarm_queue))
-                               ao_panic(2);
-               } else {
-                       if (!ao_list_is_empty(&alarm->alarm_queue))
-                               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()
-#endif
-
-uint16_t       ao_task_alarm_tick;
-
-static void
-ao_task_to_alarm_queue(struct ao_task *task)
-{
-       struct ao_task  *alarm;
-       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;
-               }
-       }
-       ao_list_append(&task->alarm_queue, &alarm_queue);
-       ao_task_alarm_tick = ao_list_first_entry(&alarm_queue, struct ao_task, alarm_queue)->alarm;
-       ao_task_validate_alarm_queue();
-}
-
-static void
-ao_task_from_alarm_queue(struct ao_task *task)
-{
-       ao_list_del(&task->alarm_queue);
-       if (ao_list_is_empty(&alarm_queue))
-               ao_task_alarm_tick = 0;
-       else
-               ao_task_alarm_tick = ao_list_first_entry(&alarm_queue, struct ao_task, alarm_queue)->alarm;
-       ao_task_validate_alarm_queue();
-}
-
-static void
-ao_task_init_queue(struct ao_task *task)
-{
-       ao_list_init(&task->queue);
-       ao_list_init(&task->alarm_queue);
-}
-
-static void
-ao_task_exit_queue(struct ao_task *task)
-{
-       ao_list_del(&task->queue);
-       ao_list_del(&task->alarm_queue);
-}
-
-void
-ao_task_check_alarm(uint16_t tick)
-{
-       struct ao_task  *alarm, *next;
-
-       ao_list_for_each_entry_safe(alarm, next, &alarm_queue, struct ao_task, alarm_queue) {
-               if ((int16_t) (tick - alarm->alarm) < 0)
-                       break;
-               alarm->alarm = 0;
-               ao_task_from_alarm_queue(alarm);
-               ao_task_to_run_queue(alarm);
-       }
-}
-
-void
-ao_task_init(void)
-{
-       uint8_t i;
-       ao_list_init(&run_queue);
-       ao_list_init(&alarm_queue);
-       ao_task_alarm_tick = 0;
-       for (i = 0; i < SLEEP_HASH_SIZE; i++)
-               ao_list_init(&sleep_queue[i]);
-}
-
-#if DEBUG
-static uint8_t
-ao_task_validate_queue(struct ao_task *task)
-{
-       uint32_t flags;
-       struct ao_task *m;
-       uint8_t ret = 0;
-       struct ao_list *queue;
-
-       flags = ao_arch_irqsave();
-       if (task->wchan) {
-               queue = ao_task_sleep_queue(task->wchan);
-               ret |= 2;
-       } else {
-               queue = &run_queue;
-               ret |= 4;
-       }
-       ao_list_for_each_entry(m, queue, struct ao_task, queue) {
-               if (m == task) {
-                       ret |= 1;
-                       break;
-               }
-       }
-       ao_arch_irqrestore(flags);
-       return ret;
-}
-
-static uint8_t
-ao_task_validate_alarm(struct ao_task *task)
-{
-       uint32_t        flags;
-       struct ao_task  *m;
-       uint8_t         ret = 0;
-
-       flags = ao_arch_irqsave();
-       if (task->alarm == 0)
-               return 0xff;
-       ao_list_for_each_entry(m, &alarm_queue, struct ao_task, alarm_queue) {
-               if (m == task)
-                       ret |= 1;
-               else {
-                       if (!(ret&1)) {
-                               if ((int16_t) (m->alarm - task->alarm) > 0)
-                                       ret |= 2;
-                       } else {
-                               if ((int16_t) (task->alarm - m->alarm) > 0)
-                                       ret |= 4;
-                       }
-               }
-       }
-       ao_arch_irqrestore(flags);
-       return ret;
-}
-
-
-static void
-ao_task_validate(void)
-{
-       uint8_t         i;
-       struct ao_task  *task;
-       uint8_t         ret;
-
-       for (i = 0; i < ao_num_tasks; i++) {
-               task = ao_tasks[i];
-               ret = ao_task_validate_queue(task);
-               if (!(ret & 1)) {
-                       if (ret & 2)
-                               printf ("sleeping task not on sleep queue %s %08x\n",
-                                       task->name, task->wchan);
-                       else
-                               printf ("running task not on run queue %s\n",
-                                       task->name);
-               }
-               ret = ao_task_validate_alarm(task);
-               if (ret != 0xff) {
-                       if (!(ret & 1))
-                               printf ("alarm task not on alarm queue %s %d\n",
-                                       task->name, task->alarm);
-                       if (ret & 2)
-                               printf ("alarm queue has sooner entries after %s %d\n",
-                                       task->name, task->alarm);
-                       if (ret & 4)
-                               printf ("alarm queue has later entries before %s %d\n",
-                                       task->name, task->alarm);
-               }
-       }
-}
-#endif /* DEBUG */
-
-#endif /* HAS_TASK_QUEUE */
-
-void
-ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant
-{
-       uint8_t task_id;
-       uint8_t t;
-       if (ao_num_tasks == AO_NUM_TASKS)
-               ao_panic(AO_PANIC_NO_TASK);
-       for (task_id = 1; task_id != 0; task_id++) {
-               for (t = 0; t < ao_num_tasks; t++)
-                       if (ao_tasks[t]->task_id == task_id)
-                               break;
-               if (t == ao_num_tasks)
-                       break;
-       }
-       task->task_id = task_id;
-       task->name = name;
-       task->wchan = NULL;
-       /*
-        * Construct a stack frame so that it will 'return'
-        * to the start of the task
-        */
-       ao_arch_init_stack(task, start);
-       ao_arch_critical(
-#if HAS_TASK_QUEUE
-               ao_task_init_queue(task);
-               ao_task_to_run_queue(task);
-#endif
-               ao_tasks[ao_num_tasks] = task;
-               ao_num_tasks++;
-               );
-}
-
-__data uint8_t ao_task_minimize_latency;
-
-/* Task switching function. This must not use any stack variables */
-void
-ao_yield(void) ao_arch_naked_define
-{
-       ao_arch_save_regs();
-
-#if HAS_TASK_QUEUE
-       if (ao_cur_task == NULL)
-               ao_cur_task = ao_tasks[ao_num_tasks-1];
-#else
-       if (ao_cur_task_index == AO_NO_TASK_INDEX)
-               ao_cur_task_index = ao_num_tasks-1;
-#endif
-       else
-       {
-#if HAS_SAMPLE_PROFILE
-               uint16_t        tick = ao_sample_profile_timer_value();
-               uint16_t        run = tick - ao_cur_task->start;
-               if (run > ao_cur_task->max_run)
-                       ao_cur_task->max_run = run;
-               ++ao_cur_task->yields;
-#endif
-               ao_arch_save_stack();
-       }
-
-       ao_arch_isr_stack();
-#if !HAS_TASK_QUEUE
-       if (ao_task_minimize_latency)
-               ao_arch_release_interrupts();
-       else
-#endif
-               ao_arch_block_interrupts();
-
-#if AO_CHECK_STACK
-       in_yield = 1;
-#endif
-       /* Find a task to run. If there isn't any runnable task,
-        * this loop will run forever, which is just fine
-        */
-#if HAS_TASK_QUEUE
-       /* If the current task is running, move it to the
-        * end of the queue to allow other tasks a chance
-        */
-       if (ao_cur_task->wchan == NULL)
-               ao_task_to_run_queue(ao_cur_task);
-       ao_cur_task = NULL;
-       for (;;) {
-               ao_arch_memory_barrier();
-               if (!ao_list_is_empty(&run_queue))
-                       break;
-               /* Wait for interrupts when there's nothing ready */
-               ao_arch_wait_interrupt();
-       }
-       ao_cur_task = ao_list_first_entry(&run_queue, struct ao_task, queue);
-#else
-       {
-               __pdata uint8_t ao_last_task_index = ao_cur_task_index;
-               for (;;) {
-                       ++ao_cur_task_index;
-                       if (ao_cur_task_index == ao_num_tasks)
-                               ao_cur_task_index = 0;
-
-                       ao_cur_task = ao_tasks[ao_cur_task_index];
-
-                       /* Check for ready task */
-                       if (ao_cur_task->wchan == NULL)
-                               break;
-
-                       /* Check if the alarm is set for a time which has passed */
-                       if (ao_cur_task->alarm &&
-                           (int16_t) (ao_time() - ao_cur_task->alarm) >= 0)
-                               break;
-
-                       /* Wait for interrupts when there's nothing ready */
-                       if (ao_cur_task_index == ao_last_task_index && !ao_task_minimize_latency)
-                               ao_arch_wait_interrupt();
-               }
-       }
-#endif
-#if HAS_SAMPLE_PROFILE
-       ao_cur_task->start = ao_sample_profile_timer_value();
-#endif
-#if HAS_STACK_GUARD
-       ao_mpu_stack_guard(ao_cur_task->stack);
-#endif
-#if AO_CHECK_STACK
-       in_yield = 0;
-#endif
-       ao_arch_restore_stack();
-}
-
-uint8_t
-ao_sleep(__xdata void *wchan)
-{
-#if HAS_TASK_QUEUE
-       uint32_t flags;
-       flags = ao_arch_irqsave();
-#endif
-       ao_cur_task->wchan = wchan;
-#if HAS_TASK_QUEUE
-       ao_task_to_sleep_queue(ao_cur_task, wchan);
-       ao_arch_irqrestore(flags);
-#endif
-       ao_yield();
-       if (ao_cur_task->wchan) {
-               ao_cur_task->wchan = NULL;
-               ao_cur_task->alarm = 0;
-               return 1;
-       }
-       return 0;
-}
-
-void
-ao_wakeup(__xdata void *wchan) __reentrant
-{
-#if HAS_TASK_QUEUE
-       struct ao_task  *sleep, *next;
-       struct ao_list  *sleep_queue;
-       uint32_t        flags;
-
-       if (ao_num_tasks == 0)
-               return;
-       sleep_queue = ao_task_sleep_queue(wchan);
-       flags = ao_arch_irqsave();
-       ao_list_for_each_entry_safe(sleep, next, sleep_queue, struct ao_task, queue) {
-               if (sleep->wchan == wchan) {
-                       sleep->wchan = NULL;
-                       ao_task_to_run_queue(sleep);
-               }
-       }
-       ao_arch_irqrestore(flags);
-#else
-       uint8_t i;
-       for (i = 0; i < ao_num_tasks; i++)
-               if (ao_tasks[i]->wchan == wchan)
-                       ao_tasks[i]->wchan = NULL;
-#endif
-       ao_check_stack();
-}
-
-void
-ao_alarm(uint16_t delay)
-{
-#if HAS_TASK_QUEUE
-       uint32_t flags;
-       /* Make sure we sleep *at least* delay ticks, which means adding
-        * one to account for the fact that we may be close to the next tick
-        */
-       flags = ao_arch_irqsave();
-#endif
-       if (!(ao_cur_task->alarm = ao_time() + delay + 1))
-               ao_cur_task->alarm = 1;
-#if HAS_TASK_QUEUE
-       ao_task_to_alarm_queue(ao_cur_task);
-       ao_arch_irqrestore(flags);
-#endif
-}
-
-void
-ao_clear_alarm(void)
-{
-#if HAS_TASK_QUEUE
-       uint32_t flags;
-
-       flags = ao_arch_irqsave();
-#endif
-       ao_cur_task->alarm = 0;
-#if HAS_TASK_QUEUE
-       ao_task_from_alarm_queue(ao_cur_task);
-       ao_arch_irqrestore(flags);
-#endif
-}
-
-static __xdata uint8_t ao_forever;
-
-void
-ao_delay(uint16_t ticks)
-{
-       ao_alarm(ticks);
-       ao_sleep(&ao_forever);
-       ao_clear_alarm();
-}
-
-void
-ao_exit(void)
-{
-       uint8_t i;
-       ao_arch_block_interrupts();
-       ao_num_tasks--;
-#if HAS_TASK_QUEUE
-       for (i = 0; i < ao_num_tasks; i++)
-               if (ao_tasks[i] == ao_cur_task)
-                       break;
-       ao_task_exit_queue(ao_cur_task);
-#else
-       i = ao_cur_task_index;
-       ao_cur_task_index = AO_NO_TASK_INDEX;
-#endif
-       for (; i < ao_num_tasks; i++)
-               ao_tasks[i] = ao_tasks[i+1];
-       ao_cur_task = NULL;
-       ao_yield();
-       /* we'll never get back here */
-}
-
-#if HAS_TASK_INFO
-void
-ao_task_info(void)
-{
-       uint8_t         i;
-       __xdata struct ao_task *task;
-
-       for (i = 0; i < ao_num_tasks; i++) {
-               task = ao_tasks[i];
-               printf("%12s: wchan %04x\n",
-                      task->name,
-                      (int) task->wchan);
-       }
-#if HAS_TASK_QUEUE && DEBUG
-       ao_task_validate();
-#endif
-}
-#endif
-
-void
-ao_start_scheduler(void)
-{
-#if !HAS_TASK_QUEUE
-       ao_cur_task_index = AO_NO_TASK_INDEX;
-#endif
-       ao_cur_task = NULL;
-#if HAS_ARCH_START_SCHEDULER
-       ao_arch_start_scheduler();
-#endif
-       ao_yield();
-}
diff --git a/src/core/ao_task.h b/src/core/ao_task.h
deleted file mode 100644 (file)
index 9c56b48..0000000
+++ /dev/null
@@ -1,117 +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_TASK_H_
-#define _AO_TASK_H_
-#if HAS_TASK_QUEUE
-#include <ao_list.h>
-#endif
-
-#ifndef HAS_TASK_INFO
-#define HAS_TASK_INFO 1
-#endif
-
-/* An AltOS task */
-struct ao_task {
-       __xdata void *wchan;            /* current wait channel (NULL if running) */
-       uint16_t alarm;                 /* abort ao_sleep time */
-       ao_arch_task_members            /* any architecture-specific fields */
-       uint8_t task_id;                /* unique id */
-       __code char *name;              /* task name */
-#if HAS_TASK_QUEUE
-       struct ao_list  queue;
-       struct ao_list  alarm_queue;
-#endif
-       uint8_t stack[AO_STACK_SIZE];   /* saved stack */
-#if HAS_SAMPLE_PROFILE
-       uint32_t ticks;
-       uint32_t yields;
-       uint16_t start;
-       uint16_t max_run;
-#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];
-extern __data uint8_t ao_num_tasks;
-extern __xdata struct ao_task *__data ao_cur_task;
-extern __data uint8_t ao_task_minimize_latency;        /* Reduce IRQ latency */
-
-/*
- ao_task.c
- */
-
-/* Suspend the current task until wchan is awoken.
- * returns:
- *  0 on normal wake
- *  1 on alarm
- */
-uint8_t
-ao_sleep(__xdata void *wchan);
-
-/* Wake all tasks sleeping on wchan */
-void
-ao_wakeup(__xdata void *wchan) __reentrant;
-
-/* set an alarm to go off in 'delay' ticks */
-void
-ao_alarm(uint16_t delay);
-
-/* Clear any pending alarm */
-void
-ao_clear_alarm(void);
-
-/* Yield the processor to another task */
-void
-ao_yield(void) ao_arch_naked_declare;
-
-/* Add a task to the run queue */
-void
-ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant;
-
-#if HAS_TASK_QUEUE
-/* Called on timer interrupt to check alarms */
-extern uint16_t        ao_task_alarm_tick;
-void
-ao_task_check_alarm(uint16_t tick);
-#endif
-
-/* Terminate the current task */
-void
-ao_exit(void);
-
-/* Dump task info to console */
-void
-ao_task_info(void);
-
-/* Start the scheduler. This will not return */
-void
-ao_start_scheduler(void);
-
-#if HAS_TASK_QUEUE
-void
-ao_task_init(void);
-#else
-#define ao_task_init()
-#endif
-
-#endif
diff --git a/src/core/ao_telem.h b/src/core/ao_telem.h
deleted file mode 100644 (file)
index 1a8da29..0000000
+++ /dev/null
@@ -1,172 +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.
- */
-
-#ifndef _AO_TELEM_H_
-#define _AO_TELEM_H_
-
-#define AO_TELEMETRY_VERSION           4
-
-/*
- * Telemetry version 4 and higher format:
- *
- * General header fields
- *
- *     Name            Value
- *
- *     VERSION         Telemetry version number (4 or more). Must be first.
- *     c               Callsign (string, no spaces allowed)
- *     n               Flight unit serial number (integer)
- *     f               Flight number (integer)
- *     r               Packet RSSI value (integer)
- *     s               Flight computer state (string, no spaces allowed)
- *     t               Flight computer clock (integer in centiseconds)
- */
-
-#define AO_TELEM_VERSION       "VERSION"
-#define AO_TELEM_CALL          "c"
-#define AO_TELEM_SERIAL                "n"
-#define AO_TELEM_FLIGHT                "f"
-#define AO_TELEM_RSSI          "r"
-#define AO_TELEM_STATE         "s"
-#define AO_TELEM_TICK          "t"
-
-/*
- * Raw sensor values
- *
- *     Name            Value
- *     r_a             Accelerometer reading (integer)
- *     r_b             Barometer reading (integer)
- *     r_t             Thermometer reading (integer)
- *     r_v             Battery reading (integer)
- *     r_d             Drogue continuity (integer)
- *     r_m             Main continuity (integer)
- */
-
-#define AO_TELEM_RAW_ACCEL     "r_a"
-#define AO_TELEM_RAW_BARO      "r_b"
-#define AO_TELEM_RAW_THERMO    "r_t"
-#define AO_TELEM_RAW_BATT      "r_v"
-#define AO_TELEM_RAW_DROGUE    "r_d"
-#define AO_TELEM_RAW_MAIN      "r_m"
-
-/*
- * Sensor calibration values
- *
- *     Name            Value
- *     c_a             Ground accelerometer reading (integer)
- *     c_b             Ground barometer reading (integer)
- *     c_p             Accelerometer reading for +1g
- *     c_m             Accelerometer reading for -1g
- */
-
-#define AO_TELEM_CAL_ACCEL_GROUND      "c_a"
-#define AO_TELEM_CAL_BARO_GROUND       "c_b"
-#define AO_TELEM_CAL_ACCEL_PLUS                "c_p"
-#define AO_TELEM_CAL_ACCEL_MINUS       "c_m"
-
-/*
- * Kalman state values
- *
- *     Name            Value
- *     k_h             Height above pad (integer, meters)
- *     k_s             Vertical speeed (integer, m/s * 16)
- *     k_a             Vertical acceleration (integer, m/s² * 16)
- */
-
-#define AO_TELEM_KALMAN_HEIGHT         "k_h"
-#define AO_TELEM_KALMAN_SPEED          "k_s"
-#define AO_TELEM_KALMAN_ACCEL          "k_a"
-
-/*
- * Ad-hoc flight values
- *
- *     Name            Value
- *     a_a             Acceleration (integer, sensor units)
- *     a_s             Speed (integer, integrated acceleration value)
- *     a_b             Barometer reading (integer, sensor units)
- */
-
-#define AO_TELEM_ADHOC_ACCEL           "a_a"
-#define AO_TELEM_ADHOC_SPEED           "a_s"
-#define AO_TELEM_ADHOC_BARO            "a_b"
-
-/*
- * GPS values
- *
- *     Name            Value
- *     g               GPS state (string):
- *                             l       locked
- *                             u       unlocked
- *                             e       error (missing or broken)
- *     g_n             Number of sats used in solution
- *     g_ns            Latitude (degrees * 10e7)
- *     g_ew            Longitude (degrees * 10e7)
- *     g_a             Altitude (integer meters)
- *     g_Y             GPS year (integer)
- *     g_M             GPS month (integer - 1-12)
- *     g_D             GPS day (integer - 1-31)
- *     g_h             GPS hour (integer - 0-23)
- *     g_m             GPS minute (integer - 0-59)
- *     g_s             GPS second (integer - 0-59)
- *     g_v             GPS vertical speed (integer, cm/sec)
- *     g_g             GPS horizontal speed (integer, cm/sec)
- *     g_c             GPS course (integer, 0-359)
- *     g_hd            GPS hdop (integer * 10)
- *     g_vd            GPS vdop (integer * 10)
- *     g_he            GPS h error (integer)
- *     g_ve            GPS v error (integer)
- */
-
-#define AO_TELEM_GPS_STATE             "g"
-#define AO_TELEM_GPS_STATE_LOCKED      'l'
-#define AO_TELEM_GPS_STATE_UNLOCKED    'u'
-#define AO_TELEM_GPS_STATE_ERROR       'e'
-#define AO_TELEM_GPS_NUM_SAT           "g_n"
-#define AO_TELEM_GPS_LATITUDE          "g_ns"
-#define AO_TELEM_GPS_LONGITUDE         "g_ew"
-#define AO_TELEM_GPS_ALTITUDE          "g_a"
-#define AO_TELEM_GPS_YEAR              "g_Y"
-#define AO_TELEM_GPS_MONTH             "g_M"
-#define AO_TELEM_GPS_DAY               "g_D"
-#define AO_TELEM_GPS_HOUR              "g_h"
-#define AO_TELEM_GPS_MINUTE            "g_m"
-#define AO_TELEM_GPS_SECOND            "g_s"
-#define AO_TELEM_GPS_VERTICAL_SPEED    "g_v"
-#define AO_TELEM_GPS_HORIZONTAL_SPEED  "g_g"
-#define AO_TELEM_GPS_COURSE            "g_c"
-#define AO_TELEM_GPS_HDOP              "g_hd"
-#define AO_TELEM_GPS_VDOP              "g_vd"
-#define AO_TELEM_GPS_HERROR            "g_he"
-#define AO_TELEM_GPS_VERROR            "g_ve"
-
-/*
- * GPS satellite values
- *
- *     Name            Value
- *     s_n             Number of satellites reported (integer)
- *     s_v0            Space vehicle ID (integer) for report 0
- *     s_c0            C/N0 number (integer) for report 0
- *     s_v1            Space vehicle ID (integer) for report 1
- *     s_c1            C/N0 number (integer) for report 1
- *     ...
- */
-
-#define AO_TELEM_SAT_NUM               "s_n"
-#define AO_TELEM_SAT_SVID              "s_v"
-#define AO_TELEM_SAT_C_N_0             "s_c"
-
-#endif /* _AO_TELEM_H_ */
diff --git a/src/core/ao_telemetry.c b/src/core/ao_telemetry.c
deleted file mode 100644 (file)
index 5a00d82..0000000
+++ /dev/null
@@ -1,547 +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_log.h"
-#include "ao_product.h"
-
-#ifndef HAS_RDF
-#define HAS_RDF 1
-#endif
-
-static __pdata uint16_t ao_telemetry_interval;
-
-#if HAS_RDF
-static __pdata uint8_t ao_rdf = 0;
-static __pdata uint16_t ao_rdf_time;
-#endif
-
-#if HAS_APRS
-static __pdata uint16_t ao_aprs_time;
-
-#include <ao_aprs.h>
-#endif
-
-#if defined(TELEMEGA)
-#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
-
-#if defined(TELEMINI_V_1_0)
-#define AO_TELEMETRY_SENSOR    AO_TELEMETRY_SENSOR_TELEMINI
-#endif
-
-#if defined(TELENANO_V_0_1)
-#define AO_TELEMETRY_SENSOR    AO_TELEMETRY_SENSOR_TELENANO
-#endif
-
-static __xdata union ao_telemetry_all  telemetry;
-
-#if defined AO_TELEMETRY_SENSOR
-/* Send sensor packet */
-static void
-ao_send_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_SENSOR;
-
-       telemetry.sensor.state = ao_flight_state;
-#if HAS_ACCEL
-       telemetry.sensor.accel = packet->adc.accel;
-#else
-       telemetry.sensor.accel = 0;
-#endif
-       telemetry.sensor.pres = ao_data_pres(packet);
-       telemetry.sensor.temp = packet->adc.temp;
-       telemetry.sensor.v_batt = packet->adc.v_batt;
-#if HAS_IGNITE
-       telemetry.sensor.sense_d = packet->adc.sense_d;
-       telemetry.sensor.sense_m = packet->adc.sense_m;
-#else
-       telemetry.sensor.sense_d = 0;
-       telemetry.sensor.sense_m = 0;
-#endif
-
-       telemetry.sensor.acceleration = ao_accel;
-       telemetry.sensor.speed = ao_speed;
-       telemetry.sensor.height = ao_height;
-
-       telemetry.sensor.ground_pres = ao_ground_pres;
-#if HAS_ACCEL
-       telemetry.sensor.ground_accel = ao_ground_accel;
-       telemetry.sensor.accel_plus_g = ao_config.accel_plus_g;
-       telemetry.sensor.accel_minus_g = ao_config.accel_minus_g;
-#else
-       telemetry.sensor.ground_accel = 0;
-       telemetry.sensor.accel_plus_g = 0;
-       telemetry.sensor.accel_minus_g = 0;
-#endif
-
-       ao_radio_send(&telemetry, sizeof (telemetry));
-}
-#endif
-
-
-#ifdef AO_SEND_MEGA
-/* Send mega sensor packet */
-static void
-ao_send_mega_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_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);
-
-#if HAS_MPU6000
-       telemetry.mega_sensor.accel_x = packet->mpu6000.accel_x;
-       telemetry.mega_sensor.accel_y = packet->mpu6000.accel_y;
-       telemetry.mega_sensor.accel_z = packet->mpu6000.accel_z;
-
-       telemetry.mega_sensor.gyro_x = packet->mpu6000.gyro_x;
-       telemetry.mega_sensor.gyro_y = packet->mpu6000.gyro_y;
-       telemetry.mega_sensor.gyro_z = packet->mpu6000.gyro_z;
-#endif
-
-#if HAS_HMC5883
-       telemetry.mega_sensor.mag_x = packet->hmc5883.x;
-       telemetry.mega_sensor.mag_y = packet->hmc5883.y;
-       telemetry.mega_sensor.mag_z = packet->hmc5883.z;
-#endif
-
-       ao_radio_send(&telemetry, sizeof (telemetry));
-}
-
-static __pdata int8_t ao_telemetry_mega_data_max;
-static __pdata int8_t ao_telemetry_mega_data_cur;
-
-/* Send mega data packet */
-static void
-ao_send_mega_data(void)
-{
-       if (--ao_telemetry_mega_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_MEGA_DATA;
-
-               telemetry.mega_data.state = ao_flight_state;
-               telemetry.mega_data.v_batt = packet->adc.v_batt;
-               telemetry.mega_data.v_pyro = packet->adc.v_pbatt;
-
-               /* ADC range is 0-4095, so shift by four to save the high 8 bits */
-               for (i = 0; i < AO_ADC_NUM_SENSE; i++)
-                       telemetry.mega_data.sense[i] = packet->adc.sense[i] >> 4;
-
-               telemetry.mega_data.ground_pres = ao_ground_pres;
-               telemetry.mega_data.ground_accel = ao_ground_accel;
-               telemetry.mega_data.accel_plus_g = ao_config.accel_plus_g;
-               telemetry.mega_data.accel_minus_g = ao_config.accel_minus_g;
-
-               telemetry.mega_data.acceleration = ao_accel;
-               telemetry.mega_data.speed = ao_speed;
-               telemetry.mega_data.height = ao_height;
-
-               ao_radio_send(&telemetry, sizeof (telemetry));
-               ao_telemetry_mega_data_cur = ao_telemetry_mega_data_max;
-       }
-}
-#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)];
-
-               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;
-
-static void
-ao_send_baro(void)
-{
-       uint8_t         sample = ao_sample_data;
-       uint8_t         samples = (sample - ao_baro_sample) & (AO_DATA_RING - 1);
-
-       if (samples > 12) {
-               ao_baro_sample = (ao_baro_sample + (samples - 12)) & (AO_DATA_RING - 1);
-               samples = 12;
-       }
-       telemetry.generic.tick = ao_data_ring[sample].tick;
-       telemetry.generic.type = AO_TELEMETRY_BARO;
-       telemetry.baro.samples = samples;
-       for (sample = 0; sample < samples; sample++) {
-               telemetry.baro.baro[sample] = ao_data_ring[ao_baro_sample].adc.pres;
-               ao_baro_sample = ao_data_ring_next(ao_baro_sample);
-       }
-       ao_radio_send(&telemetry, sizeof (telemetry));
-}
-#endif
-
-static __pdata int8_t ao_telemetry_config_max;
-static __pdata int8_t ao_telemetry_config_cur;
-
-static void
-ao_send_configuration(void)
-{
-       if (--ao_telemetry_config_cur <= 0)
-       {
-               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;
-               telemetry.configuration.main_deploy = ao_config.main_deploy;
-               telemetry.configuration.flight_log_max = ao_config.flight_log_max >> 10;
-               ao_xmemcpy (telemetry.configuration.callsign,
-                           ao_config.callsign,
-                           AO_MAX_CALLSIGN);
-               ao_xmemcpy (telemetry.configuration.version,
-                           CODE_TO_XDATA(ao_version),
-                           AO_MAX_VERSION);
-               ao_radio_send(&telemetry, sizeof (telemetry));
-               ao_telemetry_config_cur = ao_telemetry_config_max;
-       }
-}
-
-#if HAS_GPS
-
-static __pdata int8_t ao_telemetry_loc_cur;
-static __pdata int8_t ao_telemetry_sat_cur;
-
-static void
-ao_send_location(void)
-{
-       if (--ao_telemetry_loc_cur <= 0)
-       {
-               telemetry.generic.type = AO_TELEMETRY_LOCATION;
-               ao_mutex_get(&ao_gps_mutex);
-               ao_xmemcpy(&telemetry.location.flags,
-                      &ao_gps_data.flags,
-                      26);
-               telemetry.location.tick = ao_gps_tick;
-               ao_mutex_put(&ao_gps_mutex);
-               ao_radio_send(&telemetry, sizeof (telemetry));
-               ao_telemetry_loc_cur = ao_telemetry_config_max;
-       }
-}
-
-static void
-ao_send_satellite(void)
-{
-       if (--ao_telemetry_sat_cur <= 0)
-       {
-               telemetry.generic.type = AO_TELEMETRY_SATELLITE;
-               ao_mutex_get(&ao_gps_mutex);
-               telemetry.satellite.channels = ao_gps_tracking_data.channels;
-               ao_xmemcpy(&telemetry.satellite.sats,
-                      &ao_gps_tracking_data.sats,
-                      AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info));
-               ao_mutex_put(&ao_gps_mutex);
-               ao_radio_send(&telemetry, sizeof (telemetry));
-               ao_telemetry_sat_cur = ao_telemetry_config_max;
-       }
-}
-#endif
-
-#if HAS_COMPANION
-
-static __pdata int8_t ao_telemetry_companion_max;
-static __pdata int8_t ao_telemetry_companion_cur;
-
-static void
-ao_send_companion(void)
-{
-       if (--ao_telemetry_companion_cur <= 0) {
-               telemetry.generic.type = AO_TELEMETRY_COMPANION;
-               telemetry.companion.board_id = ao_companion_setup.board_id;
-               telemetry.companion.update_period = ao_companion_setup.update_period;
-               telemetry.companion.channels = ao_companion_setup.channels;
-               ao_mutex_get(&ao_companion_mutex);
-               ao_xmemcpy(&telemetry.companion.companion_data,
-                      ao_companion_data,
-                      ao_companion_setup.channels * 2);
-               ao_mutex_put(&ao_companion_mutex);
-               ao_radio_send(&telemetry, sizeof (telemetry));
-               ao_telemetry_companion_cur = ao_telemetry_companion_max;
-       }
-}
-#endif
-
-void
-ao_telemetry(void)
-{
-       uint16_t        time;
-       int16_t         delay;
-
-       ao_config_get();
-       if (!ao_config.radio_enable)
-               ao_exit();
-       while (!ao_flight_number)
-               ao_sleep(&ao_flight_number);
-
-       telemetry.generic.serial = ao_serial_number;
-       for (;;) {
-               while (ao_telemetry_interval == 0)
-                       ao_sleep(&telemetry);
-               time = ao_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
-                       {
-#ifdef AO_SEND_ALL_BARO
-                               ao_send_baro();
-#endif
-
-#if HAS_FLIGHT
-# ifdef AO_SEND_MEGA
-                               ao_send_mega_sensor();
-                               ao_send_mega_data();
-# 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 /* HAS_FLIGHT */
-
-#if HAS_COMPANION
-                               if (ao_companion_running)
-                                       ao_send_companion();
-#endif
-                               ao_send_configuration();
-#if HAS_GPS
-                               ao_send_location();
-                               ao_send_satellite();
-#endif
-                       }
-#ifndef AO_SEND_ALL_BARO
-#if HAS_RDF
-                       if (ao_rdf &&
-#if HAS_APRS
-                           !(ao_config.radio_enable & AO_RADIO_DISABLE_RDF) &&
-#endif /* HAS_APRS */
-                           (int16_t) (ao_time() - ao_rdf_time) >= 0)
-                       {
-#if HAS_IGNITE_REPORT
-                               uint8_t c;
-#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 /* 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)
-                       {
-                               ao_aprs_time = ao_time() + AO_SEC_TO_TICKS(ao_config.aprs_interval);
-                               ao_aprs_send();
-                       }
-#endif /* HAS_APRS */
-#endif /* !AO_SEND_ALL_BARO */
-                       time += ao_telemetry_interval;
-                       delay = time - ao_time();
-                       if (delay > 0) {
-                               ao_alarm(delay);
-                               ao_sleep(&telemetry);
-                               ao_clear_alarm();
-                       }
-                       else
-                               time = ao_time();
-               }
-       }
-}
-
-void
-ao_telemetry_set_interval(uint16_t interval)
-{
-       int8_t  cur = 0;
-       ao_telemetry_interval = interval;
-       
-#if AO_SEND_MEGA
-       if (interval > 1)
-               ao_telemetry_mega_data_max = 1;
-       else
-               ao_telemetry_mega_data_max = 2;
-       if (ao_telemetry_mega_data_max > cur)
-               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)
-               ao_companion_setup.update_period = AO_SEC_TO_TICKS(1);
-       ao_telemetry_companion_max = ao_companion_setup.update_period / interval;
-       if (ao_telemetry_companion_max > cur)
-               cur++;
-       ao_telemetry_companion_cur = cur;
-#endif
-
-       ao_telemetry_config_max = AO_SEC_TO_TICKS(1) / interval;
-#if HAS_COMPANION
-       if (ao_telemetry_config_max > cur)
-               cur++;
-       ao_telemetry_config_cur = cur;
-#endif
-
-#if HAS_GPS
-       if (ao_telemetry_config_max > cur)
-               cur++;
-       ao_telemetry_loc_cur = cur;
-       if (ao_telemetry_config_max > cur)
-               cur++;
-       ao_telemetry_sat_cur = cur;
-#endif
-       ao_wakeup(&telemetry);
-}
-
-#if HAS_RDF
-void
-ao_rdf_set(uint8_t rdf)
-{
-       ao_rdf = rdf;
-       if (rdf == 0)
-               ao_radio_rdf_abort();
-       else {
-               ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS;
-       }
-}
-#endif
-
-__xdata struct ao_task ao_telemetry_task;
-
-void
-ao_telemetry_init()
-{
-       ao_add_task(&ao_telemetry_task, ao_telemetry, "telemetry");
-}
diff --git a/src/core/ao_telemetry.h b/src/core/ao_telemetry.h
deleted file mode 100644 (file)
index 237a35a..0000000
+++ /dev/null
@@ -1,321 +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_TELEMETRY_H_
-#define _AO_TELEMETRY_H_
-
-/*
- * ao_telemetry.c
- */
-#define AO_MAX_CALLSIGN                        8
-#define AO_MAX_VERSION                 8
-#if LEGACY_MONITOR
-#define AO_MAX_TELEMETRY               128
-#else
-#define AO_MAX_TELEMETRY               32
-#endif
-
-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;
-};
-
-#define AO_TELEMETRY_SATELLITE_MAX_SAT 12
-
-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[AO_TELEMETRY_SATELLITE_MAX_SAT];   /* 6 */
-       uint8_t                                 unused[2];      /* 30 */
-       /* 32 */
-};
-
-#define AO_TELEMETRY_COMPANION         0x07
-
-#define AO_COMPANION_MAX_CHANNELS      12
-
-struct ao_telemetry_companion {
-       uint16_t                                serial;         /*  0 */
-       uint16_t                                tick;           /*  2 */
-       uint8_t                                 type;           /*  4 */
-       uint8_t                                 board_id;       /*  5 */
-
-       uint8_t                                 update_period;  /*  6 */
-       uint8_t                                 channels;       /*  7 */
-       uint16_t                                companion_data[AO_COMPANION_MAX_CHANNELS];      /*  8 */
-       /* 32 */
-};
-       
-#define AO_TELEMETRY_MEGA_SENSOR       0x08
-
-struct ao_telemetry_mega_sensor {
-       uint16_t        serial;         /*  0 */
-       uint16_t        tick;           /*  2 */
-       uint8_t         type;           /*  4 */
-
-       uint8_t         orient;         /*  5 angle from vertical */
-       int16_t         accel;          /*  6 Z axis */
-
-       int32_t         pres;           /*  8 Pa * 10 */
-       int16_t         temp;           /* 12 °C * 100 */
-
-       int16_t         accel_x;        /* 14 */
-       int16_t         accel_y;        /* 16 */
-       int16_t         accel_z;        /* 18 */
-
-       int16_t         gyro_x;         /* 20 */
-       int16_t         gyro_y;         /* 22 */
-       int16_t         gyro_z;         /* 24 */
-
-       int16_t         mag_x;          /* 26 */
-       int16_t         mag_y;          /* 28 */
-       int16_t         mag_z;          /* 30 */
-       /* 32 */
-};
-       
-#define AO_TELEMETRY_MEGA_DATA         0x09
-
-struct ao_telemetry_mega_data {
-       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         v_pyro;         /*  8 pyro battery voltage */
-       int8_t          sense[6];       /* 10 continuity sense */
-
-       int32_t         ground_pres;    /* 16 average pres on pad */
-       int16_t         ground_accel;   /* 20 average accel on pad */
-       int16_t         accel_plus_g;   /* 22 accel calibration at +1g */
-       int16_t         accel_minus_g;  /* 24 accel calibration at -1g */
-
-       int16_t         acceleration;   /* 26 m/s² * 16 */
-       int16_t         speed;          /* 28 m/s * 16 */
-       int16_t         height;         /* 30 m */
-       /* 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
-
-/*
- * This packet allows the full sampling rate baro
- * data to be captured over the RF link so that the
- * flight software can be tested using 'real' data.
- *
- * Along with this telemetry packet, the flight
- * code is modified to send full-rate telemetry all the time
- * and never send an RDF tone; this ensure that the full radio
- * link is available.
- */
-struct ao_telemetry_baro {
-       uint16_t                                serial;         /*  0 */
-       uint16_t                                tick;           /*  2 */
-       uint8_t                                 type;           /*  4 */
-       uint8_t                                 samples;        /*  5 number samples */
-
-       int16_t                                 baro[12];       /* 6 samples */
-       /* 32 */
-};
-
-union ao_telemetry_all {
-       struct ao_telemetry_generic             generic;
-       struct ao_telemetry_sensor              sensor;
-       struct ao_telemetry_configuration       configuration;
-       struct ao_telemetry_location            location;
-       struct ao_telemetry_satellite           satellite;
-       struct ao_telemetry_companion           companion;
-       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;
-};
-
-struct ao_telemetry_all_recv {
-       union ao_telemetry_all          telemetry;
-       int8_t                          rssi;
-       uint8_t                         status;
-};
-
-#endif /* _AO_TELEMETRY_H_ */
diff --git a/src/core/ao_usb.h b/src/core/ao_usb.h
deleted file mode 100644 (file)
index 35e64e6..0000000
+++ /dev/null
@@ -1,140 +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_USB_H_
-#define _AO_USB_H_
-
-/*
- * ao_usb.c
- */
-
-/* Put one character to the USB output queue */
-void
-ao_usb_putchar(char c);
-
-/* Get one character from the USB input queue */
-char
-ao_usb_getchar(void);
-
-/* Poll for a charcter on the USB input queue.
- * returns AO_READ_AGAIN if none are available
- */
-int
-ao_usb_pollchar(void);
-
-/* Flush the USB output queue */
-void
-ao_usb_flush(void);
-
-/* Enable the USB controller */
-void
-ao_usb_enable(void);
-
-/* Disable the USB controller */
-void
-ao_usb_disable(void);
-
-/* Initialize the USB system */
-void
-ao_usb_init(void);
-
-extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];
-
-#define AO_USB_SETUP_DIR_MASK  (0x01 << 7)
-#define AO_USB_SETUP_TYPE_MASK (0x03 << 5)
-#define AO_USB_SETUP_RECIP_MASK        (0x1f)
-
-#define AO_USB_DIR_OUT                 0
-#define AO_USB_DIR_IN                  (1 << 7)
-
-#define AO_USB_TYPE_STANDARD           0
-#define AO_USB_TYPE_CLASS              (1 << 5)
-#define AO_USB_TYPE_VENDOR             (2 << 5)
-#define AO_USB_TYPE_RESERVED           (3 << 5)
-
-#define AO_USB_RECIP_DEVICE            0
-#define AO_USB_RECIP_INTERFACE         1
-#define AO_USB_RECIP_ENDPOINT          2
-#define AO_USB_RECIP_OTHER             3
-
-/* standard requests */
-#define        AO_USB_REQ_GET_STATUS           0x00
-#define AO_USB_REQ_CLEAR_FEATURE       0x01
-#define AO_USB_REQ_SET_FEATURE         0x03
-#define AO_USB_REQ_SET_ADDRESS         0x05
-#define AO_USB_REQ_GET_DESCRIPTOR      0x06
-#define AO_USB_REQ_SET_DESCRIPTOR      0x07
-#define AO_USB_REQ_GET_CONFIGURATION   0x08
-#define AO_USB_REQ_SET_CONFIGURATION   0x09
-#define AO_USB_REQ_GET_INTERFACE       0x0A
-#define AO_USB_REQ_SET_INTERFACE       0x0B
-#define AO_USB_REQ_SYNCH_FRAME         0x0C
-
-#define AO_USB_DESC_DEVICE             1
-#define AO_USB_DESC_CONFIGURATION      2
-#define AO_USB_DESC_STRING             3
-#define AO_USB_DESC_INTERFACE          4
-#define AO_USB_DESC_ENDPOINT           5
-#define AO_USB_DESC_DEVICE_QUALIFIER   6
-#define AO_USB_DESC_OTHER_SPEED                7
-#define AO_USB_DESC_INTERFACE_POWER    8
-
-#define AO_USB_GET_DESC_TYPE(x)                (((x)>>8)&0xFF)
-#define AO_USB_GET_DESC_INDEX(x)       ((x)&0xFF)
-
-#define AO_USB_CONTROL_EP      0
-#define AO_USB_CONTROL_SIZE    32
-
-#define AO_USB_INT_EP          1
-#define AO_USB_INT_SIZE                8
-
-#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
- */
-#define AO_USB_IN_SIZE         64
-#define AO_USB_OUT_SIZE                64
-
-#define AO_USB_EP0_IDLE                0
-#define AO_USB_EP0_DATA_IN     1
-#define AO_USB_EP0_DATA_OUT    2
-#define AO_USB_EP0_STALL       3
-
-#define LE_WORD(x)    ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
-
-/* CDC definitions */
-#define AO_USB_CS_INTERFACE            0x24
-#define AO_USB_CS_ENDPOINT             0x25
-
-#define AO_USB_SET_LINE_CODING         0x20
-#define AO_USB_GET_LINE_CODING         0x21
-#define AO_USB_SET_CONTROL_LINE_STATE  0x22
-
-/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */
-struct ao_usb_line_coding {
-       uint32_t        rate;
-       uint8_t         char_format;
-       uint8_t         parity;
-       uint8_t         data_bits;
-} ;
-
-#endif /* _AO_USB_H_ */
index 0a6c72ce9e2a1af03fd81f131982bf660e6e78fb..8a1b6a4df2763e1e74ec9f61a082dc012f0da082 100644 (file)
 #endif
 
 #include <ao_aprs.h>
-#include <math.h>
 
 // Public methods, constants, and data structures for each class.
 
@@ -512,23 +511,38 @@ static int tncComment(uint8_t *buf)
 {
 #if HAS_ADC
        struct ao_data packet;
-       
+
        ao_arch_critical(ao_data_get(&packet););
 
        int16_t battery = ao_battery_decivolt(packet.adc.v_batt);
+#ifdef AO_SENSE_DROGUE
        int16_t apogee = ao_ignite_decivolt(AO_SENSE_DROGUE(&packet));
+#endif
+#ifdef AO_SENSE_MAIN
        int16_t main = ao_ignite_decivolt(AO_SENSE_MAIN(&packet));
+#endif
 
        return sprintf((char *) buf,
-                      "%c%d B%d.%d A%d.%d M%d.%d",
-                      ao_gps_locked(),
+                      "%c%d B%d.%d"
+#ifdef AO_SENSE_DROGUE
+                      " A%d.%d"
+#endif
+#ifdef AO_SENSE_MAIN
+                      " M%d.%d"
+#endif
+                      , ao_gps_locked(),
                       ao_num_sats(),
                       battery/10,
-                      battery % 10,
-                      apogee/10,
-                      apogee%10,
-                      main/10,
-                      main%10);
+                      battery % 10
+#ifdef AO_SENSE_DROGUE
+                      , apogee/10,
+                      apogee%10
+#endif
+#ifdef AO_SENSE_MAIN
+                      , main/10,
+                      main%10
+#endif
+               );
 #else
        return sprintf((char *) buf,
                       "%c%d",
@@ -537,6 +551,144 @@ static int tncComment(uint8_t *buf)
 #endif
 }
 
+/*
+ * APRS use a log encoding of altitude with a base of 1.002, such that
+ *
+ *     feet = 1.002 ** encoded_altitude
+ *
+ *     meters = (1.002 ** encoded_altitude) * 0.3048
+ *
+ *     log2(meters) = log2(1.002 ** encoded_altitude) + log2(0.3048)
+ *
+ *     log2(meters) = encoded_altitude * log2(1.002) + log2(0.3048)
+ *
+ *     encoded_altitude = (log2(meters) - log2(0.3048)) / log2(1.002)
+ *
+ *     encoded_altitude = (log2(meters) + log2(1/0.3048)) * (1/log2(1.002))
+ *
+ * We need 9 bits of mantissa to hold 1/log2(1.002) (~ 347), which leaves us
+ * 23 bits of fraction. That turns out to be *just* enough to avoid any
+ * errors in the result (cool, huh?).
+ */
+
+#define fixed23_int(x)         ((uint32_t) ((x) << 23))
+#define fixed23_one            fixed23_int(1)
+#define fixed23_two            fixed23_int(2)
+#define fixed23_half           (fixed23_one >> 1)
+#define fixed23_floor(x)       ((x) >> 23)
+#define fixed23_real(x)                ((uint32_t) ((x) * fixed23_one + 0.5))
+
+static inline uint64_t
+fixed23_mul(uint32_t x, uint32_t y)
+{
+       return ((uint64_t) x * y + fixed23_half) >> 23;
+}
+
+/*
+ * Use 30 fraction bits for the altitude. We need two bits at the
+ * top as we need to handle x, where 0 <= x < 4. We don't
+ * need 30 bits, but it's actually easier this way as we normalize
+ * the incoming value to 1 <= x < 2, and having the integer portion
+ * way up high means we don't have to deal with shifting in both
+ * directions to cover from 0 to 2**30-1.
+ */
+
+#define fixed30_int(x) ((uint32_t) ((x) << 30))
+#define fixed30_one    fixed30_int(1)
+#define fixed30_half   (fixed30_one >> 1)
+#define fixed30_two    fixed30_int(2)
+
+static inline uint32_t
+fixed30_mul(uint32_t x, uint32_t y)
+{
+       return ((uint64_t) x * y + fixed30_half) >> 30;
+}
+
+/*
+ * Fixed point log2. Takes integer argument, returns
+ * fixed point result with 23 bits of fraction
+ */
+
+static uint32_t
+ao_fixed_log2(uint32_t x)
+{
+       uint32_t        result;
+       uint32_t        frac = fixed23_one;
+
+       /* Bounds check for sanity */
+       if (x <= 0)
+               return 0;
+
+       if (x >= fixed30_one)
+               return 0xffffffff;
+
+       /*
+        * Normalize and compute integer log portion
+        *
+        * This makes 1 <= x < 2, and computes result to be
+        * the integer portion of the log2 of x
+        */
+
+       for (result = fixed23_int(30); x < fixed30_one; result -= fixed23_one, x <<= 1)
+               ;
+
+       /*
+        * Given x, find y and n such that:
+        *
+        *      x = y * 2**n            1 <= y < 2
+        *
+        * That means:
+        *
+        *      lb(x) = n + lb(y)
+        *
+        * Now, repeatedly square y to find find z and m such that:
+        *
+        *      z = y ** (2**m) 2 <= z < 4
+        *
+        * This is possible because 1 <= y < 2
+        *
+        *      lb(y) = lb(z) / 2**m
+        *
+        *              (1 + lb(z/2))
+        *            = -------------
+        *                  2**m
+        *
+        *            = 2**-m + 2**-m * lb(z/2)
+        *
+        * Note that if 2 <= z < 4, then 1 <= (z/2) < 2, so we can
+        * iterate to find lb(z/2)
+        *
+        * In this implementation, we don't care about the 'm' value,
+        * instead we only care about 2**-m, which we store in 'frac'
+        */
+
+       while (frac != 0 && x != fixed30_one) {
+               /* Repeatedly square x until 2 <= x < 4 */
+               while (x < fixed30_two) {
+                       x = fixed30_mul(x, x);
+
+                       /* Divide the fractional result bit by 2 */
+                       frac >>= 1;
+               }
+
+               /* Add in this result bit */
+               result |= frac;
+
+               /* Make 1 <= x < 2 again and iterate */
+               x >>= 1;
+       }
+       return result;
+}
+
+#define APRS_LOG_CONVERT       fixed23_real(1.714065192056127)
+#define APRS_LOG_BASE          fixed23_real(346.920048461100941)
+
+static int
+ao_aprs_encode_altitude(int meters)
+{
+       return fixed23_floor(fixed23_mul(ao_fixed_log2(meters) + APRS_LOG_CONVERT, APRS_LOG_BASE) + fixed23_half);
+}
+
 /**
  *   Generate the plain text position packet.
  */
@@ -565,10 +717,7 @@ static int tncPositionPacket(void)
     lat = ((uint64_t) 380926 * (900000000 - latitude)) / 10000000;
     lon = ((uint64_t) 190463 * (1800000000 + longitude)) / 10000000;
 
-#define ALTITUDE_LOG_BASE      0.001998002662673f      /* log(1.002) */
-
-    alt = (altitude * (int32_t) 10000 + (3048/2)) / (int32_t) 3048;
-    alt = logf((float) altitude) * (1/ALTITUDE_LOG_BASE);
+    alt = ao_aprs_encode_altitude(altitude);
 
     tncCompressInt(buf, lat, 4);
     buf += 4;
index f0f72d4d4f294d2ec02fd020827556cc7ced6d1c..f250e714a98ad5138b5d95ee41d9636613bfe325 100644 (file)
@@ -52,8 +52,8 @@ struct ao_cc115l_reg {
 
 #if CC115L_TRACE
 
-const static struct ao_cc115l_reg ao_cc115l_reg[];
-const static char *cc115l_state_name[];
+static const struct ao_cc115l_reg ao_cc115l_reg[];
+static const char *cc115l_state_name[];
 
 enum ao_cc115l_trace_type {
        trace_strobe,
@@ -88,6 +88,8 @@ static void trace_add(enum ao_cc115l_trace_type type, int16_t addr, int16_t valu
        case trace_strobe:
                comment = cc115l_state_name[(value >> 4) & 0x7];
                break;
+       default:
+               break;
        }
        trace[trace_i].type = type;
        trace[trace_i].addr = addr;
@@ -197,24 +199,22 @@ ao_radio_tx_fifo_space(void)
        return CC115L_FIFO_SIZE - (ao_radio_reg_read(CC115L_TXBYTES) & CC115L_TXBYTES_NUM_TX_BYTES_MASK);
 }
 
-#if UNUSED
+#if CC115L_DEBUG
 static uint8_t
 ao_radio_status(void)
 {
        return ao_radio_strobe (CC115L_SNOP);
 }
-#endif
 
-#define ao_radio_rdf_value 0x55
-
-#if UNUSED
 static uint8_t
 ao_radio_get_marcstate(void)
 {
        return ao_radio_reg_read(CC115L_MARCSTATE) & CC115L_MARCSTATE_MASK;
 }
 #endif
-         
+
+#define ao_radio_rdf_value 0x55
+
 static void
 ao_radio_done_isr(void)
 {
@@ -612,6 +612,12 @@ ao_radio_rdf_abort(void)
 
 #define POWER_STEP     0x08
 
+#if HAS_RADIO_POWER
+#define RADIO_POWER    ao_config.radio_power
+#else
+#define RADIO_POWER    0xc0
+#endif
+
 static void
 ao_radio_stx(void)
 {
@@ -619,9 +625,10 @@ ao_radio_stx(void)
        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)
+       for (power = POWER_STEP; power < RADIO_POWER; power += POWER_STEP)
                ao_radio_reg_write(CC115L_PA, power);
-       ao_radio_reg_write(CC115L_PA, ao_config.radio_power);
+       if (power != RADIO_POWER)
+               ao_radio_reg_write(CC115L_PA, RADIO_POWER);
 }
 
 static void
@@ -668,8 +675,8 @@ ao_radio_test_cmd(void)
 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));
+       return ((ao_gpio_get(AO_CC115L_DONE_INT_PORT, AO_CC115L_DONE_INT_PIN, AO_CC115L_DONE_INT) << 1) |
+               ao_gpio_get(AO_CC115L_FIFO_INT_PORT, AO_CC115L_FIFO_INT_PIN, AO_CC115L_FIFO_INT));
 }
 #endif
 
@@ -819,7 +826,7 @@ ao_radio_send_aprs(ao_radio_fill_func fill)
 }
 
 #if CC115L_DEBUG
-const static char *cc115l_state_name[] = {
+static const char *cc115l_state_name[] = {
        [CC115L_STATUS_STATE_IDLE] = "IDLE",
        [CC115L_STATUS_STATE_TX] = "TX",
        [CC115L_STATUS_STATE_FSTXON] = "FSTXON",
@@ -828,7 +835,7 @@ const static char *cc115l_state_name[] = {
        [CC115L_STATUS_STATE_TX_FIFO_UNDERFLOW] = "TX_FIFO_UNDERFLOW",
 };
 
-const static struct ao_cc115l_reg ao_cc115l_reg[] = {
+static const struct ao_cc115l_reg ao_cc115l_reg[] = {
        { .addr = CC115L_IOCFG2, .name = "IOCFG2" },
        { .addr = CC115L_IOCFG1, .name = "IOCFG1" },
        { .addr = CC115L_IOCFG0, .name = "IOCFG0" },
@@ -874,7 +881,7 @@ const static struct ao_cc115l_reg ao_cc115l_reg[] = {
 
 static void ao_radio_show(void) {
        uint8_t status = ao_radio_status();
-       int     i;
+       unsigned int    i;
 
        ao_radio_get();
        status = ao_radio_status();
index 01169522f2ae49f53852098b8c2e9d797dc25a3f..077698a90d514a24672b3d990d867118a1c67a9c 100644 (file)
@@ -600,6 +600,14 @@ static const uint8_t ublox_enable_nav[] = {
        UBLOX_NAV_TIMEUTC
 };
 
+void
+ao_gps_set_rate(uint8_t rate)
+{
+       uint8_t i;
+       for (i = 0; i < sizeof (ublox_enable_nav); i++)
+               ao_ublox_set_message_rate(UBLOX_NAV, ublox_enable_nav[i], rate);
+}
+
 void
 ao_gps(void) __reentrant
 {
@@ -616,8 +624,7 @@ ao_gps(void) __reentrant
                ao_ublox_set_message_rate(UBLOX_NAV, ublox_disable_nav[i], 0);
 
        /* 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_gps_set_rate(1);
 
        ao_ublox_set_navigation_settings((1 << UBLOX_CFG_NAV5_MASK_DYN) | (1 << UBLOX_CFG_NAV5_MASK_FIXMODE),
                                         UBLOX_CFG_NAV5_DYNMODEL_AIRBORNE_4G,
@@ -713,7 +720,7 @@ ao_gps(void) __reentrant
                                ao_gps_data.flags |= AO_GPS_RUNNING;
                                if (nav_sol.gps_fix & (1 << NAV_SOL_FLAGS_GPSFIXOK)) {
                                        uint8_t nsat = nav_sol.nsat;
-                                       ao_gps_data.flags |= AO_GPS_VALID;
+                                       ao_gps_data.flags |= AO_GPS_VALID | AO_GPS_COURSE_VALID;
                                        if (nsat > 15)
                                                nsat = 15;
                                        ao_gps_data.flags |= nsat;
index a5d28e615234bd509dbca8566c179e200f30d866..9e64283696eaf3c25c68510764e57c79750ca1f4 100644 (file)
@@ -36,7 +36,7 @@ ao_lco_query(uint16_t box, struct ao_pad_query *query, uint16_t *tick_offset)
        command.channels = 0;
        ao_radio_cmac_send(&command, sizeof (command));
        sent_time = ao_time();
-       r = ao_radio_cmac_recv(query, sizeof (*query), AO_MS_TO_TICKS(20));
+       r = ao_radio_cmac_recv(query, sizeof (*query), AO_MS_TO_TICKS(10));
        if (r == AO_RADIO_CMAC_OK)
                *tick_offset = sent_time - query->tick;
        ao_mutex_put(&ao_lco_mutex);
index 58ab91973ce0b63b5a51c0e6b053a1b903d10fa8..6098699edf4b1735a8a0ede41fd163722ba809aa 100644 (file)
@@ -21,8 +21,8 @@
 
 #if HAS_MS5607 || HAS_MS5611
 
-static __xdata struct ao_ms5607_prom   ms5607_prom;
-static __xdata uint8_t                 ms5607_configured;
+__xdata struct ao_ms5607_prom  ao_ms5607_prom;
+static __xdata uint8_t         ms5607_configured;
 
 static void
 ao_ms5607_start(void) {
@@ -111,7 +111,7 @@ ao_ms5607_setup(void)
                return;
        ms5607_configured = 1;
        ao_ms5607_reset();
-       ao_ms5607_prom_read(&ms5607_prom);
+       ao_ms5607_prom_read(&ao_ms5607_prom);
 }
 
 static __xdata volatile uint8_t        ao_ms5607_done;
@@ -208,14 +208,14 @@ __xdata struct ao_task ao_ms5607_task;
 void
 ao_ms5607_info(void)
 {
-       printf ("ms5607 reserved: %u\n", ms5607_prom.reserved);
-       printf ("ms5607 sens: %u\n", ms5607_prom.sens);
-       printf ("ms5607 off: %u\n", ms5607_prom.off);
-       printf ("ms5607 tcs: %u\n", ms5607_prom.tcs);
-       printf ("ms5607 tco: %u\n", ms5607_prom.tco);
-       printf ("ms5607 tref: %u\n", ms5607_prom.tref);
-       printf ("ms5607 tempsens: %u\n", ms5607_prom.tempsens);
-       printf ("ms5607 crc: %u\n", ms5607_prom.crc);
+       printf ("ms5607 reserved: %u\n", ao_ms5607_prom.reserved);
+       printf ("ms5607 sens: %u\n", ao_ms5607_prom.sens);
+       printf ("ms5607 off: %u\n", ao_ms5607_prom.off);
+       printf ("ms5607 tcs: %u\n", ao_ms5607_prom.tcs);
+       printf ("ms5607 tco: %u\n", ao_ms5607_prom.tco);
+       printf ("ms5607 tref: %u\n", ao_ms5607_prom.tref);
+       printf ("ms5607 tempsens: %u\n", ao_ms5607_prom.tempsens);
+       printf ("ms5607 crc: %u\n", ao_ms5607_prom.crc);
 }
 
 static void
index 206efd64f8c2e8ccf7934ef0441c3bff70f16b78..b58178fd136fcce36e6b8aaca4bcd2419b25d1bb 100644 (file)
@@ -57,6 +57,7 @@ struct ao_ms5607_value {
 };
 
 extern __xdata struct ao_ms5607_sample ao_ms5607_current;
+extern __xdata struct ao_ms5607_prom   ao_ms5607_prom;
 
 void
 ao_ms5607_setup(void);
@@ -74,7 +75,4 @@ void
 ao_ms5607_convert(__xdata struct ao_ms5607_sample *sample,
                  __xdata struct ao_ms5607_value *value);
 
-void
-ao_ms5607_get_prom(__data struct ao_ms5607_prom *prom);
-
 #endif /* _AO_MS5607_H_ */
index bfb952a47e7b2c8a1da54701a34765d6cd7e38f3..4d412cbe9ed18ee3e1d47fbdaf1a250230917efa 100644 (file)
@@ -25,16 +25,16 @@ ao_ms5607_convert(struct ao_ms5607_sample *sample, struct ao_ms5607_value *value
        int64_t OFF;
        int64_t SENS;
 
-       dT = sample->temp - ((int32_t) ms5607_prom.tref << 8);
+       dT = sample->temp - ((int32_t) ao_ms5607_prom.tref << 8);
        
-       TEMP = 2000 + (((int64_t) dT * ms5607_prom.tempsens) >> 23);
+       TEMP = 2000 + (((int64_t) dT * ao_ms5607_prom.tempsens) >> 23);
 
 #if HAS_MS5611
-       OFF = ((int64_t) ms5607_prom.off << 16) + (((int64_t) ms5607_prom.tco * dT) >> 7);
-       SENS = ((int64_t) ms5607_prom.sens << 15) + (((int64_t) ms5607_prom.tcs * dT) >> 8);
+       OFF = ((int64_t) ao_ms5607_prom.off << 16) + (((int64_t) ao_ms5607_prom.tco * dT) >> 7);
+       SENS = ((int64_t) ao_ms5607_prom.sens << 15) + (((int64_t) ao_ms5607_prom.tcs * dT) >> 8);
 #else
-       OFF = ((int64_t) ms5607_prom.off << 17) + (((int64_t) ms5607_prom.tco * dT) >> 6);
-       SENS = ((int64_t) ms5607_prom.sens << 16) + (((int64_t) ms5607_prom.tcs * dT) >> 7);
+       OFF = ((int64_t) ao_ms5607_prom.off << 17) + (((int64_t) ao_ms5607_prom.tco * dT) >> 6);
+       SENS = ((int64_t) ao_ms5607_prom.sens << 16) + (((int64_t) ao_ms5607_prom.tcs * dT) >> 7);
 #endif
 
        if (TEMP < 2000) {
index f3a48c464b784830462bd29b840abaa57a826f11..a74086d9cb4086a2efd0cc2d993295a762dfe677 100644 (file)
@@ -40,30 +40,30 @@ ao_ms5607_convert(__xdata struct ao_ms5607_sample *sample,
        __LOCAL ao_int64_t SENS;
        __LOCAL ao_int64_t a;
 
-       dT = sample->temp - ((int32_t) ms5607_prom.tref << 8);
+       dT = sample->temp - ((int32_t) ao_ms5607_prom.tref << 8);
        
-       /* TEMP = 2000 + (((int64_t) dT * ms5607_prom.tempsens) >> 23); */
-       ao_mul64_32_32(&a, dT, ms5607_prom.tempsens);
+       /* TEMP = 2000 + (((int64_t) dT * ao_ms5607_prom.tempsens) >> 23); */
+       ao_mul64_32_32(&a, dT, ao_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);*/
+       /* OFF = ((int64_t) ao_ms5607_prom.off << SHIFT_OFF) + (((int64_t) ao_ms5607_prom.tco * dT) >> SHIFT_TCO);*/
 #if SHIFT_OFF > 16
-       OFF.high = ms5607_prom.off >> (32 - SHIFT_OFF);
+       OFF.high = ao_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);
+       OFF.low = (uint32_t) ao_ms5607_prom.off << SHIFT_OFF;
+       ao_mul64_32_32(&a, ao_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 = ((int64_t) ao_ms5607_prom.sens << SHIFT_SENS) + (((int64_t) ao_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);
+       SENS.low = (uint32_t) ao_ms5607_prom.sens << SHIFT_SENS;
+       ao_mul64_32_32(&a, ao_ms5607_prom.tcs, dT);
        ao_rshift64(&a, &a, SHIFT_TCS);
        ao_plus64(&SENS, &SENS, &a);
        /**/
index 62ae68e98d976dcdabee72103ce32300ad355e21..144cbd70a8834e4053e67c6bebec423e68ae8175 100644 (file)
@@ -153,11 +153,11 @@ ao_pad_monitor(void)
                         *
                         *              v_pyro \
                         *      100k            igniter
-                        *              output /        
+                        *              output /
                         *      100k           \
                         *              sense   relay
-                        *      27k            / 
-                        *              gnd ---   
+                        *      27k            /
+                        *              gnd ---
                         *
                         *      If the relay is closed, then sense will be 0
                         *      If no igniter is present, then sense will be v_pyro * 27k/227k = pyro * 127 / 227 ~= pyro/2
index d376b9681194fc94d00d394781f74b19a75ace98..6d1b5fae6b6267d1a6457d3066490888d72e8084 100644 (file)
@@ -66,6 +66,24 @@ ao_led_set_mask(uint8_t colors, uint8_t mask)
        ao_led_apply();
 }
 
+#define LED_TEST       1
+#if LED_TEST
+static void
+ao_led_test(void)
+{
+       ao_cmd_hexbyte();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       ao_led_set(ao_cmd_lex_i);
+       printf("LEDs set to %02x\n", ao_cmd_lex_i);
+}
+
+static const struct ao_cmds ao_led_cmds[] = {
+       { ao_led_test,  "l <value>\0Set LEDs to <value>" },
+       { 0, NULL }
+};
+#endif
+
 void
 ao_led_toggle(uint8_t colors)
 {
@@ -86,4 +104,7 @@ ao_led_init(uint8_t enable)
 {
        (void) enable;
        ao_enable_output(AO_PCA9922_CS_PORT, AO_PCA9922_CS_PIN, AO_PCA9922_CS, 1);
+#if LED_TEST
+       ao_cmd_register(&ao_led_cmds[0]);
+#endif
 }
index d07488d08d4f9307b661a0f690f9447dab4fec73..0cdcc9fb464b413541e891cac4cc2d392398f53c 100644 (file)
 #include <ao_event.h>
 
 __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];
+static uint8_t  ao_quadrature_state[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)))
+struct ao_debounce {
+       uint8_t state;
+       uint8_t count;
+};
+
+static struct ao_debounce ao_debounce_state[AO_QUADRATURE_COUNT][2];
 
 #define port(q)        AO_QUADRATURE_ ## q ## _PORT
 #define bita(q) AO_QUADRATURE_ ## q ## _A
@@ -35,14 +38,35 @@ static int8_t       ao_quadrature_raw[AO_QUADRATURE_COUNT];
 #define pinb(q) AO_QUADRATURE_ ## q ## _B ## _PIN
 #define isr(q)  ao_quadrature_isr_ ## q
 
-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);
+#define DEBOUNCE       10
 
-       return ~((((v >> pin_a) & 1) | (((v >> pin_b) & 1) << 1))) & 3;
+static uint8_t
+ao_debounce(uint8_t cur, struct ao_debounce *debounce)
+{
+       if (cur == debounce->state)
+               debounce->count = 0;
+       else {
+               if (++debounce->count == DEBOUNCE) {
+                       debounce->state = cur;
+                       debounce->count = 0;
+               }
+       }
+       return debounce->state;
 }
 
-#define _ao_quadrature_get(q)  ao_quadrature_read(port(q), bita(q), bitb(q))
+static uint16_t
+ao_quadrature_read(struct stm_gpio *gpio, uint8_t pin_a, uint8_t pin_b, struct ao_debounce debounce_state[2]) {
+       uint16_t        v = ~stm_gpio_get_all(gpio);
+       uint8_t         a = (v >> pin_a) & 1;
+       uint8_t         b = (v >> pin_b) & 1;
+
+       a = ao_debounce(a, &debounce_state[0]);
+       b = ao_debounce(b, &debounce_state[1]);
+
+       return a | (b << 1);
+}
+
+#define _ao_quadrature_get(q)  ao_quadrature_read(port(q), bita(q), bitb(q), ao_debounce_state[q])
 
 static void
 _ao_quadrature_queue(uint8_t q, int8_t step)
@@ -54,51 +78,28 @@ _ao_quadrature_queue(uint8_t q, int8_t step)
        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_set(uint8_t q, uint8_t new) {
+       uint8_t old = ao_quadrature_state[q];
 
-       ao_quadrature_raw[q] += step[ao_quadrature_state[q]];
-       if (value == 0) {
-               if (ao_quadrature_raw[q] == 4)
+       if (old != new && new == 0) {
+               if (old & 2)
                        _ao_quadrature_queue(q, 1);
-               else if (ao_quadrature_raw[q] == -4)
+               else if (old & 1)
                        _ao_quadrature_queue(q, -1);
-               ao_quadrature_raw[q] = 0;
        }
+       ao_quadrature_state[q] = new;
 }
 
 static void
 ao_quadrature_isr(void)
 {
+#if AO_QUADRATURE_COUNT > 0
        _ao_quadrature_set(0, _ao_quadrature_get(0));
+#endif
+#if AO_QUADRATURE_COUNT > 1
        _ao_quadrature_set(1, _ao_quadrature_get(1));
+#endif
 }
 
 int32_t
@@ -120,6 +121,8 @@ static void
 ao_quadrature_test(void)
 {
        uint8_t q;
+       int32_t c;
+       uint8_t s;
 
        ao_cmd_decimal();
        q = ao_cmd_lex_i;
@@ -127,10 +130,18 @@ ao_quadrature_test(void)
                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]);
+
+       c = -10000;
+       s = 0;
+       while (ao_quadrature_count[q] != 10) {
+               if (ao_quadrature_count[q] != c ||
+                   ao_quadrature_state[q] != s) {
+                       c = ao_quadrature_count[q];
+                       s = ao_quadrature_state[q];
+                       printf ("count %3d state %2x\n", c, s);
+                       flush();
+               }
+       }
 #if 0
        for (;;) {
                int32_t c;
diff --git a/src/easymega-v0.1/.gitignore b/src/easymega-v0.1/.gitignore
new file mode 100644 (file)
index 0000000..410943d
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+easymega-*.elf
diff --git a/src/easymega-v0.1/Makefile b/src/easymega-v0.1/Makefile
new file mode 100644 (file)
index 0000000..6661985
--- /dev/null
@@ -0,0 +1,144 @@
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_boot.h \
+       ao_companion.h \
+       ao_data.h \
+       ao_sample.h \
+       ao_pins.h \
+       altitude-pa.h \
+       ao_kalman.h \
+       ao_product.h \
+       ao_ms5607.h \
+       ao_hmc5883.h \
+       ao_mpu6000.h \
+       ao_mma655x.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 \
+       ef_log.c
+
+ALTOS_SRC = \
+       ao_boot_chain.c \
+       ao_interrupt.c \
+       ao_product.c \
+       ao_romconfig.c \
+       ao_cmd.c \
+       ao_config.c \
+       ao_task.c \
+       ao_led.c \
+       ao_stdio.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_mutex.c \
+       ao_ignite.c \
+       ao_freq.c \
+       ao_dma_stm.c \
+       ao_spi_stm.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_convert_volt.c \
+       ao_log.c \
+       ao_log_mega.c \
+       ao_sample.c \
+       ao_kalman.c \
+       ao_flight.c \
+       ao_companion.c \
+       ao_pyro.c \
+       $(MATH_SRC) \
+       $(PROFILE) \
+       $(SAMPLE_PROFILE) \
+       $(STACK_GUARD)
+
+PRODUCT=EasyMega-v0.1
+PRODUCT_DEF=-DEASYMEGA
+IDPRODUCT=0x0023
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g
+
+PROGNAME=easymega-v0.1
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_easymega.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/easymega-v0.1/ao_easymega.c b/src/easymega-v0.1/ao_easymega.c
new file mode 100644 (file)
index 0000000..e217c33
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2014 Bdale Garbee <bdale@gag.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_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_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_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/easymega-v0.1/ao_pins.h b/src/easymega-v0.1/ao_pins.h
new file mode 100644 (file)
index 0000000..cb6e398
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright © 2014 Bdale Garbee <bdale@gag.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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      0
+
+#define HAS_SERIAL_2           0
+#define USE_SERIAL_2_STDIN     0
+#define SERIAL_2_PA2_PA3       0
+#define SERIAL_2_PD5_PD6       0
+
+#define HAS_SERIAL_3           0
+#define USE_SERIAL_3_STDIN     0
+#define SERIAL_3_PB10_PB11     0
+#define SERIAL_3_PC10_PC11     0
+#define SERIAL_3_PD8_PD9       0
+
+#define ao_gps_getchar         ao_serial1_getchar
+#define ao_gps_putchar         ao_serial1_putchar
+#define ao_gps_set_speed       ao_serial1_set_speed
+#define ao_gps_fifo            (ao_stm_usart1.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_BATTERY_REPORT     1
+#define HAS_RADIO              0
+#define HAS_TELEMETRY          0
+#define HAS_APRS               0
+
+#define HAS_SPI_1              1
+#define SPI_1_PA5_PA6_PA7      1       /* Barometer */
+#define SPI_1_PB3_PB4_PB5      1       /* Accelerometer, Gyro */
+#define SPI_1_PE13_PE14_PE15   0       
+#define SPI_1_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       0
+#define PACKET_HAS_MASTER      0
+
+#define LOW_LEVEL_DEBUG                0
+
+#define LED_PORT_ENABLE                STM_RCC_AHBENR_GPIOAEN
+#define LED_PORT               (&stm_gpioa)
+#define LED_PIN_RED            9
+#define LED_PIN_GREEN          10
+#define AO_LED_RED             (1 << LED_PIN_RED)
+#define AO_LED_GREEN           (1 << LED_PIN_GREEN)
+
+#define LEDS_AVAILABLE         (AO_LED_RED | AO_LED_GREEN)
+
+#define HAS_GPS                        0
+#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_gpioa)
+#define AO_PYRO_PIN_0  15
+
+/* Pyro B */
+#define AO_PYRO_PORT_1 (&stm_gpioc)
+#define AO_PYRO_PIN_1  10
+
+/* Pyro C */
+#define AO_PYRO_PORT_2 (&stm_gpiob)
+#define AO_PYRO_PIN_2  11
+
+/* Pyro D */
+#define AO_PYRO_PORT_3 (&stm_gpiob)
+#define AO_PYRO_PIN_3  10
+
+/* Drogue */
+#define AO_IGNITER_DROGUE_PORT (&stm_gpioa)
+#define AO_IGNITER_DROGUE_PIN  0
+
+/* Main */
+#define AO_IGNITER_MAIN_PORT   (&stm_gpioa)
+#define AO_IGNITER_MAIN_PIN    1
+
+/* 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         14
+#define AO_ADC_SENSE_A_PORT    (&stm_gpioc)
+#define AO_ADC_SENSE_A_PIN     4
+
+#define AO_ADC_SENSE_B         15
+#define AO_ADC_SENSE_B_PORT    (&stm_gpioc)
+#define AO_ADC_SENSE_B_PIN     5
+
+#define AO_ADC_SENSE_C         13
+#define AO_ADC_SENSE_C_PORT    (&stm_gpioc)
+#define AO_ADC_SENSE_C_PIN     3
+
+#define AO_ADC_SENSE_D         12
+#define AO_ADC_SENSE_D_PORT    (&stm_gpioc)
+#define AO_ADC_SENSE_D_PIN     2
+
+#define AO_ADC_SENSE_DROGUE    11
+#define AO_ADC_SENSE_DROGUE_PORT       (&stm_gpioc)
+#define AO_ADC_SENSE_DROGUE_PIN        1
+
+#define AO_ADC_SENSE_MAIN      10
+#define AO_ADC_SENSE_MAIN_PORT (&stm_gpioc)
+#define AO_ADC_SENSE_MAIN_PIN  0
+
+#define AO_ADC_V_BATT          8
+#define AO_ADC_V_BATT_PORT     (&stm_gpiob)
+#define AO_ADC_V_BATT_PIN      0
+
+#define AO_ADC_V_PBATT         9
+#define AO_ADC_V_PBATT_PORT    (&stm_gpiob)
+#define AO_ADC_V_PBATT_PIN     1
+
+#define AO_ADC_TEMP            16
+
+#define AO_ADC_RCC_AHBENR      ((1 << STM_RCC_AHBENR_GPIOAEN) | \
+                                (1 << STM_RCC_AHBENR_GPIOEEN) | \
+                                (1 << STM_RCC_AHBENR_GPIOBEN))
+
+#define AO_NUM_ADC_PIN         (AO_ADC_NUM_SENSE + 2)
+
+#define AO_ADC_PIN0_PORT       AO_ADC_SENSE_A_PORT
+#define AO_ADC_PIN0_PIN                AO_ADC_SENSE_A_PIN
+#define AO_ADC_PIN1_PORT       AO_ADC_SENSE_B_PORT
+#define AO_ADC_PIN1_PIN                AO_ADC_SENSE_B_PIN
+#define AO_ADC_PIN2_PORT       AO_ADC_SENSE_C_PORT
+#define AO_ADC_PIN2_PIN                AO_ADC_SENSE_C_PIN
+#define AO_ADC_PIN3_PORT       AO_ADC_SENSE_D_PORT
+#define AO_ADC_PIN3_PIN                AO_ADC_SENSE_D_PIN
+#define AO_ADC_PIN4_PORT       AO_ADC_SENSE_DROGUE_PORT
+#define AO_ADC_PIN4_PIN                AO_ADC_SENSE_DROGUE_PIN
+#define AO_ADC_PIN5_PORT       AO_ADC_SENSE_MAIN_PORT
+#define AO_ADC_PIN5_PIN                AO_ADC_SENSE_MAIN_PIN
+#define AO_ADC_PIN6_PORT       AO_ADC_V_BATT_PORT
+#define AO_ADC_PIN6_PIN                AO_ADC_V_BATT_PIN
+#define AO_ADC_PIN7_PORT       AO_ADC_V_PBATT_PORT
+#define AO_ADC_PIN7_PIN                AO_ADC_V_PBATT_PIN
+
+#define AO_NUM_ADC             (AO_ADC_NUM_SENSE + 3)
+
+#define AO_ADC_SQ1             AO_ADC_SENSE_A
+#define AO_ADC_SQ2             AO_ADC_SENSE_B
+#define AO_ADC_SQ3             AO_ADC_SENSE_C
+#define AO_ADC_SQ4             AO_ADC_SENSE_D
+#define AO_ADC_SQ5             AO_ADC_SENSE_DROGUE
+#define AO_ADC_SQ6             AO_ADC_SENSE_MAIN
+#define AO_ADC_SQ7             AO_ADC_V_BATT
+#define AO_ADC_SQ8             AO_ADC_V_PBATT
+#define AO_ADC_SQ9             AO_ADC_TEMP
+
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS    56      /* 5.6k */
+#define AO_BATTERY_DIV_MINUS   100     /* 10k */
+
+/*
+ * Voltage divider on ADC igniter samplers
+ */
+#define AO_IGNITE_DIV_PLUS     100     /* 100k */
+#define AO_IGNITE_DIV_MINUS    27      /* 27k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV    33
+
+/*
+ * Pressure sensor settings
+ */
+#define HAS_MS5607             1
+#define HAS_MS5611             0
+#define AO_MS5607_PRIVATE_PINS 1
+#define AO_MS5607_CS_PORT      (&stm_gpioa)
+#define AO_MS5607_CS_PIN       3
+#define AO_MS5607_CS_MASK      (1 << AO_MS5607_CS_PIN)
+#define AO_MS5607_MISO_PORT    (&stm_gpioa)
+#define AO_MS5607_MISO_PIN     6
+#define AO_MS5607_MISO_MASK    (1 << AO_MS5607_MISO_PIN)
+#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_PIN      12
+#define AO_M25_SPI_CS_MASK     (1 << AO_M25_SPI_CS_PIN)
+#define AO_M25_SPI_BUS         AO_SPI_2_PB13_PB14_PB15
+
+/*
+ * Mag sensor (hmc5883)
+ */
+
+#define HAS_HMC5883            1
+#define AO_HMC5883_INT_PORT    (&stm_gpioc)
+#define AO_HMC5883_INT_PIN     14
+#define AO_HMC5883_I2C_INDEX   STM_I2C_INDEX(1)
+
+/*
+ * mpu6000
+ */
+
+#define HAS_MPU6000            1
+#define AO_MPU6000_INT_PORT    (&stm_gpioc)
+#define AO_MPU6000_INT_PIN     15
+#define AO_MPU6000_SPI_BUS     AO_SPI_1_PB3_PB4_PB5
+#define AO_MPU6000_SPI_CS_PORT (&stm_gpioc)
+#define AO_MPU6000_SPI_CS_PIN  13
+#define HAS_IMU                        1
+
+/*
+ * mma655x
+ */
+
+#define HAS_MMA655X            1
+#define AO_MMA655X_SPI_INDEX   AO_SPI_1_PB3_PB4_PB5
+#define AO_MMA655X_CS_PORT     (&stm_gpioc)
+#define AO_MMA655X_CS_PIN      12
+
+#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                0
+#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/easymega-v0.1/flash-loader/Makefile b/src/easymega-v0.1/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..35312fd
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=easymega-v0.1
+include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/easymega-v0.1/flash-loader/ao_pins.h b/src/easymega-v0.1/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..445289b
--- /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_gpiob
+#define AO_BOOT_APPLICATION_PIN                6
+#define AO_BOOT_APPLICATION_VALUE      1
+#define AO_BOOT_APPLICATION_MODE       AO_EXTI_MODE_PULL_UP
+
+#endif /* _AO_PINS_H_ */
index 7dae26922568baa65266bd276d99ae21d1a19af2..654be22bffa539378fcb0be747b3e544ec1133f1 100644 (file)
@@ -32,6 +32,7 @@ ALTOS_SRC = \
        ao_sample.c \
        ao_data.c \
        ao_convert_pa.c \
+       ao_convert_volt.c \
        ao_task.c \
        ao_log.c \
        ao_log_mini.c \
index e721030d84201311706cdee0a99364bdf1f661c4..0edde5a2315d755bd89176e599052c89b783889c 100644 (file)
@@ -15,8 +15,8 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-#define HAS_BEEP       1
-#define        HAS_LED         0
+#define HAS_BEEP               1
+#define HAS_BATTERY_REPORT     1
 
 #define AO_STACK_SIZE  384
 
@@ -134,3 +134,20 @@ struct ao_adc {
 #define AO_ADC_DUMP(p) \
        printf("tick: %5u apogee: %5d main: %5d batt: %5d\n", \
               (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt)
+
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS    100     /* 100k */
+#define AO_BATTERY_DIV_MINUS   27      /* 27k */
+
+/*
+ * Voltage divider on ADC igniter samplers
+ */
+#define AO_IGNITE_DIV_PLUS     100     /* 100k */
+#define AO_IGNITE_DIV_MINUS    27      /* 27k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV    33
diff --git a/src/kernel/altitude.h b/src/kernel/altitude.h
new file mode 100644 (file)
index 0000000..a278bbc
--- /dev/null
@@ -0,0 +1,132 @@
+/*max error 3.197865153490684 at   0.782%. Average error 0.260150920474668*/
+#define NALT 129
+#define ALT_FRAC_BITS 8
+    15835, /*  10.56 kPa   0.000% */
+    15332, /*  11.42 kPa   0.781% */
+    14868, /*  12.29 kPa   1.563% */
+    14435, /*  13.16 kPa   2.344% */
+    14030, /*  14.02 kPa   3.125% */
+    13649, /*  14.90 kPa   3.906% */
+    13290, /*  15.76 kPa   4.688% */
+    12950, /*  16.63 kPa   5.469% */
+    12627, /*  17.50 kPa   6.250% */
+    12320, /*  18.37 kPa   7.031% */
+    12027, /*  19.24 kPa   7.813% */
+    11747, /*  20.10 kPa   8.594% */
+    11479, /*  20.97 kPa   9.375% */
+    11222, /*  21.84 kPa  10.156% */
+    10975, /*  22.71 kPa  10.938% */
+    10736, /*  23.58 kPa  11.719% */
+    10504, /*  24.44 kPa  12.500% */
+    10278, /*  25.31 kPa  13.281% */
+    10059, /*  26.18 kPa  14.063% */
+     9846, /*  27.05 kPa  14.844% */
+     9638, /*  27.91 kPa  15.625% */
+     9435, /*  28.78 kPa  16.406% */
+     9237, /*  29.65 kPa  17.188% */
+     9044, /*  30.52 kPa  17.969% */
+     8855, /*  31.39 kPa  18.750% */
+     8670, /*  32.26 kPa  19.531% */
+     8490, /*  33.13 kPa  20.313% */
+     8313, /*  33.99 kPa  21.094% */
+     8140, /*  34.86 kPa  21.875% */
+     7970, /*  35.73 kPa  22.656% */
+     7803, /*  36.60 kPa  23.438% */
+     7640, /*  37.47 kPa  24.219% */
+     7480, /*  38.33 kPa  25.000% */
+     7322, /*  39.20 kPa  25.781% */
+     7168, /*  40.07 kPa  26.563% */
+     7016, /*  40.94 kPa  27.344% */
+     6867, /*  41.80 kPa  28.125% */
+     6720, /*  42.67 kPa  28.906% */
+     6575, /*  43.54 kPa  29.688% */
+     6433, /*  44.41 kPa  30.469% */
+     6294, /*  45.28 kPa  31.250% */
+     6156, /*  46.15 kPa  32.031% */
+     6020, /*  47.01 kPa  32.813% */
+     5887, /*  47.88 kPa  33.594% */
+     5755, /*  48.75 kPa  34.375% */
+     5625, /*  49.62 kPa  35.156% */
+     5497, /*  50.49 kPa  35.938% */
+     5371, /*  51.35 kPa  36.719% */
+     5247, /*  52.22 kPa  37.500% */
+     5124, /*  53.09 kPa  38.281% */
+     5003, /*  53.96 kPa  39.063% */
+     4883, /*  54.83 kPa  39.844% */
+     4765, /*  55.69 kPa  40.625% */
+     4648, /*  56.56 kPa  41.406% */
+     4533, /*  57.43 kPa  42.188% */
+     4419, /*  58.30 kPa  42.969% */
+     4307, /*  59.17 kPa  43.750% */
+     4196, /*  60.03 kPa  44.531% */
+     4086, /*  60.90 kPa  45.313% */
+     3977, /*  61.77 kPa  46.094% */
+     3870, /*  62.63 kPa  46.875% */
+     3764, /*  63.51 kPa  47.656% */
+     3659, /*  64.38 kPa  48.438% */
+     3555, /*  65.24 kPa  49.219% */
+     3453, /*  66.11 kPa  50.000% */
+     3351, /*  66.98 kPa  50.781% */
+     3250, /*  67.85 kPa  51.563% */
+     3151, /*  68.72 kPa  52.344% */
+     3052, /*  69.58 kPa  53.125% */
+     2955, /*  70.45 kPa  53.906% */
+     2858, /*  71.32 kPa  54.688% */
+     2763, /*  72.19 kPa  55.469% */
+     2668, /*  73.06 kPa  56.250% */
+     2574, /*  73.92 kPa  57.031% */
+     2482, /*  74.79 kPa  57.813% */
+     2390, /*  75.66 kPa  58.594% */
+     2298, /*  76.52 kPa  59.375% */
+     2208, /*  77.40 kPa  60.156% */
+     2119, /*  78.26 kPa  60.938% */
+     2030, /*  79.13 kPa  61.719% */
+     1942, /*  80.00 kPa  62.500% */
+     1855, /*  80.87 kPa  63.281% */
+     1769, /*  81.74 kPa  64.063% */
+     1683, /*  82.60 kPa  64.844% */
+     1598, /*  83.47 kPa  65.625% */
+     1514, /*  84.34 kPa  66.406% */
+     1430, /*  85.21 kPa  67.188% */
+     1347, /*  86.08 kPa  67.969% */
+     1265, /*  86.94 kPa  68.750% */
+     1184, /*  87.81 kPa  69.531% */
+     1103, /*  88.68 kPa  70.313% */
+     1023, /*  89.55 kPa  71.094% */
+      943, /*  90.41 kPa  71.875% */
+      864, /*  91.28 kPa  72.656% */
+      786, /*  92.15 kPa  73.438% */
+      708, /*  93.02 kPa  74.219% */
+      631, /*  93.89 kPa  75.000% */
+      554, /*  94.76 kPa  75.781% */
+      478, /*  95.63 kPa  76.563% */
+      403, /*  96.49 kPa  77.344% */
+      328, /*  97.36 kPa  78.125% */
+      254, /*  98.23 kPa  78.906% */
+      180, /*  99.10 kPa  79.688% */
+      106, /*  99.97 kPa  80.469% */
+       34, /* 100.83 kPa  81.250% */
+      -39, /* 101.70 kPa  82.031% */
+     -111, /* 102.57 kPa  82.813% */
+     -182, /* 103.44 kPa  83.594% */
+     -253, /* 104.30 kPa  84.375% */
+     -323, /* 105.17 kPa  85.156% */
+     -393, /* 106.04 kPa  85.938% */
+     -462, /* 106.91 kPa  86.719% */
+     -531, /* 107.78 kPa  87.500% */
+     -600, /* 108.65 kPa  88.281% */
+     -668, /* 109.51 kPa  89.063% */
+     -736, /* 110.38 kPa  89.844% */
+     -803, /* 111.25 kPa  90.625% */
+     -870, /* 112.12 kPa  91.406% */
+     -936, /* 112.99 kPa  92.188% */
+    -1002, /* 113.85 kPa  92.969% */
+    -1068, /* 114.72 kPa  93.750% */
+    -1133, /* 115.59 kPa  94.531% */
+    -1198, /* 116.46 kPa  95.313% */
+    -1262, /* 117.33 kPa  96.094% */
+    -1326, /* 118.19 kPa  96.875% */
+    -1389, /* 119.06 kPa  97.656% */
+    -1453, /* 119.93 kPa  98.438% */
+    -1516, /* 120.80 kPa  99.219% */
+    -1578, /* 121.67 kPa 100.000% */
diff --git a/src/kernel/ao.h b/src/kernel/ao.h
new file mode 100644 (file)
index 0000000..5ff9b51
--- /dev/null
@@ -0,0 +1,970 @@
+/*
+ * 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.
+ */
+
+#ifndef _AO_H_
+#define _AO_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <ao_pins.h>
+#include <ao_arch.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/* Convert a __data pointer into an __xdata pointer */
+#ifndef DATA_TO_XDATA
+#define DATA_TO_XDATA(a)       (a)
+#endif
+#ifndef PDATA_TO_XDATA
+#define PDATA_TO_XDATA(a)      (a)
+#endif
+#ifndef CODE_TO_XDATA
+#define CODE_TO_XDATA(a)       (a)
+#endif
+
+#ifndef HAS_TASK
+#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
+#include <ao_notask.h>
+#endif
+
+/*
+ * ao_panic.c
+ */
+
+#define AO_PANIC_NO_TASK       1       /* AO_NUM_TASKS is not large enough */
+#define AO_PANIC_DMA           2       /* Attempt to start DMA while active */
+#define AO_PANIC_MUTEX         3       /* Mis-using mutex API */
+#define AO_PANIC_EE            4       /* Mis-using eeprom API */
+#define AO_PANIC_LOG           5       /* Failing to read/write log data */
+#define AO_PANIC_CMD           6       /* Too many command sets registered */
+#define AO_PANIC_STDIO         7       /* Too many stdio handlers registered */
+#define AO_PANIC_REBOOT                8       /* Reboot failed */
+#define AO_PANIC_FLASH         9       /* Invalid flash part (or wrong blocksize) */
+#define AO_PANIC_USB           10      /* Trying to send USB packet while busy */
+#define AO_PANIC_BT            11      /* Communications with bluetooth device failed */
+#define AO_PANIC_STACK         12      /* Stack overflow */
+#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 */
+#define AO_PANIC_SELF_TEST_MS5607      0x40 | 4        /* Self test failure */
+
+/* Stop the operating system, beeping and blinking the reason */
+void
+ao_panic(uint8_t reason);
+
+/*
+ * ao_timer.c
+ */
+
+#ifndef AO_TICK_TYPE
+#define AO_TICK_TYPE   uint16_t
+#define AO_TICK_SIGNED int16_t
+#endif
+
+extern volatile __data AO_TICK_TYPE ao_tick_count;
+
+/* Our timer runs at 100Hz */
+#ifndef AO_HERTZ
+#define AO_HERTZ               100
+#endif
+#define AO_MS_TO_TICKS(ms)     ((ms) / (1000 / AO_HERTZ))
+#define AO_SEC_TO_TICKS(s)     ((s) * AO_HERTZ)
+
+/* Returns the current time in ticks */
+AO_TICK_TYPE
+ao_time(void);
+
+/* Suspend the current task until ticks time has passed */
+void
+ao_delay(uint16_t ticks);
+
+/* Set the ADC interval */
+void
+ao_timer_set_adc_interval(uint8_t interval);
+
+/* Timer interrupt */
+void
+ao_timer_isr(void) ao_arch_interrupt(9);
+
+/* Initialize the timer */
+void
+ao_timer_init(void);
+
+/* Initialize the hardware clock. Must be called first */
+void
+ao_clock_init(void);
+
+/*
+ * ao_mutex.c
+ */
+
+#ifndef ao_mutex_get
+void
+ao_mutex_get(__xdata uint8_t *ao_mutex) __reentrant;
+
+void
+ao_mutex_put(__xdata uint8_t *ao_mutex) __reentrant;
+#endif
+
+/*
+ * ao_cmd.c
+ */
+
+enum ao_cmd_status {
+       ao_cmd_success = 0,
+       ao_cmd_lex_error = 1,
+       ao_cmd_syntax_error = 2,
+};
+
+extern __pdata uint16_t ao_cmd_lex_i;
+extern __pdata uint32_t ao_cmd_lex_u32;
+extern __pdata char    ao_cmd_lex_c;
+extern __pdata enum ao_cmd_status ao_cmd_status;
+
+void
+ao_put_string(__code char *s);
+
+void
+ao_cmd_lex(void);
+
+void
+ao_cmd_put8(uint8_t v);
+
+void
+ao_cmd_put16(uint16_t v);
+
+uint8_t
+ao_cmd_is_white(void);
+
+void
+ao_cmd_white(void);
+
+int8_t
+ao_cmd_hexchar(char c);
+
+void
+ao_cmd_hexbyte(void);
+
+void
+ao_cmd_hex(void);
+
+void
+ao_cmd_decimal(void) __reentrant;
+
+/* Read a single hex nibble off stdin. */
+uint8_t
+ao_getnibble(void);
+
+uint8_t
+ao_match_word(__code char *word);
+
+struct ao_cmds {
+       void            (*func)(void);
+       __code char     *help;
+};
+
+void
+ao_cmd_register(const __code struct ao_cmds *cmds);
+
+void
+ao_cmd_init(void);
+
+#if HAS_CMD_FILTER
+/*
+ * Provided by an external module to filter raw command lines
+ */
+uint8_t
+ao_cmd_filter(void);
+#endif
+
+/*
+ * Various drivers
+ */
+#if HAS_ADC
+#include <ao_adc.h>
+#endif
+
+#if HAS_BEEP
+#include <ao_beep.h>
+#endif
+
+#if LEDS_AVAILABLE
+#include <ao_led.h>
+#endif
+
+#if HAS_USB
+#include <ao_usb.h>
+#endif
+
+#if HAS_EEPROM
+#include <ao_storage.h>
+#endif
+
+#if HAS_LOG
+#include <ao_log.h>
+#endif
+
+#if HAS_FLIGHT
+#include <ao_flight.h>
+#include <ao_sample.h>
+#endif
+
+/*
+ * ao_report.c
+ */
+
+#define AO_RDF_INTERVAL_TICKS  AO_SEC_TO_TICKS(5)
+#define AO_RDF_LENGTH_MS       500
+#define AO_RDF_CONTINUITY_MS   32
+#define AO_RDF_CONTINUITY_PAUSE        96
+#define AO_RDF_CONTINUITY_TOTAL        ((AO_RDF_CONTINUITY_PAUSE + AO_RDF_CONTINUITY_MS) * 3 + AO_RDF_CONTINUITY_PAUSE)
+
+/* This assumes that we're generating a 1kHz tone, which
+ * modulates the carrier at 2kbps, or 250kBps
+ */
+#define AO_MS_TO_RDF_LEN(ms) ((ms) / 4)
+
+#define AO_RADIO_RDF_LEN       AO_MS_TO_RDF_LEN(AO_RDF_LENGTH_MS)
+#define AO_RADIO_CONT_TONE_LEN AO_MS_TO_RDF_LEN(AO_RDF_CONTINUITY_MS)
+#define AO_RADIO_CONT_PAUSE_LEN        AO_MS_TO_RDF_LEN(AO_RDF_CONTINUITY_PAUSE)
+#define AO_RADIO_CONT_TOTAL_LEN        AO_MS_TO_RDF_LEN(AO_RDF_CONTINUITY_TOTAL)
+
+/* returns a value 0-3 to indicate igniter continuity */
+uint8_t
+ao_report_igniter(void);
+
+void
+ao_report_init(void);
+
+/*
+ * ao_convert.c
+ *
+ * Given raw data, convert to SI units
+ */
+
+/* pressure from the sensor to altitude in meters */
+int16_t
+ao_pres_to_altitude(int16_t pres) __reentrant;
+
+int16_t
+ao_altitude_to_pres(int16_t alt) __reentrant;
+
+int16_t
+ao_temp_to_dC(int16_t temp) __reentrant;
+
+/*
+ * ao_convert_pa.c
+ *
+ * Convert between pressure in Pa and altitude in meters
+ */
+
+#include <ao_data.h>
+
+alt_t
+ao_pa_to_altitude(int32_t pa);
+
+int32_t
+ao_altitude_to_pa(alt_t alt);
+
+#if HAS_DBG
+#include <ao_dbg.h>
+#endif
+
+#if HAS_SERIAL_0 || HAS_SERIAL_1 || HAS_SERIAL_2 || HAS_SERIAL_3
+#include <ao_serial.h>
+#endif
+
+/*
+ * ao_convert_volt.c
+ *
+ * Convert ADC readings to decivolts
+ */
+
+int16_t
+ao_battery_decivolt(int16_t adc);
+
+int16_t
+ao_ignite_decivolt(int16_t adc);
+
+/*
+ * ao_spi_slave.c
+ */
+
+uint8_t
+ao_spi_slave_recv(void *buf, uint16_t len);
+
+void
+ao_spi_slave_send(void *buf, uint16_t len);
+
+void
+ao_spi_slave_init(void);
+
+/* This must be defined by the product; it will get called when chip
+ * select goes low, at which point it should use ao_spi_read and
+ * ao_spi_write to deal with the request
+ */
+
+void
+ao_spi_slave(void);
+
+#include <ao_telemetry.h>
+/*
+ * ao_gps.c
+ */
+
+#define AO_GPS_NUM_SAT_MASK    (0xf << 0)
+#define AO_GPS_NUM_SAT_SHIFT   (0)
+
+#define AO_GPS_VALID           (1 << 4)
+#define AO_GPS_RUNNING         (1 << 5)
+#define AO_GPS_DATE_VALID      (1 << 6)
+#define AO_GPS_COURSE_VALID    (1 << 7)
+
+#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;
+extern __xdata struct ao_telemetry_satellite ao_gps_tracking_data;
+
+struct ao_gps_orig {
+       uint8_t                 year;
+       uint8_t                 month;
+       uint8_t                 day;
+       uint8_t                 hour;
+       uint8_t                 minute;
+       uint8_t                 second;
+       uint8_t                 flags;
+       int32_t                 latitude;       /* degrees * 10⁷ */
+       int32_t                 longitude;      /* degrees * 10⁷ */
+       int16_t                 altitude;       /* m */
+       uint16_t                ground_speed;   /* cm/s */
+       uint8_t                 course;         /* degrees / 2 */
+       uint8_t                 hdop;           /* * 5 */
+       int16_t                 climb_rate;     /* cm/s */
+       uint16_t                h_error;        /* m */
+       uint16_t                v_error;        /* m */
+};
+
+struct ao_gps_sat_orig {
+       uint8_t         svid;
+       uint8_t         c_n_1;
+};
+
+#define AO_MAX_GPS_TRACKING    12
+
+struct ao_gps_tracking_orig {
+       uint8_t                 channels;
+       struct ao_gps_sat_orig  sats[AO_MAX_GPS_TRACKING];
+};
+
+void
+ao_gps_set_rate(uint8_t rate);
+
+void
+ao_gps(void);
+
+void
+ao_gps_print(__xdata struct ao_gps_orig *gps_data);
+
+void
+ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data);
+
+void
+ao_gps_show(void) __reentrant;
+
+void
+ao_gps_init(void);
+
+/*
+ * ao_gps_report.c
+ */
+
+void
+ao_gps_report(void);
+
+void
+ao_gps_report_init(void);
+
+/*
+ * ao_gps_report_mega.c
+ */
+
+void
+ao_gps_report_mega(void);
+
+void
+ao_gps_report_mega_init(void);
+
+/*
+ * ao_telemetry_orig.c
+ */
+
+#if LEGACY_MONITOR
+struct ao_adc_orig {
+       uint16_t        tick;           /* tick when the sample was read */
+       int16_t         accel;          /* accelerometer */
+       int16_t         pres;           /* pressure sensor */
+       int16_t         temp;           /* temperature sensor */
+       int16_t         v_batt;         /* battery voltage */
+       int16_t         sense_d;        /* drogue continuity sense */
+       int16_t         sense_m;        /* main continuity sense */
+};
+
+struct ao_telemetry_orig {
+       uint16_t                serial;
+       uint16_t                flight;
+       uint8_t                 flight_state;
+       int16_t                 accel;
+       int16_t                 ground_accel;
+       union {
+               struct {
+                       int16_t                 speed;
+                       int16_t                 unused;
+               } k;
+               int32_t         flight_vel;
+       } u;
+       int16_t                 height;
+       int16_t                 ground_pres;
+       int16_t                 accel_plus_g;
+       int16_t                 accel_minus_g;
+       struct ao_adc_orig      adc;
+       struct ao_gps_orig      gps;
+       char                    callsign[AO_MAX_CALLSIGN];
+       struct ao_gps_tracking_orig     gps_tracking;
+};
+
+struct ao_telemetry_tiny {
+       uint16_t                serial;
+       uint16_t                flight;
+       uint8_t                 flight_state;
+       int16_t                 height;         /* AGL in meters */
+       int16_t                 speed;          /* in m/s * 16 */
+       int16_t                 accel;          /* in m/s² * 16 */
+       int16_t                 ground_pres;    /* sensor units */
+       struct ao_adc           adc;            /* raw ADC readings */
+       char                    callsign[AO_MAX_CALLSIGN];
+};
+
+struct ao_telemetry_orig_recv {
+       struct ao_telemetry_orig        telemetry_orig;
+       int8_t                          rssi;
+       uint8_t                         status;
+};
+
+struct ao_telemetry_tiny_recv {
+       struct ao_telemetry_tiny        telemetry_tiny;
+       int8_t                          rssi;
+       uint8_t                         status;
+};
+
+#endif /* LEGACY_MONITOR */
+
+/* Unfortunately, we've exposed the CC1111 rssi units as the 'usual' method
+ * for reporting RSSI. So, now we use these values everywhere
+ */
+#define AO_RSSI_FROM_RADIO(radio)      ((int16_t) ((int8_t) (radio) >> 1) - 74)
+#define AO_RADIO_FROM_RSSI(rssi)       (((int8_t) (rssi) + 74) << 1)
+
+/*
+ * ao_radio_recv tacks on rssi and status bytes
+ */
+
+struct ao_telemetry_raw_recv {
+       uint8_t                 packet[AO_MAX_TELEMETRY + 2];
+};
+
+/* Set delay between telemetry reports (0 to disable) */
+
+#ifdef AO_SEND_ALL_BARO
+#define AO_TELEMETRY_INTERVAL_PAD      AO_MS_TO_TICKS(100)
+#define AO_TELEMETRY_INTERVAL_FLIGHT   AO_MS_TO_TICKS(100)
+#define AO_TELEMETRY_INTERVAL_RECOVER  AO_MS_TO_TICKS(100)
+#else
+#define AO_TELEMETRY_INTERVAL_PAD      AO_MS_TO_TICKS(1000)
+#define AO_TELEMETRY_INTERVAL_FLIGHT   AO_MS_TO_TICKS(100)
+#define AO_TELEMETRY_INTERVAL_RECOVER  AO_MS_TO_TICKS(1000)
+#endif
+
+void
+ao_telemetry_set_interval(uint16_t interval);
+
+void
+ao_rdf_set(uint8_t rdf);
+
+void
+ao_telemetry_init(void);
+
+void
+ao_telemetry_orig_init(void);
+
+void
+ao_telemetry_tiny_init(void);
+
+/*
+ * ao_radio.c
+ */
+
+extern __xdata uint8_t ao_radio_dma;
+
+extern __xdata int8_t  ao_radio_rssi;
+
+#ifdef PKT_APPEND_STATUS_1_CRC_OK
+#define AO_RADIO_STATUS_CRC_OK PKT_APPEND_STATUS_1_CRC_OK
+#else
+#include <ao_fec.h>
+#define AO_RADIO_STATUS_CRC_OK AO_FEC_DECODE_CRC_OK
+#endif
+
+#ifndef HAS_RADIO_RECV
+#define HAS_RADIO_RECV HAS_RADIO
+#endif
+#ifndef HAS_RADIO_XMIT
+#define HAS_RADIO_XMIT HAS_RADIO
+#endif
+
+void
+ao_radio_general_isr(void) ao_arch_interrupt(16);
+
+#if HAS_RADIO_XMIT
+void
+ao_radio_send(const __xdata void *d, uint8_t size) __reentrant;
+#endif
+
+#if HAS_RADIO_RECV
+uint8_t
+ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout) __reentrant;
+
+void
+ao_radio_recv_abort(void);
+#endif
+
+void
+ao_radio_test(uint8_t on);
+
+typedef int16_t (*ao_radio_fill_func)(uint8_t *buffer, int16_t len);
+
+void
+ao_radio_send_aprs(ao_radio_fill_func fill);
+
+/*
+ * ao_radio_pa
+ */
+
+#if HAS_RADIO_AMP
+void
+ao_radio_pa_on(void);
+
+void
+ao_radio_pa_off(void);
+
+void
+ao_radio_pa_init(void);
+#else
+#define ao_radio_pa_on()
+#define ao_radio_pa_off()
+#define ao_radio_pa_init()
+#endif
+
+/*
+ * Compute the packet length as follows:
+ *
+ * 2000 bps (for a 1kHz tone)
+ * so, for 'ms' milliseconds, we need
+ * 2 * ms bits, or ms / 4 bytes
+ */
+
+void
+ao_radio_rdf(void);
+
+void
+ao_radio_continuity(uint8_t c);
+
+void
+ao_radio_rdf_abort(void);
+
+void
+ao_radio_init(void);
+
+/*
+ * ao_monitor.c
+ */
+
+#if HAS_MONITOR
+
+extern const char const * const ao_state_names[];
+
+#define AO_MONITOR_RING        8
+
+union ao_monitor {
+       struct ao_telemetry_raw_recv    raw;
+       struct ao_telemetry_all_recv    all;
+#if LEGACY_MONITOR
+       struct ao_telemetry_orig_recv   orig;
+       struct ao_telemetry_tiny_recv   tiny;
+#endif
+};
+
+extern __xdata union ao_monitor ao_monitor_ring[AO_MONITOR_RING];
+
+#define ao_monitor_ring_next(n)        (((n) + 1) & (AO_MONITOR_RING - 1))
+
+extern __data uint8_t ao_monitoring;
+extern __data uint8_t ao_monitor_head;
+
+void
+ao_monitor(void);
+
+#define AO_MONITORING_OFF      0
+#define AO_MONITORING_ORIG     1
+
+void
+ao_monitor_set(uint8_t monitoring);
+
+void
+ao_monitor_disable(void);
+
+void
+ao_monitor_enable(void);
+
+void
+ao_monitor_init(void) __reentrant;
+
+#endif
+
+/*
+ * ao_stdio.c
+ */
+
+#define AO_READ_AGAIN  (-1)
+
+struct ao_stdio {
+       int     (*_pollchar)(void);     /* Called with interrupts blocked */
+       void    (*putchar)(char c) __reentrant;
+       void    (*flush)(void);
+       uint8_t echo;
+};
+
+extern __xdata struct ao_stdio ao_stdios[];
+extern __pdata int8_t ao_cur_stdio;
+extern __pdata int8_t ao_num_stdios;
+
+void
+flush(void);
+
+extern __xdata uint8_t ao_stdin_ready;
+
+uint8_t
+ao_echo(void);
+
+int8_t
+ao_add_stdio(int (*pollchar)(void),
+            void (*putchar)(char) __reentrant,
+            void (*flush)(void)) __reentrant;
+
+/*
+ * ao_ignite.c
+ */
+
+enum ao_igniter {
+       ao_igniter_drogue = 0,
+       ao_igniter_main = 1
+};
+
+void
+ao_ignite(enum ao_igniter igniter);
+
+enum ao_igniter_status {
+       ao_igniter_unknown,     /* unknown status (ambiguous voltage) */
+       ao_igniter_ready,       /* continuity detected */
+       ao_igniter_active,      /* igniter firing */
+       ao_igniter_open,        /* open circuit detected */
+};
+
+struct ao_ignition {
+       uint8_t request;
+       uint8_t fired;
+       uint8_t firing;
+};
+
+extern __code char * __code ao_igniter_status_names[];
+
+extern __xdata struct ao_ignition ao_ignition[2];
+
+enum ao_igniter_status
+ao_igniter_status(enum ao_igniter igniter);
+
+extern __pdata uint8_t ao_igniter_present;
+
+void
+ao_ignite_set_pins(void);
+
+void
+ao_igniter_init(void);
+
+/*
+ * ao_config.c
+ */
+#include <ao_config.h>
+
+#if AO_PYRO_NUM
+#include <ao_pyro.h>
+#endif
+
+#if HAS_FORCE_FREQ
+/*
+ * Set this to force the frequency to 434.550MHz
+ */
+extern __xdata uint8_t ao_force_freq;
+#endif
+
+/*
+ * ao_rssi.c
+ */
+
+void
+ao_rssi_set(int rssi_value);
+
+void
+ao_rssi_init(uint8_t rssi_led);
+
+/*
+ * ao_product.c
+ *
+ * values which need to be defined for
+ * each instance of a product
+ */
+
+extern const char ao_version[];
+extern const char ao_manufacturer[];
+extern const char ao_product[];
+
+/*
+ * Fifos
+ */
+
+#define AO_FIFO_SIZE   32
+
+struct ao_fifo {
+       uint8_t insert;
+       uint8_t remove;
+       char    fifo[AO_FIFO_SIZE];
+};
+
+#define ao_fifo_insert(f,c) do { \
+       (f).fifo[(f).insert] = (c); \
+       (f).insert = ((f).insert + 1) & (AO_FIFO_SIZE-1); \
+} while(0)
+
+#define ao_fifo_remove(f,c) do {\
+       c = (f).fifo[(f).remove]; \
+       (f).remove = ((f).remove + 1) & (AO_FIFO_SIZE-1); \
+} while(0)
+
+#define ao_fifo_full(f)                ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove)
+#define ao_fifo_empty(f)       ((f).insert == (f).remove)
+
+#if PACKET_HAS_MASTER || PACKET_HAS_SLAVE
+#include <ao_packet.h>
+#endif
+
+#if HAS_BTM
+#include <ao_btm.h>
+#endif
+
+#if HAS_COMPANION
+#include <ao_companion.h>
+#endif
+
+#if HAS_LCD
+#include <ao_lcd.h>
+#endif
+
+#if HAS_AES
+#include <ao_aes.h>
+#endif
+
+/* ao_launch.c */
+
+struct ao_launch_command {
+       uint16_t        tick;
+       uint16_t        serial;
+       uint8_t         cmd;
+       uint8_t         channel;
+       uint16_t        unused;
+};
+
+#define AO_LAUNCH_QUERY                1
+
+struct ao_launch_query {
+       uint16_t        tick;
+       uint16_t        serial;
+       uint8_t         channel;
+       uint8_t         valid;
+       uint8_t         arm_status;
+       uint8_t         igniter_status;
+};
+
+#define AO_LAUNCH_ARM          2
+#define AO_LAUNCH_FIRE         3
+
+void
+ao_launch_init(void);
+
+/*
+ * ao_log_single.c
+ */
+
+#define AO_LOG_TELESCIENCE_START       ((uint8_t) 's')
+#define AO_LOG_TELESCIENCE_DATA                ((uint8_t) 'd')
+
+#define AO_LOG_TELESCIENCE_NUM_ADC     12
+
+struct ao_log_telescience {
+       uint8_t         type;
+       uint8_t         csum;
+       uint16_t        tick;
+       uint16_t        tm_tick;
+       uint8_t         tm_state;
+       uint8_t         unused;
+       uint16_t        adc[AO_LOG_TELESCIENCE_NUM_ADC];
+};
+
+#define AO_LOG_SINGLE_SIZE             32
+
+union ao_log_single {
+       struct ao_log_telescience       telescience;
+       union ao_telemetry_all          telemetry;
+       uint8_t                         bytes[AO_LOG_SINGLE_SIZE];
+};
+
+extern __xdata union ao_log_single     ao_log_single_write_data;
+extern __xdata union ao_log_single     ao_log_single_read_data;
+
+void
+ao_log_single_extra_query(void);
+
+void
+ao_log_single_list(void);
+
+void
+ao_log_single_main(void);
+
+uint8_t
+ao_log_single_write(void);
+
+uint8_t
+ao_log_single_read(uint32_t pos);
+
+void
+ao_log_single_start(void);
+
+void
+ao_log_single_stop(void);
+
+void
+ao_log_single_restart(void);
+
+void
+ao_log_single_set(void);
+
+void
+ao_log_single_delete(void);
+
+void
+ao_log_single_init(void);
+
+void
+ao_log_single(void);
+
+/*
+ * ao_pyro_slave.c
+ */
+
+#define AO_TELEPYRO_NUM_ADC    9
+
+#ifndef ao_xmemcpy
+#define ao_xmemcpy(d,s,c) memcpy(d,s,c)
+#define ao_xmemset(d,v,c) memset(d,v,c)
+#define ao_xmemcmp(d,s,c) memcmp(d,s,c)
+#endif
+
+/*
+ * ao_terraui.c
+ */
+
+void
+ao_terraui_init(void);
+
+/*
+ * ao_battery.c
+ */
+
+#ifdef BATTERY_PIN
+void
+ao_battery_isr(void) ao_arch_interrupt(1);
+
+uint16_t
+ao_battery_get(void);
+
+void
+ao_battery_init(void);
+#endif /* BATTERY_PIN */
+
+/*
+ * ao_sqrt.c
+ */
+
+uint32_t
+ao_sqrt(uint32_t op);
+
+/*
+ * ao_freq.c
+ */
+
+int32_t ao_freq_to_set(int32_t freq, int32_t cal) __reentrant;
+
+/*
+ * ao_ms5607.c
+ */
+
+void ao_ms5607_init(void);
+
+#include <ao_arch_funcs.h>
+
+#endif /* _AO_H_ */
diff --git a/src/kernel/ao_adc.h b/src/kernel/ao_adc.h
new file mode 100644 (file)
index 0000000..373db1c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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_ADC_H_
+#define _AO_ADC_H_
+
+#include <ao_data.h>
+
+/* Trigger a conversion sequence (called from the timer interrupt) */
+void
+ao_adc_poll(void);
+
+/* Suspend the current task until another A/D sample is converted */
+void
+ao_adc_sleep(void);
+
+/* Initialize the A/D converter */
+void
+ao_adc_init(void);
+
+#endif /* _AO_ADC_H_ */
diff --git a/src/kernel/ao_aes.h b/src/kernel/ao_aes.h
new file mode 100644 (file)
index 0000000..c47bc2d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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_AES_H_
+#define _AO_AES_H_
+
+/* ao_aes.c */
+
+extern __xdata uint8_t ao_aes_mutex;
+
+/* AES keys and blocks are 128 bits */
+
+enum ao_aes_mode {
+       ao_aes_mode_cbc_mac
+};
+
+#if HAS_AES
+#ifdef SDCC
+void
+ao_aes_isr(void) __interrupt 4;
+#endif
+#endif
+
+void
+ao_aes_set_mode(enum ao_aes_mode mode);
+
+void
+ao_aes_set_key(__xdata uint8_t *in);
+
+void
+ao_aes_zero_iv(void);
+
+void
+ao_aes_run(__xdata uint8_t *in,
+          __xdata uint8_t *out);
+
+void
+ao_aes_init(void);
+
+#endif /* _AO_AES_H_ */
diff --git a/src/kernel/ao_balloon.c b/src/kernel/ao_balloon.c
new file mode 100644 (file)
index 0000000..904a9c0
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#ifndef AO_FLIGHT_TEST
+#include "ao.h"
+#endif
+
+#ifndef HAS_ACCEL
+#error Please define HAS_ACCEL
+#endif
+
+#ifndef HAS_GPS
+#error Please define HAS_GPS
+#endif
+
+#ifndef HAS_USB
+#error Please define HAS_USB
+#endif
+
+#if HAS_SENSOR_ERRORS
+/* Any sensor can set this to mark the flight computer as 'broken' */
+__xdata uint8_t                        ao_sensor_errors;
+#endif
+
+__pdata uint16_t               ao_motor_number;        /* number of motors burned so far */
+
+/* Main flight thread. */
+
+__pdata enum ao_flight_state   ao_flight_state;        /* current flight state */
+
+__pdata uint8_t                        ao_flight_force_idle;
+
+void
+ao_flight(void)
+{
+       ao_sample_init();
+       ao_flight_state = ao_flight_startup;
+       for (;;) {
+
+               /*
+                * Process ADC samples, just looping
+                * until the sensors are calibrated.
+                */
+               if (!ao_sample())
+                       continue;
+
+               switch (ao_flight_state) {
+               case ao_flight_startup:
+
+                       /* Check to see what mode we should go to.
+                        *  - Invalid mode if accel cal appears to be out
+                        *  - pad mode if we're upright,
+                        *  - idle mode otherwise
+                        */
+                       if (!ao_flight_force_idle)
+                       {
+                               /* Set pad mode - we can fly! */
+                               ao_flight_state = ao_flight_pad;
+#if HAS_USB
+                               /* Disable the USB controller in flight mode
+                                * to save power
+                                */
+                               if (!ao_usb_running)
+                                       ao_usb_disable();
+#endif
+
+                               /* Disable packet mode in pad state */
+                               ao_packet_slave_stop();
+
+                               /* Turn on telemetry system */
+                               ao_rdf_set(1);
+                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_BALLOON);
+
+                               /* signal successful initialization by turning off the LED */
+                               ao_led_off(AO_LED_RED);
+                       } else {
+                               /* Set idle mode */
+                               ao_flight_state = ao_flight_idle;
+                               /* signal successful initialization by turning off the LED */
+                               ao_led_off(AO_LED_RED);
+                       }
+                       /* wakeup threads due to state change */
+                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+
+                       break;
+               case ao_flight_pad:
+
+                       /* pad to coast:
+                        *
+                        * barometer: > 20m vertical motion
+                        */
+                       if (ao_height > AO_M_TO_HEIGHT(20))
+                       {
+                               ao_flight_state = ao_flight_drogue;
+
+                               /* start logging data */
+                               ao_log_start();
+
+#if HAS_GPS
+                               /* Record current GPS position by waking up GPS log tasks */
+                               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));
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static __xdata struct ao_task  flight_task;
+
+void
+ao_flight_init(void)
+{
+       ao_flight_state = ao_flight_startup;
+       ao_add_task(&flight_task, ao_flight, "flight");
+}
diff --git a/src/kernel/ao_beep.h b/src/kernel/ao_beep.h
new file mode 100644 (file)
index 0000000..9d6ecf2
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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_BEEP_H_
+#define _AO_BEEP_H_
+
+#ifndef HAS_BEEP_CONFIG
+#if defined(USE_EEPROM_CONFIG) && USE_EEPROM_CONFIG || HAS_EEPROM
+#define HAS_BEEP_CONFIG        1
+#endif
+#endif
+
+/*
+ * ao_beep.c
+ */
+
+/*
+ * Various pre-defined beep frequencies
+ *
+ * frequency = 1/2 (24e6/32) / beep
+ */
+
+#define AO_BEEP_MID_DEFAULT    94      /* 3989Hz */
+
+#if HAS_BEEP_CONFIG
+#define AO_BEEP_MID    ao_config.mid_beep
+#else
+#define AO_BEEP_MID    AO_BEEP_MID_DEFAULT
+#endif
+#define AO_BEEP_LOW    AO_BEEP_MID * 150 / 94  /* 2500Hz */
+#define AO_BEEP_HIGH   AO_BEEP_MID * 75 / 94   /* 5000Hz */
+
+#define AO_BEEP_OFF    0       /* off */
+
+#define AO_BEEP_g      240     /* 1562.5Hz */
+#define AO_BEEP_gs     227     /* 1652Hz (1655Hz) */
+#define AO_BEEP_aa     214     /* 1752Hz (1754Hz) */
+#define AO_BEEP_bbf    202     /* 1856Hz (1858Hz) */
+#define AO_BEEP_bb     190     /* 1974Hz (1969Hz) */
+#define AO_BEEP_cc     180     /* 2083Hz (2086Hz) */
+#define AO_BEEP_ccs    170     /* 2205Hz (2210Hz) */
+#define AO_BEEP_dd     160     /* 2344Hz (2341Hz) */
+#define AO_BEEP_eef    151     /* 2483Hz (2480Hz) */
+#define AO_BEEP_ee     143     /* 2622Hz (2628Hz) */
+#define AO_BEEP_ff     135     /* 2778Hz (2784Hz) */
+#define AO_BEEP_ffs    127     /* 2953Hz (2950Hz) */
+#define AO_BEEP_gg     120     /* 3125Hz */
+#define AO_BEEP_ggs    113     /* 3319Hz (3311Hz) */
+#define AO_BEEP_aaa    107     /* 3504Hz (3508Hz) */
+#define AO_BEEP_bbbf   101     /* 3713Hz (3716Hz) */
+#define AO_BEEP_bbb    95      /* 3947Hz (3937Hz) */
+#define AO_BEEP_ccc    90      /* 4167Hz (4171Hz) */
+#define AO_BEEP_cccs   85      /* 4412Hz (4419Hz) */
+#define AO_BEEP_ddd    80      /* 4688Hz (4682Hz) */
+#define AO_BEEP_eeef   76      /* 4934Hz (4961Hz) */
+#define AO_BEEP_eee    71      /* 5282Hz (5256Hz) */
+#define AO_BEEP_fff    67      /* 5597Hz (5568Hz) */
+#define AO_BEEP_fffs   64      /* 5859Hz (5899Hz) */
+#define AO_BEEP_ggg    60      /* 6250Hz */
+
+/* Set the beeper to the specified tone */
+void
+ao_beep(uint8_t beep);
+
+/* Turn on the beeper for the specified time */
+void
+ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant;
+
+/* Initialize the beeper */
+void
+ao_beep_init(void);
+
+#endif /* _AO_BEEP_H_ */
diff --git a/src/kernel/ao_boot.h b/src/kernel/ao_boot.h
new file mode 100644 (file)
index 0000000..62392d2
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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);
+
+#define AO_BOOT_FORCE_LOADER   ((uint32_t *) 0)
+
+static inline void
+ao_boot_loader(void) {
+       ao_boot_reboot(AO_BOOT_FORCE_LOADER);
+}
+
+#endif /* _AO_BOOT_H_ */
diff --git a/src/kernel/ao_btm.h b/src/kernel/ao_btm.h
new file mode 100644 (file)
index 0000000..484e5d7
--- /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.
+ */
+
+#ifndef _AO_BTM_H_
+#define _AO_BTM_H_
+
+/* ao_btm.c */
+
+/* If bt_link is on P2, this interrupt is shared by USB, so the USB
+ * code calls this function. Otherwise, it's a regular ISR.
+ */
+
+void
+ao_btm_isr(void)
+#if BT_LINK_ON_P1
+       __interrupt 15
+#endif
+       ;
+void
+ao_btm_init(void);
+
+#endif /* _AO_BTM_H_ */
diff --git a/src/kernel/ao_cmd.c b/src/kernel/ao_cmd.c
new file mode 100644 (file)
index 0000000..0052bdc
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * 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_task.h"
+
+__pdata uint16_t ao_cmd_lex_i;
+__pdata uint32_t ao_cmd_lex_u32;
+__pdata char   ao_cmd_lex_c;
+__pdata enum ao_cmd_status ao_cmd_status;
+
+#if AO_PYRO_NUM
+#define CMD_LEN 128
+#else
+#define CMD_LEN        48
+#endif
+
+static __xdata char    cmd_line[CMD_LEN];
+static __pdata uint8_t cmd_len;
+static __pdata uint8_t cmd_i;
+
+void
+ao_put_string(__code char *s)
+{
+       char    c;
+       while ((c = *s++))
+               putchar(c);
+}
+
+static void
+backspace(void)
+{
+       ao_put_string ("\010 \010");
+}
+
+static void
+readline(void)
+{
+       char c;
+       if (ao_echo())
+               ao_put_string("> ");
+       cmd_len = 0;
+       for (;;) {
+               flush();
+               c = getchar();
+               /* backspace/delete */
+               if (c == '\010' || c == '\177') {
+                       if (cmd_len != 0) {
+                               if (ao_echo())
+                                       backspace();
+                               --cmd_len;
+                       }
+                       continue;
+               }
+
+               /* ^U */
+               if (c == '\025') {
+                       while (cmd_len != 0) {
+                               if (ao_echo())
+                                       backspace();
+                               --cmd_len;
+                       }
+                       continue;
+               }
+
+               /* map CR to NL */
+               if (c == '\r')
+                       c = '\n';
+
+               if (c == '\n') {
+                       if (ao_echo())
+                               putchar('\n');
+                       break;
+               }
+
+               if (cmd_len >= CMD_LEN - 2)
+                       continue;
+               cmd_line[cmd_len++] = c;
+               if (ao_echo())
+                       putchar(c);
+       }
+       cmd_line[cmd_len++] = '\n';
+       cmd_line[cmd_len++] = '\0';
+       cmd_i = 0;
+}
+
+void
+ao_cmd_lex(void)
+{
+       ao_cmd_lex_c = '\n';
+       if (cmd_i < cmd_len)
+               ao_cmd_lex_c = cmd_line[cmd_i++];
+}
+
+static void
+putnibble(uint8_t v)
+{
+       if (v < 10)
+               putchar(v + '0');
+       else
+               putchar(v + ('a' - 10));
+}
+
+uint8_t
+ao_getnibble(void)
+{
+       char    c;
+
+       c = getchar();
+       if ('0' <= c && c <= '9')
+               return c - '0';
+       if ('a' <= c && c <= 'f')
+               return c - ('a' - 10);
+       if ('A' <= c && c <= 'F')
+               return c - ('A' - 10);
+       ao_cmd_status = ao_cmd_lex_error;
+       return 0;
+}
+
+void
+ao_cmd_put16(uint16_t v)
+{
+       ao_cmd_put8(v >> 8);
+       ao_cmd_put8(v);
+}
+
+void
+ao_cmd_put8(uint8_t v)
+{
+       putnibble((v >> 4) & 0xf);
+       putnibble(v & 0xf);
+}
+
+uint8_t
+ao_cmd_is_white(void)
+{
+       return ao_cmd_lex_c == ' ' || ao_cmd_lex_c == '\t';
+}
+
+void
+ao_cmd_white(void)
+{
+       while (ao_cmd_is_white())
+               ao_cmd_lex();
+}
+
+int8_t
+ao_cmd_hexchar(char c)
+{
+       if ('0' <= c && c <= '9')
+               return (c - '0');
+       if ('a' <= c && c <= 'f')
+               return (c - 'a' + 10);
+       if ('A' <= c && c <= 'F')
+               return (c - 'A' + 10);
+       return -1;
+}
+
+void
+ao_cmd_hexbyte(void)
+{
+       uint8_t i;
+       int8_t  n;
+
+       ao_cmd_lex_i = 0;
+       ao_cmd_white();
+       for (i = 0; i < 2; i++) {
+               n = ao_cmd_hexchar(ao_cmd_lex_c);
+               if (n < 0) {
+                       ao_cmd_status = ao_cmd_syntax_error;
+                       break;
+               }
+               ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
+               ao_cmd_lex();
+       }
+}
+
+void
+ao_cmd_hex(void)
+{
+       __pdata uint8_t r = ao_cmd_lex_error;
+       int8_t  n;
+
+       ao_cmd_lex_i = 0;
+       ao_cmd_white();
+       for(;;) {
+               n = ao_cmd_hexchar(ao_cmd_lex_c);
+               if (n < 0)
+                       break;
+               ao_cmd_lex_i = (ao_cmd_lex_i << 4) | n;
+               r = ao_cmd_success;
+               ao_cmd_lex();
+       }
+       if (r != ao_cmd_success)
+               ao_cmd_status = r;
+}
+
+void
+ao_cmd_decimal(void) __reentrant
+{
+       uint8_t r = ao_cmd_lex_error;
+
+       ao_cmd_lex_u32 = 0;
+       ao_cmd_white();
+       for(;;) {
+               if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9')
+                       ao_cmd_lex_u32 = (ao_cmd_lex_u32 * 10) + (ao_cmd_lex_c - '0');
+               else
+                       break;
+               r = ao_cmd_success;
+               ao_cmd_lex();
+       }
+       if (r != ao_cmd_success)
+               ao_cmd_status = r;
+       ao_cmd_lex_i = (uint16_t) ao_cmd_lex_u32;
+}
+
+uint8_t
+ao_match_word(__code char *word)
+{
+       while (*word) {
+               if (ao_cmd_lex_c != *word) {
+                       ao_cmd_status = ao_cmd_syntax_error;
+                       return 0;
+               }
+               word++;
+               ao_cmd_lex();
+       }
+       return 1;
+}
+
+static void
+echo(void)
+{
+       ao_cmd_hex();
+       if (ao_cmd_status == ao_cmd_success)
+               ao_stdios[ao_cur_stdio].echo = ao_cmd_lex_i != 0;
+}
+
+static void
+ao_reboot(void)
+{
+       ao_cmd_white();
+       if (!ao_match_word("eboot"))
+               return;
+       /* Delay waiting for the packet master to be turned off
+        * so that we don't end up back in idle mode because we
+        * received a packet after boot.
+        */
+       flush();
+       ao_delay(AO_SEC_TO_TICKS(1));
+       ao_arch_reboot();
+       ao_panic(AO_PANIC_REBOOT);
+}
+
+#ifndef HAS_VERSION
+#define HAS_VERSION 1
+#endif
+
+#if HAS_VERSION
+static void
+version(void)
+{
+       printf("manufacturer     %s\n"
+              "product          %s\n"
+              "serial-number    %u\n"
+#if HAS_FLIGHT || HAS_TRACKER
+              "current-flight   %u\n"
+#endif
+#if HAS_LOG
+              "log-format       %u\n"
+#if !DISABLE_LOG_SPACE
+              "log-space        %lu\n"
+#endif
+#endif
+#if defined(AO_BOOT_APPLICATION_BASE) && defined(AO_BOOT_APPLICATION_BOUND)
+              "program-space    %u\n"
+#endif
+              , ao_manufacturer
+              , ao_product
+              , ao_serial_number
+#if HAS_FLIGHT || HAS_TRACKER
+              , ao_flight_number
+#endif
+#if HAS_LOG
+              , ao_log_format
+#if !DISABLE_LOG_SPACE
+              , (unsigned long) ao_storage_log_max
+#endif
+#endif
+#if defined(AO_BOOT_APPLICATION_BASE) && defined(AO_BOOT_APPLICATION_BOUND)
+              , (uint32_t) AO_BOOT_APPLICATION_BOUND - (uint32_t) AO_BOOT_APPLICATION_BASE
+#endif
+               );
+       printf("software-version %s\n", ao_version);
+}
+#endif
+
+#ifndef NUM_CMDS
+#define NUM_CMDS       11
+#endif
+
+static __code struct ao_cmds   *__xdata (ao_cmds[NUM_CMDS]);
+static __pdata uint8_t         ao_ncmds;
+
+static void
+help(void)
+{
+       __pdata uint8_t cmds;
+       __pdata uint8_t cmd;
+       __code struct ao_cmds * __pdata cs;
+       __code const char *h;
+       uint8_t e;
+
+       for (cmds = 0; cmds < ao_ncmds; cmds++) {
+               cs = ao_cmds[cmds];
+               for (cmd = 0; cs[cmd].func; cmd++) {
+                       h = cs[cmd].help;
+                       ao_put_string(h);
+                       e = strlen(h);
+                       h += e + 1;
+                       e = 45 - e;
+                       while (e--)
+                               putchar(' ');
+                       ao_put_string(h);
+                       putchar('\n');
+               }
+       }
+}
+
+static void
+report(void)
+{
+       switch(ao_cmd_status) {
+       case ao_cmd_lex_error:
+       case ao_cmd_syntax_error:
+               puts("Syntax error");
+               ao_cmd_status = 0;
+       default:
+               break;
+       }
+}
+
+void
+ao_cmd_register(__code struct ao_cmds *cmds)
+{
+       if (ao_ncmds >= NUM_CMDS)
+               ao_panic(AO_PANIC_CMD);
+       ao_cmds[ao_ncmds++] = cmds;
+}
+
+void
+ao_cmd(void)
+{
+       __pdata char    c;
+       uint8_t cmd, cmds;
+       __code struct ao_cmds * __xdata cs;
+       void (*__xdata func)(void);
+
+       for (;;) {
+               readline();
+               ao_cmd_lex();
+               ao_cmd_white();
+               c = ao_cmd_lex_c;
+               ao_cmd_lex();
+               if (c == '\r' || c == '\n')
+                       continue;
+               func = (void (*)(void)) NULL;
+               for (cmds = 0; cmds < ao_ncmds; cmds++) {
+                       cs = ao_cmds[cmds];
+                       for (cmd = 0; cs[cmd].func; cmd++)
+                               if (cs[cmd].help[0] == c) {
+                                       func = cs[cmd].func;
+                                       break;
+                               }
+                       if (func)
+                               break;
+               }
+               if (func)
+                       (*func)();
+               else
+                       ao_cmd_status = ao_cmd_syntax_error;
+               report();
+       }
+}
+
+#if HAS_BOOT_LOADER
+
+#include <ao_boot.h>
+
+static void
+ao_loader(void)
+{
+       flush();
+       ao_boot_loader();
+}
+#endif
+
+__xdata struct ao_task ao_cmd_task;
+
+__code struct ao_cmds  ao_base_cmds[] = {
+       { help,         "?\0Help" },
+#if HAS_TASK_INFO
+       { ao_task_info, "T\0Tasks" },
+#endif
+       { echo,         "E <0 off, 1 on>\0Echo" },
+       { ao_reboot,    "r eboot\0Reboot" },
+#if HAS_VERSION
+       { version,      "v\0Version" },
+#endif
+#if HAS_BOOT_LOADER
+       { ao_loader,    "X\0Switch to boot loader" },
+#endif
+       { 0,    NULL },
+};
+
+void
+ao_cmd_init(void)
+{
+       ao_cmd_register(&ao_base_cmds[0]);
+       ao_add_task(&ao_cmd_task, ao_cmd, "cmd");
+}
diff --git a/src/kernel/ao_companion.h b/src/kernel/ao_companion.h
new file mode 100644 (file)
index 0000000..035325a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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_COMPANION_H_
+#define _AO_COMPANION_H_
+
+/* ao_companion.c */
+
+#define AO_COMPANION_SETUP             1
+#define AO_COMPANION_FETCH             2
+#define AO_COMPANION_NOTIFY            3
+
+struct ao_companion_command {
+       uint8_t         command;
+       uint8_t         flight_state;
+       uint16_t        tick;
+       uint16_t        serial;
+       uint16_t        flight;
+       int16_t         accel;
+       int16_t         speed;
+       int16_t         height;
+       int16_t         motor_number;
+};
+
+struct ao_companion_setup {
+       uint16_t        board_id;
+       uint16_t        board_id_inverse;
+       uint8_t         update_period;
+       uint8_t         channels;
+};
+
+extern __pdata uint8_t                         ao_companion_running;
+extern __xdata uint8_t                         ao_companion_mutex;
+extern __xdata struct ao_companion_command     ao_companion_command;
+extern __xdata struct ao_companion_setup       ao_companion_setup;
+extern __xdata uint16_t                                ao_companion_data[AO_COMPANION_MAX_CHANNELS];
+
+void
+ao_companion_init(void);
+
+#endif /* _AO_COMPANION_H_ */
diff --git a/src/kernel/ao_config.c b/src/kernel/ao_config.c
new file mode 100644 (file)
index 0000000..7144533
--- /dev/null
@@ -0,0 +1,902 @@
+/*
+ * 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"
+#include <ao_config.h>
+#if HAS_FLIGHT
+#include <ao_sample.h>
+#include <ao_data.h>
+#endif
+#if HAS_BEEP
+#include <ao_beep.h>
+#endif
+#if HAS_TRACKER
+#include <ao_tracker.h>
+#endif
+
+__xdata struct ao_config ao_config;
+__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"
+#define AO_CONFIG_DEFAULT_ACCEL_ZERO_G 16000
+#define AO_CONFIG_DEFAULT_APOGEE_DELAY 0
+#define AO_CONFIG_DEFAULT_IGNITE_MODE  AO_IGNITE_MODE_DUAL
+#define AO_CONFIG_DEFAULT_PAD_ORIENTATION      AO_PAD_ORIENTATION_ANTENNA_UP
+#define AO_CONFIG_DEFAULT_PYRO_TIME    AO_MS_TO_TICKS(50)
+#if HAS_EEPROM
+#ifndef USE_INTERNAL_FLASH
+#error Please define USE_INTERNAL_FLASH
+#endif
+#endif
+#ifndef AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX
+#if USE_INTERNAL_FLASH
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       ao_storage_config
+#else
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       ((uint32_t) 192 * (uint32_t) 1024)
+#endif
+#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_config_setup();
+       ao_config_erase();
+       ao_config_write(0, &ao_config, sizeof (ao_config));
+#if HAS_FLIGHT
+       ao_log_write_erase(0);
+#endif
+       ao_config_flush();
+}
+
+void
+ao_config_put(void)
+{
+       ao_mutex_get(&ao_config_mutex);
+       _ao_config_put();
+       ao_mutex_put(&ao_config_mutex);
+}
+#endif
+
+#if HAS_RADIO
+void
+ao_config_set_radio(void)
+{
+       ao_config.radio_setting = ao_freq_to_set(ao_config.frequency, ao_config.radio_cal);
+}
+#endif /* HAS_RADIO */
+
+static void
+_ao_config_get(void)
+{
+       uint8_t minor;
+
+       if (ao_config_loaded)
+               return;
+#if HAS_EEPROM
+       /* Yes, I know ao_storage_read calls ao_storage_setup,
+        * but ao_storage_setup *also* sets ao_storage_config, which we
+        * need before calling ao_storage_read here
+        */
+       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;
+               ao_config.minor = 0;
+
+               /* Version 0 stuff */
+               ao_config.main_deploy = AO_CONFIG_DEFAULT_MAIN_DEPLOY;
+               ao_xmemset(&ao_config.callsign, '\0', sizeof (ao_config.callsign));
+               ao_xmemcpy(&ao_config.callsign, CODE_TO_XDATA(AO_CONFIG_DEFAULT_CALLSIGN),
+                      sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
+               ao_config._legacy_radio_channel = 0;
+       }
+       minor = ao_config.minor;
+       if (minor != AO_CONFIG_MINOR) {
+               /* Fixups for minor version 1 */
+               if (minor < 1)
+                       ao_config.apogee_delay = AO_CONFIG_DEFAULT_APOGEE_DELAY;
+               /* Fixups for minor version 2 */
+               if (minor < 2) {
+                       ao_config.accel_plus_g = 0;
+                       ao_config.accel_minus_g = 0;
+               }
+               /* Fixups for minor version 3 */
+#if HAS_RADIO
+               if (minor < 3)
+                       ao_config.radio_cal = ao_radio_cal;
+#endif
+               /* Fixups for minor version 4 */
+#if HAS_LOG
+               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;
+               if (minor < 6)
+                       ao_config.pad_orientation = AO_CONFIG_DEFAULT_PAD_ORIENTATION;
+               if (minor < 8)
+                       ao_config.radio_enable = AO_RADIO_ENABLE_CORE;
+               if (minor < 9)
+                       ao_xmemset(&ao_config.aes_key, '\0', AO_AES_LEN);
+               if (minor < 10)
+                       ao_config.frequency = 434550 + ao_config._legacy_radio_channel * 100;
+               if (minor < 11)
+                       ao_config.apogee_lockout = 0;
+#if AO_PYRO_NUM
+               if (minor < 12)
+                       memset(&ao_config.pyro, '\0', sizeof (ao_config.pyro));
+#endif
+               if (minor < 13)
+                       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;
+               #endif
+#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
+#if HAS_BEEP_CONFIG
+               if (minor < 16)
+                       ao_config.mid_beep = AO_BEEP_MID_DEFAULT;
+#endif
+#if HAS_TRACKER
+               if (minor < 17) {
+                       ao_config.tracker_motion = AO_TRACKER_MOTION_DEFAULT;
+                       ao_config.tracker_interval = AO_TRACKER_INTERVAL_DEFAULT;
+               }
+#endif
+#if AO_PYRO_NUM
+               if (minor < 18)
+                       ao_config.pyro_time = AO_CONFIG_DEFAULT_PYRO_TIME;
+#endif
+               ao_config.minor = AO_CONFIG_MINOR;
+               ao_config_dirty = 1;
+       }
+#if HAS_RADIO
+#if HAS_FORCE_FREQ
+       if (ao_force_freq) {
+               ao_config.frequency = 434550;
+               ao_config.radio_cal = ao_radio_cal;
+               ao_xmemcpy(&ao_config.callsign, CODE_TO_XDATA(AO_CONFIG_DEFAULT_CALLSIGN),
+                      sizeof(AO_CONFIG_DEFAULT_CALLSIGN) - 1);
+       }
+#endif
+       ao_config_set_radio();
+#endif
+       ao_config_loaded = 1;
+}
+
+void
+_ao_config_edit_start(void)
+{
+       ao_mutex_get(&ao_config_mutex);
+       _ao_config_get();
+}
+
+void
+_ao_config_edit_finish(void)
+{
+       ao_config_dirty = 1;
+       ao_mutex_put(&ao_config_mutex);
+}
+
+void
+ao_config_get(void)
+{
+       _ao_config_edit_start();
+       ao_mutex_put(&ao_config_mutex);
+}
+
+void
+ao_config_callsign_show(void)
+{
+       printf ("Callsign: \"%s\"\n", ao_config.callsign);
+}
+
+void
+ao_config_callsign_set(void) __reentrant
+{
+       uint8_t c;
+       static __xdata char callsign[AO_MAX_CALLSIGN + 1];
+
+       ao_xmemset(callsign, '\0', sizeof callsign);
+       ao_cmd_white();
+       c = 0;
+       while (ao_cmd_lex_c != '\n') {
+               if (c < AO_MAX_CALLSIGN)
+                       callsign[c++] = ao_cmd_lex_c;
+               else
+                       ao_cmd_status = ao_cmd_lex_error;
+               ao_cmd_lex();
+       }
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_xmemcpy(&ao_config.callsign, &callsign,
+              AO_MAX_CALLSIGN + 1);
+       _ao_config_edit_finish();
+}
+
+#if HAS_RADIO
+
+void
+ao_config_frequency_show(void) __reentrant
+{
+       printf("Frequency: %ld\n",
+              ao_config.frequency);
+}
+
+void
+ao_config_frequency_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.frequency = ao_cmd_lex_u32;
+       ao_config_set_radio();
+       _ao_config_edit_finish();
+#if HAS_RADIO_RECV
+       ao_radio_recv_abort();
+#endif
+}
+#endif
+
+#if HAS_FLIGHT
+
+void
+ao_config_main_deploy_show(void) __reentrant
+{
+       printf("Main deploy: %d meters\n",
+              ao_config.main_deploy);
+}
+
+void
+ao_config_main_deploy_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.main_deploy = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+
+#if HAS_ACCEL
+void
+ao_config_accel_calibrate_show(void) __reentrant
+{
+       printf("Accel cal +1g: %d -1g: %d\n",
+              ao_config.accel_plus_g, ao_config.accel_minus_g);
+#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();
+       (void) getchar();
+       puts("\r\n"); flush();
+       puts("Calibrating..."); flush();
+       i = ACCEL_CALIBRATE_SAMPLES;
+       accel_total = 0;
+       cal_data_ring = ao_sample_data;
+       while (i) {
+               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;
+}
+
+void
+ao_config_accel_calibrate_set(void) __reentrant
+{
+       int16_t up, down;
+#if HAS_GYRO
+       int16_t accel_along_up = 0, accel_along_down = 0;
+       int16_t accel_across_up = 0, accel_across_down = 0;
+       int16_t accel_through_up = 0, accel_through_down = 0;
+#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();
+               if (ao_cmd_status != ao_cmd_success)
+                       return;
+               down = ao_cmd_lex_i;
+       }
+       if (up >= down) {
+               printf("Invalid accel: up (%d) down (%d)\n",
+                      up, down);
+               return;
+       }
+       _ao_config_edit_start();
+       ao_config.accel_plus_g = up;
+       ao_config.accel_minus_g = down;
+#if HAS_GYRO
+       if (ao_cmd_lex_i == 0) {
+               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 */
+
+void
+ao_config_apogee_delay_show(void) __reentrant
+{
+       printf("Apogee delay: %d seconds\n",
+              ao_config.apogee_delay);
+}
+
+void
+ao_config_apogee_delay_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.apogee_delay = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+
+void
+ao_config_apogee_lockout_show(void) __reentrant
+{
+       printf ("Apogee lockout: %d seconds\n",
+               ao_config.apogee_lockout);
+}
+
+void
+ao_config_apogee_lockout_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.apogee_lockout = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+
+#endif /* HAS_FLIGHT */
+
+#if HAS_RADIO
+void
+ao_config_radio_cal_show(void) __reentrant
+{
+       printf("Radio cal: %ld\n", ao_config.radio_cal);
+}
+
+void
+ao_config_radio_cal_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.radio_cal = ao_cmd_lex_u32;
+       ao_config_set_radio();
+       _ao_config_edit_finish();
+}
+#endif
+
+#if HAS_LOG
+void
+ao_config_log_show(void) __reentrant
+{
+       printf("Max flight log: %d kB\n", (int16_t) (ao_config.flight_log_max >> 10));
+}
+
+void
+ao_config_log_set(void) __reentrant
+{
+       uint16_t        block = (uint16_t) (ao_storage_block >> 10);
+       uint16_t        log_max = (uint16_t) (ao_storage_log_max >> 10);
+
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       if (ao_log_present())
+               printf("Storage must be empty before changing log size\n");
+       else if (block > 1024 && (ao_cmd_lex_i & (block - 1)))
+               printf("Flight log size must be multiple of %d kB\n", block);
+       else if (ao_cmd_lex_i > 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;
+               _ao_config_edit_finish();
+       }
+}
+#endif /* HAS_LOG */
+
+#if HAS_IGNITE
+void
+ao_config_ignite_mode_show(void) __reentrant
+{
+       printf("Ignite mode: %d\n", ao_config.ignite_mode);
+}
+
+void
+ao_config_ignite_mode_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.ignite_mode = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+#endif
+
+#if HAS_ACCEL
+void
+ao_config_pad_orientation_show(void) __reentrant
+{
+       printf("Pad orientation: %d\n", ao_config.pad_orientation);
+}
+
+#ifndef AO_ACCEL_INVERT
+#define AO_ACCEL_INVERT        0x7fff
+#endif
+
+void
+ao_config_pad_orientation_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_cmd_lex_i &= 1;
+       if (ao_config.pad_orientation != ao_cmd_lex_i) {
+               int16_t t;
+               t = ao_config.accel_plus_g;
+               ao_config.accel_plus_g = AO_ACCEL_INVERT - ao_config.accel_minus_g;
+               ao_config.accel_minus_g = AO_ACCEL_INVERT - t;
+       }
+       ao_config.pad_orientation = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+#endif
+
+#if HAS_RADIO
+void
+ao_config_radio_enable_show(void) __reentrant
+{
+       printf("Radio enable: %d\n", ao_config.radio_enable);
+}
+
+void
+ao_config_radio_enable_set(void) __reentrant
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.radio_enable = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+#endif /* HAS_RADIO */
+
+#if HAS_AES
+
+__xdata uint8_t        ao_config_aes_seq = 1;
+
+void
+ao_config_key_show(void) __reentrant
+{
+       uint8_t i;
+       printf("AES key: ");
+       for (i = 0; i < AO_AES_LEN; i++)
+               printf ("%02x", ao_config.aes_key[i]);
+       printf("\n");
+}
+
+void
+ao_config_key_set(void) __reentrant
+{
+       uint8_t i;
+
+       _ao_config_edit_start();
+       for (i = 0; i < AO_AES_LEN; i++) {
+               ao_cmd_hexbyte();
+               if (ao_cmd_status != ao_cmd_success)
+                       break;
+               ao_config.aes_key[i] = ao_cmd_lex_i;
+       }
+       ++ao_config_aes_seq;
+       _ao_config_edit_finish();
+}
+#endif
+
+#if HAS_APRS
+
+void
+ao_config_aprs_show(void)
+{
+       printf ("APRS interval: %d\n", ao_config.aprs_interval);
+}
+
+void
+ao_config_aprs_set(void)
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.aprs_interval = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+
+#endif /* HAS_APRS */
+
+#if HAS_RADIO_AMP
+
+void
+ao_config_radio_amp_show(void)
+{
+       printf ("Radio amp setting: %d\n", ao_config.radio_amp);
+}
+
+void
+ao_config_radio_amp_set(void)
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.radio_amp = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+
+#endif
+
+#if HAS_RADIO_POWER
+
+void
+ao_config_radio_power_show(void)
+{
+       printf ("Radio power setting: %d\n", ao_config.radio_power);
+}
+
+void
+ao_config_radio_power_set(void)
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.radio_power = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+
+#endif
+
+#if HAS_BEEP_CONFIG
+void
+ao_config_beep_show(void)
+{
+       printf ("Beeper setting: %d\n", ao_config.mid_beep);
+}
+
+void
+ao_config_beep_set(void)
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.mid_beep = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+#endif
+
+#if HAS_TRACKER
+void
+ao_config_tracker_show(void)
+{
+       printf ("Tracker setting: %d %d\n",
+               ao_config.tracker_motion,
+               ao_config.tracker_interval);
+}
+
+void
+ao_config_tracker_set(void)
+{
+       uint16_t        m, i;
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       m = ao_cmd_lex_i;
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       i = ao_cmd_lex_i;
+       _ao_config_edit_start();
+       ao_config.tracker_motion = m;
+       ao_config.tracker_interval = i;
+       _ao_config_edit_finish();
+}
+#endif /* HAS_TRACKER */
+
+#if AO_PYRO_NUM
+void
+ao_config_pyro_time_show(void)
+{
+       printf ("Pyro time: %d\n", ao_config.pyro_time);
+}
+
+void
+ao_config_pyro_time_set(void)
+{
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       _ao_config_edit_start();
+       ao_config.pyro_time = ao_cmd_lex_i;
+       _ao_config_edit_finish();
+}
+#endif
+
+struct ao_config_var {
+       __code char     *str;
+       void            (*set)(void) __reentrant;
+       void            (*show)(void) __reentrant;
+};
+
+static void
+ao_config_help(void) __reentrant;
+
+static void
+ao_config_show(void) __reentrant;
+
+#if HAS_EEPROM
+static void
+ao_config_save(void) __reentrant;
+#endif
+
+__code struct ao_config_var ao_config_vars[] = {
+#if HAS_FLIGHT
+       { "m <meters>\0Main deploy (m)",
+         ao_config_main_deploy_set,    ao_config_main_deploy_show, },
+       { "d <delay>\0Apogee delay (s)",
+         ao_config_apogee_delay_set,   ao_config_apogee_delay_show },
+       { "L <seconds>\0Apogee detect lockout (s)",
+         ao_config_apogee_lockout_set, ao_config_apogee_lockout_show, },
+#endif /* HAS_FLIGHT */
+#if HAS_RADIO
+       { "F <freq>\0Frequency (kHz)",
+         ao_config_frequency_set, ao_config_frequency_show },
+       { "c <call>\0Callsign (8 char max)",
+         ao_config_callsign_set,       ao_config_callsign_show },
+       { "e <0 disable, 1 enable>\0Enable telemetry and RDF",
+         ao_config_radio_enable_set, ao_config_radio_enable_show },
+       { "f <cal>\0Radio calib (cal = rf/(xtal/2^16))",
+         ao_config_radio_cal_set,      ao_config_radio_cal_show },
+#if HAS_RADIO_POWER
+       { "p <setting>\0Radio power setting (0-255)",
+         ao_config_radio_power_set,    ao_config_radio_power_show },
+#endif
+#if HAS_RADIO_AMP
+       { "d <setting>\0Radio amplifier setting (0-3)",
+         ao_config_radio_amp_set,      ao_config_radio_amp_show },
+#endif
+#endif /* HAS_RADIO */
+#if HAS_ACCEL
+       { "a <+g> <-g>\0Accel calib (0 for auto)",
+         ao_config_accel_calibrate_set,ao_config_accel_calibrate_show },
+       { "o <0 antenna up, 1 antenna down>\0Pad orientation",
+         ao_config_pad_orientation_set,ao_config_pad_orientation_show },
+#endif /* HAS_ACCEL */
+#if HAS_LOG
+       { "l <size>\0Flight log size (kB)",
+         ao_config_log_set,            ao_config_log_show },
+#endif
+#if HAS_IGNITE
+       { "i <0 dual, 1 apogee, 2 main>\0Igniter mode",
+         ao_config_ignite_mode_set,    ao_config_ignite_mode_show },
+#endif
+#if HAS_AES
+       { "k <32 hex digits>\0AES encryption key",
+         ao_config_key_set, ao_config_key_show },
+#endif
+#if AO_PYRO_NUM
+       { "P <n,?>\0Pyro channels",
+         ao_pyro_set, ao_pyro_show },
+       { "I <ticks>\0Pyro firing time",
+         ao_config_pyro_time_set, ao_config_pyro_time_show },
+#endif
+#if HAS_APRS
+       { "A <secs>\0APRS packet interval (0 disable)",
+         ao_config_aprs_set, ao_config_aprs_show },
+#endif
+#if HAS_BEEP_CONFIG
+       { "b <val>\0Beeper tone (freq = 1/2 (24e6/32) / beep",
+         ao_config_beep_set, ao_config_beep_show },
+#endif
+#if HAS_TRACKER
+       { "t <motion> <interval>\0Tracker configuration",
+         ao_config_tracker_set, ao_config_tracker_show },
+#endif
+       { "s\0Show",
+         ao_config_show,               0 },
+#if HAS_EEPROM
+       { "w\0Write to eeprom",
+         ao_config_save,               0 },
+#endif
+       { "?\0Help",
+         ao_config_help,               0 },
+       { 0, 0, 0 }
+};
+
+void
+ao_config_set(void)
+{
+       char    c;
+       uint8_t cmd;
+
+       ao_cmd_white();
+       c = ao_cmd_lex_c;
+       ao_cmd_lex();
+       for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
+               if (ao_config_vars[cmd].str[0] == c) {
+                       (*ao_config_vars[cmd].set)();
+                       return;
+               }
+       ao_cmd_status = ao_cmd_syntax_error;
+}
+
+static void
+ao_config_help(void) __reentrant
+{
+       uint8_t cmd;
+       for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
+               printf("%-20s %s\n",
+                      ao_config_vars[cmd].str,
+                      ao_config_vars[cmd].str+1+
+                      strlen(ao_config_vars[cmd].str));
+}
+
+static void
+ao_config_show(void) __reentrant
+{
+       uint8_t cmd;
+       ao_config_get();
+       printf("Config version: %d.%d\n",
+              ao_config.major, ao_config.minor);
+       for (cmd = 0; ao_config_vars[cmd].str != NULL; cmd++)
+               if (ao_config_vars[cmd].show)
+                       (*ao_config_vars[cmd].show)();
+#if HAS_MS5607
+       ao_ms5607_info();
+#endif
+}
+
+#if HAS_EEPROM
+static void
+ao_config_save(void) __reentrant
+{
+       uint8_t saved = 0;
+       ao_mutex_get(&ao_config_mutex);
+       if (ao_config_dirty) {
+               _ao_config_put();
+               ao_config_dirty = 0;
+               saved = 1;
+       }
+       ao_mutex_put(&ao_config_mutex);
+       if (saved)
+               puts("Saved");
+       else
+               puts("Nothing to save");
+}
+#endif
+
+__code struct ao_cmds ao_config_cmds[] = {
+       { ao_config_set,        "c <var> <value>\0Set config (? for help, s to show)" },
+       { 0, NULL },
+};
+
+void
+ao_config_init(void)
+{
+       ao_cmd_register(&ao_config_cmds[0]);
+}
diff --git a/src/kernel/ao_config.h b/src/kernel/ao_config.h
new file mode 100644 (file)
index 0000000..2b5cd35
--- /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_CONFIG_H_
+#define _AO_CONFIG_H_
+
+#include <ao_pyro.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
+
+#define AO_CONFIG_MAJOR        1
+#define AO_CONFIG_MINOR        18
+
+#define AO_AES_LEN 16
+
+extern __xdata uint8_t ao_config_aes_seq;
+
+struct ao_config {
+       uint8_t         major;
+       uint8_t         minor;
+       uint16_t        main_deploy;
+       int16_t         accel_plus_g;           /* changed for minor version 2 */
+       uint8_t         _legacy_radio_channel;
+       char            callsign[AO_MAX_CALLSIGN + 1];
+       uint8_t         apogee_delay;           /* minor version 1 */
+       int16_t         accel_minus_g;          /* minor version 2 */
+       uint32_t        radio_cal;              /* minor version 3 */
+       uint32_t        flight_log_max;         /* minor version 4 */
+       uint8_t         ignite_mode;            /* minor version 5 */
+       uint8_t         pad_orientation;        /* minor version 6 */
+       uint32_t        radio_setting;          /* minor version 7 */
+       uint8_t         radio_enable;           /* minor version 8 */
+       uint8_t         aes_key[AO_AES_LEN];    /* minor version 9 */
+       uint32_t        frequency;              /* minor version 10 */
+       uint16_t        apogee_lockout;         /* minor version 11 */
+#if AO_PYRO_NUM
+       struct ao_pyro  pyro[AO_PYRO_NUM];      /* minor version 12 */
+#endif
+       uint16_t        aprs_interval;          /* minor version 13 */
+#if HAS_RADIO_POWER
+       uint8_t         radio_power;            /* minor version 14 */
+#endif
+#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
+#if HAS_BEEP
+       uint8_t         mid_beep;               /* minor version 16 */
+#endif
+#if HAS_TRACKER
+       uint16_t        tracker_motion;         /* minor version 17 */
+       uint8_t         tracker_interval;       /* minor version 17 */
+#endif
+#if AO_PYRO_NUM
+       uint16_t        pyro_time;              /* minor version 18 */
+#endif
+};
+
+#define AO_IGNITE_MODE_DUAL            0
+#define AO_IGNITE_MODE_APOGEE          1
+#define AO_IGNITE_MODE_MAIN            2
+
+#define AO_RADIO_ENABLE_CORE           1
+#define AO_RADIO_DISABLE_TELEMETRY     2
+#define AO_RADIO_DISABLE_RDF           4
+
+#define AO_PAD_ORIENTATION_ANTENNA_UP  0
+#define AO_PAD_ORIENTATION_ANTENNA_DOWN        1
+
+#ifndef AO_CONFIG_MAX_SIZE
+#define AO_CONFIG_MAX_SIZE     128
+#endif
+
+/* Make sure AO_CONFIG_MAX_SIZE is big enough */
+typedef uint8_t        config_check_space[(int) (AO_CONFIG_MAX_SIZE - sizeof (struct ao_config))];
+
+extern __xdata struct ao_config ao_config;
+extern __pdata uint8_t ao_config_loaded;
+
+void
+_ao_config_edit_start(void);
+
+void
+_ao_config_edit_finish(void);
+
+void
+ao_config_get(void);
+
+void
+ao_config_put(void);
+
+void
+ao_config_set_radio(void);
+
+void
+ao_config_init(void);
+
+#endif /* _AO_CONFIG_H_ */
diff --git a/src/kernel/ao_convert.c b/src/kernel/ao_convert.c
new file mode 100644 (file)
index 0000000..aa9b5f4
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST)
+#include "ao.h"
+#endif
+
+static const int16_t altitude_table[] = {
+#include "altitude.h"
+};
+
+#define ALT_FRAC_SCALE (1 << ALT_FRAC_BITS)
+#define ALT_FRAC_MASK  (ALT_FRAC_SCALE - 1)
+
+int16_t
+ao_pres_to_altitude(int16_t pres) __reentrant
+{
+       uint8_t o;
+       int16_t part;
+
+       if (pres < 0)
+               pres = 0;
+       o = pres >> ALT_FRAC_BITS;
+       part = pres & ALT_FRAC_MASK;
+
+       return ((int32_t) altitude_table[o] * (ALT_FRAC_SCALE - part) +
+               (int32_t) altitude_table[o+1] * part + (ALT_FRAC_SCALE >> 1)) >> ALT_FRAC_BITS;
+}
+
+#if AO_NEED_ALTITUDE_TO_PRES
+int16_t
+ao_altitude_to_pres(int16_t alt) __reentrant
+{
+       int16_t span, sub_span;
+       uint8_t l, h, m;
+       int32_t pres;
+
+       l = 0;
+       h = NALT - 1;
+       while ((h - l) != 1) {
+               m = (l + h) >> 1;
+               if (altitude_table[m] < alt)
+                       h = m;
+               else
+                       l = m;
+       }
+       span = altitude_table[l] - altitude_table[h];
+       sub_span = altitude_table[l] - alt;
+       pres = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_FRAC_BITS) + (span >> 1)) / span;
+       if (pres > 32767)
+               pres = 32767;
+       if (pres < 0)
+               pres = 0;
+       return (int16_t) pres;
+}
+#endif
+
+#if 0
+int16_t
+ao_temp_to_dC(int16_t temp) __reentrant
+{
+       int16_t ret;
+
+       /* Output voltage at 0°C = 0.755V
+        * Coefficient = 0.00247V/°C
+        * Reference voltage = 1.25V
+        *
+        * temp = ((value / 32767) * 1.25 - 0.755) / 0.00247
+        *      = (value - 19791.268) / 32768 * 1.25 / 0.00247
+        *      ≃ (value - 19791) * 1012 / 65536
+        */
+       ret = ((temp - 19791) * 1012L) >> 16;
+       return ret;
+}
+#endif
diff --git a/src/kernel/ao_convert_pa.c b/src/kernel/ao_convert_pa.c
new file mode 100644 (file)
index 0000000..fe6e0ef
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#if !defined(AO_CONVERT_TEST) && !defined(AO_FLIGHT_TEST)
+#include "ao.h"
+#endif
+
+#ifndef AO_CONST_ATTRIB
+#define AO_CONST_ATTRIB
+#endif
+
+static const alt_t altitude_table[] AO_CONST_ATTRIB = {
+#include "altitude-pa.h"
+};
+
+#ifndef FETCH_ALT
+#define FETCH_ALT(o)   altitude_table[o]
+#endif
+
+#define ALT_SCALE      (1 << ALT_SHIFT)
+#define ALT_MASK       (ALT_SCALE - 1)
+
+alt_t
+ao_pa_to_altitude(int32_t pa)
+{
+       int16_t o;
+       int16_t part;
+       int32_t low, high;
+
+       if (pa < 0)
+               pa = 0;
+       if (pa > 120000L)
+               pa = 120000L;
+       o = pa >> ALT_SHIFT;
+       part = pa & ALT_MASK;
+
+       low = (int32_t) FETCH_ALT(o) * (ALT_SCALE - part);
+       high = (int32_t) FETCH_ALT(o+1) * part + (ALT_SCALE >> 1);
+       return (low + high) >> ALT_SHIFT;
+}
+
+#ifdef AO_CONVERT_TEST
+int32_t
+ao_altitude_to_pa(int32_t alt)
+{
+       int32_t         span, sub_span;
+       uint16_t        l, h, m;
+       int32_t         pa;
+
+       l = 0;
+       h = NALT - 1;
+       while ((h - l) != 1) {
+               m = (l + h) >> 1;
+               if (altitude_table[m] < alt)
+                       h = m;
+               else
+                       l = m;
+       }
+       span = altitude_table[l] - altitude_table[h];
+       sub_span = altitude_table[l] - alt;
+       pa = ((((int32_t) l * (span - sub_span) + (int32_t) h * sub_span) << ALT_SHIFT) + (span >> 1)) / span;
+       if (pa > 120000)
+               pa = 120000;
+       if (pa < 0)
+               pa = 0;
+       return pa;
+}
+#endif
diff --git a/src/kernel/ao_convert_pa_test.c b/src/kernel/ao_convert_pa_test.c
new file mode 100644 (file)
index 0000000..7d5b192
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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 <stdint.h>
+#define AO_CONVERT_TEST
+typedef int32_t alt_t;
+#include "ao_host.h"
+#include "ao_convert_pa.c"
+
+#define STEP_P 1
+#define STEP_A 1
+
+static inline int i_abs(int i) { return i < 0 ? -i : i; }
+
+int
+main (int argc, char **argv)
+{
+       int     i;
+       int32_t p_to_a, p_to_a_to_p;
+       int32_t a_to_p, a_to_p_to_a;
+       int max_p_error = 0, max_p_error_p = -1;
+       int max_a_error = 0, max_a_error_a = -1;
+       int p_error;
+       int a_error;
+       int ret = 0;
+
+       for (i = 0; i < 120000 + STEP_P; i += STEP_P) {
+               if (i > 120000)
+                       i = 120000;
+               p_to_a = ao_pa_to_altitude(i);
+               p_to_a_to_p = ao_altitude_to_pa(p_to_a);
+               p_error = i_abs(p_to_a_to_p - i);
+               if (p_error > max_p_error) {
+                       max_p_error = p_error;
+                       max_p_error_p = i;
+               }
+//             printf ("pa %d alt %d pa %d\n",
+//                     i, p_to_a, p_to_a_to_p);
+       }
+       for (i = -1450; i < 40000 + STEP_A; i += STEP_A) {
+               a_to_p = ao_altitude_to_pa(i);
+               a_to_p_to_a = ao_pa_to_altitude(a_to_p);
+               a_error = i_abs(a_to_p_to_a - i);
+               if (a_error > max_a_error) {
+                       max_a_error = a_error;
+                       max_a_error_a = i;
+               }
+//             printf ("alt %d pa %d alt %d\n",
+//                     i, a_to_p, a_to_p_to_a);
+       }
+       if (max_p_error > 2) {
+               printf ("max p error %d at %d\n", max_p_error,
+                       max_p_error_p);
+               ret++;
+       }
+       if (max_a_error > 1) {
+               printf ("max a error %d at %d\n", max_a_error,
+                       max_a_error_a);
+               ret++;
+       }
+       return ret;
+}
diff --git a/src/kernel/ao_convert_test.c b/src/kernel/ao_convert_test.c
new file mode 100644 (file)
index 0000000..87e7684
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#define AO_CONVERT_TEST
+#define AO_NEED_ALTITUDE_TO_PRES 1
+#include "ao_host.h"
+#include "ao_convert.c"
+
+#define STEP   1
+
+static inline int i_abs(int i) { return i < 0 ? -i : i; }
+
+int main (int argc, char **argv)
+{
+       int     i;
+       int16_t p_to_a, p_to_a_to_p;
+       int16_t a_to_p, a_to_p_to_a;
+       int max_p_error = 0, max_p_error_p = -1;
+       int max_a_error = 0, max_a_error_a = -1;
+       int p_error;
+       int a_error;
+       int ret = 0;
+
+       for (i = 0; i < 32767 + STEP; i += STEP) {
+               if (i > 32767)
+                       i = 32767;
+               p_to_a = ao_pres_to_altitude(i);
+               p_to_a_to_p = ao_altitude_to_pres(p_to_a);
+               p_error = i_abs(p_to_a_to_p - i);
+               if (p_error > max_p_error) {
+                       max_p_error = p_error;
+                       max_p_error_p = i;
+               }
+//             printf ("pres %d alt %d pres %d\n",
+//                     i, p_to_a, p_to_a_to_p);
+       }
+       for (i = -1578; i < 15835 + STEP; i += STEP) {
+               if (i > 15835)
+                       i = 15835;
+               a_to_p = ao_altitude_to_pres(i);
+               a_to_p_to_a = ao_pres_to_altitude(a_to_p);
+               a_error = i_abs(a_to_p_to_a - i);
+               if (a_error > max_a_error) {
+                       max_a_error = a_error;
+                       max_a_error_a = i;
+               }
+//             printf ("alt %d pres %d alt %d\n",
+//                     i, a_to_p, a_to_p_to_a);
+       }
+       if (max_p_error > 2) {
+               printf ("max p error %d at %d\n", max_p_error,
+                       max_p_error_p);
+               ret++;
+       }
+       if (max_a_error > 1) {
+               printf ("max a error %d at %d\n", max_a_error,
+                       max_a_error_a);
+               ret++;
+       }
+       return ret;
+}
diff --git a/src/kernel/ao_convert_volt.c b/src/kernel/ao_convert_volt.c
new file mode 100644 (file)
index 0000000..f697e74
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 MUL(p,m)       ((int32_t) AO_ADC_REFERENCE_DV * ((p) + (m)))
+#define ADD(p,m)       (MUL(p,m)/2)
+#define DIV(p,m)       ((int32_t) AO_ADC_MAX * (m))
+#define scale(v,p,m)   (((int32_t) (v) * MUL(p,m) + ADD(p,m)) / DIV(p,m))
+
+#if HAS_APRS || HAS_BATTERY_REPORT
+int16_t
+ao_battery_decivolt(int16_t adc)
+{
+       return scale(adc, AO_BATTERY_DIV_PLUS, AO_BATTERY_DIV_MINUS);
+}
+#endif
+
+#if HAS_APRS && defined(AO_IGNITE_DIV_PLUS)
+int16_t
+ao_ignite_decivolt(int16_t adc)
+{
+       return scale(adc, AO_IGNITE_DIV_PLUS, AO_IGNITE_DIV_MINUS);
+}
+#endif
diff --git a/src/kernel/ao_data.c b/src/kernel/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
diff --git a/src/kernel/ao_data.h b/src/kernel/ao_data.h
new file mode 100644 (file)
index 0000000..c4b062f
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * 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_DATA_H_
+#define _AO_DATA_H_
+
+#define GRAVITY 9.80665
+
+#if HAS_ADC
+#define AO_DATA_ADC    (1 << 0)
+#else
+#define AO_DATA_ADC    0
+#endif
+
+#if HAS_MS5607
+#include <ao_ms5607.h>
+#define AO_DATA_MS5607 (1 << 1)
+#else
+#define AO_DATA_MS5607 0
+#endif
+
+#if HAS_MPU6000
+#include <ao_mpu6000.h>
+#define AO_DATA_MPU6000        (1 << 2)
+#else
+#define AO_DATA_MPU6000        0
+#endif
+
+#if HAS_HMC5883
+#include <ao_hmc5883.h>
+#define AO_DATA_HMC5883        (1 << 3)
+#else
+#define AO_DATA_HMC5883        0
+#endif
+
+#if HAS_MMA655X
+#include <ao_mma655x.h>
+#define AO_DATA_MMA655X (1 << 4)
+#else
+#define AO_DATA_MMA655X 0
+#endif
+
+#ifdef AO_DATA_RING
+
+#define AO_DATA_ALL    (AO_DATA_ADC|AO_DATA_MS5607|AO_DATA_MPU6000|AO_DATA_HMC5883|AO_DATA_MMA655X)
+
+struct ao_data {
+       uint16_t                        tick;
+#if HAS_ADC
+       struct ao_adc                   adc;
+#endif
+#if HAS_MS5607
+       struct ao_ms5607_sample         ms5607_raw;
+       struct ao_ms5607_value          ms5607_cooked;
+#endif
+#if HAS_MPU6000
+       struct ao_mpu6000_sample        mpu6000;
+#if !HAS_MMA655X
+       int16_t                         z_accel;
+#endif
+#endif
+#if HAS_HMC5883
+       struct ao_hmc5883_sample        hmc5883;
+#endif
+#if HAS_MMA655X
+       uint16_t                        mma655x;
+#endif
+};
+
+#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;
+extern volatile __data uint8_t         ao_data_count;
+
+/*
+ * Mark a section of data as ready, check for data complete
+ */
+#define AO_DATA_PRESENT(bit)   (ao_data_present |= (bit))
+
+/*
+ * Wait until it is time to write a sensor sample; this is
+ * signaled by the timer tick
+ */
+#define AO_DATA_WAIT() do {                            \
+               ao_sleep(DATA_TO_XDATA ((void *) &ao_data_count));      \
+       } while (0)
+
+#endif /* AO_DATA_RING */
+
+#if !HAS_BARO && HAS_MS5607
+
+/* Either an MS5607 or an MS5611 hooked to a SPI port
+ */
+
+#define HAS_BARO       1
+
+typedef int32_t        pres_t;
+
+#ifndef AO_ALT_TYPE
+#define AO_ALT_TYPE    int32_t
+#endif
+
+typedef AO_ALT_TYPE    alt_t;
+
+#define ao_data_pres_cook(packet)      ao_ms5607_convert(&packet->ms5607_raw, &packet->ms5607_cooked)
+
+#define ao_data_pres(packet)   ((packet)->ms5607_cooked.pres)
+#define ao_data_temp(packet)   ((packet)->ms5607_cooked.temp)
+
+#define pres_to_altitude(p)    ao_pa_to_altitude(p)
+
+#endif
+
+#if !HAS_BARO && HAS_ADC
+
+#define HAS_BARO       1
+
+typedef int16_t pres_t;
+typedef int16_t alt_t;
+
+#define ao_data_pres(packet)   ((packet)->adc.pres)
+#define ao_data_temp(packet)   ((packet)->adc.temp)
+#define pres_to_altitude(p)    ao_pres_to_altitude(p)
+#define ao_data_pres_cook(p)
+
+#endif
+
+#if !HAS_BARO
+typedef int16_t alt_t;
+#endif
+
+/*
+ * Need a few macros to pull data from the sensors:
+ *
+ * ao_data_accel_sample        - pull raw sensor and convert to normalized values
+ * ao_data_accel       - pull normalized value (lives in the same memory)
+ * ao_data_set_accel   - store normalized value back in the sensor location
+ * ao_data_accel_invert        - flip rocket ends for positive acceleration
+ */
+
+#if HAS_ACCEL
+
+/* This section is for an analog accelerometer hooked to one of the ADC pins. As
+ * those are 5V parts, this also requires that the 5V supply be hooked to to anothe ADC
+ * pin so that the both can be measured to correct for changes between the 3.3V and 5V rails
+ */
+
+typedef int16_t accel_t;
+#define ao_data_accel(packet)                  ((packet)->adc.accel)
+#define ao_data_set_accel(packet, a)           ((packet)->adc.accel = (a))
+#define ao_data_accel_invert(a)                        (0x7fff -(a))
+
+/*
+ * Ok, the math here is a bit tricky.
+ *
+ * ao_sample_accel:  ADC output for acceleration
+ * ao_accel_ref:  ADC output for the 5V reference.
+ * ao_cook_accel: Corrected acceleration value
+ * Vcc:           3.3V supply to the CC1111
+ * Vac:           5V supply to the accelerometer
+ * accel:         input voltage to accelerometer ADC pin
+ * ref:           input voltage to 5V reference ADC pin
+ *
+ *
+ * Measured acceleration is ratiometric to Vcc:
+ *
+ *     ao_sample_accel   accel
+ *     ------------ = -----
+ *        32767        Vcc
+ *
+ * Measured 5v reference is also ratiometric to Vcc:
+ *
+ *     ao_accel_ref    ref
+ *     ------------ = -----
+ *        32767        Vcc
+ *
+ *
+ *     ao_accel_ref = 32767 * (ref / Vcc)
+ *
+ * Acceleration is measured ratiometric to the 5V supply,
+ * so what we want is:
+ *
+ *     ao_cook_accel    accel
+ *      ------------- =  -----
+ *          32767         ref
+ *
+ *
+ *                     accel    Vcc
+ *                    = ----- *  ---
+ *                       Vcc     ref
+ *
+ *                      ao_sample_accel       32767
+ *                    = ------------ *  ------------
+ *                         32767        ao_accel_ref
+ *
+ * Multiply through by 32767:
+ *
+ *                      ao_sample_accel * 32767
+ *     ao_cook_accel = --------------------
+ *                          ao_accel_ref
+ *
+ * Now, the tricky part. Getting this to compile efficiently
+ * and keeping all of the values in-range.
+ *
+ * First off, we need to use a shift of 16 instead of * 32767 as SDCC
+ * does the obvious optimizations for byte-granularity shifts:
+ *
+ *     ao_cook_accel = (ao_sample_accel << 16) / ao_accel_ref
+ *
+ * Next, lets check our input ranges:
+ *
+ *     0 <= ao_sample_accel <= 0x7fff          (singled ended ADC conversion)
+ *     0x7000 <= ao_accel_ref <= 0x7fff        (the 5V ref value is close to 0x7fff)
+ *
+ * Plugging in our input ranges, we get an output range of 0 - 0x12490,
+ * which is 17 bits. That won't work. If we take the accel ref and shift
+ * by a bit, we'll change its range:
+ *
+ *     0xe000 <= ao_accel_ref<<1 <= 0xfffe
+ *
+ *     ao_cook_accel = (ao_sample_accel << 16) / (ao_accel_ref << 1)
+ *
+ * Now the output range is 0 - 0x9248, which nicely fits in 16 bits. It
+ * is, however, one bit too large for our signed computations. So, we
+ * take the result and shift that by a bit:
+ *
+ *     ao_cook_accel = ((ao_sample_accel << 16) / (ao_accel_ref << 1)) >> 1
+ *
+ * This finally creates an output range of 0 - 0x4924. As the ADC only
+ * provides 11 bits of data, we haven't actually lost any precision,
+ * just dropped a bit of noise off the low end.
+ */
+
+#if HAS_ACCEL_REF
+
+#define ao_data_accel_cook(packet) \
+       ((uint16_t) ((((uint32_t) (packet)->adc.accel << 16) / ((packet)->adc.accel_ref << 1))) >> 1)
+
+#else
+
+#define ao_data_accel_cook(packet) ((packet)->adc.accel)
+
+#endif /* HAS_ACCEL_REF */
+
+#endif /* HAS_ACCEL */
+
+#if !HAS_ACCEL && HAS_MMA655X
+
+#define HAS_ACCEL      1
+
+typedef int16_t accel_t;
+
+/* MMA655X is hooked up so that positive values represent negative acceleration */
+
+#define AO_ACCEL_INVERT                4095
+
+#define ao_data_accel(packet)                  ((packet)->mma655x)
+#if AO_MMA655X_INVERT
+#define ao_data_accel_cook(packet)             (AO_ACCEL_INVERT - (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)            (AO_ACCEL_INVERT - (accel))
+
+#endif
+
+#if !HAS_ACCEL && HAS_MPU6000
+
+#define HAS_ACCEL      1
+
+#define AO_ACCEL_INVERT                0
+
+typedef int16_t accel_t;
+
+/* MPU6000 is hooked up so that positive y is positive acceleration */
+#define ao_data_accel(packet)                  ((packet)->z_accel)
+#define ao_data_accel_cook(packet)             (-(packet)->mpu6000.accel_y)
+#define ao_data_set_accel(packet, accel)       ((packet)->z_accel = (accel))
+#define ao_data_accel_invert(a)                        (-(a))
+
+#endif
+
+#if !HAS_GYRO && HAS_MPU6000
+
+#define HAS_GYRO       1
+
+typedef int16_t        gyro_t;         /* in raw sample units */
+typedef int16_t angle_t;       /* in degrees */
+
+/* Y axis is aligned with the direction of motion (along) */
+/* X axis is aligned in the other board axis (across) */
+/* Z axis is aligned perpendicular to the board (through) */
+
+#define ao_data_along(packet)  ((packet)->mpu6000.accel_y)
+#define ao_data_across(packet) ((packet)->mpu6000.accel_x)
+#define ao_data_through(packet)        ((packet)->mpu6000.accel_z)
+
+#define ao_data_roll(packet)   ((packet)->mpu6000.gyro_y)
+#define ao_data_pitch(packet)  ((packet)->mpu6000.gyro_x)
+#define ao_data_yaw(packet)    ((packet)->mpu6000.gyro_z)
+
+#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/kernel/ao_dbg.h b/src/kernel/ao_dbg.h
new file mode 100644 (file)
index 0000000..181e6ec
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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_DBG_H_
+#define _AO_DBG_H_
+
+/*
+ * ao_dbg.c
+ *
+ * debug another telemetrum board
+ */
+
+/* Send a byte to the dbg target */
+void
+ao_dbg_send_byte(uint8_t byte);
+
+/* Receive a byte from the dbg target */
+uint8_t
+ao_dbg_recv_byte(void);
+
+/* Start a bulk transfer to/from dbg target memory */
+void
+ao_dbg_start_transfer(uint16_t addr);
+
+/* End a bulk transfer to/from dbg target memory */
+void
+ao_dbg_end_transfer(void);
+
+/* Write a byte to dbg target memory */
+void
+ao_dbg_write_byte(uint8_t byte);
+
+/* Read a byte from dbg target memory */
+uint8_t
+ao_dbg_read_byte(void);
+
+/* Enable dbg mode, switching use of the pins */
+void
+ao_dbg_debug_mode(void);
+
+/* Reset the dbg target */
+void
+ao_dbg_reset(void);
+
+void
+ao_dbg_init(void);
+
+#endif /* _AO_DBG_H_ */
diff --git a/src/kernel/ao_debounce.c b/src/kernel/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/kernel/ao_debounce.h b/src/kernel/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/kernel/ao_distance.c b/src/kernel/ao_distance.c
new file mode 100644 (file)
index 0000000..5654182
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_distance.h>
+
+static uint32_t
+ao_dist(int32_t a, int32_t b)
+{
+       int32_t d = a - b;
+       if (d < 0)
+               d = -d;
+
+       return (uint32_t) ((int64_t) d * 111198 / 10000000);
+}
+
+static uint32_t
+ao_lat_dist(int32_t lat_a, int32_t lat_b)
+{
+       return ao_dist(lat_a, lat_b);
+}
+
+static const uint8_t cos_table[] = {
+   0, /*  0 */
+   0, /*  1 */
+   0, /*  2 */
+ 255, /*  3 */
+ 254, /*  4 */
+ 253, /*  5 */
+ 252, /*  6 */
+ 251, /*  7 */
+ 249, /*  8 */
+ 247, /*  9 */
+ 245, /* 10 */
+ 243, /* 11 */
+ 240, /* 12 */
+ 238, /* 13 */
+ 235, /* 14 */
+ 232, /* 15 */
+ 228, /* 16 */
+ 225, /* 17 */
+ 221, /* 18 */
+ 217, /* 19 */
+ 213, /* 20 */
+ 209, /* 21 */
+ 205, /* 22 */
+ 200, /* 23 */
+ 195, /* 24 */
+ 190, /* 25 */
+ 185, /* 26 */
+ 180, /* 27 */
+ 175, /* 28 */
+ 169, /* 29 */
+ 163, /* 30 */
+ 158, /* 31 */
+ 152, /* 32 */
+ 145, /* 33 */
+ 139, /* 34 */
+ 133, /* 35 */
+ 126, /* 36 */
+ 120, /* 37 */
+ 113, /* 38 */
+ 106, /* 39 */
+ 100, /* 40 */
+  93, /* 41 */
+  86, /* 42 */
+  79, /* 43 */
+  71, /* 44 */
+  64, /* 45 */
+  57, /* 46 */
+  49, /* 47 */
+  42, /* 48 */
+  35, /* 49 */
+  27, /* 50 */
+  20, /* 51 */
+  12, /* 52 */
+   5, /* 53 */
+   1, /* 54 */
+};
+
+static uint32_t
+ao_lon_dist(int32_t lon_a, int32_t lon_b)
+{
+       uint8_t         c = cos_table[lon_a >> 24];
+       uint32_t        lon_dist;
+
+       /* check if it's shorter to go the other way around */
+       if ((lon_a >> 1) < (lon_b >> 1) - (1800000000 >> 1))
+               lon_a += 3600000000;
+       lon_dist = ao_dist(lon_a, lon_b);
+       if (c) {
+               if (lon_dist & 0x7f800000)
+                       lon_dist = (lon_dist >> 8) * c;
+               else
+                       lon_dist = (lon_dist * (int16_t) c) >> 8;
+       }
+       return lon_dist;
+}
+
+static uint32_t sqr(uint32_t x) { return x * x; }
+
+uint32_t
+ao_distance(int32_t lat_a, int32_t lon_a, int32_t lat_b, int32_t lon_b)
+{
+       uint32_t        lat_dist = ao_lat_dist(lat_a, lat_b);
+       uint32_t        lon_dist = ao_lon_dist(lon_a, lon_b);
+
+       return ao_sqrt (sqr(lat_dist) + sqr(lon_dist));
+}
diff --git a/src/kernel/ao_distance.h b/src/kernel/ao_distance.h
new file mode 100644 (file)
index 0000000..6762434
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_DISTANCE_H_
+#define _AO_DISTANCE_H_
+#include <stdint.h>
+
+uint32_t
+ao_distance(int32_t lat_a, int32_t lon_a, int32_t lat_b, int32_t lon_b);
+
+#endif /* _AO_DISTANCE_H_ */
diff --git a/src/kernel/ao_ee_fake.c b/src/kernel/ao_ee_fake.c
new file mode 100644 (file)
index 0000000..7fcfcab
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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"
+
+/*
+ * For hardware without eeprom, the config code still
+ * wants to call these functions
+ */
+uint8_t
+ao_ee_write_config(uint8_t *buf, uint16_t len) __reentrant
+{
+       (void) buf;
+       (void) len;
+       return 1;
+}
+
+uint8_t
+ao_ee_read_config(uint8_t *buf, uint16_t len) __reentrant
+{
+       ao_xmemset(buf, '\0', len);
+       return 1;
+}
diff --git a/src/kernel/ao_eeprom.h b/src/kernel/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_ */
diff --git a/src/kernel/ao_fake_flight.c b/src/kernel/ao_fake_flight.c
new file mode 100644 (file)
index 0000000..11329bb
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_fake_flight.h>
+#if HAS_MS5607 || HAS_MS5611
+#include <ao_ms5607.h>
+#endif
+
+uint8_t                        ao_fake_flight_active;
+
+static uint8_t         ao_fake_has_cur;
+static volatile uint8_t        ao_fake_has_next;
+static uint8_t         ao_fake_has_offset;
+static uint16_t                ao_fake_tick_offset;
+static struct ao_data  ao_fake_cur, ao_fake_next;
+
+void
+ao_fake_flight_poll(void)
+{
+       if (ao_fake_has_next && (ao_tick_count - ao_fake_next.tick) >= 0) {
+               ao_fake_cur = ao_fake_next;
+               ao_fake_has_next = 0;
+               ao_wakeup((void *) &ao_fake_has_next);
+               ao_fake_has_cur = 1;
+       }
+       if (!ao_fake_has_cur)
+               return;
+       ao_data_ring[ao_data_head] = ao_fake_cur;
+       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);
+}
+
+static uint8_t
+ao_fake_data_read(void)
+{
+       uint8_t i;
+       uint8_t *d = (void *) &ao_fake_next;
+
+       if (getchar() == 0)
+               return FALSE;
+       for (i = 0; i < sizeof (struct ao_data); i++)
+               *d++ = getchar();
+       if (!ao_fake_has_offset) {
+               ao_fake_tick_offset = (ao_tick_count + 1000) - ao_fake_next.tick;
+               ao_fake_next.tick = ao_tick_count;
+               ao_fake_has_offset = 1;
+       } else
+               ao_fake_next.tick += ao_fake_tick_offset;
+       ao_fake_has_next = 1;
+       return TRUE;
+}
+
+static void
+ao_fake_calib_get(struct ao_fake_calib *calib)
+{
+#if HAS_ACCEL
+       calib->accel_plus_g = ao_config.accel_plus_g;
+       calib->accel_minus_g = ao_config.accel_minus_g;
+#endif
+#if HAS_GYRO
+       calib->accel_zero_along = ao_config.accel_zero_along;
+       calib->accel_zero_across = ao_config.accel_zero_across;
+       calib->accel_zero_through = ao_config.accel_zero_through;
+#endif
+#if HAS_MS5607 || HAS_MS5611
+       calib->ms5607_prom = ao_ms5607_prom;
+#endif
+}
+
+static void
+ao_fake_calib_set(struct ao_fake_calib *calib)
+{
+#if HAS_ACCEL
+       ao_config.accel_plus_g = calib->accel_plus_g;
+       ao_config.accel_minus_g = calib->accel_minus_g;
+#endif
+#if HAS_GYRO
+       ao_config.accel_zero_along = calib->accel_zero_along;
+       ao_config.accel_zero_across = calib->accel_zero_across;
+       ao_config.accel_zero_through = calib->accel_zero_through;
+#endif
+#if HAS_MS5607 || HAS_MS5611
+       ao_ms5607_prom = calib->ms5607_prom;
+#endif
+}
+
+static uint8_t
+ao_fake_calib_read(void)
+{
+       struct ao_fake_calib    ao_calib;
+       uint8_t                 *d = (void *) &ao_calib;
+       uint16_t                i;
+
+       /* Read calibration data */
+       for (i = 0; i < sizeof (struct ao_fake_calib); i++)
+               *d++ = getchar();
+       if (ao_calib.major != AO_FAKE_CALIB_MAJOR
+#if AO_FAKE_CALIB_MINOR != 0
+           || ao_calib.minor < AO_FAKE_CALIB_MINOR
+#endif
+               ) {
+               printf ("Calibration data major version mismatch %d.%d <= %d.%d\n",
+                       ao_calib.major, ao_calib.minor, AO_FAKE_CALIB_MAJOR, AO_FAKE_CALIB_MINOR);
+               return FALSE;
+       }
+       ao_fake_calib_set(&ao_calib);
+       return TRUE;
+}
+
+static void
+ao_fake_flight(void)
+{
+       int16_t                 calib_size, data_size;
+       struct ao_fake_calib    save_calib;
+       uint16_t                my_pyro_fired = 0;
+       enum ao_flight_state    my_state = ao_flight_invalid;
+       int                     i;
+
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       calib_size = ao_cmd_lex_i;
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       data_size = ao_cmd_lex_i;
+       if ((unsigned) calib_size != sizeof (struct ao_fake_calib)) {
+               printf ("calib size %d larger than actual size %d\n",
+                       calib_size, sizeof (struct ao_fake_calib));
+               ao_cmd_status = ao_cmd_syntax_error;
+               return;
+       }
+       if (data_size != sizeof (struct ao_data)) {
+               printf ("data size %d doesn't match actual size %d\n",
+                       data_size, sizeof (struct ao_data));
+               ao_cmd_status = ao_cmd_syntax_error;
+               return;
+       }
+       ao_fake_calib_get(&save_calib);
+       if (!ao_fake_calib_read())
+               return;
+
+       ao_fake_has_next = 0;
+       ao_fake_has_cur = 0;
+       ao_fake_flight_active = 1;
+       ao_sample_init();
+#if PACKET_HAS_SLAVE
+       ao_packet_slave_stop();
+#endif
+#if AO_LED_RED
+       /* Turn on the LED to indicate startup */
+       ao_led_on(AO_LED_RED);
+#endif
+       ao_flight_state = ao_flight_startup;
+       for (;;) {
+               if (my_state != ao_flight_state) {
+                       printf("state %d\n", ao_flight_state);
+                       my_state = ao_flight_state;
+                       flush();
+               }
+               if (my_pyro_fired != ao_pyro_fired) {
+                       int     pyro;
+
+                       for (pyro = 0; pyro < AO_PYRO_NUM; pyro++) {
+                               uint16_t        bit = (1 << pyro);
+                               if (!(my_pyro_fired & bit) && (ao_pyro_fired & bit))
+                                       printf ("fire %d\n", pyro);
+                       }
+                       my_pyro_fired = ao_pyro_fired;
+               }
+               while (ao_fake_has_next)
+                       ao_sleep((void *) &ao_fake_has_next);
+               if (!ao_fake_data_read())
+                       break;
+       }
+
+       /* Wait 20 seconds to see if we enter landed state */
+       for (i = 0; i < 200; i++)
+       {
+               if (ao_flight_state == ao_flight_landed)
+                       break;
+               ao_delay(AO_MS_TO_TICKS(100));
+       }
+#if AO_LED_RED
+       /* Turn on the LED to indicate startup */
+       ao_led_on(AO_LED_RED);
+#endif
+       ao_fake_flight_active = 0;
+       ao_flight_state = ao_flight_startup;
+       ao_sample_init();
+       ao_fake_calib_set(&save_calib);
+}
+
+static const struct ao_cmds ao_fake_flight_cmds[] = {
+       { ao_fake_flight,       "F <calib-size> <data-size>\0Start fake flight" },
+       { 0, NULL }
+};
+
+void
+ao_fake_flight_init(void)
+{
+       ao_cmd_register(&ao_fake_flight_cmds[0]);
+}
diff --git a/src/kernel/ao_fake_flight.h b/src/kernel/ao_fake_flight.h
new file mode 100644 (file)
index 0000000..172fc58
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_FAKE_FLIGHT_H_
+#define _AO_FAKE_FLIGHT_H_
+#if HAS_MS5607 || HAS_MS5611
+#include <ao_ms5607.h>
+#endif
+
+extern uint8_t ao_fake_flight_active;
+
+#define AO_FAKE_CALIB_MAJOR    1
+#define AO_FAKE_CALIB_MINOR    0
+
+struct ao_fake_calib {
+       uint16_t                major;
+       uint16_t                minor;
+#if HAS_ACCEL
+       int16_t                 accel_plus_g;
+       int16_t                 accel_minus_g;
+#endif
+#if HAS_GYRO
+       int16_t                 accel_zero_along;
+       int16_t                 accel_zero_across;
+       int16_t                 accel_zero_through;
+       uint16_t                pad30;
+#endif
+#if HAS_MS5607 || HAS_MS5611
+       struct ao_ms5607_prom   ms5607_prom;
+#endif
+};
+
+void
+ao_fake_flight_poll(void);
+
+void
+ao_fake_flight_init(void);
+
+#endif /* _AO_FAKE_FLIGHT_H_ */
diff --git a/src/kernel/ao_fec.h b/src/kernel/ao_fec.h
new file mode 100644 (file)
index 0000000..618756c
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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_FEC_H_
+#define _AO_FEC_H_
+
+#include <stdint.h>
+
+#define AO_FEC_CRC_INIT                        0xffff
+#define AO_FEC_TRELLIS_TERMINATOR      0x0b
+#define AO_FEC_PREPARE_EXTRA           4
+
+extern const uint8_t ao_fec_whiten_table[];
+
+#if AO_FEC_DEBUG
+void
+ao_fec_dump_bytes(const uint8_t *bytes, uint16_t len, const char *name);
+#endif
+
+static inline uint16_t
+ao_fec_crc_byte(uint8_t byte, uint16_t crc)
+{
+       uint8_t bit;
+
+       for (bit = 0; bit < 8; bit++) {
+               if (((crc & 0x8000) >> 8) ^ (byte & 0x80))
+                       crc = (crc << 1) ^ 0x8005;
+               else
+                       crc = (crc << 1);
+               byte <<= 1;
+       }
+       return crc;
+}
+
+uint16_t
+ao_fec_crc(const uint8_t *bytes, uint8_t len);
+
+/*
+ * 'len' is the length of the original data; 'bytes'
+ * must  be four bytes longer than that, and the first
+ * two after 'len' must be the received crc
+ */
+uint8_t
+ao_fec_check_crc(const uint8_t *bytes, uint8_t len);
+
+/*
+ * Compute CRC, whiten, convolve and interleave data. 'out' must be (len + 4) * 2 bytes long
+ */
+uint8_t
+ao_fec_encode(const uint8_t *in, uint8_t len, uint8_t *out);
+
+/*
+ * Decode data. 'in' is one byte per bit, soft decision
+ * 'out' must be len/8 bytes long
+ */
+
+#define AO_FEC_DECODE_BLOCK    (32)    /* callback must return multiples of this many bits */
+
+#define AO_FEC_DECODE_CRC_OK   0x80    /* stored in out[out_len-1] */
+
+uint8_t
+ao_fec_decode(const uint8_t *in, uint16_t in_len, uint8_t *out, uint8_t out_len, uint16_t (*callback)(void));
+
+/*
+ * Interleave data packed in bytes. 'out' must be 'len' bytes long.
+ */
+uint16_t
+ao_fec_interleave_bytes(uint8_t *in, uint16_t len, uint8_t *out);
+
+#endif /* _AO_FEC_H_ */
diff --git a/src/kernel/ao_fec_rx.c b/src/kernel/ao_fec_rx.c
new file mode 100644 (file)
index 0000000..c4f5559
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * 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_fec.h>
+#include <stdio.h>
+
+#ifdef TELEMEGA
+#include <ao.h>
+#endif
+
+#if AO_PROFILE
+#include <ao_profile.h>
+
+uint32_t       ao_fec_decode_start, ao_fec_decode_end;
+#endif
+
+/* 
+ * byte order repeats through 3 2 1 0
+ *     
+ * bit-pair order repeats through
+ *
+ *  1/0 3/2 5/4 7/6
+ *
+ * So, the over all order is:
+ *
+ *     3,1/0   2,1/0   1,1/0   0,1/0
+ *     3,3/2   2,3/2   1,3/2   0,3/2
+ *     3,5/4   2,5/4   1,5/4   0,5/4
+ *     3,7/6   2,7/6   1,7/6   0,7/6
+ *
+ * The raw bit order is thus
+ *
+ *     1e/1f   16/17   0e/0f   06/07
+ *     1c/1d   14/15   0c/0d   04/05
+ *     1a/1b   12/13   0a/0b   02/03
+ *     18/19   10/11   08/09   00/01
+ */
+
+static const uint8_t ao_interleave_order[] = {
+       0x1e, 0x16, 0x0e, 0x06,
+       0x1c, 0x14, 0x0c, 0x04,
+       0x1a, 0x12, 0x0a, 0x02,
+       0x18, 0x10, 0x08, 0x00
+};
+
+static inline uint16_t ao_interleave_index(uint16_t i) {
+       return (i & ~0x1e) | ao_interleave_order[(i & 0x1e) >> 1];
+}
+
+#define NUM_STATE      8
+#define NUM_HIST       24
+
+typedef uint32_t       bits_t;
+
+#define V_0            0xff
+#define V_1            0x00
+
+/*
+ * These are just the 'zero' states; the 'one' states mirror them
+ */
+static const uint8_t ao_fec_decode_table[NUM_STATE*2] = {
+       V_0, V_0,       /* 000 */
+       V_0, V_1,       /* 001 */
+       V_1, V_1,       /* 010 */
+       V_1, V_0,       /* 011 */
+       V_1, V_1,       /* 100 */
+       V_1, V_0,       /* 101 */
+       V_0, V_0,       /* 110 */
+       V_0, V_1        /* 111 */
+};
+
+static inline uint8_t
+ao_next_state(uint8_t state, uint8_t bit)
+{
+       return ((state << 1) | bit) & 0x7;
+}
+
+/*
+ * 'in' is 8-bits per symbol soft decision data
+ * 'len' is input byte length. 'out' must be
+ * 'len'/16 bytes long
+ */
+
+uint8_t
+ao_fec_decode(const uint8_t *in, uint16_t len, uint8_t *out, uint8_t out_len, uint16_t (*callback)(void))
+{
+       static uint32_t cost[2][NUM_STATE];             /* path cost */
+       static bits_t   bits[2][NUM_STATE];             /* save bits to quickly output them */
+
+       uint16_t        i;                              /* input byte index */
+       uint16_t        b;                              /* encoded symbol index (bytes/2) */
+       uint16_t        o;                              /* output bit index */
+       uint8_t         p;                              /* previous cost/bits index */
+       uint8_t         n;                              /* next cost/bits index */
+       uint8_t         state;                          /* state index */
+       const uint8_t   *whiten = ao_fec_whiten_table;
+       uint16_t        interleave;                     /* input byte array index */
+       uint8_t         s0, s1;
+       uint16_t        avail;
+       uint16_t        crc = AO_FEC_CRC_INIT;
+#if AO_PROFILE
+       uint32_t        start_tick;
+#endif
+
+       p = 0;
+       for (state = 0; state < NUM_STATE; state++) {
+               cost[0][state] = 0x7fffffff;
+               bits[0][state] = 0;
+       }
+       cost[0][0] = 0;
+
+       if (callback)
+               avail = 0;
+       else
+               avail = len;
+
+#if AO_PROFILE
+       if (!avail) {
+               avail = callback();
+               if (!avail)
+                       return 0;
+       }
+       start_tick = ao_profile_tick();
+#endif
+       o = 0;
+       for (i = 0; i < len; i += 2) {
+               b = i/2;
+               n = p ^ 1;
+
+               if (!avail) {
+                       avail = callback();
+                       if (!avail)
+                               return 0;
+               }
+
+               /* Fetch one pair of input bytes, de-interleaving
+                * the input.
+                */
+               interleave = ao_interleave_index(i);
+               s0 = in[interleave];
+               s1 = in[interleave+1];
+
+               avail -= 2;
+
+               /* Compute path costs and accumulate output bit path
+                * for each state and encoded bit value. Unrolling
+                * this loop is worth about > 30% performance boost.
+                * Decoding 76-byte remote access packets is reduced
+                * from 14.700ms to 9.3ms. Redoing the loop to
+                * directly compare the two pasts for each future state
+                * reduces this down to 5.7ms
+                */
+
+               /* Ok, of course this is tricky, it's optimized.
+                *
+                * First, it's important to realize that we have 8
+                * states representing the combinations of the three
+                * most recent bits from the encoder. Flipping any
+                * of these three bits flips both output bits.
+                *
+                * 'state<<1' represents the target state for a new
+                * bit value of 0. '(state<<1)+1' represents the
+                * target state for a new bit value of 1.
+                *
+                * 'state' is the previous state with an oldest bit
+                * value of 0. 'state + 4' is the previous state with
+                * an oldest bit value of 1. These two states will
+                * either lead to 'state<<1' or '(state<<1)+1', depending
+                * on whether the next encoded bit was a zero or a one.
+                *
+                * m0 and m1 are the cost of coming to 'state<<1' from
+                * one of the two possible previous states 'state' and
+                * 'state + 4'.
+                *
+                * Because we know the expected values of each
+                * received bit are flipped between these two previous
+                * states:
+                * 
+                *      bitcost(state+4) = 510 - bitcost(state)
+                *
+                * With those two total costs in hand, we then pick
+                * the lower as the cost of the 'state<<1', and compute
+                * the path of bits leading to that state.
+                *
+                * Then, do the same for '(state<<1) + 1'. This time,
+                * instead of computing the m0 and m1 values from
+                * scratch, because the only difference is that we're
+                * expecting a one bit instead of a zero bit, we just
+                * flip the bitcost values around to match the
+                * expected transmitted bits with some tricky
+                * arithmetic which is equivalent to:
+                *
+                *      m0 = cost[p][state] + (510 - bitcost);
+                *      m1 = cost[p][state+4] + bitcost
+                *
+                * Then, the lowest cost and bit trace of the new state
+                * is saved.
+                */
+
+#define DO_STATE(state) {                                              \
+                       uint32_t        bitcost;                        \
+                                                                       \
+                       uint32_t        m0;                             \
+                       uint32_t        m1;                             \
+                       uint32_t        bit;                            \
+                                                                       \
+                       bitcost = ((uint32_t) (s0 ^ ao_fec_decode_table[(state<<1)]) + \
+                                  (uint32_t) (s1 ^ ao_fec_decode_table[(state<<1)|1])); \
+                                                                       \
+                       m0 = cost[p][state] + bitcost;                  \
+                       m1 = cost[p][state+4] + (510 - bitcost);        \
+                       bit = m0 > m1;                                  \
+                       cost[n][state<<1] = bit ? m1 : m0;              \
+                       bits[n][state<<1] = (bits[p][state + (bit<<2)] << 1) | (state&1); \
+                                                                       \
+                       m0 -= (bitcost+bitcost-510);                    \
+                       m1 += (bitcost+bitcost-510);                    \
+                       bit = m0 > m1;                                  \
+                       cost[n][(state<<1)+1] = bit ? m1 : m0;          \
+                       bits[n][(state<<1)+1] = (bits[p][state + (bit<<2)] << 1) | (state&1); \
+               }
+
+               DO_STATE(0);
+               DO_STATE(1);
+               DO_STATE(2);
+               DO_STATE(3);
+
+#if 0
+               printf ("bit %3d symbol %2x %2x:", i/2, s0, s1);
+               for (state = 0; state < NUM_STATE; state++) {
+                       printf (" %8u(%08x)", cost[n][state], bits[n][state]);
+               }
+               printf ("\n");
+#endif
+               p = n;
+
+               /* A loop is needed to handle the last output byte. It
+                * won't have any bits of future data to perform full
+                * error correction, but we might as well give the
+                * best possible answer anyways.
+                */
+               while ((b - o) >= (8 + NUM_HIST) || (i + 2 >= len && b > o)) {
+
+                       /* Compute number of bits to the end of the
+                        * last full byte of data. This is generally
+                        * NUM_HIST, unless we've reached
+                        * the end of the input, in which case
+                        * it will be seven.
+                        */
+                       int8_t          dist = b - (o + 8);     /* distance to last ready-for-writing bit */
+                       uint32_t        min_cost;               /* lowest cost */
+                       uint8_t         min_state;              /* lowest cost state */
+                       uint8_t         byte;
+
+                       /* Find the best fit at the current point
+                        * of the decode.
+                        */
+                       min_cost = cost[p][0];
+                       min_state = 0;
+                       for (state = 1; state < NUM_STATE; state++) {
+                               if (cost[p][state] < min_cost) {
+                                       min_cost = cost[p][state];
+                                       min_state = state;
+                               }
+                       }
+
+                       /* The very last byte of data has the very last bit
+                        * of data left in the state value; just smash the
+                        * bits value in place and reset the 'dist' from
+                        * -1 to 0 so that the full byte is read out
+                        */
+                       if (dist < 0) {
+                               bits[p][min_state] = (bits[p][min_state] << 1) | (min_state & 1);
+                               dist = 0;
+                       }
+
+#if 0
+                       printf ("\tbit %3d min_cost %5d old bit %3d old_state %x bits %02x whiten %0x\n",
+                               i/2, min_cost, o + 8, min_state, (bits[p][min_state] >> dist) & 0xff, *whiten);
+#endif
+                       byte = (bits[p][min_state] >> dist) ^ *whiten++;
+                       *out++ = byte;
+                       if (out_len > 2)
+                               crc = ao_fec_crc_byte(byte, crc);
+
+                       if (!--out_len) {
+                               if ((out[-2] == (uint8_t) (crc >> 8)) &&
+                                   out[-1] == (uint8_t) crc)
+                                       out[-1] = AO_FEC_DECODE_CRC_OK;
+                               else
+                                       out[-1] = 0;
+                               out[-2] = 0;
+                               goto done;
+                       }
+                       o += 8;
+               }
+       }
+done:
+#if AO_PROFILE
+       ao_fec_decode_start = start_tick;
+       ao_fec_decode_end = ao_profile_tick();
+#endif
+       return 1;
+}
diff --git a/src/kernel/ao_fec_tx.c b/src/kernel/ao_fec_tx.c
new file mode 100644 (file)
index 0000000..4941d74
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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_fec.h>
+#include <stdio.h>
+
+#if AO_FEC_DEBUG
+void
+ao_fec_dump_bytes(const uint8_t *bytes, uint16_t len, const char *name)
+{
+       uint16_t        i;
+
+       printf ("%s (%d):", name, len);
+       for (i = 0; i < len; i++) {
+               if ((i & 7) == 0)
+                       printf ("\n\t%02x:", i);
+               printf(" %02x", bytes[i]);
+       }
+       printf ("\n");
+}
+#endif
+
+uint16_t
+ao_fec_crc(const uint8_t *bytes, uint8_t len)
+{
+       uint16_t        crc = AO_FEC_CRC_INIT;
+
+       while (len--)
+               crc = ao_fec_crc_byte(*bytes++, crc);
+       return crc;
+}
+
+/*
+ * len is the length of the data; the crc will be
+ * the fist two bytes after that
+ */
+
+uint8_t
+ao_fec_check_crc(const uint8_t *bytes, uint8_t len)
+{
+       uint16_t        computed_crc = ao_fec_crc(bytes, len);
+       uint16_t        received_crc = (bytes[len] << 8) | (bytes[len+1]);
+
+       return computed_crc == received_crc;
+}
+
+/*
+ * Compute CRC and trellis-terminator/interleave-pad bytes
+ */
+static uint8_t
+ao_fec_prepare(const uint8_t *in, uint8_t len, uint8_t *extra)
+{
+       uint16_t        crc = ao_fec_crc (in, len);
+       uint8_t         i = 0;
+       uint8_t         num_fec;
+
+       /* Append CRC */
+       extra[i++] = crc >> 8;
+       extra[i++] = crc;
+
+       /* Append FEC -- 1 byte if odd, two bytes if even */
+       num_fec = 2 - (i & 1);
+       while (num_fec--)
+               extra[i++] = AO_FEC_TRELLIS_TERMINATOR;
+       return i;
+}
+
+const uint8_t ao_fec_whiten_table[] = {
+#include "ao_whiten.h"
+};
+
+static const uint8_t ao_fec_encode_table[16] = {
+/* next 0  1     state */
+       0, 3,   /* 000 */
+       1, 2,   /* 001 */
+       3, 0,   /* 010 */
+       2, 1,   /* 011 */
+       3, 0,   /* 100 */
+       2, 1,   /* 101 */
+       0, 3,   /* 110 */
+       1, 2    /* 111 */
+};
+
+uint8_t
+ao_fec_encode(const uint8_t *in, uint8_t len, uint8_t *out)
+{
+       uint8_t         extra[AO_FEC_PREPARE_EXTRA];
+       uint8_t         extra_len;
+       uint32_t        encode, interleave;
+       uint8_t         pair, byte, bit;
+       uint16_t        fec = 0;
+       const uint8_t   *whiten = ao_fec_whiten_table;
+
+       extra_len = ao_fec_prepare(in, len, extra);
+       for (pair = 0; pair < len + extra_len; pair += 2) {
+               encode = 0;
+               for (byte = 0; byte < 2; byte++) {
+                       if (pair + byte == len)
+                               in = extra;
+                       fec |= *in++ ^ *whiten++;
+                       for (bit = 0; bit < 8; bit++) {
+                               encode = encode << 2 | ao_fec_encode_table[fec >> 7];
+                               fec = (fec << 1) & 0x7ff;
+                       }
+               }
+
+               interleave = 0;
+               for (bit = 0; bit < 4 * 4; bit++) {
+                       uint8_t byte_shift = (bit & 0x3) << 3;
+                       uint8_t bit_shift = (bit & 0xc) >> 1;
+
+                       interleave = (interleave << 2) | ((encode >> (byte_shift + bit_shift)) & 0x3);
+               }
+               *out++ = interleave >> 24;
+               *out++ = interleave >> 16;
+               *out++ = interleave >> 8;
+               *out++ = interleave >> 0;
+       }
+       return (len + extra_len) * 2;
+}
diff --git a/src/kernel/ao_flight.c b/src/kernel/ao_flight.c
new file mode 100644 (file)
index 0000000..2b433ee
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * 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.
+ */
+
+#ifndef AO_FLIGHT_TEST
+#include "ao.h"
+#include <ao_log.h>
+#endif
+
+#if HAS_MPU6000
+#include <ao_quaternion.h>
+#endif
+
+#ifndef HAS_ACCEL
+#error Please define HAS_ACCEL
+#endif
+
+#ifndef HAS_GPS
+#error Please define HAS_GPS
+#endif
+
+#ifndef HAS_USB
+#error Please define HAS_USB
+#endif
+
+#if HAS_FAKE_FLIGHT
+#include <ao_fake_flight.h>
+#endif
+
+#ifndef HAS_TELEMETRY
+#define HAS_TELEMETRY  HAS_RADIO
+#endif
+
+/* Main flight thread. */
+
+__pdata enum ao_flight_state   ao_flight_state;        /* current flight state */
+__pdata uint16_t               ao_boost_tick;          /* time of launch detect */
+__pdata uint16_t               ao_motor_number;        /* number of motors burned so far */
+
+#if HAS_SENSOR_ERRORS
+/* 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
+ */
+static __data uint16_t         ao_interval_end;
+static __data int16_t          ao_interval_min_height;
+static __data int16_t          ao_interval_max_height;
+#if HAS_ACCEL
+static __data int16_t          ao_coast_avg_accel;
+#endif
+
+__pdata uint8_t                        ao_flight_force_idle;
+
+/* We also have a clock, which can be used to sanity check things in
+ * case of other failures
+ */
+
+#define BOOST_TICKS_MAX        AO_SEC_TO_TICKS(15)
+
+/* Landing is detected by getting constant readings from both pressure and accelerometer
+ * for a fairly long time (AO_INTERVAL_TICKS)
+ */
+#define AO_INTERVAL_TICKS      AO_SEC_TO_TICKS(10)
+
+#define abs(a) ((a) < 0 ? -(a) : (a))
+
+void
+ao_flight(void)
+{
+       ao_sample_init();
+       ao_flight_state = ao_flight_startup;
+       for (;;) {
+
+               /*
+                * Process ADC samples, just looping
+                * until the sensors are calibrated.
+                */
+               if (!ao_sample())
+                       continue;
+
+               switch (ao_flight_state) {
+               case ao_flight_startup:
+
+                       /* Check to see what mode we should go to.
+                        *  - Invalid mode if accel cal appears to be out
+                        *  - pad mode if we're upright,
+                        *  - idle mode otherwise
+                        */
+#if HAS_ACCEL
+                       if (ao_config.accel_plus_g == 0 ||
+                           ao_config.accel_minus_g == 0 ||
+                           ao_ground_accel < ao_config.accel_plus_g - ACCEL_NOSE_UP ||
+                           ao_ground_accel > ao_config.accel_minus_g + ACCEL_NOSE_UP ||
+                           ao_ground_height < -1000 ||
+                           ao_ground_height > 7000)
+                       {
+                               /* Detected an accel value outside -1.5g to 1.5g
+                                * (or uncalibrated values), so we go into invalid mode
+                                */
+                               ao_flight_state = ao_flight_invalid;
+
+#if HAS_RADIO && PACKET_HAS_SLAVE
+                               /* Turn on packet system in invalid mode on TeleMetrum */
+                               ao_packet_slave_start();
+#endif
+                       } else
+#endif
+                               if (!ao_flight_force_idle
+#if HAS_ACCEL
+                                   && ao_ground_accel < ao_config.accel_plus_g + ACCEL_NOSE_UP
+#endif
+                                       )
+                       {
+                               /* Set pad mode - we can fly! */
+                               ao_flight_state = ao_flight_pad;
+#if HAS_USB && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE
+                               /* Disable the USB controller in flight mode
+                                * to save power
+                                */
+#if HAS_FAKE_FLIGHT
+                               if (!ao_fake_flight_active)
+#endif
+                                       ao_usb_disable();
+#endif
+
+#if !HAS_ACCEL && PACKET_HAS_SLAVE
+                               /* Disable packet mode in pad state on TeleMini */
+                               ao_packet_slave_stop();
+#endif
+
+#if HAS_TELEMETRY
+                               /* Turn on telemetry system */
+                               ao_rdf_set(1);
+                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
+#endif
+#if AO_LED_RED
+                               /* 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;
+#if HAS_SENSOR_ERRORS
+                               if (ao_sensor_errors)
+                                       ao_flight_state = ao_flight_invalid;
+#endif
+#if HAS_ACCEL && HAS_RADIO && PACKET_HAS_SLAVE
+                               /* Turn on packet system in idle mode on TeleMetrum */
+                               ao_packet_slave_start();
+#endif
+
+#if AO_LED_RED
+                               /* 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));
+
+                       break;
+               case ao_flight_pad:
+                       /* pad to boost:
+                        *
+                        * barometer: > 20m vertical motion
+                        *             OR
+                        * accelerometer: > 2g AND velocity > 5m/s
+                        *
+                        * The accelerometer should always detect motion before
+                        * the barometer, but we use both to make sure this
+                        * transition is detected. If the device
+                        * doesn't have an accelerometer, then ignore the
+                        * speed and acceleration as they are quite noisy
+                        * on the pad.
+                        */
+                       if (ao_height > AO_M_TO_HEIGHT(20)
+#if HAS_ACCEL
+                           || (ao_accel > AO_MSS_TO_ACCEL(20) &&
+                               ao_speed > AO_MS_TO_SPEED(5))
+#endif
+                               )
+                       {
+                               ao_flight_state = ao_flight_boost;
+                               ao_boost_tick = ao_sample_tick;
+
+                               /* start logging data */
+                               ao_log_start();
+
+#if HAS_TELEMETRY
+                               /* Increase telemetry rate */
+                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_FLIGHT);
+
+                               /* disable RDF beacon */
+                               ao_rdf_set(0);
+#endif
+
+#if HAS_GPS
+                               /* Record current GPS position by waking up GPS log tasks */
+                               ao_gps_new = AO_GPS_NEW_DATA | AO_GPS_NEW_TRACKING;
+                               ao_wakeup(&ao_gps_new);
+#endif
+
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       }
+                       break;
+               case ao_flight_boost:
+
+                       /* boost to fast:
+                        *
+                        * accelerometer: start to fall at > 1/4 G
+                        *              OR
+                        * time: boost for more than 15 seconds
+                        *
+                        * Detects motor burn out by the switch from acceleration to
+                        * deceleration, or by waiting until the maximum burn duration
+                        * (15 seconds) has past.
+                        */
+                       if ((ao_accel < AO_MSS_TO_ACCEL(-2.5) && ao_height > AO_M_TO_HEIGHT(100)) ||
+                           (int16_t) (ao_sample_tick - ao_boost_tick) > BOOST_TICKS_MAX)
+                       {
+#if HAS_ACCEL
+                               ao_flight_state = ao_flight_fast;
+                               ao_coast_avg_accel = ao_accel;
+#else
+                               ao_flight_state = ao_flight_coast;
+#endif
+                               ++ao_motor_number;
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       }
+                       break;
+#if HAS_ACCEL
+               case ao_flight_fast:
+                       /*
+                        * This is essentially the same as coast,
+                        * but the barometer is being ignored as
+                        * it may be unreliable.
+                        */
+                       if (ao_speed < AO_MS_TO_SPEED(AO_MAX_BARO_SPEED))
+                       {
+                               ao_flight_state = ao_flight_coast;
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       } else
+                               goto check_re_boost;
+                       break;
+#endif
+               case ao_flight_coast:
+
+                       /*
+                        * By customer request - allow the user
+                        * to lock out apogee detection for a specified
+                        * number of seconds.
+                        */
+                       if (ao_config.apogee_lockout) {
+                               if ((ao_sample_tick - ao_boost_tick) <
+                                   AO_SEC_TO_TICKS(ao_config.apogee_lockout))
+                                       break;
+                       }
+
+                       /* apogee detect: coast to drogue deploy:
+                        *
+                        * speed: < 0
+                        *
+                        * Also make sure the model altitude is tracking
+                        * the measured altitude reasonably closely; otherwise
+                        * we're probably transsonic.
+                        */
+                       if (ao_speed < 0
+#if !HAS_ACCEL
+                           && (ao_sample_alt >= AO_MAX_BARO_HEIGHT || ao_error_h_sq_avg < 100)
+#endif
+                               )
+                       {
+#if HAS_IGNITE
+                               /* ignite the drogue charge */
+                               ao_ignite(ao_igniter_drogue);
+#endif
+
+#if HAS_TELEMETRY
+                               /* slow down the telemetry system */
+                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER);
+
+                               /* Turn the RDF beacon back on */
+                               ao_rdf_set(1);
+#endif
+
+                               /* and enter drogue state */
+                               ao_flight_state = ao_flight_drogue;
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       }
+#if HAS_ACCEL
+                       else {
+                       check_re_boost:
+                               ao_coast_avg_accel = ao_coast_avg_accel - (ao_coast_avg_accel >> 6) + (ao_accel >> 6);
+                               if (ao_coast_avg_accel > AO_MSS_TO_ACCEL(20)) {
+                                       ao_boost_tick = ao_sample_tick;
+                                       ao_flight_state = ao_flight_boost;
+                                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                               }
+                       }
+#endif
+
+                       break;
+               case ao_flight_drogue:
+
+                       /* drogue to main deploy:
+                        *
+                        * barometer: reach main deploy altitude
+                        *
+                        * Would like to use the accelerometer for this test, but
+                        * the orientation of the flight computer is unknown after
+                        * drogue deploy, so we ignore it. Could also detect
+                        * high descent rate using the pressure sensor to
+                        * recognize drogue deploy failure and eject the main
+                        * at that point. Perhaps also use the drogue sense lines
+                        * to notice continutity?
+                        */
+                       if (ao_height <= ao_config.main_deploy)
+                       {
+#if HAS_IGNITE
+                               ao_ignite(ao_igniter_main);
+#endif
+
+                               /*
+                                * Start recording min/max height
+                                * to figure out when the rocket has landed
+                                */
+
+                               /* initialize interval values */
+                               ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
+
+                               ao_interval_min_height = ao_interval_max_height = ao_avg_height;
+
+                               ao_flight_state = ao_flight_main;
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       }
+                       break;
+
+                       /* fall through... */
+               case ao_flight_main:
+
+                       /* main to land:
+                        *
+                        * barometer: altitude stable
+                        */
+
+                       if (ao_avg_height < ao_interval_min_height)
+                               ao_interval_min_height = ao_avg_height;
+                       if (ao_avg_height > ao_interval_max_height)
+                               ao_interval_max_height = ao_avg_height;
+
+                       if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) {
+                               if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4))
+                               {
+                                       ao_flight_state = ao_flight_landed;
+
+                                       /* turn off the ADC capture */
+                                       ao_timer_set_adc_interval(0);
+
+                                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                               }
+                               ao_interval_min_height = ao_interval_max_height = ao_avg_height;
+                               ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
+                       }
+                       break;
+#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;
+               }
+       }
+}
+
+#if HAS_FLIGHT_DEBUG
+static inline int int_part(int16_t i)  { return i >> 4; }
+static inline int frac_part(int16_t i) { return ((i & 0xf) * 100 + 8) / 16; }
+
+static void
+ao_flight_dump(void)
+{
+#if HAS_ACCEL
+       int16_t accel;
+
+       accel = ((ao_config.accel_plus_g - ao_sample_accel) * ao_accel_scale) >> 16;
+#endif
+
+       printf ("sample:\n");
+       printf ("  tick        %d\n", ao_sample_tick);
+       printf ("  raw pres    %d\n", ao_sample_pres);
+#if HAS_ACCEL
+       printf ("  raw accel   %d\n", ao_sample_accel);
+#endif
+       printf ("  ground pres %d\n", ao_ground_pres);
+       printf ("  ground alt  %d\n", ao_ground_height);
+#if HAS_ACCEL
+       printf ("  raw accel   %d\n", ao_sample_accel);
+       printf ("  groundaccel %d\n", ao_ground_accel);
+       printf ("  accel_2g    %d\n", ao_accel_2g);
+#endif
+
+       printf ("  alt         %d\n", ao_sample_alt);
+       printf ("  height      %d\n", ao_sample_height);
+#if HAS_ACCEL
+       printf ("  accel       %d.%02d\n", int_part(accel), frac_part(accel));
+#endif
+
+
+       printf ("kalman:\n");
+       printf ("  height      %d\n", ao_height);
+       printf ("  speed       %d.%02d\n", int_part(ao_speed), frac_part(ao_speed));
+       printf ("  accel       %d.%02d\n", int_part(ao_accel), frac_part(ao_accel));
+       printf ("  max_height  %d\n", ao_max_height);
+       printf ("  avg_height  %d\n", ao_avg_height);
+       printf ("  error_h     %d\n", ao_error_h);
+       printf ("  error_avg   %d\n", ao_error_h_sq_avg);
+}
+
+static void
+ao_gyro_test(void)
+{
+       ao_flight_state = ao_flight_test;
+       ao_getchar();
+       ao_flight_state = ao_flight_idle;
+}
+
+uint8_t ao_orient_test;
+
+static void
+ao_orient_test_select(void)
+{
+       ao_orient_test = !ao_orient_test;
+}
+
+__code struct ao_cmds ao_flight_cmds[] = {
+       { ao_flight_dump,       "F\0Dump flight status" },
+       { ao_gyro_test,         "G\0Test gyro code" },
+       { ao_orient_test_select,"O\0Test orientation code" },
+       { 0, NULL },
+};
+#endif
+
+static __xdata struct ao_task  flight_task;
+
+void
+ao_flight_init(void)
+{
+       ao_flight_state = ao_flight_startup;
+#if HAS_FLIGHT_DEBUG
+       ao_cmd_register(&ao_flight_cmds[0]);
+#endif
+       ao_add_task(&flight_task, ao_flight, "flight");
+}
diff --git a/src/kernel/ao_flight.h b/src/kernel/ao_flight.h
new file mode 100644 (file)
index 0000000..01d21c1
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_FLIGHT_H_
+#define _AO_FLIGHT_H_
+
+
+/*
+ * ao_flight.c
+ */
+
+enum ao_flight_state {
+       ao_flight_startup = 0,
+       ao_flight_idle = 1,
+       ao_flight_pad = 2,
+       ao_flight_boost = 3,
+       ao_flight_fast = 4,
+       ao_flight_coast = 5,
+       ao_flight_drogue = 6,
+       ao_flight_main = 7,
+       ao_flight_landed = 8,
+       ao_flight_invalid = 9,
+       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 || HAS_MMA655X
+#define HAS_SENSOR_ERRORS      1
+#endif
+
+#if HAS_SENSOR_ERRORS
+extern __xdata uint8_t                 ao_sensor_errors;
+#endif
+
+extern __pdata uint16_t                        ao_launch_time;
+extern __pdata uint8_t                 ao_flight_force_idle;
+
+/* Flight thread */
+void
+ao_flight(void);
+
+/* Initialize flight thread */
+void
+ao_flight_init(void);
+
+/*
+ * ao_flight_nano.c
+ */
+
+void
+ao_flight_nano_init(void);
+
+#endif /* _AO_FLIGHT_H_ */
diff --git a/src/kernel/ao_flight_nano.c b/src/kernel/ao_flight_nano.c
new file mode 100644 (file)
index 0000000..406d81a
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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"
+
+/* Main flight thread. */
+
+__pdata enum ao_flight_state   ao_flight_state;        /* current flight state */
+__pdata uint16_t               ao_launch_tick;         /* time of launch detect */
+
+/*
+ * track min/max data over a long interval to detect
+ * resting
+ */
+__pdata uint16_t               ao_interval_end;
+__pdata alt_t                  ao_interval_min_height;
+__pdata alt_t                  ao_interval_max_height;
+
+__pdata uint8_t                        ao_flight_force_idle;
+
+/* Landing is detected by getting constant readings from both pressure and accelerometer
+ * for a fairly long time (AO_INTERVAL_TICKS)
+ */
+#define AO_INTERVAL_TICKS      AO_SEC_TO_TICKS(5)
+
+static void
+ao_flight_nano(void)
+{
+       ao_sample_init();
+       ao_flight_state = ao_flight_startup;
+
+       for (;;) {
+               /*
+                * Process ADC samples, just looping
+                * until the sensors are calibrated.
+                */
+               if (!ao_sample())
+                       continue;
+
+               switch (ao_flight_state) {
+               case ao_flight_startup:
+                       if (ao_flight_force_idle) {
+                               /* Set idle mode */
+                               ao_flight_state = ao_flight_idle;
+                       } else {
+                               ao_flight_state = ao_flight_pad;
+                               /* Disable packet mode in pad state */
+                               ao_packet_slave_stop();
+
+                               /* Turn on telemetry system */
+                               ao_rdf_set(1);
+                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_PAD);
+                       }
+                       /* signal successful initialization by turning off the LED */
+                       ao_led_off(AO_LED_RED);
+
+                       /* wakeup threads due to state change */
+                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       break;
+               case ao_flight_pad:
+                       if (ao_height> AO_M_TO_HEIGHT(20)) {
+                               ao_flight_state = ao_flight_drogue;
+                               ao_launch_tick = ao_sample_tick;
+
+                               /* start logging data */
+                               ao_log_start();
+
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       }
+                       break;
+               case ao_flight_drogue:
+                       /* drogue/main to land:
+                        *
+                        * barometer: altitude stable
+                        */
+
+                       if (ao_height < ao_interval_min_height)
+                               ao_interval_min_height = ao_height;
+                       if (ao_height > ao_interval_max_height)
+                               ao_interval_max_height = ao_height;
+
+                       if ((int16_t) (ao_sample_tick - ao_interval_end) >= 0) {
+                               if (ao_interval_max_height - ao_interval_min_height < AO_M_TO_HEIGHT(5))
+                               {
+                                       ao_flight_state = ao_flight_landed;
+
+                                       /* turn off the ADC capture */
+                                       ao_timer_set_adc_interval(0);
+                                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                               }
+                               ao_interval_min_height = ao_interval_max_height = ao_height;
+                               ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
+                       }
+                       break;
+               }
+       }
+}
+
+static __xdata struct ao_task  flight_task;
+
+void
+ao_flight_nano_init(void)
+{
+       ao_flight_state = ao_flight_startup;
+       ao_add_task(&flight_task, ao_flight_nano, "flight");
+}
diff --git a/src/kernel/ao_freq.c b/src/kernel/ao_freq.c
new file mode 100644 (file)
index 0000000..12496f6
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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>
+
+/*
+ * The provided 'calibration' value is
+ * that needed to tune the radio to precisely 434550kHz.
+ * Use that to 'walk' to the target frequency by following
+ * a 'bresenham' line from 434550kHz to the target
+ * frequency, and updating the radio setting along the way
+ */
+
+int32_t ao_freq_to_set(int32_t freq, int32_t cal) __reentrant
+{
+       static __pdata int32_t  set;
+       static __pdata uint8_t  neg;
+       static __pdata int32_t  error;
+
+       set = 0;
+       neg = 0;
+       error = -434550 / 2;
+
+       if ((freq -= 434550) < 0) {
+               neg = 1;
+               freq = -freq;
+       }
+       for (;;) {
+               if (error > 0) {
+                       error -= 434550;
+                       set++;
+               } else {
+                       error += cal;
+                       if (--freq < 0)
+                               break;
+               }
+       }
+       if (neg)
+               set = -set;
+       return cal + set;
+}
diff --git a/src/kernel/ao_gps_print.c b/src/kernel/ao_gps_print.c
new file mode 100644 (file)
index 0000000..47c945d
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#ifndef AO_GPS_TEST
+#include "ao.h"
+#endif
+#include "ao_telem.h"
+
+void
+ao_gps_print(__xdata struct ao_gps_orig *gps_data) __reentrant
+{
+       char    state;
+
+       if (gps_data->flags & AO_GPS_VALID)
+               state = AO_TELEM_GPS_STATE_LOCKED;
+       else if (gps_data->flags & AO_GPS_RUNNING)
+               state = AO_TELEM_GPS_STATE_UNLOCKED;
+       else
+               state = AO_TELEM_GPS_STATE_ERROR;
+       printf(AO_TELEM_GPS_STATE " %c "
+              AO_TELEM_GPS_NUM_SAT " %d ",
+              state,
+              (gps_data->flags & AO_GPS_NUM_SAT_MASK) >> AO_GPS_NUM_SAT_SHIFT);
+       if (!(gps_data->flags & AO_GPS_VALID))
+               return;
+       printf(AO_TELEM_GPS_LATITUDE " %ld "
+              AO_TELEM_GPS_LONGITUDE " %ld "
+              AO_TELEM_GPS_ALTITUDE " %d ",
+              (long) gps_data->latitude,
+              (long) gps_data->longitude,
+              gps_data->altitude);
+
+       if (gps_data->flags & AO_GPS_DATE_VALID)
+               printf(AO_TELEM_GPS_YEAR " %d "
+                      AO_TELEM_GPS_MONTH " %d "
+                      AO_TELEM_GPS_DAY " %d ",
+                      gps_data->year,
+                      gps_data->month,
+                      gps_data->day);
+
+       printf(AO_TELEM_GPS_HOUR " %d "
+              AO_TELEM_GPS_MINUTE " %d "
+              AO_TELEM_GPS_SECOND " %d ",
+              gps_data->hour,
+              gps_data->minute,
+              gps_data->second);
+
+       printf(AO_TELEM_GPS_HDOP " %d ",
+              gps_data->hdop * 2);
+
+       if (gps_data->flags & AO_GPS_COURSE_VALID) {
+               printf(AO_TELEM_GPS_HERROR " %d "
+                      AO_TELEM_GPS_VERROR " %d "
+                      AO_TELEM_GPS_VERTICAL_SPEED " %d "
+                      AO_TELEM_GPS_HORIZONTAL_SPEED " %d "
+                      AO_TELEM_GPS_COURSE " %d ",
+                      gps_data->h_error,
+                      gps_data->v_error,
+                      gps_data->climb_rate,
+                      gps_data->ground_speed,
+                      (int) gps_data->course * 2);
+       }
+}
+
+void
+ao_gps_tracking_print(__xdata struct ao_gps_tracking_orig *gps_tracking_data) __reentrant
+{
+       uint8_t c, n, v;
+       __xdata struct ao_gps_sat_orig  *sat;
+
+       n = gps_tracking_data->channels;
+       if (n == 0)
+               return;
+
+       sat = gps_tracking_data->sats;
+       v = 0;
+       for (c = 0; c < n; c++) {
+               if (sat->svid)
+                       v++;
+               sat++;
+       }
+
+       printf (AO_TELEM_SAT_NUM " %d ",
+               v);
+
+       sat = gps_tracking_data->sats;
+       v = 0;
+       for (c = 0; c < n; c++) {
+               if (sat->svid) {
+                       printf (AO_TELEM_SAT_SVID "%d %d "
+                               AO_TELEM_SAT_C_N_0 "%d %d ",
+                               v, sat->svid,
+                               v, sat->c_n_1);
+                       v++;
+               }
+               sat++;
+       }
+}
diff --git a/src/kernel/ao_gps_report.c b/src/kernel/ao_gps_report.c
new file mode 100644 (file)
index 0000000..07201ac
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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"
+
+void
+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 (;;) {
+               while ((new = ao_gps_new) == 0)
+                       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_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_TRACKING) {
+                       uint8_t c, n;
+
+                       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;
+
+void
+ao_gps_report_init(void)
+{
+       ao_add_task(&ao_gps_report_task, ao_gps_report, "gps_report");
+}
diff --git a/src/kernel/ao_gps_report_mega.c b/src/kernel/ao_gps_report_mega.c
new file mode 100644 (file)
index 0000000..cb0c0fd
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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"
+
+#ifndef GPS_SPARSE_LOG
+#define GPS_SPARSE_LOG 0
+#endif
+
+#if GPS_SPARSE_LOG
+static int32_t prev_lat, prev_lon, int16_t prev_alt;
+static uint8_t has_prev, unmoving;
+
+#define GPS_SPARSE_UNMOVING_REPORTS    10
+#define GPS_SPARSE_UNMOVING_GROUND     10
+#define GPS_SPARSE_UNMOVING_AIR                10
+
+static uint8_t
+ao_gps_sparse_should_log(int32_t lat, int32_t lon, int16_t alt)
+{
+       uint8_t ret = 1;
+
+       if (has_prev && ao_log_running) {
+               uint32_t        h = ao_distance(prev_lat, prev_lon, lat, lon);
+               uint16_t        v = alt > prev_alt ? (alt - prev_alt) : (prev_alt - alt);
+
+               if (h < GPS_SPARSE_UNMOVING_GROUND && v < GPS_SPARSE_UNMOVING_AIR) {
+                       if (unmoving < GPS_SPARSE_UNMOVING_REPORTS)
+                               ++unmoving;
+               } else
+                       unmoving = 0;
+       } else
+               unmoving = 0;
+
+       prev_lat = lat;
+       prev_lon = lon;
+       prev_alt = alt;
+       has_prev = 1;
+       return unmoving >= GPS_SPARSE_UNMOVING_REPORTS;
+}
+#endif
+
+void
+ao_gps_report_mega(void)
+{
+       static __xdata struct ao_log_mega               gps_log;
+       static __xdata struct ao_telemetry_location     gps_data;
+       static __xdata struct ao_telemetry_satellite    gps_tracking_data;
+       uint8_t new;
+       uint8_t c, n, i;
+
+       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 GPS_SPARSE_LOG
+               /* Don't log data if GPS has a fix and hasn't moved for a while */
+               if ((gps_data.flags & AO_GPS_VALID) &&
+                   !ao_gps_sparse_should_log(gps_data.latitude, gps_data.longitude, gps_data.altitude))
+                       continue;
+#endif
+               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.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++;
+                                       if (i >= 12)
+                                               break;
+                               }
+                       gps_log.u.gps_sat.channels = i;
+                       ao_log_mega(&gps_log);
+               }
+       }
+}
+
+__xdata struct ao_task ao_gps_report_mega_task;
+
+void
+ao_gps_report_mega_init(void)
+{
+       ao_add_task(&ao_gps_report_mega_task,
+                   ao_gps_report_mega,
+                   "gps_report");
+}
diff --git a/src/kernel/ao_gps_report_metrum.c b/src/kernel/ao_gps_report_metrum.c
new file mode 100644 (file)
index 0000000..696a833
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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;
+       uint8_t svid;
+       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/kernel/ao_gps_show.c b/src/kernel/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);
+}
diff --git a/src/kernel/ao_host.h b/src/kernel/ao_host.h
new file mode 100644 (file)
index 0000000..6eb752c
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define AO_ADC_RING    64
+#define ao_adc_ring_next(n)    (((n) + 1) & (AO_ADC_RING - 1))
+#define ao_adc_ring_prev(n)    (((n) - 1) & (AO_ADC_RING - 1))
+
+/*
+ * One set of samples read from the A/D converter
+ */
+struct ao_adc {
+       uint16_t        tick;           /* tick when the sample was read */
+       int16_t         accel;          /* accelerometer */
+       int16_t         pres;           /* pressure sensor */
+       int16_t         temp;           /* temperature sensor */
+       int16_t         v_batt;         /* battery voltage */
+       int16_t         sense_d;        /* drogue continuity sense */
+       int16_t         sense_m;        /* main continuity sense */
+};
+
+#define __pdata
+#define __data
+#define __xdata
+#define __code
+#define __reentrant
+
+#define DATA_TO_XDATA(a)       (a)
+#define PDATA_TO_XDATA(a)      (a)
+#define CODE_TO_XDATA(a)       (a)
+
+enum ao_flight_state {
+       ao_flight_startup = 0,
+       ao_flight_idle = 1,
+       ao_flight_pad = 2,
+       ao_flight_boost = 3,
+       ao_flight_fast = 4,
+       ao_flight_coast = 5,
+       ao_flight_drogue = 6,
+       ao_flight_main = 7,
+       ao_flight_landed = 8,
+       ao_flight_invalid = 9
+};
+
+struct ao_adc ao_adc_ring[AO_ADC_RING];
+uint8_t ao_adc_head;
+
+#define ao_led_on(l)
+#define ao_led_off(l)
+#define ao_timer_set_adc_interval(i)
+#define ao_wakeup(wchan) ao_dump_state(wchan)
+#define ao_cmd_register(c)
+#define ao_usb_disable()
+#define ao_telemetry_set_interval(x)
+#define ao_delay(x)
+
+enum ao_igniter {
+       ao_igniter_drogue = 0,
+       ao_igniter_main = 1
+};
+
+void
+ao_ignite(enum ao_igniter igniter)
+{
+       printf ("ignite %s\n", igniter == ao_igniter_drogue ? "drogue" : "main");
+}
+
+struct ao_task {
+       int dummy;
+};
+
+#define ao_add_task(t,f,n)
+
+#define ao_log_start()
+#define ao_log_stop()
+
+#define AO_MS_TO_TICKS(ms)     ((ms) / 10)
+#define AO_SEC_TO_TICKS(s)     ((s) * 100)
+
+#define AO_FLIGHT_TEST
+
+struct ao_adc ao_adc_static;
+
+FILE *emulator_in;
+
+void
+ao_dump_state(void *wchan);
+
+void
+ao_sleep(void *wchan);
+
+const char const * const ao_state_names[] = {
+       "startup", "idle", "pad", "boost", "fast",
+       "coast", "drogue", "main", "landed", "invalid"
+};
+
+struct ao_cmds {
+       void            (*func)(void);
+       const char      *help;
+};
+
+
+struct ao_config {
+       uint16_t        main_deploy;
+       int16_t         accel_zero_g;
+};
+
+#define ao_config_get()
+
+struct ao_config ao_config = { 250, 16000 };
+
+#define ao_xmemcpy(d,s,c) memcpy(d,s,c)
+#define ao_xmemset(d,v,c) memset(d,v,c)
+#define ao_xmemcmp(d,s,c) memcmp(d,s,c)
diff --git a/src/kernel/ao_ignite.c b/src/kernel/ao_ignite.c
new file mode 100644 (file)
index 0000000..823d003
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * 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_data.h>
+#if AO_PYRO_NUM
+#include <ao_pyro.h>
+#endif
+
+#if HAS_IGNITE
+__xdata struct ao_ignition ao_ignition[2];
+
+void
+ao_ignite(enum ao_igniter igniter)
+{
+       ao_arch_block_interrupts();
+       ao_ignition[igniter].request = 1;
+       ao_wakeup(&ao_ignition);
+       ao_arch_release_interrupts();
+}
+
+#ifndef AO_SENSE_DROGUE
+#define AO_SENSE_DROGUE(p)     ((p)->adc.sense_d)
+#define AO_SENSE_MAIN(p)       ((p)->adc.sense_m)
+#endif
+
+enum ao_igniter_status
+ao_igniter_status(enum ao_igniter igniter)
+{
+       __xdata struct ao_data packet;
+       __pdata int16_t value;
+       __pdata uint8_t request, firing, fired;
+
+       ao_arch_critical(
+               ao_data_get(&packet);
+               request = ao_ignition[igniter].request;
+               fired = ao_ignition[igniter].fired;
+               firing = ao_ignition[igniter].firing;
+               );
+       if (firing || (request && !fired))
+               return ao_igniter_active;
+
+       value = (AO_IGNITER_CLOSED>>1);
+       switch (igniter) {
+       case ao_igniter_drogue:
+               value = AO_SENSE_DROGUE(&packet);
+               break;
+       case ao_igniter_main:
+               value = AO_SENSE_MAIN(&packet);
+               break;
+       }
+       if (value < AO_IGNITER_OPEN)
+               return ao_igniter_open;
+       else if (value > AO_IGNITER_CLOSED)
+               return ao_igniter_ready;
+       else
+               return ao_igniter_unknown;
+}
+
+#ifndef AO_IGNITER_SET_DROGUE
+#define AO_IGNITER_SET_DROGUE(v)       AO_IGNITER_DROGUE = (v)
+#define AO_IGNITER_SET_MAIN(v)         AO_IGNITER_MAIN = (v)
+#endif
+
+#ifndef AO_IGNITER_FIRE_TIME
+#define AO_IGNITER_FIRE_TIME           AO_MS_TO_TICKS(50)
+#endif
+
+#ifndef AO_IGNITER_CHARGE_TIME
+#define AO_IGNITER_CHARGE_TIME         AO_MS_TO_TICKS(2000)
+#endif
+
+void
+ao_igniter_fire(enum ao_igniter igniter)
+{
+       ao_ignition[igniter].firing = 1;
+       switch(ao_config.ignite_mode) {
+       case AO_IGNITE_MODE_DUAL:
+               switch (igniter) {
+               case ao_igniter_drogue:
+                       AO_IGNITER_SET_DROGUE(1);
+                       ao_delay(AO_IGNITER_FIRE_TIME);
+                       AO_IGNITER_SET_DROGUE(0);
+                       break;
+               case ao_igniter_main:
+                       AO_IGNITER_SET_MAIN(1);
+                       ao_delay(AO_IGNITER_FIRE_TIME);
+                       AO_IGNITER_SET_MAIN(0);
+                       break;
+               }
+               break;
+       case AO_IGNITE_MODE_APOGEE:
+               switch (igniter) {
+               case ao_igniter_drogue:
+                       AO_IGNITER_SET_DROGUE(1);
+                       ao_delay(AO_IGNITER_FIRE_TIME);
+                       AO_IGNITER_SET_DROGUE(0);
+                       ao_delay(AO_IGNITER_CHARGE_TIME);
+                       AO_IGNITER_SET_MAIN(1);
+                       ao_delay(AO_IGNITER_FIRE_TIME);
+                       AO_IGNITER_SET_MAIN(0);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case AO_IGNITE_MODE_MAIN:
+               switch (igniter) {
+               case ao_igniter_main:
+                       AO_IGNITER_SET_DROGUE(1);
+                       ao_delay(AO_IGNITER_FIRE_TIME);
+                       AO_IGNITER_SET_DROGUE(0);
+                       ao_delay(AO_IGNITER_CHARGE_TIME);
+                       AO_IGNITER_SET_MAIN(1);
+                       ao_delay(AO_IGNITER_FIRE_TIME);
+                       AO_IGNITER_SET_MAIN(0);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       }
+       ao_ignition[igniter].firing = 0;
+}
+
+void
+ao_igniter(void)
+{
+       __xdata enum ao_igniter igniter;
+
+       ao_config_get();
+       for (;;) {
+               ao_sleep(&ao_ignition);
+               for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) {
+                       if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) {
+                               if (igniter == ao_igniter_drogue && ao_config.apogee_delay)
+                                       ao_delay(AO_SEC_TO_TICKS(ao_config.apogee_delay));
+
+                               ao_igniter_fire(igniter);
+                               ao_delay(AO_IGNITER_CHARGE_TIME);
+                               ao_ignition[igniter].fired = 1;
+                       }
+               }
+       }
+}
+
+#endif
+
+void
+ao_ignite_manual(void)
+{
+       ao_cmd_white();
+       if (!ao_match_word("DoIt"))
+               return;
+       ao_cmd_white();
+#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;
+}
+
+__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,
+              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[] = {
+       { ao_ignite_manual,     "i <key> {main|drogue}\0Fire igniter. <key> is doit with D&I" },
+       { ao_ignite_test,       "t\0Test igniter" },
+       { 0,    NULL },
+};
+
+#if HAS_IGNITE
+__xdata struct ao_task ao_igniter_task;
+
+void
+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_add_task(&ao_igniter_task, ao_igniter, "igniter");
+#endif
+       ao_cmd_register(&ao_ignite_cmds[0]);
+}
diff --git a/src/kernel/ao_int64.c b/src/kernel/ao_int64.c
new file mode 100644 (file)
index 0000000..ca75751
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * 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>
+
+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++;
+       }
+       ao_umul64_64_16(r, a, b);
+       if (negative)
+               ao_neg64(r, r);
+}
diff --git a/src/kernel/ao_int64.h b/src/kernel/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_ */
diff --git a/src/kernel/ao_kalman.c b/src/kernel/ao_kalman.c
new file mode 100644 (file)
index 0000000..9aea1f1
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * 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_FLIGHT_TEST
+#include "ao.h"
+#include "ao_flight.h"
+#endif
+
+#include "ao_sample.h"
+#include "ao_kalman.h"
+
+
+static __pdata int32_t         ao_k_height;
+static __pdata int32_t         ao_k_speed;
+static __pdata int32_t         ao_k_accel;
+
+#define AO_K_STEP_100          to_fix16(0.01)
+#define AO_K_STEP_2_2_100      to_fix16(0.00005)
+
+#define AO_K_STEP_10           to_fix16(0.1)
+#define AO_K_STEP_2_2_10       to_fix16(0.005)
+
+#define AO_K_STEP_1            to_fix16(1)
+#define AO_K_STEP_2_2_1                to_fix16(0.5)
+
+__pdata int16_t                        ao_height;
+__pdata int16_t                        ao_speed;
+__pdata int16_t                        ao_accel;
+__xdata int16_t                        ao_max_height;
+static __pdata int32_t         ao_avg_height_scaled;
+__xdata int16_t                        ao_avg_height;
+
+__pdata int16_t                        ao_error_h;
+__pdata int16_t                        ao_error_h_sq_avg;
+
+#if HAS_ACCEL
+__pdata int16_t                        ao_error_a;
+#endif
+
+static void
+ao_kalman_predict(void)
+{
+#ifdef AO_FLIGHT_TEST
+       if (ao_sample_tick - ao_sample_prev_tick > 50) {
+               ao_k_height += ((int32_t) ao_speed * AO_K_STEP_1 +
+                               (int32_t) ao_accel * AO_K_STEP_2_2_1) >> 4;
+               ao_k_speed += (int32_t) ao_accel * AO_K_STEP_1;
+
+               return;
+       }
+       if (ao_sample_tick - ao_sample_prev_tick > 5) {
+               ao_k_height += ((int32_t) ao_speed * AO_K_STEP_10 +
+                               (int32_t) ao_accel * AO_K_STEP_2_2_10) >> 4;
+               ao_k_speed += (int32_t) ao_accel * AO_K_STEP_10;
+
+               return;
+       }
+       if (ao_flight_debug) {
+               printf ("predict speed %g + (%g * %g) = %g\n",
+                       ao_k_speed / (65536.0 * 16.0), ao_accel / 16.0, AO_K_STEP_100 / 65536.0,
+                       (ao_k_speed + (int32_t) ao_accel * AO_K_STEP_100) / (65536.0 * 16.0));
+       }
+#endif
+       ao_k_height += ((int32_t) ao_speed * AO_K_STEP_100 +
+                       (int32_t) ao_accel * AO_K_STEP_2_2_100) >> 4;
+       ao_k_speed += (int32_t) ao_accel * AO_K_STEP_100;
+}
+
+static void
+ao_kalman_err_height(void)
+{
+       int16_t e;
+       int16_t height_distrust;
+#if HAS_ACCEL
+       int16_t speed_distrust;
+#endif
+
+       ao_error_h = ao_sample_height - (int16_t) (ao_k_height >> 16);
+
+       e = ao_error_h;
+       if (e < 0)
+               e = -e;
+       if (e > 127)
+               e = 127;
+#if HAS_ACCEL
+       ao_error_h_sq_avg -= ao_error_h_sq_avg >> 2;
+       ao_error_h_sq_avg += (e * e) >> 2;
+#else
+       ao_error_h_sq_avg -= ao_error_h_sq_avg >> 4;
+       ao_error_h_sq_avg += (e * e) >> 4;
+#endif
+
+       if (ao_flight_state >= ao_flight_drogue)
+               return;
+       height_distrust = ao_sample_alt - AO_MAX_BARO_HEIGHT;
+#if HAS_ACCEL
+       /* speed is stored * 16, but we need to ramp between 200 and 328, so
+        * we want to multiply by 2. The result is a shift by 3.
+        */
+       speed_distrust = (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) >> (4 - 1);
+       if (speed_distrust <= 0)
+               speed_distrust = 0;
+       else if (speed_distrust > height_distrust)
+               height_distrust = speed_distrust;
+#endif
+       if (height_distrust > 0) {
+#ifdef AO_FLIGHT_TEST
+               int     old_ao_error_h = ao_error_h;
+#endif
+               if (height_distrust > 0x100)
+                       height_distrust = 0x100;
+               ao_error_h = (int16_t) (((int32_t) ao_error_h * (0x100 - height_distrust)) >> 8);
+#ifdef AO_FLIGHT_TEST
+               if (ao_flight_debug) {
+                       printf("over height %g over speed %g distrust: %g height: error %d -> %d\n",
+                              (double) (ao_sample_alt - AO_MAX_BARO_HEIGHT),
+                              (ao_speed - AO_MS_TO_SPEED(AO_MAX_BARO_SPEED)) / 16.0,
+                              height_distrust / 256.0,
+                              old_ao_error_h, ao_error_h);
+               }
+#endif
+       }
+}
+
+static void
+ao_kalman_correct_baro(void)
+{
+       ao_kalman_err_height();
+#ifdef AO_FLIGHT_TEST
+       if (ao_sample_tick - ao_sample_prev_tick > 50) {
+               ao_k_height += (int32_t) AO_BARO_K0_1 * ao_error_h;
+               ao_k_speed  += (int32_t) AO_BARO_K1_1 * ao_error_h;
+               ao_k_accel  += (int32_t) AO_BARO_K2_1 * ao_error_h;
+               return;
+       }
+       if (ao_sample_tick - ao_sample_prev_tick > 5) {
+               ao_k_height += (int32_t) AO_BARO_K0_10 * ao_error_h;
+               ao_k_speed  += (int32_t) AO_BARO_K1_10 * ao_error_h;
+               ao_k_accel  += (int32_t) AO_BARO_K2_10 * ao_error_h;
+               return;
+       }
+#endif
+       ao_k_height += (int32_t) AO_BARO_K0_100 * ao_error_h;
+       ao_k_speed  += (int32_t) AO_BARO_K1_100 * ao_error_h;
+       ao_k_accel  += (int32_t) AO_BARO_K2_100 * ao_error_h;
+}
+
+#if HAS_ACCEL
+
+static void
+ao_kalman_err_accel(void)
+{
+       int32_t accel;
+
+       accel = (ao_config.accel_plus_g - ao_sample_accel) * ao_accel_scale;
+
+       /* Can't use ao_accel here as it is the pre-prediction value still */
+       ao_error_a = (accel - ao_k_accel) >> 16;
+}
+
+#ifndef FORCE_ACCEL
+static void
+ao_kalman_correct_both(void)
+{
+       ao_kalman_err_height();
+       ao_kalman_err_accel();
+
+#ifdef AO_FLIGHT_TEST
+       if (ao_sample_tick - ao_sample_prev_tick > 50) {
+               if (ao_flight_debug) {
+                       printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
+                               ao_k_speed / (65536.0 * 16.0),
+                               (double) ao_error_h, AO_BOTH_K10_1 / 65536.0,
+                               (double) ao_error_a, AO_BOTH_K11_1 / 65536.0,
+                               (ao_k_speed +
+                                (int32_t) AO_BOTH_K10_1 * ao_error_h +
+                                (int32_t) AO_BOTH_K11_1 * ao_error_a) / (65536.0 * 16.0));
+               }
+               ao_k_height +=
+                       (int32_t) AO_BOTH_K00_1 * ao_error_h +
+                       (int32_t) AO_BOTH_K01_1 * ao_error_a;
+               ao_k_speed +=
+                       (int32_t) AO_BOTH_K10_1 * ao_error_h +
+                       (int32_t) AO_BOTH_K11_1 * ao_error_a;
+               ao_k_accel +=
+                       (int32_t) AO_BOTH_K20_1 * ao_error_h +
+                       (int32_t) AO_BOTH_K21_1 * ao_error_a;
+               return;
+       }
+       if (ao_sample_tick - ao_sample_prev_tick > 5) {
+               if (ao_flight_debug) {
+                       printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
+                               ao_k_speed / (65536.0 * 16.0),
+                               (double) ao_error_h, AO_BOTH_K10_10 / 65536.0,
+                               (double) ao_error_a, AO_BOTH_K11_10 / 65536.0,
+                               (ao_k_speed +
+                                (int32_t) AO_BOTH_K10_10 * ao_error_h +
+                                (int32_t) AO_BOTH_K11_10 * ao_error_a) / (65536.0 * 16.0));
+               }
+               ao_k_height +=
+                       (int32_t) AO_BOTH_K00_10 * ao_error_h +
+                       (int32_t) AO_BOTH_K01_10 * ao_error_a;
+               ao_k_speed +=
+                       (int32_t) AO_BOTH_K10_10 * ao_error_h +
+                       (int32_t) AO_BOTH_K11_10 * ao_error_a;
+               ao_k_accel +=
+                       (int32_t) AO_BOTH_K20_10 * ao_error_h +
+                       (int32_t) AO_BOTH_K21_10 * ao_error_a;
+               return;
+       }
+       if (ao_flight_debug) {
+               printf ("correct speed %g + (%g * %g) + (%g * %g) = %g\n",
+                       ao_k_speed / (65536.0 * 16.0),
+                       (double) ao_error_h, AO_BOTH_K10_100 / 65536.0,
+                       (double) ao_error_a, AO_BOTH_K11_100 / 65536.0,
+                       (ao_k_speed +
+                        (int32_t) AO_BOTH_K10_100 * ao_error_h +
+                        (int32_t) AO_BOTH_K11_100 * ao_error_a) / (65536.0 * 16.0));
+       }
+#endif
+       ao_k_height +=
+               (int32_t) AO_BOTH_K00_100 * ao_error_h +
+               (int32_t) AO_BOTH_K01_100 * ao_error_a;
+       ao_k_speed +=
+               (int32_t) AO_BOTH_K10_100 * ao_error_h +
+               (int32_t) AO_BOTH_K11_100 * ao_error_a;
+       ao_k_accel +=
+               (int32_t) AO_BOTH_K20_100 * ao_error_h +
+               (int32_t) AO_BOTH_K21_100 * ao_error_a;
+}
+
+#else
+
+static void
+ao_kalman_correct_accel(void)
+{
+       ao_kalman_err_accel();
+
+       if (ao_sample_tick - ao_sample_prev_tick > 5) {
+               ao_k_height +=(int32_t) AO_ACCEL_K0_10 * ao_error_a;
+               ao_k_speed  += (int32_t) AO_ACCEL_K1_10 * ao_error_a;
+               ao_k_accel  += (int32_t) AO_ACCEL_K2_10 * ao_error_a;
+               return;
+       }
+       ao_k_height += (int32_t) AO_ACCEL_K0_100 * ao_error_a;
+       ao_k_speed  += (int32_t) AO_ACCEL_K1_100 * ao_error_a;
+       ao_k_accel  += (int32_t) AO_ACCEL_K2_100 * ao_error_a;
+}
+
+#endif /* else FORCE_ACCEL */
+#endif /* HAS_ACCEL */
+
+void
+ao_kalman(void)
+{
+       ao_kalman_predict();
+#if HAS_ACCEL
+       if (ao_flight_state <= ao_flight_coast) {
+#ifdef FORCE_ACCEL
+               ao_kalman_correct_accel();
+#else
+               ao_kalman_correct_both();
+#endif
+       } else
+#endif
+               ao_kalman_correct_baro();
+       ao_height = from_fix(ao_k_height);
+       ao_speed = from_fix(ao_k_speed);
+       ao_accel = from_fix(ao_k_accel);
+       if (ao_height > ao_max_height)
+               ao_max_height = ao_height;
+       ao_avg_height_scaled = ao_avg_height_scaled - ao_avg_height + ao_sample_height;
+#ifdef AO_FLIGHT_TEST
+       if (ao_sample_tick - ao_sample_prev_tick > 50)
+               ao_avg_height = (ao_avg_height_scaled + 1) >> 1;
+       else if (ao_sample_tick - ao_sample_prev_tick > 5)
+               ao_avg_height = (ao_avg_height_scaled + 7) >> 4;
+       else 
+#endif
+               ao_avg_height = (ao_avg_height_scaled + 63) >> 7;
+}
diff --git a/src/kernel/ao_lcd.h b/src/kernel/ao_lcd.h
new file mode 100644 (file)
index 0000000..f7e1391
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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_LCD_H_
+#define _AO_LCD_H_
+
+/* ao_lcd.c */
+  
+void
+ao_lcd_putchar(uint8_t d);
+
+void
+ao_lcd_putstring(char *string);
+
+void
+ao_lcd_contrast_set(uint8_t contrast);
+
+void
+ao_lcd_clear(void);
+
+void
+ao_lcd_cursor_on(void);
+
+void
+ao_lcd_cursor_off(void);
+
+#define AO_LCD_ADDR(row,col)   ((row << 6) | (col))
+
+void
+ao_lcd_goto(uint8_t addr);
+
+void
+ao_lcd_start(void);
+
+void
+ao_lcd_init(void);
+
+/* ao_lcd_port.c */
+
+void
+ao_lcd_port_put_nibble(uint8_t rs, uint8_t d);
+
+void
+ao_lcd_port_init(void);
+
+#endif /* _AO_LCD_H_ */
diff --git a/src/kernel/ao_led.h b/src/kernel/ao_led.h
new file mode 100644 (file)
index 0000000..d9a0914
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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_LED_H_
+#define _AO_LED_H_
+
+/*
+ * ao_led.c
+ */
+
+#define AO_LED_NONE    0
+
+#ifndef AO_LED_TYPE
+#define AO_LED_TYPE uint8_t
+#endif
+
+/* Turn on the specified LEDs */
+void
+ao_led_on(AO_LED_TYPE colors);
+
+/* Turn off the specified LEDs */
+void
+ao_led_off(AO_LED_TYPE colors);
+
+/* Set all of the LEDs to the specified state */
+void
+ao_led_set(AO_LED_TYPE colors);
+
+/* Set all LEDs in 'mask' to the specified state */
+void
+ao_led_set_mask(uint8_t colors, uint8_t mask);
+
+/* Toggle the specified LEDs */
+void
+ao_led_toggle(AO_LED_TYPE colors);
+
+/* Turn on the specified LEDs for the indicated interval */
+void
+ao_led_for(AO_LED_TYPE colors, uint16_t ticks) __reentrant;
+
+/* Initialize the LEDs */
+void
+ao_led_init(AO_LED_TYPE enable);
+
+#endif /* _AO_LED_H_ */
diff --git a/src/kernel/ao_list.h b/src/kernel/ao_list.h
new file mode 100644 (file)
index 0000000..8a6fa4d
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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_LIST_H_
+#define _AO_LIST_H_
+
+#include <stddef.h>
+
+struct ao_list {
+       struct ao_list  *next, *prev;
+};
+
+static inline void
+ao_list_init(struct ao_list *list)
+{
+       list->next = list->prev = list;
+}
+
+static inline void
+__ao_list_add(struct ao_list *list, struct ao_list *prev, struct ao_list *next)
+{
+       next->prev = list;
+       list->next = next;
+       list->prev = prev;
+       prev->next = list;
+}
+
+/**
+ * Insert a new element after the given list head. The new element does not
+ * need to be initialised as empty list.
+ * The list changes from:
+ *      head → some element → ...
+ * to
+ *      head → new element → older element → ...
+ *
+ * Example:
+ * struct foo *newfoo = malloc(...);
+ * ao_list_add(&newfoo->entry, &bar->list_of_foos);
+ *
+ * @param entry The new element to prepend to the list.
+ * @param head The existing list.
+ */
+static inline void
+ao_list_insert(struct ao_list *entry, struct ao_list *head)
+{
+    __ao_list_add(entry, head, head->next);
+}
+
+/**
+ * Append a new element to the end of the list given with this list head.
+ *
+ * The list changes from:
+ *      head → some element → ... → lastelement
+ * to
+ *      head → some element → ... → lastelement → new element
+ *
+ * Example:
+ * struct foo *newfoo = malloc(...);
+ * ao_list_append(&newfoo->entry, &bar->list_of_foos);
+ *
+ * @param entry The new element to prepend to the list.
+ * @param head The existing list.
+ */
+static inline void
+ao_list_append(struct ao_list *entry, struct ao_list *head)
+{
+    __ao_list_add(entry, head->prev, head);
+}
+
+static inline void
+__ao_list_del(struct ao_list *prev, struct ao_list *next)
+{
+    next->prev = prev;
+    prev->next = next;
+}
+
+/**
+ * Remove the element from the list it is in. Using this function will reset
+ * the pointers to/from this element so it is removed from the list. It does
+ * NOT free the element itself or manipulate it otherwise.
+ *
+ * Using ao_list_del on a pure list head (like in the example at the top of
+ * this file) will NOT remove the first element from
+ * the list but rather reset the list as empty list.
+ *
+ * Example:
+ * ao_list_del(&foo->entry);
+ *
+ * @param entry The element to remove.
+ */
+static inline void
+ao_list_del(struct ao_list *entry)
+{
+    __ao_list_del(entry->prev, entry->next);
+    ao_list_init(entry);
+}
+
+/**
+ * Check if the list is empty.
+ *
+ * Example:
+ * ao_list_is_empty(&bar->list_of_foos);
+ *
+ * @return True if the list contains one or more elements or False otherwise.
+ */
+static inline uint8_t
+ao_list_is_empty(struct ao_list *head)
+{
+    return head->next == head;
+}
+
+/**
+ * Returns a pointer to the container of this list element.
+ *
+ * Example:
+ * struct foo* f;
+ * f = container_of(&foo->entry, struct foo, entry);
+ * assert(f == foo);
+ *
+ * @param ptr Pointer to the struct ao_list.
+ * @param type Data type of the list element.
+ * @param member Member name of the struct ao_list field in the list element.
+ * @return A pointer to the data struct containing the list head.
+ */
+#define ao_container_of(ptr, type, member) \
+       ((type *)((char *)(ptr) - offsetof(type, member)))
+
+/**
+ * Alias of ao_container_of
+ */
+#define ao_list_entry(ptr, type, member) \
+    ao_container_of(ptr, type, member)
+
+/**
+ * Retrieve the first list entry for the given list pointer.
+ *
+ * Example:
+ * struct foo *first;
+ * first = ao_list_first_entry(&bar->list_of_foos, struct foo, list_of_foos);
+ *
+ * @param ptr The list head
+ * @param type Data type of the list element to retrieve
+ * @param member Member name of the struct ao_list field in the list element.
+ * @return A pointer to the first list element.
+ */
+#define ao_list_first_entry(ptr, type, member) \
+    ao_list_entry((ptr)->next, type, member)
+
+/**
+ * Retrieve the last list entry for the given listpointer.
+ *
+ * Example:
+ * struct foo *first;
+ * first = ao_list_last_entry(&bar->list_of_foos, struct foo, list_of_foos);
+ *
+ * @param ptr The list head
+ * @param type Data type of the list element to retrieve
+ * @param member Member name of the struct ao_list field in the list element.
+ * @return A pointer to the last list element.
+ */
+#define ao_list_last_entry(ptr, type, member) \
+    ao_list_entry((ptr)->prev, type, member)
+
+/**
+ * Loop through the list given by head and set pos to struct in the list.
+ *
+ * Example:
+ * struct foo *iterator;
+ * ao_list_for_each_entry(iterator, &bar->list_of_foos, entry) {
+ *      [modify iterator]
+ * }
+ *
+ * This macro is not safe for node deletion. Use ao_list_for_each_entry_safe
+ * instead.
+ *
+ * @param pos Iterator variable of the type of the list elements.
+ * @param head List head
+ * @param member Member name of the struct ao_list in the list elements.
+ *
+ */
+#define ao_list_for_each_entry(pos, head, type, member)                        \
+    for (pos = ao_container_of((head)->next, type, member);            \
+        &pos->member != (head);                                        \
+        pos = ao_container_of(pos->member.next, type, member))
+
+/**
+ * Loop through the list, keeping a backup pointer to the element. This
+ * macro allows for the deletion of a list element while looping through the
+ * list.
+ *
+ * See ao_list_for_each_entry for more details.
+ */
+#define ao_list_for_each_entry_safe(pos, tmp, head, type, member)              \
+       for ((pos = ao_container_of((head)->next, type, member)),               \
+            (tmp = ao_container_of(pos->member.next, type, member));           \
+            &pos->member != (head);                                            \
+            (pos = tmp), (tmp = ao_container_of(pos->member.next, type, member)))
+
+#endif /* _AO_LIST_H_ */
diff --git a/src/kernel/ao_log.c b/src/kernel/ao_log.c
new file mode 100644 (file)
index 0000000..91617d9
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * 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>
+#include <ao_config.h>
+#if HAS_TRACKER
+#include <ao_tracker.h>
+#endif
+
+__xdata uint8_t        ao_log_mutex;
+__pdata uint32_t ao_log_current_pos;
+__pdata uint32_t ao_log_end_pos;
+__pdata uint32_t ao_log_start_pos;
+__xdata uint8_t        ao_log_running;
+__pdata enum ao_flight_state ao_log_state;
+__xdata uint16_t ao_flight_number;
+
+void
+ao_log_flush(void)
+{
+       ao_storage_flush();
+}
+
+/*
+ * When erasing a flight log, make sure the config block
+ * has an up-to-date version of the current flight number
+ */
+
+struct ao_log_erase {
+       uint8_t mark;
+       uint16_t flight;
+};
+
+static __xdata struct ao_log_erase erase;
+
+#ifndef LOG_MAX_ERASE
+#define LOG_MAX_ERASE  16
+#endif
+
+#ifndef LOG_ERASE_MARK
+#if USE_EEPROM_CONFIG
+#error "Must define LOG_ERASE_MARK with USE_EEPROM_CONFIG"
+#endif
+#define LOG_ERASE_MARK 0x00
+#endif
+
+static uint32_t
+ao_log_erase_pos(uint8_t i)
+{
+       return i * sizeof (struct ao_log_erase) + AO_CONFIG_MAX_SIZE;
+}
+
+void
+ao_log_write_erase(uint8_t pos)
+{
+       erase.mark = LOG_ERASE_MARK;
+       erase.flight = ao_flight_number;
+       ao_config_write(ao_log_erase_pos(pos),  &erase, sizeof (erase));
+
+#if USE_EEPROM_CONFIG
+       if (pos == 0) {
+               uint8_t i;
+               for (i = 1; i < LOG_MAX_ERASE; i++) {
+                       erase.mark = ~LOG_ERASE_MARK;
+                       erase.flight = 0;
+                       ao_config_write(ao_log_erase_pos(i), &erase, sizeof (erase));
+               }
+       }
+#endif
+
+       ao_config_flush();
+}
+
+static void
+ao_log_read_erase(uint8_t pos)
+{
+       ao_config_read(ao_log_erase_pos(pos), &erase, sizeof (erase));
+}
+
+
+static void
+ao_log_erase_mark(void)
+{
+       uint8_t                         i;
+
+       for (i = 0; i < LOG_MAX_ERASE; i++) {
+               ao_log_read_erase(i);
+               if (erase.mark == LOG_ERASE_MARK && erase.flight == ao_flight_number)
+                       return;
+               if (erase.mark != LOG_ERASE_MARK) {
+                       ao_log_write_erase(i);
+                       return;
+               }
+       }
+       ao_config_put();
+}
+
+static uint8_t
+ao_log_slots()
+{
+       return (uint8_t) (ao_storage_log_max / ao_config.flight_log_max);
+}
+
+uint32_t
+ao_log_pos(uint8_t slot)
+{
+       return ((slot) * ao_config.flight_log_max);
+}
+
+static uint16_t
+ao_log_max_flight(void)
+{
+       uint8_t         log_slot;
+       uint8_t         log_slots;
+       uint16_t        log_flight;
+       uint16_t        max_flight = 0;
+
+       /* Scan the log space looking for the biggest flight number */
+       log_slots = ao_log_slots();
+       for (log_slot = 0; log_slot < log_slots; log_slot++) {
+               log_flight = ao_log_flight(log_slot);
+               if (!log_flight)
+                       continue;
+               if (max_flight == 0 || (int16_t) (log_flight - max_flight) > 0)
+                       max_flight = log_flight;
+       }
+       return max_flight;
+}
+
+void
+ao_log_scan(void) __reentrant
+{
+       uint8_t         log_slot;
+       uint8_t         log_slots;
+       uint8_t         log_want;
+
+       ao_config_get();
+
+       ao_flight_number = ao_log_max_flight();
+       if (ao_flight_number)
+               if (++ao_flight_number == 0)
+                       ao_flight_number = 1;
+
+       /* Now look through the log of flight numbers from erase operations and
+        * see if the last one is bigger than what we found above
+        */
+       for (log_slot = LOG_MAX_ERASE; log_slot-- > 0;) {
+               ao_log_read_erase(log_slot);
+               if (erase.mark == LOG_ERASE_MARK) {
+                       if (ao_flight_number == 0 ||
+                           (int16_t) (erase.flight - ao_flight_number) > 0)
+                               ao_flight_number = erase.flight;
+                       break;
+               }
+       }
+       if (ao_flight_number == 0)
+               ao_flight_number = 1;
+
+       /* With a flight number in hand, find a place to write a new log,
+        * use the target flight number to index the available log slots so
+        * that we write logs to each spot about the same number of times.
+        */
+
+       /* Find a log slot for the next flight, if available */
+       ao_log_current_pos = ao_log_end_pos = 0;
+       log_slots = ao_log_slots();
+       log_want = (ao_flight_number - 1) % log_slots;
+       log_slot = log_want;
+       do {
+               if (ao_log_flight(log_slot) == 0) {
+                       ao_log_current_pos = ao_log_pos(log_slot);
+                       ao_log_end_pos = ao_log_current_pos + ao_config.flight_log_max;
+                       break;
+               }
+               if (++log_slot >= log_slots)
+                       log_slot = 0;
+       } while (log_slot != log_want);
+
+       ao_wakeup(&ao_flight_number);
+}
+
+void
+ao_log_start(void)
+{
+       /* start logging */
+       ao_log_running = 1;
+       ao_wakeup(&ao_log_running);
+}
+
+void
+ao_log_stop(void)
+{
+       ao_log_running = 0;
+       ao_log_flush();
+}
+
+uint8_t
+ao_log_present(void)
+{
+       return ao_log_max_flight() != 0;
+}
+
+uint8_t
+ao_log_full(void)
+{
+       return ao_log_current_pos == ao_log_end_pos;
+}
+
+#ifndef LOG_ADC
+#define LOG_ADC        HAS_ADC
+#endif
+
+#if LOG_ADC
+static __xdata struct ao_task ao_log_task;
+#endif
+
+void
+ao_log_list(void) __reentrant
+{
+       uint8_t slot;
+       uint8_t slots;
+       uint16_t flight;
+
+       slots = ao_log_slots();
+       for (slot = 0; slot < slots; slot++)
+       {
+               flight = ao_log_flight(slot);
+               if (flight)
+                       printf ("flight %d start %x end %x\n",
+                               flight,
+                               (uint16_t) (ao_log_pos(slot) >> 8),
+                               (uint16_t) (ao_log_pos(slot+1) >> 8));
+       }
+       printf ("done\n");
+}
+
+void
+ao_log_delete(void) __reentrant
+{
+       uint8_t slot;
+       uint8_t slots;
+       uint32_t log_current_pos, log_end_pos;
+
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+
+       slots = ao_log_slots();
+       /* Look for the flight log matching the requested flight */
+       if (ao_cmd_lex_i) {
+               for (slot = 0; slot < slots; slot++) {
+                       if (ao_log_flight(slot) == ao_cmd_lex_i) {
+#if HAS_TRACKER
+                               ao_tracker_erase_start(ao_cmd_lex_i);
+#endif
+                               ao_log_erase_mark();
+                               log_current_pos = ao_log_pos(slot);
+                               log_end_pos = log_current_pos + ao_config.flight_log_max;
+                               while (log_current_pos < log_end_pos) {
+                                       uint8_t i;
+                                       static __xdata uint8_t b;
+
+                                       /*
+                                        * Check to see if we've reached the end of
+                                        * the used memory to avoid re-erasing the same
+                                        * memory over and over again
+                                        */
+                                       for (i = 0; i < 16; i++) {
+                                               if (ao_storage_read(log_current_pos + i, &b, 1))
+                                                       if (b != 0xff)
+                                                               break;
+                                       }
+                                       if (i == 16)
+                                               break;
+                                       ao_storage_erase(log_current_pos);
+                                       log_current_pos += ao_storage_block;
+                               }
+#if HAS_TRACKER
+                               ao_tracker_erase_end();
+#endif
+                               puts("Erased");
+                               return;
+                       }
+               }
+       }
+       printf("No such flight: %d\n", ao_cmd_lex_i);
+}
+
+__code struct ao_cmds ao_log_cmds[] = {
+       { ao_log_list,  "l\0List logs" },
+       { ao_log_delete,        "d <flight-number>\0Delete flight" },
+       { 0,    NULL },
+};
+
+void
+ao_log_init(void)
+{
+       ao_log_running = 0;
+
+       /* For now, just log the flight starting at the begining of eeprom */
+       ao_log_state = ao_flight_invalid;
+
+       ao_cmd_register(&ao_log_cmds[0]);
+
+#ifndef HAS_ADC
+#error Define HAS_ADC for ao_log.c
+#endif
+#if LOG_ADC
+       /* Create a task to log events to eeprom */
+       ao_add_task(&ao_log_task, ao_log, "log");
+#endif
+}
diff --git a/src/kernel/ao_log.h b/src/kernel/ao_log.h
new file mode 100644 (file)
index 0000000..33cda3e
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * 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_H_
+#define _AO_LOG_H_
+
+#include <ao_flight.h>
+
+/*
+ * ao_log.c
+ */
+
+/* We record flight numbers in the first record of
+ * the log. Tasks may wait for this to be initialized
+ * by sleeping on this variable.
+ */
+extern __xdata uint16_t ao_flight_number;
+extern __xdata uint8_t ao_log_mutex;
+extern __pdata uint32_t ao_log_current_pos;
+extern __pdata uint32_t ao_log_end_pos;
+extern __pdata uint32_t ao_log_start_pos;
+extern __xdata uint8_t ao_log_running;
+extern __pdata enum ao_flight_state ao_log_state;
+
+/* required functions from the underlying log system */
+
+#define AO_LOG_FORMAT_UNKNOWN          0       /* unknown; altosui will have to guess */
+#define AO_LOG_FORMAT_FULL             1       /* 8 byte typed log records */
+#define AO_LOG_FORMAT_TINY             2       /* two byte state/baro records */
+#define AO_LOG_FORMAT_TELEMETRY                3       /* 32 byte ao_telemetry records */
+#define AO_LOG_FORMAT_TELESCIENCE      4       /* 32 byte typed telescience records */
+#define AO_LOG_FORMAT_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_TELEGPS          9       /* 32 byte telegps records */
+#define AO_LOG_FORMAT_NONE             127     /* No log at all */
+
+extern __code uint8_t ao_log_format;
+
+/* Return the flight number from the given log slot, 0 if none */
+uint16_t
+ao_log_flight(uint8_t slot);
+
+/* Flush the log */
+void
+ao_log_flush(void);
+
+/* Logging thread main routine */
+void
+ao_log(void);
+
+/* functions provided in ao_log.c */
+
+/* Figure out the current flight number */
+void
+ao_log_scan(void) __reentrant;
+
+/* Return the position of the start of the given log slot */
+uint32_t
+ao_log_pos(uint8_t slot);
+
+/* Start logging to eeprom */
+void
+ao_log_start(void);
+
+/* Stop logging */
+void
+ao_log_stop(void);
+
+/* Initialize the logging system */
+void
+ao_log_init(void);
+
+/* Write out the current flight number to the erase log */
+void
+ao_log_write_erase(uint8_t pos);
+
+/* Returns true if there are any logs stored in eeprom */
+uint8_t
+ao_log_present(void);
+
+/* Returns true if there is no more storage space available */
+uint8_t
+ao_log_full(void);
+
+/*
+ * ao_log_big.c
+ */
+
+/*
+ * The data log is recorded in the eeprom as a sequence
+ * of data packets.
+ *
+ * Each packet starts with a 4-byte header that has the
+ * packet type, the packet checksum and the tick count. Then
+ * they all contain 2 16 bit values which hold packet-specific
+ * data.
+ *
+ * For each flight, the first packet
+ * is FLIGHT packet, indicating the serial number of the
+ * device and a unique number marking the number of flights
+ * recorded by this device.
+ *
+ * During flight, data from the accelerometer and barometer
+ * are recorded in SENSOR packets, using the raw 16-bit values
+ * read from the A/D converter.
+ *
+ * Also during flight, but at a lower rate, the deployment
+ * sensors are recorded in DEPLOY packets. The goal here is to
+ * detect failure in the deployment circuits.
+ *
+ * STATE packets hold state transitions as the flight computer
+ * transitions through different stages of the flight.
+ */
+#define AO_LOG_FLIGHT          'F'
+#define AO_LOG_SENSOR          'A'
+#define AO_LOG_TEMP_VOLT       'T'
+#define AO_LOG_DEPLOY          'D'
+#define AO_LOG_STATE           'S'
+#define AO_LOG_GPS_TIME                'G'
+#define AO_LOG_GPS_LAT         'N'
+#define AO_LOG_GPS_LON         'W'
+#define AO_LOG_GPS_ALT         'H'
+#define AO_LOG_GPS_SAT         'V'
+#define AO_LOG_GPS_DATE                'Y'
+#define AO_LOG_GPS_POS         'P'
+
+#define AO_LOG_POS_NONE                (~0UL)
+
+struct ao_log_record {
+       char                    type;                           /* 0 */
+       uint8_t                 csum;                           /* 1 */
+       uint16_t                tick;                           /* 2 */
+       union {
+               struct {
+                       int16_t         ground_accel;           /* 4 */
+                       uint16_t        flight;                 /* 6 */
+               } flight;
+               struct {
+                       int16_t         accel;                  /* 4 */
+                       int16_t         pres;                   /* 6 */
+               } sensor;
+               struct {
+                       int16_t         temp;
+                       int16_t         v_batt;
+               } temp_volt;
+               struct {
+                       int16_t         drogue;
+                       int16_t         main;
+               } deploy;
+               struct {
+                       uint16_t        state;
+                       uint16_t        reason;
+               } state;
+               struct {
+                       uint8_t         hour;
+                       uint8_t         minute;
+                       uint8_t         second;
+                       uint8_t         flags;
+               } gps_time;
+               int32_t         gps_latitude;
+               int32_t         gps_longitude;
+               struct {
+                       int16_t         altitude;
+                       uint16_t        unused;
+               } gps_altitude;
+               struct {
+                       uint16_t        svid;
+                       uint8_t         unused;
+                       uint8_t         c_n;
+               } gps_sat;
+               struct {
+                       uint8_t         year;
+                       uint8_t         month;
+                       uint8_t         day;
+                       uint8_t         extra;
+               } gps_date;
+               struct {
+                       uint16_t        d0;
+                       uint16_t        d1;
+               } anon;
+       } u;
+};
+
+struct ao_log_mega {
+       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 */
+                       int16_t         ground_accel_along;     /* 12 */
+                       int16_t         ground_accel_across;    /* 14 */
+                       int16_t         ground_accel_through;   /* 16 */
+                       int16_t         ground_roll;            /* 18 */
+                       int16_t         ground_pitch;           /* 20 */
+                       int16_t         ground_yaw;             /* 22 */
+               } flight;                                       /* 24 */
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;
+                       uint16_t        reason;
+               } state;
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint32_t        pres;           /* 4 */
+                       uint32_t        temp;           /* 8 */
+                       int16_t         accel_x;        /* 12 */
+                       int16_t         accel_y;        /* 14 */
+                       int16_t         accel_z;        /* 16 */
+                       int16_t         gyro_x;         /* 18 */
+                       int16_t         gyro_y;         /* 20 */
+                       int16_t         gyro_z;         /* 22 */
+                       int16_t         mag_x;          /* 24 */
+                       int16_t         mag_y;          /* 26 */
+                       int16_t         mag_z;          /* 28 */
+                       int16_t         accel;          /* 30 */
+               } sensor;       /* 32 */
+               /* AO_LOG_TEMP_VOLT */
+               struct {
+                       int16_t         v_batt;         /* 4 */
+                       int16_t         v_pbatt;        /* 6 */
+                       int16_t         n_sense;        /* 8 */
+                       int16_t         sense[10];      /* 10 */
+                       uint16_t        pyro;           /* 30 */
+               } volt;                                 /* 32 */
+               /* AO_LOG_GPS_TIME */
+               struct {
+                       int32_t         latitude;       /* 4 */
+                       int32_t         longitude;      /* 8 */
+                       int16_t         altitude;       /* 12 */
+                       uint8_t         hour;           /* 14 */
+                       uint8_t         minute;         /* 15 */
+                       uint8_t         second;         /* 16 */
+                       uint8_t         flags;          /* 17 */
+                       uint8_t         year;           /* 18 */
+                       uint8_t         month;          /* 19 */
+                       uint8_t         day;            /* 20 */
+                       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 */
+                       struct {
+                               uint8_t svid;
+                               uint8_t c_n;
+                       } sats[12];                     /* 6 */
+               } gps_sat;                              /* 30 */
+       } 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)
+
+struct ao_log_gps {
+       char                    type;                   /* 0 */
+       uint8_t                 csum;                   /* 1 */
+       uint16_t                tick;                   /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;                 /* 4 */
+                       int16_t         start_altitude;         /* 6 */
+                       int32_t         start_latitude;         /* 8 */
+                       int32_t         start_longitude;        /* 12 */
+               } flight;                                       /* 16 */
+               /* AO_LOG_GPS_TIME */
+               struct {
+                       int32_t         latitude;       /* 4 */
+                       int32_t         longitude;      /* 8 */
+                       int16_t         altitude;       /* 12 */
+                       uint8_t         hour;           /* 14 */
+                       uint8_t         minute;         /* 15 */
+                       uint8_t         second;         /* 16 */
+                       uint8_t         flags;          /* 17 */
+                       uint8_t         year;           /* 18 */
+                       uint8_t         month;          /* 19 */
+                       uint8_t         day;            /* 20 */
+                       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 */
+                       uint8_t         state;          /* 30 */
+               } gps;  /* 31 */
+               /* AO_LOG_GPS_SAT */
+               struct {
+                       uint16_t        channels;       /* 4 */
+                       struct {
+                               uint8_t svid;
+                               uint8_t c_n;
+                       } sats[12];                     /* 6 */
+               } gps_sat;                              /* 30 */
+       } u;
+};
+
+/* Write a record to the eeprom log */
+uint8_t
+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;
+
+uint8_t
+ao_log_gps(__xdata struct ao_log_gps *log) __reentrant;
+
+void
+ao_log_flush(void);
+
+void
+ao_gps_report_metrum_init(void);
+
+#endif /* _AO_LOG_H_ */
diff --git a/src/kernel/ao_log_big.c b/src/kernel/ao_log_big.c
new file mode 100644 (file)
index 0000000..8f57bf7
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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"
+
+static __xdata struct ao_log_record log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_FULL;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (struct ao_log_record); i++)
+               sum += *b++;
+       return -sum;
+}
+
+uint8_t
+ao_log_data(__xdata struct ao_log_record *log) __reentrant
+{
+       uint8_t wrote = 0;
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((__xdata uint8_t *) log);
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+                       ao_log_stop();
+               if (ao_log_running) {
+                       wrote = 1;
+                       ao_storage_write(ao_log_current_pos,
+                                        log,
+                                        sizeof (struct ao_log_record));
+                       ao_log_current_pos += sizeof (struct ao_log_record);
+               }
+       } ao_mutex_put(&ao_log_mutex);
+       return wrote;
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+       if (ao_log_csum((uint8_t *) &log) != 0)
+               return 0;
+       return 1;
+}
+
+static __data uint8_t  ao_log_data_pos;
+
+/* a hack to make sure that ao_log_records fill the eeprom block in even units */
+typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_record))] ;
+
+#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;
+
+       ao_storage_setup();
+
+       ao_log_scan();
+
+       while (!ao_log_running)
+               ao_sleep(&ao_log_running);
+
+       log.type = AO_LOG_FLIGHT;
+       log.tick = ao_sample_tick;
+#if HAS_ACCEL
+       log.u.flight.ground_accel = ao_ground_accel;
+#endif
+       log.u.flight.flight = ao_flight_number;
+       ao_log_data(&log);
+
+       /* Write the whole contents of the ring to the log
+        * when starting up.
+        */
+       ao_log_data_pos = ao_data_ring_next(ao_sample_data);
+       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_sample_data) {
+                       log.tick = ao_data_ring[ao_log_data_pos].tick;
+                       if ((int16_t) (log.tick - next_sensor) >= 0) {
+                               log.type = AO_LOG_SENSOR;
+                               log.u.sensor.accel = ao_data_ring[ao_log_data_pos].adc.accel;
+                               log.u.sensor.pres = ao_data_ring[ao_log_data_pos].adc.pres;
+                               ao_log_data(&log);
+                               if (ao_log_state <= ao_flight_coast)
+                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
+                               else
+                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
+                       }
+                       if ((int16_t) (log.tick - next_other) >= 0) {
+                               log.type = AO_LOG_TEMP_VOLT;
+                               log.u.temp_volt.temp = ao_data_ring[ao_log_data_pos].adc.temp;
+                               log.u.temp_volt.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
+                               ao_log_data(&log);
+                               log.type = AO_LOG_DEPLOY;
+                               log.u.deploy.drogue = ao_data_ring[ao_log_data_pos].adc.sense_d;
+                               log.u.deploy.main = ao_data_ring[ao_log_data_pos].adc.sense_m;
+                               ao_log_data(&log);
+                               next_other = log.tick + AO_OTHER_INTERVAL;
+                       }
+                       ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+               }
+               /* Write state change to EEPROM */
+               if (ao_flight_state != ao_log_state) {
+                       ao_log_state = ao_flight_state;
+                       log.type = AO_LOG_STATE;
+                       log.tick = ao_sample_tick;
+                       log.u.state.state = ao_log_state;
+                       log.u.state.reason = 0;
+                       ao_log_data(&log);
+
+                       if (ao_log_state == ao_flight_landed)
+                               ao_log_stop();
+               }
+
+               /* Wait for a while */
+               ao_delay(AO_MS_TO_TICKS(100));
+
+               /* Stop logging when told to */
+               while (!ao_log_running)
+                       ao_sleep(&ao_log_running);
+       }
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+       if (!ao_storage_read(ao_log_pos(slot),
+                            &log,
+                            sizeof (struct ao_log_record)))
+               return 0;
+
+       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+               return log.u.flight.flight;
+       return 0;
+}
diff --git a/src/kernel/ao_log_gps.c b/src/kernel/ao_log_gps.c
new file mode 100644 (file)
index 0000000..3b728c2
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_log_gps.h>
+#include <ao_data.h>
+#include <ao_flight.h>
+#include <ao_distance.h>
+#include <ao_tracker.h>
+
+static __xdata struct ao_log_gps log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEGPS;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (struct ao_log_gps); i++)
+               sum += *b++;
+       return -sum;
+}
+
+uint8_t
+ao_log_gps(__xdata struct ao_log_gps *log) __reentrant
+{
+       uint8_t wrote = 0;
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((__xdata uint8_t *) log);
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+                       ao_log_stop();
+               if (ao_log_running) {
+                       wrote = 1;
+                       ao_storage_write(ao_log_current_pos,
+                                        log,
+                                        sizeof (struct ao_log_gps));
+                       ao_log_current_pos += sizeof (struct ao_log_gps);
+               }
+       } ao_mutex_put(&ao_log_mutex);
+       return wrote;
+}
+
+void
+ao_log_gps_flight(void)
+{
+       log.type = AO_LOG_FLIGHT;
+       log.tick = ao_time();
+       log.u.flight.flight = ao_flight_number;
+       ao_log_gps(&log);
+}
+
+void
+ao_log_gps_data(uint16_t tick, struct ao_telemetry_location *gps_data)
+{
+       log.tick = tick;
+       log.type = AO_LOG_GPS_TIME;
+       log.u.gps.latitude = gps_data->latitude;
+       log.u.gps.longitude = gps_data->longitude;
+       log.u.gps.altitude = gps_data->altitude;
+
+       log.u.gps.hour = gps_data->hour;
+       log.u.gps.minute = gps_data->minute;
+       log.u.gps.second = gps_data->second;
+       log.u.gps.flags = gps_data->flags;
+       log.u.gps.year = gps_data->year;
+       log.u.gps.month = gps_data->month;
+       log.u.gps.day = gps_data->day;
+       log.u.gps.course = gps_data->course;
+       log.u.gps.ground_speed = gps_data->ground_speed;
+       log.u.gps.climb_rate = gps_data->climb_rate;
+       log.u.gps.pdop = gps_data->pdop;
+       log.u.gps.hdop = gps_data->hdop;
+       log.u.gps.vdop = gps_data->vdop;
+       log.u.gps.mode = gps_data->mode;
+       ao_log_gps(&log);
+}
+
+void
+ao_log_gps_tracking(uint16_t tick, struct ao_telemetry_satellite *gps_tracking_data)
+{
+       uint8_t c, n, i;
+
+       log.tick = tick;
+       log.type = AO_LOG_GPS_SAT;
+       i = 0;
+       n = gps_tracking_data->channels;
+       for (c = 0; c < n; c++)
+               if ((log.u.gps_sat.sats[i].svid = gps_tracking_data->sats[c].svid))
+               {
+                       log.u.gps_sat.sats[i].c_n = gps_tracking_data->sats[c].c_n_1;
+                       i++;
+                       if (i >= 12)
+                               break;
+               }
+       log.u.gps_sat.channels = i;
+       ao_log_gps(&log);
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+       if (ao_log_csum((uint8_t *) &log) != 0)
+               return 0;
+       return 1;
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+       if (!ao_storage_read(ao_log_pos(slot),
+                            &log,
+                            sizeof (struct ao_log_gps)))
+               return 0;
+
+       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+               return log.u.flight.flight;
+       return 0;
+}
diff --git a/src/kernel/ao_log_gps.h b/src/kernel/ao_log_gps.h
new file mode 100644 (file)
index 0000000..5851f4d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_telemetry.h"
+
+#ifndef _AO_LOG_GPS_H_
+#define _AO_LOG_GPS_H_
+
+uint8_t
+ao_log_gps_should_log(int32_t lat, int32_t lon, int16_t alt);
+
+void
+ao_log_gps_flight(void);
+
+void
+ao_log_gps_data(uint16_t tick, struct ao_telemetry_location *gps_data);
+
+#endif /* _AO_LOG_GPS_H_ */
diff --git a/src/kernel/ao_log_mega.c b/src/kernel/ao_log_mega.c
new file mode 100644 (file)
index 0000000..cb83be4
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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 struct ao_log_mega log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEMEGA;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (struct ao_log_mega); i++)
+               sum += *b++;
+       return -sum;
+}
+
+uint8_t
+ao_log_mega(__xdata struct ao_log_mega *log) __reentrant
+{
+       uint8_t wrote = 0;
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((__xdata uint8_t *) log);
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+                       ao_log_stop();
+               if (ao_log_running) {
+                       wrote = 1;
+                       ao_storage_write(ao_log_current_pos,
+                                        log,
+                                        sizeof (struct ao_log_mega));
+                       ao_log_current_pos += sizeof (struct ao_log_mega);
+               }
+       } ao_mutex_put(&ao_log_mutex);
+       return wrote;
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+       if (ao_log_csum((uint8_t *) &log) != 0)
+               return 0;
+       return 1;
+}
+
+#if HAS_FLIGHT
+static __data uint8_t  ao_log_data_pos;
+
+/* a hack to make sure that ao_log_megas fill the eeprom block in even units */
+typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_mega))] ;
+
+#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
+#if HAS_GYRO
+       log.u.flight.ground_accel_along = ao_ground_accel_along;
+       log.u.flight.ground_accel_across = ao_ground_accel_across;
+       log.u.flight.ground_accel_through = ao_ground_accel_through;
+       log.u.flight.ground_roll = ao_ground_roll;
+       log.u.flight.ground_pitch = ao_ground_pitch;
+       log.u.flight.ground_yaw = ao_ground_yaw;
+#endif
+       log.u.flight.ground_pres = ao_ground_pres;
+       log.u.flight.flight = ao_flight_number;
+       ao_log_mega(&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
+#if HAS_MPU6000
+                               log.u.sensor.accel_x = ao_data_ring[ao_log_data_pos].mpu6000.accel_x;
+                               log.u.sensor.accel_y = ao_data_ring[ao_log_data_pos].mpu6000.accel_y;
+                               log.u.sensor.accel_z = ao_data_ring[ao_log_data_pos].mpu6000.accel_z;
+                               log.u.sensor.gyro_x = ao_data_ring[ao_log_data_pos].mpu6000.gyro_x;
+                               log.u.sensor.gyro_y = ao_data_ring[ao_log_data_pos].mpu6000.gyro_y;
+                               log.u.sensor.gyro_z = ao_data_ring[ao_log_data_pos].mpu6000.gyro_z;
+#endif
+#if HAS_HMC5883
+                               log.u.sensor.mag_x = ao_data_ring[ao_log_data_pos].hmc5883.x;
+                               log.u.sensor.mag_y = ao_data_ring[ao_log_data_pos].hmc5883.y;
+                               log.u.sensor.mag_z = ao_data_ring[ao_log_data_pos].hmc5883.z;
+#endif
+                               log.u.sensor.accel = ao_data_accel(&ao_data_ring[ao_log_data_pos]);
+                               ao_log_mega(&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.v_pbatt = ao_data_ring[ao_log_data_pos].adc.v_pbatt;
+                               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;
+                       }
+                       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_mega(&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 /* HAS_FLIGHT */
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+       if (!ao_storage_read(ao_log_pos(slot),
+                            &log,
+                            sizeof (struct ao_log_mega)))
+               return 0;
+
+       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+               return log.u.flight.flight;
+       return 0;
+}
diff --git a/src/kernel/ao_log_metrum.c b/src/kernel/ao_log_metrum.c
new file mode 100644 (file)
index 0000000..08e7b8c
--- /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 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;
+
+       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
+#if HAS_ACCEL
+                               log.u.sensor.accel = ao_data_accel(&ao_data_ring[ao_log_data_pos]);
+#endif
+                               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/kernel/ao_log_micro.c b/src/kernel/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/kernel/ao_log_micro.h b/src/kernel/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/kernel/ao_log_mini.c b/src/kernel/ao_log_mini.c
new file mode 100644 (file)
index 0000000..0ca3ed0
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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 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;
+
+       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_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;
+}
diff --git a/src/kernel/ao_log_single.c b/src/kernel/ao_log_single.c
new file mode 100644 (file)
index 0000000..3f6235a
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+/*
+ * ao_log_single.c
+ *
+ * Stores a sequence of fixed-size (32 byte) chunks
+ * without splitting memory up into separate flights
+ */
+
+#include "ao.h"
+#include "ao_product.h"
+
+static __xdata struct ao_task ao_log_single_task;
+
+__xdata uint8_t        ao_log_running;
+__xdata uint8_t                ao_log_mutex;
+__pdata uint32_t       ao_log_start_pos;
+__pdata uint32_t       ao_log_end_pos;
+__pdata uint32_t       ao_log_current_pos;
+
+__xdata union ao_log_single ao_log_single_write_data;
+__xdata union ao_log_single ao_log_single_read_data;
+
+uint8_t
+ao_log_single_write(void)
+{
+       uint8_t wrote = 0;
+
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+                       ao_log_single_stop();
+               if (ao_log_running) {
+                       wrote = 1;
+                       ao_storage_write(ao_log_current_pos,
+                                        &ao_log_single_write_data,
+                                        AO_LOG_SINGLE_SIZE);
+                       ao_log_current_pos += AO_LOG_SINGLE_SIZE;
+               }
+       } ao_mutex_put(&ao_log_mutex);
+       return wrote;
+}
+
+static uint8_t
+ao_log_single_valid(void)
+{
+       __xdata uint8_t *d = ao_log_single_read_data.bytes;
+       uint8_t i;
+       for (i = 0; i < AO_LOG_SINGLE_SIZE; i++)
+               if (*d++ != 0xff)
+                       return 1;
+       return 0;
+}
+
+uint8_t
+ao_log_single_read(uint32_t pos)
+{
+       if (!ao_storage_read(pos, &ao_log_single_read_data, AO_LOG_SINGLE_SIZE))
+               return 0;
+       return ao_log_single_valid();
+}
+
+void
+ao_log_single_start(void)
+{
+       if (!ao_log_running) {
+               ao_log_running = 1;
+               ao_wakeup(&ao_log_running);
+       }
+}
+
+void
+ao_log_single_stop(void)
+{
+       if (ao_log_running) {
+               ao_log_running = 0;
+       }
+}
+
+void
+ao_log_single_restart(void)
+{
+       /* Find end of data */
+       ao_log_end_pos = ao_storage_config;
+       for (ao_log_current_pos = 0;
+            ao_log_current_pos < ao_storage_config;
+            ao_log_current_pos += ao_storage_block)
+       {
+               if (!ao_log_single_read(ao_log_current_pos))
+                       break;
+       }
+       if (ao_log_current_pos > 0) {
+               ao_log_current_pos -= ao_storage_block;
+               for (; ao_log_current_pos < ao_storage_config;
+                    ao_log_current_pos += sizeof (struct ao_log_telescience))
+               {
+                       if (!ao_log_single_read(ao_log_current_pos))
+                               break;
+               }
+       }
+}
+
+void
+ao_log_single_set(void)
+{
+       printf("Logging currently %s\n", ao_log_running ? "on" : "off");
+       ao_cmd_hex();
+       if (ao_cmd_status == ao_cmd_success) {
+               if (ao_cmd_lex_i) {
+                       printf("Logging from %ld to %ld\n", ao_log_current_pos, ao_log_end_pos);
+                       ao_log_single_start();
+               } else {
+                       printf ("Log stopped at %ld\n", ao_log_current_pos);
+                       ao_log_single_stop();
+               }
+       }
+       ao_cmd_status = ao_cmd_success;
+}
+
+void
+ao_log_single_delete(void)
+{
+       uint32_t        pos;
+
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       if (ao_cmd_lex_i != 1) {
+               ao_cmd_status = ao_cmd_syntax_error;
+               printf("No such flight: %d\n", ao_cmd_lex_i);
+               return;
+       }
+       ao_log_single_stop();
+       for (pos = 0; pos < ao_storage_config; pos += ao_storage_block) {
+               if (!ao_log_single_read(pos))
+                       break;
+               ao_storage_erase(pos);
+       }
+       ao_log_current_pos = ao_log_start_pos = 0;
+       if (pos == 0)
+               printf("No such flight: %d\n", ao_cmd_lex_i);
+       else
+               printf ("Erased\n");
+}
+
+uint8_t
+ao_log_full(void)
+{
+       return ao_log_current_pos >= ao_log_end_pos;
+}
+
+uint8_t
+ao_log_present(void)
+{
+       return ao_log_single_read(0);
+}
+
+static void
+ao_log_single_query(void)
+{
+       printf("Logging enabled: %d\n", ao_log_running);
+       printf("Log start: %ld\n", ao_log_start_pos);
+       printf("Log cur: %ld\n", ao_log_current_pos);
+       printf("Log end: %ld\n", ao_log_end_pos);
+       ao_log_single_extra_query();
+}
+
+const struct ao_cmds ao_log_single_cmds[] = {
+       { ao_log_single_set,    "L <0 off, 1 on>\0Set logging" },
+       { ao_log_single_list,   "l\0List stored logs" },
+       { ao_log_single_delete, "d 1\0Delete all stored logs" },
+       { ao_log_single_query, "q\0Query log status" },
+       { 0,    NULL },
+};
+
+void
+ao_log_single_init(void)
+{
+       ao_log_running = 0;
+
+       ao_cmd_register(&ao_log_single_cmds[0]);
+
+       ao_add_task(&ao_log_single_task, ao_log_single, "log");
+}
diff --git a/src/kernel/ao_log_telem.c b/src/kernel/ao_log_telem.c
new file mode 100644 (file)
index 0000000..095aca3
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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_flight.h>
+#include <ao_sample.h>
+
+__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;
+__xdata int16_t                                ao_max_height;  /* max of ao_height */
+__pdata int16_t                                sense_d, sense_m;
+__pdata uint8_t                                ao_igniter_present;
+
+static void
+ao_log_telem_track() {
+       if (ao_monitoring == sizeof (union ao_telemetry_all)) {
+               switch (ao_log_single_write_data.telemetry.generic.type) {
+               case AO_TELEMETRY_SENSOR_TELEMETRUM:
+               case AO_TELEMETRY_SENSOR_TELEMINI:
+                       /* fall through ... */
+               case AO_TELEMETRY_SENSOR_TELENANO:
+                       if (ao_log_single_write_data.telemetry.generic.type == AO_TELEMETRY_SENSOR_TELENANO) {
+                               ao_igniter_present = 0;
+                       } else {
+                               sense_d = ao_log_single_write_data.telemetry.sensor.sense_d;
+                               sense_m = ao_log_single_write_data.telemetry.sensor.sense_m;
+                               ao_igniter_present = 1;
+                       }
+                       if (ao_log_single_write_data.telemetry.sensor.height > ao_max_height) {
+                               ao_max_height = ao_log_single_write_data.telemetry.sensor.height;
+                       }
+                       if (ao_log_single_write_data.telemetry.sensor.state != ao_flight_state) {
+                               ao_flight_state = ao_log_single_write_data.telemetry.sensor.state;
+                               if (ao_flight_state == ao_flight_pad)
+                                       ao_max_height = 0;
+                               ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
+                       }
+               }
+       }
+}
+
+enum ao_igniter_status
+ao_igniter_status(enum ao_igniter igniter)
+{
+       int16_t value;
+
+       switch (igniter) {
+       case ao_igniter_drogue:
+               value = sense_d;
+               break;
+       case ao_igniter_main:
+               value = sense_m;
+               break;
+       default:
+               value = 0;
+               break;
+       }
+       if (value < AO_IGNITER_OPEN)
+               return ao_igniter_open;
+       else if (value > AO_IGNITER_CLOSED)
+               return ao_igniter_ready;
+       else
+               return ao_igniter_unknown;
+}
+
+void
+ao_log_single(void)
+{
+       ao_storage_setup();
+
+       /* This can take a while, so let the rest
+        * of the system finish booting before we start
+        */
+       ao_delay(AO_SEC_TO_TICKS(2));
+
+       ao_log_running = 1;
+       ao_log_single_restart();
+       ao_flight_state = ao_flight_startup;
+       ao_monitor_set(sizeof(struct ao_telemetry_generic));
+
+       for (;;) {
+               while (!ao_log_running)
+                       ao_sleep(&ao_log_running);
+
+               ao_log_monitor_pos = ao_monitor_head;
+               while (ao_log_running) {
+                       /* Write samples to EEPROM */
+                       while (ao_log_monitor_pos != ao_monitor_head) {
+                               ao_xmemcpy(&ao_log_single_write_data.telemetry,
+                                          &ao_monitor_ring[ao_log_monitor_pos],
+                                          AO_LOG_SINGLE_SIZE);
+                               ao_log_single_write();
+                               ao_log_monitor_pos = ao_monitor_ring_next(ao_log_monitor_pos);
+                               ao_log_telem_track();
+                       }
+                       /* Wait for more telemetry data to arrive */
+                       ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
+               }
+       }
+}
+
+void
+ao_log_single_list(void)
+{
+       if (ao_log_current_pos != 0)
+               printf("flight 1 start %x end %x\n",
+                      0,
+                      (uint16_t) ((ao_log_current_pos + 0xff) >> 8));
+       printf ("done\n");
+}
+
+void
+ao_log_single_extra_query(void)
+{
+}
diff --git a/src/kernel/ao_log_telescience.c b/src/kernel/ao_log_telescience.c
new file mode 100644 (file)
index 0000000..002a10b
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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_product.h"
+#include "ao_log.h"
+#include "ao_companion.h"
+
+static uint8_t ao_log_data_pos;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TELESCIENCE;
+
+static void
+ao_log_telescience_csum(void) __reentrant
+{
+       __xdata uint8_t *b = ao_log_single_write_data.bytes;
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       ao_log_single_write_data.telescience.csum = 0;
+       for (i = 0; i < sizeof (struct ao_log_telescience); i++)
+               sum += *b++;
+       ao_log_single_write_data.telescience.csum = -sum;
+}
+
+void
+ao_log_single(void)
+{
+       ao_storage_setup();
+
+       /* This can take a while, so let the rest
+        * of the system finish booting before we start
+        */
+       ao_delay(AO_SEC_TO_TICKS(10));
+
+       ao_log_single_restart();
+       for (;;) {
+               while (!ao_log_running)
+                       ao_sleep(&ao_log_running);
+
+               ao_log_start_pos = ao_log_current_pos;
+               ao_log_single_write_data.telescience.type = AO_LOG_TELESCIENCE_START;
+               ao_log_single_write_data.telescience.tick = ao_time();
+               ao_log_single_write_data.telescience.adc[0] = ao_companion_command.serial;
+               ao_log_single_write_data.telescience.adc[1] = ao_companion_command.flight;
+               ao_log_telescience_csum();
+               ao_log_single_write();
+               /* Write the whole contents of the ring to the log
+                * when starting up.
+                */
+               ao_log_data_pos = ao_data_ring_next(ao_data_head);
+               ao_log_single_write_data.telescience.type = AO_LOG_TELESCIENCE_DATA;
+               while (ao_log_running) {
+                       /* Write samples to EEPROM */
+                       while (ao_log_data_pos != ao_data_head) {
+                               ao_log_single_write_data.telescience.tick = ao_data_ring[ao_log_data_pos].tick;
+                               memcpy(&ao_log_single_write_data.telescience.adc, (void *) ao_data_ring[ao_log_data_pos].adc.adc,
+                                      AO_LOG_TELESCIENCE_NUM_ADC * sizeof (uint16_t));
+                               ao_log_telescience_csum();
+                               ao_log_single_write();
+                               ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+                       }
+                       /* Wait for more ADC data to arrive */
+                       ao_sleep((void *) &ao_data_head);
+               }
+               memset(&ao_log_single_write_data.telescience.adc, '\0', sizeof (ao_log_single_write_data.telescience.adc));
+       }
+}
+
+void
+ao_log_single_list(void)
+{
+       uint32_t        pos;
+       uint32_t        start = 0;
+       uint8_t         flight = 0;
+
+       for (pos = 0; ; pos += sizeof (struct ao_log_telescience)) {
+               if (pos >= ao_storage_config ||
+                   !ao_log_single_read(pos) ||
+                   ao_log_single_read_data.telescience.type == AO_LOG_TELESCIENCE_START)
+               {
+                       if (pos != start) {
+                               printf("flight %d start %x end %x\n",
+                                      flight,
+                                      (uint16_t) (start >> 8),
+                                      (uint16_t) ((pos + 0xff) >> 8)); flush();
+                       }
+                       if (ao_log_single_read_data.telescience.type != AO_LOG_TELESCIENCE_START)
+                               break;
+                       start = pos;
+                       flight++;
+               }
+       }
+       printf ("done\n");
+}
+
+void
+ao_log_single_extra_query(void)
+{
+       printf("log data tick: %04x\n", ao_log_single_write_data.telescience.tick);
+       printf("TM data tick: %04x\n", ao_log_single_write_data.telescience.tm_tick);
+       printf("TM state: %d\n", ao_log_single_write_data.telescience.tm_state);
+       printf("TM serial: %d\n", ao_companion_command.serial);
+       printf("TM flight: %d\n", ao_companion_command.flight);
+}
diff --git a/src/kernel/ao_log_tiny.c b/src/kernel/ao_log_tiny.c
new file mode 100644 (file)
index 0000000..67767dc
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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"
+
+static __data uint16_t ao_log_tiny_interval;
+
+#define AO_LOG_TINY_INTERVAL_DEFAULT   AO_MS_TO_TICKS(1000)
+#if USE_FAST_ASCENT_LOG
+#define AO_LOG_TINY_INTERVAL_ASCENT    AO_MS_TO_TICKS(100)
+#define AO_PAD_RING    8
+#else
+#define AO_LOG_TINY_INTERVAL_ASCENT    AO_LOG_TINY_INTERVAL_DEFAULT
+#define AO_PAD_RING    2
+#endif
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_TINY;
+
+void
+ao_log_tiny_set_interval(uint16_t ticks)
+{
+       ao_log_tiny_interval = ticks;
+}
+
+
+static void ao_log_tiny_data(uint16_t d)
+{
+       if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+               ao_log_stop();
+       if (ao_log_running) {
+               ao_storage_write(ao_log_current_pos, DATA_TO_XDATA(&d), 2);
+               ao_log_current_pos += 2;
+       }
+}
+
+static __xdata uint16_t ao_log_pad_ring[AO_PAD_RING];
+static __pdata uint8_t ao_log_pad_ring_pos;
+
+#define ao_pad_ring_next(n)    (((n) + 1) & (AO_PAD_RING - 1))
+
+static void ao_log_tiny_queue(uint16_t d)
+{
+       ao_log_pad_ring[ao_log_pad_ring_pos] = d;
+       ao_log_pad_ring_pos = ao_pad_ring_next(ao_log_pad_ring_pos);
+}
+
+static void ao_log_tiny_start(void)
+{
+       uint8_t         p;
+       uint16_t        d;
+
+       ao_log_tiny_data(ao_flight_number);
+       ao_log_tiny_data(ao_ground_pres);
+       p = ao_log_pad_ring_pos;
+       do {
+               d = ao_log_pad_ring[p];
+               /*
+                * ignore unwritten slots
+                */
+               if (d)
+                       ao_log_tiny_data(d);
+               p = ao_pad_ring_next(p);
+       } while (p != ao_log_pad_ring_pos);
+}
+
+void
+ao_log(void)
+{
+       uint16_t                last_time;
+       uint16_t                now;
+       enum ao_flight_state    ao_log_tiny_state;
+       int32_t                 sum;
+       int16_t                 count;
+       uint8_t                 ao_log_data;
+       uint8_t                 ao_log_started = 0;
+
+       ao_storage_setup();
+
+       ao_log_scan();
+
+       ao_log_tiny_state = ao_flight_invalid;
+       ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT;
+       sum = 0;
+       count = 0;
+       ao_log_data = ao_sample_data;
+       last_time = ao_time();
+       for (;;) {
+
+               /*
+                * Add in pending sample data
+                */
+               ao_sleep(DATA_TO_XDATA(&ao_sample_data));
+               while (ao_log_data != ao_sample_data) {
+                       sum += ao_data_pres(&ao_data_ring[ao_log_data]);
+                       count++;
+                       ao_log_data = ao_data_ring_next(ao_log_data);
+               }
+               if (ao_log_running) {
+                       if (!ao_log_started) {
+                               ao_log_tiny_start();
+                               ao_log_started = 1;
+                       }
+                       if (ao_flight_state != ao_log_tiny_state) {
+                               ao_log_tiny_data(ao_flight_state | 0x8000);
+                               ao_log_tiny_state = ao_flight_state;
+                               ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_DEFAULT;
+#if AO_LOG_TINY_INTERVAL_ASCENT != AO_LOG_TINY_INTERVAL_DEFAULT
+                               if (ao_log_tiny_state <= ao_flight_coast)
+                                       ao_log_tiny_interval = AO_LOG_TINY_INTERVAL_ASCENT;
+#endif
+                               if (ao_log_tiny_state == ao_flight_landed)
+                                       ao_log_stop();
+                       }
+               }
+
+               /* Stop logging when told to */
+               if (!ao_log_running && ao_log_started)
+                       ao_exit();
+
+               /*
+                * Write out the sample when finished
+                */
+               now = ao_time();
+               if ((int16_t) (now - (last_time + ao_log_tiny_interval)) >= 0 && count) {
+                       count = sum / count;
+                       if (ao_log_started)
+                               ao_log_tiny_data(count);
+                       else
+                               ao_log_tiny_queue(count);
+                       sum = 0;
+                       count = 0;
+                       last_time = now;
+               }
+       }
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+       static __xdata uint16_t flight;
+
+       (void) slot;
+       ao_storage_read(0, &flight, 2);
+       if (flight == 0xffff)
+               flight = 0;
+       return flight;
+}
diff --git a/src/kernel/ao_microflight.c b/src/kernel/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/kernel/ao_microkalman.c b/src/kernel/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);
+}
diff --git a/src/kernel/ao_monitor.c b/src/kernel/ao_monitor.c
new file mode 100644 (file)
index 0000000..18f170b
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * 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_telem.h"
+#include "ao_flight.h"
+
+#if !HAS_MONITOR
+#error Must define HAS_MONITOR to 1
+#endif
+
+#ifndef LEGACY_MONITOR
+#error Must define LEGACY_MONITOR
+#endif
+
+#ifndef HAS_MONITOR_PUT
+#define HAS_MONITOR_PUT 1
+#endif
+
+#ifndef AO_MONITOR_LED
+#error Must define AO_MONITOR_LED
+#endif
+
+__data uint8_t ao_monitoring;
+static __data uint8_t ao_monitor_disabled;
+static __data uint8_t ao_internal_monitoring;
+static __data uint8_t ao_external_monitoring;
+
+__xdata union ao_monitor ao_monitor_ring[AO_MONITOR_RING];
+
+__data uint8_t ao_monitor_head;
+
+static void
+_ao_monitor_adjust(void)
+{
+       if (ao_monitoring)
+               ao_radio_recv_abort();
+       if (ao_monitor_disabled)
+               ao_monitoring = 0;
+       else {
+               if (ao_external_monitoring)
+                       ao_monitoring = ao_external_monitoring;
+               else
+                       ao_monitoring = ao_internal_monitoring;
+       }
+       ao_wakeup(DATA_TO_XDATA(&ao_monitoring));
+}
+
+void
+ao_monitor_get(void)
+{
+       uint8_t size;
+
+       for (;;) {
+               switch (ao_monitoring) {
+               case 0:
+                       ao_sleep(DATA_TO_XDATA(&ao_monitoring));
+                       continue;
+#if LEGACY_MONITOR
+               case AO_MONITORING_ORIG:
+                       size = sizeof (struct ao_telemetry_orig_recv);
+                       break;
+#endif
+               default:
+                       if (ao_monitoring > AO_MAX_TELEMETRY)
+                               ao_monitoring = AO_MAX_TELEMETRY;
+                       size = ao_monitoring;
+                       break;
+               }
+               if (!ao_radio_recv(&ao_monitor_ring[ao_monitor_head], size + 2, 0))
+                       continue;
+               ao_monitor_head = ao_monitor_ring_next(ao_monitor_head);
+               ao_wakeup(DATA_TO_XDATA(&ao_monitor_head));
+       }
+}
+
+#if AO_MONITOR_LED
+__xdata struct ao_task ao_monitor_blink_task;
+
+void
+ao_monitor_blink(void)
+{
+       for (;;) {
+               ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
+               ao_led_for(AO_MONITOR_LED, AO_MS_TO_TICKS(100));
+       }
+}
+#endif
+
+#if HAS_MONITOR_PUT
+
+static const char xdigit[16] = {
+       '0', '1', '2', '3', '4', '5', '6', '7',
+       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+};
+
+#define hex(c) do { putchar(xdigit[(c) >> 4]); putchar(xdigit[(c)&0xf]); } while (0)
+
+void
+ao_monitor_put(void)
+{
+#if LEGACY_MONITOR
+       __xdata char callsign[AO_MAX_CALLSIGN+1];
+       int16_t rssi;
+#endif
+       uint8_t ao_monitor_tail;
+       uint8_t state;
+       uint8_t sum, byte;
+       __xdata union ao_monitor        *m;
+
+#define recv_raw       ((m->raw))
+#define recv_orig      ((m->orig))
+#define recv_tiny      ((m->tiny))
+
+       ao_monitor_tail = ao_monitor_head;
+       for (;;) {
+               while (!ao_external_monitoring)
+                       ao_sleep(DATA_TO_XDATA(&ao_external_monitoring));
+               while (ao_monitor_tail == ao_monitor_head && ao_external_monitoring)
+                       ao_sleep(DATA_TO_XDATA(&ao_monitor_head));
+               if (!ao_external_monitoring)
+                       continue;
+               m = &ao_monitor_ring[ao_monitor_tail];
+               ao_monitor_tail = ao_monitor_ring_next(ao_monitor_tail);
+               switch (ao_monitoring) {
+               case 0:
+                       break;
+#if LEGACY_MONITOR
+               case AO_MONITORING_ORIG:
+                       state = recv_orig.telemetry_orig.flight_state;
+
+                       rssi = (int16_t) AO_RSSI_FROM_RADIO(recv_orig.rssi);
+                       ao_xmemcpy(callsign, recv_orig.telemetry_orig.callsign, AO_MAX_CALLSIGN);
+                       if (state > ao_flight_invalid)
+                               state = ao_flight_invalid;
+                       if (recv_orig.status & PKT_APPEND_STATUS_1_CRC_OK) {
+
+                               /* General header fields */
+                               printf(AO_TELEM_VERSION " %d "
+                                      AO_TELEM_CALL " %s "
+                                      AO_TELEM_SERIAL " %d "
+                                      AO_TELEM_FLIGHT " %d "
+                                      AO_TELEM_RSSI " %d "
+                                      AO_TELEM_STATE " %s "
+                                      AO_TELEM_TICK " %d ",
+                                      AO_TELEMETRY_VERSION,
+                                      callsign,
+                                      recv_orig.telemetry_orig.serial,
+                                      recv_orig.telemetry_orig.flight,
+                                      rssi,
+                                      ao_state_names[state],
+                                      recv_orig.telemetry_orig.adc.tick);
+
+                               /* Raw sensor values */
+                               printf(AO_TELEM_RAW_ACCEL " %d "
+                                      AO_TELEM_RAW_BARO " %d "
+                                      AO_TELEM_RAW_THERMO " %d "
+                                      AO_TELEM_RAW_BATT " %d "
+                                      AO_TELEM_RAW_DROGUE " %d "
+                                      AO_TELEM_RAW_MAIN " %d ",
+                                      recv_orig.telemetry_orig.adc.accel,
+                                      recv_orig.telemetry_orig.adc.pres,
+                                      recv_orig.telemetry_orig.adc.temp,
+                                      recv_orig.telemetry_orig.adc.v_batt,
+                                      recv_orig.telemetry_orig.adc.sense_d,
+                                      recv_orig.telemetry_orig.adc.sense_m);
+
+                               /* Sensor calibration values */
+                               printf(AO_TELEM_CAL_ACCEL_GROUND " %d "
+                                      AO_TELEM_CAL_BARO_GROUND " %d "
+                                      AO_TELEM_CAL_ACCEL_PLUS " %d "
+                                      AO_TELEM_CAL_ACCEL_MINUS " %d ",
+                                      recv_orig.telemetry_orig.ground_accel,
+                                      recv_orig.telemetry_orig.ground_pres,
+                                      recv_orig.telemetry_orig.accel_plus_g,
+                                      recv_orig.telemetry_orig.accel_minus_g);
+
+                               if (recv_orig.telemetry_orig.u.k.unused == 0x8000) {
+                                       /* Kalman state values */
+                                       printf(AO_TELEM_KALMAN_HEIGHT " %d "
+                                              AO_TELEM_KALMAN_SPEED " %d "
+                                              AO_TELEM_KALMAN_ACCEL " %d ",
+                                              recv_orig.telemetry_orig.height,
+                                              recv_orig.telemetry_orig.u.k.speed,
+                                              recv_orig.telemetry_orig.accel);
+                               } else {
+                                       /* Ad-hoc flight values */
+                                       printf(AO_TELEM_ADHOC_ACCEL " %d "
+                                              AO_TELEM_ADHOC_SPEED " %ld "
+                                              AO_TELEM_ADHOC_BARO " %d ",
+                                              recv_orig.telemetry_orig.accel,
+                                              recv_orig.telemetry_orig.u.flight_vel,
+                                              recv_orig.telemetry_orig.height);
+                               }
+                               ao_gps_print(&recv_orig.telemetry_orig.gps);
+                               ao_gps_tracking_print(&recv_orig.telemetry_orig.gps_tracking);
+                               putchar('\n');
+#if HAS_RSSI
+                               ao_rssi_set(rssi);
+#endif
+                       } else {
+                               printf("CRC INVALID RSSI %3d\n", rssi);
+                       }
+                       break;
+#endif /* LEGACY_MONITOR */
+               default:
+#if AO_PROFILE
+               {
+                       extern uint32_t ao_rx_start_tick, ao_rx_packet_tick, ao_rx_done_tick, ao_rx_last_done_tick;
+                       extern uint32_t ao_fec_decode_start, ao_fec_decode_end;
+
+                       printf ("between packet: %d\n", ao_rx_start_tick - ao_rx_last_done_tick);
+                       printf ("receive start delay: %d\n", ao_rx_packet_tick - ao_rx_start_tick);
+                       printf ("decode time: %d\n", ao_fec_decode_end - ao_fec_decode_start);
+                       printf ("rx cleanup: %d\n", ao_rx_done_tick - ao_fec_decode_end);
+               }
+#endif
+                       printf("TELEM ");
+                       hex((uint8_t) (ao_monitoring + 2));
+                       sum = 0x5a;
+                       for (state = 0; state < ao_monitoring + 2; state++) {
+                               byte = recv_raw.packet[state];
+                               sum += byte;
+                               hex(byte);
+                       }
+                       hex(sum);
+                       putchar ('\n');
+#if HAS_RSSI
+                       if (recv_raw.packet[ao_monitoring + 1] & PKT_APPEND_STATUS_1_CRC_OK) {
+                               rssi = AO_RSSI_FROM_RADIO(recv_raw.packet[ao_monitoring]);
+                               ao_rssi_set(rssi);
+                       }
+#endif
+                       break;
+               }
+               ao_usb_flush();
+       }
+}
+
+__xdata struct ao_task ao_monitor_put_task;
+#endif
+
+__xdata struct ao_task ao_monitor_get_task;
+
+void
+ao_monitor_set(uint8_t monitoring)
+{
+       ao_internal_monitoring = monitoring;
+       _ao_monitor_adjust();
+}
+
+void
+ao_monitor_disable(void)
+{
+       ++ao_monitor_disabled;
+       _ao_monitor_adjust();
+}
+
+void
+ao_monitor_enable(void)
+{
+       --ao_monitor_disabled;
+       _ao_monitor_adjust();
+}
+
+#if HAS_MONITOR_PUT
+static void
+set_monitor(void)
+{
+       ao_cmd_hex();
+       ao_external_monitoring = ao_cmd_lex_i;
+       ao_wakeup(DATA_TO_XDATA(&ao_external_monitoring));
+       ao_wakeup(DATA_TO_XDATA(&ao_monitor_head));
+       _ao_monitor_adjust();
+}
+
+__code struct ao_cmds ao_monitor_cmds[] = {
+       { set_monitor,  "m <0 off, 1 old, 20 std>\0Set radio monitoring" },
+       { 0,    NULL },
+};
+#endif
+
+void
+ao_monitor_init(void) __reentrant
+{
+#if HAS_MONITOR_PUT
+       ao_cmd_register(&ao_monitor_cmds[0]);
+       ao_add_task(&ao_monitor_put_task, ao_monitor_put, "monitor_put");
+#endif
+       ao_add_task(&ao_monitor_get_task, ao_monitor_get, "monitor_get");
+#if AO_MONITOR_LED
+       ao_add_task(&ao_monitor_blink_task, ao_monitor_blink, "monitor_blink");
+#endif
+}
diff --git a/src/kernel/ao_mutex.c b/src/kernel/ao_mutex.c
new file mode 100644 (file)
index 0000000..952ff46
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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"
+
+void
+ao_mutex_get(__xdata uint8_t *mutex) __reentrant
+{
+       if (*mutex == ao_cur_task->task_id)
+               ao_panic(AO_PANIC_MUTEX);
+       ao_arch_critical(
+               while (*mutex)
+                       ao_sleep(mutex);
+               *mutex = ao_cur_task->task_id;
+               );
+}
+
+void
+ao_mutex_put(__xdata uint8_t *mutex) __reentrant
+{
+       if (*mutex != ao_cur_task->task_id)
+               ao_panic(AO_PANIC_MUTEX);
+       ao_arch_critical(
+               *mutex = 0;
+               ao_wakeup(mutex);
+               );
+}
diff --git a/src/kernel/ao_notask.c b/src/kernel/ao_notask.c
new file mode 100644 (file)
index 0000000..6f967e6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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>
+
+static volatile void *ao_wchan;
+
+uint8_t
+ao_sleep(__xdata void *wchan)
+{
+#if 1
+       ao_wchan = wchan;
+       ao_arch_wait_interrupt();
+#else
+       uint8_t sreg;
+
+       ao_wchan = wchan;
+       asm("in %0,__SREG__" : "=&r" (sreg));
+       sei();
+       while (ao_wchan)
+               ao_arch_cpu_idle();
+       asm("out __SREG__,%0" : : "r" (sreg));
+#endif
+       return 0;
+}
+
+void
+ao_wakeup(__xdata void *wchan)
+{
+       (void) wchan;
+       ao_wchan = 0;
+}
diff --git a/src/kernel/ao_notask.h b/src/kernel/ao_notask.h
new file mode 100644 (file)
index 0000000..6b6b5bb
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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_NOTASK_H_
+#define _AO_NOTASK_H_
+
+uint8_t
+ao_sleep(__xdata void *wchan);
+
+void
+ao_wakeup(__xdata void *wchan);
+
+#endif /* _AO_NOTASK_H_ */
diff --git a/src/kernel/ao_packet.h b/src/kernel/ao_packet.h
new file mode 100644 (file)
index 0000000..b8426cf
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_PACKET_H_
+#define _AO_PACKET_H_
+
+/*
+ * ao_packet.c
+ *
+ * Packet-based command interface
+ */
+
+#define AO_PACKET_MAX          64
+#define AO_PACKET_SYN          (uint8_t) 0xff
+
+struct ao_packet {
+       uint8_t         addr;
+       uint8_t         len;
+       uint8_t         seq;
+       uint8_t         ack;
+       uint8_t         d[AO_PACKET_MAX];
+       uint8_t         callsign[AO_MAX_CALLSIGN];
+};
+
+struct ao_packet_recv {
+       struct ao_packet        packet;
+       int8_t                  rssi;
+       uint8_t                 status;
+};
+
+extern __xdata struct ao_packet_recv ao_rx_packet;
+extern __xdata struct ao_packet ao_tx_packet;
+extern __xdata struct ao_task  ao_packet_task;
+extern __xdata uint8_t ao_packet_enable;
+extern __xdata uint8_t ao_packet_master_sleeping;
+extern __pdata uint8_t ao_packet_rx_len, ao_packet_rx_used, ao_packet_tx_used;
+extern __xdata uint8_t ao_packet_restart;
+
+void
+ao_packet_send(void);
+
+uint8_t
+ao_packet_recv(void);
+
+void
+ao_packet_flush(void);
+
+void
+ao_packet_putchar(char c) __reentrant;
+
+int
+_ao_packet_pollchar(void);
+
+#if PACKET_HAS_MASTER
+/* ao_packet_master.c */
+
+extern __xdata int8_t ao_packet_last_rssi;
+
+void
+ao_packet_master_init(void);
+#endif
+
+#if PACKET_HAS_SLAVE
+/* ao_packet_slave.c */
+
+void
+ao_packet_slave_start(void);
+
+void
+ao_packet_slave_stop(void);
+
+void
+ao_packet_slave_init(uint8_t enable);
+
+#endif
+
+#endif /* _AO_PACKET_H_ */
diff --git a/src/kernel/ao_panic.c b/src/kernel/ao_panic.c
new file mode 100644 (file)
index 0000000..c29cd8f
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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"
+
+#ifndef HAS_BEEP
+#error Please define HAS_BEEP
+#endif
+
+#if !HAS_BEEP
+#define ao_beep(x)
+#endif
+#if !LEDS_AVAILABLE
+#define ao_led_on(x)
+#define ao_led_off(x)
+#endif
+
+#ifndef AO_LED_PANIC
+#define AO_LED_PANIC   AO_LED_RED
+#endif
+
+static void
+ao_panic_delay(uint8_t n)
+{
+       uint8_t i = 0, j = 0;
+
+       while (n--)
+               while (--j)
+                       while (--i)
+                               ao_arch_nop();
+}
+
+void
+ao_panic(uint8_t reason)
+{
+       uint8_t n;
+
+#if LOW_LEVEL_DEBUG
+       ao_cur_task = NULL;
+       printf ("panic %d\n", reason);
+#endif
+       ao_arch_block_interrupts();
+       for (;;) {
+               ao_panic_delay(20);
+               for (n = 0; n < 5; n++) {
+                       ao_led_on(AO_LED_PANIC);
+                       ao_beep(AO_BEEP_HIGH);
+                       ao_panic_delay(1);
+                       ao_led_off(AO_LED_PANIC);
+                       ao_beep(AO_BEEP_LOW);
+                       ao_panic_delay(1);
+               }
+               ao_beep(AO_BEEP_OFF);
+               ao_panic_delay(2);
+
+#ifdef SDCC
+#pragma disable_warning 126
+#endif
+               if (reason & 0x40) {
+                       ao_led_on(AO_LED_PANIC);
+                       ao_beep(AO_BEEP_HIGH);
+                       ao_panic_delay(40);
+                       ao_led_off(AO_LED_PANIC);
+                       ao_beep(AO_BEEP_OFF);
+                       ao_panic_delay(10);
+               }
+               for (n = 0; n < (reason & 0x3f); n++) {
+                       ao_led_on(AO_LED_PANIC);
+                       ao_beep(AO_BEEP_MID);
+                       ao_panic_delay(10);
+                       ao_led_off(AO_LED_PANIC);
+                       ao_beep(AO_BEEP_OFF);
+                       ao_panic_delay(10);
+               }
+       }
+}
diff --git a/src/kernel/ao_product.c b/src/kernel/ao_product.c
new file mode 100644 (file)
index 0000000..b9327ba
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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_product.h"
+
+/* Defines which mark this particular AltOS product */
+
+const char ao_version[AO_MAX_VERSION] = AO_iVersion_STRING;
+const char ao_manufacturer[] = AO_iManufacturer_STRING;
+const char ao_product[] = AO_iProduct_STRING;
+
+#define LE_WORD(x)    ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
+
+#if HAS_USB
+
+/* 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 [] =
+{
+       /* Device descriptor */
+       0x12,
+       AO_USB_DESC_DEVICE,
+       LE_WORD(0x0110),        /*  bcdUSB */
+       0x02,                   /*  bDeviceClass */
+       0x00,                   /*  bDeviceSubClass */
+       0x00,                   /*  bDeviceProtocol */
+       AO_USB_CONTROL_SIZE,    /*  bMaxPacketSize */
+       LE_WORD(0xFFFE),        /*  idVendor */
+       LE_WORD(AO_idProduct_NUMBER),   /*  idProduct */
+       LE_WORD(0x0100),        /*  bcdDevice */
+       0x01,                   /*  iManufacturer */
+       0x02,                   /*  iProduct */
+       0x03,                   /*  iSerialNumber */
+       0x01,                   /*  bNumConfigurations */
+
+       /* Configuration descriptor */
+       0x09,
+       AO_USB_DESC_CONFIGURATION,
+       LE_WORD(67),            /*  wTotalLength */
+       0x02,                   /*  bNumInterfaces */
+       0x01,                   /*  bConfigurationValue */
+       0x00,                   /*  iConfiguration */
+       0xC0,                   /*  bmAttributes */
+       AO_USB_MAX_POWER >> 1,  /*  bMaxPower, 2mA units */
+
+       /* Control class interface */
+       0x09,
+       AO_USB_DESC_INTERFACE,
+       0x00,                   /*  bInterfaceNumber */
+       0x00,                   /*  bAlternateSetting */
+       0x01,                   /*  bNumEndPoints */
+       0x02,                   /*  bInterfaceClass */
+       0x02,                   /*  bInterfaceSubClass */
+       0x01,                   /*  bInterfaceProtocol, linux requires value of 1 for the cdc_acm module */
+       0x00,                   /*  iInterface */
+
+       /* Header functional descriptor */
+       0x05,
+       AO_USB_CS_INTERFACE,
+       0x00,                   /*  bDescriptor SubType Header */
+       LE_WORD(0x0110),        /*  CDC version 1.1 */
+
+       /* Call management functional descriptor */
+       0x05,
+       AO_USB_CS_INTERFACE,
+       0x01,                   /* bDescriptor SubType Call Management */
+       0x01,                   /* bmCapabilities = device handles call management */
+       0x01,                   /* bDataInterface call management interface number */
+
+       /* ACM functional descriptor */
+       0x04,
+       AO_USB_CS_INTERFACE,
+       0x02,                   /* bDescriptor SubType Abstract Control Management */
+       0x02,                   /* bmCapabilities = D1 (Set_line_Coding, Set_Control_Line_State, Get_Line_Coding and Serial_State) */
+
+       /* Union functional descriptor */
+       0x05,
+       AO_USB_CS_INTERFACE,
+       0x06,                   /* bDescriptor SubType Union Functional descriptor */
+       0x00,                   /* bMasterInterface */
+       0x01,                   /* bSlaveInterface0 */
+
+       /* Notification EP */
+       0x07,
+       AO_USB_DESC_ENDPOINT,
+       AO_USB_INT_EP|0x80,     /* bEndpointAddress */
+       0x03,                   /* bmAttributes = intr */
+       LE_WORD(8),             /* wMaxPacketSize */
+       0xff,                   /* bInterval */
+
+       /* Data class interface descriptor */
+       0x09,
+       AO_USB_DESC_INTERFACE,
+       0x01,                   /* bInterfaceNumber */
+       0x00,                   /* bAlternateSetting */
+       0x02,                   /* bNumEndPoints */
+       0x0A,                   /* bInterfaceClass = data */
+       0x00,                   /* bInterfaceSubClass */
+       0x00,                   /* bInterfaceProtocol */
+       0x00,                   /* iInterface */
+
+       /* Data EP OUT */
+       0x07,
+       AO_USB_DESC_ENDPOINT,
+       AO_USB_OUT_EP,          /* bEndpointAddress */
+       0x02,                   /* bmAttributes = bulk */
+       LE_WORD(AO_USB_OUT_SIZE),/* wMaxPacketSize */
+       0x00,                   /* bInterval */
+
+       /* Data EP in */
+       0x07,
+       AO_USB_DESC_ENDPOINT,
+       AO_USB_IN_EP|0x80,      /* bEndpointAddress */
+       0x02,                   /* bmAttributes = bulk */
+       LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */
+       0x00,                   /* bInterval */
+
+       /* String descriptors */
+       0x04,
+       AO_USB_DESC_STRING,
+       LE_WORD(0x0409),
+
+       /* iManufacturer */
+       AO_iManufacturer_LEN,
+       AO_USB_DESC_STRING,
+       AO_iManufacturer_UCS2,
+
+       /* iProduct */
+       AO_iProduct_LEN,
+       AO_USB_DESC_STRING,
+       AO_iProduct_UCS2,
+
+       /* iSerial */
+       AO_iSerial_LEN,
+       AO_USB_DESC_STRING,
+       AO_iSerial_UCS2,
+
+       /* Terminating zero */
+       0
+};
+#endif
diff --git a/src/kernel/ao_pyro.c b/src/kernel/ao_pyro.c
new file mode 100644 (file)
index 0000000..85d88d9
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * 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_FLIGHT_TEST
+#include <ao.h>
+#include <ao_sample.h>
+#include <ao_flight.h>
+#endif
+#include <ao_pyro.h>
+
+#if IS_COMPANION
+#include <ao_companion.h>
+#define ao_accel ao_companion_command.accel
+#define ao_speed ao_companion_command.speed
+#define ao_height ao_companion_command.height
+#define ao_flight_state ao_companion_command.flight_state
+#define ao_motor_number ao_companion_command.motor_number
+#endif
+
+#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
+ * of the requirements
+ */
+static uint8_t
+ao_pyro_ready(struct ao_pyro *pyro)
+{
+       enum ao_pyro_flag flag, flags;
+
+       flags = pyro->flags;
+       while (flags != ao_pyro_none) {
+               flag = ao_lowbit(flags);
+               flags &= ~flag;
+               switch (flag) {
+
+               case ao_pyro_accel_less:
+                       if (ao_accel <= pyro->accel_less)
+                               continue;
+                       break;
+               case ao_pyro_accel_greater:
+                       if (ao_accel >= pyro->accel_greater)
+                               continue;
+                       break;
+
+
+               case ao_pyro_speed_less:
+                       if (ao_speed <= pyro->speed_less)
+                               continue;
+                       break;
+               case ao_pyro_speed_greater:
+                       if (ao_speed >= pyro->speed_greater)
+                               continue;
+                       break;
+
+               case ao_pyro_height_less:
+                       if (ao_height <= pyro->height_less)
+                               continue;
+                       break;
+               case ao_pyro_height_greater:
+                       if (ao_height >= pyro->height_greater)
+                               continue;
+                       break;
+
+#if HAS_GYRO
+               case ao_pyro_orient_less:
+                       if (ao_sample_orient <= pyro->orient_less)
+                               continue;
+                       break;
+               case ao_pyro_orient_greater:
+                       if (ao_sample_orient >= pyro->orient_greater)
+                               continue;
+                       break;
+#endif
+
+               case ao_pyro_time_less:
+                       if ((int16_t) (ao_time() - ao_boost_tick) <= pyro->time_less)
+                               continue;
+                       break;
+               case ao_pyro_time_greater:
+                       if ((int16_t) (ao_time() - ao_boost_tick) >= pyro->time_greater)
+                               continue;
+                       break;
+
+               case ao_pyro_ascending:
+                       if (ao_speed > 0)
+                               continue;
+                       break;
+               case ao_pyro_descending:
+                       if (ao_speed < 0)
+                               continue;
+                       break;
+
+               case ao_pyro_after_motor:
+                       if (ao_motor_number == pyro->motor)
+                               continue;
+                       break;
+
+               case ao_pyro_delay:
+                       /* handled separately */
+                       continue;
+
+               case ao_pyro_state_less:
+                       if (ao_flight_state < pyro->state_less)
+                               continue;
+                       break;
+               case ao_pyro_state_greater_or_equal:
+                       if (ao_flight_state >= pyro->state_greater_or_equal)
+                               continue;
+                       break;
+
+               default:
+                       continue;
+               }
+               return FALSE;
+       }
+       return TRUE;
+}
+
+#ifndef AO_FLIGHT_TEST
+static void
+ao_pyro_pin_set(uint8_t p, uint8_t v)
+{
+       switch (p) {
+#if AO_PYRO_NUM > 0
+       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_gpio_set(AO_PYRO_PORT_1, AO_PYRO_PIN_1, AO_PYRO_1, v); break;
+#endif
+#if AO_PYRO_NUM > 2
+       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_gpio_set(AO_PYRO_PORT_3, AO_PYRO_PIN_3, AO_PYRO_3, v); break;
+#endif
+#if AO_PYRO_NUM > 4
+       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_gpio_set(AO_PYRO_PORT_5, AO_PYRO_PIN_5, AO_PYRO_5, v); break;
+#endif
+#if AO_PYRO_NUM > 6
+       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_gpio_set(AO_PYRO_PORT_7, AO_PYRO_PIN_7, AO_PYRO_7, v); break;
+#endif
+       default: break;
+       }
+}
+#endif
+
+uint8_t        ao_pyro_wakeup;
+
+static void
+ao_pyro_pins_fire(uint16_t fire)
+{
+       uint8_t p;
+
+       for (p = 0; p < AO_PYRO_NUM; p++) {
+               if (fire & (1 << p))
+                       ao_pyro_pin_set(p, 1);
+       }
+       ao_delay(ao_config.pyro_time);
+       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));
+}
+
+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 disabled igniters
+                */
+               if (!pyro->flags)
+                       continue;
+
+               any_waiting = 1;
+               /* Check pyro state to see if it should 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;
+                               if (!pyro->delay_done)
+                                       pyro->delay_done = 1;
+                       }
+               }
+
+               /* 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;
+               }
+
+               fire |= (1 << p);
+       }
+
+       if (fire)
+               ao_pyro_pins_fire(fire);
+
+       return any_waiting;
+}
+
+#define NO_VALUE       0xff
+
+#define AO_PYRO_NAME_LEN       4
+
+#if !DISABLE_HELP
+#define ENABLE_HELP 1
+#endif
+
+#if ENABLE_HELP
+#define HELP(s)        (s)
+#else
+#define HELP(s)
+#endif
+
+const struct {
+       char                    name[AO_PYRO_NAME_LEN];
+       enum ao_pyro_flag       flag;
+       uint8_t                 offset;
+#if ENABLE_HELP
+       char                    *help;
+#endif
+} ao_pyro_values[] = {
+       { "a<", ao_pyro_accel_less,     offsetof(struct ao_pyro, accel_less), HELP("accel less (m/ss * 16)") },
+       { "a>", ao_pyro_accel_greater,  offsetof(struct ao_pyro, accel_greater), HELP("accel greater (m/ss * 16)") },
+
+       { "s<", ao_pyro_speed_less,     offsetof(struct ao_pyro, speed_less), HELP("speed less (m/s * 16)") },
+       { "s>", ao_pyro_speed_greater,  offsetof(struct ao_pyro, speed_greater), HELP("speed greater (m/s * 16)") },
+
+       { "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_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
+
+       { "t<", ao_pyro_time_less,      offsetof(struct ao_pyro, time_less), HELP("time less (s * 100)") },
+       { "t>", ao_pyro_time_greater,   offsetof(struct ao_pyro, time_greater), HELP("time greater (s * 100)")  },
+
+       { "f<", ao_pyro_state_less,     offsetof(struct ao_pyro, state_less), HELP("state less") },
+       { "f>=",ao_pyro_state_greater_or_equal, offsetof(struct ao_pyro, state_greater_or_equal), HELP("state greater or equal")  },
+
+       { "A", ao_pyro_ascending,       NO_VALUE, HELP("ascending") },
+       { "D", ao_pyro_descending,      NO_VALUE, HELP("descending") },
+
+       { "m", ao_pyro_after_motor,     offsetof(struct ao_pyro, motor), HELP("after motor") },
+
+       { "d", ao_pyro_delay,           offsetof(struct ao_pyro, delay), HELP("delay before firing (s * 100)") },
+       { "", 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)
+{
+       const char *s = ao_pyro_values[v].name;
+       printf ("%s%s", s, "   " + strlen(s));
+}
+
+#if ENABLE_HELP
+static void
+ao_pyro_help(void)
+{
+       uint8_t v;
+       for (v = 0; ao_pyro_values[v].flag != ao_pyro_none; v++) {
+               ao_pyro_print_name(v);
+               if (ao_pyro_values[v].offset != NO_VALUE)
+                       printf ("<n> ");
+               else
+                       printf ("    ");
+               printf ("%s\n", ao_pyro_values[v].help);
+       }
+}
+#endif
+
+void
+ao_pyro_show(void)
+{
+       uint8_t         p;
+       uint8_t         v;
+       struct ao_pyro  *pyro;
+
+       printf ("Pyro-count: %d\n", AO_PYRO_NUM);
+       for (p = 0; p < AO_PYRO_NUM; p++) {
+               printf ("Pyro %2d: ", p);
+               pyro = &ao_config.pyro[p];
+               if (!pyro->flags) {
+                       printf ("<disabled>\n");
+                       continue;
+               }
+               for (v = 0; ao_pyro_values[v].flag != ao_pyro_none; v++) {
+                       if (!(pyro->flags & ao_pyro_values[v].flag))
+                               continue;
+                       ao_pyro_print_name(v);
+                       if (ao_pyro_values[v].offset != NO_VALUE) {
+                               int16_t value;
+
+                               if (ao_pyro_values[v].flag & AO_PYRO_8_BIT_VALUE)
+                                       value = *((uint8_t *) ((char *) pyro + ao_pyro_values[v].offset));
+                               else
+                                       value = *((int16_t *) ((char *) pyro + ao_pyro_values[v].offset));
+                               printf ("%6d ", value);
+                       } else {
+                               printf ("       ");
+                       }
+               }
+               printf ("\n");
+       }
+}
+
+void
+ao_pyro_set(void)
+{
+       uint8_t p;
+       struct ao_pyro pyro_tmp;
+       char    name[AO_PYRO_NAME_LEN];
+       uint8_t c;
+       uint8_t v;
+
+       ao_cmd_white();
+
+#if ENABLE_HELP
+       switch (ao_cmd_lex_c) {
+       case '?':
+               ao_pyro_help();
+               return;
+       }
+#endif
+
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       p = ao_cmd_lex_i;
+       if (AO_PYRO_NUM <= p) {
+               printf ("invalid pyro channel %d\n", p);
+               return;
+       }
+       pyro_tmp.flags = 0;
+       for (;;) {
+               ao_cmd_white();
+               if (ao_cmd_lex_c == '\n')
+                       break;
+
+               for (c = 0; c < AO_PYRO_NAME_LEN - 1; c++) {
+                       if (ao_cmd_is_white())
+                               break;
+                       name[c] = ao_cmd_lex_c;
+                       ao_cmd_lex();
+               }
+               name[c] = '\0';
+               for (v = 0; ao_pyro_values[v].flag != ao_pyro_none; v++) {
+                       if (!strcmp (ao_pyro_values[v].name, name))
+                               break;
+               }
+               if (ao_pyro_values[v].flag == ao_pyro_none) {
+                       printf ("invalid pyro field %s\n", name);
+                       ao_cmd_status = ao_cmd_syntax_error;
+                       return;
+               }
+               pyro_tmp.flags |= ao_pyro_values[v].flag;
+               if (ao_pyro_values[v].offset != NO_VALUE) {
+                       ao_cmd_decimal();
+                       if (ao_cmd_status != ao_cmd_success)
+                               return;
+                       if (ao_pyro_values[v].flag & AO_PYRO_8_BIT_VALUE)
+                               *((uint8_t *) ((char *) &pyro_tmp + ao_pyro_values[v].offset)) = ao_cmd_lex_i;
+                       else
+                               *((int16_t *) ((char *) &pyro_tmp + ao_pyro_values[v].offset)) = ao_cmd_lex_i;
+               }
+       }
+       _ao_config_edit_start();
+       ao_config.pyro[p] = pyro_tmp;
+       _ao_config_edit_finish();
+}
+
+void
+ao_pyro_manual(uint8_t p)
+{
+       printf ("ao_pyro_manual %d\n", p);
+       if (p >= AO_PYRO_NUM) {
+               ao_cmd_status = ao_cmd_syntax_error;
+               return;
+       }
+       ao_pyro_pins_fire(1 << p);
+}
+
+void
+ao_pyro_init(void)
+{
+#if AO_PYRO_NUM > 0
+       ao_enable_output(AO_PYRO_PORT_0, AO_PYRO_PIN_0, AO_PYRO_0, 0);
+#endif
+#if AO_PYRO_NUM > 1
+       ao_enable_output(AO_PYRO_PORT_1, AO_PYRO_PIN_1, AO_PYRO_1, 0);
+#endif
+#if AO_PYRO_NUM > 2
+       ao_enable_output(AO_PYRO_PORT_2, AO_PYRO_PIN_2, AO_PYRO_2, 0);
+#endif
+#if AO_PYRO_NUM > 3
+       ao_enable_output(AO_PYRO_PORT_3, AO_PYRO_PIN_3, AO_PYRO_3, 0);
+#endif
+#if AO_PYRO_NUM > 4
+       ao_enable_output(AO_PYRO_PORT_4, AO_PYRO_PIN_4, AO_PYRO_4, 0);
+#endif
+#if AO_PYRO_NUM > 5
+       ao_enable_output(AO_PYRO_PORT_5, AO_PYRO_PIN_5, AO_PYRO_5, 0);
+#endif
+#if AO_PYRO_NUM > 6
+       ao_enable_output(AO_PYRO_PORT_6, AO_PYRO_PIN_6, AO_PYRO_6, 0);
+#endif
+#if AO_PYRO_NUM > 7
+       ao_enable_output(AO_PYRO_PORT_7, AO_PYRO_PIN_7, AO_PYRO_7, 0);
+#endif
+       ao_add_task(&ao_pyro_task, ao_pyro, "pyro");
+}
+#endif
diff --git a/src/kernel/ao_pyro.h b/src/kernel/ao_pyro.h
new file mode 100644 (file)
index 0000000..b37aaeb
--- /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.
+ */
+
+#ifndef _AO_PYRO_H_
+#define _AO_PYRO_H_
+
+enum ao_pyro_flag {
+       ao_pyro_none                    = 0x00000000,
+
+       ao_pyro_accel_less              = 0x00000001,
+       ao_pyro_accel_greater           = 0x00000002,
+
+       ao_pyro_speed_less              = 0x00000004,
+       ao_pyro_speed_greater           = 0x00000008,
+
+       ao_pyro_height_less             = 0x00000010,
+       ao_pyro_height_greater          = 0x00000020,
+
+       ao_pyro_orient_less             = 0x00000040,
+       ao_pyro_orient_greater          = 0x00000080,
+
+       ao_pyro_time_less               = 0x00000100,
+       ao_pyro_time_greater            = 0x00000200,
+
+       ao_pyro_ascending               = 0x00000400,
+       ao_pyro_descending              = 0x00000800,
+
+       ao_pyro_after_motor             = 0x00001000,
+
+       ao_pyro_delay                   = 0x00002000,
+
+       ao_pyro_state_less              = 0x00004000,
+       ao_pyro_state_greater_or_equal  = 0x00008000,
+}
+#ifdef __GNUC__
+       __attribute__ ((packed))
+#endif
+       ;
+
+struct ao_pyro {
+       enum ao_pyro_flag       flags;
+       int16_t                 accel_less, accel_greater;
+       int16_t                 speed_less, speed_greater;
+       int16_t                 height_less, height_greater;
+       int16_t                 orient_less, orient_greater;
+       int16_t                 time_less, time_greater;
+       int16_t                 delay;
+       uint8_t                 state_less, state_greater_or_equal;
+       int16_t                 motor;
+       uint16_t                delay_done;
+       uint8_t                 fired;
+};
+
+#define AO_PYRO_8_BIT_VALUE    (ao_pyro_state_less|ao_pyro_state_greater_or_equal)
+
+extern uint8_t ao_pyro_wakeup;
+
+extern uint16_t        ao_pyro_fired;
+
+void
+ao_pyro_set(void);
+
+void
+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/kernel/ao_quaternion.h b/src/kernel/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/kernel/ao_radio_cmac.c b/src/kernel/ao_radio_cmac.c
new file mode 100644 (file)
index 0000000..bff848f
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * 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_radio_cmac.h>
+
+static __xdata uint8_t ao_radio_cmac_mutex;
+__pdata int8_t ao_radio_cmac_rssi;
+static __xdata uint8_t cmac_data[AO_CMAC_MAX_LEN + AO_CMAC_KEY_LEN + 2 + AO_CMAC_KEY_LEN];
+
+static uint8_t
+round_len(uint8_t len)
+{
+       uint8_t rem;
+
+       /* Make sure we transfer at least one packet, and
+        * then make sure every packet is full. Note that
+        * there is no length encoded, and that the receiver
+        * must deal with any extra bytes in the packet
+        */
+       if (len < AO_CMAC_KEY_LEN)
+               len = AO_CMAC_KEY_LEN;
+       rem = len % AO_CMAC_KEY_LEN;
+       if (rem != 0)
+               len += (AO_CMAC_KEY_LEN - rem);
+       return len;
+}
+
+/*
+ * Sign and deliver the data sitting in the cmac buffer
+ */
+static void
+radio_cmac_send(uint8_t len) __reentrant
+{
+       uint8_t i;
+
+       len = round_len(len);
+       /* Make sure the AES key is loaded */
+       ao_config_get();
+
+#if HAS_MONITOR
+       ao_monitor_set(0);
+#endif
+
+       ao_mutex_get(&ao_aes_mutex);
+       ao_aes_set_mode(ao_aes_mode_cbc_mac);
+       ao_aes_set_key(ao_config.aes_key);
+       ao_aes_zero_iv();
+       for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
+               if (i + AO_CMAC_KEY_LEN < len)
+                       ao_aes_run(&cmac_data[i], NULL);
+               else
+                       ao_aes_run(&cmac_data[i], &cmac_data[len]);
+       }
+       ao_mutex_put(&ao_aes_mutex);
+
+       ao_radio_send(cmac_data, len + AO_CMAC_KEY_LEN);
+}
+
+/*
+ * Receive and validate an incoming packet
+ */
+
+static int8_t
+radio_cmac_recv(uint8_t len, uint16_t timeout) __reentrant
+{
+       uint8_t i;
+
+       len = round_len(len);
+#if HAS_MONITOR
+       ao_monitor_set(0);
+#endif
+       i = ao_radio_recv(cmac_data, len + AO_CMAC_KEY_LEN + 2, timeout);
+
+       if (!i) {
+               ao_radio_cmac_rssi = 0;
+               return AO_RADIO_CMAC_TIMEOUT;
+       }
+
+       ao_radio_cmac_rssi = ao_radio_rssi;
+       if (!(cmac_data[len + AO_CMAC_KEY_LEN +1] & AO_RADIO_STATUS_CRC_OK))
+               return AO_RADIO_CMAC_CRC_ERROR;
+
+       ao_config_get();
+
+       /* Compute the packet signature
+        */
+       ao_mutex_get(&ao_aes_mutex);
+       ao_aes_set_mode(ao_aes_mode_cbc_mac);
+       ao_aes_set_key(ao_config.aes_key);
+       ao_aes_zero_iv();
+       for (i = 0; i < len; i += AO_CMAC_KEY_LEN) {
+               if (i + AO_CMAC_KEY_LEN < len)
+                       ao_aes_run(&cmac_data[i], NULL);
+               else
+                       ao_aes_run(&cmac_data[i], &cmac_data[len + AO_CMAC_KEY_LEN + 2]);
+       }
+       ao_mutex_put(&ao_aes_mutex);
+
+       /* Check the packet signature against the signature provided
+        * over the link
+        */
+        
+       if (memcmp(&cmac_data[len],
+                  &cmac_data[len + AO_CMAC_KEY_LEN + 2],
+                  AO_CMAC_KEY_LEN) != 0) {
+               return AO_RADIO_CMAC_MAC_ERROR;
+       }
+
+       return AO_RADIO_CMAC_OK;
+}
+
+int8_t
+ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant
+{
+       if (len > AO_CMAC_MAX_LEN)
+               return AO_RADIO_CMAC_LEN_ERROR;
+       ao_mutex_get(&ao_radio_cmac_mutex);
+       ao_xmemcpy(cmac_data, packet, len);
+#if AO_LED_TX
+       ao_led_on(AO_LED_TX);
+#endif
+       radio_cmac_send(len);
+#if AO_LED_TX
+       ao_led_off(AO_LED_TX);
+#endif
+       ao_mutex_put(&ao_radio_cmac_mutex);
+       return AO_RADIO_CMAC_OK;
+}
+
+int8_t
+ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant
+{
+       int8_t  i;
+       if (len > AO_CMAC_MAX_LEN)
+               return AO_RADIO_CMAC_LEN_ERROR;
+       ao_mutex_get(&ao_radio_cmac_mutex);
+#if AO_LED_RX
+       ao_led_on(AO_LED_RX);
+#endif
+       i = radio_cmac_recv(len, timeout);
+#if AO_LED_RX
+       ao_led_off(AO_LED_RX);
+#endif
+       if (i == AO_RADIO_CMAC_OK)
+               ao_xmemcpy(packet, cmac_data, len);
+       ao_mutex_put(&ao_radio_cmac_mutex);
+       return i;
+}
+
diff --git a/src/kernel/ao_radio_cmac.h b/src/kernel/ao_radio_cmac.h
new file mode 100644 (file)
index 0000000..e86f31e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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_RADIO_CMAC_H_
+#define _AO_RADIO_CMAC_H_
+
+#include <ao_aes.h>
+
+#define AO_CMAC_KEY_LEN                AO_AES_LEN
+#define AO_CMAC_MAX_LEN                (128 - AO_CMAC_KEY_LEN)
+
+extern __pdata int8_t ao_radio_cmac_rssi;
+
+int8_t
+ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant;
+
+#define AO_RADIO_CMAC_OK       0
+#define AO_RADIO_CMAC_LEN_ERROR        -1
+#define AO_RADIO_CMAC_CRC_ERROR        -2
+#define AO_RADIO_CMAC_MAC_ERROR        -3
+#define AO_RADIO_CMAC_TIMEOUT  -4
+
+int8_t
+ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant;
+
+void
+ao_radio_cmac_init(void);
+
+#endif /* _AO_RADIO_CMAC_H_ */
diff --git a/src/kernel/ao_radio_cmac_cmd.c b/src/kernel/ao_radio_cmac_cmd.c
new file mode 100644 (file)
index 0000000..6441092
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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_radio_cmac_cmd.h>
+#include <ao_radio_cmac.h>
+
+static __xdata uint8_t cmac_data[AO_CMAC_MAX_LEN];
+
+static uint8_t
+getnibble(void)
+{
+       int8_t  b;
+
+       b = ao_cmd_hexchar(getchar());
+       if (b < 0) {
+               ao_cmd_status = ao_cmd_lex_error;
+               return 0;
+       }
+       return (uint8_t) b;
+}
+
+static uint8_t
+getbyte(void)
+{
+       uint8_t b;
+       b = getnibble() << 4;
+       b |= getnibble();
+       return b;
+}
+       
+static void
+radio_cmac_send_cmd(void) __reentrant
+{
+       uint8_t i;
+       uint8_t len;
+
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       len = ao_cmd_lex_i;
+       if (len > AO_CMAC_MAX_LEN) {
+               ao_cmd_status = ao_cmd_syntax_error;
+               return;
+       }
+       flush();
+       len = ao_cmd_lex_i;
+       for (i = 0; i < len; i++) {
+               cmac_data[i] = getbyte();
+               if (ao_cmd_status != ao_cmd_success)
+                       return;
+       }
+       ao_radio_cmac_send(cmac_data, len);
+}
+
+static void
+radio_cmac_recv_cmd(void) __reentrant
+{
+       uint8_t         len, i;
+       uint16_t        timeout;
+
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       len = ao_cmd_lex_i;
+       ao_cmd_decimal();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       timeout = AO_MS_TO_TICKS(ao_cmd_lex_i);
+       i = ao_radio_cmac_recv(cmac_data, len, timeout);
+       if (i == AO_RADIO_CMAC_OK) {
+               printf ("PACKET ");
+               for (i = 0; i < len; i++)
+                       printf("%02x", cmac_data[i]);
+               printf (" %d\n", ao_radio_cmac_rssi);
+       } else
+               printf ("ERROR %d %d\n", i, ao_radio_cmac_rssi);
+}
+
+static __code struct ao_cmds ao_radio_cmac_cmds[] = {
+       { radio_cmac_send_cmd,  "s <length>\0Send AES-CMAC packet. Bytes to send follow on next line" },
+       { radio_cmac_recv_cmd,  "S <length> <timeout>\0Receive AES-CMAC packet. Timeout in ms" },
+       { 0, NULL },
+};
+
+void
+ao_radio_cmac_cmd_init(void)
+{
+       ao_cmd_register(&ao_radio_cmac_cmds[0]);
+}
diff --git a/src/kernel/ao_radio_cmac_cmd.h b/src/kernel/ao_radio_cmac_cmd.h
new file mode 100644 (file)
index 0000000..6b8782d
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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_RADIO_CMAC_CMD_H_
+#define _AO_RADIO_CMAC_CMD_H_
+
+void
+ao_radio_cmac_cmd_init(void);
+
+#endif /* _AO_RADIO_CMAC_CMD_H_ */
diff --git a/src/kernel/ao_report.c b/src/kernel/ao_report.c
new file mode 100644 (file)
index 0000000..f226315
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * 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_flight.h>
+#include <ao_sample.h>
+
+#define BIT(i,x)          ((x) ? (1 << (i)) : 0)
+#define MORSE1(a)          (1 | BIT(3,a))
+#define MORSE2(a,b)        (2 | BIT(3,a) | BIT(4,b))
+#define MORSE3(a,b,c)      (3 | BIT(3,a) | BIT(4,b) | BIT(5,c))
+#define MORSE4(a,b,c,d)    (4 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d))
+#define MORSE5(a,b,c,d,e)  (5 | BIT(3,a) | BIT(4,b) | BIT(5,c) | BIT(6,d) | BIT(7,e))
+
+static const uint8_t flight_reports[] = {
+       MORSE3(0,0,0),          /* startup, 'S' */
+       MORSE2(0,0),            /* idle 'I' */
+       MORSE4(0,1,1,0),        /* pad 'P' */
+       MORSE4(1,0,0,0),        /* boost 'B' */
+       MORSE4(0,0,1,0),        /* fast 'F' */
+       MORSE4(1,0,1,0),        /* coast 'C' */
+       MORSE3(1,0,0),          /* drogue 'D' */
+       MORSE2(1,1),            /* main 'M' */
+       MORSE4(0,1,0,0),        /* landed 'L' */
+       MORSE4(1,0,0,1),        /* invalid 'X' */
+};
+
+#if HAS_BEEP
+#define low(time)      ao_beep_for(AO_BEEP_LOW, time)
+#define mid(time)      ao_beep_for(AO_BEEP_MID, time)
+#define high(time)     ao_beep_for(AO_BEEP_HIGH, time)
+#else
+#define low(time)      ao_led_for(AO_LED_GREEN, time)
+#define mid(time)      ao_led_for(AO_LED_RED, time)
+#define high(time)     ao_led_for(AO_LED_GREEN|AO_LED_RED, time)
+#endif
+#define pause(time)    ao_delay(time)
+
+static __pdata enum ao_flight_state ao_report_state;
+
+/*
+ * Farnsworth spacing
+ *
+ * From: http://www.arrl.org/files/file/Technology/x9004008.pdf
+ *
+ *     c:      character rate in wpm
+ *     s:      overall rate in wpm
+ *     u:      unit rate (dit speed)
+ *
+ *     dit:                    u
+ *     dah:                    3u
+ *     intra-character-time:   u
+ *
+ *     u = 1.2/c
+ *
+ * Because our clock runs at 10ms, we'll round up to 70ms for u, which
+ * is about 17wpm
+ *
+ *     Farnsworth adds space between characters and
+ *     words:
+ *           60 c - 37.2 s
+ *     Ta = -------------
+ *                sc
+ *
+ *           3 Ta
+ *     Tc = ----
+ *            19
+ *
+ *           7 Ta
+ *     Tw = ----
+ *            19
+ *
+ *     Ta = total delay to add to the characters (31 units)
+ *           of a standard 50-unit "word", in seconds
+ *
+ *      Tc = period between characters, in seconds
+ *
+ *     Tw = period between words, in seconds
+ *
+ * We'll use Farnsworth spacing with c=18 and s=12:
+ *
+ *     u = 1.2/18 = 0.0667
+ *
+ *     Ta = (60 * 17 - 37.2 * 12) / (17 * 12) = 2.812
+ *
+ *     Tc = 3 * Ta / 19 = .444
+ *
+ *     Tw = 1.036
+ *
+ * Note that the values below are all reduced by 10ms; that's because
+ * the timer always adds a tick to make sure the task actually sleeps
+ * at least as long as the argument.
+ */
+
+static void
+ao_report_beep(void) __reentrant
+{
+       uint8_t r = flight_reports[ao_flight_state];
+       uint8_t l = r & 7;
+
+       if (!r)
+               return;
+       while (l--) {
+               if (r & 8)
+                       mid(AO_MS_TO_TICKS(200));
+               else
+                       mid(AO_MS_TO_TICKS(60));
+               pause(AO_MS_TO_TICKS(60));
+               r >>= 1;
+       }
+       pause(AO_MS_TO_TICKS(360));
+}
+
+static void
+ao_report_digit(uint8_t digit) __reentrant
+{
+       if (!digit) {
+               mid(AO_MS_TO_TICKS(500));
+               pause(AO_MS_TO_TICKS(200));
+       } else {
+               while (digit--) {
+                       mid(AO_MS_TO_TICKS(200));
+                       pause(AO_MS_TO_TICKS(200));
+               }
+       }
+       pause(AO_MS_TO_TICKS(300));
+}
+
+static void
+ao_report_number(int16_t n)
+{
+       __xdata uint8_t digits[10];
+       __pdata uint8_t ndigits, i;
+
+       if (n < 0)
+               n = 0;
+       ndigits = 0;
+       do {
+               digits[ndigits++] = n % 10;
+               n /= 10;
+       } while (n);
+
+       i = ndigits;
+       do
+               ao_report_digit(digits[--i]);
+       while (i != 0);
+}
+
+static void
+ao_report_altitude(void)
+{
+       ao_report_number(ao_max_height);
+}
+
+#if HAS_BATTERY_REPORT
+static void
+ao_report_battery(void)
+{
+       __xdata struct ao_data packet;
+       for (;;) {
+               ao_data_get(&packet);
+               if (packet.adc.v_batt != 0)
+                       break;
+               ao_sleep(DATA_TO_XDATA(&ao_sample_data));
+       }
+       ao_report_number(ao_battery_decivolt(packet.adc.v_batt));
+}
+#endif
+
+#if HAS_IGNITE_REPORT
+static uint8_t
+ao_report_igniter_ready(enum ao_igniter igniter)
+{
+       return ao_igniter_status(igniter) == ao_igniter_ready ? 1 : 0;
+}
+
+uint8_t
+ao_report_igniter(void)
+{
+       return (ao_report_igniter_ready(ao_igniter_drogue) |
+                    (ao_report_igniter_ready(ao_igniter_main) << 1));
+}
+
+static void
+ao_report_continuity(void) __reentrant
+{
+       uint8_t c;
+
+#if !HAS_IGNITE
+       if (!ao_igniter_present)
+               return;
+#endif
+       c = ao_report_igniter();
+       if (c) {
+               while (c--) {
+                       high(AO_MS_TO_TICKS(25));
+                       pause(AO_MS_TO_TICKS(100));
+               }
+       } else {
+               c = 10;
+               while (c--) {
+                       high(AO_MS_TO_TICKS(20));
+                       low(AO_MS_TO_TICKS(20));
+               }
+       }
+#if HAS_LOG
+       if (ao_log_full()) {
+               pause(AO_MS_TO_TICKS(100));
+               c = 2;
+               while (c--) {
+                       low(AO_MS_TO_TICKS(100));
+                       mid(AO_MS_TO_TICKS(100));
+                       high(AO_MS_TO_TICKS(100));
+                       mid(AO_MS_TO_TICKS(100));
+               }
+       }
+#endif
+}
+#endif
+
+void
+ao_report(void)
+{
+       ao_report_state = ao_flight_state;
+       for(;;) {
+#if HAS_BATTERY_REPORT
+               if (ao_flight_state == ao_flight_startup)
+                       ao_report_battery();
+               else
+#endif
+                       ao_report_beep();
+               if (ao_flight_state == ao_flight_landed) {
+                       ao_report_altitude();
+#if HAS_FLIGHT
+                       ao_delay(AO_SEC_TO_TICKS(5));
+                       continue;
+#endif
+               }
+#if HAS_IGNITE_REPORT
+               if (ao_flight_state == ao_flight_idle)
+                       ao_report_continuity();
+               while (ao_flight_state == ao_flight_pad) {
+                       uint8_t c;
+                       ao_report_continuity();
+                       c = 50;
+                       while (c-- && ao_flight_state == ao_flight_pad)
+                               pause(AO_MS_TO_TICKS(100));
+               }
+#endif
+
+               while (ao_report_state == ao_flight_state)
+                       ao_sleep(DATA_TO_XDATA(&ao_flight_state));
+               ao_report_state = ao_flight_state;
+       }
+}
+
+static __xdata struct ao_task ao_report_task;
+
+void
+ao_report_init(void)
+{
+       ao_add_task(&ao_report_task, ao_report, "report");
+}
diff --git a/src/kernel/ao_report_micro.c b/src/kernel/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);
+}
diff --git a/src/kernel/ao_rssi.c b/src/kernel/ao_rssi.c
new file mode 100644 (file)
index 0000000..244a84f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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"
+
+static __xdata uint16_t        ao_rssi_time;
+static __pdata uint16_t        ao_rssi_delay;
+static __pdata uint8_t ao_rssi_led;
+
+void
+ao_rssi(void)
+{
+       for (;;) {
+               while ((int16_t) (ao_time() - ao_rssi_time) > AO_SEC_TO_TICKS(3))
+                       ao_sleep(&ao_rssi_time);
+               ao_led_for(ao_rssi_led, AO_MS_TO_TICKS(100));
+               ao_delay(ao_rssi_delay);
+       }
+}
+
+void
+ao_rssi_set(int rssi_value)
+{
+       if (rssi_value > 0)
+               rssi_value = 0;
+       ao_rssi_delay = AO_MS_TO_TICKS((-rssi_value) * 5);
+       ao_rssi_time = ao_time();
+       ao_wakeup(&ao_rssi_time);
+}
+
+__xdata struct ao_task ao_rssi_task;
+
+void
+ao_rssi_init(uint8_t rssi_led)
+{
+       ao_rssi_led = rssi_led;
+       ao_rssi_delay = 0;
+       ao_add_task(&ao_rssi_task, ao_rssi, "rssi");
+}
diff --git a/src/kernel/ao_sample.c b/src/kernel/ao_sample.c
new file mode 100644 (file)
index 0000000..3465895
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * 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_FLIGHT_TEST
+#include "ao.h"
+#include <ao_data.h>
+#endif
+
+#if HAS_GYRO
+#include <ao_quaternion.h>
+#endif
+
+/*
+ * Current sensor values
+ */
+
+#ifndef PRES_TYPE
+#define PRES_TYPE int32_t
+#define ALT_TYPE int32_t
+#define ACCEL_TYPE int16_t
+#endif
+
+__pdata uint16_t       ao_sample_tick;         /* time of last data */
+__pdata pres_t         ao_sample_pres;
+__pdata alt_t          ao_sample_alt;
+__pdata alt_t          ao_sample_height;
+#if HAS_ACCEL
+__pdata accel_t                ao_sample_accel;
+#endif
+#if HAS_GYRO
+__pdata accel_t                ao_sample_accel_along;
+__pdata accel_t                ao_sample_accel_across;
+__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_orient;
+#endif
+
+__data uint8_t         ao_sample_data;
+
+/*
+ * Sensor calibration values
+ */
+
+__pdata pres_t         ao_ground_pres;         /* startup pressure */
+__pdata alt_t          ao_ground_height;       /* MSL of ao_ground_pres */
+
+#if HAS_ACCEL
+__pdata accel_t                ao_ground_accel;        /* startup acceleration */
+__pdata accel_t                ao_accel_2g;            /* factory accel calibration */
+__pdata int32_t                ao_accel_scale;         /* sensor to m/s² conversion */
+#endif
+
+#if HAS_GYRO
+__pdata accel_t                ao_ground_accel_along;
+__pdata accel_t                ao_ground_accel_across;
+__pdata accel_t                ao_ground_accel_through;
+__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 */
+
+static __pdata uint16_t        nsamples;
+__pdata int32_t ao_sample_pres_sum;
+#if HAS_ACCEL
+__pdata int32_t ao_sample_accel_sum;
+#endif
+#if HAS_GYRO
+__pdata int32_t ao_sample_accel_along_sum;
+__pdata int32_t ao_sample_accel_across_sum;
+__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
+
+#if HAS_FLIGHT_DEBUG
+extern uint8_t ao_orient_test;
+#endif
+
+static void
+ao_sample_preflight_add(void)
+{
+#if HAS_ACCEL
+       ao_sample_accel_sum += ao_sample_accel;
+#endif
+       ao_sample_pres_sum += ao_sample_pres;
+#if HAS_GYRO
+       ao_sample_accel_along_sum += ao_sample_accel_along;
+       ao_sample_accel_across_sum += ao_sample_accel_across;
+       ao_sample_accel_through_sum += ao_sample_accel_through;
+       ao_sample_pitch_sum += ao_sample_pitch;
+       ao_sample_yaw_sum += ao_sample_yaw;
+       ao_sample_roll_sum += ao_sample_roll;
+#endif
+       ++nsamples;
+}
+
+static void
+ao_sample_preflight_set(void)
+{
+#if HAS_ACCEL
+       ao_ground_accel = ao_sample_accel_sum >> 9;
+       ao_sample_accel_sum = 0;
+#endif
+       ao_ground_pres = ao_sample_pres_sum >> 9;
+       ao_ground_height = pres_to_altitude(ao_ground_pres);
+       ao_sample_pres_sum = 0;
+#if HAS_GYRO
+       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;
+       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_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);
+#if HAS_FLIGHT_DEBUG
+       if (ao_orient_test)
+               printf("\n\treset\n");
+#endif 
+#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);
+
+#if HAS_FLIGHT_DEBUG
+       if (ao_orient_test) {
+               printf ("rot %d %d %d orient %d     \r",
+                       (int) (x * 1000),
+                       (int) (y * 1000),
+                       (int) (z * 1000),
+                       ao_sample_orient);
+       }
+#endif
+
+}
+#endif
+
+static void
+ao_sample_preflight(void)
+{
+       /* startup state:
+        *
+        * Collect 512 samples of acceleration and pressure
+        * data and average them to find the resting values
+        */
+       if (nsamples < 512) {
+               ao_sample_preflight_add();
+       } else {
+#if HAS_ACCEL
+               ao_accel_2g = ao_config.accel_minus_g - ao_config.accel_plus_g;
+               ao_accel_scale = to_fix32(GRAVITY * 2 * 16) / ao_accel_2g;
+#endif
+               ao_sample_preflight_set();
+               ao_preflight = FALSE;
+       }
+}
+
+/*
+ * While in pad mode, constantly update the ground state by
+ * re-averaging the data.  This tracks changes in orientation, which
+ * might be caused by adjustments to the rocket on the pad and
+ * pressure, which might be caused by changes in the weather.
+ */
+
+static void
+ao_sample_preflight_update(void)
+{
+       if (nsamples < 512)
+               ao_sample_preflight_add();
+       else if (nsamples < 1024)
+               ++nsamples;
+       else
+               ao_sample_preflight_set();
+}
+
+#if 0
+#if HAS_GYRO
+static int32_t p_filt;
+static int32_t y_filt;
+
+static gyro_t inline ao_gyro(void) {
+       gyro_t  p = ao_sample_pitch - ao_ground_pitch;
+       gyro_t  y = ao_sample_yaw - ao_ground_yaw;
+
+       p_filt = p_filt - (p_filt >> 6) + p;
+       y_filt = y_filt - (y_filt >> 6) + y;
+
+       p = p_filt >> 6;
+       y = y_filt >> 6;
+       return ao_sqrt(p*p + y*y);
+}
+#endif
+#endif
+
+uint8_t
+ao_sample(void)
+{
+       ao_wakeup(DATA_TO_XDATA(&ao_sample_data));
+       ao_sleep((void *) DATA_TO_XDATA(&ao_data_head));
+       while (ao_sample_data != ao_data_head) {
+               __xdata struct ao_data *ao_data;
+
+               /* Capture a sample */
+               ao_data = (struct ao_data *) &ao_data_ring[ao_sample_data];
+               ao_sample_tick = ao_data->tick;
+
+#if HAS_BARO
+               ao_data_pres_cook(ao_data);
+               ao_sample_pres = ao_data_pres(ao_data);
+               ao_sample_alt = pres_to_altitude(ao_sample_pres);
+               ao_sample_height = ao_sample_alt - ao_ground_height;
+#endif
+
+#if HAS_ACCEL
+               ao_sample_accel = ao_data_accel_cook(ao_data);
+               if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP)
+                       ao_sample_accel = ao_data_accel_invert(ao_sample_accel);
+               ao_data_set_accel(ao_data, ao_sample_accel);
+#endif
+#if HAS_GYRO
+               ao_sample_accel_along = ao_data_along(ao_data);
+               ao_sample_accel_across = ao_data_across(ao_data);
+               ao_sample_accel_through = ao_data_through(ao_data);
+               ao_sample_pitch = ao_data_pitch(ao_data);
+               ao_sample_yaw = ao_data_yaw(ao_data);
+               ao_sample_roll = ao_data_roll(ao_data);
+#endif
+
+               if (ao_preflight)
+                       ao_sample_preflight();
+               else {
+                       if (ao_flight_state < ao_flight_boost)
+                               ao_sample_preflight_update();
+                       ao_kalman();
+#if HAS_GYRO
+                       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;
+}
+
+void
+ao_sample_init(void)
+{
+       ao_config_get();
+       nsamples = 0;
+       ao_sample_pres_sum = 0;
+       ao_sample_pres = 0;
+#if HAS_ACCEL
+       ao_sample_accel_sum = 0;
+       ao_sample_accel = 0;
+#endif
+#if HAS_GYRO
+       ao_sample_accel_along_sum = 0;
+       ao_sample_accel_across_sum = 0;
+       ao_sample_accel_through_sum = 0;
+       ao_sample_accel_along = 0;
+       ao_sample_accel_across = 0;
+       ao_sample_accel_through = 0;
+       ao_sample_pitch_sum = 0;
+       ao_sample_yaw_sum = 0;
+       ao_sample_roll_sum = 0;
+       ao_sample_pitch = 0;
+       ao_sample_yaw = 0;
+       ao_sample_roll = 0;
+       ao_sample_orient = 0;
+#endif
+       ao_sample_data = ao_data_head;
+       ao_preflight = TRUE;
+}
diff --git a/src/kernel/ao_sample.h b/src/kernel/ao_sample.h
new file mode 100644 (file)
index 0000000..16d4c50
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * 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_SAMPLE_H_
+#define _AO_SAMPLE_H_
+
+#include <ao_data.h>
+
+/*
+ * ao_sample.c
+ */
+
+/*
+ * Barometer calibration
+ *
+ * We directly sample the barometer. The specs say:
+ *
+ * Pressure range: 15-115 kPa
+ * Voltage at 115kPa: 2.82
+ * Output scale: 27mV/kPa
+ *
+ * If we want to detect launch with the barometer, we need
+ * a large enough bump to not be fooled by noise. At typical
+ * launch elevations (0-2000m), a 200Pa pressure change cooresponds
+ * to about a 20m elevation change. This is 5.4mV, or about 3LSB.
+ * As all of our calculations are done in 16 bits, we'll actually see a change
+ * of 16 times this though
+ *
+ * 27 mV/kPa * 32767 / 3300 counts/mV = 268.1 counts/kPa
+ */
+
+/* Accelerometer calibration
+ *
+ * We're sampling the accelerometer through a resistor divider which
+ * consists of 5k and 10k resistors. This multiplies the values by 2/3.
+ * That goes into the cc1111 A/D converter, which is running at 11 bits
+ * of precision with the bits in the MSB of the 16 bit value. Only positive
+ * values are used, so values should range from 0-32752 for 0-3.3V. The
+ * specs say we should see 40mV/g (uncalibrated), multiply by 2/3 for what
+ * the A/D converter sees (26.67 mV/g). We should see 32752/3300 counts/mV,
+ * for a final computation of:
+ *
+ * 26.67 mV/g * 32767/3300 counts/mV = 264.8 counts/g
+ *
+ * Zero g was measured at 16000 (we would expect 16384).
+ * Note that this value is only require to tell if the
+ * rocket is standing upright. Once that is determined,
+ * the value of the accelerometer is averaged for 100 samples
+ * to find the resting accelerometer value, which is used
+ * for all further flight computations
+ */
+
+/*
+ * Above this height, the baro sensor doesn't work
+ */
+#if HAS_MS5607
+#define AO_MAX_BARO_HEIGHT     30000
+#else
+#define AO_MAX_BARO_HEIGHT     12000
+#endif
+
+/*
+ * Above this speed, baro measurements are unreliable
+ */
+#define AO_MAX_BARO_SPEED      200
+
+#define ACCEL_NOSE_UP  (ao_accel_2g >> 2)
+
+/*
+ * Speed and acceleration are scaled by 16 to provide a bit more
+ * resolution while still having reasonable range. Note that this
+ * limits speed to 2047m/s (around mach 6) and acceleration to
+ * 2047m/s² (over 200g)
+ */
+
+#define AO_M_TO_HEIGHT(m)      ((int16_t) (m))
+#define AO_MS_TO_SPEED(ms)     ((int16_t) ((ms) * 16))
+#define AO_MSS_TO_ACCEL(mss)   ((int16_t) ((mss) * 16))
+
+extern __pdata uint16_t        ao_sample_tick;         /* time of last data */
+extern __data uint8_t  ao_sample_adc;          /* Ring position of last processed sample */
+extern __data uint8_t  ao_sample_data;         /* Ring position of last processed sample */
+
+#if HAS_BARO
+extern __pdata pres_t  ao_sample_pres;         /* most recent pressure sensor reading */
+extern __pdata alt_t   ao_sample_alt;          /* MSL of ao_sample_pres */
+extern __pdata alt_t   ao_sample_height;       /* AGL of ao_sample_pres */
+extern __pdata pres_t  ao_ground_pres;         /* startup pressure */
+extern __pdata alt_t   ao_ground_height;       /* MSL of ao_ground_pres */
+#endif
+
+#if HAS_ACCEL
+extern __pdata accel_t ao_sample_accel;        /* most recent accel sensor reading */
+extern __pdata accel_t ao_ground_accel;        /* startup acceleration */
+extern __pdata accel_t         ao_accel_2g;            /* factory accel calibration */
+extern __pdata int32_t ao_accel_scale;         /* sensor to m/s² conversion */
+#endif
+#if HAS_GYRO
+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 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);
+
+/* returns FALSE in preflight mode, TRUE in flight mode */
+uint8_t ao_sample(void);
+
+/*
+ * ao_kalman.c
+ */
+
+#define to_fix16(x) ((int16_t) ((x) * 65536.0 + 0.5))
+#define to_fix32(x) ((int32_t) ((x) * 65536.0 + 0.5))
+#define from_fix(x)    ((x) >> 16)
+
+extern __pdata int16_t                 ao_height;      /* meters */
+extern __pdata int16_t                 ao_speed;       /* m/s * 16 */
+extern __pdata int16_t                 ao_accel;       /* m/s² * 16 */
+extern __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;
+
+#if HAS_ACCEL
+extern __pdata int16_t                 ao_error_a;
+#endif
+
+void ao_kalman(void);
+
+#endif /* _AO_SAMPLE_H_ */
diff --git a/src/kernel/ao_sample_profile.c b/src/kernel/ao_sample_profile.c
new file mode 100644 (file)
index 0000000..d3743d1
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * 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_sample_profile.h>
+#include <ao_task.h>
+
+#ifndef AO_SAMPLE_PROFILE_LOW_PC
+#define AO_SAMPLE_PROFILE_LOW_PC       0x08002000
+#endif
+
+#ifndef AO_SAMPLE_PROFILE_HIGH_PC
+#define AO_SAMPLE_PROFILE_HIGH_PC      0x0800f000
+#endif
+
+#ifndef AO_SAMPLE_PROFILE_SHIFT
+#define AO_SAMPLE_PROFILE_SHIFT                6
+#endif
+
+#define AO_SAMPLE_PROFILE_RANGE                (AO_SAMPLE_PROFILE_HIGH_PC - AO_SAMPLE_PROFILE_LOW_PC)
+#define AO_SAMPLE_PROFILE_NUM          (AO_SAMPLE_PROFILE_RANGE >> AO_SAMPLE_PROFILE_SHIFT)
+
+static uint16_t        prev_tick;
+static uint16_t        samples[AO_SAMPLE_PROFILE_NUM];
+static uint8_t missed[AO_SAMPLE_PROFILE_NUM/8];
+static uint16_t max_miss;
+static uint32_t task, isr, os, idle;
+
+extern uint8_t ao_idle_loc;
+
+void
+ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr)
+{
+       uint16_t        delta = tick - prev_tick;
+
+       if (pc < AO_SAMPLE_PROFILE_LOW_PC)
+               return;
+       if (pc >= AO_SAMPLE_PROFILE_HIGH_PC)
+               return;
+       if (ao_cur_task) {
+               uint8_t         *sp;
+               int32_t         sp_delta;
+               
+               asm("mov %0,sp" : "=&r" (sp));
+               sp_delta = sp - (uint8_t *) ao_cur_task->stack;
+               if (-96 < sp_delta && sp_delta < 16)
+                       ao_panic(AO_PANIC_STACK);
+       }
+
+       if (in_isr)
+               isr += delta;
+       else if (ao_cur_task) {
+               ao_cur_task->ticks += delta;
+               task += delta;
+       } else if (pc == (uint32_t) &ao_idle_loc)
+               idle += delta;
+       else
+               os += delta;
+
+       pc -= AO_SAMPLE_PROFILE_LOW_PC;
+       pc >>= AO_SAMPLE_PROFILE_SHIFT;
+       samples[pc] += delta;
+
+       if (delta > 1)
+               missed[pc >> 3] |= (1 << (pc & 7));
+       if (delta > max_miss)
+               max_miss = delta;
+       prev_tick = tick;
+}
+
+static void
+ao_sample_profile_start(void)
+{
+       prev_tick = ao_sample_profile_timer_start();
+}
+
+static void
+ao_sample_profile_stop(void)
+{
+       ao_sample_profile_timer_stop();
+}
+
+static void
+ao_sample_profile_dump(void)
+{
+       uint16_t        a;
+       uint8_t         t;
+
+       printf ("task %6d\n", task);
+       printf ("isr  %6d\n", isr);
+       printf ("os   %6d\n", os);
+       printf ("idle %6d\n", idle);
+       printf ("irq blocked %d\n", max_miss);
+       for (t = 0; t < ao_num_tasks; t++)
+               printf ("task %6d %6d %6d %s\n",
+                       ao_tasks[t]->ticks,
+                       ao_tasks[t]->yields,
+                       ao_tasks[t]->max_run,
+                       ao_tasks[t]->name);
+       for (a = 0; a < AO_SAMPLE_PROFILE_NUM; a++) {
+               if (samples[a])
+                       printf ("%04x %c %u\n",
+                               (a << AO_SAMPLE_PROFILE_SHIFT) + AO_SAMPLE_PROFILE_LOW_PC,
+                               missed[a >> 3] & (1 << (a & 7)) ? '*' : ' ',
+                               samples[a]);
+       }
+}
+
+static void
+ao_sample_profile_clear(void)
+{
+       int t;
+
+       task = isr = os = idle = 0;
+       max_miss = 0;
+       memset(samples, '\0', sizeof (samples));
+       memset(missed, '\0', sizeof (missed));
+       for (t = 0; t < ao_num_tasks; t++) {
+               ao_tasks[t]->ticks = 0;
+               ao_tasks[t]->yields = 0;
+               ao_tasks[t]->max_run = 0;
+       }
+}
+
+static void
+ao_sample_profile_cmd(void)
+{
+       ao_cmd_white();
+       switch (ao_cmd_lex_c) {
+       case '1':
+               ao_sample_profile_start();
+               break;
+       case '0':
+               ao_sample_profile_stop();
+               break;
+       case 'd':
+               ao_sample_profile_dump();
+               break;
+       case 'c':
+               ao_sample_profile_clear();
+               break;
+       default:
+               ao_cmd_status = ao_cmd_syntax_error;
+               break;
+       }
+}
+
+static __code struct ao_cmds ao_sample_profile_cmds[] = {
+       { ao_sample_profile_cmd,        "S <1 start,0 stop, d dump,c clear>\0Sample profile" },
+       { 0, NULL }
+};
+
+void
+ao_sample_profile_init(void)
+{
+       ao_sample_profile_timer_init();
+       ao_cmd_register(&ao_sample_profile_cmds[0]);
+       ao_sample_profile_clear();
+}
diff --git a/src/kernel/ao_sample_profile.h b/src/kernel/ao_sample_profile.h
new file mode 100644 (file)
index 0000000..dbc29d3
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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_SAMPLE_PROFILE_H_
+#define _AO_SAMPLE_PROFILE_H_
+
+#include <ao_sample_profile_timer.h>
+
+void
+ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr);
+
+void
+ao_sample_profile_init(void);
+
+#endif /* _AO_SAMPLE_PROFILE_H_ */
diff --git a/src/kernel/ao_send_packet.c b/src/kernel/ao_send_packet.c
new file mode 100644 (file)
index 0000000..66315d2
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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 AO_MAX_SEND    128
+
+static __xdata uint8_t ao_send[AO_MAX_SEND];
+
+static void
+ao_send_packet(void)
+{
+       __pdata uint16_t count;
+       uint8_t b;
+       __pdata uint8_t i;
+
+       ao_cmd_hex();
+       count = ao_cmd_lex_i;
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       if (count > AO_MAX_SEND - 2) {
+               ao_cmd_status = ao_cmd_syntax_error;
+               return;
+       }
+       for (i = 0; i < count; i++) {
+               b = ao_getnibble() << 4;
+               b |= ao_getnibble();
+               if (ao_cmd_status != ao_cmd_success)
+                       return;
+               ao_send[i] = b;
+       }
+       ao_radio_send(ao_send, count);
+}
+
+static __code struct ao_cmds ao_send_packet_cmds[] = {
+       { ao_send_packet, "S <len>\0Send packet. Data on next line" },
+       { 0, NULL }
+};
+
+void
+ao_send_packet_init(void)
+{
+       ao_cmd_register(&ao_send_packet_cmds[0]);
+}
diff --git a/src/kernel/ao_send_packet.h b/src/kernel/ao_send_packet.h
new file mode 100644 (file)
index 0000000..526f7b5
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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_SEND_PACKET_H_
+#define _AO_SEND_PACKET_H_
+
+void
+ao_send_packet_init(void);
+
+#endif /* _AO_SEND_PACKET_H_ */
diff --git a/src/kernel/ao_serial.h b/src/kernel/ao_serial.h
new file mode 100644 (file)
index 0000000..baf213c
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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_SERIAL_H_
+#define _AO_SERIAL_H_
+
+#define AO_SERIAL_SPEED_4800   0
+#define AO_SERIAL_SPEED_9600   1
+#define AO_SERIAL_SPEED_19200  2
+#define AO_SERIAL_SPEED_57600  3
+#define AO_SERIAL_SPEED_115200 4
+
+#if HAS_SERIAL_0
+extern volatile __xdata struct ao_fifo ao_serial0_rx_fifo;
+extern volatile __xdata struct ao_fifo ao_serial0_tx_fifo;
+
+char
+ao_serial0_getchar(void);
+
+int
+_ao_serial0_pollchar(void);
+
+void
+ao_serial0_putchar(char c);
+
+void
+ao_serial0_drain(void);
+
+void
+ao_serial0_set_speed(uint8_t speed);
+#endif
+
+#if HAS_SERIAL_1
+extern volatile __xdata struct ao_fifo ao_serial1_rx_fifo;
+extern volatile __xdata struct ao_fifo ao_serial1_tx_fifo;
+
+char
+ao_serial1_getchar(void);
+
+int
+_ao_serial1_pollchar(void);
+
+void
+ao_serial1_putchar(char c);
+
+void
+ao_serial1_drain(void);
+
+void
+ao_serial1_set_speed(uint8_t speed);
+#endif
+
+#if HAS_SERIAL_2
+extern volatile __xdata struct ao_fifo ao_serial2_rx_fifo;
+extern volatile __xdata struct ao_fifo ao_serial2_tx_fifo;
+
+char
+ao_serial2_getchar(void);
+
+int
+_ao_serial2_pollchar(void);
+
+void
+ao_serial2_putchar(char c);
+
+void
+ao_serial2_drain(void);
+
+void
+ao_serial2_set_speed(uint8_t speed);
+#endif
+
+#if HAS_SERIAL_3
+extern volatile __xdata struct ao_fifo ao_serial3_rx_fifo;
+extern volatile __xdata struct ao_fifo ao_serial3_tx_fifo;
+
+char
+ao_serial3_getchar(void);
+
+int
+_ao_serial3_pollchar(void);
+
+void
+ao_serial3_putchar(char c);
+
+void
+ao_serial3_drain(void);
+
+void
+ao_serial3_set_speed(uint8_t speed);
+#endif
+
+void
+ao_serial_init(void);
+
+#endif /* _AO_SERIAL_H_ */
diff --git a/src/kernel/ao_sqrt.c b/src/kernel/ao_sqrt.c
new file mode 100644 (file)
index 0000000..3a550ea
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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_FLIGHT_TEST
+#include "ao.h"
+#endif
+
+/* Adapted from int_sqrt.c in the linux kernel, which is licensed GPLv2 */
+/**
+ * int_sqrt - rough approximation to sqrt
+ * @x: integer of which to calculate the sqrt
+ *
+ * A very rough approximation to the sqrt() function.
+ */
+
+uint32_t
+ao_sqrt(uint32_t op)
+{
+       uint32_t        res = 0;
+       uint32_t        one = 1UL << (sizeof (one) * 8 - 2);
+
+       while (one > op)
+               one >>= 2;
+
+       while (one != 0) {
+               if (op >= res + one) {
+                       op = op - (res + one);
+                       res = res +  2 * one;
+               }
+               res /= 2;
+               one /= 4;
+       }
+       return res;
+}
diff --git a/src/kernel/ao_state.c b/src/kernel/ao_state.c
new file mode 100644 (file)
index 0000000..ed197aa
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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"
+
+const char const * const ao_state_names[] = {
+       "startup", "idle", "pad", "boost", "fast",
+       "coast", "drogue", "main", "landed", "invalid"
+};
diff --git a/src/kernel/ao_stdio.c b/src/kernel/ao_stdio.c
new file mode 100644 (file)
index 0000000..9911813
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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"
+
+/*
+ * Basic I/O functions to support SDCC stdio package
+ */
+
+#ifndef USE_SERIAL_0_STDIN
+#define USE_SERIAL_0_STDIN     0
+#endif
+#ifndef USE_SERIAL_1_STDIN
+#define USE_SERIAL_1_STDIN     0
+#endif
+#ifndef USE_SERIAL_2_STDIN
+#define USE_SERIAL_2_STDIN     0
+#endif
+#ifndef USE_SERIAL_3_STDIN
+#define USE_SERIAL_3_STDIN     0
+#endif
+#ifndef USE_SERIAL_4_STDIN
+#define USE_SERIAL_4_STDIN     0
+#endif
+#ifndef USE_SERIAL_5_STDIN
+#define USE_SERIAL_5_STDIN     0
+#endif
+#ifndef USE_SERIAL_6_STDIN
+#define USE_SERIAL_6_STDIN     0
+#endif
+#ifndef USE_SERIAL_7_STDIN
+#define USE_SERIAL_7_STDIN     0
+#endif
+#ifndef USE_SERIAL_8_STDIN
+#define USE_SERIAL_8_STDIN     0
+#endif
+#ifndef USE_SERIAL_9_STDIN
+#define USE_SERIAL_9_STDIN     0
+#endif
+#ifndef PACKET_HAS_SLAVE
+#define PACKET_HAS_SLAVE       0
+#endif
+
+#define USE_SERIAL_STDIN (USE_SERIAL_0_STDIN + \
+                         USE_SERIAL_1_STDIN +  \
+                         USE_SERIAL_2_STDIN +  \
+                         USE_SERIAL_3_STDIN +  \
+                         USE_SERIAL_4_STDIN +  \
+                         USE_SERIAL_5_STDIN +  \
+                         USE_SERIAL_6_STDIN +  \
+                         USE_SERIAL_7_STDIN +  \
+                         USE_SERIAL_8_STDIN +  \
+                         USE_SERIAL_9_STDIN)
+
+#define AO_NUM_STDIOS  (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN)
+
+__xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS];
+
+#if AO_NUM_STDIOS > 1
+__pdata int8_t ao_cur_stdio;
+__pdata int8_t ao_num_stdios;
+#else
+__pdata int8_t ao_cur_stdio;
+#define ao_cur_stdio   0
+#define ao_num_stdios  0
+#endif
+
+void
+putchar(char c)
+{
+#if LOW_LEVEL_DEBUG
+       if (!ao_cur_task) {
+               extern void ao_debug_out(char c);
+               if (c == '\n')
+                       ao_debug_out('\r');
+               ao_debug_out(c);
+               return;
+       }
+#endif
+       if (c == '\n')
+               (*ao_stdios[ao_cur_stdio].putchar)('\r');
+       (*ao_stdios[ao_cur_stdio].putchar)(c);
+}
+
+void
+flush(void)
+{
+       if (ao_stdios[ao_cur_stdio].flush)
+               ao_stdios[ao_cur_stdio].flush();
+}
+
+__xdata uint8_t ao_stdin_ready;
+
+char
+getchar(void) __reentrant
+{
+       int c;
+       int8_t stdio;
+
+       ao_arch_block_interrupts();
+       stdio = ao_cur_stdio;
+       for (;;) {
+               c = ao_stdios[stdio]._pollchar();
+               if (c != AO_READ_AGAIN)
+                       break;
+#if AO_NUM_STDIOS > 1
+               if (++stdio == ao_num_stdios)
+                       stdio = 0;
+               if (stdio == ao_cur_stdio)
+#endif
+                       ao_sleep(&ao_stdin_ready);
+       }
+#if AO_NUM_STDIOS > 1
+       ao_cur_stdio = stdio;
+#endif
+       ao_arch_release_interrupts();
+       return c;
+}
+
+uint8_t
+ao_echo(void)
+{
+       return ao_stdios[ao_cur_stdio].echo;
+}
+
+int8_t
+ao_add_stdio(int (*_pollchar)(void),
+            void (*putchar)(char),
+            void (*flush)(void)) __reentrant
+{
+#if AO_NUM_STDIOS > 1
+       if (ao_num_stdios == AO_NUM_STDIOS)
+               ao_panic(AO_PANIC_STDIO);
+#endif
+       ao_stdios[ao_num_stdios]._pollchar = _pollchar;
+       ao_stdios[ao_num_stdios].putchar = putchar;
+       ao_stdios[ao_num_stdios].flush = flush;
+       ao_stdios[ao_num_stdios].echo = 1;
+#if AO_NUM_STDIOS > 1
+       return ao_num_stdios++;
+#else
+       return 0;
+#endif
+}
diff --git a/src/kernel/ao_storage.c b/src/kernel/ao_storage.c
new file mode 100644 (file)
index 0000000..6eddae7
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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_storage.h>
+
+uint8_t
+ao_storage_read(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant
+{
+       uint16_t this_len;
+       uint16_t this_off;
+
+       ao_storage_setup();
+       if (pos >= ao_storage_total || pos + len > ao_storage_total)
+               return 0;
+       while (len) {
+
+               /* Compute portion of transfer within
+                * a single block
+                */
+               this_off = (uint16_t) pos & (ao_storage_unit - 1);
+               this_len = ao_storage_unit - this_off;
+               if (this_len > len)
+                       this_len = len;
+
+               if (!ao_storage_device_read(pos, buf, this_len))
+                       return 0;
+
+               /* See how much is left */
+               buf += this_len;
+               len -= this_len;
+               pos += this_len;
+       }
+       return 1;
+}
+
+uint8_t
+ao_storage_write(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant
+{
+       uint16_t this_len;
+       uint16_t this_off;
+
+       ao_storage_setup();
+       if (pos >= ao_storage_total || pos + len > ao_storage_total)
+               return 0;
+       while (len) {
+
+               /* Compute portion of transfer within
+                * a single block
+                */
+               this_off = (uint16_t) pos & (ao_storage_unit - 1);
+               this_len = ao_storage_unit - this_off;
+               if (this_len > len)
+                       this_len = len;
+
+               if (!ao_storage_device_write(pos, buf, this_len))
+                       return 0;
+
+               /* See how much is left */
+               buf += this_len;
+               len -= this_len;
+               pos += this_len;
+       }
+       return 1;
+}
+
+static __xdata uint8_t storage_data[8];
+
+static void
+ao_storage_dump(void) __reentrant
+{
+       uint8_t i, j;
+
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       for (i = 0; ; i += 8) {
+               if (ao_storage_read(((uint32_t) (ao_cmd_lex_i) << 8) + i,
+                                 storage_data,
+                                 8)) {
+                       ao_cmd_put16((uint16_t) i);
+                       for (j = 0; j < 8; j++) {
+                               putchar(' ');
+                               ao_cmd_put8(storage_data[j]);
+                       }
+                       putchar ('\n');
+               }
+               if (i == 248)
+                       break;
+       }
+}
+
+#if HAS_STORAGE_DEBUG
+
+/* not enough space for this today
+ */
+static void
+ao_storage_store(void) __reentrant
+{
+       uint16_t block;
+       uint8_t i;
+       uint16_t len;
+       static __xdata uint8_t b;
+       uint32_t addr;
+
+       ao_cmd_hex();
+       block = ao_cmd_lex_i;
+       ao_cmd_hex();
+       i = ao_cmd_lex_i;
+       addr = ((uint32_t) block << 8) | i;
+       ao_cmd_hex();
+       len = ao_cmd_lex_i;
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       while (len--) {
+               ao_cmd_hex();
+               if (ao_cmd_status != ao_cmd_success)
+                       return;
+               b = ao_cmd_lex_i;
+               ao_storage_write(addr, &b, 1);
+               addr++;
+       }
+}
+#endif
+
+void
+ao_storage_zap(void) __reentrant
+{
+       ao_cmd_hex();
+       if (ao_cmd_status != ao_cmd_success)
+               return;
+       ao_storage_erase((uint32_t) ao_cmd_lex_i << 8);
+}
+
+void
+ao_storage_zapall(void) __reentrant
+{
+       uint32_t        pos;
+
+       ao_cmd_white();
+       if (!ao_match_word("DoIt"))
+               return;
+       for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block)
+               ao_storage_erase(pos);
+}
+
+void
+ao_storage_info(void) __reentrant
+{
+       ao_storage_setup();
+       printf("Storage size: %ld\n", (long) ao_storage_total);
+       printf("Storage erase unit: %ld\n", (long) ao_storage_block);
+       ao_storage_device_info();
+}
+
+__code struct ao_cmds ao_storage_cmds[] = {
+       { ao_storage_info, "f\0Show storage" },
+       { ao_storage_dump, "e <block>\0Dump flash" },
+#if HAS_STORAGE_DEBUG
+       { ao_storage_store, "w <block> <start> <len> <data> ...\0Write data to flash" },
+#endif
+       { ao_storage_zap, "z <block>\0Erase <block>" },
+       { ao_storage_zapall,"Z <key>\0Erase all. <key> is doit with D&I" },
+       { 0, NULL },
+};
+
+void
+ao_storage_init(void)
+{
+       ao_storage_device_init();
+       ao_cmd_register(&ao_storage_cmds[0]);
+}
diff --git a/src/kernel/ao_storage.h b/src/kernel/ao_storage.h
new file mode 100644 (file)
index 0000000..6cc6fcb
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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_STORAGE_H_
+#define _AO_STORAGE_H_
+
+/*
+ * Storage interface, provided by one of the eeprom or flash
+ * drivers
+ */
+
+#ifndef ao_storage_pos_t
+#define ao_storage_pos_t uint32_t
+#endif
+
+typedef ao_storage_pos_t ao_pos_t;
+
+/* Total bytes of available storage */
+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;
+
+/* Initialize above values. Can only be called once the OS is running */
+void
+ao_storage_setup(void) __reentrant;
+
+/* Write data. Returns 0 on failure, 1 on success */
+uint8_t
+ao_storage_write(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant;
+
+/* Read data. Returns 0 on failure, 1 on success */
+uint8_t
+ao_storage_read(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant;
+
+/* Erase a block of storage. This always clears ao_storage_block bytes */
+uint8_t
+ao_storage_erase(ao_pos_t pos) __reentrant;
+
+/* Flush any pending writes to stable storage */
+void
+ao_storage_flush(void) __reentrant;
+
+/* Initialize the storage code */
+void
+ao_storage_init(void);
+
+/*
+ * Low-level functions wrapped by ao_storage.c
+ */
+
+/* Read data within a storage unit */
+uint8_t
+ao_storage_device_read(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant;
+
+/* Write data within a storage unit */
+uint8_t
+ao_storage_device_write(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant;
+
+/* Initialize low-level device bits */
+void
+ao_storage_device_init(void);
+
+/* Print out information about flash chips */
+void
+ao_storage_device_info(void) __reentrant;
+
+#endif /* _AO_STORAGE_H_ */
diff --git a/src/kernel/ao_task.c b/src/kernel/ao_task.c
new file mode 100644 (file)
index 0000000..bafb494
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * 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_task.h>
+#if HAS_SAMPLE_PROFILE
+#include <ao_sample_profile.h>
+#endif
+#if HAS_STACK_GUARD
+#include <ao_mpu.h>
+#endif
+
+#define DEBUG  0
+
+#define AO_NO_TASK_INDEX       0xff
+
+__xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS];
+__data uint8_t ao_num_tasks;
+__xdata struct ao_task *__data ao_cur_task;
+
+#if !HAS_TASK_QUEUE
+static __data uint8_t ao_cur_task_index;
+#endif
+
+#ifdef ao_arch_task_globals
+ao_arch_task_globals
+#endif
+
+#define AO_CHECK_STACK 0
+
+#if AO_CHECK_STACK
+static uint8_t in_yield;
+
+static inline void ao_check_stack(void) {
+       uint8_t q;
+       if (!in_yield && ao_cur_task && &q < &ao_cur_task->stack[0])
+               ao_panic(AO_PANIC_STACK);
+}
+#else
+#define ao_check_stack()
+#endif
+
+#if HAS_TASK_QUEUE
+
+#define SLEEP_HASH_SIZE        17
+
+static struct ao_list  run_queue;
+static struct ao_list  alarm_queue;
+static struct ao_list  sleep_queue[SLEEP_HASH_SIZE];
+
+static void
+ao_task_to_run_queue(struct ao_task *task)
+{
+       ao_list_del(&task->queue);
+       ao_list_append(&task->queue, &run_queue);
+}
+
+static struct ao_list *
+ao_task_sleep_queue(void *wchan)
+{
+       return &sleep_queue[(uintptr_t) wchan % SLEEP_HASH_SIZE];
+}
+
+static void
+ao_task_to_sleep_queue(struct ao_task *task, void *wchan)
+{
+       ao_list_del(&task->queue);
+       ao_list_append(&task->queue, ao_task_sleep_queue(wchan));
+}
+
+#if DEBUG
+static void
+ao_task_validate_alarm_queue(void)
+{
+       struct ao_task  *alarm, *prev = NULL;
+       int             i;
+
+       if (ao_list_is_empty(&alarm_queue))
+               return;
+       ao_list_for_each_entry(alarm, &alarm_queue, struct ao_task, alarm_queue) {
+               if (prev) {
+                       if ((int16_t) (alarm->alarm - prev->alarm) < 0) {
+                               ao_panic(1);
+                       }
+               }
+               prev = alarm;
+       }
+       for (i = 0; i < ao_num_tasks; i++) {
+               alarm = ao_tasks[i];
+               if (alarm->alarm) {
+                       if (ao_list_is_empty(&alarm->alarm_queue))
+                               ao_panic(2);
+               } else {
+                       if (!ao_list_is_empty(&alarm->alarm_queue))
+                               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()
+#endif
+
+uint16_t       ao_task_alarm_tick;
+
+static void
+ao_task_to_alarm_queue(struct ao_task *task)
+{
+       struct ao_task  *alarm;
+       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;
+               }
+       }
+       ao_list_append(&task->alarm_queue, &alarm_queue);
+       ao_task_alarm_tick = ao_list_first_entry(&alarm_queue, struct ao_task, alarm_queue)->alarm;
+       ao_task_validate_alarm_queue();
+}
+
+static void
+ao_task_from_alarm_queue(struct ao_task *task)
+{
+       ao_list_del(&task->alarm_queue);
+       if (ao_list_is_empty(&alarm_queue))
+               ao_task_alarm_tick = 0;
+       else
+               ao_task_alarm_tick = ao_list_first_entry(&alarm_queue, struct ao_task, alarm_queue)->alarm;
+       ao_task_validate_alarm_queue();
+}
+
+static void
+ao_task_init_queue(struct ao_task *task)
+{
+       ao_list_init(&task->queue);
+       ao_list_init(&task->alarm_queue);
+}
+
+static void
+ao_task_exit_queue(struct ao_task *task)
+{
+       ao_list_del(&task->queue);
+       ao_list_del(&task->alarm_queue);
+}
+
+void
+ao_task_check_alarm(uint16_t tick)
+{
+       struct ao_task  *alarm, *next;
+
+       ao_list_for_each_entry_safe(alarm, next, &alarm_queue, struct ao_task, alarm_queue) {
+               if ((int16_t) (tick - alarm->alarm) < 0)
+                       break;
+               alarm->alarm = 0;
+               ao_task_from_alarm_queue(alarm);
+               ao_task_to_run_queue(alarm);
+       }
+}
+
+void
+ao_task_init(void)
+{
+       uint8_t i;
+       ao_list_init(&run_queue);
+       ao_list_init(&alarm_queue);
+       ao_task_alarm_tick = 0;
+       for (i = 0; i < SLEEP_HASH_SIZE; i++)
+               ao_list_init(&sleep_queue[i]);
+}
+
+#if DEBUG
+static uint8_t
+ao_task_validate_queue(struct ao_task *task)
+{
+       uint32_t flags;
+       struct ao_task *m;
+       uint8_t ret = 0;
+       struct ao_list *queue;
+
+       flags = ao_arch_irqsave();
+       if (task->wchan) {
+               queue = ao_task_sleep_queue(task->wchan);
+               ret |= 2;
+       } else {
+               queue = &run_queue;
+               ret |= 4;
+       }
+       ao_list_for_each_entry(m, queue, struct ao_task, queue) {
+               if (m == task) {
+                       ret |= 1;
+                       break;
+               }
+       }
+       ao_arch_irqrestore(flags);
+       return ret;
+}
+
+static uint8_t
+ao_task_validate_alarm(struct ao_task *task)
+{
+       uint32_t        flags;
+       struct ao_task  *m;
+       uint8_t         ret = 0;
+
+       flags = ao_arch_irqsave();
+       if (task->alarm == 0)
+               return 0xff;
+       ao_list_for_each_entry(m, &alarm_queue, struct ao_task, alarm_queue) {
+               if (m == task)
+                       ret |= 1;
+               else {
+                       if (!(ret&1)) {
+                               if ((int16_t) (m->alarm - task->alarm) > 0)
+                                       ret |= 2;
+                       } else {
+                               if ((int16_t) (task->alarm - m->alarm) > 0)
+                                       ret |= 4;
+                       }
+               }
+       }
+       ao_arch_irqrestore(flags);
+       return ret;
+}
+
+
+static void
+ao_task_validate(void)
+{
+       uint8_t         i;
+       struct ao_task  *task;
+       uint8_t         ret;
+
+       for (i = 0; i < ao_num_tasks; i++) {
+               task = ao_tasks[i];
+               ret = ao_task_validate_queue(task);
+               if (!(ret & 1)) {
+                       if (ret & 2)
+                               printf ("sleeping task not on sleep queue %s %08x\n",
+                                       task->name, task->wchan);
+                       else
+                               printf ("running task not on run queue %s\n",
+                                       task->name);
+               }
+               ret = ao_task_validate_alarm(task);
+               if (ret != 0xff) {
+                       if (!(ret & 1))
+                               printf ("alarm task not on alarm queue %s %d\n",
+                                       task->name, task->alarm);
+                       if (ret & 2)
+                               printf ("alarm queue has sooner entries after %s %d\n",
+                                       task->name, task->alarm);
+                       if (ret & 4)
+                               printf ("alarm queue has later entries before %s %d\n",
+                                       task->name, task->alarm);
+               }
+       }
+}
+#endif /* DEBUG */
+
+#endif /* HAS_TASK_QUEUE */
+
+void
+ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant
+{
+       uint8_t task_id;
+       uint8_t t;
+       if (ao_num_tasks == AO_NUM_TASKS)
+               ao_panic(AO_PANIC_NO_TASK);
+       for (task_id = 1; task_id != 0; task_id++) {
+               for (t = 0; t < ao_num_tasks; t++)
+                       if (ao_tasks[t]->task_id == task_id)
+                               break;
+               if (t == ao_num_tasks)
+                       break;
+       }
+       task->task_id = task_id;
+       task->name = name;
+       task->wchan = NULL;
+       /*
+        * Construct a stack frame so that it will 'return'
+        * to the start of the task
+        */
+       ao_arch_init_stack(task, start);
+       ao_arch_critical(
+#if HAS_TASK_QUEUE
+               ao_task_init_queue(task);
+               ao_task_to_run_queue(task);
+#endif
+               ao_tasks[ao_num_tasks] = task;
+               ao_num_tasks++;
+               );
+}
+
+__data uint8_t ao_task_minimize_latency;
+
+/* Task switching function. This must not use any stack variables */
+void
+ao_yield(void) ao_arch_naked_define
+{
+       ao_arch_save_regs();
+
+#if HAS_TASK_QUEUE
+       if (ao_cur_task == NULL)
+               ao_cur_task = ao_tasks[ao_num_tasks-1];
+#else
+       if (ao_cur_task_index == AO_NO_TASK_INDEX)
+               ao_cur_task_index = ao_num_tasks-1;
+#endif
+       else
+       {
+#if HAS_SAMPLE_PROFILE
+               uint16_t        tick = ao_sample_profile_timer_value();
+               uint16_t        run = tick - ao_cur_task->start;
+               if (run > ao_cur_task->max_run)
+                       ao_cur_task->max_run = run;
+               ++ao_cur_task->yields;
+#endif
+               ao_arch_save_stack();
+       }
+
+       ao_arch_isr_stack();
+#if !HAS_TASK_QUEUE
+       if (ao_task_minimize_latency)
+               ao_arch_release_interrupts();
+       else
+#endif
+               ao_arch_block_interrupts();
+
+#if AO_CHECK_STACK
+       in_yield = 1;
+#endif
+       /* Find a task to run. If there isn't any runnable task,
+        * this loop will run forever, which is just fine
+        */
+#if HAS_TASK_QUEUE
+       /* If the current task is running, move it to the
+        * end of the queue to allow other tasks a chance
+        */
+       if (ao_cur_task->wchan == NULL)
+               ao_task_to_run_queue(ao_cur_task);
+       ao_cur_task = NULL;
+       for (;;) {
+               ao_arch_memory_barrier();
+               if (!ao_list_is_empty(&run_queue))
+                       break;
+               /* Wait for interrupts when there's nothing ready */
+               ao_arch_wait_interrupt();
+       }
+       ao_cur_task = ao_list_first_entry(&run_queue, struct ao_task, queue);
+#else
+       {
+               __pdata uint8_t ao_last_task_index = ao_cur_task_index;
+               for (;;) {
+                       ++ao_cur_task_index;
+                       if (ao_cur_task_index == ao_num_tasks)
+                               ao_cur_task_index = 0;
+
+                       ao_cur_task = ao_tasks[ao_cur_task_index];
+
+                       /* Check for ready task */
+                       if (ao_cur_task->wchan == NULL)
+                               break;
+
+                       /* Check if the alarm is set for a time which has passed */
+                       if (ao_cur_task->alarm &&
+                           (int16_t) (ao_time() - ao_cur_task->alarm) >= 0)
+                               break;
+
+                       /* Wait for interrupts when there's nothing ready */
+                       if (ao_cur_task_index == ao_last_task_index && !ao_task_minimize_latency)
+                               ao_arch_wait_interrupt();
+               }
+       }
+#endif
+#if HAS_SAMPLE_PROFILE
+       ao_cur_task->start = ao_sample_profile_timer_value();
+#endif
+#if HAS_STACK_GUARD
+       ao_mpu_stack_guard(ao_cur_task->stack);
+#endif
+#if AO_CHECK_STACK
+       in_yield = 0;
+#endif
+       ao_arch_restore_stack();
+}
+
+uint8_t
+ao_sleep(__xdata void *wchan)
+{
+#if HAS_TASK_QUEUE
+       uint32_t flags;
+       flags = ao_arch_irqsave();
+#endif
+       ao_cur_task->wchan = wchan;
+#if HAS_TASK_QUEUE
+       ao_task_to_sleep_queue(ao_cur_task, wchan);
+       ao_arch_irqrestore(flags);
+#endif
+       ao_yield();
+       if (ao_cur_task->wchan) {
+               ao_cur_task->wchan = NULL;
+               ao_cur_task->alarm = 0;
+               return 1;
+       }
+       return 0;
+}
+
+void
+ao_wakeup(__xdata void *wchan) __reentrant
+{
+#if HAS_TASK_QUEUE
+       struct ao_task  *sleep, *next;
+       struct ao_list  *sleep_queue;
+       uint32_t        flags;
+
+       if (ao_num_tasks == 0)
+               return;
+       sleep_queue = ao_task_sleep_queue(wchan);
+       flags = ao_arch_irqsave();
+       ao_list_for_each_entry_safe(sleep, next, sleep_queue, struct ao_task, queue) {
+               if (sleep->wchan == wchan) {
+                       sleep->wchan = NULL;
+                       ao_task_to_run_queue(sleep);
+               }
+       }
+       ao_arch_irqrestore(flags);
+#else
+       uint8_t i;
+       for (i = 0; i < ao_num_tasks; i++)
+               if (ao_tasks[i]->wchan == wchan)
+                       ao_tasks[i]->wchan = NULL;
+#endif
+       ao_check_stack();
+}
+
+void
+ao_alarm(uint16_t delay)
+{
+#if HAS_TASK_QUEUE
+       uint32_t flags;
+       /* Make sure we sleep *at least* delay ticks, which means adding
+        * one to account for the fact that we may be close to the next tick
+        */
+       flags = ao_arch_irqsave();
+#endif
+       if (!(ao_cur_task->alarm = ao_time() + delay + 1))
+               ao_cur_task->alarm = 1;
+#if HAS_TASK_QUEUE
+       ao_task_to_alarm_queue(ao_cur_task);
+       ao_arch_irqrestore(flags);
+#endif
+}
+
+void
+ao_clear_alarm(void)
+{
+#if HAS_TASK_QUEUE
+       uint32_t flags;
+
+       flags = ao_arch_irqsave();
+#endif
+       ao_cur_task->alarm = 0;
+#if HAS_TASK_QUEUE
+       ao_task_from_alarm_queue(ao_cur_task);
+       ao_arch_irqrestore(flags);
+#endif
+}
+
+static __xdata uint8_t ao_forever;
+
+void
+ao_delay(uint16_t ticks)
+{
+       ao_alarm(ticks);
+       ao_sleep(&ao_forever);
+       ao_clear_alarm();
+}
+
+void
+ao_exit(void)
+{
+       uint8_t i;
+       ao_arch_block_interrupts();
+       ao_num_tasks--;
+#if HAS_TASK_QUEUE
+       for (i = 0; i < ao_num_tasks; i++)
+               if (ao_tasks[i] == ao_cur_task)
+                       break;
+       ao_task_exit_queue(ao_cur_task);
+#else
+       i = ao_cur_task_index;
+       ao_cur_task_index = AO_NO_TASK_INDEX;
+#endif
+       for (; i < ao_num_tasks; i++)
+               ao_tasks[i] = ao_tasks[i+1];
+       ao_cur_task = NULL;
+       ao_yield();
+       /* we'll never get back here */
+}
+
+#if HAS_TASK_INFO
+void
+ao_task_info(void)
+{
+       uint8_t         i;
+       __xdata struct ao_task *task;
+
+       for (i = 0; i < ao_num_tasks; i++) {
+               task = ao_tasks[i];
+               printf("%12s: wchan %04x\n",
+                      task->name,
+                      (int) task->wchan);
+       }
+#if HAS_TASK_QUEUE && DEBUG
+       ao_task_validate();
+#endif
+}
+#endif
+
+void
+ao_start_scheduler(void)
+{
+#if !HAS_TASK_QUEUE
+       ao_cur_task_index = AO_NO_TASK_INDEX;
+#endif
+       ao_cur_task = NULL;
+#if HAS_ARCH_START_SCHEDULER
+       ao_arch_start_scheduler();
+#endif
+       ao_yield();
+}
diff --git a/src/kernel/ao_task.h b/src/kernel/ao_task.h
new file mode 100644 (file)
index 0000000..9c56b48
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_TASK_H_
+#define _AO_TASK_H_
+#if HAS_TASK_QUEUE
+#include <ao_list.h>
+#endif
+
+#ifndef HAS_TASK_INFO
+#define HAS_TASK_INFO 1
+#endif
+
+/* An AltOS task */
+struct ao_task {
+       __xdata void *wchan;            /* current wait channel (NULL if running) */
+       uint16_t alarm;                 /* abort ao_sleep time */
+       ao_arch_task_members            /* any architecture-specific fields */
+       uint8_t task_id;                /* unique id */
+       __code char *name;              /* task name */
+#if HAS_TASK_QUEUE
+       struct ao_list  queue;
+       struct ao_list  alarm_queue;
+#endif
+       uint8_t stack[AO_STACK_SIZE];   /* saved stack */
+#if HAS_SAMPLE_PROFILE
+       uint32_t ticks;
+       uint32_t yields;
+       uint16_t start;
+       uint16_t max_run;
+#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];
+extern __data uint8_t ao_num_tasks;
+extern __xdata struct ao_task *__data ao_cur_task;
+extern __data uint8_t ao_task_minimize_latency;        /* Reduce IRQ latency */
+
+/*
+ ao_task.c
+ */
+
+/* Suspend the current task until wchan is awoken.
+ * returns:
+ *  0 on normal wake
+ *  1 on alarm
+ */
+uint8_t
+ao_sleep(__xdata void *wchan);
+
+/* Wake all tasks sleeping on wchan */
+void
+ao_wakeup(__xdata void *wchan) __reentrant;
+
+/* set an alarm to go off in 'delay' ticks */
+void
+ao_alarm(uint16_t delay);
+
+/* Clear any pending alarm */
+void
+ao_clear_alarm(void);
+
+/* Yield the processor to another task */
+void
+ao_yield(void) ao_arch_naked_declare;
+
+/* Add a task to the run queue */
+void
+ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *name) __reentrant;
+
+#if HAS_TASK_QUEUE
+/* Called on timer interrupt to check alarms */
+extern uint16_t        ao_task_alarm_tick;
+void
+ao_task_check_alarm(uint16_t tick);
+#endif
+
+/* Terminate the current task */
+void
+ao_exit(void);
+
+/* Dump task info to console */
+void
+ao_task_info(void);
+
+/* Start the scheduler. This will not return */
+void
+ao_start_scheduler(void);
+
+#if HAS_TASK_QUEUE
+void
+ao_task_init(void);
+#else
+#define ao_task_init()
+#endif
+
+#endif
diff --git a/src/kernel/ao_telem.h b/src/kernel/ao_telem.h
new file mode 100644 (file)
index 0000000..1a8da29
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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_TELEM_H_
+#define _AO_TELEM_H_
+
+#define AO_TELEMETRY_VERSION           4
+
+/*
+ * Telemetry version 4 and higher format:
+ *
+ * General header fields
+ *
+ *     Name            Value
+ *
+ *     VERSION         Telemetry version number (4 or more). Must be first.
+ *     c               Callsign (string, no spaces allowed)
+ *     n               Flight unit serial number (integer)
+ *     f               Flight number (integer)
+ *     r               Packet RSSI value (integer)
+ *     s               Flight computer state (string, no spaces allowed)
+ *     t               Flight computer clock (integer in centiseconds)
+ */
+
+#define AO_TELEM_VERSION       "VERSION"
+#define AO_TELEM_CALL          "c"
+#define AO_TELEM_SERIAL                "n"
+#define AO_TELEM_FLIGHT                "f"
+#define AO_TELEM_RSSI          "r"
+#define AO_TELEM_STATE         "s"
+#define AO_TELEM_TICK          "t"
+
+/*
+ * Raw sensor values
+ *
+ *     Name            Value
+ *     r_a             Accelerometer reading (integer)
+ *     r_b             Barometer reading (integer)
+ *     r_t             Thermometer reading (integer)
+ *     r_v             Battery reading (integer)
+ *     r_d             Drogue continuity (integer)
+ *     r_m             Main continuity (integer)
+ */
+
+#define AO_TELEM_RAW_ACCEL     "r_a"
+#define AO_TELEM_RAW_BARO      "r_b"
+#define AO_TELEM_RAW_THERMO    "r_t"
+#define AO_TELEM_RAW_BATT      "r_v"
+#define AO_TELEM_RAW_DROGUE    "r_d"
+#define AO_TELEM_RAW_MAIN      "r_m"
+
+/*
+ * Sensor calibration values
+ *
+ *     Name            Value
+ *     c_a             Ground accelerometer reading (integer)
+ *     c_b             Ground barometer reading (integer)
+ *     c_p             Accelerometer reading for +1g
+ *     c_m             Accelerometer reading for -1g
+ */
+
+#define AO_TELEM_CAL_ACCEL_GROUND      "c_a"
+#define AO_TELEM_CAL_BARO_GROUND       "c_b"
+#define AO_TELEM_CAL_ACCEL_PLUS                "c_p"
+#define AO_TELEM_CAL_ACCEL_MINUS       "c_m"
+
+/*
+ * Kalman state values
+ *
+ *     Name            Value
+ *     k_h             Height above pad (integer, meters)
+ *     k_s             Vertical speeed (integer, m/s * 16)
+ *     k_a             Vertical acceleration (integer, m/s² * 16)
+ */
+
+#define AO_TELEM_KALMAN_HEIGHT         "k_h"
+#define AO_TELEM_KALMAN_SPEED          "k_s"
+#define AO_TELEM_KALMAN_ACCEL          "k_a"
+
+/*
+ * Ad-hoc flight values
+ *
+ *     Name            Value
+ *     a_a             Acceleration (integer, sensor units)
+ *     a_s             Speed (integer, integrated acceleration value)
+ *     a_b             Barometer reading (integer, sensor units)
+ */
+
+#define AO_TELEM_ADHOC_ACCEL           "a_a"
+#define AO_TELEM_ADHOC_SPEED           "a_s"
+#define AO_TELEM_ADHOC_BARO            "a_b"
+
+/*
+ * GPS values
+ *
+ *     Name            Value
+ *     g               GPS state (string):
+ *                             l       locked
+ *                             u       unlocked
+ *                             e       error (missing or broken)
+ *     g_n             Number of sats used in solution
+ *     g_ns            Latitude (degrees * 10e7)
+ *     g_ew            Longitude (degrees * 10e7)
+ *     g_a             Altitude (integer meters)
+ *     g_Y             GPS year (integer)
+ *     g_M             GPS month (integer - 1-12)
+ *     g_D             GPS day (integer - 1-31)
+ *     g_h             GPS hour (integer - 0-23)
+ *     g_m             GPS minute (integer - 0-59)
+ *     g_s             GPS second (integer - 0-59)
+ *     g_v             GPS vertical speed (integer, cm/sec)
+ *     g_g             GPS horizontal speed (integer, cm/sec)
+ *     g_c             GPS course (integer, 0-359)
+ *     g_hd            GPS hdop (integer * 10)
+ *     g_vd            GPS vdop (integer * 10)
+ *     g_he            GPS h error (integer)
+ *     g_ve            GPS v error (integer)
+ */
+
+#define AO_TELEM_GPS_STATE             "g"
+#define AO_TELEM_GPS_STATE_LOCKED      'l'
+#define AO_TELEM_GPS_STATE_UNLOCKED    'u'
+#define AO_TELEM_GPS_STATE_ERROR       'e'
+#define AO_TELEM_GPS_NUM_SAT           "g_n"
+#define AO_TELEM_GPS_LATITUDE          "g_ns"
+#define AO_TELEM_GPS_LONGITUDE         "g_ew"
+#define AO_TELEM_GPS_ALTITUDE          "g_a"
+#define AO_TELEM_GPS_YEAR              "g_Y"
+#define AO_TELEM_GPS_MONTH             "g_M"
+#define AO_TELEM_GPS_DAY               "g_D"
+#define AO_TELEM_GPS_HOUR              "g_h"
+#define AO_TELEM_GPS_MINUTE            "g_m"
+#define AO_TELEM_GPS_SECOND            "g_s"
+#define AO_TELEM_GPS_VERTICAL_SPEED    "g_v"
+#define AO_TELEM_GPS_HORIZONTAL_SPEED  "g_g"
+#define AO_TELEM_GPS_COURSE            "g_c"
+#define AO_TELEM_GPS_HDOP              "g_hd"
+#define AO_TELEM_GPS_VDOP              "g_vd"
+#define AO_TELEM_GPS_HERROR            "g_he"
+#define AO_TELEM_GPS_VERROR            "g_ve"
+
+/*
+ * GPS satellite values
+ *
+ *     Name            Value
+ *     s_n             Number of satellites reported (integer)
+ *     s_v0            Space vehicle ID (integer) for report 0
+ *     s_c0            C/N0 number (integer) for report 0
+ *     s_v1            Space vehicle ID (integer) for report 1
+ *     s_c1            C/N0 number (integer) for report 1
+ *     ...
+ */
+
+#define AO_TELEM_SAT_NUM               "s_n"
+#define AO_TELEM_SAT_SVID              "s_v"
+#define AO_TELEM_SAT_C_N_0             "s_c"
+
+#endif /* _AO_TELEM_H_ */
diff --git a/src/kernel/ao_telemetry.c b/src/kernel/ao_telemetry.c
new file mode 100644 (file)
index 0000000..9f778b0
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * 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_log.h"
+#include "ao_product.h"
+
+#ifndef HAS_RDF
+#define HAS_RDF 1
+#endif
+
+static __pdata uint16_t ao_telemetry_interval;
+
+#if HAS_RDF
+static __pdata uint8_t ao_rdf = 0;
+static __pdata uint16_t ao_rdf_time;
+#endif
+
+#if HAS_APRS
+static __pdata uint16_t ao_aprs_time;
+
+#include <ao_aprs.h>
+#endif
+
+#if defined(TELEMEGA)
+#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
+
+#if defined(TELEMINI_V_1_0)
+#define AO_TELEMETRY_SENSOR    AO_TELEMETRY_SENSOR_TELEMINI
+#endif
+
+#if defined(TELENANO_V_0_1)
+#define AO_TELEMETRY_SENSOR    AO_TELEMETRY_SENSOR_TELENANO
+#endif
+
+static __xdata union ao_telemetry_all  telemetry;
+
+#if defined AO_TELEMETRY_SENSOR
+/* Send sensor packet */
+static void
+ao_send_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_SENSOR;
+
+       telemetry.sensor.state = ao_flight_state;
+#if HAS_ACCEL
+       telemetry.sensor.accel = packet->adc.accel;
+#else
+       telemetry.sensor.accel = 0;
+#endif
+       telemetry.sensor.pres = ao_data_pres(packet);
+       telemetry.sensor.temp = packet->adc.temp;
+       telemetry.sensor.v_batt = packet->adc.v_batt;
+#if HAS_IGNITE
+       telemetry.sensor.sense_d = packet->adc.sense_d;
+       telemetry.sensor.sense_m = packet->adc.sense_m;
+#else
+       telemetry.sensor.sense_d = 0;
+       telemetry.sensor.sense_m = 0;
+#endif
+
+       telemetry.sensor.acceleration = ao_accel;
+       telemetry.sensor.speed = ao_speed;
+       telemetry.sensor.height = ao_height;
+
+       telemetry.sensor.ground_pres = ao_ground_pres;
+#if HAS_ACCEL
+       telemetry.sensor.ground_accel = ao_ground_accel;
+       telemetry.sensor.accel_plus_g = ao_config.accel_plus_g;
+       telemetry.sensor.accel_minus_g = ao_config.accel_minus_g;
+#else
+       telemetry.sensor.ground_accel = 0;
+       telemetry.sensor.accel_plus_g = 0;
+       telemetry.sensor.accel_minus_g = 0;
+#endif
+
+       ao_radio_send(&telemetry, sizeof (telemetry));
+}
+#endif
+
+
+#ifdef AO_SEND_MEGA
+/* Send mega sensor packet */
+static void
+ao_send_mega_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_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);
+
+#if HAS_MPU6000
+       telemetry.mega_sensor.accel_x = packet->mpu6000.accel_x;
+       telemetry.mega_sensor.accel_y = packet->mpu6000.accel_y;
+       telemetry.mega_sensor.accel_z = packet->mpu6000.accel_z;
+
+       telemetry.mega_sensor.gyro_x = packet->mpu6000.gyro_x;
+       telemetry.mega_sensor.gyro_y = packet->mpu6000.gyro_y;
+       telemetry.mega_sensor.gyro_z = packet->mpu6000.gyro_z;
+#endif
+
+#if HAS_HMC5883
+       telemetry.mega_sensor.mag_x = packet->hmc5883.x;
+       telemetry.mega_sensor.mag_y = packet->hmc5883.y;
+       telemetry.mega_sensor.mag_z = packet->hmc5883.z;
+#endif
+
+       ao_radio_send(&telemetry, sizeof (telemetry));
+}
+
+static __pdata int8_t ao_telemetry_mega_data_max;
+static __pdata int8_t ao_telemetry_mega_data_cur;
+
+/* Send mega data packet */
+static void
+ao_send_mega_data(void)
+{
+       if (--ao_telemetry_mega_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_MEGA_DATA;
+
+               telemetry.mega_data.state = ao_flight_state;
+               telemetry.mega_data.v_batt = packet->adc.v_batt;
+               telemetry.mega_data.v_pyro = packet->adc.v_pbatt;
+
+               /* ADC range is 0-4095, so shift by four to save the high 8 bits */
+               for (i = 0; i < AO_ADC_NUM_SENSE; i++)
+                       telemetry.mega_data.sense[i] = packet->adc.sense[i] >> 4;
+
+               telemetry.mega_data.ground_pres = ao_ground_pres;
+               telemetry.mega_data.ground_accel = ao_ground_accel;
+               telemetry.mega_data.accel_plus_g = ao_config.accel_plus_g;
+               telemetry.mega_data.accel_minus_g = ao_config.accel_minus_g;
+
+               telemetry.mega_data.acceleration = ao_accel;
+               telemetry.mega_data.speed = ao_speed;
+               telemetry.mega_data.height = ao_height;
+
+               ao_radio_send(&telemetry, sizeof (telemetry));
+               ao_telemetry_mega_data_cur = ao_telemetry_mega_data_max;
+       }
+}
+#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;
+#if HAS_ACCEL
+       telemetry.metrum_sensor.accel = ao_data_accel(packet);
+#endif
+       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)];
+
+               telemetry.generic.tick = packet->tick;
+               telemetry.generic.type = AO_TELEMETRY_METRUM_DATA;
+
+               telemetry.metrum_data.ground_pres = ao_ground_pres;
+#if HAS_ACCEL
+               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;
+#else
+               telemetry.metrum_data.ground_accel = 1;
+               telemetry.metrum_data.accel_plus_g = 0;
+               telemetry.metrum_data.accel_minus_g = 2;
+#endif
+
+               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;
+
+static void
+ao_send_baro(void)
+{
+       uint8_t         sample = ao_sample_data;
+       uint8_t         samples = (sample - ao_baro_sample) & (AO_DATA_RING - 1);
+
+       if (samples > 12) {
+               ao_baro_sample = (ao_baro_sample + (samples - 12)) & (AO_DATA_RING - 1);
+               samples = 12;
+       }
+       telemetry.generic.tick = ao_data_ring[sample].tick;
+       telemetry.generic.type = AO_TELEMETRY_BARO;
+       telemetry.baro.samples = samples;
+       for (sample = 0; sample < samples; sample++) {
+               telemetry.baro.baro[sample] = ao_data_ring[ao_baro_sample].adc.pres;
+               ao_baro_sample = ao_data_ring_next(ao_baro_sample);
+       }
+       ao_radio_send(&telemetry, sizeof (telemetry));
+}
+#endif
+
+static __pdata int8_t ao_telemetry_config_max;
+static __pdata int8_t ao_telemetry_config_cur;
+
+static void
+ao_send_configuration(void)
+{
+       if (--ao_telemetry_config_cur <= 0)
+       {
+               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;
+#if AO_idProduct_NUMBER == 0x25 && HAS_ADC
+               /* TeleGPS gets battery voltage instead of apogee delay */
+               telemetry.configuration.apogee_delay = ao_data_ring[ao_data_ring_prev(ao_data_head)].adc.v_batt;
+#else
+               telemetry.configuration.apogee_delay = ao_config.apogee_delay;
+               telemetry.configuration.main_deploy = ao_config.main_deploy;
+#endif
+
+               telemetry.configuration.flight_log_max = ao_config.flight_log_max >> 10;
+               ao_xmemcpy (telemetry.configuration.callsign,
+                           ao_config.callsign,
+                           AO_MAX_CALLSIGN);
+               ao_xmemcpy (telemetry.configuration.version,
+                           CODE_TO_XDATA(ao_version),
+                           AO_MAX_VERSION);
+               ao_radio_send(&telemetry, sizeof (telemetry));
+               ao_telemetry_config_cur = ao_telemetry_config_max;
+       }
+}
+
+#if HAS_GPS
+
+static __pdata int8_t ao_telemetry_loc_cur;
+static __pdata int8_t ao_telemetry_sat_cur;
+
+static void
+ao_send_location(void)
+{
+       if (--ao_telemetry_loc_cur <= 0)
+       {
+               telemetry.generic.type = AO_TELEMETRY_LOCATION;
+               ao_mutex_get(&ao_gps_mutex);
+               ao_xmemcpy(&telemetry.location.flags,
+                      &ao_gps_data.flags,
+                      26);
+               telemetry.location.tick = ao_gps_tick;
+               ao_mutex_put(&ao_gps_mutex);
+               ao_radio_send(&telemetry, sizeof (telemetry));
+               ao_telemetry_loc_cur = ao_telemetry_config_max;
+       }
+}
+
+static void
+ao_send_satellite(void)
+{
+       if (--ao_telemetry_sat_cur <= 0)
+       {
+               telemetry.generic.type = AO_TELEMETRY_SATELLITE;
+               ao_mutex_get(&ao_gps_mutex);
+               telemetry.satellite.channels = ao_gps_tracking_data.channels;
+               ao_xmemcpy(&telemetry.satellite.sats,
+                      &ao_gps_tracking_data.sats,
+                      AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info));
+               ao_mutex_put(&ao_gps_mutex);
+               ao_radio_send(&telemetry, sizeof (telemetry));
+               ao_telemetry_sat_cur = ao_telemetry_config_max;
+       }
+}
+#endif
+
+#if HAS_COMPANION
+
+static __pdata int8_t ao_telemetry_companion_max;
+static __pdata int8_t ao_telemetry_companion_cur;
+
+static void
+ao_send_companion(void)
+{
+       if (--ao_telemetry_companion_cur <= 0) {
+               telemetry.generic.type = AO_TELEMETRY_COMPANION;
+               telemetry.companion.board_id = ao_companion_setup.board_id;
+               telemetry.companion.update_period = ao_companion_setup.update_period;
+               telemetry.companion.channels = ao_companion_setup.channels;
+               ao_mutex_get(&ao_companion_mutex);
+               ao_xmemcpy(&telemetry.companion.companion_data,
+                      ao_companion_data,
+                      ao_companion_setup.channels * 2);
+               ao_mutex_put(&ao_companion_mutex);
+               ao_radio_send(&telemetry, sizeof (telemetry));
+               ao_telemetry_companion_cur = ao_telemetry_companion_max;
+       }
+}
+#endif
+
+void
+ao_telemetry(void)
+{
+       uint16_t        time;
+       int16_t         delay;
+
+       ao_config_get();
+       if (!ao_config.radio_enable)
+               ao_exit();
+       while (!ao_flight_number)
+               ao_sleep(&ao_flight_number);
+
+       telemetry.generic.serial = ao_serial_number;
+       for (;;) {
+               while (ao_telemetry_interval == 0)
+                       ao_sleep(&telemetry);
+               time = ao_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
+                       {
+#ifdef AO_SEND_ALL_BARO
+                               ao_send_baro();
+#endif
+
+#if HAS_FLIGHT
+# ifdef AO_SEND_MEGA
+                               ao_send_mega_sensor();
+                               ao_send_mega_data();
+# 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 /* HAS_FLIGHT */
+
+#if HAS_COMPANION
+                               if (ao_companion_running)
+                                       ao_send_companion();
+#endif
+                               ao_send_configuration();
+#if HAS_GPS
+                               ao_send_location();
+                               ao_send_satellite();
+#endif
+                       }
+#ifndef AO_SEND_ALL_BARO
+#if HAS_RDF
+                       if (ao_rdf &&
+#if HAS_APRS
+                           !(ao_config.radio_enable & AO_RADIO_DISABLE_RDF) &&
+#endif /* HAS_APRS */
+                           (int16_t) (ao_time() - ao_rdf_time) >= 0)
+                       {
+#if HAS_IGNITE_REPORT
+                               uint8_t c;
+#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 /* 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)
+                       {
+                               ao_aprs_time = ao_time() + AO_SEC_TO_TICKS(ao_config.aprs_interval);
+                               ao_aprs_send();
+                       }
+#endif /* HAS_APRS */
+#endif /* !AO_SEND_ALL_BARO */
+                       time += ao_telemetry_interval;
+                       delay = time - ao_time();
+                       if (delay > 0) {
+                               ao_alarm(delay);
+                               ao_sleep(&telemetry);
+                               ao_clear_alarm();
+                       }
+                       else
+                               time = ao_time();
+               }
+       }
+}
+
+void
+ao_telemetry_set_interval(uint16_t interval)
+{
+       int8_t  cur = 0;
+       ao_telemetry_interval = interval;
+       
+#if AO_SEND_MEGA
+       if (interval > 1)
+               ao_telemetry_mega_data_max = 1;
+       else
+               ao_telemetry_mega_data_max = 2;
+       if (ao_telemetry_mega_data_max > cur)
+               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)
+               ao_companion_setup.update_period = AO_SEC_TO_TICKS(1);
+       ao_telemetry_companion_max = ao_companion_setup.update_period / interval;
+       if (ao_telemetry_companion_max > cur)
+               cur++;
+       ao_telemetry_companion_cur = cur;
+#endif
+
+       ao_telemetry_config_max = AO_SEC_TO_TICKS(1) / interval;
+#if HAS_COMPANION
+       if (ao_telemetry_config_max > cur)
+               cur++;
+       ao_telemetry_config_cur = cur;
+#endif
+
+#if HAS_GPS
+       if (ao_telemetry_config_max > cur)
+               cur++;
+       ao_telemetry_loc_cur = cur;
+       if (ao_telemetry_config_max > cur)
+               cur++;
+       ao_telemetry_sat_cur = cur;
+#endif
+       ao_wakeup(&telemetry);
+}
+
+#if HAS_RDF
+void
+ao_rdf_set(uint8_t rdf)
+{
+       ao_rdf = rdf;
+       if (rdf == 0)
+               ao_radio_rdf_abort();
+       else {
+               ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS;
+       }
+}
+#endif
+
+__xdata struct ao_task ao_telemetry_task;
+
+void
+ao_telemetry_init()
+{
+       ao_add_task(&ao_telemetry_task, ao_telemetry, "telemetry");
+}
diff --git a/src/kernel/ao_telemetry.h b/src/kernel/ao_telemetry.h
new file mode 100644 (file)
index 0000000..be7d034
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * 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_TELEMETRY_H_
+#define _AO_TELEMETRY_H_
+
+/*
+ * ao_telemetry.c
+ */
+#define AO_MAX_CALLSIGN                        8
+#define AO_MAX_VERSION                 8
+#if LEGACY_MONITOR
+#define AO_MAX_TELEMETRY               128
+#else
+#define AO_MAX_TELEMETRY               32
+#endif
+
+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;         /* 31 unused */
+       /* 32 */
+};
+
+#define AO_TELEMETRY_SATELLITE         0x06
+
+struct ao_telemetry_satellite_info {
+       uint8_t         svid;
+       uint8_t         c_n_1;
+};
+
+#define AO_TELEMETRY_SATELLITE_MAX_SAT 12
+
+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[AO_TELEMETRY_SATELLITE_MAX_SAT];   /* 6 */
+       uint8_t                                 unused[2];      /* 30 */
+       /* 32 */
+};
+
+#define AO_TELEMETRY_COMPANION         0x07
+
+#define AO_COMPANION_MAX_CHANNELS      12
+
+struct ao_telemetry_companion {
+       uint16_t                                serial;         /*  0 */
+       uint16_t                                tick;           /*  2 */
+       uint8_t                                 type;           /*  4 */
+       uint8_t                                 board_id;       /*  5 */
+
+       uint8_t                                 update_period;  /*  6 */
+       uint8_t                                 channels;       /*  7 */
+       uint16_t                                companion_data[AO_COMPANION_MAX_CHANNELS];      /*  8 */
+       /* 32 */
+};
+
+#define AO_TELEMETRY_MEGA_SENSOR       0x08
+
+struct ao_telemetry_mega_sensor {
+       uint16_t        serial;         /*  0 */
+       uint16_t        tick;           /*  2 */
+       uint8_t         type;           /*  4 */
+
+       uint8_t         orient;         /*  5 angle from vertical */
+       int16_t         accel;          /*  6 Z axis */
+
+       int32_t         pres;           /*  8 Pa * 10 */
+       int16_t         temp;           /* 12 °C * 100 */
+
+       int16_t         accel_x;        /* 14 */
+       int16_t         accel_y;        /* 16 */
+       int16_t         accel_z;        /* 18 */
+
+       int16_t         gyro_x;         /* 20 */
+       int16_t         gyro_y;         /* 22 */
+       int16_t         gyro_z;         /* 24 */
+
+       int16_t         mag_x;          /* 26 */
+       int16_t         mag_y;          /* 28 */
+       int16_t         mag_z;          /* 30 */
+       /* 32 */
+};
+
+#define AO_TELEMETRY_MEGA_DATA         0x09
+
+struct ao_telemetry_mega_data {
+       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         v_pyro;         /*  8 pyro battery voltage */
+       int8_t          sense[6];       /* 10 continuity sense */
+
+       int32_t         ground_pres;    /* 16 average pres on pad */
+       int16_t         ground_accel;   /* 20 average accel on pad */
+       int16_t         accel_plus_g;   /* 22 accel calibration at +1g */
+       int16_t         accel_minus_g;  /* 24 accel calibration at -1g */
+
+       int16_t         acceleration;   /* 26 m/s² * 16 */
+       int16_t         speed;          /* 28 m/s * 16 */
+       int16_t         height;         /* 30 m */
+       /* 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
+
+/*
+ * This packet allows the full sampling rate baro
+ * data to be captured over the RF link so that the
+ * flight software can be tested using 'real' data.
+ *
+ * Along with this telemetry packet, the flight
+ * code is modified to send full-rate telemetry all the time
+ * and never send an RDF tone; this ensure that the full radio
+ * link is available.
+ */
+struct ao_telemetry_baro {
+       uint16_t                                serial;         /*  0 */
+       uint16_t                                tick;           /*  2 */
+       uint8_t                                 type;           /*  4 */
+       uint8_t                                 samples;        /*  5 number samples */
+
+       int16_t                                 baro[12];       /* 6 samples */
+       /* 32 */
+};
+
+union ao_telemetry_all {
+       struct ao_telemetry_generic             generic;
+       struct ao_telemetry_sensor              sensor;
+       struct ao_telemetry_configuration       configuration;
+       struct ao_telemetry_location            location;
+       struct ao_telemetry_satellite           satellite;
+       struct ao_telemetry_companion           companion;
+       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;
+};
+
+struct ao_telemetry_all_recv {
+       union ao_telemetry_all          telemetry;
+       int8_t                          rssi;
+       uint8_t                         status;
+};
+
+#endif /* _AO_TELEMETRY_H_ */
diff --git a/src/kernel/ao_tracker.c b/src/kernel/ao_tracker.c
new file mode 100644 (file)
index 0000000..9febc7f
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_flight.h>
+#include <ao_log.h>
+#include <ao_log_gps.h>
+#include <ao_distance.h>
+#include <ao_tracker.h>
+#include <ao_exti.h>
+
+static uint8_t         ao_tracker_force_telem;
+
+#if HAS_USB_CONNECT
+static inline uint8_t
+ao_usb_connected(void)
+{
+       return ao_gpio_get(AO_USB_CONNECT_PORT, AO_USB_CONNECT_PIN, AO_USB_CONNECT) != 0;
+}
+#else
+#define ao_usb_connected()     1
+#endif
+
+struct gps_position {
+       int32_t latitude;
+       int32_t longitude;
+       int16_t altitude;
+};
+
+#define GPS_RING       16
+
+struct gps_position    gps_position[GPS_RING];
+
+#define ao_gps_ring_next(n)    (((n) + 1) & (GPS_RING - 1))
+#define ao_gps_ring_prev(n)    (((n) - 1) & (GPS_RING - 1))
+
+static uint8_t gps_head;
+
+static uint8_t tracker_mutex;
+static uint8_t log_started;
+static struct ao_telemetry_location gps_data;
+static uint8_t tracker_running;
+static uint16_t tracker_interval;
+
+static void
+ao_tracker(void)
+{
+       uint8_t new;
+       int32_t ground_distance;
+       int16_t height;
+       uint16_t gps_tick;
+       uint8_t new_tracker_running;
+
+#if HAS_ADC
+       ao_timer_set_adc_interval(100);
+#endif
+
+#if !HAS_USB_CONNECT
+       ao_tracker_force_telem = 1;
+#endif
+       ao_log_scan();
+
+       ao_rdf_set(1);
+
+       tracker_interval = ao_config.tracker_interval;
+       ao_gps_set_rate(tracker_interval);
+
+       for (;;) {
+
+               /** Wait for new GPS data
+                */
+               while (!(new = ao_gps_new))
+                       ao_sleep(&ao_gps_new);
+               ao_mutex_get(&ao_gps_mutex);
+               gps_data = ao_gps_data;
+               gps_tick = ao_gps_tick;
+               ao_gps_new = 0;
+               ao_mutex_put(&ao_gps_mutex);
+
+               new_tracker_running = ao_tracker_force_telem || !ao_usb_connected();
+
+               if (ao_config.tracker_interval != tracker_interval) {
+                       tracker_interval = ao_config.tracker_interval;
+                       ao_gps_set_rate(tracker_interval);
+
+                       /* force telemetry interval to be reset */
+                       tracker_running = 0;
+               }
+
+               if (new_tracker_running && !tracker_running)
+                       ao_telemetry_set_interval(AO_SEC_TO_TICKS(tracker_interval));
+               else if (!new_tracker_running && tracker_running)
+                       ao_telemetry_set_interval(0);
+
+               tracker_running = new_tracker_running;
+
+               if (new_tracker_running && !ao_log_running)
+                       ao_log_start();
+               else if (!new_tracker_running && ao_log_running)
+                       ao_log_stop();
+
+               if (!ao_log_running)
+                       continue;
+
+               if (new & AO_GPS_NEW_DATA) {
+                       if ((gps_data.flags & (AO_GPS_VALID|AO_GPS_COURSE_VALID)) ==
+                           (AO_GPS_VALID|AO_GPS_COURSE_VALID))
+                       {
+                               uint8_t ring;
+                               uint8_t moving = 0;
+
+                               for (ring = ao_gps_ring_next(gps_head); ring != gps_head; ring = ao_gps_ring_next(ring)) {
+                                       ground_distance = ao_distance(gps_data.latitude, gps_data.longitude,
+                                                                     gps_position[ring].latitude,
+                                                                     gps_position[ring].longitude);
+                                       height = gps_position[ring].altitude - gps_data.altitude;
+                                       if (height < 0)
+                                               height = -height;
+
+                                       if (ao_tracker_force_telem)
+                                               printf("head %d ring %d ground_distance %d height %d\n", gps_head, ring, ground_distance, height);
+                                       if (ground_distance > ao_config.tracker_motion ||
+                                           height > (ao_config.tracker_motion << 1))
+                                       {
+                                               moving = 1;
+                                               break;
+                                       }
+                               }
+                               if (ao_tracker_force_telem) {
+                                       printf ("moving %d started %d\n", moving, log_started);
+                                       flush();
+                               }
+                               if (moving) {
+                                       ao_mutex_get(&tracker_mutex);
+                                       if (!log_started) {
+                                               ao_log_gps_flight();
+                                               log_started = 1;
+                                       }
+                                       ao_log_gps_data(gps_tick, &gps_data);
+                                       gps_position[gps_head].latitude = gps_data.latitude;
+                                       gps_position[gps_head].longitude = gps_data.longitude;
+                                       gps_position[gps_head].altitude = gps_data.altitude;
+                                       gps_head = ao_gps_ring_next(gps_head);
+                                       ao_mutex_put(&tracker_mutex);
+                               }
+                       }
+               }
+       }
+}
+
+static uint8_t erasing_current;
+
+void
+ao_tracker_erase_start(uint16_t flight)
+{
+       erasing_current = flight == ao_flight_number;
+       if (erasing_current) {
+               ao_mutex_get(&tracker_mutex);
+               ao_log_stop();
+               if (++ao_flight_number == 0)
+                       ao_flight_number = 1;
+       }
+}
+
+void
+ao_tracker_erase_end(void)
+{
+       if (erasing_current) {
+               ao_log_scan();
+               log_started = 0;
+               ao_mutex_put(&tracker_mutex);
+       }
+}
+
+static struct ao_task ao_tracker_task;
+
+static void
+ao_tracker_set_telem(void)
+{
+       uint8_t telem;
+       ao_cmd_hex();
+       telem = ao_cmd_lex_i;
+       if (ao_cmd_status == ao_cmd_success)
+               ao_tracker_force_telem = telem;
+       ao_cmd_status = ao_cmd_success;
+       printf ("flight: %d\n", ao_flight_number);
+       printf ("force_telem: %d\n", ao_tracker_force_telem);
+       printf ("tracker_running: %d\n", tracker_running);
+       printf ("log_started: %d\n", log_started);
+       printf ("latitude: %ld\n", (long) gps_data.latitude);
+       printf ("longitude: %ld\n", (long) gps_data.longitude);
+       printf ("altitude: %d\n", gps_data.altitude);
+       printf ("log_running: %d\n", ao_log_running);
+       printf ("log_start_pos: %ld\n", (long) ao_log_start_pos);
+       printf ("log_cur_pos: %ld\n", (long) ao_log_current_pos);
+       printf ("log_end_pos: %ld\n", (long) ao_log_end_pos);
+}
+
+static const struct ao_cmds ao_tracker_cmds[] = {
+       { ao_tracker_set_telem, "t <d>\0Set telem on USB" },
+       { 0, NULL },
+};
+
+void
+ao_tracker_init(void)
+{
+#if HAS_USB_CONNECT
+       ao_enable_input(AO_USB_CONNECT_PORT, AO_USB_CONNECT_PIN, 0);
+#endif
+       ao_cmd_register(&ao_tracker_cmds[0]);
+       ao_add_task(&ao_tracker_task, ao_tracker, "tracker");
+}
diff --git a/src/kernel/ao_tracker.h b/src/kernel/ao_tracker.h
new file mode 100644 (file)
index 0000000..78c40cb
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_TRACKER_H_
+#define _AO_TRACKER_H_
+
+/* Any motion more than this will result in a log entry */
+
+#define AO_TRACKER_MOTION_DEFAULT      10
+#define AO_TRACKER_INTERVAL_DEFAULT    1
+
+#define AO_TRACKER_MOTION_COUNT                10
+
+void
+ao_tracker_init(void);
+
+void
+ao_tracker_erase_start(uint16_t flight);
+
+void
+ao_tracker_erase_end(void);
+
+#endif /* _AO_TRACKER_H_ */
diff --git a/src/kernel/ao_usb.h b/src/kernel/ao_usb.h
new file mode 100644 (file)
index 0000000..1ce4f82
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * 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_USB_H_
+#define _AO_USB_H_
+
+/*
+ * ao_usb.c
+ */
+
+/* Put one character to the USB output queue */
+void
+ao_usb_putchar(char c);
+
+/* Get one character from the USB input queue */
+char
+ao_usb_getchar(void);
+
+/* Poll for a charcter on the USB input queue.
+ * returns AO_READ_AGAIN if none are available
+ */
+int
+ao_usb_pollchar(void);
+
+/* Flush the USB output queue */
+void
+ao_usb_flush(void);
+
+/* Enable the USB controller */
+void
+ao_usb_enable(void);
+
+/* Disable the USB controller */
+void
+ao_usb_disable(void);
+
+/* Initialize the USB system */
+void
+ao_usb_init(void);
+
+extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];
+
+#define AO_USB_SETUP_DIR_MASK  (0x01 << 7)
+#define AO_USB_SETUP_TYPE_MASK (0x03 << 5)
+#define AO_USB_SETUP_RECIP_MASK        (0x1f)
+
+#define AO_USB_DIR_OUT                 0
+#define AO_USB_DIR_IN                  (1 << 7)
+
+#define AO_USB_TYPE_STANDARD           0
+#define AO_USB_TYPE_CLASS              (1 << 5)
+#define AO_USB_TYPE_VENDOR             (2 << 5)
+#define AO_USB_TYPE_RESERVED           (3 << 5)
+
+#define AO_USB_RECIP_DEVICE            0
+#define AO_USB_RECIP_INTERFACE         1
+#define AO_USB_RECIP_ENDPOINT          2
+#define AO_USB_RECIP_OTHER             3
+
+/* standard requests */
+#define        AO_USB_REQ_GET_STATUS           0x00
+#define AO_USB_REQ_CLEAR_FEATURE       0x01
+#define AO_USB_REQ_SET_FEATURE         0x03
+#define AO_USB_REQ_SET_ADDRESS         0x05
+#define AO_USB_REQ_GET_DESCRIPTOR      0x06
+#define AO_USB_REQ_SET_DESCRIPTOR      0x07
+#define AO_USB_REQ_GET_CONFIGURATION   0x08
+#define AO_USB_REQ_SET_CONFIGURATION   0x09
+#define AO_USB_REQ_GET_INTERFACE       0x0A
+#define AO_USB_REQ_SET_INTERFACE       0x0B
+#define AO_USB_REQ_SYNCH_FRAME         0x0C
+
+#define AO_USB_DESC_DEVICE             1
+#define AO_USB_DESC_CONFIGURATION      2
+#define AO_USB_DESC_STRING             3
+#define AO_USB_DESC_INTERFACE          4
+#define AO_USB_DESC_ENDPOINT           5
+#define AO_USB_DESC_DEVICE_QUALIFIER   6
+#define AO_USB_DESC_OTHER_SPEED                7
+#define AO_USB_DESC_INTERFACE_POWER    8
+
+#define AO_USB_GET_DESC_TYPE(x)                (((x)>>8)&0xFF)
+#define AO_USB_GET_DESC_INDEX(x)       ((x)&0xFF)
+
+#define AO_USB_CONTROL_EP      0
+#define AO_USB_CONTROL_SIZE    32
+
+#define AO_USB_INT_EP          1
+#define AO_USB_INT_SIZE                8
+
+#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
+ */
+#define AO_USB_IN_SIZE         64
+#define AO_USB_OUT_SIZE                64
+
+#define AO_USB_EP0_IDLE                0
+#define AO_USB_EP0_DATA_IN     1
+#define AO_USB_EP0_DATA_OUT    2
+#define AO_USB_EP0_STALL       3
+
+#define LE_WORD(x)    ((x)&0xFF),((uint8_t) (((uint16_t) (x))>>8))
+
+/* CDC definitions */
+#define AO_USB_CS_INTERFACE            0x24
+#define AO_USB_CS_ENDPOINT             0x25
+
+#define AO_USB_SET_LINE_CODING         0x20
+#define AO_USB_GET_LINE_CODING         0x21
+#define AO_USB_SET_CONTROL_LINE_STATE  0x22
+
+/* Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */
+struct ao_usb_line_coding {
+       uint32_t        rate;
+       uint8_t         char_format;
+       uint8_t         parity;
+       uint8_t         data_bits;
+} ;
+
+extern __pdata uint8_t ao_usb_running;
+
+#endif /* _AO_USB_H_ */
index fecb9135d6824f4067de9b95acb3c15b7f44471f..bccea5bc1e3ca250c905fdb94cf32eafda92d26e 100644 (file)
@@ -4,7 +4,7 @@ endif
 
 include $(TOPDIR)/Makedefs
 
-vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/core:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math
+vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math
 vpath make-altitude $(TOPDIR)/util
 vpath make-kalman $(TOPDIR)/util
 vpath kalman.5c $(TOPDIR)/kalman
@@ -28,7 +28,7 @@ CC=$(ARM_CC)
 
 WARN_FLAGS=-Wall -Wextra -Werror
 
-AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/core -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR) $(PDCLIB_INCLUDES) 
+AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR) $(PDCLIB_INCLUDES) 
 LPC_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\
        -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS)
 
index e1aae0e484d5c726910185e5c15907c41a5932f6..b24163eeb9daa3b91bdfad259879f8de81c249a7 100644 (file)
@@ -160,7 +160,7 @@ ao_adc_dump(void) __reentrant
 #else
        printf("tick: %5u",  packet.tick);
        d = (int16_t *) (&packet.adc);
-       for (i = 0; i < AO_NUM_ADC; i++)
+       for (i = 0; i < AO_ADC_NUM; i++)
                printf (" %2d: %5d", i, d[i]);
        printf("\n");
 #endif
index d04bf2c8b06d210a59b39ce39653fdcf14df0304..5fbb8dfaa0f24183341d1d78dbbc49e80cdf16b3 100644 (file)
 #define AO_STACK_SIZE  512
 #endif
 
-#define AO_LED_TYPE    uint16_t
-
 #define AO_PORT_TYPE   uint32_t
 
+#define AO_LED_TYPE    AO_PORT_TYPE
+
 #ifndef AO_TICK_TYPE
 #define AO_TICK_TYPE   uint16_t
 #define AO_TICK_SIGNED int16_t
@@ -140,7 +140,12 @@ ao_serial_init(void);
 #define AO_SPI_SPEED_FAST      AO_SPI_SPEED_12MHz
 
 #define AO_BOOT_APPLICATION_BASE       ((uint32_t *) 0x00001000)
+#define AO_BOOT_APPLICATION_BOUND      ((uint32_t *) (0x00000000 + 32 * 1024))
 #define AO_BOOT_LOADER_BASE            ((uint32_t *) 0x00000000)
 #define HAS_BOOT_LOADER                        1
 
+/* ADC definitions */
+
+#define AO_ADC_MAX     32767
+
 #endif /* _AO_ARCH_H_ */
diff --git a/src/lpc/ao_boot.h b/src/lpc/ao_boot.h
deleted file mode 100644 (file)
index e0ed4de..0000000
+++ /dev/null
@@ -1,39 +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_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_ */
index a08d1f2c647b823fec0c151a952d0a6644e8832d..9e45ba27f085eaa5e8b2d07515eaa9c14b26adc7 100644 (file)
@@ -43,14 +43,14 @@ struct ao_boot {
 };
 
 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)
+               if (ao_boot.base == AO_BOOT_FORCE_LOADER)
                        return 0;
                ao_boot_chain(ao_boot.base);
        }
index 941aa965dde3d7b8c7723c6aad94e16544dd31a9..fdb6a1caa976bef23789dc7aea69669b3b4be550 100644 (file)
@@ -69,7 +69,7 @@ _ao_exti_set_enable(uint8_t pint)
                lpc_gpio_pin.sienr = mask;
        else
                lpc_gpio_pin.cienr = mask;
-               
+
        if (mode & AO_EXTI_MODE_FALLING)
                lpc_gpio_pin.sienf = mask;
        else
@@ -98,7 +98,7 @@ ao_exti_setup (uint8_t port, uint8_t pin, uint8_t mode, void (*callback)(void))
        mask = (1 << pint);
        ao_pint_inuse |= mask;
        ao_pint_enabled &= ~mask;
-       
+
        ao_pint_map[id] = pint;
        ao_exti_callback[pint] = callback;
 
index c4dc786760b460f17bd8f20a9100e36cba7b0652..3318db2bd14ea71ed768991c07fa8eaf01291fca 100644 (file)
@@ -172,5 +172,5 @@ const void *lpc_interrupt_vector[] = {
        i(0xb0, hardfault),     /* IRQ28 */
        i(0xb4, hardfault),
        i(0xb8, usb_wakeup),
-       i(0xbc, hardfault),     
+       i(0xbc, hardfault),
 };
index 7bef51ba25cdce0e07b05b0bae002395fc940d66..d983437cd4c4549c0a64886b434d8e61f2aebe7b 100644 (file)
 
 #include <ao.h>
 
-__pdata uint16_t ao_led_enable;
+__pdata AO_PORT_TYPE ao_led_enable;
 
 void
-ao_led_on(uint16_t colors)
+ao_led_on(AO_PORT_TYPE colors)
 {
        lpc_gpio.pin[LED_PORT] |= colors;
 }
 
 void
-ao_led_off(uint16_t colors)
+ao_led_off(AO_PORT_TYPE colors)
 {
        lpc_gpio.pin[LED_PORT] &= ~colors;
 }
 
 void
-ao_led_set(uint16_t colors)
+ao_led_set(AO_PORT_TYPE colors)
 {
-       uint16_t        on = colors & ao_led_enable;
-       uint16_t        off = ~colors & ao_led_enable;
+       AO_PORT_TYPE    on = colors & ao_led_enable;
+       AO_PORT_TYPE    off = ~colors & ao_led_enable;
 
        ao_led_off(off);
        ao_led_on(on);
 }
 
 void
-ao_led_toggle(uint16_t colors)
+ao_led_toggle(AO_PORT_TYPE colors)
 {
        lpc_gpio.pin[LED_PORT] ^= colors;
 }
 
 void
-ao_led_for(uint16_t colors, uint16_t ticks) __reentrant
+ao_led_for(AO_PORT_TYPE colors, uint16_t ticks) __reentrant
 {
        ao_led_on(colors);
        ao_delay(ticks);
@@ -56,10 +56,8 @@ ao_led_for(uint16_t colors, uint16_t ticks) __reentrant
 }
 
 void
-ao_led_init(uint16_t enable)
+ao_led_init(AO_PORT_TYPE enable)
 {
-       int     bit;
-
        ao_led_enable = enable;
        lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO);
        lpc_gpio.dir[LED_PORT] |= enable;
index 431ae98a784e61aca1ca09590a8b29b334b77957..b0d5fcbc577003cc8076a73684f4f86d6abe2624 100644 (file)
@@ -206,8 +206,8 @@ ao_serial_init(void)
        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,
+       ao_add_stdio(_ao_serial0_pollchar,
+                    ao_serial0_putchar,
                     NULL);
 #endif
 }
index d02ccdd6a5cbe06ab4ab74f951765b9e66dd0f73..12f5d8e6973013c5c5113bbe9d50a97d509d9fd3 100644 (file)
@@ -109,7 +109,7 @@ static uint8_t      ao_usb_in_pending;
  * but not pulled to the shadow buffer.
  */
 static uint8_t ao_usb_out_avail;
-static uint8_t ao_usb_running;
+uint8_t                ao_usb_running;
 static uint8_t ao_usb_configuration;
 
 #define AO_USB_EP0_GOT_RESET   1
@@ -875,7 +875,7 @@ ao_usb_enable(void)
        int     t;
 
        /* Enable USB pins */
-#if HAS_USB_CONNECT
+#if HAS_LPC_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) |
index c0074ce2989ad8e97b5de8152d7765fbc2d62897..0ffc2fad3d4c5b2d6699844e476a2633c5a78e09 100644 (file)
@@ -16,7 +16,6 @@
  */
 
 #define HAS_BEEP       0
-#define        HAS_LED         1
 
 /* Crystal on the board */
 #define AO_LPC_CLKIN   12000000
index 6035c3482576e71a3bc6bbdef6960b02219b108b..ade8e4964341f7d684f6efc3dc61e9f4d58de7f0 100644 (file)
@@ -9,6 +9,7 @@ INC = \
        ao.h \
        ao_arch.h \
        ao_arch_funcs.h \
+       ao_boot.h \
        ao_pins.h \
        ao_product.h \
        ao_cc1120_CC1120.h \
index dcc328749af927de6f31484054a6d88ef177b5f4..6ae3d0be2acb08611b2119bfe611d3b7d659f02d 100644 (file)
@@ -2,12 +2,15 @@
 # Tiny AltOS build
 #
 #
-vpath % ../attiny:../drivers:../core:../product:..
+vpath % ../attiny:../drivers:../kernel:../product:..
 vpath ao-make-product.5c ../util
 vpath make-altitude-pa ../util
 
 include ../avr/Makefile.defs
 
+PUBLISH_DIR=$(HOME)/altusmetrumllc/Binaries
+PUBLISH_FILE=$(PUBLISH_DIR)/$(PROG)-$(VERSION).hex
+
 MCU=attiny85
 DUDECPUTYPE=t85
 #PROGRAMMER=stk500v2 -P usb
@@ -47,7 +50,7 @@ INC=\
 IDPRODUCT=0
 PRODUCT=MicroPeak-v0.1
 PRODUCT_DEF=-DMICROPEAK
-CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../core -I.. -I../drivers -I../product
+CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../kernel -I.. -I../drivers -I../product
 CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY
 
 NICKLE=nickle
@@ -98,6 +101,16 @@ clean:
        rm -f *.o $(PROG) $(PROG).hex
        rm -f ao_product.h
 
+
+publish: $(PROG).hex
+       cp -a $(PROG).hex $(PUBLISH_FILE)
+
+load-product:
+       $(LOADCMD) $(LOADARG)$(PUBLISH_FILE)
+
+load-product-slow:
+       $(LOADCMD) $(LOADSLOW) $(LOADARG)$(PUBLISH_FILE)
+
 ../altitude-pa.h: make-altitude-pa
        nickle $< > $@
 
diff --git a/src/microwater/.gitignore b/src/microwater/.gitignore
new file mode 100644 (file)
index 0000000..0573d98
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+microwater-*
diff --git a/src/microwater/Makefile b/src/microwater/Makefile
new file mode 100644 (file)
index 0000000..a49cda4
--- /dev/null
@@ -0,0 +1,121 @@
+#
+# Tiny AltOS build
+#
+#
+vpath % ../attiny:../drivers:../kernel:../product:..
+vpath ao-make-product.5c ../util
+vpath make-altitude-pa ../util
+
+include ../avr/Makefile.defs
+
+PUBLISH_DIR=$(HOME)/altusmetrumllc/Binaries
+PUBLISH_FILE=$(PUBLISH_DIR)/$(PROG)-$(VERSION).hex
+
+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=MicroWater-v0.1
+PRODUCT_DEF=-DMICROPEAK
+CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../kernel -I.. -I../drivers -I../product
+CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY
+
+NICKLE=nickle
+
+PROG=microwater-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
+
+
+publish: $(PROG).hex
+       cp -a $(PROG).hex $(PUBLISH_FILE)
+
+load-product:
+       $(LOADCMD) $(LOADARG)$(PUBLISH_FILE)
+
+load-product-slow:
+       $(LOADCMD) $(LOADSLOW) $(LOADARG)$(PUBLISH_FILE)
+
+../altitude-pa.h: make-altitude-pa
+       nickle $< > $@
+
+install:
+
+uninstall:
+
+$(OBJ): ao_product.h $(INC)
diff --git a/src/microwater/ao_pins.h b/src/microwater/ao_pins.h
new file mode 100644 (file)
index 0000000..37885ec
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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<<4)
+#define AO_LED_SERIAL          4
+#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       3
+
+/* 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)
+
+/* Pressure change (in Pa) to detect boost */
+#ifndef BOOST_DETECT
+#define BOOST_DETECT           120     /* 10m at sea level, 12m at 2000m */
+#endif
+
+#endif /* _AO_PINS_H_ */
index 04eea902956c3b3b40096b6560df0caf55a8154c..d377959490d09b632271ba88964a34f75540538b 100644 (file)
@@ -2,7 +2,7 @@
 # Tiny AltOS build
 #
 #
-vpath % ../attiny:../drivers:../core:../product:..
+vpath % ../attiny:../drivers:../kernel:../product:..
 vpath ao-make-product.5c ../util
 vpath make-altitude-pa ../util
 
@@ -47,7 +47,7 @@ INC=\
 IDPRODUCT=0
 PRODUCT=NanoPeak-v0.1
 PRODUCT_DEF=-DNANOPEAK
-CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../core -I.. -I../drivers -I../product
+CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../kernel -I.. -I../drivers -I../product
 CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY
 
 NICKLE=nickle
index da9bcba04597487776c62fe6efd5ee444ba431a7..81151364da6557e3cf45ae13562f14286fd74142 100644 (file)
@@ -7,8 +7,8 @@
 # TD_VER, TD_DEF and include
 # this file
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index a5e2eb7fb12912afbcb7db443e2fccd57f78b8f4..90fe7833f4d239f3b72f9175abace26d8b13a203 100644 (file)
@@ -4,8 +4,8 @@
 # define TELELAUNCH_VER, TELELAUNCH_DEF
 # this file
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index c740a4831149325ca8bf67965847696de6150598..dbbf57d80437e25b6f259ce7ea1aa996935f861a 100644 (file)
@@ -7,8 +7,8 @@
 # TM_VER, TM_DEF, TM_INC and TM_SRC and include
 # this file
 
-vpath %.c .:..:../core:../cc1111:../drivers:../product
-vpath %.h .:..:../core:../cc1111:../drivers:../product
+vpath %.c .:..:../kernel:../cc1111:../drivers:../product
+vpath %.h .:..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index 0884079eb701543cc090c3e0ea7358b0c4ac1123..ff8b9d5649d83e0e9fad17f9710cfe8730e9df03 100644 (file)
@@ -4,8 +4,8 @@
 # Define TELEMINI_VER and TELEMINI_DEF and then
 # include this file
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index c31989eedf2fa213837923961da8cb7604e2d777..d2fcb6d8b8ca5d45f4e9929f834cad9a4c50849c 100644 (file)
@@ -4,8 +4,8 @@
 # Define TELENANO_VER and TELENANO_DEF and then
 # include this file
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index 6cb308e1fa5ee580656af86757ddbcf9c4bcd97f..9a12add659a00af10bc62b48b5042b62f834f73e 100644 (file)
@@ -79,6 +79,14 @@ ao_block_erase(void)
        ao_flash_erase_page(p);
 }
 
+static int
+ao_block_valid_address(uint32_t addr)
+{
+       if ((uint32_t) AO_BOOT_APPLICATION_BASE <= addr && addr <= (uint32_t) AO_BOOT_APPLICATION_BOUND - 256)
+               return 1;
+       return 0;
+}
+
 static void
 ao_block_write(void)
 {
@@ -87,12 +95,10 @@ ao_block_write(void)
        uint8_t         data[256];
        uint16_t        i;
 
-       if (addr < (uint32_t) AO_BOOT_APPLICATION_BASE) {
-               ao_put_string("Invalid address\n");
-               return;
-       }
        for (i = 0; i < 256; i++)
                data[i] = ao_usb_getchar();
+       if (!ao_block_valid_address(addr))
+               return;
        ao_flash_page(p, (void *) data);
 }
 
@@ -104,18 +110,43 @@ ao_block_read(void)
        uint16_t        i;
        uint8_t         c;
 
+       if (!ao_block_valid_address(addr)) {
+               for (i = 0; i < 256; i++)
+                       ao_usb_putchar(0xff);
+               return;
+       }
        for (i = 0; i < 256; i++) {
                c = *p++;
                ao_usb_putchar(c);
        }
 }
 
+static inline void
+hexchar(uint8_t c)
+{
+       if (c > 10)
+               c += 'a' - ('9' + 1);
+       ao_usb_putchar(c + '0');
+}
+
+static void
+ao_put_hex(uint32_t u)
+{
+       int8_t i;
+       for (i = 28; i >= 0; i -= 4)
+               hexchar((u >> i) & 0xf);
+}
+
 static void
 ao_show_version(void)
 {
        ao_put_string("altos-loader");
        ao_put_string("\nmanufacturer     "); ao_put_string(ao_manufacturer);
        ao_put_string("\nproduct          "); ao_put_string(ao_product);
+       ao_put_string("\nflash-range      ");
+       ao_put_hex((uint32_t) AO_BOOT_APPLICATION_BASE);
+       ao_usb_putchar(' ');
+       ao_put_hex((uint32_t) AO_BOOT_APPLICATION_BOUND);
        ao_put_string("\nsoftware-version "); ao_put_string(ao_version);
        ao_put_string("\n");
 }
index 0cefca6f0ea3408319477ab6dca1d2c79670fa2e..0ec407d7bad503c15d2e37148b4e02ef3156f818 100644 (file)
@@ -25,7 +25,9 @@
 #define GROUND_AVG             (1 << GROUND_AVG_SHIFT)
 
 /* Pressure change (in Pa) to detect boost */
+#ifndef BOOST_DETECT
 #define BOOST_DETECT           360     /* 30m at sea level, 36m at 2000m */
+#endif
 
 /* Wait after power on before doing anything to give the user time to assemble the rocket */
 #define BOOST_DELAY            AO_SEC_TO_TICKS(60)
index b9f6129cc5e3163b05dea20a1d16d80f43be2363..2c77e32b9ebaf291d12a62dd5ec012a9d6bba055 100644 (file)
@@ -1,2 +1,2 @@
---directory=../cc1111:../product:../core:../drivers:.
+--directory=../cc1111:../product:../kernel:../drivers:.
 
index e644bc49d64785798682282b804fa1dc984fa7ab..cd7a9cde3de1d30f0154052f0611eb97f14685e8 100644 (file)
@@ -5,8 +5,8 @@
 SPIRADIO_VER=0.1
 SPIRADIO_DEF=0_1
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index 797df2d697b4cc3ffd05cde93717855270386ad7..b0943e5665fb34f94ee1872755df8d0f040e83a9 100644 (file)
@@ -1,4 +1,4 @@
-vpath % ..:../core:../product:../drivers:../stm
+vpath % ..:../kernel:../product:../drivers:../stm
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index 98fcd9e587f6721bda89fd85900db01547c72037..869fb32fd4010d71a5c63135f643b7bdc51087a4 100644 (file)
@@ -9,6 +9,7 @@ INC = \
        ao.h \
        ao_arch.h \
        ao_arch_funcs.h \
+       ao_boot.h \
        ao_pins.h \
        ao_product.h
 
@@ -26,7 +27,6 @@ ALTOS_SRC = \
        ao_stdio.c \
        ao_panic.c \
        ao_timer.c \
-       ao_serial_stm.c \
        ao_lcd_stm.c \
        ao_lcd_font.c \
        ao_mutex.c \
index 58cf651b472471bef053a180e525fd321740bef6..ffc5d2d873b3f7d8e176d3edc2cf2d7428af3b8a 100644 (file)
@@ -171,12 +171,38 @@ ao_event(void)
 }
 #endif
 
+static uint8_t ao_blinking = 0;
+
+static void
+ao_blink(void)
+{
+       for (;;) {
+               while (!ao_blinking)
+                       ao_sleep(&ao_blinking);
+               while (ao_blinking) {
+                       ao_led_toggle(AO_LED_BLUE|AO_LED_GREEN);
+                       ao_delay(AO_MS_TO_TICKS(500));
+               }
+       }
+}
+
+static struct ao_task ao_blink_task;
+
+static void
+ao_blink_toggle(void)
+{
+       ao_blinking = !ao_blinking;
+       ao_wakeup(&ao_blinking);
+}
+
+
 __code struct ao_cmds ao_demo_cmds[] = {
        { ao_dma_test,  "D\0DMA test" },
        { ao_spi_write, "W\0SPI write" },
        { ao_spi_read, "R\0SPI read" },
        { ao_i2c_write, "i\0I2C write" },
        { ao_temp, "t\0Show temp" },
+       { ao_blink_toggle, "b\0Toggle LED blinking" },
 /*     { ao_event, "e\0Monitor event queue" }, */
        { 0, NULL }
 };
@@ -188,23 +214,26 @@ main(void)
        
        ao_task_init();
 
-       ao_serial_init();
+       ao_led_init(LEDS_AVAILABLE);
+       ao_led_on(AO_LED_GREEN);
+       ao_led_off(AO_LED_BLUE);
        ao_timer_init();
        ao_dma_init();
        ao_cmd_init();
 //     ao_lcd_stm_init();
 //     ao_lcd_font_init();
-       ao_spi_init();
-       ao_i2c_init();
-       ao_exti_init();
+//     ao_spi_init();
+//     ao_i2c_init();
+//     ao_exti_init();
 //     ao_quadrature_init();
 //     ao_button_init();
 
-       ao_timer_set_adc_interval(100);
+//     ao_timer_set_adc_interval(100);
 
-       ao_adc_init();
+//     ao_adc_init();
        ao_usb_init();
 
+       ao_add_task(&ao_blink_task, ao_blink, "blink");
        ao_cmd_register(&ao_demo_cmds[0]);
        
        ao_start_scheduler();
index 40e48a367423c78c081df828af7bf8be800a43c0..885b9db6f5717834eaa1bc5d1bbe3fb35b08fed5 100644 (file)
 #define AO_APB2_PRESCALER              1
 #define AO_RCC_CFGR_PPRE2_DIV  STM_RCC_CFGR_PPRE2_DIV_1
 
-#define HAS_SERIAL_1           1
-#define USE_SERIAL_1_STDIN     1
+#define HAS_SERIAL_1           0
+#define USE_SERIAL_1_STDIN     0
 #define SERIAL_1_PB6_PB7       1
 #define SERIAL_1_PA9_PA10      0
 
 #define HAS_SERIAL_2           0
-#define USE_SERIAL_2_STDIN     1
+#define USE_SERIAL_2_STDIN     0
 #define SERIAL_2_PA2_PA3       0
 #define SERIAL_2_PD5_PD6       1
 
@@ -70,7 +70,7 @@
 
 #define AO_BOOT_CHAIN          1
 
-#define LOW_LEVEL_DEBUG                1
+#define LOW_LEVEL_DEBUG                0
 
 #define LED_PORT_ENABLE                STM_RCC_AHBENR_GPIOBEN
 #define LED_PORT               (&stm_gpiob)
@@ -78,8 +78,7 @@
 #define LED_PIN_BLUE           6
 #define AO_LED_GREEN           (1 << LED_PIN_GREEN)
 #define AO_LED_BLUE            (1 << LED_PIN_BLUE)
-
-#define AO_LED_RED             AO_LED_BLUE     /* a patent lie */
+#define AO_LED_PANIC           AO_LED_BLUE
 
 #define LEDS_AVAILABLE         (AO_LED_BLUE | AO_LED_GREEN)
 
diff --git a/src/stm-demo/flash-loader/Makefile b/src/stm-demo/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..27e5427
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=stm-demo
+include $(TOPDIR)/stm/Makefile-flash.defs
diff --git a/src/stm-demo/flash-loader/ao_pins.h b/src/stm-demo/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..4c59101
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2013 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+/* Bridge SB17 on the board and use the MCO from the other chip */
+#define AO_HSE         8000000
+#define AO_HSE_BYPASS          1
+
+#include <ao_flash_stm_pins.h>
+
+/* Use the 'user switch' to force boot loader on power on */
+
+#define AO_BOOT_PIN                    1
+#define AO_BOOT_APPLICATION_GPIO       stm_gpioa
+#define AO_BOOT_APPLICATION_PIN                0
+#define AO_BOOT_APPLICATION_VALUE      0
+#define AO_BOOT_APPLICATION_MODE       0
+
+#endif /* _AO_PINS_H_ */
index 5c0699e1bbed20d510a76b69325f82e098dd6633..568ab85af1b9df167cab3fc99f975495271a96be 100644 (file)
@@ -9,6 +9,7 @@ INC = \
        ao.h \
        ao_arch.h \
        ao_arch_funcs.h \
+       ao_boot.h \
        ao_pins.h \
        ao_product.h
 
index 3890eff1a19c6d0046b2030dcfddb4ec4ef807f0..dde51a684cc85308645e2bb0587ec2dad77b47b8 100644 (file)
@@ -1,4 +1,4 @@
-vpath % $(TOPDIR)/stm:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/core:$(TOPDIR)/util:$(TOPDIR)
+vpath % $(TOPDIR)/stm:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)
 vpath ao-make-product.5c $(TOPDIR)/util
 
 .SUFFIXES: .elf .ihx
@@ -14,7 +14,7 @@ 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) $(PDCLIB_INCLUDES)
+AO_CFLAGS=-I. -I$(TOPDIR)/stm -I$(TOPDIR)/kernel -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
index 42adfd0923b3ddc04f7ccab0d0a50e7756e7a850..c3d2707faf76dae341d4b86943c58ce0e0b52242 100644 (file)
@@ -1,4 +1,4 @@
-vpath % ../stm:../product:../drivers:../core:../util:../kalman:../aes:../math:..
+vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:..
 vpath make-altitude ../util
 vpath make-kalman ../util
 vpath kalman.5c ../kalman
@@ -26,7 +26,7 @@ LIBS=$(PDCLIB_LIBS_M3) -lgcc
 
 WARN_FLAGS=-Wall -Wextra -Werror
 
-AO_CFLAGS=-I. -I../stm -I../core -I../drivers -I../math -I.. $(PDCLIB_INCLUDES)
+AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I.. $(PDCLIB_INCLUDES)
 STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb \
        -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS)
 
index 76fa91947bd619d1884cbda63de15b94cd14db7e..a6276c5ae306963e8ac76fc0e86b02ca9e76b2fa 100644 (file)
@@ -139,7 +139,8 @@ ao_adc_init();
 #define AO_ADC_MAX                     4095
 
 #define AO_BOOT_APPLICATION_BASE       ((uint32_t *) 0x08001000)
-#define AO_BOOT_LOADER_BASE            ((uint32_t *) 0x0)
+#define AO_BOOT_APPLICATION_BOUND      ((uint32_t *) (0x08000000 + stm_flash_size()))
+#define AO_BOOT_LOADER_BASE            ((uint32_t *) 0x08000000)
 #define HAS_BOOT_LOADER                        1
 
 #endif /* _AO_ARCH_H_ */
diff --git a/src/stm/ao_boot.h b/src/stm/ao_boot.h
deleted file mode 100644 (file)
index e0ed4de..0000000
+++ /dev/null
@@ -1,39 +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_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_ */
index 6a3864a71356ac69c80059f15cf85a6d8b6ba4dd..bcebf033ed5b9fa78dd19e80daf240262e5ed9ee 100644 (file)
@@ -50,7 +50,7 @@ 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)
+               if (ao_boot.base == AO_BOOT_FORCE_LOADER)
                        return 0;
                ao_boot_chain(ao_boot.base);
        }
index 1000a65a8c1e361728b9e024ae3d3f67f6357976..e825b618299bbe416e27153cfa0b331955d5e12b 100644 (file)
@@ -26,7 +26,7 @@ ao_boot_check_pin(void)
 
        /* 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);
index d61b40c99bed32f5a25af6010f41ad1e93ef9869..9a73eb51c30c3c2e1562907124e9d44c3768cb8c 100644 (file)
@@ -88,7 +88,11 @@ void stm_tim6_isr(void)
 #define TIMER_23467_SCALER 1
 #endif
 
-#define TIMER_10kHz    ((AO_PCLK1 * TIMER_23467_SCALER) / 10000)
+#ifndef FAST_TIMER_FREQ
+#define FAST_TIMER_FREQ        10000
+#endif
+
+#define TIMER_FAST     ((AO_PCLK1 * TIMER_23467_SCALER) / FAST_TIMER_FREQ)
 
 void
 ao_fast_timer_init(void)
@@ -100,7 +104,7 @@ ao_fast_timer_init(void)
                /* Turn on timer 6 */
                stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM6EN);
 
-               stm_tim6.psc = TIMER_10kHz;
+               stm_tim6.psc = TIMER_FAST;
                stm_tim6.arr = 9;
                stm_tim6.cnt = 0;
 
index 969e6a0f7b6a23a7433785f114c76765005509bb..56cce0c02ff90af23fac42ee05af44783b59626c 100644 (file)
@@ -39,6 +39,38 @@ void stm_ignore_isr(void)
 
 const void *stm_interrupt_vector[];
 
+uint32_t
+stm_flash_size(void) {
+       uint16_t        dev_id = stm_dev_id();
+       uint16_t        kbytes = 0;
+
+       switch (dev_id) {
+       case 0x416:     /* cat 1 */
+               kbytes = stm_flash_size_medium.f_size;
+               break;
+       case 0x429:     /* cat 2 */
+               kbytes = stm_flash_size_medium.f_size & 0xff;
+               break;
+       case 0x427:     /* cat 3 */
+               kbytes = stm_flash_size_large.f_size;
+               break;
+       case 0x436:     /* cat 4 */
+               switch (stm_flash_size_large.f_size) {
+               case 0:
+                       kbytes = 256;
+                       break;
+               case 1:
+                       kbytes = 384;
+                       break;
+               }
+               break;
+       case 0x437:     /* cat 5 */
+               kbytes = stm_flash_size_large.f_size;
+               break;
+       }
+       return (uint32_t) kbytes * 1024;
+}
+
 void start(void)
 {
 #ifdef AO_BOOT_CHAIN
index d93531fc7da8623d1e4531959f50ce8fea75cd51..8db62e76a806b6ff51e49ecb3e23d0cc087aab72 100644 (file)
@@ -17,6 +17,9 @@
 
 #include "ao.h"
 #include <ao_task.h>
+#if HAS_FAKE_FLIGHT
+#include <ao_fake_flight.h>
+#endif
 
 #ifndef HAS_TICK
 #define HAS_TICK 1
@@ -47,7 +50,12 @@ void stm_systick_isr(void)
 #if AO_DATA_ALL
                if (++ao_data_count == ao_data_interval) {
                        ao_data_count = 0;
-                       ao_adc_poll();
+#if HAS_FAKE_FLIGHT
+                       if (ao_fake_flight_active)
+                               ao_fake_flight_poll();
+                       else
+#endif
+                               ao_adc_poll();
 #if (AO_DATA_ALL & ~(AO_DATA_ADC))
                        ao_wakeup((void *) &ao_data_count);
 #endif
index 27b82357843d3d278b815165b99ecfdc97555f2a..4e9d1f145cd98001e4378d3f8ea12050fc034e91 100644 (file)
@@ -117,7 +117,7 @@ static uint8_t      ao_usb_in_pending;
  * but not pulled to the shadow buffer.
  */
 static uint8_t ao_usb_out_avail;
-static uint8_t ao_usb_running;
+uint8_t                ao_usb_running;
 static uint8_t ao_usb_configuration;
 
 #define AO_USB_EP0_GOT_RESET   1
@@ -727,6 +727,9 @@ ao_usb_ep0_handle(uint8_t receive)
        if (receive & AO_USB_EP0_GOT_TX_ACK) {
                debug ("\tgot tx ack\n");
 
+#if HAS_FLIGHT && AO_USB_FORCE_IDLE
+               ao_flight_force_idle = 1;
+#endif
                /* Wait until the IN packet is received from addr 0
                 * before assigning our local address
                 */
index 8318c75a87a6330634b08ec6c3a71a5d3e778e97..d40fd90f1e04f3339e55a1a89d1db2f377e3dfb5 100644 (file)
@@ -52,5 +52,10 @@ stm_scb    = 0xe000ed00;
 
 stm_mpu    = 0xe000ed90;
 
+stm_dbg_mcu = 0xe0042000;
+
 /* calibration data in system memory */
 stm_temp_cal = 0x1ff80078;
+stm_flash_size_medium = 0x1ff8004c;
+stm_flash_size_large = 0x1ff800cc;
+stm_device_id = 0x1ff80050;
index 302f4d2451bf6fd762a544b257ab38cc0c93b7df..799cccbd2a1848bd9510ad0aa1f62d2cea857ee3 100644 (file)
@@ -176,12 +176,27 @@ 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;
-extern struct stm_gpio stm_gpiod;
-extern struct stm_gpio stm_gpioe;
-extern struct stm_gpio stm_gpioh;
+/*
+ * We can't define these in registers.ld or our fancy
+ * ao_enable_gpio macro will expand into a huge pile of code
+ * as the compiler won't do correct constant folding and
+ * dead-code elimination
+
+ extern struct stm_gpio stm_gpioa;
+ extern struct stm_gpio stm_gpiob;
+ extern struct stm_gpio stm_gpioc;
+ extern struct stm_gpio stm_gpiod;
+ extern struct stm_gpio stm_gpioe;
+ extern struct stm_gpio stm_gpioh;
+
+*/
+
+#define stm_gpioh  (*((struct stm_gpio *) 0x40021400))
+#define stm_gpioe  (*((struct stm_gpio *) 0x40021000))
+#define stm_gpiod  (*((struct stm_gpio *) 0x40020c00))
+#define stm_gpioc  (*((struct stm_gpio *) 0x40020800))
+#define stm_gpiob  (*((struct stm_gpio *) 0x40020400))
+#define stm_gpioa  (*((struct stm_gpio *) 0x40020000))
 
 struct stm_usart {
        vuint32_t       sr;     /* status register */
@@ -1492,6 +1507,36 @@ extern struct stm_temp_cal       stm_temp_cal;
 #define stm_temp_cal_cold      25
 #define stm_temp_cal_hot       110
 
+struct stm_dbg_mcu {
+       uint32_t        idcode;
+};
+
+extern struct stm_dbg_mcu      stm_dbg_mcu;
+
+static inline uint16_t
+stm_dev_id(void) {
+       return stm_dbg_mcu.idcode & 0xfff;
+}
+
+struct stm_flash_size {
+       uint16_t        f_size;
+};
+
+extern struct stm_flash_size   stm_flash_size_medium;
+extern struct stm_flash_size   stm_flash_size_large;
+
+/* Returns flash size in bytes */
+extern uint32_t
+stm_flash_size(void);
+
+struct stm_device_id {
+       uint32_t        u_id0;
+       uint32_t        u_id1;
+       uint32_t        u_id2;
+};
+
+extern struct stm_device_id    stm_device_id;
+
 #define STM_NUM_I2C    2
 
 #define STM_I2C_INDEX(channel) ((channel) - 1)
index 6ff076a9c8598a28b922b6a7b59c215fe6dc6e7b..c6f6345aa80f69afd6274a87ac375a74d9874553 100644 (file)
@@ -17,8 +17,8 @@ TELEBALLOON_SRC = \
        ao_gps_skytraq.c \
        ao_m25.c
 
-vpath %.c ..:../core:../cc1111:../drivers:../product:.
-vpath %.h ..:../core:../cc1111:../drivers:../product:.
+vpath %.c ..:../kernel:../cc1111:../drivers:../product:.
+vpath %.h ..:../kernel:../cc1111:../drivers:../product:.
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
diff --git a/src/teleballoon-v1.1/ao_balloon.c b/src/teleballoon-v1.1/ao_balloon.c
deleted file mode 100644 (file)
index 12752d1..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AO_FLIGHT_TEST
-#include "ao.h"
-#endif
-
-#ifndef HAS_ACCEL
-#error Please define HAS_ACCEL
-#endif
-
-#ifndef HAS_GPS
-#error Please define HAS_GPS
-#endif
-
-#ifndef HAS_USB
-#error Please define HAS_USB
-#endif
-
-/* Main flight thread. */
-
-__pdata enum ao_flight_state   ao_flight_state;        /* current flight state */
-
-__pdata uint8_t                        ao_flight_force_idle;
-
-void
-ao_flight(void)
-{
-       ao_sample_init();
-       ao_flight_state = ao_flight_startup;
-       for (;;) {
-
-               /*
-                * Process ADC samples, just looping
-                * until the sensors are calibrated.
-                */
-               if (!ao_sample())
-                       continue;
-
-               switch (ao_flight_state) {
-               case ao_flight_startup:
-
-                       /* Check to see what mode we should go to.
-                        *  - Invalid mode if accel cal appears to be out
-                        *  - pad mode if we're upright,
-                        *  - idle mode otherwise
-                        */
-                       if (!ao_flight_force_idle)
-                       {
-                               /* Set pad mode - we can fly! */
-                               ao_flight_state = ao_flight_pad;
-#if HAS_USB
-                               /* Disable the USB controller in flight mode
-                                * to save power
-                                */
-                               ao_usb_disable();
-#endif
-
-                               /* Disable packet mode in pad state */
-                               ao_packet_slave_stop();
-
-                               /* Turn on telemetry system */
-                               ao_rdf_set(1);
-                               ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_BALLOON);
-
-                               /* signal successful initialization by turning off the LED */
-                               ao_led_off(AO_LED_RED);
-                       } else {
-                               /* Set idle mode */
-                               ao_flight_state = ao_flight_idle;
-                               /* signal successful initialization by turning off the LED */
-                               ao_led_off(AO_LED_RED);
-                       }
-                       /* wakeup threads due to state change */
-                       ao_wakeup(DATA_TO_XDATA(&ao_flight_state));
-
-                       break;
-               case ao_flight_pad:
-
-                       /* pad to coast:
-                        *
-                        * barometer: > 20m vertical motion
-                        */
-                       if (ao_height > AO_M_TO_HEIGHT(20))
-                       {
-                               ao_flight_state = ao_flight_drogue;
-
-                               /* start logging data */
-                               ao_log_start();
-
-#if HAS_GPS
-                               /* Record current GPS position by waking up GPS log tasks */
-                               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));
-                       }
-                       break;
-               case ao_flight_drogue:
-                       break;
-                       
-               }
-       }
-}
-
-static __xdata struct ao_task  flight_task;
-
-void
-ao_flight_init(void)
-{
-       ao_flight_state = ao_flight_startup;
-       ao_add_task(&flight_task, ao_flight, "flight");
-}
index 7ba48c96e0bd1d3648d1b6c24e2a68ebfc333ff2..4c23ca88f1bb6c3ab005f11a1128dd435235d8ca 100644 (file)
@@ -28,6 +28,7 @@
        #define HAS_FLIGHT              1
        #define HAS_USB                 1
        #define HAS_BEEP                1
+       #define HAS_BATTERY_REPORT      1
        #define HAS_GPS                 1
        #define HAS_SERIAL_1            1
        #define HAS_ADC                 1
diff --git a/src/teleballoon-v2.0/.gitignore b/src/teleballoon-v2.0/.gitignore
new file mode 100644 (file)
index 0000000..85f1255
--- /dev/null
@@ -0,0 +1,3 @@
+ao_product.h
+teleballoon-*.elf
+
diff --git a/src/teleballoon-v2.0/Makefile b/src/teleballoon-v2.0/Makefile
new file mode 100644 (file)
index 0000000..2858877
--- /dev/null
@@ -0,0 +1,130 @@
+#
+# AltOS build
+#
+#
+
+include ../stm/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_boot.h \
+       ao_companion.h \
+       ao_data.h \
+       ao_sample.h \
+       ao_pins.h \
+       altitude-pa.h \
+       ao_kalman.h \
+       ao_product.h \
+       ao_ms5607.h \
+       ao_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
+
+MATH_SRC=\
+       ef_log.c
+
+ALTOS_SRC = \
+       ao_boot_chain.c \
+       ao_interrupt.c \
+       ao_product.c \
+       ao_romconfig.c \
+       ao_cmd.c \
+       ao_config.c \
+       ao_task.c \
+       ao_led.c \
+       ao_stdio.c \
+       ao_panic.c \
+       ao_timer.c \
+       ao_mutex.c \
+       ao_serial_stm.c \
+       ao_gps_ublox.c \
+       ao_gps_show.c \
+       ao_gps_report_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_convert_volt.c \
+       ao_log.c \
+       ao_log_metrum.c \
+       ao_sample.c \
+       ao_kalman.c \
+       ao_balloon.c \
+       ao_telemetry.c \
+       ao_packet_slave.c \
+       ao_packet.c \
+       ao_companion.c \
+       ao_aprs.c \
+       $(MATH_SRC) \
+       $(PROFILE) \
+       $(SAMPLE_PROFILE) \
+       $(STACK_GUARD)
+
+PRODUCT=TeleBalloon-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=teleballoon-v2.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_teleballoon.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/teleballoon-v2.0/ao_pins.h b/src/teleballoon-v2.0/ao_pins.h
new file mode 100644 (file)
index 0000000..a369070
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * 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 AO_CONFIG_MAX_SIZE                     1024
+#define LOG_ERASE_MARK                         0x55
+#define LOG_MAX_ERASE                          128
+
+#define HAS_EEPROM             1
+#define USE_INTERNAL_FLASH     0
+#define USE_EEPROM_CONFIG      1
+#define USE_STORAGE_CONFIG     0
+#define HAS_USB                        1
+#define HAS_BEEP               1
+#define HAS_BATTERY_REPORT     1
+#define BEEPER_CHANNEL         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
+#define AO_USB_FORCE_IDLE      0
+
+/*
+ * Igniter
+ */
+
+#define HAS_IGNITE             0
+#define HAS_IGNITE_REPORT      0
+
+#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
+
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS    56      /* 5.6k */
+#define AO_BATTERY_DIV_MINUS   100     /* 10k */
+
+/*
+ * Voltage divider on ADC igniter samplers
+ */
+#define AO_IGNITE_DIV_PLUS     100     /* 100k */
+#define AO_IGNITE_DIV_MINUS    27      /* 27k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV    33
+
+/*
+ * 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                0
+
+/* Disable accelerometer for balloon mode */
+   
+#define HAS_ACCEL              0
+
+/*
+ * mma655x
+ */
+
+#define HAS_MMA655X            0
+#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
+
+/*
+ * Teleballoon-specific bits
+ */
+
+#define AO_TELEMETRY_INTERVAL_BALLOON  AO_MS_TO_TICKS(1000)
+
+#define AO_SEND_METRUM         1
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/teleballoon-v2.0/ao_teleballoon.c b/src/teleballoon-v2.0/ao_teleballoon.c
new file mode 100644 (file)
index 0000000..9b50681
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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_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;
+}
index b9f6129cc5e3163b05dea20a1d16d80f43be2363..2c77e32b9ebaf291d12a62dd5ec012a9d6bba055 100644 (file)
@@ -1,2 +1,2 @@
---directory=../cc1111:../product:../core:../drivers:.
+--directory=../cc1111:../product:../kernel:../drivers:.
 
index 40853fc3cc04d083686fe4e54b46242ec5e0f778..a7797499a70a67513f162bf4be2219c1a070c403 100644 (file)
@@ -5,8 +5,8 @@
 TELEBT_VER=1.0
 TELEBT_DEF=1_0
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index b9f6129cc5e3163b05dea20a1d16d80f43be2363..2c77e32b9ebaf291d12a62dd5ec012a9d6bba055 100644 (file)
@@ -1,2 +1,2 @@
---directory=../cc1111:../product:../core:../drivers:.
+--directory=../cc1111:../product:../kernel:../drivers:.
 
index f9e116983bea0c26545a903c6861410125708627..25267268e3a5dd0c67ec409983c46338884af147 100644 (file)
@@ -5,8 +5,8 @@
 TELEFIRE_VER=0.1
 TELEFIRE_DEF=0_1
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index b9f6129cc5e3163b05dea20a1d16d80f43be2363..2c77e32b9ebaf291d12a62dd5ec012a9d6bba055 100644 (file)
@@ -1,2 +1,2 @@
---directory=../cc1111:../product:../core:../drivers:.
+--directory=../cc1111:../product:../kernel:../drivers:.
 
index a820990a6edd8663ca0657e083037067f9c01388..ad5065c175d5f6a738ad0b7bfabe5f5da9bf5be0 100644 (file)
@@ -5,8 +5,8 @@
 TELEFIRE_VER=0.2
 TELEFIRE_DEF=0_2
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index 77ef9c4a8e9c6a394f7f85be0cde32325260e8a5..46eb0ac5edc6278e7175d527a40d364eb3916d5f 100644 (file)
@@ -9,6 +9,7 @@ INC = \
        ao.h \
        ao_arch.h \
        ao_arch_funcs.h \
+       ao_boot.h \
        ao_pins.h \
        ao_product.h \
        ao_task.h \
index 5aad32b542a149fea83742928e8a708e5a739032..1eaf7c474b5a2d1886e6a02dd74027150d93129e 100644 (file)
@@ -11,6 +11,7 @@ INC = \
        ao_arch_funcs.h \
        ao_pins.h \
        ao_product.h \
+       ao_tracker.h \
        ao_task.h \
        ao_whiten.h \
        ao_cc115l.h \
@@ -19,9 +20,6 @@ INC = \
        Makefile
 
 
-MATH_SRC=\
-       ef_log.c
-
 ALTOS_SRC = \
        ao_interrupt.c \
        ao_boot_chain.c \
@@ -44,13 +42,14 @@ ALTOS_SRC = \
        ao_cc115l.c \
        ao_fec_tx.c \
        ao_aprs.c \
+       ao_tracker.c \
        ao_telemetry.c \
        ao_storage.c \
        ao_m25.c \
        ao_log.c \
-       ao_log_mega.c \
-       ao_gps_report_mega.c \
-       $(MATH_SRC) \
+       ao_log_gps.c \
+       ao_distance.c \
+       ao_sqrt.c \
        $(SAMPLE_PROFILE)
 
 PRODUCT=TeleGPS-v0.3
@@ -61,11 +60,12 @@ CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) $(PROFILE_DEF) -Os -g
 
 PROGNAME=telegps-v0.3
 PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
 
 SRC=$(ALTOS_SRC) ao_telegps.c
 OBJ=$(SRC:.c=.o)
 
-all: $(PROG)
+all: $(PROG) $(HEX)
 
 LDFLAGS=-L../lpc -Wl,-Taltos.ld
 
index a4afaa547230d1ae0138537502cd4c7a211aa754..d0e4d835b6c7261d860f9b6881487b953176d8aa 100644 (file)
@@ -46,7 +46,7 @@
 #define HAS_BEEP               0
 #define HAS_RADIO              1
 #define HAS_TELEMETRY          1
-#define HAS_RDF                        0
+#define HAS_RDF                        1
 #define HAS_APRS               1
 #define HAS_RADIO_RECV         0
 
 #define HAS_FLIGHT             0
 #define HAS_ADC                        0
 #define HAS_LOG                        1
+#define HAS_TRACKER            1
 
-#define AO_CONFIG_DEFAULT_APRS_INTERVAL        5
+#define AO_CONFIG_DEFAULT_APRS_INTERVAL                0
 #define AO_CONFIG_DEFAULT_RADIO_POWER          0xc0
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       496 * 1024
 
 /*
  * GPS
@@ -85,9 +87,9 @@
 
 /* gets pretty close to 434.550 */
 
-#define AO_RADIO_CAL_DEFAULT   0x10b6a5
+#define AO_RADIO_CAL_DEFAULT   1095378
 
-#define HAS_RADIO_POWER                1
+#define HAS_RADIO_POWER                0
 #define AO_FEC_DEBUG           0
 #define AO_CC115L_SPI_CS_PORT  0
 #define AO_CC115L_SPI_CS_PIN   3
index 608817e7601a788d2e7da1241a44faa91ffabfdd..dd699ecff6336a27cc0578fdd925f8780186013a 100644 (file)
 
 #include <ao.h>
 #include <ao_exti.h>
-#include <ao_fat.h>
-
-uint16_t       ao_flight_number = 1;
+#include <ao_tracker.h>
 
 int
 main(void)
 {
        ao_clock_init();
-       
+
 #if HAS_STACK_GUARD
        ao_mpu_init();
 #endif
@@ -48,18 +46,18 @@ main(void)
 
        ao_gps_init();
 #if HAS_LOG
-       ao_gps_report_mega_init();
        ao_log_init();
 #endif
 
+       ao_tracker_init();
+
        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-v1.0/.gitignore b/src/telegps-v1.0/.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-v1.0/Makefile b/src/telegps-v1.0/Makefile
new file mode 100644 (file)
index 0000000..bd13cfe
--- /dev/null
@@ -0,0 +1,91 @@
+#
+# AltOS build
+#
+#
+
+include ../lpc/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_pins.h \
+       ao_product.h \
+       ao_tracker.h \
+       ao_task.h \
+       ao_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_tracker.c \
+       ao_telemetry.c \
+       ao_storage.c \
+       ao_m25.c \
+       ao_log.c \
+       ao_log_gps.c \
+       ao_distance.c \
+       ao_sqrt.c \
+       ao_data.c \
+       ao_adc_lpc.c \
+       ao_convert_volt.c \
+       $(SAMPLE_PROFILE)
+
+PRODUCT=TeleGPS-v1.0
+PRODUCT_DEF=-DTELEGPS
+IDPRODUCT=0x0025
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) $(PROFILE_DEF) -Os -g
+
+PROGNAME=telegps-v1.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_telegps.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX)
+
+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-v1.0/ao_pins.h b/src/telegps-v1.0/ao_pins.h
new file mode 100644 (file)
index 0000000..5f53dd9
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * 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                        1
+#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
+#define HAS_USB_CONNECT                1
+#define AO_USB_CONNECT_PORT    1
+#define AO_USB_CONNECT_PIN     19
+
+/* 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_LOG                        1
+#define HAS_TRACKER            1
+
+#define AO_CONFIG_DEFAULT_APRS_INTERVAL                0
+#define AO_CONFIG_DEFAULT_RADIO_POWER          0xc0
+#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       496 * 1024
+
+/*
+ * GPS
+ */
+
+#define AO_SERIAL_SPEED_UBLOX  AO_SERIAL_SPEED_9600
+
+/*
+ * Radio (cc115l)
+ */
+
+/* gets pretty close to 434.550 */
+
+#define AO_RADIO_CAL_DEFAULT   1095378
+
+#define HAS_RADIO_POWER                0
+#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
+
+/*
+ * ADC
+ */
+
+#define HAS_ADC                        1
+#define LOG_ADC                        0
+
+#define AO_DATA_RING           4
+
+#define AO_ADC_3               1
+
+struct ao_adc {
+       int16_t                 v_batt;
+};
+
+#define AO_ADC_DUMP(p) \
+       printf("tick: %5u batt: %5d\n", \
+              (p)->tick, \
+              (p)->adc.v_batt)
+
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS    56      /* 5.6k */
+#define AO_BATTERY_DIV_MINUS   100     /* 10k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV    33
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/telegps-v1.0/ao_telegps.c b/src/telegps-v1.0/ao_telegps.c
new file mode 100644 (file)
index 0000000..7a71699
--- /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>
+#include <ao_exti.h>
+#include <ao_tracker.h>
+
+int
+main(void)
+{
+       ao_clock_init();
+
+#if HAS_STACK_GUARD
+       ao_mpu_init();
+#endif
+
+       ao_task_init();
+       ao_timer_init();
+
+       ao_spi_init();
+       ao_exti_init();
+
+       ao_storage_init();
+
+       ao_serial_init();
+
+       ao_cmd_init();
+
+       ao_usb_init();
+       ao_radio_init();
+
+#if HAS_ADC
+       ao_adc_init();
+#endif
+
+       ao_gps_init();
+#if HAS_LOG
+       ao_log_init();
+#endif
+
+       ao_tracker_init();
+
+       ao_telemetry_init();
+
+#if HAS_SAMPLE_PROFILE
+       ao_sample_profile_init();
+#endif
+       ao_config_init();
+
+       ao_start_scheduler();
+       return 0;
+}
diff --git a/src/telegps-v1.0/flash-loader/Makefile b/src/telegps-v1.0/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..5283f55
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=telegps-v1.0
+include $(TOPDIR)/lpc/Makefile-flash.defs
diff --git a/src/telegps-v1.0/flash-loader/ao_pins.h b/src/telegps-v1.0/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 44d9237fc760f7e1a1d2aae28423e1d03357ca39..f7628c30e7c1ee88c93337abf3fc5a78790452f2 100644 (file)
@@ -9,6 +9,7 @@ INC = \
        ao.h \
        ao_arch.h \
        ao_arch_funcs.h \
+       ao_boot.h \
        ao_companion.h \
        ao_data.h \
        ao_sample.h \
index f28bdd320510697bc0f760714d1c5ae9d0b1a469..7a21f099c742ebd3440081f90b9427ed1629a491 100644 (file)
@@ -9,6 +9,7 @@ INC = \
        ao.h \
        ao_arch.h \
        ao_arch_funcs.h \
+       ao_boot.h \
        ao_companion.h \
        ao_data.h \
        ao_sample.h \
index 0bbb76f10218d651cc53d6b8ac5b88978c4ad626..b3f5bb169cab5bf7a8a573672c1baf87d37f7991 100644 (file)
@@ -251,18 +251,22 @@ ao_lco_search(void)
 {
        uint16_t        tick_offset;
        int8_t          r;
+       int8_t          try;
        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) {
-                       ao_lco_box_set_present(box);
-                       ao_delay(AO_MS_TO_TICKS(30));
+               for (try = 0; try < 5; try++) {
+                       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) {
+                               ao_lco_box_set_present(box);
+                               ao_delay(AO_MS_TO_TICKS(30));
+                               break;
+                       }
                }
        }
        if (ao_lco_min_box <= ao_lco_max_box)
index 62f221a1da8979402697e6da3dfbebe94db05bbe..a6fd4ff8fc2c681412025d8a03795c4fd5dfb434 100644 (file)
@@ -72,6 +72,8 @@
 #define PACKET_HAS_SLAVE       0
 #define PACKET_HAS_MASTER      0
 
+#define FAST_TIMER_FREQ                10000   /* .1ms for debouncing */
+
 /*
  * Radio is a cc1120 connected via SPI
  */
index db397c669927630357a2103837df52f9627f84ba..2616e9061e20a5d1a7ea93073d3c4287dd1dc2bb 100644 (file)
 #define ao_gps_fifo            (ao_stm_usart3.rx_fifo)
 
 #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       (1024 * 1024)
+#define AO_CONFIG_MAX_SIZE                     1024
+#define LOG_ERASE_MARK                         0x55
+#define LOG_MAX_ERASE                          128
+
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
 #define USE_EEPROM_CONFIG      1
 #define USE_STORAGE_CONFIG     0
 #define HAS_USB                        1
 #define HAS_BEEP               1
+#define HAS_BATTERY_REPORT     1
 #define HAS_RADIO              1
 #define HAS_TELEMETRY          1
 #define HAS_APRS               1
index 7a0c1195d534fb682a4715922ca000a5724c926d..46c768e47c0c0901ba6f96671c35cb5cd19a3f85 100644 (file)
@@ -9,6 +9,7 @@ INC = \
        ao.h \
        ao_arch.h \
        ao_arch_funcs.h \
+       ao_boot.h \
        ao_companion.h \
        ao_data.h \
        ao_sample.h \
index fe97c684114f947cc6fab805298cb4b223013d17..77b753d1edb3083cf56c6d917f30154438da864f 100644 (file)
 #define ao_gps_fifo            (ao_stm_usart3.rx_fifo)
 
 #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       (1024 * 1024)
+#define AO_CONFIG_MAX_SIZE                     1024
+#define LOG_ERASE_MARK                         0x55
+#define LOG_MAX_ERASE                          128
+
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
 #define USE_EEPROM_CONFIG      1
 #define USE_STORAGE_CONFIG     0
 #define HAS_USB                        1
 #define HAS_BEEP               1
+#define HAS_BATTERY_REPORT     1
 #define HAS_RADIO              1
 #define HAS_TELEMETRY          1
 #define HAS_APRS               1
index fbe9a599d2221d052bd9d59ccb5fd87f900843d9..e9a51ea664404a0b1e610df9d09a2815b6ea7af9 100644 (file)
@@ -1 +1 @@
---directory=../cc1111:../product:../core:../drivers:.
+--directory=../cc1111:../product:../kernel:../drivers:.
index fbe9a599d2221d052bd9d59ccb5fd87f900843d9..e9a51ea664404a0b1e610df9d09a2815b6ea7af9 100644 (file)
@@ -1 +1 @@
---directory=../cc1111:../product:../core:../drivers:.
+--directory=../cc1111:../product:../kernel:../drivers:.
index e44be7f9ae5c9bfde8b180a857a28fd42ecaabf4..61e9273b118399b23afd1a1c118157584d14b904 100644 (file)
@@ -12,6 +12,7 @@ TM_SRC = \
        ao_companion.c \
        ao_gps_skytraq.c \
        ao_gps_show.c \
+       ao_convert_volt.c \
        ao_m25.c
 
 include ../product/Makefile.telemetrum
index f2285fbed52b0c3c5f21f39fd9e13133715dd3da..38ba6d49c59f9dd71addf01522c078f254b1d800 100644 (file)
@@ -12,6 +12,7 @@ TM_SRC = \
        ao_companion.c \
        ao_gps_skytraq.c \
        ao_gps_show.c \
+       ao_convert_volt.c \
        ao_m25.c
 
 include ../product/Makefile.telemetrum
index 83a364dcbdd4ea3d526352146919e76287a13aec..d77e95852e825236075cca0b913374a4c55fb188 100644 (file)
@@ -9,6 +9,7 @@ INC = \
        ao.h \
        ao_arch.h \
        ao_arch_funcs.h \
+       ao_boot.h \
        ao_companion.h \
        ao_data.h \
        ao_sample.h \
index 1b5cedc743607418fbef6e5a6d2d6ef60f895f8e..a9a4b243a690643b65e0431a4406cfb1e30e3452 100644 (file)
 #define SERIAL_3_PD8_PD9       0
 
 #define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX       (512 * 1024)
+#define AO_CONFIG_MAX_SIZE                     1024
+#define LOG_ERASE_MARK                         0x55
+#define LOG_MAX_ERASE                          128
+
 #define HAS_EEPROM             1
 #define USE_INTERNAL_FLASH     0
 #define USE_EEPROM_CONFIG      1
 #define USE_STORAGE_CONFIG     0
 #define HAS_USB                        1
 #define HAS_BEEP               1
+#define HAS_BATTERY_REPORT     1
 #define BEEPER_CHANNEL         4
 #define HAS_RADIO              1
 #define HAS_TELEMETRY          1
index b9f6129cc5e3163b05dea20a1d16d80f43be2363..2c77e32b9ebaf291d12a62dd5ec012a9d6bba055 100644 (file)
@@ -1,2 +1,2 @@
---directory=../cc1111:../product:../core:../drivers:.
+--directory=../cc1111:../product:../kernel:../drivers:.
 
index b9f6129cc5e3163b05dea20a1d16d80f43be2363..2c77e32b9ebaf291d12a62dd5ec012a9d6bba055 100644 (file)
@@ -1,2 +1,2 @@
---directory=../cc1111:../product:../core:../drivers:.
+--directory=../cc1111:../product:../kernel:../drivers:.
 
index fcac2c48faeb657cf4eb5b35fb4f6de4568311bb..ca69dc415eaf2f1a78ef2e5d4db4b98199b36f21 100644 (file)
@@ -5,8 +5,8 @@
 TELEMINI_VER=2.0
 TELEMINI_DEF=2_0
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
@@ -30,7 +30,6 @@ INC = \
 CORE_SRC = \
        ao_cmd.c \
        ao_config.c \
-       ao_convert.c \
        ao_flight.c \
        ao_kalman.c \
        ao_log.c \
@@ -59,6 +58,7 @@ CC1111_SRC = \
        ao_spi.c \
        ao_usb.c \
        ao_convert_pa.c \
+       ao_convert_volt.c \
        ao_beep.c \
        ao_timer.c \
        ao_exti.c \
index c4681ee28a90eb9049f3bfd38dfe7282435de8cd..f202ccd1c31488608a412dd95aa08a8ed9b138ff 100644 (file)
 
 #define HAS_FLIGHT             1
 #define HAS_USB                        1
+
+#define HAS_USB_PULLUP 1
+#define AO_USB_PULLUP_PORT     P1
+#define AO_USB_PULLUP_PIN      0
+#define AO_USB_PULLUP          P1_0
+
 #define USB_FORCE_FLIGHT_IDLE  1
 #define HAS_BEEP               1
+#define HAS_BEEP_CONFIG                0
+#define HAS_BATTERY_REPORT     1
 #define HAS_GPS                        0
 #define HAS_SERIAL_1           0
 #define HAS_EEPROM             1
@@ -32,9 +40,8 @@
 #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 LEDS_AVAILABLE         AO_LED_RED
 #define HAS_EXTERNAL_TEMP      0
 #define HAS_ACCEL              0
 #define HAS_IGNITE             1
@@ -158,4 +165,21 @@ struct ao_adc {
                ao_data_ring[ao_data_head].ms5607_raw.temp = ao_ms5607_current.temp; \
        } while (0)
 
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS    100     /* 100k */
+#define AO_BATTERY_DIV_MINUS   27      /* 27k */
+
+/*
+ * Voltage divider on ADC igniter samplers
+ */
+#define AO_IGNITE_DIV_PLUS     100     /* 100k */
+#define AO_IGNITE_DIV_MINUS    27      /* 27k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV    33
+
 #endif /* _AO_PINS_H_ */
index 025b324a360833c6befa99fb84b4aab561713c5d..dcac03dc57ffa35ac166591705eb3e3f4cb0e407 100644 (file)
@@ -2,7 +2,7 @@
 # AltOS build
 #
 #
-vpath % .:..:../core:../product:../drivers:../avr
+vpath % .:..:../kernel:../product:../drivers:../avr
 vpath ao-make-product.5c ../util
 
 include ../avr/Makefile.defs
@@ -45,7 +45,7 @@ PRODUCT=TelePyro-v0.1
 MCU=atmega32u4
 PRODUCT_DEF=-DTELEPYRO
 IDPRODUCT=0x0011
-CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I..
+CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../kernel -I..
 CFLAGS += -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues -DAVR
 
 NICKLE=nickle
index de81b8d798ec397af3b71ed62b01377eb67a372d..493bd4800e0d3628ad5b4bbe697fd8b710fcad4b 100644 (file)
@@ -2,7 +2,7 @@
 # AltOS build
 #
 #
-vpath % ..:../core:../product:../drivers:../avr
+vpath % ..:../kernel:../product:../drivers:../avr
 vpath ao-make-product.5c ../util
 
 include ../avr/Makefile.defs
@@ -57,7 +57,7 @@ PRODUCT=TeleScience-PWM
 MCU=atmega32u4
 PRODUCT_DEF=-DTELESCIENCE -DTELESCIENCE_PWM
 IDPRODUCT=0x0011
-CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I..
+CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../kernel -I..
 CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues -DAVR
 
 NICKLE=nickle
index 6e4eb6de429a7e1c7d35a93ae26b00a40f61613c..c55c48e2a347c2d70f7cf41941934ba49c45ee23 100644 (file)
@@ -2,7 +2,7 @@
 # AltOS build
 #
 #
-vpath % ..:../core:../product:../drivers:../avr
+vpath % ..:../kernel:../product:../drivers:../avr
 vpath ao-make-product.5c ../util
 
 include ../avr/Makefile.defs
@@ -56,7 +56,7 @@ PRODUCT=TeleScience-v0.1
 MCU=atmega32u4
 PRODUCT_DEF=-DTELESCIENCE
 IDPRODUCT=0x0011
-CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I..
+CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../kernel -I..
 CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues -DAVR
 
 NICKLE=nickle
index e8b262efe25f224fde19d538fab2eeeb09122c75..f54488a25c14bbae1708d98a3d6d48367e986960 100644 (file)
@@ -17,8 +17,8 @@ TELESHIELD_SRC = \
        ao_btm.c \
        ao_spi.c
 
-vpath %.c ..:../core:../cc1111:../drivers:../product:.
-vpath %.h ..:../core:../cc1111:../drivers:../product:.
+vpath %.c ..:../kernel:../cc1111:../drivers:../product:.
+vpath %.h ..:../kernel:../cc1111:../drivers:../product:.
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index fbe9a599d2221d052bd9d59ccb5fd87f900843d9..e9a51ea664404a0b1e610df9d09a2815b6ea7af9 100644 (file)
@@ -1 +1 @@
---directory=../cc1111:../product:../core:../drivers:.
+--directory=../cc1111:../product:../kernel:../drivers:.
index 88637360d35f191be751c532af839a30d52d051e..826c52e552a17d7042f769c5c8a7d08cb22296c3 100644 (file)
@@ -2,8 +2,8 @@
 # TeleTerra build file
 #
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
index c602521900a522561d320d2b33457de16894abdb..017f7f71788d24fc3fb46a0f675e2fb34e64e084 100644 (file)
@@ -1,4 +1,4 @@
-vpath % ..:../core:../drivers:../util:../micropeak:../aes:../product
+vpath % ..:../kernel:../drivers:../util:../micropeak:../aes:../product
 
 PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \
        ao_gps_test ao_gps_test_skytraq ao_gps_test_ublox ao_convert_test ao_convert_pa_test ao_fec_test \
@@ -9,7 +9,7 @@ INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quat
 
 KALMAN=make-kalman 
 
-CFLAGS=-I.. -I. -I../core -I../drivers -I../micropeak -I../product -O0 -g -Wall
+CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -O0 -g -Wall
 
 all: $(PROGS) ao_aprs_data.wav
 
@@ -52,10 +52,10 @@ ao_kalman.h: $(KALMAN)
        (cd .. && make ao_kalman.h)
 
 ao_fec_test: ao_fec_test.c ao_fec_tx.c ao_fec_rx.c
-       cc $(CFLAGS) -DAO_FEC_DEBUG=1 -o $@ ao_fec_test.c ../core/ao_fec_tx.c ../core/ao_fec_rx.c -lm
+       cc $(CFLAGS) -DAO_FEC_DEBUG=1 -o $@ ao_fec_test.c ../kernel/ao_fec_tx.c ../kernel/ao_fec_rx.c -lm
 
 ao_aprs_test: ao_aprs_test.c ao_aprs.c
-       cc $(CFLAGS) -o $@ ao_aprs_test.c
+       cc $(CFLAGS) -o $@ ao_aprs_test.c -lm
 
 SOX_INPUT_ARGS=--type raw --encoding unsigned-integer -b 8 -c 1 -r 9600
 SOX_OUTPUT_ARGS=--type wav
index 69147786ff26e413533a441be00bfa9d94f105d2..86cf527ae2f4c7219e376135b357aad327a6f14d 100644 (file)
 
 #include <ao_telemetry.h>
 
+#define AO_GPS_NUM_SAT_MASK    (0xf << 0)
+#define AO_GPS_NUM_SAT_SHIFT   (0)
+
+#define AO_GPS_VALID           (1 << 4)
+#define AO_GPS_RUNNING         (1 << 5)
+#define AO_GPS_DATE_VALID      (1 << 6)
+#define AO_GPS_COURSE_VALID    (1 << 7)
+
 struct ao_telemetry_location ao_gps_data;
+struct ao_telemetry_satellite ao_gps_tracking_data;
 
 #define AO_APRS_TEST
 
@@ -73,7 +82,7 @@ ao_radio_send_aprs(ao_radio_fill_func fill);
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *  
+ *
 
  */
 
@@ -88,14 +97,42 @@ audio_gap(int secs)
 #endif
 }
 
+#include <math.h>
+
+int
+ao_aprs_encode_altitude_expensive(int meters)
+{
+       double  feet = meters / 0.3048;
+
+       double  encode = log(feet) / log(1.002);
+       return floor(encode + 0.5);
+}
+
 // This is where we go after reset.
 int main(int argc, char **argv)
 {
+       int     e, x;
+       int     a;
+
+       for (a = 1; a < 100000; a++) {
+               e = ao_aprs_encode_altitude(a);
+               x = ao_aprs_encode_altitude_expensive(a);
+
+               if (e != x) {
+                       double  back_feet, back_meters;
+                       back_feet = pow(1.002, e);
+                       back_meters = back_feet * 0.3048;
+                       fprintf (stderr, "APRS altitude encoding failure: altitude %d actual %d expected %d actual meters %f\n",
+                                a, e, x, back_meters);
+               }
+       }
+
     audio_gap(1);
 
     ao_gps_data.latitude = (45.0 + 28.25 / 60.0) * 10000000;
     ao_gps_data.longitude = (-(122 + 44.2649 / 60.0)) * 10000000;
     ao_gps_data.altitude = 84;
+    ao_gps_data.flags = (AO_GPS_VALID|AO_GPS_RUNNING);
 
     /* Transmit one packet */
     ao_aprs_send();
index 0abb4090d397e0a615ea1ca31a00288f7057d5a5..0647fc6c3e97206381af8c6814484216706bd052 100644 (file)
@@ -49,13 +49,12 @@ int ao_gps_new;
 #define HAS_MPU6000            1
 #define HAS_MMA655X            1
 #define HAS_HMC5883            1
+#define HAS_BEEP               1
 
 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;
 };
 #else
@@ -309,7 +308,7 @@ struct ao_cmds {
 #if TELEMEGA
 #include "ao_convert_pa.c"
 #include <ao_ms5607.h>
-struct ao_ms5607_prom  ms5607_prom;
+struct ao_ms5607_prom  ao_ms5607_prom;
 #include "ao_ms5607_convert.c"
 #define AO_PYRO_NUM    4
 #include <ao_pyro.h>
@@ -317,22 +316,8 @@ struct ao_ms5607_prom      ms5607_prom;
 #include "ao_convert.c"
 #endif
 
-struct ao_config {
-       uint16_t        main_deploy;
-       int16_t         accel_plus_g;
-       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
-#define AO_PAD_ORIENTATION_ANTENNA_DOWN        1
+#include <ao_config.h>
+#include <ao_fake_flight.h>
 
 #define ao_config_get()
 
@@ -732,6 +717,18 @@ ao_sleep(void *wchan)
                                        ao_flight_started = 1;
                                        ao_ground_pres = int32(bytes, 4);
                                        ao_ground_height = ao_pa_to_altitude(ao_ground_pres);
+                                       ao_ground_accel_along = int16(bytes, 8);
+                                       ao_ground_accel_across = int16(bytes, 10);
+                                       ao_ground_accel_through = int16(bytes, 12);
+                                       ao_ground_roll = int16(bytes, 14);
+                                       ao_ground_pitch = int16(bytes, 16);
+                                       ao_ground_yaw = int16(bytes, 18);
+                                       ao_ground_mpu6000.accel_x = ao_ground_accel_across;
+                                       ao_ground_mpu6000.accel_y = ao_ground_accel_along;
+                                       ao_ground_mpu6000.accel_z = ao_ground_accel_through;
+                                       ao_ground_mpu6000.gyro_x = ao_ground_pitch >> 9;
+                                       ao_ground_mpu6000.gyro_y = ao_ground_roll >> 9;
+                                       ao_ground_mpu6000.gyro_z = ao_ground_yaw >> 9;
                                        break;
                                case 'A':
                                        ao_data_static.tick = tick;
@@ -768,21 +765,21 @@ ao_sleep(void *wchan)
                                continue;
                        } else if (nword == 3 && strcmp(words[0], "ms5607") == 0) {
                                if (strcmp(words[1], "reserved:") == 0)
-                                       ms5607_prom.reserved = strtoul(words[2], NULL, 10);
+                                       ao_ms5607_prom.reserved = strtoul(words[2], NULL, 10);
                                else if (strcmp(words[1], "sens:") == 0)
-                                       ms5607_prom.sens = strtoul(words[2], NULL, 10);
+                                       ao_ms5607_prom.sens = strtoul(words[2], NULL, 10);
                                else if (strcmp(words[1], "off:") == 0)
-                                       ms5607_prom.off = strtoul(words[2], NULL, 10);
+                                       ao_ms5607_prom.off = strtoul(words[2], NULL, 10);
                                else if (strcmp(words[1], "tcs:") == 0)
-                                       ms5607_prom.tcs = strtoul(words[2], NULL, 10);
+                                       ao_ms5607_prom.tcs = strtoul(words[2], NULL, 10);
                                else if (strcmp(words[1], "tco:") == 0)
-                                       ms5607_prom.tco = strtoul(words[2], NULL, 10);
+                                       ao_ms5607_prom.tco = strtoul(words[2], NULL, 10);
                                else if (strcmp(words[1], "tref:") == 0)
-                                       ms5607_prom.tref = strtoul(words[2], NULL, 10);
+                                       ao_ms5607_prom.tref = strtoul(words[2], NULL, 10);
                                else if (strcmp(words[1], "tempsens:") == 0)
-                                       ms5607_prom.tempsens = strtoul(words[2], NULL, 10);
+                                       ao_ms5607_prom.tempsens = strtoul(words[2], NULL, 10);
                                else if (strcmp(words[1], "crc:") == 0)
-                                       ms5607_prom.crc = strtoul(words[2], NULL, 10);
+                                       ao_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);
@@ -791,7 +788,7 @@ ao_sleep(void *wchan)
 
                                for (i = 2; i < nword; i++) {
                                        for (j = 0; j < NUM_PYRO_VALUES; j++)
-                                               if (!strcmp (words[2], ao_pyro_values[j].name))
+                                               if (!strcmp (words[i], ao_pyro_values[j].name))
                                                        break;
                                        if (j == NUM_PYRO_VALUES)
                                                continue;
@@ -991,6 +988,7 @@ void run_flight_fixed(char *name, FILE *f, int summary, char *info)
        emulator_in = f;
        emulator_info = info;
        ao_summary = summary;
+
        ao_flight_init();
        ao_flight();
 }
index ad593204b2394a9157220b575f4146621cd132f8..1c571f1cbd1587aeedeb4c79c78655ed98943fda 100644 (file)
@@ -23,7 +23,7 @@
 #include <stdint.h>
 #include <ao_ms5607.h>
 
-struct ao_ms5607_prom ms5607_prom = {
+struct ao_ms5607_prom ao_ms5607_prom = {
        0x002c,
        0xa6e0,
        0x988e,
index b2ba537bfc36336e6fa82f18e489c4882fc95340..0e90d74485d52d01f37584fb417153364d10e273 100644 (file)
@@ -2,8 +2,8 @@
 # TIDongle build file
 #
 
-vpath %.c ..:../core:../cc1111:../drivers:../product
-vpath %.h ..:../core:../cc1111:../drivers:../product
+vpath %.c ..:../kernel:../cc1111:../drivers:../product
+vpath %.h ..:../kernel:../cc1111:../drivers:../product
 vpath ao-make-product.5c ../util
 
 ifndef VERSION
diff --git a/src/usbrelay-v0.1/ao_pins.h b/src/usbrelay-v0.1/ao_pins.h
new file mode 100644 (file)
index 0000000..a72f6cc
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2014 Bdale Garbee <bdale@gag.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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 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      6
+
+/* USART */
+
+#define HAS_SERIAL             1
+#define USE_SERIAL_0_STDIN     0
+#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              0
+#define SPI_SCK0_P0_6          0
+#define HAS_SPI_1              0
+#define SPI_SCK1_P1_15         0
+#define SPI_MISO1_P0_22                0
+#define SPI_MOSI1_P0_21                0
+
+/* LED */
+
+#define LED_PORT               0
+#define LED_PIN_RED            23
+#define LED_PIN_GREEN          7
+#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)
+
+/* RELAY */
+
+#define RELAY_PORT             0
+#define RELAY_PIN              3
+#define RELAY_BIT              (1 << RELAY_PIN)
+
+/* Kludge the SPI driver to not configure any
+ * pin for SCK or MOSI
+ */
+#define HAS_SCK1               0
+#define HAS_MOSI1              0
diff --git a/src/usbrelay-v0.1/ao_serial_lpc.h b/src/usbrelay-v0.1/ao_serial_lpc.h
new file mode 100644 (file)
index 0000000..a95b6af
--- /dev/null
@@ -0,0 +1,33 @@
+#define AO_LPC_USARTCLK 12000000
+
+static const struct {
+       uint16_t dl;
+       uint8_t divaddval;
+       uint8_t mulval;
+} ao_usart_speeds[] = {
+       [AO_SERIAL_SPEED_4800] = { /* actual =  4800.00 */
+               .dl = 125,
+               .divaddval = 1,
+               .mulval = 4
+       },
+       [AO_SERIAL_SPEED_9600] = { /* actual =  9603.07 */
+               .dl = 71,
+               .divaddval = 1,
+               .mulval = 10
+       },
+       [AO_SERIAL_SPEED_19200] = { /* actual = 19181.59 */
+               .dl = 23,
+               .divaddval = 7,
+               .mulval = 10
+       },
+       [AO_SERIAL_SPEED_57600] = { /* actual = 57692.31 */
+               .dl = 7,
+               .divaddval = 6,
+               .mulval = 7
+       },
+       [AO_SERIAL_SPEED_115200] = { /* actual = 115384.6 */
+               .dl = 4,
+               .divaddval = 5,
+               .mulval = 8
+       },
+};
diff --git a/src/usbrelay-v0.1/ao_usbrelay.c b/src/usbrelay-v0.1/ao_usbrelay.c
new file mode 100644 (file)
index 0000000..879094b
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2014 Bdale Garbee <bdale@gag.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+uint8_t                relay_output;
+
+void
+ao_relay_init(void)
+{
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO);
+        lpc_gpio.dir[RELAY_PORT] |= RELAY_BIT;
+}
+
+// switch relay to selected output, turn correct LED on as a side effect
+static void
+ao_relay_control(uint8_t output)
+{
+       switch (output) {
+       case 1:
+               lpc_gpio.pin[RELAY_PORT] |= RELAY_BIT;
+               ao_led_on(AO_LED_RED);
+               ao_led_off(AO_LED_GREEN);
+               break;
+       default:
+               lpc_gpio.pin[RELAY_PORT] &= ~RELAY_BIT;
+               ao_led_off(AO_LED_RED);
+               ao_led_on(AO_LED_GREEN);
+       }
+}
+
+static void
+ao_relay_select(void) __reentrant
+{
+       uint8_t output;
+
+       ao_cmd_decimal();
+        if (ao_cmd_status != ao_cmd_success)
+                return;
+       output = ao_cmd_lex_i;
+       if (output > 1) 
+               printf ("Invalid relay position %u\n", output);
+       else
+               ao_relay_control(output);
+}
+
+static __code struct ao_cmds ao_relay_cmds[] = {
+       { ao_relay_select, "R <output>\0Select relay output" },
+       { 0, NULL }
+};
+
+void
+main(void)
+{
+       ao_clock_init();
+       ao_task_init();
+       ao_timer_init();
+
+       ao_usb_init();
+
+       ao_serial_init();
+
+       ao_led_init(LEDS_AVAILABLE);
+
+       ao_relay_init();
+
+       // initialize to default output
+       relay_output = 0;
+       ao_relay_control(relay_output);
+
+       ao_cmd_init();
+
+       ao_cmd_register(ao_relay_cmds);
+
+       ao_start_scheduler();
+}
diff --git a/src/usbrelay-v0.1/flash-loader/ao_pins.h b/src/usbrelay-v0.1/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..a804600
--- /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      6
+
+#endif /* _AO_PINS_H_ */
diff --git a/src/usbtrng/Makefile b/src/usbtrng/Makefile
new file mode 100644 (file)
index 0000000..80e137e
--- /dev/null
@@ -0,0 +1,70 @@
+#
+# 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_task.c \
+       ao_cmd.c \
+       ao_timer_lpc.c \
+       ao_exti_lpc.c \
+       ao_usb_lpc.c \
+       ao_serial_lpc.c \
+       ao_spi_lpc.c \
+       ao_led_lpc.c
+
+PRODUCT=usbtrng-v0.1
+PRODUCT_DEF=-DUSBTRNG_V_0_1
+IDPRODUCT=0x0028
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+
+PROGNAME=usbtrng-v0.1
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_usbtrng.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/usbtrng/ao_pins.h b/src/usbtrng/ao_pins.h
new file mode 100644 (file)
index 0000000..b1fa6eb
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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 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      6
+
+/* USART */
+
+#define HAS_SERIAL             1
+#define USE_SERIAL_0_STDIN     0
+#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              0
+#define SPI_SCK0_P0_6          0
+#define HAS_SPI_1              1
+#define SPI_SCK1_P1_15         0
+#define SPI_MISO1_P0_22                1
+#define SPI_MOSI1_P0_21                0
+
+/* LED */
+
+#define LED_PORT               0
+#define LED_PIN_RED            3
+#define LED_PIN_GREEN          21
+#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)
+
+/* Kludge the SPI driver to not configure any
+ * pin for SCK or MOSI
+ */
+#define HAS_SCK1               0
+#define HAS_MOSI1              0
diff --git a/src/usbtrng/ao_usbtrng.c b/src/usbtrng/ao_usbtrng.c
new file mode 100644 (file)
index 0000000..6b4d20f
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+#define AO_TRNG_SPI_BUS                1
+#define AO_TRNG_SPI_SPEED      AO_SPI_SPEED_250kHz
+
+static void
+ao_trng_test(void)
+{
+       static uint8_t  random[32];
+       uint8_t         i;
+
+       ao_spi_get(AO_TRNG_SPI_BUS, AO_TRNG_SPI_SPEED);
+       ao_spi_recv(random, sizeof (random), AO_TRNG_SPI_BUS);
+       ao_spi_put(AO_TRNG_SPI_BUS);
+       for (i = 0; i < sizeof (random); i++)
+               printf (" %02x", random[i]);
+       printf ("\n");
+}
+
+static const struct ao_cmds ao_trng_cmds[] = {
+       { ao_trng_test, "R\0Dump some random numbers" },
+       { 0, NULL }
+};
+
+void
+main(void)
+{
+       ao_clock_init();
+       ao_task_init();
+       ao_timer_init();
+
+       ao_spi_init();
+       ao_usb_init();
+
+       ao_serial_init();
+
+       ao_led_init(LEDS_AVAILABLE);
+
+       ao_led_on(AO_LED_GREEN);
+
+       ao_cmd_init();
+
+       ao_cmd_register(ao_trng_cmds);
+
+       ao_start_scheduler();
+}
diff --git a/src/usbtrng/flash-loader/Makefile b/src/usbtrng/flash-loader/Makefile
new file mode 100644 (file)
index 0000000..e34f108
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=usbtrng-v0.1
+include $(TOPDIR)/lpc/Makefile-flash.defs
diff --git a/src/usbtrng/flash-loader/ao_pins.h b/src/usbtrng/flash-loader/ao_pins.h
new file mode 100644 (file)
index 0000000..a804600
--- /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      6
+
+#endif /* _AO_PINS_H_ */
diff --git a/telegps/.gitignore b/telegps/.gitignore
new file mode 100644 (file)
index 0000000..edb509f
--- /dev/null
@@ -0,0 +1,27 @@
+windows/
+linux/
+macosx/
+fat/
+Manifest.txt
+Manifest-fat.txt
+AltosVersion.java
+Info.plist
+libaltosJNI
+classes
+telegps
+telegps-test
+telegps-jdb
+classtelegps.stamp
+telegps-windows.nsi
+TeleGPS-Linux-*.tar.bz2
+TeleGPS-Linux-*.sh
+TeleGPS-Mac-*.zip
+TeleGPS-Windows-*.exe
+telegps.desktop
+telegps-windows.log
+*.dll
+*.dylib
+*.so
+*.jar
+*.class
+*.dmg
diff --git a/telegps/Info.plist.in b/telegps/Info.plist.in
new file mode 100644 (file)
index 0000000..df05bb6
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+       <key>CFBundleName</key>
+       <string>TeleGPS</string>
+       <key>CFBundleVersion</key>
+       <string>@VERSION@</string>
+       <key>CFBundleAllowMixedLocalizations</key>
+       <string>true</string>
+       <key>CFBundleExecutable</key>
+       <string>JavaApplicationStub</string>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleIdentifier</key>
+       <string>org.altusmetrum.telegps</string>
+       <key>CFBundleSignature</key>
+       <string>Altu</string>
+       <key>CFBundleGetInfoString</key>
+       <string>TeleGPS version @VERSION@</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleIconFile</key>
+       <string>TeleGPS.icns</string>
+       <key>Java</key>
+       <dict>
+               <key>MainClass</key>
+               <string>org.altusmetrum.telegps.TeleGPS</string>
+               <key>JVMVersion</key>
+               <string>1.5+</string>
+               <key>ClassPath</key>
+               <array>
+                       <string>$JAVAROOT/telegps.jar</string>
+                       <string>$JAVAROOT/freetts.jar</string>
+               </array>
+               <key>VMOptions</key>
+               <array>
+                 <string>-Xms512M</string>
+                 <string>-Xmx512M</string>
+                 <string>-Dosgi.clean=true</string>
+               </array>
+       </dict>
+</dict>
+</plist>
diff --git a/telegps/Makefile.am b/telegps/Makefile.am
new file mode 100644 (file)
index 0000000..7b550e9
--- /dev/null
@@ -0,0 +1,294 @@
+JAVAROOT=classes
+AM_JAVACFLAGS=-target 1.6 -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked -source 6
+
+man_MANS=telegps.1
+
+altoslibdir=$(libdir)/altos
+
+CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH=".:classes:../altoslib/*:../altosuilib/*:../libaltos:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar:$(FREETTS)/freetts.jar"
+
+bin_SCRIPTS=telegps
+
+telegpsdir=$(datadir)/java
+
+telegps_JAVA= \
+       TeleGPS.java \
+       TeleGPSStatus.java \
+       TeleGPSStatusUpdate.java \
+       TeleGPSInfo.java \
+       TeleGPSState.java \
+       TeleGPSConfig.java \
+       TeleGPSConfigUI.java \
+       TeleGPSPreferences.java \
+       TeleGPSGraphUI.java \
+       TeleGPSDisplayThread.java
+
+JFREECHART_CLASS= \
+    jfreechart.jar
+
+JCOMMON_CLASS=\
+    jcommon.jar
+
+FREETTS_CLASS= \
+       cmudict04.jar \
+       cmulex.jar \
+       cmu_time_awb.jar \
+       cmutimelex.jar \
+       cmu_us_kal.jar \
+       en_us.jar \
+       freetts.jar
+
+JAR=telegps.jar
+
+FATJAR=telegps-fat.jar
+
+LIBALTOS= \
+       libaltos.so \
+       libaltos.dylib \
+       altos64.dll \
+       altos.dll
+
+ALTOSLIB_CLASS=\
+       altoslib_$(ALTOSLIB_VERSION).jar
+
+ALTOSUILIB_CLASS=\
+       altosuilib_$(ALTOSUILIB_VERSION).jar
+
+# Icons
+ICONDIR=$(top_srcdir)/icon
+
+JAVA_ICONS=\
+       $(ICONDIR)/telegps-16.png \
+       $(ICONDIR)/telegps-32.png \
+       $(ICONDIR)/telegps-48.png \
+       $(ICONDIR)/telegps-64.png \
+       $(ICONDIR)/telegps-128.png \
+       $(ICONDIR)/telegps-256.png
+
+# icon base names for jar
+ICONJAR= -C $(ICONDIR) telegps-16.png \
+       -C $(ICONDIR) telegps-32.png \
+       -C $(ICONDIR) telegps-48.png \
+       -C $(ICONDIR) telegps-64.png \
+       -C $(ICONDIR) telegps-128.png \
+       -C $(ICONDIR) telegps-256.png
+
+WINDOWS_ICON=$(ICONDIR)/telegps.ico
+MACOSX_ICON=$(ICONDIR)/TeleGPS.icns
+
+# Firmware
+FIRMWARE_TD_0_2=$(top_srcdir)/src/teledongle-v0.2/teledongle-v0.2-$(VERSION).ihx
+FIRMWARE_TD=$(FIRMWARE_TD_0_2)
+
+FIRMWARE_TBT_1_0=$(top_srcdir)/src/telebt-v1.0/telebt-v1.0-$(VERSION).ihx
+FIRMWARE_TBT=$(FIRMWARE_TBT_1_0)
+
+FIRMWARE_TG_1_0=$(top_srcdir)/src/telegps-v1.0/telegps-v1.0-$(VERSION).ihx
+FIRMWARE_TG=$(FIRMWARE_TG_1_0)
+
+FIRMWARE=$(FIRMWARE_TG) $(FIRMWARE_TD) $(FIRMWARE_TBT)
+
+desktopdir = $(datadir)/applications
+desktop_file = telegps.desktop
+desktop_SCRIPTS = $(desktop_file)
+
+all-local: telegps-test telegps-jdb $(JAR)
+
+clean-local:
+       -rm -rf classes $(JAR) $(FATJAR) \
+               TeleGPS-Linux-*.tar.bz2 TeleGPS-Mac-*.dmg TeleGPS-Windows-*.exe \
+               $(ALTOSLIB_CLASS) \
+               $(ALTOSUILIB_CLASS) \
+               $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt \
+               telegps telegps-test telegps-jdb macosx linux windows telegps-windows.log \
+               telegps-windows.nsi
+
+EXTRA_DIST = $(desktop_file).in
+
+$(desktop_file): $(desktop_file).in
+       sed -e 's#%bindir%#@bindir@#' -e 's#%icondir%#$(datadir)/icons/hicolor/scalable/apps#' ${srcdir}/telegps.desktop.in > $@
+       chmod +x $@
+
+LINUX_DIST=TeleGPS-Linux-$(VERSION).tar.bz2
+LINUX_SH=TeleGPS-Linux-$(VERSION).sh
+MACOSX_DIST=TeleGPS-Mac-$(VERSION).dmg
+WINDOWS_DIST=TeleGPS-Windows-$(VERSION_DASH).exe
+
+TELEGPS_DOC=$(top_srcdir)/doc/telegps.pdf
+
+DOC=$(TELEGPS_DOC)
+
+FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS)
+
+LINUX_FILES=$(FAT_FILES) libaltos.so $(FIRMWARE) $(DOC) telegps.desktop.in ../icon/telegps.svg
+LINUX_EXTRA=telegps-fat telegps.desktop.in
+
+MACOSX_INFO_PLIST=Info.plist
+MACOSX_README=ReadMe-Mac.rtf
+MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(MACOSX_README) $(DOC) $(MACOSX_ICON)
+MACOSX_EXTRA=$(FIRMWARE)
+
+WINDOWS_FILES=$(FAT_FILES) altos.dll altos64.dll $(top_srcdir)/altusmetrum.inf $(top_srcdir)/altusmetrum.cat $(DOC) $(WINDOWS_ICON)
+
+if FATINSTALL
+
+FATTARGET=$(FATDIR)/$(VERSION)
+
+LINUX_DIST_TARGET=$(FATTARGET)/$(LINUX_DIST)
+LINUX_SH_TARGET=$(FATTARGET)/$(LINUX_SH)
+MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST)
+WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST)
+
+fat: $(LINUX_DIST_TARGET) $(LINUX_SH_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET)
+
+$(LINUX_DIST_TARGET): $(LINUX_DIST)
+       mkdir -p $(FATTARGET)
+       cp -p $< $@
+
+$(LINUX_SH_TARGET): $(LINUX_SH)
+       mkdir -p $(FATTARGET)
+       cp -p $< $@
+
+$(MACOSX_DIST_TARGET): $(MACOSX_DIST)
+       mkdir -p $(FATTARGET)
+       cp -p $< $@
+
+$(WINDOWS_DIST_TARGET): $(WINDOWS_DIST)
+       mkdir -p $(FATTARGET)
+       cp -p $< $@
+
+else
+fat: $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) $(WINDOWS_DIST)
+endif
+
+telegps: Makefile
+       echo "#!/bin/sh" > $@
+       echo 'exec java  -Djava.library.path="$(altoslibdir)" -jar "$(telegpsdir)/telegps.jar" "$$@"' >> $@
+       chmod +x $@
+
+telegps-jdb: Makefile
+       echo "#!/bin/sh" > $@
+       echo 'exec jdb -classpath "classes:./*:../libaltos:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="../libaltos/.libs" org.altusmetrum.telegps.TeleGPS "$$@"' >> $@
+       chmod +x $@
+
+telegps-test: Makefile
+       echo "#!/bin/sh" > $@
+       echo 'exec java -Djava.library.path="../libaltos/.libs" -jar telegps.jar "$$@"' >> $@
+       chmod +x $@
+
+install-telegpsJAVA: telegps.jar
+       @$(NORMAL_INSTALL)
+       test -z "$(telegpsdir)" || $(MKDIR_P) "$(DESTDIR)$(telegpsdir)"
+       echo " $(INSTALL_DATA)" "$<" "'$(DESTDIR)$(telegpsdir)/telegps.jar'"; \
+       $(INSTALL_DATA) "$<" "$(DESTDIR)$(telegpsdir)"
+
+$(JAR): classtelegps.stamp Manifest.txt $(JAVA_ICONS) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS)
+       jar cfm $@ Manifest.txt \
+               $(ICONJAR) \
+               -C classes org \
+               -C ../libaltos libaltosJNI
+
+$(FATJAR): classtelegps.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(JAVA_ICONS)
+       jar cfm $@ Manifest-fat.txt \
+               $(ICONJAR) \
+               -C classes org \
+               -C ../libaltos libaltosJNI
+
+classaltosui.stamp: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS)
+
+libaltos.so: build-libaltos
+       -rm -f "$@"
+       $(LN_S) ../libaltos/.libs/"$@" .
+
+libaltos.dylib:
+       -rm -f "$@"
+       $(LN_S) ../libaltos/"$@" .
+
+altos.dll: ../libaltos/altos.dll
+       -rm -f "$@"
+       $(LN_S) ../libaltos/"$@" .
+
+altos64.dll: ../libaltos/altos64.dll
+       -rm -f "$@"
+       $(LN_S) ../libaltos/"$@" .
+
+../libaltos/.libs/libaltos.so: build-libaltos
+
+../libaltos/altos.dll: build-altos-dll
+
+../libaltos/altos64.dll: build-altos64-dll
+
+build-libaltos:
+       +cd ../libaltos && make libaltos.la
+build-altos-dll:
+       +cd ../libaltos && make altos.dll
+
+build-altos64-dll:
+       +cd ../libaltos && make altos64.dll
+
+$(ALTOSLIB_CLASS):
+       -rm -f "$@"
+       $(LN_S) ../altoslib/"$@" .
+
+$(ALTOSUILIB_CLASS):
+       -rm -f "$@"
+       $(LN_S) ../altosuilib/"$@" .
+
+$(FREETTS_CLASS):
+       -rm -f "$@"
+       $(LN_S) "$(FREETTS)"/"$@" .
+
+$(JFREECHART_CLASS):
+       -rm -f "$@"
+       $(LN_S) "$(JFREECHART)"/"$@" .
+
+$(JCOMMON_CLASS):
+       -rm -f "$@"
+       $(LN_S) "$(JCOMMON)"/"$@" .
+
+$(LINUX_DIST): $(LINUX_FILES) $(LINUX_EXTRA)
+       -rm -f $@
+       -rm -rf linux
+       mkdir -p linux/TeleGPS
+       cp -p $(LINUX_FILES) linux/TeleGPS
+       cp -p telegps-fat linux/TeleGPS/telegps
+       chmod +x linux/TeleGPS/telegps
+       tar cjf $@ -C linux TeleGPS
+
+$(LINUX_SH): $(LINUX_DIST) $(srcdir)/../altosui/linux-install.sh
+       sed 's/AltOS/TeleGPS/g' $(srcdir)/../altosui/linux-install.sh | cat - $(LINUX_DIST) > $@
+       chmod +x $@
+
+$(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) Makefile
+       -rm -f $@
+       -rm -rf macosx
+       mkdir macosx
+       cp -a TeleGPS.app macosx/
+       cp -a $(MACOSX_README) macosx/ReadMe.rtf
+       mkdir -p macosx/Doc
+       cp -a $(DOC) macosx/Doc
+       cp -p Info.plist macosx/TeleGPS.app/Contents
+       mkdir -p macosx/AltOS-$(VERSION) macosx/TeleGPS.app/Contents/Resources/Java
+       cp -p $(MACOSX_ICON) macosx/TeleGPS.app/Contents/Resources
+       cp -p $(FATJAR) macosx/TeleGPS.app/Contents/Resources/Java/telegps.jar
+       cp -p libaltos.dylib macosx/TeleGPS.app/Contents/Resources/Java
+       cp -p $(ALTOSLIB_CLASS) macosx/TeleGPS.app/Contents/Resources/Java
+       cp -p $(ALTOSUILIB_CLASS) macosx/TeleGPS.app/Contents/Resources/Java
+       cp -p $(FREETTS_CLASS) macosx/TeleGPS.app/Contents/Resources/Java
+       cp -p $(JFREECHART_CLASS) macosx/TeleGPS.app/Contents/Resources/Java
+       cp -p $(JCOMMON_CLASS) macosx/TeleGPS.app/Contents/Resources/Java
+       cp -p $(MACOSX_EXTRA) macosx/AltOS-$(VERSION)
+       genisoimage -D -V TeleGPS-$(VERSION) -no-pad -r -apple -o $@ macosx
+
+$(WINDOWS_DIST): $(WINDOWS_FILES) telegps-windows.nsi
+       -rm -f $@
+       makensis -Otelegps-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" telegps-windows.nsi || (cat telegps-windows.log && exit 1)
+
+Manifest.txt: Makefile
+       echo 'Main-Class: org.altusmetrum.telegps.TeleGPS' > $@
+       echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS)/freetts.jar $(JCOMMON)/jcommon.jar $(JFREECHART)/jfreechart.jar" >> $@
+
+Manifest-fat.txt:
+       echo 'Main-Class: org.altusmetrum.telegps.TeleGPS' > $@
+       echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) freetts.jar jcommon.jar jfreechart.jar" >> $@
+
diff --git a/telegps/ReadMe-Mac.rtf b/telegps/ReadMe-Mac.rtf
new file mode 100644 (file)
index 0000000..48a82ed
--- /dev/null
@@ -0,0 +1,58 @@
+{\rtf1\ansi\ansicpg1252\deff0\uc1
+{\fonttbl
+{\f0\fnil\fcharset0\fprq0\fttruetype Helvetica;}
+{\f1\fnil\fcharset0\fprq0\fttruetype Arial;}
+{\f2\fnil\fcharset0\fprq0\fttruetype Liberation Serif;}
+{\f3\fnil\fcharset0\fprq0\fttruetype Courier New;}}
+{\colortbl
+\red0\green0\blue0;
+\red255\green255\blue255;
+\red255\green255\blue255;}
+{\stylesheet
+{\s6\fi-431\li720\sbasedon28\snext28 Contents 1;}
+{\s7\fi-431\li1440\sbasedon28\snext28 Contents 2;}
+{\s1\fi-431\li720 Arrowhead List;}
+{\s27\fi-431\li720\sbasedon28 Lower Roman List;}
+{\s29\tx431\sbasedon20\snext28 Numbered Heading 1;}
+{\s30\tx431\sbasedon21\snext28 Numbered Heading 2;}
+{\s12\fi-431\li720 Diamond List;}
+{\s9\fi-431\li2880\sbasedon28\snext28 Contents 4;}
+{\s8\fi-431\li2160\sbasedon28\snext28 Contents 3;}
+{\s31\tx431\sbasedon22\snext28 Numbered Heading 3;}
+{\s32\fi-431\li720 Numbered List;}
+{\s15\sbasedon28 Endnote Text;}
+{\*\cs14\fs20\super Endnote Reference;}
+{\s4\fi-431\li720 Bullet List;}
+{\s5\tx1584\sbasedon29\snext28 Chapter Heading;}
+{\s35\fi-431\li720 Square List;}
+{\s11\fi-431\li720 Dashed List;}
+{\s22\sb440\sa60\f1\fs24\b\sbasedon28\snext28 Heading 3;}
+{\s37\fi-431\li720 Tick List;}
+{\s24\fi-431\li720 Heart List;}
+{\s40\fi-431\li720\sbasedon32 Upper Roman List;}
+{\s39\fi-431\li720\sbasedon32 Upper Case List;}
+{\s16\fi-288\li288\fs20\sbasedon28 Footnote;}
+{\s19\fi-431\li720 Hand List;}
+{\s18\fs20\sbasedon28 Footnote Text;}
+{\s20\sb440\sa60\f1\fs34\b\sbasedon28\snext28 Heading 1;}
+{\s21\sb440\sa60\f1\fs28\b\sbasedon28\snext28 Heading 2;}
+{\s10\qc\sb240\sa120\f1\fs32\b\sbasedon28\snext28 Contents Header;}
+{\s23\sb440\sa60\f1\fs24\b\sbasedon28\snext28 Heading 4;}
+{\s28\f2\fs24 Normal;}
+{\s26\fi-431\li720\sbasedon32 Lower Case List;}
+{\s2\li1440\ri1440\sa120\sbasedon28 Block Text;}
+{\s33\f3\sbasedon28 Plain Text;}
+{\s34\tx1584\sbasedon29\snext28 Section Heading;}
+{\s25\fi-431\li720 Implies List;}
+{\s3\fi-431\li720 Box List;}
+{\s36\fi-431\li720 Star List;}
+{\*\cs17\fs20\super Footnote Reference;}
+{\s38\fi-431\li720 Triangle List;}
+{\s13\fi-288\li288\sbasedon28 Endnote;}}
+\kerning0\cf0\ftnbj\fet2\ftnstart1\ftnnar\aftnnar\ftnstart1\aftnstart1\aenddoc\revprop3{\*\rdf}{\info\uc1}\deftab720\viewkind1\paperw12240\paperh15840\margl1440\margr1440\widowctrl
+\sectd\sbknone\colsx0\pgncont\ltrsect
+\pard\plain\ltrpar\ql\sl240\slmult1\itap0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640{\f0\fs24\lang1033{\*\listtag0}\abinodiroverride\ltrch Installing }{\f0\fs24\lang1033{\*\listtag0}TeleGPS}{\f0\fs24\lang1033{\*\listtag0} software for Mac OS X computers}{\f0\fs24\lang1033{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sl240\slmult1\itap0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640{\f0\fs24\lang1033{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sl240\slmult1\itap0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640{\f0\fs24\lang1033{\*\listtag0}\abinodiroverride\ltrch As with most Mac OS X applications, install }{\f0\fs24\lang1033{\*\listtag0}TeleGPS}{\f0\fs24\lang1033{\*\listtag0} by dragging it from the distribution disk image to a suitable place on your computer.}{\f0\fs24\lang1033{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sl240\slmult1\itap0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640{\f0\fs24\lang1033{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sl240\slmult1\itap0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640{\f0\fs24\lang1033{\*\listtag0}\abinodiroverride\ltrch Thanks for choosing AltusMetrum products!}{\f0\fs24\lang1033{\*\listtag0}\par}}
\ No newline at end of file
diff --git a/telegps/TeleGPS.app/Contents/MacOS/JavaApplicationStub b/telegps/TeleGPS.app/Contents/MacOS/JavaApplicationStub
new file mode 100755 (executable)
index 0000000..c661d3e
Binary files /dev/null and b/telegps/TeleGPS.app/Contents/MacOS/JavaApplicationStub differ
diff --git a/telegps/TeleGPS.app/Contents/PkgInfo b/telegps/TeleGPS.app/Contents/PkgInfo
new file mode 100644 (file)
index 0000000..8a43480
--- /dev/null
@@ -0,0 +1 @@
+APPLAM.O
diff --git a/telegps/TeleGPS.app/Contents/Resources/TeleGPSIcon.icns b/telegps/TeleGPS.app/Contents/Resources/TeleGPSIcon.icns
new file mode 100644 (file)
index 0000000..44e2bce
Binary files /dev/null and b/telegps/TeleGPS.app/Contents/Resources/TeleGPSIcon.icns differ
diff --git a/telegps/TeleGPS.java b/telegps/TeleGPS.java
new file mode 100644 (file)
index 0000000..6e68dd3
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.telegps;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.util.concurrent.*;
+import java.util.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
+
+public class TeleGPS
+       extends AltosUIFrame
+       implements AltosFlightDisplay, AltosFontListener, AltosUnitsListener, ActionListener
+{
+
+       static String[] telegps_icon_names = {
+               "/telegps-16.png",
+               "/telegps-32.png",
+               "/telegps-48.png",
+               "/telegps-64.png",
+               "/telegps-128.png",
+               "/telegps-256.png"
+       };
+
+       static { set_icon_names(telegps_icon_names); }
+
+       static AltosVoice       voice;
+
+       static AltosVoice voice() {
+               if (voice == null)
+                       voice = new AltosVoice();
+               return voice;
+       }
+
+       AltosFlightReader       reader;
+       TeleGPSDisplayThread    thread;
+
+       JMenuBar                menu_bar;
+
+       JMenu                   file_menu;
+       JMenu                   monitor_menu;
+       JMenu                   device_menu;
+       AltosFreqList           frequencies;
+       ActionListener          frequency_listener;
+
+       Container               bag;
+
+       TeleGPSStatus           telegps_status;
+       TeleGPSStatusUpdate     status_update;
+       javax.swing.Timer       status_timer;
+
+       JTabbedPane             pane;
+
+       AltosUIMap              map;
+       TeleGPSInfo             gps_info;
+       TeleGPSState            gps_state;
+       AltosInfoTable          info_table;
+
+       LinkedList<AltosFlightDisplay>  displays;
+
+       /* File menu */
+       final static String     new_command = "new";
+       final static String     graph_command = "graph";
+       final static String     export_command = "export";
+       final static String     load_maps_command = "loadmaps";
+       final static String     preferences_command = "preferences";
+       final static String     close_command = "close";
+       final static String     exit_command = "exit";
+
+       static final String[][] file_menu_entries = new String[][] {
+               { "New Window",         new_command },
+               { "Graph Data",         graph_command },
+               { "Export Data",        export_command },
+               { "Load Maps",          load_maps_command },
+               { "Preferences",        preferences_command },
+               { "Close",              close_command },
+               { "Exit",               exit_command },
+       };
+
+       /* Monitor menu */
+       final static String     connect_command = "connect";
+       final static String     disconnect_command = "disconnect";
+       final static String     scan_command = "scan";
+
+       static final String[][] monitor_menu_entries = new String[][] {
+               { "Connect Device",     connect_command },
+               { "Disconnect",         disconnect_command },
+               { "Scan Channels",      scan_command },
+       };
+
+       /* Device menu */
+       final static String     download_command = "download";
+       final static String     configure_command = "configure";
+       final static String     flash_command = "flash";
+
+       static final String[][] device_menu_entries = new String[][] {
+               { "Download Data",      download_command },
+               { "Configure Device",   configure_command },
+               { "Flash Device",       flash_command },
+       };
+
+       void stop_display() {
+               if (thread != null && thread.isAlive()) {
+                       thread.interrupt();
+                       try {
+                               thread.join();
+                       } catch (InterruptedException ie) {}
+               }
+               thread = null;
+       }
+
+       public void reset() {
+               for (AltosFlightDisplay display : displays)
+                       display.reset();
+       }
+
+       public void font_size_changed(int font_size) {
+               for (AltosFlightDisplay display : displays)
+                       display.font_size_changed(font_size);
+       }
+
+       public void units_changed(boolean imperial_units) {
+               for (AltosFlightDisplay display : displays)
+                       display.units_changed(imperial_units);
+       }
+
+       public void show(AltosState state, AltosListenerState listener_state) {
+               try {
+                       status_update.saved_state = state;
+
+                       if (state == null)
+                               state = new AltosState();
+
+                       int i = 0;
+                       for (AltosFlightDisplay display : displays) {
+                               display.show(state, listener_state);
+                               i++;
+                       }
+               } catch (Exception ex) {
+                       System.out.printf("Exception %s\n", ex.toString());
+                       for (StackTraceElement e : ex.getStackTrace())
+                               System.out.printf("%s\n", e.toString());
+               }
+       }
+
+       void new_window() {
+               new TeleGPS();
+       }
+
+       void preferences() {
+               new TeleGPSPreferences(this, voice());
+       }
+
+       void load_maps() {
+               new AltosUIMapPreload(this);
+       }
+
+       void disconnect() {
+               setTitle("TeleGPS");
+               stop_display();
+               if (status_timer != null) {
+                       status_timer.stop();
+                       status_timer = null;
+                       status_update = null;
+               }
+
+               telegps_status.disable_receive();
+               disable_frequency_menu();
+       }
+
+       void connect(AltosDevice device) {
+               if (reader != null)
+                       disconnect();
+               try {
+                       AltosFlightReader       reader = new AltosTelemetryReader(new AltosSerial(device));
+                       set_reader(reader, device);
+               } catch (FileNotFoundException ee) {
+                       JOptionPane.showMessageDialog(this,
+                                                     ee.getMessage(),
+                                                     String.format ("Cannot open %s", device.toShortString()),
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (AltosSerialInUseException si) {
+                       JOptionPane.showMessageDialog(this,
+                                                     String.format("Device \"%s\" already in use",
+                                                                   device.toShortString()),
+                                                     "Device in use",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (IOException ee) {
+                       JOptionPane.showMessageDialog(this,
+                                                     String.format ("Unknown I/O error on %s", device.toShortString()),
+                                                     "Unknown I/O error",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (TimeoutException te) {
+                       JOptionPane.showMessageDialog(this,
+                                                     String.format ("Timeout on %s", device.toShortString()),
+                                                     "Timeout error",
+                                                     JOptionPane.ERROR_MESSAGE);
+               } catch (InterruptedException ie) {
+                       JOptionPane.showMessageDialog(this,
+                                                     String.format("Interrupted %s", device.toShortString()),
+                                                     "Interrupted exception",
+                                                     JOptionPane.ERROR_MESSAGE);
+               }
+       }
+
+       void connect() {
+               AltosDevice     device = AltosDeviceUIDialog.show(this,
+                                                                 AltosLib.product_basestation);
+               if (device == null)
+                       return;
+               connect(device);
+       }
+
+       public void scan_device_selected(AltosDevice device) {
+               connect(device);
+       }
+
+       void scan() {
+               new AltosScanUI(this, false);
+       }
+
+       void download(){
+               new AltosEepromManage(this, AltosLib.product_telegps);
+       }
+
+       void configure() {
+               new TeleGPSConfig(this);
+       }
+
+       void export() {
+               AltosDataChooser chooser;
+               chooser = new AltosDataChooser(this);
+               AltosStateIterable states = chooser.runDialog();
+               if (states == null)
+                       return;
+               new AltosCSVUI(this, states, chooser.file());
+       }
+
+       void graph() {
+               AltosDataChooser chooser;
+               chooser = new AltosDataChooser(this);
+               AltosStateIterable states = chooser.runDialog();
+               if (states == null)
+                       return;
+               try {
+                       new TeleGPSGraphUI(states, chooser.file());
+               } catch (InterruptedException ie) {
+               } catch (IOException ie) {
+               }
+       }
+
+       void flash() {
+               AltosFlashUI.show(this);
+       }
+
+       public void actionPerformed(ActionEvent ev) {
+
+               /* File menu */
+               if (new_command.equals(ev.getActionCommand())) {
+                       new_window();
+                       return;
+               }
+               if (preferences_command.equals(ev.getActionCommand())) {
+                       preferences();
+                       return;
+               }
+               if (load_maps_command.equals(ev.getActionCommand())) {
+                       load_maps();
+                       return;
+               }
+               if (close_command.equals(ev.getActionCommand())) {
+                       close();
+                       return;
+               }
+               if (exit_command.equals(ev.getActionCommand()))
+                       System.exit(0);
+
+               /* Monitor menu */
+               if (connect_command.equals(ev.getActionCommand())) {
+                       connect();
+                       return;
+               }
+               if (disconnect_command.equals(ev.getActionCommand())) {
+                       disconnect();
+                       return;
+               }
+               if (scan_command.equals(ev.getActionCommand())) {
+                       scan();
+                       return;
+               }
+
+               /* Device menu */
+               if (download_command.equals(ev.getActionCommand())) {
+                       download();
+                       return;
+               }
+               if (configure_command.equals(ev.getActionCommand())) {
+                       configure();
+                       return;
+               }
+               if (export_command.equals(ev.getActionCommand())) {
+                       export();
+                       return;
+               }
+               if (graph_command.equals(ev.getActionCommand())) {
+                       graph();
+                       return;
+               }
+               if (flash_command.equals(ev.getActionCommand())) {
+                       flash();
+                       return;
+               }
+       }
+
+       void enable_frequency_menu(int serial, final AltosFlightReader reader) {
+
+               if (frequency_listener != null)
+                       disable_frequency_menu();
+
+               frequency_listener = new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       double frequency = frequencies.frequency();
+                                       try {
+                                               reader.set_frequency(frequency);
+                                       } catch (TimeoutException te) {
+                                       } catch (InterruptedException ie) {
+                                       }
+                                       reader.save_frequency();
+                               }
+                       };
+
+               frequencies.addActionListener(frequency_listener);
+               frequencies.set_product("Monitor");
+               frequencies.set_serial(serial);
+               frequencies.set_frequency(AltosUIPreferences.frequency(serial));
+               frequencies.setEnabled(true);
+
+       }
+
+       void disable_frequency_menu() {
+               if (frequency_listener != null) {
+                       frequencies.removeActionListener(frequency_listener);
+                       frequencies.setEnabled(false);
+                       frequency_listener = null;
+               }
+
+       }
+
+       public void set_reader(AltosFlightReader reader, AltosDevice device) {
+               status_update = new TeleGPSStatusUpdate(telegps_status);
+
+               status_timer = new javax.swing.Timer(100, status_update);
+               status_timer.start();
+
+               setTitle(String.format("TeleGPS %s", reader.name));
+               thread = new TeleGPSDisplayThread(this, voice(), this, reader);
+               thread.start();
+
+               if (device != null)
+                       enable_frequency_menu(device.getSerial(), reader);
+       }
+
+       static int      number_of_windows;
+
+       static public void add_window() {
+               ++number_of_windows;
+       }
+
+       static public void subtract_window() {
+               --number_of_windows;
+               if (number_of_windows == 0)
+                       System.exit(0);
+       }
+
+       private void close() {
+               disconnect();
+               AltosUIPreferences.unregister_font_listener(this);
+               AltosPreferences.unregister_units_listener(this);
+               setVisible(false);
+               dispose();
+               subtract_window();
+       }
+
+       private void add_menu(JMenu menu, String label, String action) {
+               JMenuItem       item = new JMenuItem(label);
+               menu.add(item);
+               item.addActionListener(this);
+               item.setActionCommand(action);
+       }
+
+
+       private JMenu make_menu(String label, String[][] items) {
+               JMenu   menu = new JMenu(label);
+               for (int i = 0; i < items.length; i++)
+                       add_menu(menu, items[i][0], items[i][1]);
+               menu_bar.add(menu);
+               return menu;
+       }
+
+       public TeleGPS() {
+
+               AltosUIPreferences.set_component(this);
+
+               reader = null;
+
+               bag = getContentPane();
+               bag.setLayout(new GridBagLayout());
+
+               GridBagConstraints c = new GridBagConstraints();
+
+               setTitle("TeleGPS");
+
+               menu_bar = new JMenuBar();
+               setJMenuBar(menu_bar);
+
+               file_menu = make_menu("File", file_menu_entries);
+               monitor_menu = make_menu("Monitor", monitor_menu_entries);
+               device_menu = make_menu("Device", device_menu_entries);
+               frequencies = new AltosFreqList();
+               frequencies.setEnabled(false);
+               menu_bar.add(frequencies);
+
+               displays = new LinkedList<AltosFlightDisplay>();
+
+               int serial = -1;
+
+               /* TeleGPS status is always visible */
+               telegps_status = new TeleGPSStatus();
+               c.gridx = 0;
+               c.gridy = 1;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.gridwidth = 2;
+               bag.add(telegps_status, c);
+               c.gridwidth = 1;
+               displays.add(telegps_status);
+
+
+               /* The rest of the window uses a tabbed pane to
+                * show one of the alternate data views
+                */
+               pane = new JTabbedPane();
+
+               /* Make the tabbed pane use the rest of the window space */
+               c.gridx = 0;
+               c.gridy = 2;
+               c.fill = GridBagConstraints.BOTH;
+               c.weightx = 1;
+               c.weighty = 1;
+               c.gridwidth = 2;
+               bag.add(pane, c);
+
+               map = new AltosUIMap();
+               pane.add(map.getName(), map);
+               displays.add(map);
+
+               gps_info = new TeleGPSInfo();
+               pane.add(gps_info.getName(), gps_info);
+               displays.add(gps_info);
+
+               gps_state = new TeleGPSState();
+               pane.add(gps_state.getName(), gps_state);
+               displays.add(gps_state);
+
+               info_table = new AltosInfoTable();
+               pane.add("Table", info_table);
+               displays.add(info_table);
+
+               setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+
+               AltosUIPreferences.register_font_listener(this);
+               AltosPreferences.register_units_listener(this);
+
+               addWindowListener(new WindowAdapter() {
+                               @Override
+                               public void windowClosing(WindowEvent e) {
+                                       close();
+                               }
+                       });
+
+               pack();
+               setVisible(true);
+
+               add_window();
+       }
+
+       public TeleGPS(AltosFlightReader reader) {
+               this();
+               set_reader(reader, null);
+       }
+
+       public TeleGPS(AltosDevice device) {
+               this();
+               connect(device);
+       }
+
+       static AltosStateIterable record_iterable(File file) {
+               FileInputStream in;
+               try {
+                       in = new FileInputStream(file);
+               } catch (Exception e) {
+                       System.out.printf("Failed to open file '%s'\n", file);
+                       return null;
+               }
+               if (file.getName().endsWith("telem"))
+                       return new AltosTelemetryFile(in);
+               else
+                       return new AltosEepromFile(in);
+       }
+
+       static AltosReplayReader replay_file(File file) {
+               AltosStateIterable states = record_iterable(file);
+               if (states == null)
+                       return null;
+               return new AltosReplayReader(states.iterator(), file);
+       }
+
+       static boolean process_graph(File file) {
+               AltosStateIterable states = record_iterable(file);
+               if (states == null)
+                       return false;
+               try {
+                       new TeleGPSGraphUI(states, file);
+               } catch (Exception e) {
+                       return false;
+               }
+               return true;
+       }
+
+       static boolean process_replay(File file) {
+               AltosReplayReader new_reader = replay_file(file);
+               if (new_reader == null)
+                       return false;
+
+               new TeleGPS(new_reader);
+               return true;
+       }
+
+       static final int process_none = 0;
+       static final int process_csv = 1;
+       static final int process_kml = 2;
+       static final int process_graph = 3;
+       static final int process_replay = 4;
+       static final int process_summary = 5;
+       static final int process_cat = 6;
+
+       public static boolean load_library(Frame frame) {
+               if (!AltosUILib.load_library()) {
+                       JOptionPane.showMessageDialog(frame,
+                                                     String.format("No AltOS library in \"%s\"",
+                                                                   System.getProperty("java.library.path","<undefined>")),
+                                                     "Cannot load device access library",
+                                                     JOptionPane.ERROR_MESSAGE);
+                       return false;
+               }
+               return true;
+       }
+
+       public static void help(int code) {
+               System.out.printf("Usage: altosui [OPTION]... [FILE]...\n");
+               System.out.printf("  Options:\n");
+               System.out.printf("    --fetchmaps <lat> <lon>\tpre-fetch maps for site map view\n");
+               System.out.printf("    --replay <filename>\t\trelive the glory of past flights \n");
+               System.out.printf("    --graph <filename>\t\tgraph a flight\n");
+               System.out.printf("    --csv\tgenerate comma separated output for spreadsheets, etc\n");
+               System.out.printf("    --kml\tgenerate KML output for use with Google Earth\n");
+               System.exit(code);
+       }
+
+       public static void main(String[] args) {
+               int     errors = 0;
+
+               load_library(null);
+               try {
+                       UIManager.setLookAndFeel(AltosUIPreferences.look_and_feel());
+               } catch (Exception e) {
+               }
+
+               boolean any_created = false;
+
+
+               /* Handle batch-mode */
+               int process = process_none;
+               for (int i = 0; i < args.length; i++) {
+                       if (args[i].equals("--help"))
+                               help(0);
+                       else if (args[i].equals("--fetchmaps")) {
+                               if (args.length < i + 3) {
+                                       help(1);
+                               } else {
+                                       double lat = Double.parseDouble(args[i+1]);
+                                       double lon = Double.parseDouble(args[i+2]);
+                                       AltosUIMap.prefetch_maps(lat, lon);
+                                       i += 2;
+                               }
+                       } else if (args[i].equals("--replay"))
+                               process = process_replay;
+                       else if (args[i].equals("--kml"))
+                               process = process_kml;
+                       else if (args[i].equals("--csv"))
+                               process = process_csv;
+                       else if (args[i].equals("--graph"))
+                               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 {
+                               File file = new File(args[i]);
+                               switch (process) {
+                               case process_none:
+                               case process_graph:
+                                       if (!process_graph(file))
+                                               ++errors;
+                                       break;
+                               case process_replay:
+                                       if (!process_replay(file))
+                                               ++errors;
+                                       any_created = true;
+                                       break;
+                               case process_kml:
+                                       ++errors;
+                                       break;
+                               case process_csv:
+                                       ++errors;
+                                       break;
+                               case process_summary:
+                                       ++errors;
+                                       break;
+                               case process_cat:
+                                       ++errors;
+                               }
+                       }
+               }
+               if (errors != 0)
+                       System.exit(errors);
+               if (number_of_windows == 0) {
+                       java.util.List<AltosDevice> devices = AltosUSBDevice.list(AltosLib.product_basestation);
+                       if (devices != null)
+                               for (AltosDevice device : devices) {
+                                       new TeleGPS(device);
+                                       any_created = true;
+                               }
+                       if (number_of_windows == 0)
+                               new TeleGPS();
+               }
+       }
+}
diff --git a/telegps/TeleGPSConfig.java b/telegps/TeleGPSConfig.java
new file mode 100644 (file)
index 0000000..3505b0b
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * 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.telegps;
+
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.util.concurrent.*;
+import java.text.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
+
+public class TeleGPSConfig implements ActionListener {
+
+       class int_ref {
+               int     value;
+
+               public int get() {
+                       return value;
+               }
+               public void set(int i) {
+                       value = i;
+               }
+               public int_ref(int i) {
+                       value = i;
+               }
+       }
+
+       class string_ref {
+               String  value;
+
+               public String get() {
+                       return value;
+               }
+               public void set(String i) {
+                       value = i;
+               }
+               public string_ref(String i) {
+                       value = i;
+               }
+       }
+
+       JFrame          owner;
+       AltosDevice     device;
+       AltosSerial     serial_line;
+
+       AltosConfigData data;
+       TeleGPSConfigUI config_ui;
+       boolean         serial_started;
+       boolean         made_visible;
+
+       void start_serial() throws InterruptedException, TimeoutException {
+               serial_started = true;
+       }
+
+       void stop_serial() throws InterruptedException {
+               if (!serial_started)
+                       return;
+               serial_started = false;
+       }
+
+       void update_ui() {
+               data.set_values(config_ui);
+               config_ui.set_clean();
+               if (!made_visible) {
+                       made_visible = true;
+                       config_ui.make_visible();
+               }
+       }
+
+       int     pyro;
+
+       final static int        serial_mode_read = 0;
+       final static int        serial_mode_save = 1;
+       final static int        serial_mode_reboot = 2;
+
+       class SerialData implements Runnable {
+               TeleGPSConfig   config;
+               int             serial_mode;
+
+               void callback(String in_cmd) {
+                       final String cmd = in_cmd;
+                       Runnable r = new Runnable() {
+                                       public void run() {
+                                               if (cmd.equals("abort")) {
+                                                       abort();
+                                               } else if (cmd.equals("all finished")) {
+                                                       if (serial_line != null)
+                                                               update_ui();
+                                               }
+                                       }
+                               };
+                       SwingUtilities.invokeLater(r);
+               }
+
+               void get_data() {
+                       data = null;
+                       try {
+                               start_serial();
+                               data = new AltosConfigData(config.serial_line);
+                       } catch (InterruptedException ie) {
+                       } catch (TimeoutException te) {
+                               try {
+                                       stop_serial();
+                                       callback("abort");
+                               } catch (InterruptedException ie) {
+                               }
+                       } finally {
+                               try {
+                                       stop_serial();
+                               } catch (InterruptedException ie) {
+                               }
+                       }
+                       callback("all finished");
+               }
+
+               void save_data() {
+                       try {
+                               start_serial();
+                               data.save(serial_line, false);
+                       } catch (InterruptedException ie) {
+                       } catch (TimeoutException te) {
+                       } finally {
+                               try {
+                                       stop_serial();
+                               } catch (InterruptedException ie) {
+                               }
+                       }
+               }
+
+               void reboot() {
+                       try {
+                               start_serial();
+                               serial_line.printf("r eboot\n");
+                               serial_line.flush_output();
+                       } catch (InterruptedException ie) {
+                       } catch (TimeoutException te) {
+                       } finally {
+                               try {
+                                       stop_serial();
+                                       serial_line.close();
+                               } catch (InterruptedException ie) {
+                               }
+                       }
+               }
+
+               public void run () {
+                       switch (serial_mode) {
+                       case serial_mode_save:
+                               save_data();
+                               /* fall through ... */
+                       case serial_mode_read:
+                               get_data();
+                               break;
+                       case serial_mode_reboot:
+                               reboot();
+                               break;
+                       }
+               }
+
+               public SerialData(TeleGPSConfig in_config, int in_serial_mode) {
+                       config = in_config;
+                       serial_mode = in_serial_mode;
+               }
+       }
+
+       void run_serial_thread(int serial_mode) {
+               SerialData      sd = new SerialData(this, serial_mode);
+               Thread          st = new Thread(sd);
+               st.start();
+       }
+
+       void init_ui () throws InterruptedException, TimeoutException {
+               config_ui = new TeleGPSConfigUI(owner);
+               config_ui.addActionListener(this);
+               serial_line.set_frame(owner);
+               set_ui();
+       }
+
+       void abort() {
+               if (serial_line != null) {
+                       serial_line.close();
+                       serial_line = null;
+               }
+               JOptionPane.showMessageDialog(owner,
+                                             String.format("Connection to \"%s\" failed",
+                                                           device.toShortString()),
+                                             "Connection Failed",
+                                             JOptionPane.ERROR_MESSAGE);
+               config_ui.setVisible(false);
+       }
+
+       void set_ui() throws InterruptedException, TimeoutException {
+               if (serial_line != null)
+                       run_serial_thread(serial_mode_read);
+               else
+                       update_ui();
+       }
+
+       double frequency() {
+               return AltosConvert.radio_to_frequency(data.radio_frequency,
+                                                      data.radio_setting,
+                                                      data.radio_calibration,
+                                                      data.radio_channel);
+       }
+
+       void save_data() {
+
+               try {
+                       /* bounds check stuff */
+                       if (config_ui.flight_log_max() > data.log_space()/1024) {
+                               JOptionPane.showMessageDialog(owner,
+                                                             String.format("Requested flight log, %dk, is larger than the available space, %dk.\n",
+                                                                           config_ui.flight_log_max(),
+                                                                           data.log_space()/1024),
+                                                             "Maximum Flight Log Too Large",
+                                                             JOptionPane.ERROR_MESSAGE);
+                               return;
+                       }
+
+                       /* Pull data out of the UI and stuff back into our local data record */
+
+                       data.get_values(config_ui);
+                       run_serial_thread(serial_mode_save);
+               } catch (AltosConfigDataException ae) {
+                       JOptionPane.showMessageDialog(owner,
+                                                     ae.getMessage(),
+                                                     "Configuration Data Error",
+                                                     JOptionPane.ERROR_MESSAGE);
+               }
+       }
+
+       public void actionPerformed(ActionEvent e) {
+               String  cmd = e.getActionCommand();
+               try {
+                       if (cmd.equals("Save")) {
+                               save_data();
+                       } else if (cmd.equals("Reset")) {
+                               set_ui();
+                       } else if (cmd.equals("Reboot")) {
+                               if (serial_line != null)
+                                       run_serial_thread(serial_mode_reboot);
+                       } else if (cmd.equals("Close")) {
+                               if (serial_line != null)
+                                       serial_line.close();
+                       }
+               } catch (InterruptedException ie) {
+                       abort();
+               } catch (TimeoutException te) {
+                       abort();
+               }
+       }
+
+       public TeleGPSConfig(JFrame given_owner) {
+               owner = given_owner;
+
+               device = AltosDeviceUIDialog.show(owner, AltosLib.product_telegps);
+               if (device != null) {
+                       try {
+                               serial_line = new AltosSerial(device);
+                               try {
+                                       init_ui();
+                               } catch (InterruptedException ie) {
+                                       abort();
+                               } catch (TimeoutException te) {
+                                       abort();
+                               }
+                       } catch (FileNotFoundException ee) {
+                               JOptionPane.showMessageDialog(owner,
+                                                             ee.getMessage(),
+                                                             "Cannot open target device",
+                                                             JOptionPane.ERROR_MESSAGE);
+                       } catch (AltosSerialInUseException si) {
+                               JOptionPane.showMessageDialog(owner,
+                                                             String.format("Device \"%s\" already in use",
+                                                                           device.toShortString()),
+                                                             "Device in use",
+                                                             JOptionPane.ERROR_MESSAGE);
+                       }
+               }
+       }
+}
diff --git a/telegps/TeleGPSConfigUI.java b/telegps/TeleGPSConfigUI.java
new file mode 100644 (file)
index 0000000..5f269fd
--- /dev/null
@@ -0,0 +1,785 @@
+/*
+ * 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.telegps;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
+
+public class TeleGPSConfigUI
+       extends AltosUIDialog
+       implements ActionListener, ItemListener, DocumentListener, AltosConfigValues, AltosUnitsListener
+{
+
+       Container               pane;
+       JLabel                  product_label;
+       JLabel                  version_label;
+       JLabel                  serial_label;
+       JLabel                  frequency_label;
+       JLabel                  radio_calibration_label;
+       JLabel                  radio_frequency_label;
+       JLabel                  radio_enable_label;
+       JLabel                  aprs_interval_label;
+       JLabel                  flight_log_max_label;
+       JLabel                  callsign_label;
+       JLabel                  tracker_motion_label;
+       JLabel                  tracker_interval_label;
+
+       public boolean          dirty;
+
+       JFrame                  owner;
+       JLabel                  product_value;
+       JLabel                  version_value;
+       JLabel                  serial_value;
+       AltosFreqList           radio_frequency_value;
+       JTextField              radio_calibration_value;
+       JRadioButton            radio_enable_value;
+       JComboBox<String>       aprs_interval_value;
+       JComboBox<String>       flight_log_max_value;
+       JTextField              callsign_value;
+       JComboBox<String>       tracker_motion_value;
+       JComboBox<String>       tracker_interval_value;
+
+       JButton                 save;
+       JButton                 reset;
+       JButton                 reboot;
+       JButton                 close;
+
+       ActionListener          listener;
+
+       static String[]         aprs_interval_values = {
+               "Disabled",
+               "2",
+               "5",
+               "10"
+       };
+
+       static String[]         tracker_motion_values_m = {
+               "2",
+               "5",
+               "10",
+               "25",
+       };
+
+       static String[]         tracker_motion_values_ft = {
+               "5",
+               "20",
+               "50",
+               "100"
+       };
+
+       static String[]         tracker_interval_values = {
+               "1",
+               "2",
+               "5",
+               "10"
+       };
+
+       /* A window listener to catch closing events and tell the config code */
+       class ConfigListener extends WindowAdapter {
+               TeleGPSConfigUI ui;
+
+               public ConfigListener(TeleGPSConfigUI this_ui) {
+                       ui = this_ui;
+               }
+
+               public void windowClosing(WindowEvent e) {
+                       ui.actionPerformed(new ActionEvent(e.getSource(),
+                                                          ActionEvent.ACTION_PERFORMED,
+                                                          "Close"));
+               }
+       }
+
+       public void set_pyros(AltosPyro[] new_pyros) {
+       }
+
+       public AltosPyro[] pyros() {
+               return null;
+       }
+
+       public void set_pyro_firing_time(double new_pyro_firing_time) {
+       }
+
+       public double pyro_firing_time() {
+               return -1;
+       }
+
+       boolean is_telemetrum() {
+               String  product = product_value.getText();
+               return product != null && product.startsWith("TeleGPS");
+       }
+
+       void set_radio_calibration_tool_tip() {
+               if (radio_calibration_value.isEnabled())
+                       radio_calibration_value.setToolTipText("Tune radio output to match desired frequency");
+               else
+                       radio_calibration_value.setToolTipText("Cannot tune radio while connected over packet mode");
+       }
+
+       void set_radio_enable_tool_tip() {
+               if (radio_enable_value.isEnabled())
+                       radio_enable_value.setToolTipText("Enable/Disable telemetry and RDF transmissions");
+               else
+                       radio_enable_value.setToolTipText("Firmware version does not support disabling radio");
+       }
+
+       void set_aprs_interval_tool_tip() {
+               if (aprs_interval_value.isEnabled())
+                       aprs_interval_value.setToolTipText("Enable APRS and set the interval between APRS reports");
+               else
+                       aprs_interval_value.setToolTipText("Hardware doesn't support APRS");
+       }
+
+       void set_flight_log_max_tool_tip() {
+               if (flight_log_max_value.isEnabled())
+                       flight_log_max_value.setToolTipText("Size reserved for each flight log (in kB)");
+               else
+                       flight_log_max_value.setToolTipText("Cannot set max value with flight logs in memory");
+       }
+
+       /* Build the UI using a grid bag */
+       public TeleGPSConfigUI(JFrame in_owner) {
+               super (in_owner, "Configure Device", false);
+
+               owner = in_owner;
+               GridBagConstraints c;
+               int row = 0;
+
+               Insets il = new Insets(4,4,4,4);
+               Insets ir = new Insets(4,4,4,4);
+
+               pane = getContentPane();
+               pane.setLayout(new GridBagLayout());
+
+               /* Product */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               product_label = new JLabel("Product:");
+               pane.add(product_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               product_value = new JLabel("");
+               pane.add(product_value, c);
+               row++;
+
+               /* Version */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               version_label = new JLabel("Software version:");
+               pane.add(version_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               version_value = new JLabel("");
+               pane.add(version_value, c);
+               row++;
+
+               /* Serial */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               serial_label = new JLabel("Serial:");
+               pane.add(serial_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               serial_value = new JLabel("");
+               pane.add(serial_value, c);
+               row++;
+
+               /* Frequency */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               radio_frequency_label = new JLabel("Frequency:");
+               pane.add(radio_frequency_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               radio_frequency_value = new AltosFreqList();
+               radio_frequency_value.addItemListener(this);
+               pane.add(radio_frequency_value, c);
+               radio_frequency_value.setToolTipText("Telemetry, RDF and packet frequency");
+               row++;
+
+               /* Radio Calibration */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               radio_calibration_label = new JLabel("RF Calibration:");
+               pane.add(radio_calibration_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               radio_calibration_value = new JTextField(String.format("%d", 1186611));
+               radio_calibration_value.getDocument().addDocumentListener(this);
+               pane.add(radio_calibration_value, c);
+               set_radio_calibration_tool_tip();
+               row++;
+
+               /* Radio Enable */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               radio_enable_label = new JLabel("Telemetry/RDF/APRS Enable:");
+               pane.add(radio_enable_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               radio_enable_value = new JRadioButton("Enabled");
+               radio_enable_value.addItemListener(this);
+               pane.add(radio_enable_value, c);
+               set_radio_enable_tool_tip();
+               row++;
+
+               /* APRS interval */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               aprs_interval_label = new JLabel("APRS Interval(s):");
+               pane.add(aprs_interval_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               aprs_interval_value = new JComboBox<String>(aprs_interval_values);
+               aprs_interval_value.setEditable(true);
+               aprs_interval_value.addItemListener(this);
+               pane.add(aprs_interval_value, c);
+               set_aprs_interval_tool_tip();
+               row++;
+
+               /* Callsign */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               callsign_label = new JLabel("Callsign:");
+               pane.add(callsign_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               callsign_value = new JTextField(AltosUIPreferences.callsign());
+               callsign_value.getDocument().addDocumentListener(this);
+               pane.add(callsign_value, c);
+               callsign_value.setToolTipText("Callsign reported in telemetry data");
+               row++;
+
+               /* Flight log max */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               flight_log_max_label = new JLabel("Maximum Log Size (kB):");
+               pane.add(flight_log_max_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               flight_log_max_value = new JComboBox<String>();
+               flight_log_max_value.setEditable(true);
+               flight_log_max_value.addItemListener(this);
+               pane.add(flight_log_max_value, c);
+               set_flight_log_max_tool_tip();
+               row++;
+
+               /* Tracker triger horiz distances */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               tracker_motion_label = new JLabel(get_tracker_motion_label());
+               pane.add(tracker_motion_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               tracker_motion_value = new JComboBox<String>(tracker_motion_values());
+               tracker_motion_value.setEditable(true);
+               tracker_motion_value.addItemListener(this);
+               pane.add(tracker_motion_value, c);
+               row++;
+
+               /* Tracker triger vert distances */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               c.ipady = 5;
+               tracker_interval_label = new JLabel("Position Reporting Interval (s):");
+               pane.add(tracker_interval_label, c);
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 4;
+               c.fill = GridBagConstraints.HORIZONTAL;
+               c.weightx = 1;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = ir;
+               c.ipady = 5;
+               tracker_interval_value = new JComboBox<String>(tracker_interval_values);
+               tracker_interval_value.setEditable(true);
+               tracker_interval_value.addItemListener(this);
+               pane.add(tracker_interval_value, c);
+               set_tracker_tool_tip();
+               row++;
+
+               /* Buttons */
+               c = new GridBagConstraints();
+               c.gridx = 0; c.gridy = row;
+               c.gridwidth = 2;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_START;
+               c.insets = il;
+               save = new JButton("Save");
+               pane.add(save, c);
+               save.addActionListener(this);
+               save.setActionCommand("Save");
+
+               c = new GridBagConstraints();
+               c.gridx = 2; c.gridy = row;
+               c.gridwidth = 2;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = il;
+               reset = new JButton("Reset");
+               pane.add(reset, c);
+               reset.addActionListener(this);
+               reset.setActionCommand("Reset");
+
+               c = new GridBagConstraints();
+               c.gridx = 4; c.gridy = row;
+               c.gridwidth = 2;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.CENTER;
+               c.insets = il;
+               reboot = new JButton("Reboot");
+               pane.add(reboot, c);
+               reboot.addActionListener(this);
+               reboot.setActionCommand("Reboot");
+
+               c = new GridBagConstraints();
+               c.gridx = 6; c.gridy = row;
+               c.gridwidth = 2;
+               c.fill = GridBagConstraints.NONE;
+               c.anchor = GridBagConstraints.LINE_END;
+               c.insets = il;
+               close = new JButton("Close");
+               pane.add(close, c);
+               close.addActionListener(this);
+               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 */
+       public void make_visible() {
+               pack();
+               setLocationRelativeTo(owner);
+               setVisible(true);
+       }
+
+       /* If any values have been changed, confirm before closing */
+       public boolean check_dirty(String operation) {
+               if (dirty) {
+                       Object[] options = { String.format("%s anyway", operation), "Keep editing" };
+                       int i;
+                       i = JOptionPane.showOptionDialog(this,
+                                                        String.format("Configuration modified. %s anyway?", operation),
+                                                        "Configuration Modified",
+                                                        JOptionPane.DEFAULT_OPTION,
+                                                        JOptionPane.WARNING_MESSAGE,
+                                                        null, options, options[1]);
+                       if (i != 0)
+                               return false;
+               }
+               return true;
+       }
+
+       void set_dirty() {
+               dirty = true;
+               save.setEnabled(true);
+       }
+
+       public void set_clean() {
+               dirty = false;
+               save.setEnabled(false);
+       }
+
+       public void 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("Close") || cmd.equals("Reboot"))
+                       if (!check_dirty(cmd))
+                               return;
+               listener.actionPerformed(e);
+               if (cmd.equals("Close") || cmd.equals("Reboot")) {
+                       setVisible(false);
+                       dispose();
+               }
+               set_clean();
+       }
+
+       /* ItemListener interface method */
+       public void itemStateChanged(ItemEvent e) {
+               set_dirty();
+       }
+
+       /* DocumentListener interface methods */
+       public void changedUpdate(DocumentEvent e) {
+               set_dirty();
+       }
+
+       public void insertUpdate(DocumentEvent e) {
+               set_dirty();
+       }
+
+       public void removeUpdate(DocumentEvent e) {
+               set_dirty();
+       }
+
+       /* Let the config code hook on a listener */
+       public void addActionListener(ActionListener l) {
+               listener = l;
+       }
+
+       public void units_changed(boolean imperial_units) {
+               if (tracker_motion_value.isEnabled()) {
+                       String motion = tracker_motion_value.getSelectedItem().toString();
+                       tracker_motion_label.setText(get_tracker_motion_label());
+                       set_tracker_motion_values();
+                       set_tracker_motion((int) (AltosConvert.height.parse(motion, !imperial_units) + 0.5));
+               }
+       }
+
+       /* set and get all of the dialog values */
+       public void set_product(String product) {
+               radio_frequency_value.set_product(product);
+               product_value.setText(product);
+               set_flight_log_max_tool_tip();
+       }
+
+       public void set_version(String version) {
+               version_value.setText(version);
+       }
+
+       public void set_serial(int serial) {
+               radio_frequency_value.set_serial(serial);
+               serial_value.setText(String.format("%d", serial));
+       }
+
+       public void set_main_deploy(int new_main_deploy) {
+       }
+
+       public int main_deploy() {
+               return -1;
+       }
+
+       public void set_apogee_delay(int new_apogee_delay) { }
+
+       public int apogee_delay() {
+               return -1;
+       }
+
+       public void set_apogee_lockout(int new_apogee_lockout) { }
+
+       public int apogee_lockout() { return -1; }
+
+       public void set_radio_frequency(double new_radio_frequency) {
+               radio_frequency_value.set_frequency(new_radio_frequency);
+       }
+
+       public double radio_frequency() {
+               return radio_frequency_value.frequency();
+       }
+
+       public void set_radio_calibration(int 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));
+       }
+
+       private int parse_int(String name, String s, boolean split) throws AltosConfigDataException {
+               String v = s;
+               if (split)
+                       v = s.split("\\s+")[0];
+               try {
+                       return Integer.parseInt(v);
+               } catch (NumberFormatException ne) {
+                       throw new AltosConfigDataException("Invalid %s \"%s\"", name, s);
+               }
+       }
+
+       public int radio_calibration() throws AltosConfigDataException {
+               return parse_int("radio calibration", radio_calibration_value.getText(), false);
+       }
+
+       public void set_radio_enable(int new_radio_enable) {
+               if (new_radio_enable >= 0) {
+                       radio_enable_value.setSelected(new_radio_enable > 0);
+                       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();
+       }
+
+       public int radio_enable() {
+               if (radio_enable_value.isEnabled())
+                       return radio_enable_value.isSelected() ? 1 : 0;
+               else
+                       return -1;
+       }
+
+       public void set_callsign(String new_callsign) {
+               callsign_value.setVisible(new_callsign != null);
+               callsign_value.setText(new_callsign);
+       }
+
+       public String callsign() {
+               return callsign_value.getText();
+       }
+
+       int     flight_log_max_limit;
+       int     flight_log_max;
+
+       public String flight_log_max_label(int flight_log_max) {
+               if (flight_log_max_limit != 0) {
+                       int     nflight = flight_log_max_limit / flight_log_max;
+                       String  plural = nflight > 1 ? "s" : "";
+
+                       return String.format("%d (%d flight%s)", flight_log_max, nflight, plural);
+               }
+               return String.format("%d", flight_log_max);
+       }
+
+       public void set_flight_log_max(int new_flight_log_max) {
+               flight_log_max_value.setSelectedItem(flight_log_max_label(new_flight_log_max));
+               flight_log_max = new_flight_log_max;
+               set_flight_log_max_tool_tip();
+       }
+
+       public void set_flight_log_max_enabled(boolean enable) {
+               flight_log_max_value.setEnabled(enable);
+               set_flight_log_max_tool_tip();
+       }
+
+       public int flight_log_max() throws AltosConfigDataException {
+               return parse_int("flight log max", flight_log_max_value.getSelectedItem().toString(), true);
+       }
+
+       public void set_flight_log_max_limit(int new_flight_log_max_limit) {
+               flight_log_max_limit = new_flight_log_max_limit;
+               flight_log_max_value.removeAllItems();
+               for (int i = 8; i >= 1; i--) {
+                       int     size = flight_log_max_limit / i;
+                       flight_log_max_value.addItem(String.format("%d (%d flights)", size, i));
+               }
+               if (flight_log_max != 0)
+                       set_flight_log_max(flight_log_max);
+       }
+
+       public void set_ignite_mode(int new_ignite_mode) { }
+       public int ignite_mode() { return -1; }
+
+
+       public void set_pad_orientation(int new_pad_orientation) { }
+       public int pad_orientation() { return -1; }
+
+       public void set_beep(int new_beep) { }
+
+       public int beep() { return -1; }
+
+       String[] tracker_motion_values() {
+               if (AltosConvert.imperial_units)
+                       return tracker_motion_values_ft;
+               else
+                       return tracker_motion_values_m;
+       }
+
+       void set_tracker_motion_values() {
+               String[]        v = tracker_motion_values();
+               while (tracker_motion_value.getItemCount() > 0)
+                       tracker_motion_value.removeItemAt(0);
+               for (int i = 0; i < v.length; i++)
+                       tracker_motion_value.addItem(v[i]);
+               tracker_motion_value.setMaximumRowCount(v.length);
+       }
+
+       String get_tracker_motion_label() {
+               return String.format("Logging Trigger Motion (%s):", AltosConvert.height.show_units());
+       }
+
+       void set_tracker_tool_tip() {
+               if (tracker_motion_value.isEnabled())
+                       tracker_motion_value.setToolTipText("How far the device must move before logging");
+               else
+                       tracker_motion_value.setToolTipText("This device doesn't disable logging when stationary");
+               if (tracker_interval_value.isEnabled())
+                       tracker_interval_value.setToolTipText("How often to report GPS position");
+               else
+                       tracker_interval_value.setToolTipText("This device can't configure interval");
+       }
+
+       public void set_tracker_motion(int tracker_motion) {
+               tracker_motion_value.setSelectedItem(AltosConvert.height.say(tracker_motion));
+       }
+
+       public int tracker_motion() throws AltosConfigDataException {
+               return (int) AltosConvert.height.parse(tracker_motion_value.getSelectedItem().toString());
+       }
+
+       public void set_tracker_interval(int tracker_interval) {
+               tracker_interval_value.setSelectedItem(String.format("%d", tracker_interval));
+       }
+
+       public int tracker_interval() throws AltosConfigDataException {
+               return parse_int ("tracker interval", tracker_interval_value.getSelectedItem().toString(), false);
+       }
+
+       public void set_aprs_interval(int new_aprs_interval) {
+               String  s;
+
+               if (new_aprs_interval <= 0)
+                       s = "Disabled";
+               else
+                       s = Integer.toString(new_aprs_interval);
+               aprs_interval_value.setSelectedItem(s);
+               aprs_interval_value.setVisible(new_aprs_interval >= 0);
+               set_aprs_interval_tool_tip();
+       }
+
+       public int aprs_interval() throws AltosConfigDataException {
+               String  s = aprs_interval_value.getSelectedItem().toString();
+
+               if (s.equals("Disabled"))
+                       return 0;
+               return parse_int("aprs interval", s, false);
+       }
+}
diff --git a/telegps/TeleGPSDisplayThread.java b/telegps/TeleGPSDisplayThread.java
new file mode 100644 (file)
index 0000000..a3d4ea0
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * 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.telegps;
+
+import java.awt.*;
+import javax.swing.*;
+import java.io.*;
+import java.text.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
+
+public class TeleGPSDisplayThread extends Thread {
+
+       Frame                   parent;
+       IdleThread              idle_thread;
+       AltosVoice              voice;
+       AltosFlightReader       reader;
+       AltosState              old_state, state;
+       AltosListenerState      listener_state;
+       AltosFlightDisplay      display;
+
+       synchronized void show_safely() {
+               final AltosState my_state = state;
+               final AltosListenerState my_listener_state = listener_state;
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               display.show(my_state, my_listener_state);
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       void reading_error_internal() {
+               JOptionPane.showMessageDialog(parent,
+                                             String.format("Error reading from \"%s\"", reader.name),
+                                             "Telemetry Read Error",
+                                             JOptionPane.ERROR_MESSAGE);
+       }
+
+       void reading_error_safely() {
+               Runnable r = new Runnable() {
+                               public void run() {
+                                       try {
+                                               reading_error_internal();
+                                       } catch (Exception ex) {
+                                       }
+                               }
+                       };
+               SwingUtilities.invokeLater(r);
+       }
+
+       class IdleThread extends Thread {
+
+               boolean started;
+               int     report_interval;
+               long    report_time;
+
+               public synchronized void report(boolean last) {
+                       if (state == null)
+                               return;
+
+                       if (state.height() != AltosLib.MISSING) {
+                               if (state.from_pad != null) {
+                                       voice.speak("Height %s, bearing %s %d, elevation %d, range %s, .\n",
+                                                   AltosConvert.height.say(state.gps_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 {
+                                       voice.speak("Height %s.\n",
+                                                   AltosConvert.height.say(state.height()));
+                               }
+                       }
+               }
+
+               long now () {
+                       return System.currentTimeMillis();
+               }
+
+               void set_report_time() {
+                       report_time = now() + report_interval;
+               }
+
+               public void run () {
+                       try {
+                               for (;;) {
+                                       if (reader.has_monitor_battery()) {
+                                               listener_state.battery = reader.monitor_battery();
+                                               show_safely();
+                                       }
+                                       set_report_time();
+                                       for (;;) {
+                                               voice.drain();
+                                               synchronized (this) {
+                                                       long    sleep_time = report_time - now();
+                                                       if (sleep_time <= 0)
+                                                               break;
+                                                       wait(sleep_time);
+                                               }
+                                       }
+
+                                       report(false);
+                               }
+                       } catch (InterruptedException ie) {
+                               try {
+                                       voice.drain();
+                               } catch (InterruptedException iie) { }
+                       }
+               }
+
+               public synchronized void notice(boolean spoken) {
+                       if (old_state != null && old_state.state != state.state) {
+                               report_time = now();
+                               this.notify();
+                       } else if (spoken)
+                               set_report_time();
+               }
+
+               public IdleThread() {
+                       report_interval = 10000;
+               }
+       }
+
+       synchronized boolean tell() {
+               boolean ret = false;
+               if (old_state == null || old_state.gps_ready != state.gps_ready) {
+                       if (state.gps_ready) {
+                               voice.speak("GPS ready");
+                               ret = true;
+                       }
+                       else if (old_state != null) {
+                               voice.speak("GPS lost");
+                               ret = true;
+                       }
+               }
+               old_state = state;
+               return ret;
+       }
+
+       public void run() {
+               boolean         interrupted = false;
+               boolean         told;
+
+               idle_thread = new IdleThread();
+               idle_thread.start();
+
+               try {
+                       for (;;) {
+                               try {
+                                       state = reader.read();
+                                       if (state == null)
+                                               break;
+                                       reader.update(state);
+                                       show_safely();
+                                       told = tell();
+                                       idle_thread.notice(told);
+                               } catch (ParseException pp) {
+                                       System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage());
+                               } catch (AltosCRCException ce) {
+                                       ++listener_state.crc_errors;
+                                       show_safely();
+                               }
+                       }
+               } catch (InterruptedException ee) {
+                       interrupted = true;
+               } catch (IOException ie) {
+                       reading_error_safely();
+               } finally {
+                       if (!interrupted)
+                               idle_thread.report(true);
+                       reader.close(interrupted);
+                       idle_thread.interrupt();
+                       try {
+                               idle_thread.join();
+                       } catch (InterruptedException ie) {}
+               }
+       }
+
+       public TeleGPSDisplayThread(Frame in_parent, AltosVoice in_voice, AltosFlightDisplay in_display, AltosFlightReader in_reader) {
+               listener_state = new AltosListenerState();
+               parent = in_parent;
+               voice = in_voice;
+               display = in_display;
+               reader = in_reader;
+               display.reset();
+       }
+}
diff --git a/telegps/TeleGPSGraphUI.java b/telegps/TeleGPSGraphUI.java
new file mode 100644 (file)
index 0000000..244eb7b
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2010 Anthony Towns
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 or any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.telegps;
+
+import java.io.*;
+import java.util.ArrayList;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.io.*;
+import java.util.concurrent.*;
+import java.util.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
+
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.ui.RefineryUtilities;
+
+public class TeleGPSGraphUI extends AltosUIFrame
+{
+       JTabbedPane             pane;
+       AltosGraph              graph;
+       AltosUIEnable           enable;
+       AltosUIMap              map;
+       AltosState              state;
+       AltosFlightStats        stats;
+       AltosGraphDataSet       graphDataSet;
+       AltosFlightStatsTable   statsTable;
+
+       void fill_map(AltosStateIterable states) {
+               for (AltosState state : states) {
+                       if (state.gps != null && state.gps.locked && state.gps.nsat >= 4)
+                               map.show(state, null);
+               }
+       }
+
+       private void close() {
+               setVisible(false);
+               dispose();
+               TeleGPS.subtract_window();
+       }
+
+       TeleGPSGraphUI(AltosStateIterable states, File file) throws InterruptedException, IOException {
+               super(file.getName());
+               state = null;
+
+               pane = new JTabbedPane();
+
+               enable = new AltosUIEnable();
+               stats = new AltosFlightStats(states);
+               graphDataSet = new AltosGraphDataSet(states);
+               graph = new AltosGraph(enable, stats, graphDataSet);
+               statsTable = new AltosFlightStatsTable(stats);
+
+               map = new AltosUIMap();
+
+               pane.add("Graph", graph.panel);
+               pane.add("Configure Graph", enable);
+               pane.add("Statistics", statsTable);
+               fill_map(states);
+               pane.add("Map", map);
+
+               setContentPane (pane);
+
+               addWindowListener(new WindowAdapter() {
+                               @Override
+                               public void windowClosing(WindowEvent e) {
+                                       close();
+                               }
+                       });
+
+               pack();
+
+               setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+
+               TeleGPS.add_window();
+
+               setVisible(true);
+
+               if (state != null)
+                       map.centre(state);
+
+       }
+}
diff --git a/telegps/TeleGPSInfo.java b/telegps/TeleGPSInfo.java
new file mode 100644 (file)
index 0000000..e87fea9
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * 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.telegps;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
+
+public class TeleGPSInfo extends AltosUIFlightTab {
+
+       JLabel                          cur, max;
+
+       abstract class Value extends AltosUIUnitsIndicator {
+               public abstract void show(AltosState state, AltosListenerState listener_state);
+
+               public Value (Container container, int y, AltosUnits units, String text) {
+                       super(container, y, units, text, 1, false, 2);
+               }
+       }
+
+       abstract class DualValue extends AltosUIUnitsIndicator {
+               public DualValue (Container container, int y, AltosUnits units, String text) {
+                       super(container, y, units, text, 2, false, 1);
+               }
+       }
+
+       abstract class ValueHold extends DualValue {
+               public void reset() {
+                       super.reset();
+               }
+               public ValueHold (Container container, int y, AltosUnits units, String text) {
+                       super(container, y, units, text);
+               }
+       }
+
+       class Altitude extends ValueHold {
+               public double value(AltosState state, int i) {
+                       if (i == 0)
+                               return state.altitude();
+                       else
+                               return state.max_altitude();
+               }
+
+               public Altitude (Container container, int y) {
+                       super (container, y, AltosConvert.height, "Altitude");
+               }
+       }
+
+       class AscentRate extends ValueHold {
+               public double value(AltosState state, int i) {
+                       if (i == 0)
+                               return state.gps_ascent_rate();
+                       else
+                               return state.max_gps_ascent_rate();
+               }
+               public AscentRate (Container container, int y) {
+                       super (container, y, AltosConvert.speed, "Ascent Rate");
+               }
+       }
+
+       class GroundSpeed extends ValueHold {
+               public double value(AltosState state, int i) {
+                       if (i == 0)
+                               return state.gps_ground_speed();
+                       else
+                               return state.max_gps_ground_speed();
+               }
+               public GroundSpeed (Container container, int y) {
+                       super (container, y, AltosConvert.speed, "Ground Speed");
+               }
+       }
+
+       class Course extends AltosUIIndicator {
+
+               public void show (AltosState state, AltosListenerState listener_state) {
+                       double  course = state.gps_course();
+                       if (course == AltosLib.MISSING)
+                               show("Missing", "Missing");
+                       else
+                               show( String.format("%3.0f°", course),
+                                     AltosConvert.bearing_to_words(
+                                             AltosConvert.BEARING_LONG,
+                                             course));
+               }
+               public Course (Container container, int y) {
+                       super (container, y, "Course", 2, false, 1);
+               }
+       }
+
+       class Lat extends AltosUIIndicator {
+
+               String pos(double p, String pos, String neg) {
+                       String  h = pos;
+                       if (p < 0) {
+                               h = neg;
+                               p = -p;
+                       }
+                       int deg = (int) Math.floor(p);
+                       double min = (p - Math.floor(p)) * 60.0;
+                       return String.format("%s %4d° %9.6f", h, deg, min);
+               }
+
+               public void show (AltosState state, AltosListenerState listener_state) {
+                       if (state.gps != null && state.gps.connected && state.gps.lat != AltosLib.MISSING)
+                               show(pos(state.gps.lat,"N", "S"));
+                       else
+                               show("Missing");
+               }
+               public Lat (Container container, int y) {
+                       super (container, y, "Latitude", 1, false, 2);
+               }
+       }
+
+       class Lon extends AltosUIIndicator {
+
+               String pos(double p, String pos, String neg) {
+                       String  h = pos;
+                       if (p < 0) {
+                               h = neg;
+                               p = -p;
+                       }
+                       int deg = (int) Math.floor(p);
+                       double min = (p - Math.floor(p)) * 60.0;
+                       return String.format("%s %4d° %9.6f", h, deg, min);
+               }
+
+               public void show (AltosState state, AltosListenerState listener_state) {
+                       if (state.gps != null && state.gps.connected && state.gps.lon != AltosLib.MISSING)
+                               show(pos(state.gps.lon,"E", "W"));
+                       else
+                               show("Missing");
+               }
+               public Lon (Container container, int y) {
+                       super (container, y, "Longitude", 1, false, 2);
+               }
+       }
+
+       class GPSLocked extends AltosUIIndicator {
+
+               public void show (AltosState state, AltosListenerState listener_state) {
+                       if (state == null || state.gps == null)
+                               hide();
+                       else {
+                               int soln = state.gps.nsat;
+                               int nsat = state.gps.cc_gps_sat != null ? state.gps.cc_gps_sat.length : 0;
+                               show("%4d in solution", soln,
+                                    "%4d in view", nsat);
+                               set_lights(state.gps.locked && soln >= 4);
+                       }
+               }
+               public GPSLocked (Container container, int y) {
+                       super (container, y, "GPS Locked", 2, true, 1);
+               }
+       }
+
+       public void font_size_changed(int font_size) {
+               cur.setFont(AltosUILib.label_font);
+               max.setFont(AltosUILib.label_font);
+               super.font_size_changed(font_size);
+       }
+
+       public void labels(Container container, int y) {
+               GridBagLayout           layout = (GridBagLayout)(container.getLayout());
+               GridBagConstraints      c;
+
+               cur = new JLabel("Current");
+               cur.setFont(AltosUILib.label_font);
+               c = new GridBagConstraints();
+               c.gridx = 2; c.gridy = y;
+               c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad);
+               layout.setConstraints(cur, c);
+               add(cur);
+
+               max = new JLabel("Maximum");
+               max.setFont(AltosUILib.label_font);
+               c.gridx = 3; c.gridy = y;
+               layout.setConstraints(max, c);
+               add(max);
+       }
+
+       public String getName() {
+               return "Location";
+       }
+
+       public TeleGPSInfo() {
+               int y = 0;
+               labels(this, y++);
+               add(new Altitude(this, y++));
+               add(new GroundSpeed(this, y++));
+               add(new AscentRate(this, y++));
+               add(new Course(this, y++));
+               add(new Lat(this, y++));
+               add(new Lon(this, y++));
+               add(new GPSLocked(this, y++));
+       }
+}
diff --git a/telegps/TeleGPSPreferences.java b/telegps/TeleGPSPreferences.java
new file mode 100644 (file)
index 0000000..8bd371f
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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.telegps;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.beans.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.altusmetrum.altosuilib_2.*;
+
+public class TeleGPSPreferences
+       extends AltosUIConfigure
+       implements DocumentListener
+{
+       AltosVoice      voice;
+
+       public JTextField       callsign_value;
+       public JComboBox<String>        position_value;
+
+       /* DocumentListener interface methods */
+       public void insertUpdate(DocumentEvent e) {
+               changedUpdate(e);
+       }
+
+       public void removeUpdate(DocumentEvent e) {
+               changedUpdate(e);
+       }
+
+       public void changedUpdate(DocumentEvent e) {
+               if (callsign_value != null)
+                       AltosUIPreferences.set_callsign(callsign_value.getText());
+       }
+
+       public void add_voice() {
+
+               /* Voice settings */
+               pane.add(new JLabel("Voice"), constraints(0, 1));
+
+               JRadioButton enable_voice = new JRadioButton("Enable", AltosUIPreferences.voice());
+               enable_voice.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       JRadioButton item = (JRadioButton) e.getSource();
+                                       boolean enabled = item.isSelected();
+                                       AltosUIPreferences.set_voice(enabled);
+                                       if (enabled)
+                                               voice.speak_always("Enable voice.");
+                                       else
+                                               voice.speak_always("Disable voice.");
+                               }
+                       });
+               pane.add(enable_voice, constraints(1, 1));
+               enable_voice.setToolTipText("Enable/Disable all audio in-flight announcements");
+
+               JButton test_voice = new JButton("Test Voice");
+               test_voice.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       voice.speak("That's one small step for man; one giant leap for mankind.");
+                               }
+                       });
+               pane.add(test_voice, constraints(2, 1));
+               test_voice.setToolTipText("Play a stock audio clip to check volume");
+               row++;
+       }
+
+       public void add_callsign() {
+               /* Callsign setting */
+               pane.add(new JLabel("Callsign"), constraints(0, 1));
+
+               callsign_value = new JTextField(AltosUIPreferences.callsign());
+               callsign_value.getDocument().addDocumentListener(this);
+               callsign_value.setToolTipText("Callsign sent in packet mode");
+               pane.add(callsign_value, constraints(1, 2, GridBagConstraints.BOTH));
+               row++;
+       }
+
+       public void add_bluetooth() {
+               JButton manage_bluetooth = new JButton("Manage Bluetooth");
+               manage_bluetooth.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       AltosBTManage.show(owner, AltosBTKnown.bt_known());
+                               }
+                       });
+               pane.add(manage_bluetooth, constraints(0, 2));
+               /* in the same row as add_frequencies, so don't bump row */
+       }
+
+       public void add_frequencies() {
+               JButton manage_frequencies = new JButton("Manage Frequencies");
+               manage_frequencies.addActionListener(new ActionListener() {
+                               public void actionPerformed(ActionEvent e) {
+                                       AltosConfigFreqUI.show(owner);
+                               }
+                       });
+               manage_frequencies.setToolTipText("Configure which values are shown in frequency menus");
+               pane.add(manage_frequencies, constraints(2, 1));
+               row++;
+       }
+
+       public TeleGPSPreferences(JFrame owner, AltosVoice voice) {
+               super(owner, "TeleGPS Preferences", "Configure TeleGPS");
+
+               this.voice = voice;
+       }
+}
diff --git a/telegps/TeleGPSState.java b/telegps/TeleGPSState.java
new file mode 100644 (file)
index 0000000..a76182e
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright © 2014 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.telegps;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
+
+public class TeleGPSState extends AltosUIFlightTab {
+
+       JLabel  cur, max;
+
+       abstract class Value extends AltosUIUnitsIndicator {
+               public Value (Container container, int y, AltosUnits units, String text) {
+                       super(container, y, units, text, 1, false, 2);
+               }
+       }
+
+       abstract class DualValue extends AltosUIUnitsIndicator {
+               public DualValue (Container container, int y, AltosUnits units, String text) {
+                       super(container, y, units, text, 2, false, 1);
+               }
+       }
+
+       abstract class ValueHold extends DualValue {
+               public ValueHold (Container container, int y, AltosUnits units, String text) {
+                       super(container, y, units, text);
+               }
+       }
+
+       class Height extends ValueHold {
+               public double value(AltosState state, int i) {
+                       if (i == 0)
+                               return state.height();
+                       else
+                               return state.max_height();
+               }
+
+               public Height(Container container, int y) {
+                       super(container, y, AltosConvert.height, "Height");
+               }
+       }
+
+       class Speed extends ValueHold {
+               public double value(AltosState state, int i) {
+                       if (i == 0)
+                               return state.gps_speed();
+                       else
+                               return state.max_gps_speed();
+               }
+
+               public Speed(Container container, int y) {
+                       super(container, y, AltosConvert.speed, "Speed");
+               }
+       }
+
+       class Distance extends Value {
+               public double value(AltosState state, int i) {
+                       if (state.from_pad != null)
+                               return state.from_pad.distance;
+                       else
+                               return AltosLib.MISSING;
+               }
+
+               public Distance(Container container, int y) {
+                       super(container, y, AltosConvert.distance, "Distance");
+               }
+       }
+
+       class Range extends Value {
+               public double value(AltosState state, int i) {
+                       return state.range;
+               }
+               public Range (Container container, int y) {
+                       super (container, y, AltosConvert.distance, "Range");
+               }
+       }
+
+       class Bearing extends AltosUIIndicator {
+               public void show (AltosState state, AltosListenerState listener_state) {
+                       if (state.from_pad != null && state.from_pad.bearing != AltosLib.MISSING) {
+                               show( String.format("%3.0f°", state.from_pad.bearing),
+                                     state.from_pad.bearing_words(
+                                             AltosGreatCircle.BEARING_LONG));
+                       } else {
+                               show("Missing", "Missing");
+                       }
+               }
+               public Bearing (Container container, int y) {
+                       super (container, y, "Bearing", 2, false, 1);
+               }
+       }
+
+       class Elevation extends AltosUIIndicator {
+               public void show (AltosState state, AltosListenerState listener_state) {
+                       if (state.elevation == AltosLib.MISSING)
+                               show("Missing");
+                       else
+                               show("%3.0f°", state.elevation);
+               }
+               public Elevation (Container container, int y) {
+                       super (container, y, "Elevation", 1, false, 2);
+               }
+       }
+
+       class FirmwareVersion extends AltosUIIndicator {
+               public void show(AltosState state, AltosListenerState listener_state) {
+                       if (state.firmware_version == null)
+                               show("Missing");
+                       else
+                               show(state.firmware_version);
+               }
+
+               public FirmwareVersion(Container container, int y) {
+                       super(container, y, "Firmware Version", 1, false, 2);
+               }
+       }
+
+       class FlightLogMax extends AltosUIIndicator {
+               public void show(AltosState state, AltosListenerState listener_state) {
+                       if (state.flight_log_max == AltosLib.MISSING)
+                               show("Missing");
+                       else
+                               show(String.format("%dkB", state.flight_log_max));
+               }
+
+               public FlightLogMax(Container container, int y) {
+                       super(container, y, "Flight Log Storage", 1, false, 2);
+               }
+       }
+
+       class BatteryVoltage extends AltosUIVoltageIndicator {
+               public double voltage(AltosState state) {
+                       return state.battery_voltage;
+               }
+
+               public double good() {
+                       return AltosLib.ao_battery_good;
+               }
+
+               public BatteryVoltage(Container container, int y) {
+                       super(container, y, "Battery Voltage", 2);
+               }
+       }
+
+
+       public void labels(Container container, int y) {
+               GridBagLayout           layout = (GridBagLayout)(container.getLayout());
+               GridBagConstraints      c;
+
+               cur = new JLabel("Current");
+               cur.setFont(AltosUILib.label_font);
+               c = new GridBagConstraints();
+               c.gridx = 2; c.gridy = y;
+               c.insets = new Insets(AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad, AltosUILib.tab_elt_pad);
+               layout.setConstraints(cur, c);
+               add(cur);
+
+               max = new JLabel("Maximum");
+               max.setFont(AltosUILib.label_font);
+               c.gridx = 3; c.gridy = y;
+               layout.setConstraints(max, c);
+               add(max);
+       }
+
+       public void font_size_changed(int font_size) {
+               cur.setFont(AltosUILib.label_font);
+               max.setFont(AltosUILib.label_font);
+               super.font_size_changed(font_size);
+       }
+
+       public String getName() {
+               return "Status";
+       }
+
+       public TeleGPSState() {
+               int y = 0;
+               labels(this, y++);
+               add(new Height(this, y++));
+               add(new Speed(this, y++));
+               add(new Distance(this, y++));
+               add(new Range(this, y++));
+               add(new Bearing(this, y++));
+               add(new Elevation(this, y++));
+               add(new FirmwareVersion(this, y++));
+               add(new FlightLogMax(this, y++));
+               add(new BatteryVoltage(this, y++));
+       }
+}
diff --git a/telegps/TeleGPSStatus.java b/telegps/TeleGPSStatus.java
new file mode 100644 (file)
index 0000000..f3951a3
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * 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.telegps;
+
+import java.awt.*;
+import javax.swing.*;
+import org.altusmetrum.altoslib_4.*;
+import org.altusmetrum.altosuilib_2.*;
+
+public class TeleGPSStatus extends JComponent implements AltosFlightDisplay {
+       GridBagLayout   layout;
+
+       public class Value {
+               JLabel          label;
+               JTextField      value;
+
+               void show(AltosState state, AltosListenerState listener_state) {}
+
+               void reset() {
+                       value.setText("");
+               }
+
+               void set_font() {
+                       label.setFont(AltosUILib.status_font);
+                       value.setFont(AltosUILib.status_font);
+               }
+
+               void setVisible(boolean visible) {
+                       label.setVisible(visible);
+                       value.setVisible(visible);
+               }
+
+               public Value (GridBagLayout layout, int x, String text) {
+                       GridBagConstraints      c = new GridBagConstraints();
+                       c.insets = new Insets(5, 5, 5, 5);
+                       c.anchor = GridBagConstraints.CENTER;
+                       c.fill = GridBagConstraints.BOTH;
+                       c.weightx = 1;
+                       c.weighty = 1;
+
+                       label = new JLabel(text);
+                       label.setFont(AltosUILib.status_font);
+                       label.setHorizontalAlignment(SwingConstants.CENTER);
+                       c.gridx = x; c.gridy = 0;
+                       layout.setConstraints(label, c);
+                       add(label);
+
+                       value = new JTextField("");
+                       value.setEditable(false);
+                       value.setFont(AltosUILib.status_font);
+                       value.setHorizontalAlignment(SwingConstants.CENTER);
+                       c.gridx = x; c.gridy = 1;
+                       layout.setConstraints(value, c);
+                       add(value);
+               }
+       }
+
+       class Call extends Value {
+               String  call;
+
+               void show(AltosState state, AltosListenerState listener_state) {
+                       if (state.callsign != call) {
+                               value.setText(state.callsign);
+                               call = state.callsign;
+                       }
+                       if (state.callsign == null)
+                               setVisible(false);
+                       else
+                               setVisible(true);
+               }
+
+               public void reset() {
+                       super.reset();
+                       call = "";
+               }
+
+               public Call (GridBagLayout layout, int x) {
+                       super (layout, x, "Callsign");
+               }
+       }
+
+       Call call;
+
+       class Serial extends Value {
+               int     serial = -1;
+               void show(AltosState state, AltosListenerState listener_state) {
+                       if (state.serial != serial) {
+                               if (state.serial == AltosLib.MISSING)
+                                       value.setText("none");
+                               else
+                                       value.setText(String.format("%d", state.serial));
+                               serial = state.serial;
+                       }
+               }
+
+               public void reset() {
+                       super.reset();
+                       serial = -1;
+               }
+
+               public Serial (GridBagLayout layout, int x) {
+                       super (layout, x, "Serial");
+               }
+       }
+
+       Serial serial;
+
+       class Flight extends Value {
+
+               int     last_flight = -1;
+
+               void show(AltosState state, AltosListenerState listener_state) {
+                       if (state.flight != last_flight) {
+                               if (state.flight == AltosLib.MISSING)
+                                       value.setText("none");
+                               else
+                                       value.setText(String.format("%d", state.flight));
+                               last_flight = state.flight;
+                       }
+               }
+
+               public void reset() {
+                       super.reset();
+                       last_flight = -1;
+               }
+
+               public Flight (GridBagLayout layout, int x) {
+                       super (layout, x, "Flight");
+               }
+       }
+
+       Flight flight;
+
+       class RSSI extends Value {
+               int     rssi = 10000;
+
+               void show(AltosState state, AltosListenerState listener_state) {
+                       int     new_rssi = state.rssi();
+
+                       if (new_rssi != rssi) {
+                               value.setText(String.format("%d", new_rssi));
+                               if (state.rssi == AltosLib.MISSING)
+                                       setVisible(false);
+                               else
+                                       setVisible(true);
+                               rssi = new_rssi;
+                       }
+               }
+
+               public void reset() {
+                       super.reset();
+                       rssi = 10000;
+               }
+
+               public RSSI (GridBagLayout layout, int x) {
+                       super (layout, x, "RSSI");
+               }
+       }
+
+       RSSI rssi;
+
+       class LastPacket extends Value {
+
+               long    last_secs = -1;
+
+               void show(AltosState state, AltosListenerState listener_state) {
+                       long secs = (System.currentTimeMillis() - state.received_time + 500) / 1000;
+
+                       if (secs != last_secs) {
+                               value.setText(String.format("%d", secs));
+                               last_secs = secs;
+                       }
+               }
+
+               void reset() {
+                       super.reset();
+                       last_secs = -1;
+               }
+
+               void disable() {
+                       value.setText("");
+               }
+
+               public LastPacket(GridBagLayout layout, int x) {
+                       super (layout, x, "Age");
+               }
+       }
+
+       LastPacket last_packet;
+
+       public void disable_receive() {
+               last_packet.disable();
+       }
+
+       public void reset () {
+               call.reset();
+               serial.reset();
+               flight.reset();
+               rssi.reset();
+               last_packet.reset();
+       }
+
+       public void font_size_changed(int font_size) {
+               call.set_font();
+               serial.set_font();
+               flight.set_font();
+               rssi.set_font();
+               last_packet.set_font();
+       }
+
+       public void units_changed(boolean imperial_units) {
+       }
+
+       public void show (AltosState state, AltosListenerState listener_state) {
+               call.show(state, listener_state);
+               serial.show(state, listener_state);
+               flight.show(state, listener_state);
+               rssi.show(state, listener_state);
+               last_packet.show(state, listener_state);
+       }
+
+       public int height() {
+               Dimension d = layout.preferredLayoutSize(this);
+               return d.height;
+       }
+
+       public TeleGPSStatus() {
+               layout = new GridBagLayout();
+
+               setLayout(layout);
+
+               call = new Call(layout, 0);
+               serial = new Serial(layout, 1);
+               flight = new Flight(layout, 2);
+               rssi = new RSSI(layout, 4);
+               last_packet = new LastPacket(layout, 5);
+       }
+}
diff --git a/telegps/TeleGPSStatusUpdate.java b/telegps/TeleGPSStatusUpdate.java
new file mode 100644 (file)
index 0000000..e7684d8
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.telegps;
+
+import java.awt.event.*;
+import org.altusmetrum.altoslib_4.*;
+
+public class TeleGPSStatusUpdate implements ActionListener {
+
+       public AltosState               saved_state;
+       public AltosListenerState       saved_listener_state;
+       TeleGPSStatus                   status;
+
+       public void actionPerformed (ActionEvent e) {
+               if (saved_state != null) {
+                       if (saved_listener_state == null)
+                               saved_listener_state = new AltosListenerState();
+                       status.show(saved_state, saved_listener_state);
+               }
+       }
+
+       public TeleGPSStatusUpdate (TeleGPSStatus in_status) {
+               status = in_status;
+       }
+}
+
diff --git a/telegps/telegps-fat b/telegps/telegps-fat
new file mode 100755 (executable)
index 0000000..8749124
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+me=`which "$0"`
+dir=`dirname "$me"`
+exec java -cp "$dir/*" -Djava.library.path="$dir" -jar "$dir"/telegps-fat.jar  "$@"
diff --git a/telegps/telegps-windows.nsi.in b/telegps/telegps-windows.nsi.in
new file mode 100644 (file)
index 0000000..e6798c4
--- /dev/null
@@ -0,0 +1,194 @@
+!addplugindir ../altosui/Instdrv/NSIS/Plugins
+!include x64.nsh
+; Definitions for Java 1.7 Detection
+!define JRE_VERSION "1.7"
+!define JRE_ALTERNATE "1.6"
+!define JRE32_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=83383&/jre-7u51-windows-i586.exe"
+!define JRE64_URL "http://javadl.sun.com/webapps/download/AutoDL?BundleId=83385&/jre-7u51-windows-x64.exe"
+!define PRODUCT_NAME "TeleGPS Windows Software"
+
+Name "TeleGPS Installer"
+
+; Default install directory
+InstallDir "$PROGRAMFILES\AltusMetrum"
+
+; Tell the installer where to re-install a new version
+InstallDirRegKey HKLM "Software\AltusMetrum" "Install_Dir"
+
+LicenseText "GNU General Public License Version 2"
+LicenseData "../COPYING"
+
+; Need admin privs for Vista or Win7
+RequestExecutionLevel admin
+
+ShowInstDetails Show
+
+ComponentText "TeleGPS Software Installer"
+
+Function .onInit
+       DetailPrint "Checking host operating system"
+       ${If} ${RunningX64}
+               DetailPrint "Installer running on 64-bit host"
+               SetRegView 64
+               StrCpy $INSTDIR "$PROGRAMFILES64\AltusMetrum"
+               ${DisableX64FSRedirection}
+       ${EndIf}
+FunctionEnd
+
+Var JavaDownload
+Var JavaBits
+
+Function GetJRE
+       ${If} ${RunningX64}
+          StrCpy $JavaDownload ${JRE64_URL}
+          StrCpy $JavaBits "64"
+       ${Else}
+          StrCpy $JavaDownload ${JRE32_URL}
+          StrCpy $JavaBits "32"
+       ${EndIf}
+
+        MessageBox MB_OK "${PRODUCT_NAME} uses Java ${JRE_VERSION}, \
+                       $JavaBits bits, it will now \
+                        be downloaded and installed"
+
+        StrCpy $2 "$TEMP\Java Runtime Environment.exe"
+        nsisdl::download /TIMEOUT=30000 $JavaDownload $2
+        Pop $R0 ;Get the return value
+                StrCmp $R0 "success" +3
+                MessageBox MB_OK "Download failed: $R0"
+                Quit
+        ExecWait $2
+        Delete $2
+FunctionEnd
+
+Function DetectJRE
+  ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" \
+             "CurrentVersion"
+
+  StrCmp $2 ${JRE_VERSION} done
+
+  StrCmp $2 ${JRE_ALTERNATE} done
+
+  Call GetJRE
+
+  done:
+FunctionEnd
+
+; Pages to present
+
+Page license
+Page components
+Page directory
+Page instfiles
+
+UninstPage uninstConfirm
+UninstPage instfiles
+
+; And the stuff to install
+
+Section "Install Driver" InstDriver
+
+       InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} AltusMetrumSerial
+       Pop $0
+       DetailPrint "InitDriverSetup: $0"
+       InstDrv::DeleteOemInfFiles /NOUNLOAD
+       InstDrv::CreateDevice /NOUNLOAD
+
+       SetOutPath $INSTDIR
+       File "../altusmetrum.inf"
+       File "../altusmetrum.cat"
+
+       ${DisableX64FSRedirection}
+       IfFileExists $WINDIR\System32\PnPutil.exe 0 nopnp
+               ${DisableX64FSRedirection}
+               nsExec::ExecToLog '"$WINDIR\System32\PnPutil.exe" -i -a "$INSTDIR\altusmetrum.inf"'
+               Goto done
+nopnp:
+               InstDrv::InstallDriver /NOUNLOAD "$INSTDIR\altusmetrum.inf"
+done:
+
+SectionEnd
+
+Section "TeleGPS Application"
+       Call DetectJRE
+
+       SetOutPath $INSTDIR
+
+       File "telegps-fat.jar"
+       File "altoslib_@ALTOSLIB_VERSION@.jar"
+       File "altosuilib_@ALTOSUILIB_VERSION@.jar"
+       File "cmudict04.jar"
+       File "cmulex.jar"
+       File "cmu_time_awb.jar"
+       File "cmutimelex.jar"
+       File "cmu_us_kal.jar"
+       File "en_us.jar"
+       File "freetts.jar"
+       File "jfreechart.jar"
+       File "jcommon.jar"
+
+       File "*.dll"
+
+       File "../icon/*.ico"
+
+       CreateShortCut "$SMPROGRAMS\TeleGPS.lnk" "$SYSDIR\javaw.exe" "-jar telegps-fat.jar" "$INSTDIR\telegps.ico"
+SectionEnd
+
+Section "TeleGPS Desktop Shortcut"
+       CreateShortCut "$DESKTOP\TeleGPS.lnk" "$INSTDIR\telegps-fat.jar"  "" "$INSTDIR\telegps.ico"
+SectionEnd
+
+Section "TeleGPS, TeleDongle and TeleBT Firmware"
+
+       SetOutPath $INSTDIR
+
+       File "../src/telegps-v1.0/telegps-v1.0-${VERSION}.ihx"
+       File "../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx"
+       File "../src/telebt-v1.0/telebt-v1.0-${VERSION}.ihx"
+
+SectionEnd
+
+Section "Documentation"
+
+       SetOutPath $INSTDIR
+
+       File "../doc/telegps.pdf"
+       File "../doc/altos.pdf"
+       File "../doc/telemetry.pdf"
+SectionEnd
+
+Section "Uninstaller"
+
+       ; Deal with the uninstaller
+
+       SetOutPath $INSTDIR
+
+       ; Write the install path to the registry
+       WriteRegStr HKLM SOFTWARE\AltusMetrum "Install_Dir" "$INSTDIR"
+
+       ; Write the uninstall keys for windows
+       WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "DisplayName" "Altus Metrum"
+       WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "UninstallString" '"$INSTDIR\uninstall.exe"'
+       WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "NoModify" "1"
+       WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum" "NoRepair" "1"
+
+       WriteUninstaller "uninstall.exe"
+SectionEnd
+
+Section "Uninstall"
+       DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\AltusMetrum"
+       DeleteRegKey HKLM "Software\AltusMetrum"
+
+       Delete "$INSTDIR\*.*"
+       RMDir "$INSTDIR"
+
+       ; Remove devices
+       InstDrv::InitDriverSetup /NOUNLOAD {4D36E96D-E325-11CE-BFC1-08002BE10318} AltusMetrumSerial
+       InstDrv::DeleteOemInfFiles /NOUNLOAD
+       InstDrv::RemoveAllDevices
+
+       ; Remove shortcuts, if any
+       Delete "$SMPROGRAMS\TeleGPS.lnk"
+       Delete "$DESKTOP\TeleGPS.lnk"
+       
+SectionEnd
diff --git a/telegps/telegps.1 b/telegps/telegps.1
new file mode 100644 (file)
index 0000000..57fa448
--- /dev/null
@@ -0,0 +1,46 @@
+.\"
+.\" Copyright © 2010 Bdale Garbee <bdale@gag.com>
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful, but
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+.\" General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+.\"
+.\"
+.TH ALTOSUI 1 "altosui" ""
+.SH NAME
+altosui \- Rocket flight monitor
+.SH SYNOPSIS
+.B "altosui"
+.SH DESCRIPTION
+.I altosui
+connects to a TeleDongle or TeleMetrum device through a USB serial device.
+It provides a menu-oriented
+user interface to monitor, record and review rocket flight data.
+.SH USAGE
+When connected to a TeleDongle device, altosui turns on the radio
+receiver and listens for telemetry packets. It displays the received
+telemetry data, and reports flight status via voice synthesis. All
+received telemetry information is recorded to a file.
+.P
+When connected to a TeleMetrum device, altosui can be used to configure the
+TeleMetrum, and to downloads the eeprom data and store it in a file.
+.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 ~/TeleMetrum). Files are named using the current date, the serial
+number of the reporting device, the flight number recorded in the data
+and either '.telem' for telemetry data or '.eeprom' for eeprom data.
+.SH AUTHOR
+Keith Packard
diff --git a/telegps/telegps.desktop.in b/telegps/telegps.desktop.in
new file mode 100644 (file)
index 0000000..3d249d8
--- /dev/null
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Type=Application
+Name=TeleGPS
+GenericName=TeleGPS monitor, download and analysis
+Comment=View and log data from TeleGPS tracking devices
+Icon=%icondir%/telegps.svg
+Exec=%bindir%/telegps %f
+Terminal=false
+MimeType=text/plain;
+Categories=Education;Electronics;Science;
diff --git a/telemetrum.inf b/telemetrum.inf
deleted file mode 100755 (executable)
index 220069b..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-; Copyright (C) 2010 Keith Packard (keithp@keithp.com)\r
-; released under GNU General Public License version 2\r
-\r
-[Version]\r
-Signature      = "$Windows NT$"\r
-Class          = Modem\r
-ClassGUID      = {4D36E96D-E325-11CE-BFC1-08002BE10318}\r
-Provider       = %Mfg%\r
-DriverVer      = 08/05/2010,7.1.1.0\r
-PnpLockDown    = 0\r
-DriverPackageDisplayName = %DriverName%\r
-\r
-[DestinationDirs]\r
-FakeModemCopyFileSection = 12\r
-DefaultDestDir = 12\r
-\r
-[ControlFlags]\r
-\r
-[Manufacturer]\r
-%Mfg% = Models, NTx86, NTamd64, NTia64\r
-\r
-[Models]\r
-%AltusMetrum%  = AltusMetrum.Install, USB\VID_FFFE&PID_000A, AltusMetrumSerial\r
-%TeleMetrum%   = AltusMetrum.Install, USB\VID_FFFE&PID_000B, AltusMetrumSerial\r
-%TeleDongle%   = AltusMetrum.Install, USB\VID_FFFE&PID_000C, AltusMetrumSerial\r
-%TeleTerra%    = AltusMetrum.Install, USB\VID_FFFE&PID_000D, AltusMetrumSerial\r
-%TeleBT%       = AltusMetrum.Install, USB\VID_FFFE&PID_000e, AltusMetrumSerial\r
-%TeleLaunch%   = AltusMetrum.Install, USB\VID_FFFE&PID_000f, AltusMetrumSerial\r
-%TeleLCO%      = AltusMetrum.Install, USB\VID_FFFE&PID_0010, AltusMetrumSerial\r
-%TeleScience%  = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial\r
-%TelePyro%     = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial\r
-%TeleShield%   = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial\r
-%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
-%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
-%AltusMetrum2b%        = AltusMetrum.Install, USB\VID_FFFE&PID_002b, AltusMetrumSerial\r
-%AltusMetrum2c%        = AltusMetrum.Install, USB\VID_FFFE&PID_002c, AltusMetrumSerial\r
-\r
-[Models.NTx86]\r
-%AltusMetrum%  = AltusMetrum.Install, USB\VID_FFFE&PID_000A, AltusMetrumSerial\r
-%TeleMetrum%   = AltusMetrum.Install, USB\VID_FFFE&PID_000B, AltusMetrumSerial\r
-%TeleDongle%   = AltusMetrum.Install, USB\VID_FFFE&PID_000C, AltusMetrumSerial\r
-%TeleTerra%    = AltusMetrum.Install, USB\VID_FFFE&PID_000D, AltusMetrumSerial\r
-%TeleBT%       = AltusMetrum.Install, USB\VID_FFFE&PID_000e, AltusMetrumSerial\r
-%TeleLaunch%   = AltusMetrum.Install, USB\VID_FFFE&PID_000f, AltusMetrumSerial\r
-%TeleLCO%      = AltusMetrum.Install, USB\VID_FFFE&PID_0010, AltusMetrumSerial\r
-%TeleScience%  = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial\r
-%TelePyro%     = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial\r
-%TeleShield%   = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial\r
-%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
-%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
-%AltusMetrum2b%        = AltusMetrum.Install, USB\VID_FFFE&PID_002b, AltusMetrumSerial\r
-%AltusMetrum2c%        = AltusMetrum.Install, USB\VID_FFFE&PID_002c, AltusMetrumSerial\r
-\r
-[Models.NTamd64]\r
-%AltusMetrum%  = AltusMetrum.Install, USB\VID_FFFE&PID_000A, AltusMetrumSerial\r
-%TeleMetrum%   = AltusMetrum.Install, USB\VID_FFFE&PID_000B, AltusMetrumSerial\r
-%TeleDongle%   = AltusMetrum.Install, USB\VID_FFFE&PID_000C, AltusMetrumSerial\r
-%TeleTerra%    = AltusMetrum.Install, USB\VID_FFFE&PID_000D, AltusMetrumSerial\r
-%TeleBT%       = AltusMetrum.Install, USB\VID_FFFE&PID_000e, AltusMetrumSerial\r
-%TeleLaunch%   = AltusMetrum.Install, USB\VID_FFFE&PID_000f, AltusMetrumSerial\r
-%TeleLCO%      = AltusMetrum.Install, USB\VID_FFFE&PID_0010, AltusMetrumSerial\r
-%TeleScience%  = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial\r
-%TelePyro%     = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial\r
-%TeleShield%   = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial\r
-%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
-%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
-%AltusMetrum2b%        = AltusMetrum.Install, USB\VID_FFFE&PID_002b, AltusMetrumSerial\r
-%AltusMetrum2c%        = AltusMetrum.Install, USB\VID_FFFE&PID_002c, AltusMetrumSerial\r
-\r
-[Models.NTia64]\r
-%AltusMetrum%  = AltusMetrum.Install, USB\VID_FFFE&PID_000A, AltusMetrumSerial\r
-%TeleMetrum%   = AltusMetrum.Install, USB\VID_FFFE&PID_000B, AltusMetrumSerial\r
-%TeleDongle%   = AltusMetrum.Install, USB\VID_FFFE&PID_000C, AltusMetrumSerial\r
-%TeleTerra%    = AltusMetrum.Install, USB\VID_FFFE&PID_000D, AltusMetrumSerial\r
-%TeleBT%       = AltusMetrum.Install, USB\VID_FFFE&PID_000e, AltusMetrumSerial\r
-%TeleLaunch%   = AltusMetrum.Install, USB\VID_FFFE&PID_000f, AltusMetrumSerial\r
-%TeleLCO%      = AltusMetrum.Install, USB\VID_FFFE&PID_0010, AltusMetrumSerial\r
-%TeleScience%  = AltusMetrum.Install, USB\VID_FFFE&PID_0011, AltusMetrumSerial\r
-%TelePyro%     = AltusMetrum.Install, USB\VID_FFFE&PID_0012, AltusMetrumSerial\r
-%TeleShield%   = AltusMetrum.Install, USB\VID_FFFE&PID_0013, AltusMetrumSerial\r
-%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
-%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
-%AltusMetrum2b%        = AltusMetrum.Install, USB\VID_FFFE&PID_002b, AltusMetrumSerial\r
-%AltusMetrum2c%        = AltusMetrum.Install, USB\VID_FFFE&PID_002c, AltusMetrumSerial\r
-\r
-;----------------------------------------------------------------------------\r
-; Installation sections\r
-;----------------------------------------------------------------------------\r
-\r
-[AltusMetrum.Install.NT]\r
-include                = mdmcpq.inf\r
-CopyFiles      = FakeModemCopyFileSection\r
-AddReg         = All.AddReg, Modem.AddReg, Uninstall.AddReg\r
-\r
-[AltusMetrum.Install.NT.Services]\r
-include                = mdmcpq.inf\r
-AddService     = usbser, 0x00000000, LowerFilter_Service_Inst\r
-\r
-[AltusMetrum.Install.NT.HW]\r
-include                = mdmcpq.inf\r
-AddReg         = LowerFilterAddReg\r
-\r
-;----------------------------------------------------------------------------\r
-; AddReg sections\r
-;----------------------------------------------------------------------------\r
-\r
-[All.AddReg]\r
-HKR,,FriendlyDriver,,          Unimodem.vxd\r
-HKR,,DevLoader,,               *vcomm\r
-HKR,,ConfigDialog,,            modemui.dll\r
-HKR,,EnumPropPages,,           "modemui.dll,EnumPropPages"\r
-HKR,,PortSubClass, 1,          02\r
-HKR,,DeviceType, 1,            01\r
-\r
-[Modem.AddReg]\r
-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\%AltusMetrum%,DisplayName,,"%AltusMetrum%"\r
-\r
-[Strings]\r
-Mfg            = "altusmetrum.org"\r
-AltusMetrum    = "AltusMetrum"\r
-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