Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / wireless_bootloader / downloader.c @ 1428

History | View | Annotate | Download (9.69 KB)

1 1428 rcahoon
#include <stdio.h>
2
#include <termios.h>
3
#include <fcntl.h>
4
#include <stdlib.h>
5
#include <unistd.h>
6
#include <sys/ioctl.h>
7
8
int setupSerial(int fd, int baud)
9
{
10
        struct termios options;
11
12
    /* set baud rate, etc. correctly */
13
14
        tcgetattr(fd, &options);
15
        cfsetispeed(&options, baud);
16
        cfsetospeed(&options, baud);
17
        options.c_iflag &= ~ICRNL;
18
        options.c_oflag &= ~OCRNL;
19
        options.c_cflag |= (CLOCAL | CREAD);
20
        options.c_cflag &= ~PARENB;
21
        options.c_cflag &= ~CSTOPB;
22
        options.c_cflag &= ~CSIZE;
23
        options.c_cflag |= CS8;
24
        options.c_lflag &= ~ICANON;
25
        options.c_cc[VMIN] = 1;
26
        options.c_cc[VTIME] = 50;
27
28
        if (tcsetattr(fd, TCSANOW, &options))
29
        {
30
                printf("Error setting attributes.\n");
31
                return -1;
32
        }
33
34
    return 0;
35
}
36
37
int initSerial(char* portName)
38
{
39
    /* open port for I/O */
40
    int fd = open(portName, O_RDWR | O_NOCTTY );
41
    if (fd <0)
42
    {
43
        perror(portName);
44
        return -1;
45
    }
46
47
    return fd;
48
}
49
50
int writeSerial(int h, const char buf[], int length)
51
{
52
    return write(h,buf,length);
53
}
54
int writeByte(int h, char buf)
55
{
56
    return writeSerial(h, &buf, 1);
57
}
58
59
int getAvailBytes(int h)
60
{
61
    int bytes;
62
    ioctl(h, FIONREAD, &bytes);
63
    return bytes;
64
}
65
66
int readSerial(int h, char buf[], int length)
67
{
68
    return read(h,buf,length);
69
}
70
int readByte(int h)
71
{
72
    char buf;
73
    if (readSerial(h, &buf, 1)<1)
74
        return -1;
75
    return buf;
76
}
77
78
void closeSerial(int h)
79
{
80
    close(h);
81
}
82
83
int wait_for_ok(int h)
84
{
85
    const char* s = "OK\r";
86
    const char* curr = s;
87
    int count = 0;
88
    while (curr - s < 3)
89
    {
90
        int c;
91
        while(!getAvailBytes(h))
92
        {
93
            if (count++ > 150) return 0;
94
            usleep(10000);
95
        }
96
        c = readByte(h);
97
        if (c>=0)
98
        {
99
            if (c == *curr) {
100
                curr++;
101
            } else {
102
                curr = s;
103
            }
104
        }
105
    }
106
107
    return 1;
108
}
109
110
int xbee_setup(int h, int robotNum)
111
{
112
    int _init = 0;
113
114
    char idstr[9] = "ATIDFF";
115
    setupSerial(h, B9600);
116
117
    writeSerial(h, "+++", 3);
118
    if (wait_for_ok(h))
119
    {
120
        printf("Initializing XBee\n");
121
122
        writeSerial(h, "ATCH0C\r", 7);
123
        wait_for_ok(h);
124
125
        idstr[6] = (robotNum / 10) + 0x30;
126
        idstr[7] = robotNum % 10 + 0x30;
127
        idstr[8] = '\r';
128
        writeSerial(h, idstr, 9);
129
        wait_for_ok(h);
130
131
        writeSerial(h, "ATDH0\r", 6);
132
        wait_for_ok(h);
133
        writeSerial(h, "ATDLFFFF\r", 9);
134
        wait_for_ok(h);
135
        writeSerial(h, "ATAP0\r", 6);
136
        wait_for_ok(h);
137
        writeSerial(h, "ATBD6\r", 6);
138
        wait_for_ok(h);
139
        writeSerial(h, "ATCN\r", 5);
140
        wait_for_ok(h);
141
142
        _init = 1;
143
    }
144
145
    setupSerial(h, B57600);
146
147
    if (!_init)
148
    {
149
        printf("Configuring XBee\n");
150
151
        writeSerial(h, "+++", 3);
152
        wait_for_ok(h);
153
154
        idstr[6] = (robotNum / 10) + 0x30;
155
        idstr[7] = robotNum % 10 + 0x30;
156
        idstr[8] = '\r';
157
        writeSerial(h, idstr, 9);
158
        wait_for_ok(h);
159
160
        writeSerial(h, "ATCN\r", 5);
161
        wait_for_ok(h);
162
    }
163
164
    return 0;
165
}
166
167
/* Take in an intel hex file and load it into a large array
168
 * This allows us to read sequential data from the large array without having to
169
 * worry about weird character line-feed breaks in the text/HEX file.
170
 *
171
 * Takes: file name?
172
 * Returns: Big array
173
 *
174
 * For ATmega168, we have to load 128 bytes at a time (program full page). Document: AVR095
175
 */
176
177
#define MEM_SIZE 131072
178
179
unsigned char intel_hex_array[MEM_SIZE];
180
181
unsigned int Hex_Convert(char str[3])
182
{
183
    unsigned int hex_num;
184
    char hstr[5] = { '0', 'x', 0, 0, 0 };
185
    hstr[2] = str[0];
186
    hstr[3] = str[1];
187
    sscanf(hstr, "%x", &hex_num);
188
    return hex_num;
189
}
190
191
int parse_file(char* file)
192
{
193
    int i;
194
    char buffer[3];
195
196
        /* Read in the HEX file - clean it up */
197
        FILE* fnum = fopen(file, "r");
198
    if (fnum == NULL)
199
        return 1;
200
201
        /* Pre-fill hex_array with 0xFF */
202
        for (i=0; i < MEM_SIZE; i++)
203
    {
204
                intel_hex_array[i] = 0xff;
205
        }
206
207
        /* Step through cleaned file and load file contents into large array
208
         * Also convert from ASCII to binary */
209
        for(;;)
210
    {
211
        int Record_Length, Memory_Address_High, Memory_Address_Low, Memory_Address, End_Record;
212
213
        /* Peel off first character */
214
        int first = fgetc(fnum);
215
216
        /* Remove empty lines + lines not starting with a ":" */
217
        if (first == EOF) break;
218
                if (first != ':') continue;
219
220
                /* Peel off record length */
221
                Record_Length = Hex_Convert(fgets(buffer, 3, fnum));
222
223
                /* Get the memory address of this line */
224
                Memory_Address_High = Hex_Convert(fgets(buffer, 3, fnum));
225
                Memory_Address_Low = Hex_Convert(fgets(buffer, 3, fnum));
226
                Memory_Address = (Memory_Address_High << 8) + Memory_Address_Low;
227
228
                /*Divide Memory address by 2
229
                         If (Memory_Address_High Mod 2) <> 0 Then
230
                             Memory_Address_Low = Memory_Address_Low + 256
231
                         End If
232
                         Memory_Address_High = Memory_Address_High \ 2
233
                         Memory_Address_Low = Memory_Address_Low \ 2*/
234
235
                /* Peel off and check for end of file tage */
236
                End_Record = Hex_Convert(fgets(buffer, 3, fnum));
237
        if (End_Record == 04 ) continue;
238
                if (End_Record == 01) break;
239
240
                for (i=0; i < Record_Length; i++)
241
        {
242
                        /* Pull out the byte and store it in the memory_address location of the intel_hex array */
243
                        intel_hex_array[Memory_Address + i] = Hex_Convert(fgets(buffer, 3, fnum));
244
                }
245
246
        }
247
248
    fclose(fnum);
249
250
        return 0;
251
}
252
253
254
int download(int h, char *file)
255
{
256
        int j;
257
258
        int Memory_Address_High;
259
        int Memory_Address_Low;
260
261
        int Check_Sum;
262
263
    char buf;
264
265
        int last_memory_address;
266
        int current_memory_address;
267
268
        int page_size = 256; /* For ATmega168, we have to load 128 bytes at a time (program full page). Document: AVR095 */
269
270
        /* Take intel hex file and store it squentially into large array */
271
        if (parse_file(file))
272
    {
273
                fprintf(stderr, "Whoa - problem parsing file!\n");
274
                return -1;
275
        }
276
277
        printf("Waiting for target IC to broadcast\n");
278
279
        /* "Send the reset signal"; */
280
281
        while(!getAvailBytes(h))
282
    {
283
        usleep(1500000);
284
        writeByte(h, 6);
285
    }
286
287
        printf("Load Mode Notification Received\n");
288
289
        /* Find the last spot in the large hex_array */
290
        last_memory_address = MEM_SIZE - 1;
291
        while(last_memory_address > 0)
292
    {
293
                if (intel_hex_array[last_memory_address] != 255) break;
294
                last_memory_address--;
295
        }
296
297
        /* Start at beginning of large intel array */
298
        current_memory_address = 0;
299
        while (current_memory_address < last_memory_address)
300
    {
301
        while((buf = readByte(h))==-1)
302
            usleep(1000);
303
304
                if (buf == 'T') /* All is well */
305
        {
306
                        /* Total_Code_Words = Total_Code_Words + (Record_Length / 2) */
307
        }
308
                else if (buf == 7)  /* Re-send line */
309
        {
310
            static int resend_count = 0;
311
                        current_memory_address = current_memory_address - page_size;
312
            if (current_memory_address<0) current_memory_address=0;
313
            printf("\nResending: %d\n", ++resend_count);
314
                        usleep(1000);
315
        }
316
                else
317
        {
318
                        fprintf(stderr, "\nError : Incorrect response from target IC: %d. Programming is incomplete and will now halt.\n", buf);
319
                        return -2;
320
                }
321
322
                /* Update progress */
323
                printf("\rLoaded %d code words", current_memory_address);
324
        fflush(stdout);
325
326
                /*=============================================*/
327
                /* Convert 16-bit current_memory_address into two 8-bit characters */
328
                Memory_Address_High = current_memory_address >> 8;
329
                Memory_Address_Low = current_memory_address & 0xff;
330
331
                /*=============================================*/
332
                /* Calculate current check_sum */
333
                Check_Sum = 0;
334
                Check_Sum += page_size >> 8;    /* page size high byte */
335
        Check_Sum += page_size & 0xff;  /* page size low byte */
336
                Check_Sum += Memory_Address_High; /* Convert high byte */
337
                Check_Sum += Memory_Address_Low; /* Convert low byte */
338
339
                for(j=0; j < page_size; j++)
340
        {
341
                        Check_Sum += intel_hex_array[current_memory_address + j];
342
                }
343
344
                /* Now reduce check_sum to 8 bits */
345
                Check_Sum &= 0xff;
346
                /* Now take 2's compliment */
347
                Check_Sum = 256 - Check_Sum;
348
349
                /*=============================================*/
350
                /* Send the start character */
351
        writeByte(h, ':');
352
353
                /* Send the record length */
354
        writeByte(h, page_size & 0xff); /* low byte */
355
        writeByte(h, page_size >> 8);   /* high byte */
356
357
                /* Send this block's address */
358
        writeByte(h, Memory_Address_Low);
359
        writeByte(h, Memory_Address_High);
360
361
                /* Send this block's check sum */
362
        writeByte(h, Check_Sum);
363
364
                /* Send the block */
365
                for (j=0; j < page_size; j++)
366
        {
367
                        writeByte(h, intel_hex_array[current_memory_address + j]);
368
                }
369
                /*=============================================*/
370
371
                current_memory_address += page_size;
372
        }
373
374
        /* Tell the target IC we are done transmitting data */
375
    writeByte(h, ':');
376
    writeByte(h, 'S');
377
    writeByte(h, 'S');
378
379
        printf("\nDownload Complete!\n");
380
381
    return 0;
382
}
383
384
int main(int argc, char* argv[])
385
{
386
    int h;
387
388
    printf("//=\\\\     _                          __               \n");
389
    printf("||  .    |_) _ |_  _  _  |    |_    /   _  |  _ __  \\/\n");
390
    printf("|| -A!   | \\(_)|_)(_)(_  | |_||_)   \\__(_) | (_)| | / \n");
391
    printf("                                                      \n");
392
    printf("                 Universal Programmer                 \n");
393
    printf("                                                      \n");
394
395
    switch(argc)
396
    {
397
    case 3:
398
        /* open port for I/O */
399
        h = initSerial(argv[1]);
400
        setupSerial(h, B57600);
401
    break;
402
    case 4:
403
        h = initSerial(argv[1]);
404
        xbee_setup(h, atoi(argv[3]));
405
    break;
406
    default:
407
        printf("Usage: %s <port name> <hex file> [<robot ID>]\n", argv[0]);
408
        return -1;
409
    }
410
411
    int ret = download(h, argv[2]);
412
413
    closeSerial(h);
414
415
    return ret;
416
}