X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=altoslib%2FAltosEeprom.java;fp=altoslib%2FAltosEeprom.java;h=2600e80259301add5212e25e3d8910e1de3b2691;hb=e4f1fa544f1cb21070c9d79c81ebae0fb71d77db;hp=0000000000000000000000000000000000000000;hpb=0e586ab3604bb695c36ae86c95f533197522fc65;p=fw%2Faltos diff --git a/altoslib/AltosEeprom.java b/altoslib/AltosEeprom.java new file mode 100644 index 00000000..2600e802 --- /dev/null +++ b/altoslib/AltosEeprom.java @@ -0,0 +1,291 @@ +/* + * Copyright © 2017 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +package org.altusmetrum.altoslib_11; + +import java.util.*; +import java.io.*; + +public class AltosEeprom { + + private AltosJson config; + ArrayList data; + private AltosConfigData config_data; + + /* + * Public accessor APIs + */ + public int data8(int offset) { + return ((int) data.get(offset)) & 0xff; + } + + public int data16(int offset) { + return data8(offset) | (data8(offset+1) << 8); + } + + public int data24(int offset) { + return (data8(offset) | + (data8(offset+1) << 8) | + (data8(offset+2) << 16)); + } + + public int data32(int offset) { + return (data8(offset) | + (data8(offset+1) << 8) | + (data8(offset+2) << 16) | + (data8(offset+3) << 24)); + } + + public int size() { + return data.size(); + } + + public AltosConfigData config_data() { + if (config_data == null) { + config_data = (AltosConfigData) config.make(AltosConfigData.class); + if (config_data == null) + config_data = new AltosConfigData(); + + if (config_data.log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN) { + config_data.log_format = AltosLib.AO_LOG_FORMAT_FULL; + if (config_data.product != null) { + if (config_data.product.startsWith("TeleMetrum")) + config_data.log_format = AltosLib.AO_LOG_FORMAT_FULL; + else if (config_data.product.startsWith("TeleMini")) + config_data.log_format = AltosLib.AO_LOG_FORMAT_TINY; + } + } + } + return config_data; + } + + private void write_config(Writer w) throws IOException { + config.write(w, 0, true); + w.append('\n'); + } + + /* + * Private I/O APIs + */ + private void write_data(Writer w) throws IOException { + PrintWriter pw = new PrintWriter(w); + + for (int i = 0; i < data.size(); i++) { + if (i > 0) { + if ((i & 0x1f) == 0) + pw.printf("\n"); + else + pw.printf(" "); + } + pw.printf("%02x", data.get(i)); + } + w.append('\n'); + } + + private boolean read_config(InputStream stream) throws IOException { + config = AltosJson.fromInputStream(stream); + if (config == null) + return false; + return true; + } + + private String read_line(InputStream stream) throws IOException { + StringBuffer buffer = null; + int c; + + for (;;) { + c = stream.read(); + if (c == -1 && buffer == null) + return null; + if (buffer == null) + buffer = new StringBuffer(); + if (c == -1 || c == '\n') + return buffer.toString(); + buffer.append((char) c); + } + } + + private boolean read_data(InputStream stream) throws IOException { + String s; + + data = new ArrayList(); + while ((s = read_line(stream)) != null) { + + String[] tokens = s.split("\\s+"); + + for (int i = 0; i < tokens.length; i++) { + if (tokens[i].length() > 0) { + try { + data.add((byte) AltosLib.fromhex(tokens[i])); + } catch (NumberFormatException e) { + throw new IOException(e.toString()); + } + } + } + } + return true; + } + + private boolean read_old_config(InputStream stream) throws IOException { + AltosConfigData cfg = new AltosConfigData(); + for (;;) { + boolean done = false; + + /* The data starts with an upper case F character followed by a space */ + stream.mark(2); + int first = stream.read(); + if (first == 'F') { + int second = stream.read(); + if (second == ' ') + done = true; + } + stream.reset(); + if (done) + break; + + String line = read_line(stream); + if (line == null) + return false; + cfg.parse_line(line); + } + config = new AltosJson(cfg); + return true; + } + + private boolean read_old_data(InputStream stream) throws IOException { + String line; + + data = new ArrayList(); + while ((line = read_line(stream)) != null) { + String[] tokens = line.split("\\s+"); + + /* Make sure there's at least a type and time */ + if (tokens.length < 2) + break; + + /* packet type */ + if (tokens[0].length() != 1) + break; + int start = data.size(); + + if (config_data().log_format != AltosLib.AO_LOG_FORMAT_TINY) { + byte cmd = (byte) tokens[0].codePointAt(0); + data.add(cmd); + + int time = AltosLib.fromhex(tokens[1]); + + data.add((byte) 0); + data.add((byte) (time & 0xff)); + data.add((byte) (time >> 8)); + } + if (tokens.length == 4) { + /* Handle ancient log files */ + if (config_data().log_format == AltosLib.AO_LOG_FORMAT_TINY) { + /* + * Ancient TeleMini log files stored "extra" data to pretend + * that it was a TeleMetrum device. Throw that away and + * just save the actual log data. + */ + int a = AltosLib.fromhex(tokens[2]); + int b = AltosLib.fromhex(tokens[3]); + if (a != 0) + b = 0x8000 | a; + data.add((byte) (b & 0xff)); + data.add((byte) ((b >> 8))); + } else { + for (int i = 2; i < tokens.length; i++) { + int v = AltosLib.fromhex(tokens[i]); + data.add((byte) (v & 0xff)); + data.add((byte) ((v >> 8))); + } + /* Re-compute the checksum byte */ + data.set(start + 1, (byte) (256 - AltosConvert.checksum(data, start, data.size() - start))); + } + } else { + for (int i = 2; i < tokens.length; i++) + data.add((byte) AltosLib.fromhex(tokens[i])); + /* Re-compute the checksum byte */ + data.set(start + 1, (byte) (256 - AltosConvert.checksum(data, start, data.size() - start))); + } + } + return true; + } + + private void read(InputStream stream) throws IOException { + BufferedInputStream bis = new BufferedInputStream(stream); + + bis.mark(1); + int c = bis.read(); + bis.reset(); + + if (c == '{') { + if (!read_config(bis)) + throw new IOException("failed to read config"); + if (!read_data(bis)) + throw new IOException("failed to read data"); + } else { + if (!read_old_config(bis)) + throw new IOException("failed to read old config"); + if (!read_old_data(bis)) + throw new IOException("failed to read old data"); + } + } + + /* + * Public APIs for I/O + */ + public void write(Writer w) throws IOException { + write_config(w); + write_data(w); + } + + public String toString() { + try { + Writer w = new StringWriter(); + + write(w); + return w.toString(); + } catch (Exception e) { + return null; + } + } + + public void print() throws IOException { + System.out.printf("%s", toString()); + } + + /* + * Constructors + */ + public AltosEeprom(InputStream stream) throws IOException { + read(stream); + } + + public AltosEeprom(String s) throws IOException { + read(new AltosStringInputStream(s)); + } + + public AltosEeprom(AltosJson config, ArrayList data) { + this.config = config; + this.data = data; + } + + public AltosEeprom(AltosConfigData config_data, ArrayList data) { + this.config = new AltosJson(config_data); + this.data = data; + } + + public AltosEeprom() { + } +}