/*
openaltimeter -- an open-source altimeter for RC aircraft
Copyright (C) 2010-2011 Jony Hudson
http://openaltimeter.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
*/
package org.openaltimeter;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.UnsupportedCommOperationException;
import java.io.IOException;
import java.util.TooManyListenersException;
import org.openaltimeter.comms.SerialLink;
import org.openaltimeter.data.FlightLog;
import org.openaltimeter.data.LogEntry;
import org.openaltimeter.desktopapp.Controller;
import org.openaltimeter.settings.Settings;
public class Altimeter {
// this timeout needs to be long enough for the longest download to finish.
private static final int TIMEOUT_LOOP_LIMIT = 1200;
public static final int FLASH_MEMORY_SIZE = 512 * 1024;
private static final int SETTINGS_MEMORY_SIZE = 512;
private SerialLink serial;
public Settings settings;
public String firmwareVersion;
public int loggingPeriod;
public Altimeter() {
serial = new SerialLink();
}
public String connect(String comPortName, int baudRate) throws NoSuchPortException,
PortInUseException, UnsupportedCommOperationException, IOException, NotAnOpenaltimeterException, TooManyListenersException {
// we reset the logger after opening the serial port, and then wait for
// the welcome message
serial.connect(comPortName, baudRate);
reset();
// wait for the logger to start up
try {Thread.sleep(16000);} catch (Exception e) {};
// read the welcome message, check that the altimeter has responded
// send a command to stop logging.
serial.write('c');
try {Thread.sleep(500);} catch (Exception e) {};
String welcomeString = serial.readString(2048);
if (!welcomeString.startsWith("openaltimeter")) {
serial.disconnect();
throw new NotAnOpenaltimeterException();
}
// parse the welcome message to get the OA firmware version
String firstLine = welcomeString.split("\n")[0];
firmwareVersion = firstLine.split(": ")[1];
firmwareVersion = firmwareVersion.substring(0, firmwareVersion.length() - 1);
// extract the logging period
String logPeriodLine = welcomeString.split("\n")[4];
String logPeriodText = logPeriodLine.split(": ")[1];
String trimLPText = logPeriodText.substring(0, logPeriodText.length() - 1);
loggingPeriod = Integer.parseInt(trimLPText);
// return the welcome message
return welcomeString;
}
public String getFileInfo() throws IOException
{
serial.clearInput();
serial.write('i');
try {Thread.sleep(500);} catch (Exception e) {};
String fileInfoString = serial.readString(2048);
return fileInfoString.trim();
}
public void disconnect() {
serial.disconnect();
}
public void reset() {
serial.sendReset();
}
public FlightLog downloadData() throws IOException, DownloadTimeoutException {
// we first find out how many entries we're expecting
String fileInfo = getFileInfo();
String[] infoStrings = fileInfo.split("\n");
String numberEntriesString = (infoStrings[1].split(":"))[1].trim();
int numberOfEntries = Integer.parseInt(numberEntriesString);
// flush the input buffer and tell the logger to commence the upload
serial.clearInput();
// make sure the input stream is clear
while (serial.in.available() != 0) serial.clearInput();
// tell the logger to upload its data
serial.startBufferedRead(FLASH_MEMORY_SIZE * 2);
serial.write('d');
// loop, checking on the progress of the data upload, timeout if necessary
int timeoutCounter = 0;
while (serial.available() < (numberOfEntries + 2) * LogEntry.DATASTORE_LOG_ENTRY_SIZE ) {
int percentage = (int)((double)(100 * serial.available()) / (double)(numberOfEntries * LogEntry.DATASTORE_LOG_ENTRY_SIZE));
Controller.setProgress(percentage);
try { Thread.sleep(100); } catch (InterruptedException e) {}
if (timeoutCounter++ == TIMEOUT_LOOP_LIMIT) throw new DownloadTimeoutException();
}
serial.stopBufferedRead();
Controller.setProgress(100);
// there are numberOfEntries log entries, plus two file end markers.
FlightLog log = new FlightLog();
byte[] data = serial.getBuffer();
for (int i = 0; i < numberOfEntries + 2; i++)
{
int os = i *LogEntry.DATASTORE_LOG_ENTRY_SIZE;
LogEntry le = LogEntry.logEntryFromBytes(data, os);
log.add(le);
}
log.calculateAltitudes();
log.logInterval = (double)loggingPeriod / 1000.0;
return log;
}
public String erase() throws IOException {
serial.clearInput();
serial.write("ee");
try {Thread.sleep(5000);} catch (Exception e) {};
String response = serial.readString(2048);
return response.trim();
}
public void readSettings() throws IOException {
serial.clearInput();
// make sure the input stream is clear
while (serial.in.available() != 0) serial.clearInput();
// tell the logger to upload its data
serial.startBufferedRead(SETTINGS_MEMORY_SIZE);
serial.write('r');
// cheesily just use a short delay
try {Thread.sleep(500);} catch (Exception e) {};
serial.stopBufferedRead();
settings = new Settings(serial.getBuffer());
}
public void writeSettings() throws IOException
{
serial.clearInput();
serial.write("ss");
byte[] settingsBytes = settings.toByteArray();
for (int i = 0; i < settingsBytes.length; i++) {
serial.write((char)settingsBytes[i]);
try {Thread.sleep(10);} catch (InterruptedException e) {}
}
try {Thread.sleep(4000);} catch (InterruptedException e) {}
}
public void wipeSettings() throws IOException {
serial.clearInput();
serial.write("ww");
try {Thread.sleep(4000);} catch (Exception e) {};
}
public void upload(String dataToUpload) throws IOException{
erase();
serial.clearInput();
String[] lines = dataToUpload.split("\n");
for (String line : lines) {
serial.write('u');
serial.write(line + "*");
System.out.println("u" + line + "*");
try {Thread.sleep(150);} catch (InterruptedException e) {}
}
//serial.clearInput();
serial.write('o');
try {Thread.sleep(15000);} catch (InterruptedException e) {}
Controller.log(serial.readString(2048), "altimeter");
}
@SuppressWarnings("serial")
public class DownloadTimeoutException extends Exception {
}
@SuppressWarnings("serial")
public class NotAnOpenaltimeterException extends Exception {
}
}