Remove the test program, and the unnecessary time delay
[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
15#define PORT_NAME "/dev/ttyUSB0"
16
17
18void 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
30int 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 */
49int 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];
9c66c9ff
JM
112 logd("UpdateMem: Verify %d words @ %04x", dev->rowsize, addr);
113 if (loader_readmem(pt, addr, again, dev->rowsize)) {
114 loge("UpdateMem: Aborting on failed read");
115 return 1;
116 }
117 print_memory(addr, again, dev->rowsize);
118 for (int i=0; i<rowlen; i++) {
119 if (again[i] != buff[i]) {
120 loge("UpdateMem: Verify failed on block 0x%04X", addr);
121 return 1;
122 }
123 }
124 }
125
126 /* shuffle along */
127 left -= len;
128 p += len;
129 addr += dev->rowsize;
130 }
131 }
132 return 0;
133}
134
135int main(int argc, char **argv)
136{
137 int opt;
138 char * port = NULL;
139 int baud = BAUD_RATE;
140 int verify = 0;
141 int idonly = 0;
142
143 while ((opt=getopt(argc, argv, "h?b:p:ivd"))!=-1) {
144 switch (opt) {
145 case 'b':
146 baud = atoi(optarg);
147 break;
148 case 'p':
149 if (port) free(port);
150 port = strdup(optarg);
151 break;
152 case 'v':
153 verify=1;
154 break;
155 case 'i':
156 idonly=1;
157 break;
158 case 'd':
159 debug++;
160 break;
161 case 'h':
162 case '?':
163 default:
164 usage(argv[0]);
165 return 1;
166 }
167 }
168
169 if (port == NULL) port = PORT_NAME;
170
171 if (!idonly && optind >= argc) {
172 loge("Error: missing hexfile");
173 return 1;
174 }
175
176 mem_t * ram = NULL;
177
178 if (!idonly) {
179 FILE * fd = NULL;
180 if ((fd = fopen(argv[optind], "r"))==NULL) {
181 loge("Error opening %s: %s", argv[optind], strerror(errno));
182 return 1;
183 }
184 ram = load_ihex(fd);
185 fclose(fd);
186
187 logd("Memory Summary :-");
188 list_mem(ram);
189 }
190
191 logd("open serial port %s at %d baud", port, baud);
192 port_t * pt = serial_open(port, baud);
193 if (pt == NULL) return 1;
194
195 uint16_t maxmem;
196 uint16_t devid;
197 if (loader_connect(pt, &maxmem, &devid)) {
198 return 1;
199 }
200
201 const devid_t * dev = devid_to_info(devid);
202
203 if (idonly) {
204 logi("Device ID: %04X", devid);
205 logi(" Free Mem: %d words available", maxmem);
206 if (dev != NULL) {
207 logi(" Dev Name: %s", dev->name );
208 logi(" Max Mem: %d", dev->memsize );
209 }
210
211 return 0;
212 }
213 if (dev) logd("Device Name: %s", dev->name);
214
215 /* check that the selected program will fit on this device */
216 if (makesafe_mem(&ram, maxmem)) {
217 serial_close(pt);
218 return 1;
219 }
220 logd("After re-organisation");
221 list_mem(ram);
222
223 /* now write the updated memory plan to the device */
224 if (!update_mem(pt, dev, maxmem, ram, verify)) {
225 if (verify)
226 logi("Device Write (and Verify) Complete");
227 else
228 logi("Device Write Complete");
229 }
230
231 /* finished */
232 serial_close(pt);
233 logd("done.");
234 return 0;
235
236}