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