Added --console, built in terminal emulator to talk to device once loaded

Support for Win32, via mingw. Precompiled .exe added.
Support for OSX, must open device with O_NONBLOCK
Added bootloader search timeout
Updated docs
This commit is contained in:
Joby Taffey committed 2012-03-08 21:52:00 +00:00
1 parent c0a9d84660
commit 4ee6ff78d0
8 files changed
+1451 -75

No files matched your search

+11 -2
View File
@@ -5,7 +5,7 @@ CCTL is a serial bootloader for the Chipcon CC1110/CC1111 using only one 1KB pag
It allows update of the the microcontroller firmware over its serial port.
The bootloader consists of two components, a piece of firmware that is flashed
onto the device and a C utility for downloading code and manipulating the
onto the device and a utility for downloading code and manipulating the
flash memory.
Authors
@@ -25,13 +25,22 @@ Once the device is flashed with this firmware it will identify itself over the s
The microcontroller is configured for 115200, 8N1 transmitting on P0.3, receiving on P0.2.
Note that the CC111x is not 5v tolerant, so be sure to use a 3v serial adapter.
You can now use cctl-prog to download your payload code.
A prebuilt version of cctl-prog.exe is provided for Windows. For Linux or OSX, type "make".
For usage instructions, run cctl-prog with no arguments:
`./cctl-prog`
ChipCon Tiny Loader Programmer
cctl-prog -d /dev/ttyXYZ [-c] [-f file.hex]
--help -h This help
--console -c Connect console to serial port on device
--flash=file.hex -f file.hex Reflash device with intel hex file
--timeout=n -t n Search for bootload string for n seconds
If both `--console` and `--flash` are specified, then the device will be reflashed first, then the console will connect.
Preparing your user code for usage with the bootloader is very simple. All you
need to do is set your linker to start the code section at 0x400. For an
example of this see the `Makefile` file in the `example_payload` subdirectory.
Executable
BIN
View File
Binary file not shown.
+2
View File
@@ -1,3 +1,5 @@
# Makefile for Linux and OSX/Darwin
CFLAGS=-Wall
TARGET=cctl-prog
+12
View File
@@ -0,0 +1,12 @@
# Makefile for Win32, using MingW32 GCC toolchain
CROSS_COMPILE=/usr/bin/i586-mingw32msvc-
CFLAGS=-Wall
TARGET=cctl-prog
all:
$(CROSS_COMPILE)gcc -o $(TARGET).exe $(CFLAGS) $(TARGET).c hex.c
clean:
rm -f $(TARGET).exe
+165
View File
@@ -0,0 +1,165 @@
/* Macros to swap the order of bytes in integer values.
Copyright (C) 1997,1998,2000,2001,2002,2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _PORTABLEXDR_BYTESWAP_H
#define _PORTABLEXDR_BYTESWAP_H 1
#include <sys/param.h>
/* Swap bytes in 16 bit value. */
#define __bswap_constant_16(x) \
((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))
#ifdef __GNUC__
# define __bswap_16(x) \
(__extension__ \
({ unsigned short int __bsx = (x); __bswap_constant_16 (__bsx); }))
#else
static __inline unsigned short int
__bswap_16 (unsigned short int __bsx)
{
return __bswap_constant_16 (__bsx);
}
#endif
/* Swap bytes in 32 bit value. */
#define __bswap_constant_32(x) \
((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | \
(((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24))
#ifdef __GNUC__
# define __bswap_32(x) \
(__extension__ \
({ register unsigned int __bsx = (x); __bswap_constant_32 (__bsx); }))
#else
static __inline unsigned int
__bswap_32 (unsigned int __bsx)
{
return __bswap_constant_32 (__bsx);
}
#endif
#if defined __GNUC__ && __GNUC__ >= 2
/* Swap bytes in 64 bit value. */
# define __bswap_constant_64(x) \
((((x) & 0xff00000000000000ull) >> 56) \
| (((x) & 0x00ff000000000000ull) >> 40) \
| (((x) & 0x0000ff0000000000ull) >> 24) \
| (((x) & 0x000000ff00000000ull) >> 8) \
| (((x) & 0x00000000ff000000ull) << 8) \
| (((x) & 0x0000000000ff0000ull) << 24) \
| (((x) & 0x000000000000ff00ull) << 40) \
| (((x) & 0x00000000000000ffull) << 56))
# define __bswap_64(x) \
(__extension__ \
({ union { __extension__ unsigned long long int __ll; \
unsigned int __l[2]; } __w, __r; \
if (__builtin_constant_p (x)) \
__r.__ll = __bswap_constant_64 (x); \
else \
{ \
__w.__ll = (x); \
__r.__l[0] = __bswap_32 (__w.__l[1]); \
__r.__l[1] = __bswap_32 (__w.__l[0]); \
} \
__r.__ll; }))
#endif
/* Copyright (C) 1993,97,2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef HAVE_NTOHL
#undef htonl
#undef ntohl
static inline uint32_t
htonl (x)
uint32_t x;
{
#if BYTE_ORDER == BIG_ENDIAN
return x;
#elif BYTE_ORDER == LITTLE_ENDIAN
return __bswap_32 (x);
#else
# error "What kind of system is this?"
#endif
}
#define ntohl htonl
#endif
/* Copyright (C) 1993,97,2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef HAVE_NTOHS
#undef htons
#undef ntohs
static inline uint16_t
htons (x)
uint16_t x;
{
#if BYTE_ORDER == BIG_ENDIAN
return x;
#elif BYTE_ORDER == LITTLE_ENDIAN
return __bswap_16 (x);
#else
# error "What kind of system is this?"
#endif
}
#define ntohs htons
#endif
#endif
+648 -71
View File
@@ -4,24 +4,176 @@
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/types.h>
#include <stdbool.h>
#include <getopt.h>
#include <sys/time.h>
#define SERIAL_TIMEOUT 2
#ifndef WIN32
#include <termios.h>
#include <sys/select.h>
#else
#include <windows.h>
#include <wincon.h>
#include <time.h>
#define O_NOCTTY 0
#define O_NDELAY 0
#define B115200 115200
#endif
#include "hex.h"
int serial_open(char *port)
static struct option long_options[] =
{
{"help", no_argument, 0, 'h'},
{"console", no_argument, 0, 'c'},
{"flash", required_argument, 0, 'f'},
{"device", required_argument, 0, 'd'},
{"timeout", required_argument, 0, 't'},
{0, 0, 0, 0}
};
void usage(void)
{
fprintf(stderr, "ChipCon Tiny Loader Programmer\n");
#ifdef WIN32
fprintf(stderr, "cctl-prog -d COMx [-c] [-f file.hex]\n");
#else
fprintf(stderr, "cctl-prog -d /dev/ttyXYZ [-c] [-f file.hex]\n");
#endif
fprintf(stderr, " --help -h This help\n");
fprintf(stderr, " --console -c Connect console to serial port on device\n");
fprintf(stderr, " --flash=file.hex -f file.hex Reflash device with intel hex file\n");
fprintf(stderr, " --timeout=n -t n Search for bootload string for n seconds\n");
}
static bool opt_console = false;
static bool opt_flash = false;
static int opt_timeout = 10;
static bool opt_device = false;
static char *flash_filename = NULL;
static char *device_name = NULL;
#ifndef WIN32
static struct termios orig_termios;
#endif
int parse_options(int argc, char **argv)
{
int c;
int option_index;
while(1)
{
c = getopt_long (argc, argv, "hcf:d:t:", long_options, &option_index);
if (c == -1)
break;
switch(c)
{
case 'h':
return 1;
break;
case 't':
opt_timeout = atoi(optarg);
break;
case 'c':
opt_console = true;
break;
case 'f':
opt_flash = true;
flash_filename = strdup(optarg);
break;
case 'd':
opt_device = true;
device_name = strdup(optarg);
break;
default:
return 1;
break;
}
}
if (!opt_device)
return 1;
if (!opt_flash && !opt_console)
return 1;
return 0;
}
static void do_exit(void)
{
#ifndef WIN32
tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
#endif
puts("exiting\n");
}
#ifndef WIN32
static int enableRawMode(void)
{
struct termios raw;
if (!isatty(STDIN_FILENO))
return -1;
if (tcgetattr(STDIN_FILENO,&orig_termios) == -1)
return -1;
raw = orig_termios; /* modify the original mode */
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
raw.c_oflag &= ~(OPOST);
raw.c_cflag |= (CS8);
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
raw.c_cc[VMIN] = 1;
raw.c_cc[VTIME] = 0;
if (tcsetattr(STDIN_FILENO,TCSAFLUSH,&raw) < 0)
return -1;
return 0;
}
#endif
int serialOpen(char *port)
{
int fd;
#ifndef WIN32
struct termios t_opt;
#else
char path[1024];
HANDLE hCom = NULL;
#endif
fd = open(port, O_RDWR | O_NOCTTY);
if (fd == -1) {
fprintf(stderr, "Could not open serial port.");
#ifdef WIN32
if (port[0] != '\\')
{
snprintf(path, sizeof(path), "\\\\.\\%s", port);
port = path;
}
#endif
#ifndef WIN32
if ((fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
{
fprintf(stderr, "Could not open serial port %s\n", port);
return -1;
}
#else
hCom = CreateFile(port, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (!hCom || hCom == INVALID_HANDLE_VALUE )
{
fprintf(stderr, "Invalid handle for serial port\n");
return -1;
}
else
fd = (int)hCom;
#endif
#ifndef WIN32
fcntl(fd, F_SETFL, 0);
tcgetattr(fd, &t_opt);
cfsetispeed(&t_opt, B115200);
@@ -40,20 +192,160 @@ int serial_open(char *port)
tcsetattr(fd, TCSANOW, &t_opt);
return fd;
#else
{
DCB dcb = {0};
HANDLE hCom = (HANDLE)fd;
COMMTIMEOUTS cto = { 2, 1, 1, 0, 0 };
if(!SetCommTimeouts(hCom,&cto))
{
fprintf(stderr, "SetCommTimeouts failed\n");
return -1;
}
dcb.DCBlength = sizeof(dcb);
dcb.BaudRate = B115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fBinary = 1;
if (!SetCommState(hCom, &dcb))
{
fprintf(stderr, "Failed to setup serial port\n");
return -1;
}
return (int)hCom;
}
#endif
}
#ifdef WIN32
int __stdcall serialSelect(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfs, const struct timeval* timeout)
{
time_t maxtc = time(0) + (timeout->tv_sec);
COMSTAT cs = {0};
if (readfds->fd_count != 1 )
{
fprintf(stderr, "Too many fds\n");
return -1;
}
while( time(0) <= maxtc )
{ //only one file supported
if (ClearCommError( (HANDLE)readfds->fd_array[0], 0, &cs) != TRUE )
{
fprintf(stderr, "comm error\n");
return -1;
}
if (cs.cbInQue > 0 )
{
return 1;
}
Sleep(10);
}
return 0;
}
#endif
#ifdef WIN32
int serialRead(int fd, void* buf, int len)
{
HANDLE hCom = (HANDLE)fd;
int res = 0;
unsigned long bread = 0;
res = ReadFile(hCom, buf, len, &bread, NULL);
if (res == FALSE )
return -1;
else
return bread;
}
#else
int serialRead(int fd, void* buf, int len)
{
struct timeval start, now;
int rc;
gettimeofday(&start, NULL);
do
{
if ((rc = read(fd, buf, len)) < 0)
return rc;
if (rc > 0)
return rc;
}
while((now.tv_sec - start.tv_sec) < SERIAL_TIMEOUT);
return 1;
}
#endif
#ifdef WIN32
int serialWrite(int fd, const void* buf, int len)
{
HANDLE hCom = (HANDLE)fd;
int res = 0;
unsigned long bwritten = 0;
res = WriteFile(hCom, buf, len, &bwritten, NULL);
if (res == FALSE )
return -1;
else
return bwritten;
}
#else
int serialWrite(int fd, void* buf, int len)
{
struct timeval start, now;
int rc;
gettimeofday(&start, NULL);
do
{
if ((rc = write(fd, buf, len)) < 0)
return rc;
if (rc > 0)
return rc;
}
while((now.tv_sec - start.tv_sec) < SERIAL_TIMEOUT);
return 1;
}
#endif
#ifdef WIN32
int serialClose(int fd)
{
HANDLE hCom = (HANDLE)fd;
CloseHandle(hCom);
return 0;
}
#else
#define serialClose close
#endif
int program_page(int fd, int page)
{
char cmd = 'p';
char rsp;
if (write(fd, &cmd, 1) <= 0)
if (serialWrite(fd, &cmd, 1) <= 0)
return 1;
if (write(fd, &page, 1) <= 0)
if (serialWrite(fd, &page, 1) <= 0)
return 1;
if (read(fd, &rsp, 1) <= 0 || rsp != 0)
if (serialRead(fd, &rsp, 1) <= 0 || rsp != 0)
return 1;
return 0;
@@ -66,22 +358,22 @@ int read_page(int fd, uint8_t page, uint8_t *data)
char cmd = 'r';
char rsp;
if (write(fd, &cmd, 1) <= 0)
if (serialWrite(fd, &cmd, 1) <= 0)
return 1;
if (write(fd, &page, 1) <= 0)
if (serialWrite(fd, &page, 1) <= 0)
return 1;
remaining = 1024;
while(remaining > 0)
{
rc = read(fd, data + (1024 - remaining), remaining);
rc = serialRead(fd, data + (1024 - remaining), remaining);
if (rc <= 0)
return 1;
remaining -= rc;
}
if (read(fd, &rsp, 1) <= 0 || rsp != 0)
if (serialRead(fd, &rsp, 1) <= 0 || rsp != 0)
return 1;
return 0;
@@ -92,13 +384,13 @@ int erase_page(int fd, uint8_t page)
char cmd = 'e';
char rsp;
if (write(fd, &cmd, 1) <= 0)
if (serialWrite(fd, &cmd, 1) <= 0)
return 1;
if (write(fd, &page, 1) <= 0)
if (serialWrite(fd, &page, 1) <= 0)
return 1;
if (read(fd, &rsp, 1) <= 0 || rsp != 0)
if (serialRead(fd, &rsp, 1) <= 0 || rsp != 0)
{
fprintf(stderr, "erase_page rsp=%02X\n", rsp);
return 1;
@@ -114,19 +406,19 @@ int load_data(int fd, uint8_t *data)
char cmd = 'l';
char rsp;
if (write(fd, &cmd, 1) <= 0)
if (serialWrite(fd, &cmd, 1) <= 0)
return 1;
remaining = 1024;
while(remaining > 0)
{
rc = write(fd, data + (1024 - remaining), remaining);
rc = serialWrite(fd, data + (1024 - remaining), remaining);
if (rc <= 0)
return 1;
remaining -= rc;
}
if (read(fd, &rsp, 1) <= 0 || rsp != 0)
if (serialRead(fd, &rsp, 1) <= 0 || rsp != 0)
return 1;
return 0;
@@ -182,27 +474,39 @@ int erase_program_verify_page(int fd, uint8_t *data, uint8_t page)
return 0;
}
int wait_for_bootloader(int fd)
int wait_for_bootloader(int fd, int timeout)
{
uint8_t c;
uint8_t c = 0;
uint8_t prev_c = 0;
int attempts = 100;
struct timeval start, now;
int rc;
while(attempts-- > 0)
gettimeofday(&start, NULL);
printf("Waiting %ds for bootloader, reset board now\n", timeout);
do
{
printf("Waiting...\n");
if (read(fd, &c, 1) < 0)
if ((rc = serialRead(fd, &c, 1)) < 0)
{
fprintf(stderr, "read failed\n");
return 1;
}
else
if (rc == 1)
{
if (c == 'B' && prev_c == 'B')
break;
prev_c = c;
}
gettimeofday(&now, NULL);
}
while((now.tv_sec - start.tv_sec) < timeout);
if (now.tv_sec - start.tv_sec >= timeout)
return 1;
c = 0x00;
if (write(fd, &c, 1) <= 0)
if (serialWrite(fd, &c, 1) <= 0)
return 1;
return 0;
@@ -212,79 +516,352 @@ int send_jump(int fd)
{
uint8_t cmd = 'j';
if (write(fd, &cmd, 1) <= 0)
if (serialWrite(fd, &cmd, 1) <= 0)
return 1;
return 0;
}
int main(int argc, char *argv[])
#ifndef WIN32
void do_console(int fd)
{
int fd;
uint8_t buf[32*1024];
int i, j;
fd_set rfds;
struct timeval tv;
int rc;
if (argc < 3)
if (0 != enableRawMode())
{
fprintf(stderr, "Usage %s <serial device> <hex file>\n", argv[0]);
return 1;
fprintf(stderr, "Not a TTY?\n");
return;
}
fd = serial_open(argv[1]);
if (fd < 0)
while(1)
{
fprintf(stderr, "Failed to open %s\n", argv[1]);
return 1;
}
uint8_t c;
tv.tv_sec = 1;
tv.tv_usec = 0;
int maxfd = 1;
memset(buf, 0xFF, sizeof(buf));
if (0 != read_hexfile(buf, sizeof(buf), argv[2]))
{
fprintf(stderr, "Failed to read %s\n", argv[2]);
return 1;
}
FD_ZERO(&rfds);
FD_SET(0, &rfds);
#ifndef WIN32
FD_SET(fd, &rfds);
maxfd = fd+1;
#endif
if (0 != wait_for_bootloader(fd))
{
fprintf(stderr, "No bootloader detected\n");
return 1;
}
rc = select(maxfd, &rfds, NULL, NULL, &tv);
for (i=0x400;i<32*1024;i+=1024)
{
bool all_empty = true;
for (j=i;j<i+1024;j++)
if (rc == -1)
{
if (buf[j] != 0xFF)
{
all_empty = false;
break;
}
fprintf(stderr, "select failed\n");
return;
}
if (!all_empty)
else
if (rc)
{
printf("erase/write/verify page %d\n", i/1024);
if (0 != erase_program_verify_page(fd, buf + i, i/1024))
if (FD_ISSET(0, &rfds))
{
fprintf(stderr, "erase_program_verify_page failed\n");
return 1;
if(read(0, &c, 1) > 0)
{
if (c == 0x03 || c == 0x04) // ctrl-d, ctrl-c
{
return;
}
if (1 != serialWrite(fd, &c, 1))
{
fprintf(stderr, "write error\n");
return;
}
}
}
else
if (FD_ISSET(fd, &rfds))
{
if(serialRead(fd, &c, 1) > 0)
{
if (1 != write(1, &c, 1))
{
fprintf(stderr, "write error\n");
return;
}
}
}
}
else
{
printf("erasing page %d\n", i/1024);
if (0 != erase_page(fd, i/1024))
// timeout
}
}
}
#else
DWORD CALLBACK SerialRxThread( HANDLE h )
{
OVERLAPPED ov;
HANDLE hconn = GetStdHandle(STD_INPUT_HANDLE);
BOOL quit = FALSE;
char kb;
INPUT_RECORD b1;
if (hconn == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "Invalid input handle\n");
exit(1);
}
ZeroMemory(&ov,sizeof(ov));
ov.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
if (ov.hEvent == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "CreateEvent failed\n");
SetCommMask(h,0);
return 0;
}
SetConsoleMode(hconn,0);
do
{
char buf[2] = {0,0};
DWORD rd = 0;
WaitForSingleObject(hconn,INFINITE);
// fetch input
if(!ReadConsoleInput(hconn,&b1,1,&rd))
{
fprintf(stderr, "Failed to read from console, perhaps we're not running in cmd.exe?\n");
quit = TRUE;
}
else
{
kb=b1.Event.KeyEvent.uChar.AsciiChar;
buf[0] = kb;
}
if(rd)
{
DWORD wr = 1;
if (buf[0] == 0x3 ) // ctrl-c
{
fprintf(stderr, "erase failed\n");
return 1;
quit = TRUE;
break;
}
else
{
if (buf[0] != 0x0 && b1.Event.KeyEvent.bKeyDown)
{
if (!WriteFile(h,buf,wr,&wr,&ov) )
{
if(GetLastError() == ERROR_IO_PENDING)
{
if (!GetOverlappedResult(h,&ov,&wr,TRUE) )
{
fprintf(stderr, "GetOverlappedResult failed\n");
quit = TRUE;
}
}
}
else
{
fprintf(stderr, "WriteFile failed\n");
quit = TRUE;
}
}
}
}
}
if (0 != send_jump(fd))
while(!quit);
if (!SetCommMask(h,0)) // send request to terminate thread
fprintf(stderr, "SetCommMask-GetLastError: %ld\n", GetLastError());
return 0;
}
void do_console(int fd)
{
DWORD mask;
DWORD id;
DWORD i;
OVERLAPPED ov;
HANDLE h = (HANDLE)fd;
// start serial receiver thread
HANDLE hconin = CreateThread(NULL, 0, SerialRxThread, h, 0, &id);
if (hconin == INVALID_HANDLE_VALUE )
{
fprintf(stderr, "send jump failed\n");
fprintf(stderr, "CreateThread failed\n");
return;
}
CloseHandle(hconin);
// Overlapped IO event
ZeroMemory(&ov, sizeof(ov));
ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(ov.hEvent == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "CreateThread failed\n");
return;
}
close(fd);
// only interested in rx
if(!SetCommMask(h, EV_RXCHAR))
{
fprintf(stderr, "SetCommMask failed\n");
return;
}
while (1)
{
if (!WaitCommEvent(h, &mask, &ov))
{
if (GetLastError() == ERROR_IO_PENDING )
{
DWORD r;
if (!GetOverlappedResult(h,&ov,&r,TRUE) )
{
fprintf(stderr, "GetOverlappedResult failed\n");
break;
}
}
else
{
break;
}
}
// See if we've been asked to terminate
if ( mask == 0 )
break;
if (mask & EV_RXCHAR) // received data
{
char buf[1024] = {0};
DWORD readcount;
do
{
readcount = 0;
if (!ReadFile(h, buf, sizeof(buf), &readcount, &ov))
{
if (GetLastError() == ERROR_IO_PENDING)
{
if (!GetOverlappedResult(h, &ov, &readcount, TRUE))
{
fprintf(stderr, "GetOverlappedResult failed\n");
break;
}
}
else
{
fprintf(stderr, "ReadFile failed\n");
break;
}
}
for (i=0;i<readcount;i++)
{
putchar(buf[i]);
fflush(stdout);
}
}
while(readcount);
}
mask = 0;
}
CloseHandle(ov.hEvent);
}
#endif
int main(int argc, char *argv[])
{
int fd;
uint8_t *buf;
int i, j;
if (NULL == (buf=malloc(32*1024)))
{
fprintf(stderr, "out of ram\n");
return 1;
}
if (0 != parse_options(argc, argv))
{
usage();
return 1;
}
if ((fd = serialOpen(device_name)) < 0)
{
fprintf(stderr, "Failed to open %s\n", device_name);
return 1;
}
if (opt_flash)
{
memset(buf, 0xFF, 32*1024);
if (0 != read_hexfile(buf, 32*1024, flash_filename))
{
fprintf(stderr, "Failed to read %s\n", flash_filename);
return 1;
}
if (0 != wait_for_bootloader(fd, opt_timeout))
{
fprintf(stderr, "No bootloader detected\n");
return 1;
}
else
{
printf("Bootloader detected\n");
}
for (i=0x400;i<32*1024;i+=1024)
{
bool all_empty = true;
for (j=i;j<i+1024;j++)
{
if (buf[j] != 0xFF)
{
all_empty = false;
break;
}
}
if (!all_empty)
{
printf("Erasing, programming and verifying page %d\n", i/1024);
if (0 != erase_program_verify_page(fd, buf + i, i/1024))
{
fprintf(stderr, "erase_program_verify_page failed\n");
return 1;
}
}
else
{
printf("Erasing page %d\n", i/1024);
if (0 != erase_page(fd, i/1024))
{
fprintf(stderr, "erase failed\n");
return 1;
}
}
}
if (0 != send_jump(fd))
{
fprintf(stderr, "send jump failed\n");
return 1;
}
printf("Programming complete\n");
}
if (opt_console)
{
atexit(do_exit);
printf("Connected to %s, ctrl-c to exit\n", device_name);
do_console(fd);
}
serialClose(fd);
return 0;
}
+7 -2
View File
@@ -6,13 +6,18 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#ifndef WIN32
#include <arpa/inet.h>
#else
#include "byteswap.h"
#endif
static uint8_t tolowercase(uint8_t ch)
{
if ((ch >= 'A') && (ch <= 'Z'))
return ch + 0x20; // Convert uppercase to lowercase
return ch; // Simply return original character if it doesn't require any adjustments
return ch;
}
static int8_t parseHexDigit(uint8_t digit)
@@ -39,7 +44,7 @@ static int hexstring_parse(const char *hexstr, uint8_t *buf, size_t *buflen)
if (*buflen < hexstrlen/2)
{
fprintf(stderr, "hexstring_parse: buffer too small %d < %d\n", *buflen, hexstrlen/2);
fprintf(stderr, "hexstring_parse: buffer too small %zu < %zu\n", *buflen, hexstrlen/2);
return 1;
}
+606
View File
@@ -0,0 +1,606 @@
:1004000002048B0211E8FFFFFFFFFF32FFFFFFFF37
:10041000FFFFFF021F1DFFFFFFFFFF32FFFFFFFF78
:10042000FFFFFF32FFFFFFFFFFFFFF021E4CFFFF3A
:10043000FFFFFF32FFFFFFFFFFFFFF32FFFFFFFF66
:10044000FFFFFF32FFFFFFFFFFFFFF32FFFFFFFF56
:10045000FFFFFF020BB5FFFFFFFFFF32FFFFFFFFB4
:10046000FFFFFF32FFFFFFFFFFFFFF32FFFFFFFF36
:10047000FFFFFF32FFFFFFFFFFFFFF021456FFFFEA
:10048000FFFFFF0212DB120F9C80FE7581201227F6
:10049000CAE5826003020486790DE94400601B7A94
:1004A0000190296178067593F2E493F2A308B800ED
:1004B000020593D9F4DAF27593FFE478FFF6D8FDDC
:1004C0007800E84400600A79007593F0E4F309D8F5
:1004D000FC7806E84402600C790390F000E4F0A395
:1004E000D8FCD9FA90F1767406F090F1777406F0A2
:1004F00090F1787406F090F1797406F090F17A74C6
:1005000006F090F17B7406F090F17C7404F090F1A9
:100510007DE4F090F17EF090F17F74DFF090F18057
:1005200074BEF090F181E4F090F1827407F090F1E4
:10053000837420F090F1847442F00204862290F0DB
:10054000007401F0A3E4F090F0027401F0A3E4F071
:1005500022C00A85810AAA827B007401B50200507C
:1005600037E50A24FBF8740326FCE40836FD088608
:10057000068C828D838EF01226BCFCA31226BCFD55
:10058000A31226BCFE8C828D838EF0C00212215BEA
:10059000AC82AD83D0028C03EA602EE50A24FBF81E
:1005A00086020886040886058A828C838DF01226CE
:1005B000BCFAA31226BCFCA31226BCFDC0038A828F
:1005C0008C838DF012166E1581D00A22C00A8581A7
:1005D0000A0581AA82A80A0876007402B5020050B2
:1005E0003AE50A24FBF8740626FCE40836FD088682
:1005F000068C828D838EF01226BCFCA31226BCFDD5
:10060000A31226BCFE8C828D838EF0C00212215B69
:10061000AC82AD83D002A80A08A6047401B502001A
:100620005060E50A24FBF8740326FAE40836FC0857
:1006300086058A828C838DF01226BCFAA31226BC12
:10064000FCA31226BCFDE50A24FBF88606088607F3
:100650000886038E828F838BF01226BCFEA312269F
:10066000BCFFA31226BCFBA80A08E6C0E0C002C07B
:1006700004C0058E828F838BF0121625E58124FC41
:10068000F581850A81D00A22C00A85810AAA827B67
:10069000007401B502005037E50A24FBF874032604
:1006A000FCE40836FD0886068C828D838EF01226C7
:1006B000BCFCA31226BCFDA31226BCFE8C828D833B
:1006C0008EF0C00212215BAC82AD83D0028C03EAB3
:1006D000602EE50A24FBF886020886040886058A4F
:1006E000828C838DF01226BCFAA31226BCFCA312C6
:1006F00026BCFDC0038A828C838DF01216B315814F
:10070000D00A22C00A85810AAA827B007401B50240
:10071000005037E50A24FBF8740326FCE40836FD94
:100720000886068C828D838EF01226BCFCA31226CE
:10073000BCFDA31226BCFE8C828D838EF0C00212FB
:10074000215BAC82AD83D0028C03EA602EE50A24E3
:10075000FBF886020886040886058A828C838DF061
:100760001226BCFAA31226BCFCA31226BCFDC003B1
:100770008A828C838DF01216F81581D00A22C00A65
:1007800085810A12154ED00A22C00A85810AE582A7
:10079000FA603EE50A24FBF8860208860308860410
:1007A0008A828B838CF01226BCFAA31226BCFBA390
:1007B0001226BCFC8A828B838CF012215BAA82AB4E
:1007C0008390F000EAF0A3EBF090F002EAF0A3EBE4
:1007D000F0D00A22C00A85810AE582FA6036E50A6D
:1007E00024FBF886020886030886048A828B838CA1
:1007F000F01226BCFAA31226BCFBA31226BCFC8A6C
:10080000828B838CF012215B1218BE9027CE75F07C
:1008100080122033D00A22C00A85810AC082E58175
:100820002408F581E50A24FBF88603088604088677
:10083000058B828C838DF01226BCFEA31226BCFF92
:10084000A31226BCFAC003C004C0057415C0E0742E
:1008500028C0E07480C0E08E828F838AF012262B3D
:10086000AA82AE83158115811581D005D004D003ED
:10087000BA006EBE006B7D00EDC40354F8FEF5F0C7
:100880009027D593FAA3E5F093FBA3E5F093FCBA88
:100890000009BB0006BC00030209D78A828B838C47
:1008A000F0C005C006122033758220122027D00622
:1008B000EE24D5FEE43427FF8E828F83A3A3A3E426
:1008C00093FEA3E493FFA3E493FA8E828F838AF0CE
:1008D00012203390281A75F080122033D0050D8035
:1008E00097A80A08087600A80A0808E6C40354F87E
:1008F000FE24D5F582E43427F583E50A2403F8E4E1
:1009000093F6A3E49308F6A3E49308F6E50A240318
:10091000F8B6000B08B6000708B600030209D7C0F6
:10092000068B828C838DF01226BCFFA31226BCFEA0
:10093000A31226BCFAC003C004C005E50A2403F8CC
:10094000E6C0E008E6C0E008E6C0E08F828E838A59
:10095000F012262BAA82AE83158115811581D00550
:10096000D004D003BA0005BE00028004D006805F28
:10097000D006EE24D5FEE43427FA74062EF582E480
:100980003AF583E493FEA3E493FFE50A2406F874A2
:10099000032BF6E43C08F608A605A80A08E614FAB4
:1009A000C006C007E50A2406F8E6C0E008E6C0E095
:1009B00008E6C0E074C3C0E07409C0E0C006C00728
:1009C0008A8222158115811581D007D0068008A85A
:1009D0000A0808060208E7850A81D00A222290F058
:1009E00002E0FAA3E0FBC3E49A74808BF063F0802A
:1009F00095F0502E1ABAFF011B90F002EAF0A3EB1B
:100A0000F090F002E0FAA3E0FBBA0016BB0013126C
:100A1000154E90F000E0FAA3E0FB90F002EAF0A39C
:100A2000EBF0222222C00A85810AAA82AB83902899
:100A30001D75F080C002C003122033D003D0027CA9
:100A4000008A828B838CF012203390282275F080EC
:100A5000122033E50A24FCF886020886037C008A0B
:100A6000828B838CF012203390282475F080122022
:100A700033E50A24FBF886027B007C007D008A8235
:100A80008B838CF0ED12209090281A75F080122044
:100A900033D00A22C00A85810AAA82AB8390282A11
:100AA00075F080C002C003122033D003D0027C0056
:100AB0008A828B838CF012203390282475F0801268
:100AC0002033E50A24FDF886027B007C007D008A45
:100AD000828B838CF0ED12209090281A75F0801292
:100AE0002033D00A22C00A85810AAA82AB839028CB
:100AF0003975F080C002C003122033D003D0027CCD
:100B0000008A828B838CF012203390282475F08029
:100B1000122033E50A24FDF886027B007C007D006C
:100B20008A828B838CF0ED12209090281A75F080C9
:100B3000122033D00A22C00A85810AAA82AB839090
:100B4000284875F080C002C003122033D003D002C1
:100B50007C008A828B838CF012203390282475F0DD
:100B600080122033E50A24FDF886027B007C007D9C
:100B7000008A828B838CF0ED12209090281A75F0F9
:100B800080122033D00A2253BEFBE5BE30E6FB754F
:100B9000C6E9E5C630E6FB75C6A8E5C620E6FB4318
:100BA000BE0422222274FC55C94403F5C953C9FB73
:100BB00043C90880FEC0E0C082C083C0D075D000A9
:100BC000759CFF90F00AE02401F0D0D0D083D08251
:100BD000D0E03290F004E4F0A3F090F006E4F0A34B
:100BE000F0A3F0A3F090F00AE4F0020BED759D0D78
:100BF000AA9E74FC5A4404F59E439E10D2BA22C0A9
:100C00000AE581F50A2408F581AA82AB838A048B60
:100C1000057E008E078D068C057C00C002C0037423
:100C2000FAC0E0E4C0E0C0E0C0E08C828D838EF0CA
:100C3000EF12242BA80A08A68208A68308A6F008AB
:100C4000F6E58124FCF581D003D00290F004E0FCAD
:100C5000A3E0FD7E007F00A80A08E62CFC08E63D24
:100C6000FD08E63E08E63F90F004ECF0A3EDF074DA
:100C7000FAC0E0E4C0E08A828B8312212AAA82AB08
:100C8000831581158190F006E50A2405F8E0F6A3A6
:100C9000E008F6A3E008F6A3E008F6E4FCFDE50AA8
:100CA0002405F890F006EA26F0EB0836A3F0EC08ED
:100CB00036A3F0ED0836A3F0850A81D00A22AA8275
:100CC00090F006E0FBA3E0FCA3E0FDA3E0FE7F00C4
:100CD0007800790090F006EA2BF0EF3CA3F0E83DB5
:100CE000A3F0E93EA3F02290F006E0FAA3E0FBA314
:100CF000E0FCA3E08A828B838CF02290F00AE0FB78
:100D00007A00AC9C7D0074FFC39CFCE49DFDEC422A
:100D100002ED420390F004E0FCA3E0FDEC2AF58232
:100D2000ED3BF58322C00A85810AAA82AB83ACF031
:100D3000FDE50A24FAF8E6C39AFA08E69BFB08E602
:100D40009CFC08E69DFDC002C003C004C0059000E5
:100D5000FAE4F5F0122715AB83ACF0E58124FCF53D
:100D6000818B828C83D00A22AA82AB837C008C0583
:100D70008B048A037A0074FAC0E0E4C0E0C0E0C0EB
:100D8000E08A828B838CF0ED12242BAA82AB83E560
:100D90008124FCF581C002C003120CFBAC82AD8340
:100DA000D003D002C002C003C004C005120CFBAEC9
:100DB00082AF83D005D004D003D002EEC39CFEEFF7
:100DC0009DFFC3EA9EEB9F50DB22741855BEFA606C
:100DD0000ABA0802800EBA101D80129028D375F04E
:100DE000800220339028D775F0800220339028DBD2
:100DF00075F08002203322120B87120BA343FF08E9
:100E00001220049028DF75F08012203375822012A2
:100E100020279028E975F080122033758220122057
:100E200027120DCA9028F475F080122033120BD3CC
:100E3000120FA4D2AF121091121459121C4F121A91
:100E40009002053EC00AE581F50A2404F581120BE3
:100E5000A4121007121C5F121000E5826003020F3B
:100E600096121AA01209DD120CFBAA82AB838A0625
:100E70008B07A80A08A60608A607087600087600C9
:100E800090F206E0FAA3E0FB7C007D00C006C007FC
:100E9000A80A08E6C0E008E6C0E008E6C0E008E608
:100EA000C0E08A828B838CF0ED120D25AA82AB8381
:100EB000E58124FCF581D007D006C374E89A740359
:100EC0009B501690F206EEF0A3EFF0C006C007129A
:100ED0001C5E1209DED007D00690F208E0FAA3E00B
:100EE000FB7C007D00C006C007A80A08E6C0E00839
:100EF000E6C0E008E6C0E008E6C0E08A828B838CAA
:100F0000F0ED120D25AA82AB83E58124FCF581D09A
:100F100007D006C374649AE49B501690F208EEF072
:100F2000A3EFF0C006C007120A2312142BD007D07B
:100F30000690F20AE0FAA3E0FB7C007D00C006C048
:100F400007A80A08E6C0E008E6C0E008E6C0E00836
:100F5000E6C0E08A828B838CF0ED120D25AA82AB6D
:100F600083E58124FCF581D007D006C3740A9AE496
:100F70009B502390F20AEEF0A3EFF0120A2490F2B5
:100F80000CE0FA90F20C04F0BA190B90F20CE4F0B9
:100F9000758201120CBE850A81D00A22120DF71249
:100FA0000E4480FB907E00E493FABA4202802190C6
:100FB00028F775F08012203390555512141DC2A3E6
:100FC000900064120D68D2A3900064120D6880EE48
:100FD00090290A75F0801220337408C0E0907E02D8
:100FE00075F0801220E0158122AA8290F20FE4F0C1
:100FF00090F20DF090F00BEAF0BA0003021B902281
:1010000090F20FE0F5822290F00BE0FABA00012294
:10101000BA01028005BA026A804590F20FE0FA60D8
:101020002890DF3AE0F5821214D390DF39E0FA30ED
:10103000E70890F00D121BA1800990291275F0802D
:10104000122033758200120FE990F20DE0FA60323F
:1010500090291B75F080122033758200020FE990F1
:10106000F20FE0FA6006758200120FE990F20DE0CF
:10107000FA600F90292675F08012203375820002E5
:101080000FE922AA8290DF3BE0FBB502F8758201EE
:101090002290DF0074D3F090DF017491F090DF02B2
:1010A00074FFF090DF037404F090DF047405F09097
:1010B000DF05E4F090DF06F090DF07740CF090DFBE
:1010C00008E4F090DF097421F090DF0A7465F09075
:1010D000DF0B746AF090DF0C742DF090DF0D743B21
:1010E000F090DF0E7413F090DF0F7422F090DF1099
:1010F00074F8F090DF117462F090DF127407F090D2
:10110000DF137430F090DF147418F090DF15741D45
:10111000F090DF16741CF090DF1774C7F090DF18A2
:10112000E4F090DF1974B0F090DF1A74B6F090DF3D
:101130001B7410F090DF1C74EAF090DF1D742AF02D
:1011400090DF1EE4F090DF1F741FF090DF2374889F
:10115000F090DF247431F090DF257409F090DF27E0
:10116000E4F090DF28F090DF29F090DF2AF090DFA4
:101170002BE4F090DF2CF090DF2DF090DF2E7450F8
:10118000F090DF2FE4F090DF30F090DF31F090DF6F
:10119000367401F090DF377403F090DF38E4F0909C
:1011A000DF39F090DF3A7480F090DF3B7401F0900B
:1011B000DF3CE4F090DF3D7494F090DF05E4F075DF
:1011C000E900439A01D2A84391F175E104758201C7
:1011D000121083758200020FE975E1047582011215
:1011E0001083758200020FE9C0E0C0F0C082C083A6
:1011F000C002C003C004C005C006C0D075D000AA9C
:10120000D990DF3BE0FBBB134690F00DE0FB7C0088
:101210000BBB00010C90F210E0FD7E00C3ED9BEED5
:1012200064808CF063F08095F0501C90F210E0FB2D
:1012300090F210E02401F0EB240DF582E434F0F597
:1012400083E0F5D90212C690F20D7401F080779018
:10125000DF3BE0FBBB0D6F90F210E0FB602290F0F3
:101260000DE0FB7C000BBB00010C90F210E0FD7E5A
:1012700000C3ED9BEE64808CF063F08095F0502409
:1012800090F210E0FBBB4000501A90F210E0FB908F
:10129000F210E02401F0EB240DF582E434F0F58344
:1012A000EAF0802290F00DE0FA7B000ABA00010B10
:1012B00090F210E0FC7D00B50206EDB50302800659
:1012C00090F20D7401F0D0D0D006D005D004D00338
:1012D000D002D083D082D0F0D0E032C0E0C082C053
:1012E00083C002C003C004C005C0D075D000539BAA
:1012F000FCE5E930E43090F00DE0FA7B000ABA003A
:10130000010B90F210E0FC7D00B5020CEDB5030876
:1013100090F20F7401F0800690F20D7401F075E107
:101320000490F210E4F0E5E920E70AE5E920E6059B
:10133000E5E930E50E75E10490F210E4F090F20D6D
:101340007401F0E5E930E00590F210E4F075E90091
:10135000D0D0D005D004D003D002D083D082D0E04A
:101360003290F00BE0FA600ABA01307402B5E10283
:10137000802975E104758201121083758202120FB3
:10138000E990F210E4F090F20EF090F20FF090F28B
:101390000DF075E10375821302108390293175F009
:1013A0008002203390F00BE0FABA021690F20FE0C0
:1013B000FA700A90F20DE0FA7003FA80027A018A5C
:1013C00082227582012290F00B7401F075E10475A0
:1013D000820112108390F20DE4F090F210F090F27E
:1013E0000E7401F090F20FE4F075E10275820D02C7
:1013F0001083AA82AB83E0FC7D000CBC00010D7E53
:1014000000C004C005C002C003C00690F00D75F016
:1014100000122503E58124FBF581021361AA83E50F
:101420008290F211F0A3EAF002142B90F211E0FA8C
:10143000A3E0FB90F211EA33F0EB33A3F012242186
:10144000E092E0F090F211E0FAA3E0FBEA30E00372
:10145000C2A322D2A322C2EB3290F06EE4F090F04D
:101460005DF07410C0E0E4C0E0E4C0E090F04D75C1
:10147000F0001224981581158115817410C0E0E4E4
:10148000C0E0E4C0E090F05E75F000122498158191
:10149000158115817A00BA8000503775E10490DF1C
:1014A0003BE0FBBB01F875E10290DF3BE0FBBB0DCD
:1014B000F8900001C002120D6890DF3AE0F5821248
:1014C00014D3D00275E10490DF3BE0FBBB01F80AC6
:1014D00080C422AA8290F05DE0FB244DFCE434F04D
:1014E000FD8C828D83E062028C828D83EAF0EB04B6
:1014F00090F05D540FF02290F06EE01490F06EF0DA
:10150000245EF582E434F0F583E0F58222C00A859A
:10151000810AAA82AB83ACF0E50A24FDF886058D2A
:10152000061DEE6026C002C003C004C0051214F7F9
:10153000AE82D005D004D003D0028A828B838CF097
:10154000EE12226FA3AA82AB8380D4D00A2290F03D
:101550006FE4F07401C0E0E4C0E090F06F121D028F
:101560001581158122C00A85810AAA82E50A24FA1A
:10157000F886820886830886F0C002122613AB82A2
:10158000E50A24F7F886820886830886F0C00312ED
:101590002613AC82D003D00274042B2C90F06FF091
:1015A00090F070EAF090F071E50A24FDF8E6F07A28
:1015B0000074012BFDE43AFEC002C003C004C00564
:1015C000C006E50A24FAF8E6C0E008E6C0E008E64E
:1015D000C0E090F07275F000122503E58124FBF560
:1015E00081D004D003D0027D000CBC00010D740436
:1015F0002BFBE43AFAEB246FFBEA34F0FA7E00C0EE
:1016000004C005E50A24F7F8E6C0E008E6C0E008F3
:10161000E6C0E08B828A838EF0122503E58124FBED
:10162000F581D00A22C00A85810AAA82AB83ACF078
:10163000E50A24FBF8E6C0E008E6C0E008E6C0E002
:10164000C002C003C004E50A24FAF8E6C0E07582CF
:1016500002121565E58124F9F5817401C0E0E4C04A
:10166000E090F06F121D0215811581D00A22C00A88
:1016700085810AAA82AB83ACF0743FC0E07429C0B4
:10168000E07480C0E0C002C003C004E50A24FDF895
:10169000E6C0E0758200121565E58124F9F58174D4
:1016A00001C0E0E4C0E090F06F121D0215811581C9
:1016B000D00A22C00A85810AAA82AB83ACF0743FAB
:1016C000C0E07429C0E07480C0E0C002C003C00460
:1016D000E50A24FDF8E6C0E0758204121565E5818F
:1016E00024F9F5817401C0E0E4C0E090F06F121DB0
:1016F0000215811581D00A22C00A85810AAA82AB0F
:1017000083ACF0743FC0E07429C0E07480C0E0C0D6
:1017100002C003C004E50A24FDF8E6C0E0758206B5
:10172000121565E58124F9F5817401C0E0E4C0E09B
:1017300090F06F121D0215811581D00A22C00A8512
:10174000810AC082C083E5812406F581A80A088643
:10175000040886057E00BC0009BD0006BE00030229
:1017600018B5A80A088682088683E0FCBC040050ED
:10177000030218B5A80A088682088683A3E0FDE55F
:101780000A2403F8A605A80A088682088683A3A36C
:10179000E0FEE50A2404F8A606A80A08E50A2405DE
:1017A000F9740326F7E4083609F7E50A2405F886F4
:1017B000050886068D828E83E060218C077A000FF3
:1017C000BF00010AA80A08EF26FFEA0836FAC3EDAF
:1017D0009FEE9A50070DBD00DB0E80D88D028E0360
:1017E0008D828E83E0700774012DFAE43EFBE50ADA
:1017F0002403F8B601028021E50A2403F8B60302A7
:101800008039E50A2403F8B605028042E50A24037C
:10181000F8B6070280790218A2E50A2404F8E6C0A7
:10182000E0C002C003E50A2405F886820886831218
:101830000A251581158115810218B5E50A2404F8D9
:10184000E6C0E08A828B83120A9415818067E50ADC
:101850002405F88682088683E07013E50A2404F8DC
:10186000E6C0E08A828B83120AE515818047E50A8B
:101870002404F8E6C0E0C002C003E50A2405F886A7
:1018800082088683120A251581158115818026E537
:101890000A2404F8E6C0E08A828B83120B36158195
:1018A000801390294075F080122033E50A2403F854
:1018B0008682122071850A81D00A2202053D021E0D
:1018C00055C00A85810AC082C083C0F0C0E0E581AE
:1018D0002409F581E50A2405F8E4F608F6740AC03F
:1018E000E0E4C0E0C0E0C0E0A80A08868208868381
:1018F0000886F008E61223CBAA82AB83ACF0FDE5A4
:101900008124FCF581EA4B4C4D6033E50A24FBF859
:10191000E6C0E008E6C0E008E6C0E08A828B838C7F
:10192000F0ED1218C1AA82AB83ACF0FD15811581D0
:101930001581E50A2405F8A60208A603802CA80A4A
:1019400008080808E630E722E50A2405F8760108C9
:101950007600E50A24FBF886020886030886048AD6
:10196000828B838CF0742D12226FE50A2405F88691
:1019700002088603E50A2405F806B600020806E513
:101980000A24FBF8E50A2407F9EA26F7EB083609EA
:10199000F70809E6F7740AC0E0E4C0E0C0E0C0E080
:1019A000A80A0886820886830886F008E61223774C
:1019B000AD82AE83E58124FCF5818D828E83122277
:1019C00088AA8274302AFAE50A2407F886820886F3
:1019D000830886F0EA12226FE50A24FBF8E50A2460
:1019E00005F9E726FA09E70836FB0886048A828BA0
:1019F000838CF0E412226FE50A2405F88606088637
:101A000007E63395E0FA8E828F838AF0850A81D0CB
:101A10000A22C00AE581F50A2418F581A80A087689
:101A2000B00876F008760018187A017BB07CF0BA1E
:101A3000080050368B828C83E0FDFE602DBE202393
:101A40008B828C83E4F08A050AED75F003A428F9F3
:101A500074012BFDE43CFE7F00A70509A70609A73A
:101A60000719190BBB00C80C80C588037C007D409A
:101A7000C003C004C0058A8212081715811581159C
:101A800081850A81D00A2290294975F0800220338D
:101A900090F131E4F090F0AFF090F0B0F0021A87DE
:101AA000C00A85810A0581AA0A0A7B007C408A82D5
:101AB0008B838CF0121FB8E5827003021B8A90F1B1
:101AC00031E0FA6003021B8AA80A088602BA0802FB
:101AD0008020BA0A02800ABA0D028005BA7F3F80D0
:101AE0001190F1317401F090294C75F0801220337F
:101AF000807090F0AFE0FB6069EB1490F0AFF024E1
:101B0000B0F582E434F0F583E4F075820812202702
:101B1000758220122027758208122027804490F0B9
:101B2000AFE0FBBB800050348A8212202790F0AFD8
:101B3000E0FA90F0AF04F0EA24B0FAE434F0FBA845
:101B40000A0886048A828B83ECF090F0AFE0FA24D6
:101B5000B0F582E434F0F583E4F080067582071274
:101B6000202790F131E0FA7003021AA790F0AFE05D
:101B7000FA6003121A1290F0AFE4F090F0B0F01295
:101B80001A8790F131E4F0021AA7850A81D00A225F
:101B900090F132E0FA6009900002120D680213C65B
:101BA00022AA82AB83E0FCBC0B0050012274022A03
:101BB000FCE43BFD7E00C002C0037408C0E0E4C04A
:101BC000E07402C0E0747EC0E07480C0E08C828D5E
:101BD000838EF01222BBAC82AD83E58124FBF581BC
:101BE000D003D002BC0067BD0064740A2AF582E409
:101BF0003BF583E0FC90F175E0FD90F17504F0ECAD
:101C0000B50502800990294F75F0800220338A8241
:101C10008B83A3E0FC530401740B2AFAE43BFBC062
:101C2000048A828B8312173D1581AA08AB097C00B8
:101C3000BA0008BB0005BC0002800E850882850939
:101C4000831218BBE4F508F50990F132E4F022E4C0
:101C5000F508F50990F132E4F090F175F02222C018
:101C60000AE581F50A2404F581AA08AB097C00BACB
:101C70000009BB0006BC0003021CFC120CFBAA827C
:101C8000AB83A80A08A60208A60308760008760017
:101C900090F133E0FEA3E0FF7A007B00A80A08E69B
:101CA000C0E008E6C0E008E6C0E008E6C0E08E82DA
:101CB0008F838AF0EB120D25AA82AB83E58124FC89
:101CC000F581C374059AE49B5032AA08AB09E4F588
:101CD00008F50990F132E4F0C002C0031211D99066
:101CE000F175E02401F0E4C0E090000012173D150A
:101CF00081D003D0028A828B831218BB850A81D0DF
:101D00000A22C00A85810AC082C083E50A24FDF840
:101D1000E660047C0180027C00E50A24FCF8E660B1
:101D2000047D0480027D00ED420490F136ECF074F5
:101D300008C0E0E4C0E07402C0E0747EC0E07480DB
:101D4000C0E090F13775F000122503E58124FBF522
:101D500081E50A24FCF8E6605090F175E090F13FCF
:101D6000F0A80A088682088683E0FC7D000CBC008F
:101D7000010DA80A0886060886077A00C004C00577
:101D8000C006C007C00290F14075F000122503E5BF
:101D90008124FBF581A80A088682088683E0FA740C
:101DA0000B2AFA90F135F08046A80A088682088648
:101DB00083E0FA7B000ABA00010BA80A088604082F
:101DC00086057E00C002C003C004C005C00690F1B5
:101DD0003F75F000122503E58124FBF581A80A0870
:101DE0008682088683E0FA740A2AFA90F135F09028
:101DF000F1351213F21213A4E58260F9E50A24FC0E
:101E0000F8E6602DA80A08860808860990F1327461
:101E100001F0120CFBE5828583F090F133F0A3E52D
:101E2000F0F090F132E0FA601D121007121C5F8092
:101E3000F1E4F508F50990F132E4F0A80A08868289
:101E40000886831218BB850A81D00A22C2C753A113
:101E5000FE53BEFC32AA82E5D5E5D4BA0001227554
:101E6000A20475A2018A037C00C002C003C00490D2
:101E7000010F122299AB82AC8315811581D0028C9F
:101E8000A4EA75F00FA4F5A3C2C753A1FE43A110A5
:101E9000D2AD53BEFBE5BE30E5FBABC674F85B4488
:101EA00041F5C6E5C630E6FB43BE0443D6817B76EA
:101EB0007CF18C0390F17DEBF07B767CF190F17EF0
:101EC000EBF07B7D7CF18CD57B7D7CF18BD475D662
:101ED00001ABA5EBB5A50280FA43A20443C7027586
:101EE000BE06000000E5BE54037003021EF675D75F
:101EF00001004387010053C7FD53A1EFC002120B3D
:101F000087120BED7B00C0039000FA122299AA827F
:101F1000AB83158115818A828B83020BFFC020C0A1
:101F2000E0C0F0C082C083C002C003C004C005C0CE
:101F300006C007C000C001C0D075D000C28B90F2AF
:101F400005E0FA7B00747E2AF582E43BF583747F1A
:101F5000C0E0E4C0E01226D8AA82AB8315811581C7
:101F600090F204E0FCFD7E00EDB50206EEB5030242
:101F70008029EC2485F582E434F1F583E5C1F08D08
:101F8000828E83A3747FC0E0E4C0E01226D8AA82C8
:101F9000AB831581158190F204EAF0D0D0D001D046
:101FA00000D007D006D005D004D003D002D083D013
:101FB00082D0F0D0E0D02032AA82AB83ACF090F295
:101FC00004E0FD90F205E0FEEDB506047582002206
:101FD000EE2485F582E434F1F583E08A828B838CEC
:101FE000F012226F7A008E828A83A3747FC0E0E4AD
:101FF000C0E01226D8AA821581158190F205EAF078
:102000007582012290F205E4F090F204F0AAF174D6
:10201000FE5A4402F5F143F30C7586C075C2227571
:10202000C50DC28BD2AA228582C1E58630E1FB5361
:1020300086FD22AA82AB83ACF08A828B838CF0125D
:1020400026BCFD60180ABA00010B8D82C002C003D5
:10205000C004122027D004D003D00280DC22AA8240
:10206000BA0A00500674302AF5822274372AF582A3
:1020700022AA8274F05AC4540FF582C00212205E64
:10208000122027D002740F5AF58212205E022027F8
:10209000C00A85810AC082C083C0F0C0E0E5812407
:1020A00011F581E50A2405FEFF7A007B40C006C0D9
:1020B00007C002C003A80A0886820886830886F043
:1020C00008E61218C1158115811581D0067A007BAA
:1020D000408E828A838BF0122033850A81D00A22B7
:1020E000C00A85810AAA82AB83ACF0E50A24FDF818
:1020F00086058D061DEE60268A828B838CF0122663
:10210000BCFEA3AA82AB838E82C002C003C004C0FF
:1021100005122071D005D004D003D00280D49029BC
:102120005E75F080122033D00A22E58124FEF8E6A5
:10213000F918E6F87A10E4FBFCE58225E0F582E583
:102140008333F583EB33FBEC33FCEB98F5F0EC9940
:102150004006FCABF0438201DADF22C00A85810A27
:10216000C082C083C0F00581058105817D007E00AD
:10217000A80A0886070886020886038F828A838B4E
:10218000F01226BCFC602EC374B98CF063F080950D
:10219000F04007EC648094B0501B8F828A838BF0F0
:1021A0001226BCFCBC2D02800CBC2B0280070FBF8A
:1021B00000C90A80C6A80A08A60708A60208A6033E
:1021C0008F828A838BF01226BCFAE4BA2D0104FBBD
:1021D000FC7003BA2B09A80A0806B600020806A874
:1021E0000A08E50A2404F9E6F70809E6F70809E60B
:1021F000F7E50A2404F886820886830886F012260A
:10220000BCFB6051C3EB648094B0404974B98BF05F
:1022100063F08095F0403EC004C003C005C0069046
:10222000000A122299AC82AA8315811581D003EB92
:102230003395E0FFEB24D0FBEF34FFFFEB2CFCEFFA
:102240003AFA8C058A06E50A2404F806B600020864
:1022500006D004809CEC6009C3E49DFAE49EFB80F8
:10226000048D028E038A828B83850A81D00A222004
:10227000F71030F6118883A88220F507F6A8837539
:10228000830022F280F7F022E58330E70BC3E49568
:1022900082F582E49583F5832274FE2581F8E68534
:1022A00082F0A4C0E08582F018E6A4F582D0E02593
:1022B000F0C58386F0A42583F58322C00A85810AB0
:1022C000C082C083C0F0E50A24F9F8E6084670062B
:1022D000900000022371E50A24F9F88605088606B5
:1022E0001DBDFF011EED4E6055C005C006A80A08C1
:1022F00086820886830886F01226BCFFE50A24FB46
:10230000F886020886030886048A828B838CF01282
:1023100026BCFDEFB505028006D006D005801FD093
:1023200006D005A80A0806B600020806E50A24FB3E
:10233000F874012AF6E43B08F608A60480A2A80A6D
:102340000886820886830886F01226BCFA7B00E5A0
:102350000A24FBF886040886050886068C828D838D
:102360008EF01226BCFC7D00EAC39CF582EB9DF545
:1023700083850A81D00A22F9C2D530E715D2D5E487
:10238000C39582F582E49583F583E495F0F5F0E456
:1023900099F9E58124FBF88602088603088604087B
:1023A000E6FD30E70DE4C39AFAE49BFBE49CFCE411
:1023B0009DFD1225B230D512E4C39582F582E495D5
:1023C00083F583E495F0F5F0E49922FBC2D530E77C
:1023D00015D2D5E4C39582F582E49583F583E4951F
:1023E000F0F5F0E49BFBE58124FEF8E630E715B25A
:1023F000D5181818E4C396F6E40896F6E40896F69D
:10240000E40896F618181812243130D513FBE4C3EB
:102410009582F582E49583F583E495F0F5F0E49BED
:1024200022C5827002158314C58222FBE58124FB3C
:10243000F8E6F9087A20E4FCFDFEFFE5822582F546
:1024400082E58333F583E5F033F5F0EB33FB40179A
:10245000DAE98042E5822582F582E58333F583E57A
:10246000F033F5F0EB33FBEC33FCED33FDEE33FEF4
:10247000EF33FFEC99ED96EE0896EF0896181840AA
:1024800013EC99FCED96FDEE0896FEEF0896FF180A
:1024900018438201DABEEB22C00A85810AC082C0DD
:1024A00083C0F0058105810581A80A08E50A240496
:1024B000F9E6F70809E6F70809E6F7E50A24FBF864
:1024C00086020886038A048B051ABAFF011BEC4DAD
:1024D0006020E50A2404F886820886830886F0E5F1
:1024E0000A24FDF9E712226FA31818A68208A68312
:1024F00080D3A80A0886820886830886F0850A8128
:10250000D00A22C00AE581F50A2409F581AA82AB26
:1025100083ACF0A80A08A60208A60308A604E50AE8
:1025200024FBF88605088606088607E50A2407F8CE
:10253000A60508A60608A607E50A2404F8A60208C8
:10254000A60308A604E50A24F9F886050886068D80
:10255000078E021DBDFF011EEF4A6034E50A240705
:10256000F886820886830886F01226BCFAA318181B
:10257000A68208A683E50A2404F8868208868308D2
:1025800086F0EA12226FA31818A68208A68380BFDD
:10259000A80A0886820886830886F0850A81D00A00
:1025A00022F9E58124FBF8860208860308860408E0
:1025B00086057800EA4B4C4D60587800C308ED2042
:1025C000E727EA25E0FAEB33FBEC33FCED33FDE5DE
:1025D000829AE5839BE5F09CE99D50E1C3ED13FDF4
:1025E000EC13FCEB13FBEA13FAE5829AE5839BFEFE
:1025F000E5F09CFFE99D400AF98FF08E83E5829A11
:10260000F582C3ED13FDEC13FCEB13FBEA13FAD8D0
:10261000D8E922AA82AB831226BC6003A380F8C348
:10262000E5829AF582E5839BF58322C00AE581F570
:102630000A2405F581AA82AB83ACF0A80A08A60299
:1026400008A60308A604E50A24FBF8860508860602
:10265000088607A80A0886820886830886F012265C
:10266000BCFA7B008D828E838FF01226BCFCC005E5
:10267000C006C0077D00EAC39CFAEB9DFBE50A2477
:1026800004F8A60208A603D007D006D005EA4B70CE
:102690001B8D828E838FF01226BC6010A80A08065C
:1026A000B6000208060DBD00AA0E80A7E50A2404A4
:1026B000F88682088683850A81D00A2220F71430A2
:1026C000F6148883A88220F507E6A8837583002284
:1026D000E280F7E49322E022C2D5E58330E70DD211
:1026E000D5E4C39582F582E49583F583E58124FEE4
:1026F000F8E630E70918E4C396F6E40896F6860192
:1027000018860012278F30D50BE4C39582F582E43A
:102710009583F58322AAF0FB74FB2581F8E5828678
:10272000F0A9F008A4FCADF0E58389F0A42DFDE448
:1027300035F0FEE58286F0A42DFDE5F03EFEE433A3
:10274000FFEA89F0A42EFEE5F03FFFE58386F0A4C2
:102750002EFEE5F03FFFE5820886F0A42EFEE5F0B0
:102760003FFFEB89F0A42FFFE58386F0A42FFFEA5B
:102770001886F0A42FFFE582080886F0A42F8EF0BB
:102780008D838C8222E58124FEF88601188600E87C
:102790004960367A01E825E0F8E933400EF9E58230
:1027A00098E5839940030A80ECC3E913F9E813F82C
:1027B000C3E58298F5F0E583994005F58385F082BD
:1027C000C3E913F9E813F8DAE72275820022776F7C
:1027D0006B650D0A005928805D28805105692880A5
:1027E0006D2880CC057F288083288088068F2880EC
:1027F0009528800307A12880A628807E07A7288027
:10280000B028808907BE2880C42880D40700000033
:10281000000000000068656C70000D0A00494E461B
:1028200020003D00207365713D0050555441434BDD
:10283000207374617475733D0053554241434B20BE
:102840007374617475733D00554E53554241434B4B
:10285000207374617475733D00676574003C6B652B
:10286000793E205B7365715D00707574003C6B652B
:10287000793E203C76616C3E205B7365715D007330
:102880007562003C6B65793E205B7365715D007518
:102890006E737562003C6B65793E205B7365715D9C
:1028A00000706F6C6C00006175746F706F6C6C0001
:1028B0003C706572696F6420696E20533E00736CD2
:1028C000656570003C717561727465722D73656326
:1028D000733E00424F440045585400574454007022
:1028E000626E6F646561707000313437343A313430
:1028F00037384D000D0A0050414E49433A206E6F63
:1029000020636F6E6669670D0A0045554936343A93
:1029100020004261644352430D0A00525820657200
:10292000726F720D0A005458206572726F720D0A30
:1029300000726164696F2062757379210D0A00006D
:10294000626164636D642120003E20000D0A004234
:10295000616420706F6C6C207365710D0A000D0A44
:102960000000000000000000000000000000FFFF69
:107E000042FF0000000000000003FFFFFFFFFFFF34
:107E1000843B9EBEEF57247F93D91F0E12095D2B22
:107E200051C6972585D79EC8AE8300E96AB52DA6B1
:107E30007731772E686F6467657069672E6F726738
:107E400000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41
:107F3000D4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C
:00000001FF