564bfbfb14493629a12d1c24f5e8fa166c3926da
[bootloader] / cli / boot.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <stdint.h>
7
8 #include "log.h"
9 #include "serial.h"
10 #include "protocol.h"
11 #include "devices.h"
12 #include "memory.h"
13
14 #define BAUD_RATE 19200
15 #define PORT_NAME "/dev/ttyUSB0"
16
17
18 void usage(const char * name)
19 {
20         loge("Usage: %s [-b baud] [-p port] [-i] [-v] {file.hex}\n", name);
21         loge("-b baud   Set baudrate (default: %d)\n", BAUD_RATE);
22         loge("-p port   Set serial port (default: %s)\n", PORT_NAME);
23         loge("-i        ID Only mode.\n");
24         loge("-v        Verify after write\n");
25 }
26
27
28 #define MIN(a,b) ((a)<(b)?(a):(b))
29
30 int bitmask(int value)
31 {
32         int out = 0;
33         if (value >= (1<<1)) out |= 1;
34         if (value >= (1<<2)) out |= 1<<1;
35         if (value >= (1<<3)) out |= 1<<2;
36         if (value >= (1<<4)) out |= 1<<3;
37         if (value >= (1<<5)) out |= 1<<4;
38         if (value >= (1<<6)) out |= 1<<5;
39         if (value >= (1<<7)) out |= 1<<6;
40         if (value >= (1<<8)) out |= 1<<7;
41         if (value >= (1<<9)) out |= 1<<8;
42         if (value >= (1<<10)) out |= 1<<9;
43
44         return out;
45 }
46 /*
47  * This routine writes a memory plan out to the device
48  */
49 int update_mem(port_t * pt, const devid_t * dev, uint16_t maxmem, mem_t * ram, int verify)
50 {
51         mem_t * block = ram;
52         uint8_t buff[1024];  // scratch space
53
54         for (block=ram; block != NULL; block=block->next) {
55                 int bstart = block->start / 2;
56
57                 /* skip config words, we cant write them anyway */
58                 if (bstart >= 0x8000) {
59                         logd("UpdateMem: skip config block @ %04x", bstart);
60                         continue;
61                 }
62                         
63
64                 uint8_t * p = block->bytes;
65                 int left = block->len;
66                 uint16_t addr = bstart;
67                 int rowlen = dev->rowsize * 2;
68                 logd("UpdateMem: new block %d bytes @ %04x", block->len, bstart);
69
70                 while (left > 0) {
71                         int off = 0;
72                         int len = rowlen;
73
74                         memset(buff, 255, sizeof(buff));
75                         if (addr == bstart) {
76                                 /* first row, align the start */
77                                 if (addr % dev->rowsize != 0) {
78                                         addr &= ~bitmask(dev->rowsize);
79                                         off = (bstart - addr) * 2;
80                                         len -= off;
81                                         logd("UpdateMem: realigning %04X to %04X", bstart, addr);
82                                 }
83                         }
84
85                         len = MIN(len, left);
86
87                         logd("UpdateMem: Preparing %d bytes @ %04X", len, addr);
88
89                         /* partial row write, read first */
90                         if (off != 0 || len < rowlen) {
91                                 logd("UpdateMem: Read %d words @ %04x", dev->rowsize, addr);
92                                 if (loader_readmem(pt, addr, buff, dev->rowsize)) {
93                                         loge("UpdateMem: Aborting on failed read");
94                                         return 1;
95                                 }
96                                 print_memory(addr, buff, dev->rowsize);
97                         }
98
99                         /* update with new values */
100                         memcpy(&buff[off], p, len);
101
102                         /* write the row */
103                         logd("UpdateMem: Writing %d words @ %04x", dev->rowsize, addr);
104                         print_memory(addr, buff, dev->rowsize);
105                         if (loader_writemem(pt, addr, buff, dev->rowsize)) {
106                                 loge("UpdateMem: Aborting on failed write");
107                                 return 1;
108                         }
109
110                         if (verify) {
111                                 uint8_t again[1024];
112                                 sleep(1);
113                                 logd("UpdateMem: Verify %d words @ %04x", dev->rowsize, addr);
114                                 if (loader_readmem(pt, addr, again, dev->rowsize)) {
115                                         loge("UpdateMem: Aborting on failed read");
116                                         return 1;
117                                 }
118                                 print_memory(addr, again, dev->rowsize);
119                                 for (int i=0; i<rowlen; i++) {
120                                         if (again[i] != buff[i]) {
121                                                 loge("UpdateMem: Verify failed on block 0x%04X", addr);
122                                                 return 1;
123                                         }
124                                 }
125                         }
126
127                         /* shuffle along */
128                         left -= len;
129                         p += len;
130                         addr += dev->rowsize;
131                 }
132         }
133         return 0;
134 }
135
136 int main(int argc, char **argv)
137 {
138         int opt;
139         char * port = NULL;
140         int baud = BAUD_RATE;
141         int verify = 0;
142         int idonly = 0;
143
144         while ((opt=getopt(argc, argv, "h?b:p:ivd"))!=-1) {
145                 switch (opt) {
146                         case 'b':
147                                 baud = atoi(optarg);
148                                 break;
149                         case 'p':
150                                 if (port) free(port);
151                                 port = strdup(optarg);
152                                 break;
153                         case 'v':
154                                 verify=1;
155                                 break;
156                         case 'i':
157                                 idonly=1;
158                                 break;
159                         case 'd':
160                                 debug++;
161                                 break;
162                         case 'h':
163                         case '?':
164                         default:
165                                 usage(argv[0]);
166                                 return 1;
167                 }
168         }
169
170         if (port == NULL) port = PORT_NAME;
171
172         if (!idonly && optind >= argc) {
173                 loge("Error: missing hexfile");
174                 return 1;
175         }
176
177         mem_t * ram = NULL;
178
179         if (!idonly) {
180                 FILE * fd = NULL;
181                 if ((fd = fopen(argv[optind], "r"))==NULL) {
182                         loge("Error opening %s: %s", argv[optind], strerror(errno));
183                         return 1;
184                 }
185                 ram = load_ihex(fd);
186                 fclose(fd);
187
188                 logd("Memory Summary :-");
189                 list_mem(ram);
190         }
191
192         logd("open serial port %s at %d baud", port, baud);
193         port_t * pt = serial_open(port, baud);
194         if (pt == NULL) return 1;
195
196         uint16_t maxmem;
197         uint16_t devid;
198         if (loader_connect(pt, &maxmem, &devid)) {
199                 return 1;
200         }
201
202         const devid_t * dev = devid_to_info(devid);
203
204         if (idonly) {
205                 logi("Device ID: %04X", devid);
206                 logi(" Free Mem: %d words available", maxmem);
207                 if (dev != NULL) {
208                         logi(" Dev Name: %s", dev->name );
209                         logi("  Max Mem: %d", dev->memsize );
210                 }
211
212                 return 0;
213         }
214         if (dev) logd("Device Name: %s", dev->name);
215
216         /* check that the selected program will fit on this device */
217         if (makesafe_mem(&ram, maxmem)) {
218                 serial_close(pt);
219                 return 1;
220         }
221         logd("After re-organisation");
222         list_mem(ram);
223
224         /* now write the updated memory plan to the device */
225         if (!update_mem(pt, dev, maxmem, ram, verify)) {
226                 if (verify)
227                         logi("Device Write (and Verify) Complete");
228                 else
229                         logi("Device Write Complete");
230         }
231
232         /* finished */
233         serial_close(pt);
234         logd("done.");
235         return 0;
236
237 }