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