]> rtime.felk.cvut.cz Git - sysless.git/blob - arch/arm/mach-lpc17cmsis/tools/lpc21isp/lpc21isp.c
Added flash loading tool lpc21isp for LPC17xx
[sysless.git] / arch / arm / mach-lpc17cmsis / tools / lpc21isp / lpc21isp.c
1 /******************************************************************************
2
3 Project:           Portable command line ISP for Philips LPC17XX / LPC2000 family
4                    and Analog Devices ADUC70xx
5
6 Filename:          lpc21isp.c
7
8 Compiler:          Microsoft VC 6/7, Microsoft VS2008, GCC Cygwin, GCC Linux, GCC ARM ELF
9
10 Author:            Martin Maurer (Martin.Maurer@clibb.de)
11
12 Copyright:         (c) Martin Maurer 2003-2010, All rights reserved
13 Portions Copyright (c) by Aeolus Development 2004 http://www.aeolusdevelopment.com
14
15     This file is part of lpc21isp.
16
17     lpc21isp is free software: you can redistribute it and/or modify
18     it under the terms of the GNU Lesser General Public License as published by
19     the Free Software Foundation, either version 3 of the License, or
20     any later version.
21
22     lpc21isp is distributed in the hope that it will be useful,
23     but WITHOUT ANY WARRANTY; without even the implied warranty of
24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25     GNU Lesser General Public License for more details.
26
27     You should have received a copy of the GNU Lesser General Public License
28     and GNU General Public License along with lpc21isp.
29     If not, see <http://www.gnu.org/licenses/>.
30 */
31
32 #if defined(_WIN32)
33 #if !defined __BORLANDC__
34 #include "StdAfx.h"        // Precompiled Header for WIN32
35 #endif
36 #endif // defined(_WIN32)
37 #include "lpc21isp.h"   // if using propriatory serial port communication (customize attached lpc21isp.h)
38 #include "adprog.h"
39 #include "lpcprog.h"
40 #include "lpcterm.h"
41
42 /*
43 Change-History:
44
45 1.00  2004-01-08  Initial Version, tested for MSVC6/7 and GCC under Cygwin
46 1.01  2004-01-10  Porting to Linux (at least compiling must work)
47 1.02  2004-01-10  Implemented conversion intel hex format -> binary
48 1.03  2004-01-25  Preparation to upload to public website
49 1.04  2004-02-12  Merged in bugfixes by Soeren Gust
50 1.05  2004-03-14  Implement printing of error codes as text / strings
51 1.06  2004-03-09  Merged in bugfixes by Charles Manning:
52                   The '?' sychronisation does not reliably respond to the first '?'.
53                   I added some retries.
54                   The LPC2106 sometimes responds to the '?' by echoing them back.
55                   This sometimes causes an attempt to match "?Synchonized".
56                   Added code to strip off any leading '?'s.
57                   Timeouts were too long.
58                   Change from RTS/CTS to no flow control.
59                   Done because many/most people will use only 3-wire comms.
60                   Added some progress tracing.
61 1.07  2004-03-14  Implement handling of control lines for easier booting
62 1.08  2004-04-01  Bugfix for upload problem
63 1.09  2004-04-03  Redesign of upload routine
64                   Now always 180 byte blocks are uploaded, to prevent
65                   small junks in uuencoding
66 1.10  2004-04-03  Clear buffers before sending commands to LPC21xx,
67                   this prevents synchronizing errors when previously loaded
68                   program does a lot of output, so FIFO of PC runs full
69 1.11  2004-04-03  Small optimization for controlling reset line
70                   otherwise termonly starts LPC twice, free PC buffers
71 1.12  2004-04-04  Add switch to enable logging terminal output to lpc21isp.log
72 1.13  2004-05-19  Merged in improvement by Charles Manning:
73                   Instead of exiting the wrong hex file size is corrected
74 1.14  2004-07-07  Merged in improvement by Alex Holden:
75                   Remove little/big endian dependancy
76 1.15  2004-09-27  Temporary improvement by Cyril Holweck:
77                   Removed test (data echoed = data transmited) on the main
78                   data transfert, since this was the biggest failure
79                   reason and is covered by checksome anyway.
80                   Added COMPILE_FOR_LPC21, to have target dump it's own
81                   memory to stdout.
82 1.16  2004-10-09  Merged in bugfix / improvement by Sinelnikov Evgeny
83                   I found out that Linux and Windows serial port initialization
84                   are different with pinouts states. My board don't get
85                   reset signal at first cycle of DTR pinout moving.
86                   And I add this moving to initalization cycle.
87 1.17  2004-10-21  Changes by Cyril Holweck
88                   Divide main, take out the real programming function, that can
89                   also be used by a target to copy its own code to another.
90 1.18  2004-10-26  Changes by Cyril Holweck
91                   Added a "G 0 A\r\n" at end of programming to run code.
92 1.19  2004-11-03  Changes by Robert Adsett
93                   Add support for Analog Devices.
94                   Separate file load from programming.
95                   Change from a debug on/off flag to debug level
96                   Remove if (debug) tests and replace with DebugPrintf
97                   statements.
98                   Change serial I/O and timing so that the system
99                   dependancies are isolated to a few portability functions.
100                   Add support for binary serial I/O.
101                   Add doxygen support.
102 1.20  2004-11-07  Preparation for multiport booting (factory support)
103 1.21  2004-11-08  Bugfix from Robert Adsett
104                   BinaryLength was not initialized
105 1.22  2004-11-08  Changes from Cyril Holweck / Evgeny Sinelnikov
106                   Forgotten IspEnvironment-> and bugfixes if COMPILE_FOR_LINUX
107                   If COMPILE_FOR_LPC21, PhilipsDownload() 'acts as' main():
108                   - it should not be static and should return int.
109                   - no sub-function can use exit() but only return ()
110                   Use 'char' instead of 'byte' ;)
111 1.23  2005-01-16  Build in automatic detection of LPC chiptype
112                   (needed for 256 KByte support)
113 1.24B 2005-06-02  Changes by Thiadmer Riemersma: completed support for other
114                   chip types (LPC213x series and others).
115 1.24C 2005-06-11  Changes by Thiadmer Riemersma: added the device ID codes for
116                   chip types LPC2131 and LPC2132.
117 1.25  2005-06-19  Martin Maurer: Setup more parameters in DCB,
118                   otherwise wrong code is downloaded (only Windows and Cygwin)
119                   when a previous program has changed these parameters
120                   Check exact string of "G 0 A\r\n0\r\n" instead of whole received buffer,
121                   to prevent checking of already received by program start
122                   (error on running program, but reports CMD_SUCCESS)
123                   Add ifdefs for all baudrates (needed only for high baudrate,
124                   which seem to be not available on Macs...)
125 1.26  2005-06-26  Martin Maurer:
126                   Correct check again: "G 0 A\r\n0\r\n" is cutted, because of reboot
127                   (error on running program, but reports CMD_SUCCESS)
128 1.27  2005-06-29  Martin Maurer:
129                   Add LPC chip ID's (thanks to Robert from Philips) for
130                   missing LPC213x and upcoming new LPC214x chips
131                   (currently untested, because i don't have access to these chips,
132                   please give me feedback !)
133 1.28  2005-07-27  Anders Rosvall / Embedded Artists AB:
134                   Changed the reset timeout to 500 ms when entering the bootloader.
135                   Some external reset controllers have quite long timeout periods,
136                   so extening the timeout delay would be a good thing.
137 1.29  2005-09-14  Rob Jansen:
138                   Added functionality to download to RAM and run from there.
139                   In LoadFile() added record types 04 (Extended Linear Address Record)
140                   and 05 (Start Linear Address Record), added address offset
141                   (IspEnvironment->BinaryOffset) and start address (...->StartAddress).
142                   Changed PhilipsDownload to skip all Flash prepare/erase/copy commands.
143                   Note: Tested with VC7 only
144 1.30   2005-10-04 Rob Jansen:
145                   - forgot to change the version string in 1.29
146                   - Wrong text in LoadFile corrected (printed text mentions record type 05,
147                     this should be 04
148                   - Changed LoadFile to accept multiple record types 04
149                   - Changed LoadFile to check on memory size, will not load more than x MB
150                     if linear extended address records are used
151 1.31   2005-11-13 Martin Maurer: Thanks to Frank Gutmann
152                   Updated number of sectors in device table
153                   for LPC2194, LPC2292 and LPC2294
154 1.32   2005-12-02 Martin Maurer: Corrected missing control of RTS/DTR
155                   in case user selected -termonly and -control
156                   Small correction (typo in debug)
157 1.33   2006-10-01 Jean-Marc Koller:
158                   Added support for MacOS X (difference on how to set termios baudrate).
159 1.34   2006-10-01  Cyril Holweck:
160                   Made it compile again for lpc21isp
161                   Added const keyword to constant variables to make it better
162                   code for embeded target. (decrease RAM usage)
163                   Replaced all regular call to printf() by DebugPrintf()
164                   Removed call to scanf() (not much usefull and cost a lot to my target)
165 1.35   2006-22-01 Cyril Holweck
166                   Added feature for LPC21: will start downloading at Sector 1 and upward,
167                   to finish with Sector 0, the one containing the checksum controling BSL entry
168 1.36   2006-25-01 Cyril Holweck
169                   PhilipsDownload() will now return a unique error code for each error
170 1.37   2006-10-03 Jeroen Domburg
171                   Added LPC2103 (and only the 2103, I can't find the IDs for 2101/2102)
172                   Corrected a loop which occured if the program completely fits in sector 0
173 1.38   2007-01-05 Ray Molenkamp
174                   Added feature for LPC21: Wipe entire device before programming to enable
175                   reflashing of chips with the lpc codeprotection feature enabled.
176 1.39   2007-01-12 Martin Maurer
177                   Added initial support for new processors LPC23xx and LPC24xx
178 1.40   2007-01-22 Martin Maurer
179                   Correction of chip id of LPC2458
180 1.41   2007-01-28 Jean-Marc Koller
181                   Modified Terminal() to disable ECHO with termios only once, instead of
182                   modifying and restoring termios in each getch and kbhit call (which caused
183                   a strange echo behaviour in MacOS X).
184 1.42   2007-01-28 Rob Probin
185                   Added -localecho command to allow local echoing in terminal mode for use
186                   where target does not echo back keystrokes.
187 1.43   2007-01-29 Martin Maurer
188                   Moved keyboard handling routines to own subroutines,
189                   so they can be used during aborting synchronisation.
190                   Newest cygwin made problems, StringOscillator always contained '\0x0d'
191                   at the end, when calling lpc21isp from batch file
192 1.44   2007-02-23 Yang Yang
193                   Added feature for LPC21: Verify the data in Flash after every writes
194                   to sector. To detect errors in writing to Flash ROM.
195 1.45   2007-02-25 Martin Maurer
196                   Replace printf syntax of DumpString by a simple pointer to a string
197                   printf syntax is a nice thing, but it is not working :-(
198                   and therefore makes debugging much more difficult...
199                   Moved VERSION_STR to top of file to avoid possible cosmetical errors
200 1.46   2007-02-25 Martin Maurer
201                   Again corrected debug output: should solve output of
202                   (FFFFFFB5) instead of (B5)
203 1.47   2007-02-27 Robert Adsett
204                   Raised timeout on AD send packet function.
205 1.48   2007-04-20 Martin Maurer
206                   Thanks to Josef Wolf for preventing to overwrite over end of array
207 1.49   2007-10-16 New Option -halfduplex allow single wire using.
208                   Implemented and tested only for Windows. Data Resend implemented.
209 1.50   2007-10-31 Changes by Simon Ellwood
210                   Formated the code for readablity
211                   Fixed some c++ compiler issues
212 1.51   2007-11-20 Changes by Simon Ellwood
213                   Split into seperate files
214                   Made more modular so when used in an embedded mode only the required code is built
215 1.52   2008-01-22 Changes by Manuel Koeppen
216                   Made compileable again for linux and windows
217                   Fixed bug in ClearSerialPortBuffers (linux)
218 1.53   2008-02-25 Changes by Michael Roth
219                   Get priority of debug messages wih -control right
220 1.54   2008-03-03 Martin Maurer
221                   Try to bring lpc21isp back to a useable state in Windows, Cygwin, Linux and Mac OS.
222                   Merged in changes by Erika Stefanini, which were done only for old version 1.49:
223                   Added device ids for revision B chips
224 1.55   2008-03-03 Martin Maurer
225                   Thanks to Fausto Marzoli, bugfix for compiling latest version under Linux
226 1.56   2008-04-01 Steve Franks
227                   Integrate FreeBSD patch.
228                   Add support for swapping and/or inverting RTS & DTR
229 1.57   2008-04-06 Mauricio Scaff
230                   Changed OpenSerialPort to work with MacOS
231                   Corrected the number of sectors in some 512K devices (28 instead of 27)
232                   Added support for LPC2387 and LPC2388
233                   Defined BL error 19 (Code Protected)
234 1.58   2008-05-10 Herbert Demmel dh2@demmel.com
235                   I had the special requirement to integrate the program into my own Windows
236                   software compiled with Borland C++ Builder 5. I had to do some minor changes
237                   for Borland (see defined __BORLANDC__) and modified to code slightly to have
238                   some simple callbacks for screen i/o (see define INTEGRATED_IN_WIN_APP).
239                   Please notet that I don *not* check / modify the part for AnalogDevices !!
240                   Besides that I fixed some minor issues:
241                   added dcb.fOutxCtsFlow = FALSE and dcb.fOutxDsrFlow = FALSE (sometimes required)
242                   Now comparing one character less of answer to "Now launching ... code" command
243 1.59   2008-07-07 Peter Hayward
244                   Fixed freeze under Windows XP SP2 by removing redundant call to SetCommMask.
245 1.60   2008-07-21 Martin Maurer
246                   Added uptodate part ids for LPC2458, LPC2468 and LPC2478
247                   Add comment "obsolete" for older part ids for LPC2458 and LPC2468
248                   Add ", " between compile date and time
249 1.61   2008-10-21 Fausto Marzoli (thanks to Geoffrey Wossum for the patches)
250                   Fix for compiling latest version under Linux and "ControlLinesSwapped" issue
251 1.62   2008-11-19 Martin Maurer
252                   Added (untested) support for LPC2109
253                   Added (untested) support for LPC2361 / LPC2362
254                   Heavy update of part identification number of LPC23xx and LPC24xx
255                   Correct bug, that hex file must exist, when "-detectonly" is used
256                   Correct Makefile.vc: use /Fe instead of -o
257 1.63   2008-11-23 Martin Maurer
258                   Changed to GNU Lesser General Public License
259 1.64   2009-01-19 Steve Franks
260                   __FREEBSD__ changed to __FreeBSD__ at some point, plus other com port fixes
261 1.65   2009-03-26 Vito Marolda
262                   Added pre-erasure of sector 0 to invalidate checksum before starting
263                   modification of the other sectors, so that the bootloader restarts
264                   if programming gets aborted while writing on a non-empty part.
265 1.66   2009-03-26 Vito Marolda
266                   Corrected interpretation of intel hex record 03 which is execution start address
267                   and not data segment address
268 1.67   2009-04-19 SASANO Takayoshi
269                   Add OpenBSD support
270 1.68   2009-05-17 Martin Maurer
271                   Merge in changes done by Bruno Quoitin (baudrate problem when __APPLE__ is used)
272                   Remove TABs from source code and replaced them with spaces
273 1.69   2009-06-18 Martin Maurer
274                   Add support for LPC17xx devices
275 1.70   2009-06-29 Martin Maurer
276                   Further improvement of LPC17xx support
277                   Workaround for booter (4.1) of LPC17xx, which does not echo all sent characters (0D,0A,...)
278                   ISP command GO seems to be broken:
279                   Sending 'G 196 T(0A)'
280                   Answer(Length=15): 'G 196 T(0A)0(0D)(0A)'
281                   leads to 'prefetch_abort_exception(0D)(0A)1FFF07A5'
282                   No solution known...need your help here...
283                   Manual workaround: Use DTR and RTS toggling to start application (e.g. 2 batch files)
284 1.71   2009-07-19 Martin Maurer
285                   Added LPC17xx with CPUID starting with 0x26 (not according user manual)
286 1.72   2009-09-14 Martin Maurer
287                   Add support for LPC13xx devices
288 1.73   2009-09-14 Martin Maurer
289                   Correct again (hopefully the last time) the CPUIDs for some LPC17xx devices
290                   (Now according to User Manual LPC17xx Version 00.07 (31 July 2009))
291 1.74   2009-09-14 Mario Ivancic
292                   Added support for multiple HEX files, besed on internal version 1.37B.
293                   NOTE: this feature is used in production in 1.37B but is not tested in this version.
294                   Added numeric debug level command line switch -debugn, n=[0-5]
295                   Added command line scitch -try n to specify nQuestionMarks limit. Defaul: 100
296                   Merged in DoNotStart patch from cgommel_new
297                   Static functions declarations moved from lpc21isp.h to this file
298                   Modified LoadFile() to return error_code instead exit(1)
299                   Removed IspEnvironment.debug_level, all code uses global debug_level
300 1.75   2010-01-05 Martin Maurer
301                   Added support for LPC11xx devices (not tested at all)
302                   Changed Product in LPC_DEVICE_TYPE from number to string to distinguish new LPC11 devices
303                   Changed "unsigned" to "unsigned int" in LPC_DEVICE_TYPE
304 1.76   2010-02-01 Published test version without source code
305 1.77   2010-02-01 Martin Maurer
306                   Corrected chip id of LPC1342 and LPC1343
307                   Added a new chip type for LPC11xx and LPC13xx microcontrollers
308                   Use higher area of RAM with LPC11xx and LPC13xx, because lower RAM is occupied by ISP
309                   Add code to lpcprog.c to read unique id, but not yet activate.
310                   Adapt block sizes for copying for each model of LPC11xx and LPC13xx
311 1.78   2010-02-16 Martin Maurer
312                   Corrected chip id of LPC1751
313                   Added support for LPC1759, LPC1767 and LPC1769
314 1.79   2010-02-19 Andrew Pines
315                   Added __APPLE__ flag to CFLAGS in Makefile to detect and handle OS X
316                   Added -Wall to Makefile to report warnings more comprehensively
317                   Added #define in lpc21isp.h to substitute strnicmp with strncasecmp (needed for Unix)
318                   Fixed a few format specifiers in lpcprog.c to eliminate some warnings
319
320 */
321
322 // Please don't use TABs in the source code !!!
323
324 // Don't forget to update the version string that is on the next line
325 #define VERSION_STR "1.79"
326
327 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
328 static char RxTmpBuf[256];        // save received data to this buffer for half-duplex
329 char * pRxTmpBuf = RxTmpBuf;
330 #endif
331
332 #if !defined COMPILE_FOR_LPC21
333 int debug_level = 2;
334 #endif
335
336 static void ControlModemLines(ISP_ENVIRONMENT *IspEnvironment, unsigned char DTR, unsigned char RTS);
337 static unsigned char Ascii2Hex(unsigned char c);
338
339 #ifdef COMPILE_FOR_WINDOWS
340 static void SerialTimeoutSet(ISP_ENVIRONMENT *IspEnvironment, unsigned timeout_milliseconds);
341 static int SerialTimeoutCheck(ISP_ENVIRONMENT *IspEnvironment);
342 #endif // COMPILE_FOR_WINDOWS
343
344 static int AddFileHex(ISP_ENVIRONMENT *IspEnvironment, const char *arg);
345 static int AddFileBinary(ISP_ENVIRONMENT *IspEnvironment, const char *arg);
346 static int LoadFile(ISP_ENVIRONMENT *IspEnvironment, const char *filename, int FileFormat);
347
348 #define ERR_RECORD_TYPE_LOADFILE        55 /** File record type not yet implemented. */
349 #define ERR_ALLOC_FILE_LIST 60
350 #define ERR_FILE_OPEN_HEX       61      /**< Couldn't open hex file. */
351 #define ERR_FILE_SIZE_HEX       62      /**< Unexpected hex file size. */
352 #define ERR_FILE_ALLOC_HEX      63      /**< Couldn't allocate enough memory for hex file. */
353 #define ERR_FILE_ALLOC_BIN      64      /**< Couldn't allocate enough memory for bin file. */
354 #define ERR_FILE_RECST_HEX      65      /**< Can't find start of record indicator for Intel Hex file.*/
355 #define ERR_FILE_OPEN_BIN       66      /**< Couldn't open binary file. */
356 #define ERR_FILE_SIZE_BIN       67      /**< Unexpected binary file size. */
357 #define ERR_FILE_WRITE_BIN      68      /**< Couldn't write debug binary file to disk. How's that for ironic? */
358 #define ERR_MEMORY_RANGE    69  /**< Out of memory range. */
359
360 /************* Portability layer. Serial and console I/O differences    */
361 /* are taken care of here.                                              */
362
363 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
364 static void OpenSerialPort(ISP_ENVIRONMENT *IspEnvironment)
365 {
366     DCB    dcb;
367     COMMTIMEOUTS commtimeouts;
368
369     IspEnvironment->hCom = CreateFile(IspEnvironment->serial_port, GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
370
371     if (IspEnvironment->hCom == INVALID_HANDLE_VALUE)
372     {
373         DebugPrintf(1, "Can't open COM-Port %s ! - Error: %ld\n", IspEnvironment->serial_port, GetLastError());
374         exit(2);
375     }
376
377     DebugPrintf(3, "COM-Port %s opened...\n", IspEnvironment->serial_port);
378
379     GetCommState(IspEnvironment->hCom, &dcb);
380     dcb.BaudRate    = atol(IspEnvironment->baud_rate);
381     dcb.ByteSize    = 8;
382     dcb.StopBits    = ONESTOPBIT;
383     dcb.Parity      = NOPARITY;
384     dcb.fDtrControl = DTR_CONTROL_DISABLE;
385     dcb.fOutX       = FALSE;
386     dcb.fInX        = FALSE;
387     dcb.fNull       = FALSE;
388     dcb.fRtsControl = RTS_CONTROL_DISABLE;
389
390     // added by Herbert Demmel - iF CTS line has the wrong state, we would never send anything!
391     dcb.fOutxCtsFlow = FALSE;
392     dcb.fOutxDsrFlow = FALSE;
393
394     if (SetCommState(IspEnvironment->hCom, &dcb) == 0)
395     {
396         DebugPrintf(1, "Can't set baudrate %s ! - Error: %ld", IspEnvironment->baud_rate, GetLastError());
397         exit(3);
398     }
399
400    /*
401     *  Peter Hayward 02 July 2008
402     *
403     *  The following call is only needed if the WaitCommEvent
404     *  or possibly the GetCommMask functions are used.  They are
405     *  *not* in this implimentation.  However, under Windows XP SP2
406     *  on my laptop the use of this call causes XP to freeze (crash) while
407     *  this program is running, e.g. in section 5/6/7 ... of a largish
408     *  download.  Removing this *unnecessary* call fixed the problem.
409     *  At the same time I've added a call to SetupComm to request
410     *  (not necessarity honoured) the operating system to provide
411     *  large I/O buffers for high speed I/O without handshaking.
412     *
413     *   SetCommMask(IspEnvironment->hCom,EV_RXCHAR | EV_TXEMPTY);
414     */
415     SetupComm(IspEnvironment->hCom, 32000, 32000);
416
417     SetCommMask(IspEnvironment->hCom, EV_RXCHAR | EV_TXEMPTY);
418
419     commtimeouts.ReadIntervalTimeout         = MAXDWORD;
420     commtimeouts.ReadTotalTimeoutMultiplier  =    0;
421     commtimeouts.ReadTotalTimeoutConstant    =    1;
422     commtimeouts.WriteTotalTimeoutMultiplier =    0;
423     commtimeouts.WriteTotalTimeoutConstant   =    0;
424     SetCommTimeouts(IspEnvironment->hCom, &commtimeouts);
425 }
426 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
427
428 #if defined COMPILE_FOR_LINUX
429 static void OpenSerialPort(ISP_ENVIRONMENT *IspEnvironment)
430 {
431     IspEnvironment->fdCom = open(IspEnvironment->serial_port, O_RDWR | O_NOCTTY | O_NONBLOCK);
432
433     if (IspEnvironment->fdCom < 0)
434     {
435         int err = errno;
436         DebugPrintf(1, "Can't open COM-Port %s ! (Error: %dd (0x%X))\n", IspEnvironment->serial_port, err, err);
437         exit(2);
438     }
439
440     DebugPrintf(3, "COM-Port %s opened...\n", IspEnvironment->serial_port);
441
442     /* clear input & output buffers, then switch to "blocking mode" */
443     tcflush(IspEnvironment->fdCom, TCOFLUSH);
444     tcflush(IspEnvironment->fdCom, TCIFLUSH);
445     fcntl(IspEnvironment->fdCom, F_SETFL, fcntl(IspEnvironment->fdCom, F_GETFL) & ~O_NONBLOCK);
446
447     tcgetattr(IspEnvironment->fdCom, &IspEnvironment->oldtio); /* save current port settings */
448
449     bzero(&IspEnvironment->newtio, sizeof(IspEnvironment->newtio));
450     IspEnvironment->newtio.c_cflag = CS8 | CLOCAL | CREAD;
451
452 #if defined(__FreeBSD__) || defined(__OpenBSD__)
453
454     if(cfsetspeed(&IspEnvironment->newtio,(speed_t) strtol(IspEnvironment->baud_rate,NULL,10))) {
455                   DebugPrintf(1, "baudrate %s not supported\n", IspEnvironment->baud_rate);
456                   exit(3);
457               };
458 #else
459
460 #ifdef __APPLE__
461 #define NEWTERMIOS_SETBAUDARTE(bps) IspEnvironment->newtio.c_ispeed = IspEnvironment->newtio.c_ospeed = bps;
462 #else
463 #define NEWTERMIOS_SETBAUDARTE(bps) IspEnvironment->newtio.c_cflag |= bps;
464 #endif
465
466     switch (atol(IspEnvironment->baud_rate))
467     {
468 #ifdef B1152000
469           case 1152000: NEWTERMIOS_SETBAUDARTE(B1152000); break;
470 #endif // B1152000
471 #ifdef B576000
472           case  576000: NEWTERMIOS_SETBAUDARTE(B576000); break;
473 #endif // B576000
474 #ifdef B230400
475           case  230400: NEWTERMIOS_SETBAUDARTE(B230400); break;
476 #endif // B230400
477 #ifdef B115200
478           case  115200: NEWTERMIOS_SETBAUDARTE(B115200); break;
479 #endif // B115200
480 #ifdef B57600
481           case   57600: NEWTERMIOS_SETBAUDARTE(B57600); break;
482 #endif // B57600
483 #ifdef B38400
484           case   38400: NEWTERMIOS_SETBAUDARTE(B38400); break;
485 #endif // B38400
486 #ifdef B19200
487           case   19200: NEWTERMIOS_SETBAUDARTE(B19200); break;
488 #endif // B19200
489 #ifdef B9600
490           case    9600: NEWTERMIOS_SETBAUDARTE(B9600); break;
491 #endif // B9600
492           default:
493               {
494                   DebugPrintf(1, "unknown baudrate %s\n", IspEnvironment->baud_rate);
495                   exit(3);
496               }
497     }
498
499 #endif
500
501     IspEnvironment->newtio.c_iflag = IGNPAR | IGNBRK | IXON | IXOFF;
502     IspEnvironment->newtio.c_oflag = 0;
503
504     /* set input mode (non-canonical, no echo,...) */
505     IspEnvironment->newtio.c_lflag = 0;
506
507     cfmakeraw(&IspEnvironment->newtio);
508     IspEnvironment->newtio.c_cc[VTIME]    = 1;   /* inter-character timer used */
509     IspEnvironment->newtio.c_cc[VMIN]     = 0;   /* blocking read until 0 chars received */
510
511     tcflush(IspEnvironment->fdCom, TCIFLUSH);
512     if(tcsetattr(IspEnvironment->fdCom, TCSANOW, &IspEnvironment->newtio))
513     {
514        DebugPrintf(1, "Could not change serial port behaviour (wrong baudrate?)\n");
515        exit(3);
516     }
517
518 }
519 #endif // defined COMPILE_FOR_LINUX
520
521 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
522 static void CloseSerialPort(ISP_ENVIRONMENT *IspEnvironment)
523 {
524     CloseHandle(IspEnvironment->hCom);
525 }
526
527 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
528
529 #if defined COMPILE_FOR_LINUX
530 static void CloseSerialPort(ISP_ENVIRONMENT *IspEnvironment)
531 {
532     tcflush(IspEnvironment->fdCom, TCOFLUSH);
533     tcflush(IspEnvironment->fdCom, TCIFLUSH);
534     tcsetattr(IspEnvironment->fdCom, TCSANOW, &IspEnvironment->oldtio);
535
536     close(IspEnvironment->fdCom);
537 }
538 #endif // defined COMPILE_FOR_LINUX
539
540
541 /***************************** SendComPortBlock *************************/
542 /**  Sends a block of bytes out the opened com port.
543 \param [in] s block to send.
544 \param [in] n size of the block.
545 */
546 void SendComPortBlock(ISP_ENVIRONMENT *IspEnvironment, const void *s, size_t n)
547 {
548 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
549
550     unsigned long realsize;
551     size_t m;
552     unsigned long rxsize;
553     char * pch;
554     char * rxpch;
555 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
556
557     DumpString(4, s, n, "Sending ");
558
559 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
560
561     if (IspEnvironment->HalfDuplex == 0)
562     {
563         WriteFile(IspEnvironment->hCom, s, n, &realsize, NULL);
564     }
565     else
566     {
567         pch = (char *)s;
568         rxpch = RxTmpBuf;
569         pRxTmpBuf = RxTmpBuf;
570
571         // avoid buffer otherflow
572         if (n > sizeof (RxTmpBuf))
573             n = sizeof (RxTmpBuf);
574
575         for (m = 0; m < n; m++)
576         {
577             WriteFile(IspEnvironment->hCom, pch, 1, &realsize, NULL);
578
579             if ((*pch != '?') || (n != 1))
580             {
581                 do
582                 {
583                     ReadFile(IspEnvironment->hCom, rxpch, 1, &rxsize, NULL);
584                 }while (rxsize == 0);
585             }
586             pch++;
587             rxpch++;
588         }
589         *rxpch = 0;        // terminate echo string
590     }
591 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
592
593 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_LPC21
594
595     write(IspEnvironment->fdCom, s, n);
596
597 #endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_LPC21
598 }
599
600 /***************************** SendComPort ******************************/
601 /**  Sends a string out the opened com port.
602 \param [in] s string to send.
603 */
604 void SendComPort(ISP_ENVIRONMENT *IspEnvironment, const char *s)
605 {
606     SendComPortBlock(IspEnvironment, s, strlen(s));
607 }
608
609 /***************************** SerialTimeoutTick ************************/
610 /**  Performs a timer tick.  In this simple case all we do is count down
611 with protection against underflow and wrapping at the low end.
612 */
613 static void SerialTimeoutTick(ISP_ENVIRONMENT *IspEnvironment)
614 {
615     if (IspEnvironment->serial_timeout_count <= 1)
616     {
617         IspEnvironment->serial_timeout_count = 0;
618     }
619     else
620     {
621         IspEnvironment->serial_timeout_count--;
622     }
623 }
624
625
626 /***************************** ReceiveComPortBlock **********************/
627 /**  Receives a buffer from the open com port. Returns all the characters
628 ready (waits for up to 'n' milliseconds before accepting that no more
629 characters are ready) or when the buffer is full. 'n' is system dependant,
630 see SerialTimeout routines.
631 \param [out] answer buffer to hold the bytes read from the serial port.
632 \param [in] max_size the size of buffer pointed to by answer.
633 \param [out] real_size pointer to a long that returns the amout of the
634 buffer that is actually used.
635 */
636 static void ReceiveComPortBlock(ISP_ENVIRONMENT *IspEnvironment,
637                                           void *answer, unsigned long max_size,
638                                           unsigned long *real_size)
639 {
640     char tmp_string[32];
641
642 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
643
644     if (IspEnvironment->HalfDuplex == 0)
645         ReadFile(IspEnvironment->hCom, answer, max_size, real_size, NULL);
646     else
647     {
648         *real_size = strlen (pRxTmpBuf);
649         if (*real_size)
650         {
651             if (max_size >= *real_size)
652             {
653                 strncpy((char*) answer, pRxTmpBuf, *real_size);
654                 RxTmpBuf[0] = 0;
655                 pRxTmpBuf = RxTmpBuf;
656             }
657             else
658             {
659                 strncpy((char*) answer, pRxTmpBuf, max_size);
660                 *real_size = max_size;
661                 pRxTmpBuf += max_size;
662             }
663         }
664         else
665             ReadFile(IspEnvironment->hCom, answer, max_size, real_size, NULL);
666     }
667
668 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
669
670 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_LPC21
671
672     *real_size = read(IspEnvironment->fdCom, answer, max_size);
673
674 #endif // defined COMPILE_FOR_LINUX
675
676     sprintf(tmp_string, "Read(Length=%ld): ", (*real_size));
677     DumpString(5, answer, (*real_size), tmp_string);
678
679     if (*real_size == 0)
680     {
681         SerialTimeoutTick(IspEnvironment);
682     }
683 }
684
685
686 /***************************** SerialTimeoutSet *************************/
687 /**  Sets (or resets) the timeout to the timout period requested.  Starts
688 counting to this period.  This timeout support is a little odd in that the
689 timeout specifies the accumulated deadtime waiting to read not the total
690 time waiting to read. They should be close enought to the same for this
691 use. Used by the serial input routines, the actual counting takes place in
692 ReceiveComPortBlock.
693 \param [in] timeout_milliseconds the time in milliseconds to use for
694 timeout.  Note that just because it is set in milliseconds doesn't mean
695 that the granularity is that fine.  In many cases (particularly Linux) it
696 will be coarser.
697 */
698 static void SerialTimeoutSet(ISP_ENVIRONMENT *IspEnvironment, unsigned timeout_milliseconds)
699 {
700 #if defined COMPILE_FOR_LINUX
701     IspEnvironment->serial_timeout_count = timeout_milliseconds / 100;
702 #elif defined COMPILE_FOR_LPC21
703     IspEnvironment->serial_timeout_count = timeout_milliseconds * 200;
704 #else
705     IspEnvironment->serial_timeout_count = timeout_milliseconds;
706 #endif
707 }
708
709
710
711 /***************************** SerialTimeoutCheck ***********************/
712 /**  Check to see if the serial timeout timer has run down.
713 \retval 1 if timer has run out.
714 \retval 0 if timer still has time left.
715 */
716 static int SerialTimeoutCheck(ISP_ENVIRONMENT *IspEnvironment)
717 {
718     if (IspEnvironment->serial_timeout_count == 0)
719     {
720         return 1;
721     }
722     return 0;
723 }
724
725
726 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
727 /***************************** getch ************************************/
728 /** Replacement for the common dos function of the same name. Reads a
729 single unbuffered character from the 'keyboard'.
730 \return The character read from the keyboard.
731 */
732 int getch(void)
733 {
734     char ch;
735
736     /* Read in one character */
737     read(0,&ch,1);
738
739     return ch;
740 }
741 #endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
742
743 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
744 /***************************** kbhit ************************************/
745 /** Replacement for the common dos function of the same name. Indicates if
746 there are characters to be read from the console.
747 \retval 0 No characters ready.
748 \retval 1 Characters from the console ready to be read.
749 */
750 int kbhit(void)
751 {
752     /* return 0 for no key pressed, 1 for key pressed */
753     int return_value = 0;
754
755     /* time struct for the select() function, to only wait a little while */
756     struct timeval select_time;
757     /* file descriptor variable for the select() call */
758     fd_set readset;
759
760     /* we're only interested in STDIN */
761     FD_ZERO(&readset);
762     FD_SET(STDIN_FILENO, &readset);
763
764     /* how long to block for - this must be > 0.0, but could be changed
765     to some other setting. 10-18msec seems to work well and only
766     minimally load the system (0% CPU loading) */
767     select_time.tv_sec = 0;
768     select_time.tv_usec = 10;
769
770     /* is there a keystroke there? */
771     if (select(1, &readset, NULL, NULL, &select_time))
772     {
773         /* yes, remember it */
774         return_value = 1;
775     }
776
777
778     /* return with what we found out */
779     return return_value;
780 }
781 struct termios keyboard_origtty;
782 #endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
783
784
785 /***************************** PrepareKeyboardTtySettings ***************/
786 /** Set the keyboard tty to be able to check for new characters via kbhit
787 getting them via getch
788 */
789
790 void PrepareKeyboardTtySettings(void)
791 {
792 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
793     /* store the current tty settings */
794     if (!tcgetattr(0, &keyboard_origtty))
795     {
796         struct termios tty;
797         /* start with the current settings */
798         tty = keyboard_origtty;
799         /* make modifications to put it in raw mode, turn off echo */
800         tty.c_lflag &= ~ICANON;
801         tty.c_lflag &= ~ECHO;
802         tty.c_lflag &= ~ISIG;
803         tty.c_cc[VMIN] = 1;
804         tty.c_cc[VTIME] = 0;
805
806         /* put the settings into effect */
807         tcsetattr(0, TCSADRAIN, &tty);
808     }
809 #endif
810 }
811
812
813 /***************************** ResetKeyboardTtySettings *****************/
814 /** Reset the keyboard tty to original settings
815 */
816 void ResetKeyboardTtySettings(void)
817 {
818 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
819     /* reset the tty to its original settings */
820     tcsetattr(0, TCSADRAIN, &keyboard_origtty);
821 #endif
822 }
823
824
825 #if !defined COMPILE_FOR_LPC21
826 /***************************** ControlModemLines ************************/
827 /**  Controls the modem lines to place the microcontroller into various
828 states during the programming process.
829 error rather abruptly terminates the program.
830 \param [in] DTR the state to set the DTR line to.
831 \param [in] RTS the state to set the RTS line to.
832 */
833 static void ControlModemLines(ISP_ENVIRONMENT *IspEnvironment, unsigned char DTR, unsigned char RTS)
834 {
835     //handle wether to invert the control lines:
836     DTR ^= IspEnvironment->ControlLinesInverted;
837     RTS ^= IspEnvironment->ControlLinesInverted;
838
839     //handle wether to swap the control lines
840     if (IspEnvironment->ControlLinesSwapped)
841     {
842         unsigned char tempRTS;
843         tempRTS = RTS;
844         RTS = DTR;
845         DTR = tempRTS;
846     }
847
848 #if defined COMPILE_FOR_LINUX
849     int status;
850
851     if (ioctl(IspEnvironment->fdCom, TIOCMGET, &status) == 0)
852     {
853         DebugPrintf(3, "ioctl get ok, status = %X\n",status);
854     }
855     else
856     {
857         DebugPrintf(1, "ioctl get failed\n");
858     }
859
860     if (DTR) status |=  TIOCM_DTR;
861     else    status &= ~TIOCM_DTR;
862
863     if (RTS) status |=  TIOCM_RTS;
864     else    status &= ~TIOCM_RTS;
865
866     if (ioctl(IspEnvironment->fdCom, TIOCMSET, &status) == 0)
867     {
868         DebugPrintf(3, "ioctl set ok, status = %X\n",status);
869     }
870     else
871     {
872         DebugPrintf(1, "ioctl set failed\n");
873     }
874
875     if (ioctl(IspEnvironment->fdCom, TIOCMGET, &status) == 0)
876     {
877         DebugPrintf(3, "ioctl get ok, status = %X\n",status);
878     }
879     else
880     {
881         DebugPrintf(1, "ioctl get failed\n");
882     }
883
884 #endif // defined COMPILE_FOR_LINUX
885 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
886
887     if (DTR) EscapeCommFunction(IspEnvironment->hCom, SETDTR);
888     else    EscapeCommFunction(IspEnvironment->hCom, CLRDTR);
889
890     if (RTS) EscapeCommFunction(IspEnvironment->hCom, SETRTS);
891     else    EscapeCommFunction(IspEnvironment->hCom, CLRRTS);
892
893 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
894
895 #if defined COMPILE_FOR_LPC21
896     LPC_RESET(DTR);
897     LPC_BSL(RTS);
898 #endif
899
900     DebugPrintf(3, "DTR (%d), RTS (%d)\n", DTR, RTS);
901 }
902
903
904 /***************************** ClearSerialPortBuffers********************/
905 /**  Empty the serial port buffers.  Cleans things to a known state.
906 */
907 void ClearSerialPortBuffers(ISP_ENVIRONMENT *IspEnvironment)
908 {
909 #if defined COMPILE_FOR_LINUX
910     /* variables to store the current tty state, create a new one */
911     struct termios origtty, tty;
912
913     /* store the current tty settings */
914     tcgetattr(IspEnvironment->fdCom, &origtty);
915
916     // Flush input and output buffers
917     tty=origtty;
918     tcsetattr(IspEnvironment->fdCom, TCSAFLUSH, &tty);
919
920     /* reset the tty to its original settings */
921     tcsetattr(IspEnvironment->fdCom, TCSADRAIN, &origtty);
922 #endif // defined COMPILE_FOR_LINUX
923 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
924     PurgeComm(IspEnvironment->hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
925 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
926 }
927 #endif // !defined COMPILE_FOR_LPC21
928
929
930 #if defined COMPILE_FOR_LINUX
931 /***************************** Sleep ************************************/
932 /**  Provide linux replacement for windows function.
933 \param [in] Milliseconds the time to wait for in milliseconds.
934 */
935 void Sleep(unsigned long MilliSeconds)
936 {
937     usleep(MilliSeconds*1000); //convert to microseconds
938 }
939 #endif // defined COMPILE_FOR_LINUX
940
941
942 #if defined COMPILE_FOR_LPC21
943 /**  Provide linux replacement for windows function.
944 \note I implement that one in my private header file today...
945 \param [in] Milliseconds the time to wait for in milliseconds.
946 */
947 /*static void Sleep(unsigned long MilliSeconds)
948 {
949 #   warning Sleep function not implemented
950 }
951 */
952 #endif // defined COMPILE_FOR_LPC21
953
954
955
956 /************* Applicationlayer.                                        */
957
958 #if !defined COMPILE_FOR_LPC21
959 /***************************** DebugPrintf ******************************/
960 /**  Prints a debug string depending the current debug level. The higher
961 the debug level the more detail that will be printed.  Each print
962 has an associated level, the higher the level the more detailed the
963 debugging information being sent.
964 \param [in] level the debug level of the print statement, if the level
965 is less than or equal to the current debug level it will be printed.
966 \param [in] fmt a standard printf style format string.
967 \param [in] ... the usual printf parameters.
968 */
969 #if !defined INTEGRATED_IN_WIN_APP
970 void DebugPrintf(int level, const char *fmt, ...)
971 {
972     va_list ap;
973
974     if (level <= debug_level)
975     {
976         char pTemp[2000];
977         va_start(ap, fmt);
978         //vprintf(fmt, ap);
979         vsprintf(pTemp, fmt, ap);
980         TRACE(pTemp);
981         va_end(ap);
982         fflush(stdout);
983     }
984 }
985 #endif
986 #endif // !defined COMPILE_FOR_LPC21
987
988
989 /***************************** ReceiveComPort ***************************/
990 /**  Receives a buffer from the open com port. Returns when the buffer is
991 filled, the numer of requested linefeeds has been received or the timeout
992 period has passed
993 \param [in] ISPEnvironment.
994 \param [out] Answer buffer to hold the bytes read from the serial port.
995 \param [in] MaxSize the size of buffer pointed to by Answer.
996 \param [out] RealSize pointer to a long that returns the amout of the
997 buffer that is actually used.
998 \param [in] WantedNr0x0A the maximum number of linefeeds to accept before
999 returning.
1000 \param [in] timeOutMilliseconds the maximum amount of time to wait before
1001 reading with an incomplete buffer.
1002 */
1003 void ReceiveComPort(ISP_ENVIRONMENT *IspEnvironment,
1004                                     const char *Ans, unsigned long MaxSize,
1005                                     unsigned long *RealSize, unsigned long WantedNr0x0A,
1006                                     unsigned timeOutMilliseconds)
1007 {
1008     unsigned long tmp_realsize;
1009     unsigned long nr_of_0x0A = 0;
1010     unsigned long nr_of_0x0D = 0;
1011     int eof = 0;
1012     unsigned long p;
1013     unsigned char *Answer;
1014     char tmp_string[32];
1015
1016     Answer = (unsigned char*) Ans;
1017
1018     SerialTimeoutSet(IspEnvironment, timeOutMilliseconds);
1019
1020     (*RealSize) = 0;
1021
1022     do
1023     {
1024         ReceiveComPortBlock(IspEnvironment, Answer + (*RealSize), MaxSize - 1 - (*RealSize), &tmp_realsize);
1025
1026         if (tmp_realsize != 0)
1027         {
1028             for (p = (*RealSize); p < (*RealSize) + tmp_realsize; p++)
1029             {
1030                 if (Answer[p] == 0x0a)
1031                 {
1032                     nr_of_0x0A++;
1033                 }
1034                 else if (Answer[p] == 0x0d)
1035                 {
1036                     nr_of_0x0D++;
1037                 }
1038                 else if (((signed char) Answer[p]) < 0)
1039                 {
1040                     eof = 1;
1041                 }
1042             }
1043         }
1044
1045         (*RealSize) += tmp_realsize;
1046
1047     } while (((*RealSize) < MaxSize) && (SerialTimeoutCheck(IspEnvironment) == 0) && (nr_of_0x0A < WantedNr0x0A) && (nr_of_0x0D < WantedNr0x0A) && !eof);
1048
1049     Answer[(*RealSize)] = 0;
1050
1051     sprintf(tmp_string, "Answer(Length=%ld): ", (*RealSize));
1052     DumpString(3, Answer, (*RealSize), tmp_string);
1053 }
1054
1055
1056 #if !defined COMPILE_FOR_LPC21
1057
1058 /***************************** ReceiveComPortBlockComplete **************/
1059 /**  Receives a fixed block from the open com port. Returns when the
1060 block is completely filled or the timeout period has passed
1061 \param [out] block buffer to hold the bytes read from the serial port.
1062 \param [in] size the size of the buffer pointed to by block.
1063 \param [in] timeOut the maximum amount of time to wait before guvung up on
1064 completing the read.
1065 \return 0 if successful, non-zero otherwise.
1066 */
1067 int ReceiveComPortBlockComplete(ISP_ENVIRONMENT *IspEnvironment,
1068                                                     void *block, size_t size, unsigned timeout)
1069 {
1070     unsigned long realsize = 0, read;
1071     char *result;
1072     char tmp_string[32];
1073
1074     result = (char*) block;
1075
1076     SerialTimeoutSet(IspEnvironment, timeout);
1077
1078     do
1079     {
1080         ReceiveComPortBlock(IspEnvironment, result + realsize, size - realsize, &read);
1081
1082         realsize += read;
1083
1084     } while ((realsize < size) && (SerialTimeoutCheck(IspEnvironment) == 0));
1085
1086     sprintf(tmp_string, "Answer(Length=%ld): ", realsize);
1087     DumpString(3, result, realsize, tmp_string);
1088
1089     if (realsize != size)
1090     {
1091         return 1;
1092     }
1093     return 0;
1094 }
1095
1096 /***************************** ReadArguments ****************************/
1097 /**  Reads the command line arguments and parses it for the various
1098 options. Uses the same arguments as main.  Used to separate the command
1099 line parsing from main and improve its readability.  This should also make
1100 it easier to modify the command line parsing in the future.
1101 \param [in] argc the number of arguments.
1102 \param [in] argv an array of pointers to the arguments.
1103 */
1104 static void ReadArguments(ISP_ENVIRONMENT *IspEnvironment, unsigned int argc, char *argv[])
1105 {
1106     unsigned int i;
1107
1108     if (argc >= 5)
1109     {
1110         for (i = 1; i < argc - 3; i++)
1111         {
1112             if (stricmp(argv[i], "-wipe") == 0)
1113             {
1114                 IspEnvironment->WipeDevice = 1;
1115                 DebugPrintf(3, "Wipe entire device before writing.\n");
1116                 continue;
1117             }
1118
1119             if (stricmp(argv[i], "-bin") == 0)
1120             {
1121                 IspEnvironment->FileFormat = FORMAT_BINARY;
1122                 DebugPrintf(3, "Binary format file input.\n");
1123                 continue;
1124             }
1125
1126             if (stricmp(argv[i], "-hex") == 0)
1127             {
1128                 IspEnvironment->FileFormat = FORMAT_HEX;
1129                 DebugPrintf(3, "Hex format file input.\n");
1130                 continue;
1131             }
1132
1133             if (stricmp(argv[i], "-logfile") == 0)
1134             {
1135                 IspEnvironment->LogFile = 1;
1136                 DebugPrintf(3, "Log terminal output.\n");
1137                 continue;
1138             }
1139
1140             if (stricmp(argv[i], "-detectonly") == 0)
1141             {
1142                 IspEnvironment->DetectOnly  = 1;
1143                 IspEnvironment->ProgramChip = 0;
1144                 DebugPrintf(3, "Only detect LPC chip part id.\n");
1145                 continue;
1146             }
1147
1148             if(strnicmp(argv[i],"-debug", 6) == 0)
1149             {
1150                 char* num;
1151                 num = argv[i] + 6;
1152                 while(*num && isdigit(*num) == 0) num++;
1153                 if(isdigit(*num) != 0) debug_level = atoi( num);
1154                 else debug_level = 4;
1155                 DebugPrintf(3, "Turn on debug, level: %d.\n", debug_level);
1156                 continue;
1157             }
1158
1159             if (stricmp(argv[i], "-DoNotStart") == 0)
1160             {
1161                 IspEnvironment->DoNotStart = 1;
1162                 DebugPrintf(3, "Do NOT start MCU after programming.\n");
1163                 continue;
1164             }
1165
1166             if (stricmp(argv[i], "-control") == 0)
1167             {
1168                 IspEnvironment->ControlLines = 1;
1169                 DebugPrintf(3, "Use RTS/DTR to control target state.\n");
1170                 continue;
1171             }
1172
1173             if (stricmp(argv[i], "-controlswap") == 0)
1174             {
1175                 IspEnvironment->ControlLinesSwapped = 1;
1176                 DebugPrintf(3, "Use RTS to control reset, and DTR to control P0.14(ISP).\n");
1177                 continue;
1178             }
1179
1180             if (stricmp(argv[i], "-controlinv") == 0)
1181             {
1182                 IspEnvironment->ControlLinesInverted = 1;
1183                 DebugPrintf(3, "Invert state of RTS & DTR (0=true/assert/set, 1=false/deassert/clear).\n");
1184                 continue;
1185             }
1186
1187             if (stricmp(argv[i], "-halfduplex") == 0)
1188             {
1189                 IspEnvironment->HalfDuplex = 1;
1190                 DebugPrintf(3, "halfduplex serial communication.\n");
1191                 continue;
1192             }
1193
1194             if (stricmp(argv[i], "-ADARM") == 0)
1195             {
1196                 IspEnvironment->micro = ANALOG_DEVICES_ARM;
1197                 DebugPrintf(2, "Target: Analog Devices.\n");
1198                 continue;
1199             }
1200
1201             if (stricmp(argv[i], "-PHILIPSARM") == 0)
1202             {
1203                 IspEnvironment->micro = PHILIPS_ARM;
1204                 DebugPrintf(2, "Target: Philips.\n");
1205                 continue;
1206             }
1207
1208             if (stricmp(argv[i], "-Verify") == 0)
1209             {
1210                 IspEnvironment->Verify = 1;
1211                 DebugPrintf(2, "Verify after copy RAM to Flash.\n");
1212                 continue;
1213             }
1214
1215 #ifdef INTEGRATED_IN_WIN_APP
1216             if (stricmp(argv[i], "-nosync") == 0)
1217             {
1218                 IspEnvironment->NoSync = 1;
1219                 DebugPrintf(2, "Performing no syncing, already done.\n");
1220                 continue;
1221             }
1222 #endif
1223
1224 #ifdef TERMINAL_SUPPORT
1225             if (CheckTerminalParameters(IspEnvironment, argv[i]))
1226             {
1227                 continue;
1228             }
1229 #endif
1230
1231             if(*argv[i] == '-') DebugPrintf( 2, "Unknown command line option: \"%s\"\n", argv[i]);
1232             else
1233             {
1234                 int ret_val;
1235                 if(IspEnvironment->FileFormat == FORMAT_HEX)
1236                 {
1237                     ret_val = AddFileHex(IspEnvironment, argv[i]);
1238                 }
1239                 else
1240                 {
1241                     ret_val = AddFileBinary(IspEnvironment, argv[i]);
1242                 }
1243                 if( ret_val != 0)
1244                 {
1245                     DebugPrintf( 2, "Unknown command line option: \"%s\"\n", argv[i]);
1246                 }
1247             }
1248         }
1249
1250         // Newest cygwin delivers a '\x0d' at the end of argument
1251         // when calling lpc21isp from batch file
1252         for (i = 0; i < strlen(argv[argc - 1]) && i < (sizeof(IspEnvironment->StringOscillator) - 1) &&
1253             argv[argc - 1][i] >= '0' && argv[argc - 1][i] <= '9'; i++)
1254         {
1255             IspEnvironment->StringOscillator[i] = argv[argc - 1][i];
1256         }
1257         IspEnvironment->StringOscillator[i] = 0;
1258
1259         IspEnvironment->serial_port = argv[argc - 3];
1260         IspEnvironment->baud_rate = argv[argc - 2];
1261     }
1262
1263     if (argc < 5)
1264     {
1265         debug_level = (debug_level < 2) ? 2 : debug_level;
1266     }
1267
1268     if (argc < 5)
1269     {
1270         DebugPrintf(2, "\n"
1271                        "Portable command line ISP for NXP LPC2000 family and Analog Devices ADUC 70xx\n"
1272                        "Version " VERSION_STR " compiled for " COMPILED_FOR ": " __DATE__ ", " __TIME__ "\n"
1273                        "Copyright (c) by Martin Maurer, 2003-2009, Email: Martin.Maurer@clibb.de\n"
1274                        "Portions Copyright (c) by Aeolus Development 2004, www.aeolusdevelopment.com\n"
1275                        "\n");
1276
1277         DebugPrintf(1, "Syntax:  lpc21isp [Options] file[ file[ ...]] comport baudrate Oscillator_in_kHz\n\n"
1278                        "Example: lpc21isp test.hex com1 115200 14746\n\n"
1279                        "Options: -bin         for uploading binary file\n"
1280                        "         -hex         for uploading file in intel hex format (default)\n"
1281                        "         -term        for starting terminal after upload\n"
1282                        "         -termonly    for starting terminal without an upload\n"
1283                        "         -localecho   for local echo in terminal\n"
1284                        "         -detectonly  detect only used LPC chiptype (PHILIPSARM only)\n"
1285                        "         -debug0      for no debug\n"
1286                        "         -debug3      for progress info only\n"
1287                        "         -debug5      for full debug\n"
1288                        "         -donotstart  do not start MCU after download\n"
1289                        "         -try<n>      try n times to synchronise\n"
1290                        "         -wipe        Erase entire device before upload\n"
1291                        "         -control     for controlling RS232 lines for easier booting\n"
1292                        "                      (Reset = DTR, EnableBootLoader = RTS)\n"
1293 #ifdef INTEGRATED_IN_WIN_APP
1294                        "         -nosync      Do not synchronize device via '?'\n"
1295 #endif
1296                        "         -controlswap swap RS232 control lines\n"
1297                        "                      (Reset = RTS, EnableBootLoader = DTR)\n"
1298                        "         -controlinv  Invert state of RTS & DTR \n"
1299                        "                      (0=true/assert/set, 1=false/deassert/clear).\n"
1300                        "         -verify      Verify the data in Flash after every writes to\n"
1301                        "                      sector. To detect errors in writing to Flash ROM\n"
1302                        "         -logfile     for enabling logging of terminal output to lpc21isp.log\n"
1303                        "         -halfduplex  use halfduplex serial communication (i.e. with K-Line)\n"
1304                        "         -ADARM       for downloading to an Analog Devices\n"
1305                        "                      ARM microcontroller ADUC70xx\n"
1306                        "         -PHILIPSARM  for downloading to a microcontroller from\n"
1307                        "                      NXP(Philips) LPC13xx/LPC17xx/LPC2000 family (default)\n");
1308
1309         exit(1);
1310     }
1311
1312     if (IspEnvironment->micro == PHILIPS_ARM)
1313     {
1314         // If StringOscillator is bigger than 100 MHz, there seems to be something wrong
1315         if (strlen(IspEnvironment->StringOscillator) > 5)
1316         {
1317             DebugPrintf(1, "Invalid crystal frequency %s\n", IspEnvironment->StringOscillator);
1318             exit(1);
1319         }
1320     }
1321 }
1322
1323 /***************************** ResetTarget ******************************/
1324 /**  Resets the target leaving it in either download (program) mode or
1325 run mode.
1326 \param [in] mode the mode to leave the target in.
1327 */
1328 void ResetTarget(ISP_ENVIRONMENT *IspEnvironment, TARGET_MODE mode)
1329 {
1330     if (IspEnvironment->ControlLines)
1331     {
1332         switch (mode)
1333         {
1334         /* Reset and jump to boot loader.                       */
1335         case PROGRAM_MODE:
1336             ControlModemLines(IspEnvironment, 1, 1);
1337             Sleep(100);
1338             ClearSerialPortBuffers(IspEnvironment);
1339             Sleep(100);
1340             ControlModemLines(IspEnvironment, 0, 1);
1341             //Longer delay is the Reset signal is conected to an external rest controller
1342             Sleep(500);
1343             // Clear the RTS line after having reset the micro
1344             // Needed for the "GO <Address> <Mode>" ISP command to work */
1345             ControlModemLines(IspEnvironment, 0, 0);
1346             break;
1347
1348         /* Reset and start uploaded program                     */
1349         case RUN_MODE:
1350             ControlModemLines(IspEnvironment, 1, 0);
1351             Sleep(100);
1352             ClearSerialPortBuffers(IspEnvironment);
1353             Sleep(100);
1354             ControlModemLines(IspEnvironment, 0, 0);
1355             Sleep(100);
1356             break;
1357         }
1358     }
1359 }
1360
1361
1362 /***************************** Ascii2Hex ********************************/
1363 /**  Converts a hex character to its equivalent number value. In case of an
1364 error rather abruptly terminates the program.
1365 \param [in] c the hex digit to convert.
1366 \return the value of the hex digit.
1367 */
1368 static unsigned char Ascii2Hex(unsigned char c)
1369 {
1370     if (c >= '0' && c <= '9')
1371     {
1372         return (unsigned char)(c - '0');
1373     }
1374
1375     if (c >= 'A' && c <= 'F')
1376     {
1377         return (unsigned char)(c - 'A' + 10);
1378     }
1379
1380     if (c >= 'a' && c <= 'f')
1381     {
1382         return (unsigned char)(c - 'a' + 10);
1383     }
1384
1385     DebugPrintf(1, "Wrong Hex-Nibble %c (%02X)\n", c, c);
1386     exit(1);
1387
1388     return 0;  // this "return" will never be reached, but some compilers give a warning if it is not present
1389 }
1390
1391
1392 /***************************** AddFileHex *******************************/
1393 /**  Add a file to the list of files to read in, flag it as hex format.
1394 \param [in] IspEnvironment Programming environment.
1395 \param [in] arg The argument that was passed to the program as a file name.
1396 \return 0 on success, an error code otherwise.
1397 */
1398 static int AddFileHex(ISP_ENVIRONMENT *IspEnvironment, const char *arg)
1399 {
1400     FILE_LIST *entry;
1401
1402     // Add file to list.  If cannot allocate storage for node return an error.
1403     entry = malloc(sizeof(FILE_LIST));
1404     if( entry == 0)
1405     {
1406         DebugPrintf(1, "Error %d Could not allocated memory for file node %s\n", ERR_ALLOC_FILE_LIST, arg);
1407         return  ERR_ALLOC_FILE_LIST;
1408     }
1409
1410     // Build up entry and insert it at the start of the list.
1411     entry->name = arg;
1412     entry->prev = IspEnvironment->f_list;
1413     entry->hex_flag = 1;
1414     IspEnvironment->f_list = entry;
1415
1416     return 0;       // Success.
1417 }
1418
1419
1420 /***************************** AddFileBinary ****************************/
1421 /**  Add a file to the list of files to read in, flag it as binary format.
1422 \param [in] IspEnvironment Programming environment.
1423 \param [in] arg The argument that was passed to the program as a file name.
1424 \return 0 on success, an error code otherwise.
1425 */
1426 static int AddFileBinary(ISP_ENVIRONMENT *IspEnvironment, const char *arg)
1427 {
1428     FILE_LIST *entry;
1429
1430     // Add file to list. If cannot allocate storage for node return an error.
1431     entry = malloc(sizeof(FILE_LIST));
1432     if( entry == 0)
1433     {
1434         DebugPrintf( 1, "Error %d Could not allocated memory for file node %s\n", ERR_ALLOC_FILE_LIST, arg);
1435         return  ERR_ALLOC_FILE_LIST;
1436     }
1437
1438     // Build up entry and insert it at the start of the list.
1439     entry->name = arg;
1440     entry->prev = IspEnvironment->f_list;
1441     entry->hex_flag = 0;
1442     IspEnvironment->f_list = entry;
1443
1444     return 0;       // Success.
1445 }
1446
1447 #if 0
1448 void ReadHexFile(ISP_ENVIRONMENT *IspEnvironment)
1449 {
1450     LoadFile(IspEnvironment);
1451
1452     if (IspEnvironment->BinaryLength)
1453     {
1454         BINARY* FileContent = IspEnvironment->FileContent;
1455
1456         unsigned long  Pos;
1457         unsigned char  RecordLength;
1458         unsigned short RecordAddress;
1459         unsigned long  RealAddress = 0;
1460         unsigned char  RecordType;
1461         unsigned char  Hexvalue;
1462         unsigned long  StartAddress;
1463         int            BinaryOffsetDefined = 0;
1464         unsigned char  i;
1465
1466
1467         DebugPrintf(3, "Converting file %s to binary format...\n", IspEnvironment->input_file);
1468
1469         Pos = 0;
1470         while (Pos < IspEnvironment->BinaryLength)
1471         {
1472             if (FileContent[Pos] == '\r')
1473             {
1474                 Pos++;
1475                 continue;
1476             }
1477
1478             if (FileContent[Pos] == '\n')
1479             {
1480                 Pos++;
1481                 continue;
1482             }
1483
1484             if (FileContent[Pos] != ':')
1485             {
1486                 DebugPrintf(1, "Missing start of record (':') wrong byte %c / %02X\n", FileContent[Pos], FileContent[Pos]);
1487                 exit(1);
1488             }
1489
1490             Pos++;
1491
1492             RecordLength   = Ascii2Hex(FileContent[Pos++]);
1493             RecordLength <<= 4;
1494             RecordLength  |= Ascii2Hex(FileContent[Pos++]);
1495
1496             DebugPrintf(4, "RecordLength = %02X\n", RecordLength);
1497
1498             RecordAddress   = Ascii2Hex(FileContent[Pos++]);
1499             RecordAddress <<= 4;
1500             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
1501             RecordAddress <<= 4;
1502             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
1503             RecordAddress <<= 4;
1504             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
1505
1506             DebugPrintf(4, "RecordAddress = %04X\n", RecordAddress);
1507
1508             RealAddress = RealAddress - (RealAddress & 0xffff) + RecordAddress;
1509
1510             DebugPrintf(4, "RealAddress = %08lX\n", RealAddress);
1511
1512             RecordType      = Ascii2Hex(FileContent[Pos++]);
1513             RecordType    <<= 4;
1514             RecordType     |= Ascii2Hex(FileContent[Pos++]);
1515
1516             DebugPrintf(4, "RecordType = %02X\n", RecordType);
1517
1518             if (RecordType == 0x00)          // 00 - Data record
1519             {
1520                 /*
1521                 * Binary Offset is defined as soon as first data record read
1522                 */
1523
1524                 //BinaryOffsetDefined = 1;
1525
1526                 // Memory for binary file big enough ?
1527                 while ((RealAddress + RecordLength - IspEnvironment->BinaryOffset) > IspEnvironment->BinaryMemSize)
1528                 {
1529                     IspEnvironment->BinaryMemSize <<= 1;    // Double the size allocated !!!
1530                     IspEnvironment->BinaryContent = (BINARY*) realloc(IspEnvironment->BinaryContent, IspEnvironment->BinaryMemSize);
1531                 }
1532
1533                 // We need to know, what the highest address is,
1534                 // how many bytes / sectors we must flash
1535                 if (RealAddress + RecordLength - IspEnvironment->BinaryOffset > IspEnvironment->BinaryLength)
1536                 {
1537                     IspEnvironment->BinaryLength = RealAddress + RecordLength - IspEnvironment->BinaryOffset;
1538                     DebugPrintf(3, "Image size now: %ld\n", IspEnvironment->BinaryLength);
1539                 }
1540
1541                 for (i = 0; i < RecordLength; i++)
1542                 {
1543                     Hexvalue        = Ascii2Hex(FileContent[Pos++]);
1544                     Hexvalue      <<= 4;
1545                     Hexvalue       |= Ascii2Hex(FileContent[Pos++]);
1546                     IspEnvironment->BinaryContent[RealAddress + i - IspEnvironment->BinaryOffset] = Hexvalue;
1547                 }
1548             }
1549             else if (RecordType == 0x01)     // 01 - End of file record
1550             {
1551                 break;
1552             }
1553             else if (RecordType == 0x02)     // 02 - Extended segment address record
1554             {
1555                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1556                 {
1557                     RealAddress <<= 4;
1558                     if (i == 0)
1559                     {
1560                         RealAddress  = Ascii2Hex(FileContent[Pos++]);
1561                     }
1562                     else
1563                     {
1564                         RealAddress |= Ascii2Hex(FileContent[Pos++]);
1565                     }
1566                 }
1567                 RealAddress <<= 4;
1568             }
1569             else if (RecordType == 0x03)     // 03 - Start segment address record
1570             {
1571                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1572                 {
1573                     RealAddress <<= 4;
1574                     if (i == 0)
1575                     {
1576                         RealAddress  = Ascii2Hex(FileContent[Pos++]);
1577                     }
1578                     else
1579                     {
1580                         RealAddress |= Ascii2Hex(FileContent[Pos++]);
1581                     }
1582                 }
1583                 RealAddress <<= 8;
1584             }
1585             else if (RecordType == 0x04)     // 04 - Extended linear address record, used by IAR
1586             {
1587                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1588                 {
1589                     RealAddress <<= 4;
1590                     if (i == 0)
1591                     {
1592                         RealAddress  = Ascii2Hex(FileContent[Pos++]);
1593                     }
1594                     else
1595                     {
1596                         RealAddress |= Ascii2Hex(FileContent[Pos++]);
1597                     }
1598                 }
1599                 RealAddress <<= 16;
1600                 if (!BinaryOffsetDefined)
1601                 {
1602                     // set startaddress of BinaryContent
1603                     // use of LPC_FLASHMASK to allow a memory range, not taking the first
1604                     // [04] record as actual start-address.
1605                     IspEnvironment->BinaryOffset = RealAddress & LPC_FLASHMASK;
1606                 }
1607                 else
1608                 {
1609                     if ((RealAddress & LPC_FLASHMASK) != IspEnvironment->BinaryOffset)
1610                     {
1611                         DebugPrintf(1, "New Extended Linear Address Record [04] out of memory range\n"
1612                                        "Current Memory starts at: 0x%08X, new Address is: 0x%08X",
1613                                        IspEnvironment->BinaryOffset, RealAddress);
1614                         exit(1);
1615                     }
1616                 }
1617             }
1618             else if (RecordType == 0x05)     // 05 - Start linear address record
1619             {
1620                 StartAddress = 0;
1621                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1622                 {
1623                     StartAddress <<= 4;
1624                     if (i == 0)
1625                     {
1626                         StartAddress  = Ascii2Hex(FileContent[Pos++]);
1627                     }
1628                     else
1629                     {
1630                         StartAddress |= Ascii2Hex(FileContent[Pos++]);
1631                     }
1632                 }
1633                 DebugPrintf(1,"Start Address = 0x%08X\n", StartAddress);
1634                 IspEnvironment->StartAddress = StartAddress;
1635             }
1636
1637             while (FileContent[Pos++] != 0x0a)      // Search till line end
1638             {
1639             }
1640         }
1641
1642         DebugPrintf(2, "\tconverted to binary format...\n");
1643
1644         // When debugging is switched on, output result of conversion to file debugout.bin
1645         if (debug_level >= 4)
1646         {
1647             int fdout;
1648             fdout = open("debugout.bin", O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0777);
1649             write(fdout, IspEnvironment->BinaryContent, IspEnvironment->BinaryLength);
1650             close(fdout);
1651         }
1652     }
1653 }
1654 #endif // #if 0
1655
1656
1657 /***************************** LoadFile *********************************/
1658 /**  Loads the requested file to download into memory.
1659 \param [in] IspEnvironment  structure containing input filename
1660 \param [in] filename    the name of the file to read in.
1661 \param [in] FileFormat  the format of the file to read in (FORMAT_HEX or FORMAT_BINARY)
1662 \return 0 if successful, otherwise an error code.
1663 */
1664 static int LoadFile(ISP_ENVIRONMENT *IspEnvironment, const char *filename, int FileFormat)
1665 {
1666     int            fd;
1667     int            i;
1668     int            BinaryOffsetDefined;
1669     unsigned long  Pos;
1670     unsigned long  FileLength;
1671     BINARY        *FileContent;              /**< Used to store the content of a hex */
1672                                              /*   file before converting to binary.  */
1673     unsigned long  BinaryMemSize;
1674
1675     fd = open(filename, O_RDONLY | O_BINARY);
1676     if (fd == -1)
1677     {
1678         DebugPrintf(1, "Can't open file %s\n", filename);
1679         return ERR_FILE_OPEN_HEX;
1680     }
1681
1682     FileLength = lseek(fd, 0L, 2);      // Get file size
1683
1684     if (FileLength == (size_t)-1)
1685     {
1686         DebugPrintf(1, "\nFileLength = -1 !?!\n");
1687         return ERR_FILE_SIZE_HEX;
1688     }
1689
1690     lseek(fd, 0L, 0);
1691
1692     // Just read the entire file into memory to parse.
1693     FileContent = (BINARY*) malloc(FileLength);
1694
1695     if( FileContent == 0)
1696     {
1697         DebugPrintf( 1, "\nCouldn't allocate enough memory for file.\n");
1698         return ERR_FILE_ALLOC_HEX;
1699     }
1700
1701     BinaryOffsetDefined = 0;
1702
1703     BinaryMemSize = IspEnvironment->BinaryLength;
1704
1705     read(fd, FileContent, FileLength);
1706
1707     close(fd);
1708
1709     DebugPrintf(2, "File %s:\n\tloaded...\n", filename);
1710
1711     // Intel-Hex -> Binary Conversion
1712
1713     if (FileFormat == FORMAT_HEX)
1714     {
1715         unsigned char  RecordLength;
1716         unsigned short RecordAddress;
1717         unsigned long  RealAddress = 0;
1718         unsigned char  RecordType;
1719         unsigned char  Hexvalue;
1720         unsigned long  StartAddress;
1721
1722         DebugPrintf(3, "Converting file %s to binary format...\n", filename);
1723
1724         Pos = 0;
1725         while (Pos < FileLength)
1726         {
1727             if (FileContent[Pos] == '\r')
1728             {
1729                 Pos++;
1730                 continue;
1731             }
1732
1733             if (FileContent[Pos] == '\n')
1734             {
1735                 Pos++;
1736                 continue;
1737             }
1738
1739             if (FileContent[Pos] != ':')
1740             {
1741                 DebugPrintf(1, "Missing start of record (':') wrong byte %c / %02X\n", FileContent[Pos], FileContent[Pos]);
1742                 exit(1);
1743             }
1744
1745             Pos++;
1746
1747             RecordLength   = Ascii2Hex(FileContent[Pos++]);
1748             RecordLength <<= 4;
1749             RecordLength  |= Ascii2Hex(FileContent[Pos++]);
1750
1751             DebugPrintf(4, "RecordLength = %02X\n", RecordLength);
1752
1753             RecordAddress   = Ascii2Hex(FileContent[Pos++]);
1754             RecordAddress <<= 4;
1755             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
1756             RecordAddress <<= 4;
1757             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
1758             RecordAddress <<= 4;
1759             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
1760
1761             DebugPrintf(4, "RecordAddress = %04X\n", RecordAddress);
1762
1763             RealAddress = RealAddress - (RealAddress & 0xffff) + RecordAddress;
1764
1765             DebugPrintf(4, "RealAddress = %08lX\n", RealAddress);
1766
1767             RecordType      = Ascii2Hex(FileContent[Pos++]);
1768             RecordType    <<= 4;
1769             RecordType     |= Ascii2Hex(FileContent[Pos++]);
1770
1771             DebugPrintf(4, "RecordType = %02X\n", RecordType);
1772
1773             if (RecordType == 0x00)          // 00 - Data record
1774             {
1775                 /*
1776                 * Binary Offset is defined as soon as first data record read
1777                 */
1778                 BinaryOffsetDefined = 1;
1779                 // Memory for binary file big enough ?
1780                 while (RealAddress + RecordLength - IspEnvironment->BinaryOffset > BinaryMemSize)
1781                 {
1782                     if(!BinaryMemSize) BinaryMemSize = FileLength * 2;
1783                     else BinaryMemSize <<= 1;
1784                     IspEnvironment->BinaryContent = realloc(IspEnvironment->BinaryContent, BinaryMemSize);
1785                 }
1786
1787                 // We need to know, what the highest address is,
1788                 // how many bytes / sectors we must flash
1789                 if (RealAddress + RecordLength - IspEnvironment->BinaryOffset > IspEnvironment->BinaryLength)
1790                 {
1791                     IspEnvironment->BinaryLength = RealAddress + RecordLength - IspEnvironment->BinaryOffset;
1792                     DebugPrintf(3, "Image size now: %ld\n", IspEnvironment->BinaryLength);
1793                 }
1794
1795                 for (i = 0; i < RecordLength; i++)
1796                 {
1797                     Hexvalue        = Ascii2Hex(FileContent[Pos++]);
1798                     Hexvalue      <<= 4;
1799                     Hexvalue       |= Ascii2Hex(FileContent[Pos++]);
1800                     IspEnvironment->BinaryContent[RealAddress + i - IspEnvironment->BinaryOffset] = Hexvalue;
1801                 }
1802             }
1803             else if (RecordType == 0x01)     // 01 - End of file record
1804             {
1805                 break;
1806             }
1807             else if (RecordType == 0x02)     // 02 - Extended segment address record
1808             {
1809                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1810                 {
1811                     RealAddress <<= 4;
1812                     if (i == 0)
1813                     {
1814                         RealAddress  = Ascii2Hex(FileContent[Pos++]);
1815                     }
1816                     else
1817                     {
1818                         RealAddress |= Ascii2Hex(FileContent[Pos++]);
1819                     }
1820                 }
1821                 RealAddress <<= 4;
1822             }
1823             else if (RecordType == 0x03)     // 03 - Start segment address record
1824             {
1825                 unsigned long cs,ip;
1826                 StartAddress = 0;
1827                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1828                 {
1829                     StartAddress <<= 4;
1830                     if (i == 0)
1831                     {
1832                         StartAddress  = Ascii2Hex(FileContent[Pos++]);
1833                     }
1834                     else
1835                     {
1836                         StartAddress |= Ascii2Hex(FileContent[Pos++]);
1837                     }
1838                 }
1839                 cs = StartAddress >> 16; //high part
1840                 ip = StartAddress & 0xffff; //low part
1841                 StartAddress = cs*16+ip; //segmented 20-bit space
1842                 DebugPrintf(1,"Start Address = 0x%08X\n", StartAddress);
1843                 IspEnvironment->StartAddress = StartAddress;
1844             }
1845             else if (RecordType == 0x04)     // 04 - Extended linear address record, used by IAR
1846             {
1847                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1848                 {
1849                     RealAddress <<= 4;
1850                     if (i == 0)
1851                     {
1852                         RealAddress  = Ascii2Hex(FileContent[Pos++]);
1853                     }
1854                     else
1855                     {
1856                         RealAddress |= Ascii2Hex(FileContent[Pos++]);
1857                     }
1858                 }
1859                 RealAddress <<= 16;
1860                 if (!BinaryOffsetDefined)
1861                 {
1862                     // set startaddress of BinaryContent
1863                     // use of LPC_FLASHMASK to allow a memory range, not taking the first
1864                     // [04] record as actual start-address.
1865                     IspEnvironment->BinaryOffset = RealAddress & LPC_FLASHMASK;
1866                 }
1867                 else
1868                 {
1869                     if ((RealAddress & LPC_FLASHMASK) != IspEnvironment->BinaryOffset)
1870                     {
1871                         DebugPrintf(1, "New Extended Linear Address Record [04] out of memory range\n");
1872                         DebugPrintf(1, "Current Memory starts at: 0x%08X, new Address is: 0x%08X",
1873                             IspEnvironment->BinaryOffset, RealAddress);
1874                         return ERR_MEMORY_RANGE;
1875                     }
1876                 }
1877             }
1878             else if (RecordType == 0x05)     // 05 - Start linear address record
1879             {
1880                 StartAddress = 0;
1881                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1882                 {
1883                     StartAddress <<= 4;
1884                     if (i == 0)
1885                     {
1886                         StartAddress  = Ascii2Hex(FileContent[Pos++]);
1887                     }
1888                     else
1889                     {
1890                         StartAddress |= Ascii2Hex(FileContent[Pos++]);
1891                     }
1892                 }
1893                 DebugPrintf(1,"Start Address = 0x%08X\n", StartAddress);
1894                 IspEnvironment->StartAddress = StartAddress;
1895             }
1896             else
1897             {
1898                 free( FileContent);
1899                 DebugPrintf( 1, "Error %d RecordType %02X not yet implemented\n", ERR_RECORD_TYPE_LOADFILE, RecordType);
1900                 return( ERR_RECORD_TYPE_LOADFILE);
1901             }
1902
1903             while (FileContent[Pos++] != 0x0a)      // Search till line end
1904             {
1905             }
1906         }
1907
1908         DebugPrintf(2, "\tconverted to binary format...\n");
1909
1910         // When debugging is switched on, output result of conversion to file debugout.bin
1911         if (debug_level >= 4)
1912         {
1913             int fdout;
1914             fdout = open("debugout.bin", O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0777);
1915             write(fdout, IspEnvironment->BinaryContent, IspEnvironment->BinaryLength);
1916             close(fdout);
1917         }
1918
1919         free( FileContent);             // Done with file contents
1920     }
1921     else // FORMAT_BINARY
1922     {
1923         IspEnvironment->BinaryContent = FileContent;
1924         IspEnvironment->BinaryLength = FileLength;
1925     }
1926
1927     DebugPrintf(2, "\timage size : %ld\n", IspEnvironment->BinaryLength);
1928
1929     return 0;
1930 }
1931
1932 /***************************** LoadFiles1 ********************************/
1933 /**  Loads the requested files to download into memory.
1934 \param [in] IspEnvironment structure containing input filename(s).
1935 \param [in] file simple linked list of files to read
1936 \return 0 if successful, otherwise an error code.
1937 */
1938 static int LoadFiles1(ISP_ENVIRONMENT *IspEnvironment, const FILE_LIST *file)
1939 {
1940     int ret_val;
1941
1942     if( file->prev != 0)
1943     {
1944         DebugPrintf( 3, "Follow file list %s\n", file->name);
1945
1946         ret_val = LoadFiles1( IspEnvironment, file->prev);
1947                 if( ret_val != 0)
1948                 {
1949                         return ret_val;
1950                 }
1951     }
1952
1953     DebugPrintf( 3, "Attempt to read File %s\n", file->name);
1954     if(file->hex_flag != 0)
1955     {
1956         ret_val = LoadFile(IspEnvironment, file->name, FORMAT_HEX);
1957     }
1958     else
1959     {
1960                 ret_val = LoadFile(IspEnvironment, file->name, FORMAT_BINARY);
1961     }
1962     if( ret_val != 0)
1963     {
1964                 return ret_val;
1965     }
1966
1967     return 0;
1968 }
1969
1970 /***************************** LoadFiles ********************************/
1971 /**  Loads the requested files to download into memory.
1972 \param [in] IspEnvironment structure containing input filename(s).
1973 \param [in] file simple linked list of files to read
1974 \return 0 if successful, otherwise an error code.
1975 */
1976 static int LoadFiles(ISP_ENVIRONMENT *IspEnvironment)
1977 {
1978         int ret_val;
1979
1980     ret_val = LoadFiles1(IspEnvironment, IspEnvironment->f_list);
1981     if( ret_val != 0)
1982     {
1983                 exit(1); // return ret_val;
1984     }
1985
1986         DebugPrintf( 2, "Image size : %ld\n", IspEnvironment->BinaryLength);
1987
1988     // check length to flash for correct alignment, can happen with broken ld-scripts
1989     if (IspEnvironment->BinaryLength % 4 != 0)
1990     {
1991         unsigned long NewBinaryLength = ((IspEnvironment->BinaryLength + 3)/4) * 4;
1992
1993         DebugPrintf( 2, "Warning:  data not aligned to 32 bits, padded (length was %lX, now %lX)\n", IspEnvironment->BinaryLength, NewBinaryLength);
1994
1995         IspEnvironment->BinaryLength = NewBinaryLength;
1996     }
1997
1998         // When debugging is switched on, output result of conversion to file debugout.bin
1999     if(debug_level >= 4)
2000     {
2001          int fdout;
2002                  DebugPrintf( 1, "Dumping image file.\n");
2003          fdout = open("debugout.bin", O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0777);
2004          write(fdout, IspEnvironment->BinaryContent, IspEnvironment->BinaryLength);
2005          close(fdout);
2006     }
2007     return 0;
2008 }
2009 #endif // !defined COMPILE_FOR_LPC21
2010
2011 #ifndef COMPILE_FOR_LPC21
2012 int PerformActions(ISP_ENVIRONMENT *IspEnvironment)
2013 {
2014     int downloadResult = -1;
2015
2016     DebugPrintf(2, "lpc21isp version " VERSION_STR "\n");
2017
2018     /* Download requested, read in the input file.                  */
2019     if (IspEnvironment->ProgramChip)
2020     {
2021         LoadFiles(IspEnvironment);
2022     }
2023
2024     OpenSerialPort(IspEnvironment);   /* Open the serial port to the microcontroller. */
2025
2026     ResetTarget(IspEnvironment, PROGRAM_MODE);
2027
2028     ClearSerialPortBuffers(IspEnvironment);
2029
2030     /* Perform the requested download.                              */
2031     if (IspEnvironment->ProgramChip || IspEnvironment->DetectOnly)
2032     {
2033         switch (IspEnvironment->micro)
2034         {
2035 #ifdef LPC_SUPPORT
2036         case PHILIPS_ARM:
2037             downloadResult = PhilipsDownload(IspEnvironment);
2038             break;
2039 #endif
2040
2041 #ifdef AD_SUPPORT
2042         case ANALOG_DEVICES_ARM:
2043             downloadResult = AnalogDevicesDownload(IspEnvironment);
2044             break;
2045 #endif
2046         }
2047
2048         if (downloadResult != 0)
2049         {
2050             CloseSerialPort(IspEnvironment);
2051             exit(downloadResult);
2052         }
2053     }
2054
2055     if (IspEnvironment->StartAddress == 0 || IspEnvironment->TerminalOnly)
2056     {
2057         /* Only reset target if startaddress = 0
2058         * Otherwise stay with the running program as started in Download()
2059         */
2060         ResetTarget(IspEnvironment, RUN_MODE);
2061     }
2062
2063     debug_level = 1;    /* From now on there is no more debug output !! */
2064                                         /* Therefore switch it off...                   */
2065
2066 #ifdef TERMINAL_SUPPORT
2067     // Pass control to Terminal which will provide a terminal if one was asked for
2068     // User asked for terminal emulation, provide a really dumb terminal.
2069     Terminal(IspEnvironment);
2070 #endif
2071
2072     CloseSerialPort(IspEnvironment);  /*  All done, close the serial port to the      */
2073
2074     return 0;
2075 }
2076 #endif
2077
2078 /***************************** main *************************************/
2079 /**  main. Everything starts from here.
2080 \param [in] argc the number of arguments.
2081 \param [in] argv an array of pointers to the arguments.
2082 */
2083
2084 #if !defined COMPILE_FOR_LPC21
2085
2086 #if defined INTEGRATED_IN_WIN_APP
2087 int AppDoProgram(int argc, char *argv[])
2088 #else
2089 int main(int argc, char *argv[])
2090 #endif
2091 {
2092     ISP_ENVIRONMENT IspEnvironment;
2093
2094     // Initialize debug level
2095     debug_level = 2;
2096
2097     // Initialize ISP Environment
2098     memset(&IspEnvironment, 0, sizeof(IspEnvironment));       // Clear the IspEnviroment to a known value
2099     IspEnvironment.micro       = PHILIPS_ARM;                 // Default Micro
2100     IspEnvironment.FileFormat  = FORMAT_HEX;                  // Default File Format
2101     IspEnvironment.ProgramChip = TRUE;                        // Default to Programming the chip
2102     IspEnvironment.nQuestionMarks = 100;
2103     IspEnvironment.DoNotStart = 0;
2104     ReadArguments(&IspEnvironment, argc, argv);               // Read and parse the command line
2105
2106     return PerformActions(&IspEnvironment);                   // Do as requested !
2107 }
2108
2109 #endif // !defined COMPILE_FOR_LPC21
2110
2111 /***************************** DumpString ******************************/
2112 /**  Prints an area of memory to stdout. Converts non-printables to hex.
2113 \param [in] level the debug level of the block to be dumped.  If this is
2114 less than or equal to the current debug level than the dump will happen
2115 otherwise this just returns.
2116 \param [in] b pointer to an area of memory.
2117 \param [in] size the length of the memory block to print.
2118 \param [in] prefix string is a pointer to a prefix string.
2119 */
2120 void DumpString(int level, const void *b, size_t size, const char *prefix_string)
2121 {
2122     size_t i;
2123     const char * s = (const char*) b;
2124     unsigned char c;
2125
2126     DebugPrintf(level, prefix_string);
2127
2128     DebugPrintf(level, "'");
2129     for (i = 0; i < size; i++)
2130     {
2131         c = s[i];
2132         if (c >= 0x20 && c <= 0x7e) /*isprint?*/
2133         {
2134             DebugPrintf(level, "%c", c);
2135         }
2136         else
2137         {
2138             DebugPrintf(level, "(%02X)", c);
2139         }
2140     }
2141     DebugPrintf(level, "'\n");
2142 }
2143
2144 #if !defined COMPILE_FOR_LPC21
2145 int lpctest(char* FileName)
2146 {
2147     ISP_ENVIRONMENT IspEnvironment;
2148
2149     // Initialize debug level
2150     debug_level = 2;
2151
2152     // Initialize ISP Environment
2153     memset(&IspEnvironment, 0, sizeof(IspEnvironment));        // Clear the IspEnviroment to a known value
2154     IspEnvironment.micro        = PHILIPS_ARM;                 // Default Micro
2155     IspEnvironment.FileFormat   = FORMAT_HEX;                  // Default File Format
2156     IspEnvironment.ProgramChip  = TRUE;                        // Default to Programming the chip
2157     // IspEnvironment.input_file   = FileName;
2158     IspEnvironment.ControlLines = TRUE;
2159     IspEnvironment.serial_port  = "COM2";
2160     IspEnvironment.baud_rate    = "19200";
2161     IspEnvironment.nQuestionMarks = 100;
2162     IspEnvironment.DoNotStart = 0;
2163     strcpy(IspEnvironment.StringOscillator, "25000");
2164
2165     return PerformActions(&IspEnvironment);                    // Do as requested !
2166 }
2167 #endif