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