altoslib/altosuilib: Validate rom image is for target device
[fw/altos] / altoslib / AltosSelfFlash.java
1 /*
2  * Copyright © 2013 Keith Packard <keithp@keithp.com>
3  *
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.
8  *
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.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 package org.altusmetrum.altoslib_12;
20
21 import java.io.*;
22
23 public class AltosSelfFlash extends AltosProgrammer {
24         File                    file;
25         FileInputStream         input;
26         AltosHexfile            image;
27         AltosLink               link;
28         boolean                 aborted;
29         AltosFlashListener      listener;
30         AltosRomconfig          rom_config;
31
32         void action(String s, int percent) {
33                 if (listener != null && !aborted)
34                         listener.position(s, percent);
35         }
36
37         void action(int part, int total) {
38                 int percent = 100 * part / total;
39                 action(String.format("%d/%d (%d%%)",
40                                      part, total, percent),
41                        percent);
42         }
43
44         byte[] read_memory(long addr, int len) throws InterruptedException, IOException {
45                 int b;
46                 byte[]  data = new byte[len];
47
48                 System.out.printf("read_memory %x %d\n", addr, len);
49                 for (int offset = 0; offset < len; offset += 0x100) {
50                         link.printf("R %x\n", addr + offset);
51                         byte[]  reply = link.get_binary_reply(5000, 0x100);
52
53                         if (reply == null)
54                                 throw new IOException("Read device memory timeout");
55                         for (b = 0; b < 0x100 && b + offset < len; b++)
56                                 data[b+offset] = reply[b];
57                 }
58                 return data;
59         }
60
61         AltosHexfile read_hexfile(long addr, int len) throws InterruptedException {
62                 try {
63                         byte[] mem = read_memory(addr, len);
64
65                         AltosHexfile    hexfile = new AltosHexfile(mem, addr);
66
67                         if (image != null)
68                                 hexfile.add_symbols(image);
69                         return hexfile;
70                 } catch (IOException ie) {
71                         return null;
72                 }
73         }
74
75         void write_memory(long addr, byte[] data, int start, int len) {
76                 int b;
77                 link.printf("W %x\n", addr);
78                 link.flush_output();
79                 for (b = 0; b < len; b++)
80                         link.putchar(data[start + b]);
81                 for (; b < 0x100; b++)
82                         link.putchar((byte) 0xff);
83         }
84
85         void reboot() {
86                 link.printf("a\n");
87                 link.flush_output();
88         }
89
90         public void flash() {
91                 try {
92                         if (!check_rom_config())
93                                 throw new IOException("Invalid rom config settings");
94
95                         /*
96                          * Store desired config values into image
97                          */
98                         rom_config.write(image);
99
100                         int remain = image.data.length;
101                         long flash_addr = image.address;
102                         int image_start = 0;
103
104                         action("start", 0);
105                         action(0, image.data.length);
106                         while (remain > 0 && !aborted) {
107                                 int this_time = remain;
108                                 if (this_time > 0x100)
109                                         this_time = 0x100;
110
111                                 if (link != null) {
112                                         /* write the data */
113                                         write_memory(flash_addr, image.data, image_start, this_time);
114
115                                         byte[] check = read_memory(flash_addr, this_time);
116                                         for (int i = 0; i < this_time; i++)
117                                                 if (check[i] != image.data[image_start + i])
118                                                         throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
119                                                                                             image.address + image_start + i,
120                                                                                             check[i], image.data[image_start + i]));
121                                 } else {
122                                         Thread.sleep(100);
123                                 }
124
125                                 remain -= this_time;
126                                 flash_addr += this_time;
127                                 image_start += this_time;
128
129                                 action(image.data.length - remain, image.data.length);
130                         }
131                         if (!aborted) {
132                                 action("done", 100);
133                         }
134                         close();
135                 } catch (IOException ie) {
136                         action(ie.getMessage(), -1);
137                         abort();
138                 } catch (InterruptedException ie) {
139                         abort();
140                 }
141         }
142
143         public void close() {
144                 if (link != null) {
145                         reboot();
146                         try {
147                                 link.close();
148                         } catch (InterruptedException ie) {
149                         }
150                         link = null;
151                 }
152         }
153
154         synchronized public void abort() {
155                 aborted = true;
156                 close();
157         }
158
159         private AltosHexfile get_rom() throws InterruptedException {
160                 try {
161                         long base = AltosRomconfig.fetch_base(image);
162                         long bounds = AltosRomconfig.fetch_bounds(image);
163
164                         System.out.printf("rom base %x bounds %x\n", base, bounds);
165                         return read_hexfile(base, (int) (bounds - base));
166                 } catch (AltosNoSymbol ns) {
167                         return null;
168                 }
169         }
170
171         public boolean check_rom_config() throws InterruptedException {
172                 if (link == null) {
173                         return true;
174                 }
175                 if (rom_config == null) {
176                         AltosHexfile hexfile = get_rom();
177                         if (hexfile != null)
178                                 rom_config = new AltosRomconfig(hexfile);
179                 }
180                 return rom_config != null && rom_config.valid();
181         }
182
183         public void set_romconfig (AltosRomconfig romconfig) {
184                 rom_config = romconfig;
185         }
186
187         public AltosRomconfig target_romconfig() throws InterruptedException {
188                 if (!check_rom_config())
189                         return null;
190                 return rom_config;
191         }
192
193         public AltosRomconfig image_romconfig() {
194                 return new AltosRomconfig(image);
195         }
196
197         public AltosSelfFlash(File file, AltosLink link, AltosFlashListener listener)
198                 throws IOException, FileNotFoundException, InterruptedException {
199                 this.file = file;
200                 this.link = link;
201                 this.listener = listener;
202                 input = new FileInputStream(file);
203                 image = new AltosHexfile(input);
204         }
205 }