0250cce741a6d1f3c64713418f5a953b12f04412
[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_13;
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                 for (int offset = 0; offset < len; offset += 0x100) {
49                         link.printf("R %x\n", addr + offset);
50                         byte[]  reply = link.get_binary_reply(5000, 0x100);
51
52                         if (reply == null)
53                                 throw new IOException("Read device memory timeout");
54                         for (b = 0; b < 0x100 && b + offset < len; b++)
55                                 data[b+offset] = reply[b];
56                 }
57                 return data;
58         }
59
60         AltosHexfile read_hexfile(long addr, int len) throws InterruptedException {
61                 try {
62                         byte[] mem = read_memory(addr, len);
63
64                         AltosHexfile    hexfile = new AltosHexfile(mem, addr);
65
66                         if (image != null)
67                                 hexfile.add_symbols(image);
68                         return hexfile;
69                 } catch (IOException ie) {
70                         return null;
71                 }
72         }
73
74         void write_memory(long addr, byte[] data, int start, int len) {
75                 int b;
76                 link.printf("W %x\n", addr);
77                 link.flush_output();
78                 for (b = 0; b < len; b++)
79                         link.putchar(data[start + b]);
80                 for (; b < 0x100; b++)
81                         link.putchar((byte) 0xff);
82         }
83
84         void reboot() {
85                 link.printf("a\n");
86                 link.flush_output();
87         }
88
89         public void flash() {
90                 try {
91                         if (!check_rom_config())
92                                 throw new IOException("Invalid rom config settings");
93
94                         /*
95                          * Store desired config values into image
96                          */
97                         rom_config.write(image);
98
99                         int remain = image.data.length;
100                         long flash_addr = image.address;
101                         int image_start = 0;
102
103                         action(AltosFlashListener.flash_start, 0);
104                         action(0, image.data.length);
105                         while (remain > 0 && !aborted) {
106                                 int this_time = remain;
107                                 if (this_time > 0x100)
108                                         this_time = 0x100;
109
110                                 if (link != null) {
111                                         /* write the data */
112                                         write_memory(flash_addr, image.data, image_start, this_time);
113
114                                         byte[] check = read_memory(flash_addr, this_time);
115                                         for (int i = 0; i < this_time; i++)
116                                                 if (check[i] != image.data[image_start + i])
117                                                         throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)",
118                                                                                             image.address + image_start + i,
119                                                                                             check[i], image.data[image_start + i]));
120                                 } else {
121                                         Thread.sleep(100);
122                                 }
123
124                                 remain -= this_time;
125                                 flash_addr += this_time;
126                                 image_start += this_time;
127
128                                 action(image.data.length - remain, image.data.length);
129                         }
130                         if (!aborted) {
131                                 action(AltosFlashListener.flash_done, 100);
132                         }
133                         close();
134                 } catch (IOException ie) {
135                         action(ie.getMessage(), -1);
136                         abort();
137                 } catch (InterruptedException ie) {
138                         abort();
139                 }
140         }
141
142         public void close() {
143                 if (link != null) {
144                         reboot();
145                         try {
146                                 link.close();
147                         } catch (InterruptedException ie) {
148                         }
149                         link = null;
150                 }
151         }
152
153         synchronized public void abort() {
154                 aborted = true;
155                 close();
156         }
157
158         private AltosHexfile get_rom() throws InterruptedException {
159                 try {
160                         long base = AltosRomconfig.fetch_base(image);
161                         long bounds = AltosRomconfig.fetch_bounds(image);
162
163                         if (link.debug)
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 }