From 4ee6ff78d0849897951c4890be7e42947ffe86ab Mon Sep 17 00:00:00 2001 From: Joby Taffey Date: Thu, 8 Mar 2012 21:52:00 +0000 Subject: [PATCH] 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 --- README.markdown | 13 +- cctl-prog.exe | Bin 0 -> 65895 bytes cctl-prog/Makefile | 2 + cctl-prog/Makefile.mingw32 | 12 + cctl-prog/byteswap.h | 165 +++++++++ cctl-prog/cctl-prog.c | 719 +++++++++++++++++++++++++++++++++---- cctl-prog/hex.c | 9 +- cctl-prog/tmp.hex | 606 +++++++++++++++++++++++++++++++ 8 files changed, 1451 insertions(+), 75 deletions(-) create mode 100755 cctl-prog.exe create mode 100644 cctl-prog/Makefile.mingw32 create mode 100644 cctl-prog/byteswap.h create mode 100644 cctl-prog/tmp.hex diff --git a/README.markdown b/README.markdown index be3073c..7835ec8 100644 --- a/README.markdown +++ b/README.markdown @@ -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. diff --git a/cctl-prog.exe b/cctl-prog.exe new file mode 100755 index 0000000000000000000000000000000000000000..5482ed720e0b10cf2b7716f96fa8c1aefa9ceaa4 GIT binary patch literal 65895 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ⅅ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 literal 0 HcmV?d00001 diff --git a/cctl-prog/Makefile b/cctl-prog/Makefile index 0ad51c0..1d6e77d 100644 --- a/cctl-prog/Makefile +++ b/cctl-prog/Makefile @@ -1,3 +1,5 @@ +# Makefile for Linux and OSX/Darwin + CFLAGS=-Wall TARGET=cctl-prog diff --git a/cctl-prog/Makefile.mingw32 b/cctl-prog/Makefile.mingw32 new file mode 100644 index 0000000..51c7343 --- /dev/null +++ b/cctl-prog/Makefile.mingw32 @@ -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 + diff --git a/cctl-prog/byteswap.h b/cctl-prog/byteswap.h new file mode 100644 index 0000000..13cb9b2 --- /dev/null +++ b/cctl-prog/byteswap.h @@ -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 + +/* 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 diff --git a/cctl-prog/cctl-prog.c b/cctl-prog/cctl-prog.c index 717b9c6..401098f 100644 --- a/cctl-prog/cctl-prog.c +++ b/cctl-prog/cctl-prog.c @@ -4,24 +4,176 @@ #include #include #include -#include -#include #include #include +#include +#include + +#define SERIAL_TIMEOUT 2 + +#ifndef WIN32 +#include +#include +#else +#include +#include +#include +#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 \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 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 #include #include + +#ifndef WIN32 #include +#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; } diff --git a/cctl-prog/tmp.hex b/cctl-prog/tmp.hex new file mode 100644 index 0000000..4254a60 --- /dev/null +++ b/cctl-prog/tmp.hex @@ -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