2 * Copyright © 2017 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
15 package org.altusmetrum.altoslib_14;
20 public class AltosEeprom {
22 private AltosJson config;
24 private AltosConfigData config_data;
28 * Public accessor APIs
30 public int data8(int offset) {
31 return ((int) data.get(offset)) & 0xff;
34 public int data16(int offset) {
35 return data8(offset) | (data8(offset+1) << 8);
38 public int data24(int offset) {
39 return (data8(offset) |
40 (data8(offset+1) << 8) |
41 (data8(offset+2) << 16));
44 public int data32(int offset) {
45 return (data8(offset) |
46 (data8(offset+1) << 8) |
47 (data8(offset+2) << 16) |
48 (data8(offset+3) << 24));
55 public AltosConfigData config_data() {
56 if (config_data == null) {
57 config_data = (AltosConfigData) config.make(AltosConfigData.class);
58 if (config_data == null)
59 config_data = new AltosConfigData();
61 if (config_data.log_format == AltosLib.AO_LOG_FORMAT_UNKNOWN) {
62 config_data.log_format = AltosLib.AO_LOG_FORMAT_FULL;
63 if (config_data.product != null) {
64 if (config_data.product.startsWith("TeleMetrum"))
65 config_data.log_format = AltosLib.AO_LOG_FORMAT_FULL;
66 else if (config_data.product.startsWith("TeleMini"))
67 config_data.log_format = AltosLib.AO_LOG_FORMAT_TINY;
74 private void write_config(Writer w) throws IOException {
75 config.write(w, 0, true);
82 private void write_data(Writer w) throws IOException {
83 PrintWriter pw = new PrintWriter(w);
85 for (int i = 0; i < data.size(); i++) {
92 pw.printf("%02x", data.get(i));
97 private boolean read_config(InputStream stream) throws IOException {
98 config = AltosJson.fromInputStream(stream);
104 private String read_line(InputStream stream) throws IOException {
105 StringBuffer buffer = null;
110 if (c == -1 && buffer == null)
113 buffer = new StringBuffer();
114 if (c == -1 || c == '\n')
115 return buffer.toString();
116 buffer.append((char) c);
120 private boolean read_data(InputStream stream) throws IOException {
123 data = new ArrayList<Byte>();
124 while ((s = read_line(stream)) != null) {
126 String[] tokens = s.split("\\s+");
128 for (int i = 0; i < tokens.length; i++) {
129 if (tokens[i].length() > 0) {
131 data.add((byte) AltosLib.fromhex(tokens[i]));
132 } catch (NumberFormatException e) {
133 throw new IOException(e.toString());
141 private boolean read_old_config(InputStream stream) throws IOException {
142 AltosConfigData cfg = new AltosConfigData();
144 boolean done = false;
146 /* The data starts with an upper case F character followed by a space */
148 int first = stream.read();
150 int second = stream.read();
158 String line = read_line(stream);
161 cfg.parse_line(line);
163 config = new AltosJson(cfg);
167 private boolean read_old_data(InputStream stream) throws IOException {
170 data = new ArrayList<Byte>();
171 while ((line = read_line(stream)) != null) {
172 String[] tokens = line.split("\\s+");
174 /* Make sure there's at least a type and time */
175 if (tokens.length < 2)
179 if (tokens[0].length() != 1)
181 int start = data.size();
183 if (config_data().log_format != AltosLib.AO_LOG_FORMAT_TINY) {
184 byte cmd = (byte) tokens[0].codePointAt(0);
187 int time = AltosLib.fromhex(tokens[1]);
190 data.add((byte) (time & 0xff));
191 data.add((byte) (time >> 8));
193 if (tokens.length == 4) {
194 /* Handle ancient log files */
195 if (config_data().log_format == AltosLib.AO_LOG_FORMAT_TINY) {
197 * Ancient TeleMini log files stored "extra" data to pretend
198 * that it was a TeleMetrum device. Throw that away and
199 * just save the actual log data.
201 int a = AltosLib.fromhex(tokens[2]);
202 int b = AltosLib.fromhex(tokens[3]);
205 data.add((byte) (b & 0xff));
206 data.add((byte) ((b >> 8)));
208 for (int i = 2; i < tokens.length; i++) {
209 int v = AltosLib.fromhex(tokens[i]);
210 data.add((byte) (v & 0xff));
211 data.add((byte) ((v >> 8)));
213 /* Re-compute the checksum byte */
214 data.set(start + 1, (byte) (256 - AltosConvert.checksum(data, start, data.size() - start)));
217 for (int i = 2; i < tokens.length; i++)
218 data.add((byte) AltosLib.fromhex(tokens[i]));
219 /* Re-compute the checksum byte */
220 data.set(start + 1, (byte) (256 - AltosConvert.checksum(data, start, data.size() - start)));
226 private void read(InputStream stream) throws IOException {
227 BufferedInputStream bis = new BufferedInputStream(stream);
234 if (!read_config(bis))
235 throw new IOException("failed to read config");
237 throw new IOException("failed to read data");
239 if (!read_old_config(bis))
240 throw new IOException("failed to read old config");
241 if (!read_old_data(bis))
242 throw new IOException("failed to read old data");
247 * Public APIs for I/O
249 public void write(Writer w) throws IOException {
254 public String toString() {
256 Writer w = new StringWriter();
260 } catch (Exception e) {
265 public void print() throws IOException {
266 System.out.printf("%s", toString());
272 public AltosEeprom(InputStream stream) throws IOException {
276 public AltosEeprom(String s) throws IOException {
277 read(new AltosStringInputStream(s));
280 public AltosEeprom(AltosJson config, ArrayList<Byte> data) {
281 this.config = config;
285 public AltosEeprom(AltosConfigData config_data, ArrayList<Byte> data) {
286 this.config = new AltosJson(config_data);
290 public AltosEeprom() {