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