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-2014, 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 1.95   2014-01-08 Martin Maurer
392                   Add a lot of new chip ids for LPC1763, LPC11Exx, LPC11Uxx
393                   (completely untested because I don't have these chips)
394                   Corrected checking of 2 field chip ids (must be masked)
395                   Corrected Makefile (-static)
396                   Move while directory with files into a subdirectory
397 1.96   2014-01-08 Martin Maurer merged changes by Moses McKnight
398                   Added devices: LPC1315, LPC1316, LPC1317, LPC1345, LPC1346, LPC1347
399                   Add .gitignore file (MM: Removed *.layout)
400                   Remove lpc21isp.depend
401        2014-01-08 Martin Maurer merged bugfix by smartavionics:
402                   - Wrong length in ReceiveComPort
403                   - Enable SerialTimeoutTick
404        2014-01-08 Martin Maurer merged bugfix by justyn:
405                   - Fix the total sector size fields for 1114.../323 and 1114.../333
406        2014-01-08 Martin Maurer merged bugfix by imyller:
407                   - Support for bad UARTs: added -writedelay command-line switch
408 1.97   2014-01-09 Martin Maurer
409                   Add some new chip ids for LPC11xx
410                   Updated .gitignore file (Now with ignored *.layout)
411                   Removed *.layout from lpc21isp project
412                   Removed *.depend from lpc21isp project
413 */
414 
415 // Please don't use TABs in the source code !!!
416 
417 // Don't forget to update the version string that is on the next line
418 #define VERSION_STR "1.97"
419 
420 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
421 static char RxTmpBuf[256];        // save received data to this buffer for half-duplex
422 char * pRxTmpBuf = RxTmpBuf;
423 #endif
424 
425 #if !defined COMPILE_FOR_LPC21
426 int debug_level = 2;
427 #endif
428 
429 static void ControlModemLines(ISP_ENVIRONMENT *IspEnvironment, unsigned char DTR, unsigned char RTS);
430 static unsigned char Ascii2Hex(unsigned char c);
431 
432 #ifdef COMPILE_FOR_WINDOWS
433 static void SerialTimeoutSet(ISP_ENVIRONMENT *IspEnvironment, unsigned timeout_milliseconds);
434 static int SerialTimeoutCheck(ISP_ENVIRONMENT *IspEnvironment);
435 #endif // COMPILE_FOR_WINDOWS
436 
437 static int AddFileHex(ISP_ENVIRONMENT *IspEnvironment, const char *arg);
438 static int AddFileBinary(ISP_ENVIRONMENT *IspEnvironment, const char *arg);
439 static int LoadFile(ISP_ENVIRONMENT *IspEnvironment, const char *filename, int FileFormat);
440 
441 /************* Portability layer. Serial and console I/O differences    */
442 /* are taken care of here.                                              */
443 
444 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
OpenSerialPort(ISP_ENVIRONMENT * IspEnvironment)445 static void OpenSerialPort(ISP_ENVIRONMENT *IspEnvironment)
446 {
447     DCB    dcb;
448     COMMTIMEOUTS commtimeouts;
449 
450 #ifdef _MSC_VER
451     /* Torsten Lang 2013-05-06 Switch to higher timer resolution (we want to use 1ms timeouts in the serial device driver!) */
452     (void)timeBeginPeriod(1UL);
453 #endif // _MSC_VER
454 
455     IspEnvironment->hCom = CreateFile(IspEnvironment->serial_port, GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
456 
457     if (IspEnvironment->hCom == INVALID_HANDLE_VALUE)
458     {
459         DebugPrintf(1, "Can't open COM-Port %s ! - Error: %ld\n", IspEnvironment->serial_port, GetLastError());
460         exit(2);
461     }
462 
463     DebugPrintf(3, "COM-Port %s opened...\n", IspEnvironment->serial_port);
464 
465     GetCommState(IspEnvironment->hCom, &dcb);
466     dcb.BaudRate    = atol(IspEnvironment->baud_rate);
467     dcb.ByteSize    = 8;
468     dcb.StopBits    = ONESTOPBIT;
469     dcb.Parity      = NOPARITY;
470     dcb.fDtrControl = DTR_CONTROL_DISABLE;
471     dcb.fOutX       = TRUE; // TL TODO - according to LPC manual! FALSE;
472     dcb.fInX        = TRUE; // TL TODO - according to LPC manual! FALSE;
473     dcb.fNull       = FALSE;
474     dcb.fRtsControl = RTS_CONTROL_DISABLE;
475 
476     // added by Herbert Demmel - iF CTS line has the wrong state, we would never send anything!
477     dcb.fOutxCtsFlow = FALSE;
478     dcb.fOutxDsrFlow = FALSE;
479 
480     if (SetCommState(IspEnvironment->hCom, &dcb) == 0)
481     {
482         DebugPrintf(1, "Can't set baudrate %s ! - Error: %ld", IspEnvironment->baud_rate, GetLastError());
483         exit(3);
484     }
485 
486    /*
487     *  Peter Hayward 02 July 2008
488     *
489     *  The following call is only needed if the WaitCommEvent
490     *  or possibly the GetCommMask functions are used.  They are
491     *  *not* in this implimentation.  However, under Windows XP SP2
492     *  on my laptop the use of this call causes XP to freeze (crash) while
493     *  this program is running, e.g. in section 5/6/7 ... of a largish
494     *  download.  Removing this *unnecessary* call fixed the problem.
495     *  At the same time I've added a call to SetupComm to request
496     *  (not necessarity honoured) the operating system to provide
497     *  large I/O buffers for high speed I/O without handshaking.
498     *
499     *   SetCommMask(IspEnvironment->hCom,EV_RXCHAR | EV_TXEMPTY);
500     */
501     SetupComm(IspEnvironment->hCom, 32000, 32000);
502 
503     SetCommMask(IspEnvironment->hCom, EV_RXCHAR | EV_TXEMPTY);
504 
505     // Torsten Lang 2013-05-06: ReadFile may hang indefinitely with MAXDWORD/0/1/0/0 on FTDI devices!!!
506     commtimeouts.ReadIntervalTimeout         = MAXDWORD;
507     commtimeouts.ReadTotalTimeoutMultiplier  = MAXDWORD;
508     commtimeouts.ReadTotalTimeoutConstant    =    1;
509     commtimeouts.WriteTotalTimeoutMultiplier =    0;
510     commtimeouts.WriteTotalTimeoutConstant   =    0;
511     SetCommTimeouts(IspEnvironment->hCom, &commtimeouts);
512 }
513 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
514 
515 #if defined COMPILE_FOR_LINUX
OpenSerialPort(ISP_ENVIRONMENT * IspEnvironment)516 static void OpenSerialPort(ISP_ENVIRONMENT *IspEnvironment)
517 {
518     IspEnvironment->fdCom = open(IspEnvironment->serial_port, O_RDWR | O_NOCTTY | O_NONBLOCK);
519 
520     if (IspEnvironment->fdCom < 0)
521     {
522         int err = errno;
523         DebugPrintf(1, "Can't open COM-Port %s ! (Error: %dd (0x%X))\n", IspEnvironment->serial_port, err, err);
524         exit(2);
525     }
526 
527     DebugPrintf(3, "COM-Port %s opened...\n", IspEnvironment->serial_port);
528 
529     /* clear input & output buffers, then switch to "blocking mode" */
530     tcflush(IspEnvironment->fdCom, TCOFLUSH);
531     tcflush(IspEnvironment->fdCom, TCIFLUSH);
532     fcntl(IspEnvironment->fdCom, F_SETFL, fcntl(IspEnvironment->fdCom, F_GETFL) & ~O_NONBLOCK);
533 
534     tcgetattr(IspEnvironment->fdCom, &IspEnvironment->oldtio); /* save current port settings */
535 
536     bzero(&IspEnvironment->newtio, sizeof(IspEnvironment->newtio));
537     IspEnvironment->newtio.c_cflag = CS8 | CLOCAL | CREAD;
538 
539 #if defined(__FreeBSD__) || defined(__OpenBSD__)
540 
541     if(cfsetspeed(&IspEnvironment->newtio,(speed_t) strtol(IspEnvironment->baud_rate,NULL,10))) {
542                   DebugPrintf(1, "baudrate %s not supported\n", IspEnvironment->baud_rate);
543                   exit(3);
544               };
545 #else
546 
547 #ifdef __APPLE__
548 #define NEWTERMIOS_SETBAUDARTE(bps) IspEnvironment->newtio.c_ispeed = IspEnvironment->newtio.c_ospeed = bps;
549 #else
550 #define NEWTERMIOS_SETBAUDARTE(bps) IspEnvironment->newtio.c_cflag |= bps;
551 #endif
552 
553     switch (atol(IspEnvironment->baud_rate))
554     {
555 #ifdef B1152000
556           case 1152000: NEWTERMIOS_SETBAUDARTE(B1152000); break;
557 #endif // B1152000
558 #ifdef B576000
559           case  576000: NEWTERMIOS_SETBAUDARTE(B576000); break;
560 #endif // B576000
561 #ifdef B230400
562           case  230400: NEWTERMIOS_SETBAUDARTE(B230400); break;
563 #endif // B230400
564 #ifdef B115200
565           case  115200: NEWTERMIOS_SETBAUDARTE(B115200); break;
566 #endif // B115200
567 #ifdef B57600
568           case   57600: NEWTERMIOS_SETBAUDARTE(B57600); break;
569 #endif // B57600
570 #ifdef B38400
571           case   38400: NEWTERMIOS_SETBAUDARTE(B38400); break;
572 #endif // B38400
573 #ifdef B19200
574           case   19200: NEWTERMIOS_SETBAUDARTE(B19200); break;
575 #endif // B19200
576 #ifdef B9600
577           case    9600: NEWTERMIOS_SETBAUDARTE(B9600); break;
578 #endif // B9600
579 
580           // Special value
581           // case   32000: NEWTERMIOS_SETBAUDARTE(32000); break;
582 
583           default:
584               {
585                   DebugPrintf(1, "unknown baudrate %s\n", IspEnvironment->baud_rate);
586                   exit(3);
587               }
588     }
589 
590 #endif
591 
592     IspEnvironment->newtio.c_iflag = IGNPAR | IGNBRK | IXON | IXOFF;
593     IspEnvironment->newtio.c_oflag = 0;
594 
595     /* set input mode (non-canonical, no echo,...) */
596     IspEnvironment->newtio.c_lflag = 0;
597 
598     cfmakeraw(&IspEnvironment->newtio);
599     IspEnvironment->newtio.c_cc[VTIME]    = 1;   /* inter-character timer used */
600     IspEnvironment->newtio.c_cc[VMIN]     = 0;   /* blocking read until 0 chars received */
601 
602     tcflush(IspEnvironment->fdCom, TCIFLUSH);
603     if(tcsetattr(IspEnvironment->fdCom, TCSANOW, &IspEnvironment->newtio))
604     {
605        DebugPrintf(1, "Could not change serial port behaviour (wrong baudrate?)\n");
606        exit(3);
607     }
608 
609 }
610 #endif // defined COMPILE_FOR_LINUX
611 
612 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
CloseSerialPort(ISP_ENVIRONMENT * IspEnvironment)613 static void CloseSerialPort(ISP_ENVIRONMENT *IspEnvironment)
614 {
615     CloseHandle(IspEnvironment->hCom);
616 
617 #ifdef _MSC_VER
618     /* Torsten Lang 2013-05-06 Switch back timer resolution */
619     (void)timeEndPeriod(1UL);
620 #endif // _MSC_VER
621 }
622 
623 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
624 
625 #if defined COMPILE_FOR_LINUX
CloseSerialPort(ISP_ENVIRONMENT * IspEnvironment)626 static void CloseSerialPort(ISP_ENVIRONMENT *IspEnvironment)
627 {
628     tcflush(IspEnvironment->fdCom, TCOFLUSH);
629     tcflush(IspEnvironment->fdCom, TCIFLUSH);
630     tcsetattr(IspEnvironment->fdCom, TCSANOW, &IspEnvironment->oldtio);
631 
632     close(IspEnvironment->fdCom);
633 }
634 #endif // defined COMPILE_FOR_LINUX
635 
636 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
ControlXonXoffSerialPort(ISP_ENVIRONMENT * IspEnvironment,unsigned char XonXoff)637 void ControlXonXoffSerialPort(ISP_ENVIRONMENT *IspEnvironment, unsigned char XonXoff)
638 {
639     DCB dcb;
640 
641     GetCommState(IspEnvironment->hCom, &dcb);
642 
643     if(XonXoff)
644     {
645         dcb.fOutX = TRUE;
646         dcb.fInX  = TRUE;
647     }
648     else
649     {
650         dcb.fOutX = FALSE;
651         dcb.fInX  = FALSE;
652     }
653 
654     if (SetCommState(IspEnvironment->hCom, &dcb) == 0)
655     {
656         DebugPrintf(1, "Can't set XonXoff ! - Error: %ld", GetLastError());
657         exit(3);
658     }
659 }
660 
661 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
662 
663 #if defined COMPILE_FOR_LINUX
ControlXonXoffSerialPort(ISP_ENVIRONMENT * IspEnvironment,unsigned char XonXoff)664 void ControlXonXoffSerialPort(ISP_ENVIRONMENT *IspEnvironment, unsigned char XonXoff)
665 {
666     if(tcgetattr(IspEnvironment->fdCom, &IspEnvironment->newtio))
667     {
668        DebugPrintf(1, "Could not get serial port behaviour\n");
669        exit(3);
670     }
671 
672     if(XonXoff)
673     {
674       IspEnvironment->newtio.c_iflag |= IXON;
675       IspEnvironment->newtio.c_iflag |= IXOFF;
676     }
677     else
678     {
679       IspEnvironment->newtio.c_iflag &= ~IXON;
680       IspEnvironment->newtio.c_iflag &= ~IXOFF;
681     }
682 
683     if(tcsetattr(IspEnvironment->fdCom, TCSANOW, &IspEnvironment->newtio))
684     {
685        DebugPrintf(1, "Could not set serial port behaviour\n");
686        exit(3);
687     }
688 }
689 #endif // defined COMPILE_FOR_LINUX
690 
691 /***************************** SendComPortBlock *************************/
692 /**  Sends a block of bytes out the opened com port.
693 \param [in] s block to send.
694 \param [in] n size of the block.
695 */
SendComPortBlock(ISP_ENVIRONMENT * IspEnvironment,const void * s,size_t n)696 void SendComPortBlock(ISP_ENVIRONMENT *IspEnvironment, const void *s, size_t n)
697 {
698 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
699 
700     unsigned long realsize;
701     size_t m;
702     unsigned long rxsize;
703     char * pch;
704     char * rxpch;
705 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
706 
707     DumpString(4, s, n, "Sending ");
708 
709 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
710 
711     if (IspEnvironment->HalfDuplex == 0)
712     {
713         WriteFile(IspEnvironment->hCom, s, n, &realsize, NULL);
714     }
715     else
716     {
717         pch = (char *)s;
718         rxpch = RxTmpBuf;
719         pRxTmpBuf = RxTmpBuf;
720 
721         // avoid buffer otherflow
722         if (n > sizeof (RxTmpBuf))
723             n = sizeof (RxTmpBuf);
724 
725         for (m = 0; m < n; m++)
726         {
727             WriteFile(IspEnvironment->hCom, pch, 1, &realsize, NULL);
728 
729             if ((*pch != '?') || (n != 1))
730             {
731                 do
732                 {
733                     ReadFile(IspEnvironment->hCom, rxpch, 1, &rxsize, NULL);
734                 }while (rxsize == 0);
735             }
736             pch++;
737             rxpch++;
738         }
739         *rxpch = 0;        // terminate echo string
740     }
741 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
742 
743 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_LPC21
744 
745     write(IspEnvironment->fdCom, s, n);
746 
747 #endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_LPC21
748 
749     if (IspEnvironment->WriteDelay == 1)
750     {
751         Sleep(100); // 100 ms delay after each block (makes lpc21isp to work with bad UARTs)
752     }
753 }
754 
755 /***************************** SendComPort ******************************/
756 /**  Sends a string out the opened com port.
757 \param [in] s string to send.
758 */
SendComPort(ISP_ENVIRONMENT * IspEnvironment,const char * s)759 void SendComPort(ISP_ENVIRONMENT *IspEnvironment, const char *s)
760 {
761     SendComPortBlock(IspEnvironment, s, strlen(s));
762 }
763 
764 /***************************** SerialTimeoutTick ************************/
765 /**  Performs a timer tick.  In this simple case all we do is count down
766 with protection against underflow and wrapping at the low end.
767 */
SerialTimeoutTick(ISP_ENVIRONMENT * IspEnvironment)768 static void SerialTimeoutTick(ISP_ENVIRONMENT *IspEnvironment)
769 {
770     if (IspEnvironment->serial_timeout_count <= 1)
771     {
772         IspEnvironment->serial_timeout_count = 0;
773     }
774     else
775     {
776         IspEnvironment->serial_timeout_count--;
777     }
778 }
779 
780 /***************************** ReceiveComPortBlock **********************/
781 /**  Receives a buffer from the open com port. Returns all the characters
782 ready (waits for up to 'n' milliseconds before accepting that no more
783 characters are ready) or when the buffer is full. 'n' is system dependant,
784 see SerialTimeout routines.
785 \param [out] answer buffer to hold the bytes read from the serial port.
786 \param [in] max_size the size of buffer pointed to by answer.
787 \param [out] real_size pointer to a long that returns the amout of the
788 buffer that is actually used.
789 */
ReceiveComPortBlock(ISP_ENVIRONMENT * IspEnvironment,void * answer,unsigned long max_size,unsigned long * real_size)790 static void ReceiveComPortBlock(ISP_ENVIRONMENT *IspEnvironment,
791                                           void *answer, unsigned long max_size,
792                                           unsigned long *real_size)
793 {
794     char tmp_string[32];
795 
796 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
797 
798     if (IspEnvironment->HalfDuplex == 0)
799         ReadFile(IspEnvironment->hCom, answer, max_size, real_size, NULL);
800     else
801     {
802         *real_size = strlen (pRxTmpBuf);
803         if (*real_size)
804         {
805             if (max_size >= *real_size)
806             {
807                 strncpy((char*) answer, pRxTmpBuf, *real_size);
808                 RxTmpBuf[0] = 0;
809                 pRxTmpBuf = RxTmpBuf;
810             }
811             else
812             {
813                 strncpy((char*) answer, pRxTmpBuf, max_size);
814                 *real_size = max_size;
815                 pRxTmpBuf += max_size;
816             }
817         }
818         else
819             ReadFile(IspEnvironment->hCom, answer, max_size, real_size, NULL);
820     }
821 
822 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
823 
824 #if defined COMPILE_FOR_LPC21
825 
826     *real_size = read(IspEnvironment->fdCom, answer, max_size);
827 
828 #endif // defined COMPILE_FOR_LPC21
829 
830 #if defined COMPILE_FOR_LINUX
831     {
832         fd_set
833             readSet;
834         struct timeval
835             timeVal;
836 
837         FD_ZERO(&readSet);                             // clear the set
838         FD_SET(IspEnvironment->fdCom,&readSet);        // add this descriptor to the set
839         timeVal.tv_sec=0;                              // set up the timeout waiting for one to come ready (500ms)
840         timeVal.tv_usec=500*1000;
841         if(select(FD_SETSIZE,&readSet,NULL,NULL,&timeVal)==1)    // wait up to 500 ms or until our data is ready
842         {
843             *real_size=read(IspEnvironment->fdCom, answer, max_size);
844         }
845         else
846         {
847             // timed out, show no characters received and timer expired
848             *real_size=0;
849             IspEnvironment->serial_timeout_count=0;
850         }
851     }
852 #endif // defined COMPILE_FOR_LINUX
853 
854     sprintf(tmp_string, "Read(Length=%ld): ", (*real_size));
855     DumpString(5, answer, (*real_size), tmp_string);
856 
857     if (*real_size == 0)
858     {
859         SerialTimeoutTick(IspEnvironment);
860     }
861 }
862 
863 
864 /***************************** SerialTimeoutSet *************************/
865 /**  Sets (or resets) the timeout to the timout period requested.  Starts
866 counting to this period.  This timeout support is a little odd in that the
867 timeout specifies the accumulated deadtime waiting to read not the total
868 time waiting to read. They should be close enought to the same for this
869 use. Used by the serial input routines, the actual counting takes place in
870 ReceiveComPortBlock.
871 \param [in] timeout_milliseconds the time in milliseconds to use for
872 timeout.  Note that just because it is set in milliseconds doesn't mean
873 that the granularity is that fine.  In many cases (particularly Linux) it
874 will be coarser.
875 */
SerialTimeoutSet(ISP_ENVIRONMENT * IspEnvironment,unsigned timeout_milliseconds)876 static void SerialTimeoutSet(ISP_ENVIRONMENT *IspEnvironment, unsigned timeout_milliseconds)
877 {
878 #if defined COMPILE_FOR_LINUX
879     IspEnvironment->serial_timeout_count = timeout_milliseconds / 100;
880 #elif defined COMPILE_FOR_LPC21
881     IspEnvironment->serial_timeout_count = timeout_milliseconds * 200;
882 #else
883 #ifdef _MSC_VER
884     IspEnvironment->serial_timeout_count = timeGetTime() + timeout_milliseconds;
885 #else
886     IspEnvironment->serial_timeout_count = timeout_milliseconds;
887 #endif // _MSC_VER
888 #endif
889 }
890 
891 
892 
893 /***************************** SerialTimeoutCheck ***********************/
894 /**  Check to see if the serial timeout timer has run down.
895 \retval 1 if timer has run out.
896 \retval 0 if timer still has time left.
897 */
SerialTimeoutCheck(ISP_ENVIRONMENT * IspEnvironment)898 static int SerialTimeoutCheck(ISP_ENVIRONMENT *IspEnvironment)
899 {
900 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
901 #ifdef _MSC_VER
902     if ((signed long)(IspEnvironment->serial_timeout_count - timeGetTime()) < 0)
903     {
904         return 1;
905     }
906 #else
907     if (IspEnvironment->serial_timeout_count == 0)
908     {
909         return 1;
910     }
911 #endif // _MSC_VER
912 #else
913     if (IspEnvironment->serial_timeout_count == 0)
914     {
915         return 1;
916     }
917 #endif
918     return 0;
919 }
920 
921 
922 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
923 /***************************** getch ************************************/
924 /** Replacement for the common dos function of the same name. Reads a
925 single unbuffered character from the 'keyboard'.
926 \return The character read from the keyboard.
927 */
getch(void)928 int getch(void)
929 {
930     char ch;
931 
932     /* Read in one character */
933     read(0,&ch,1);
934 
935     return ch;
936 }
937 #endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
938 
939 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
940 /***************************** kbhit ************************************/
941 /** Replacement for the common dos function of the same name. Indicates if
942 there are characters to be read from the console.
943 \retval 0 No characters ready.
944 \retval 1 Characters from the console ready to be read.
945 */
kbhit(void)946 int kbhit(void)
947 {
948     /* return 0 for no key pressed, 1 for key pressed */
949     int return_value = 0;
950 
951     /* time struct for the select() function, to only wait a little while */
952     struct timeval select_time;
953     /* file descriptor variable for the select() call */
954     fd_set readset;
955 
956     /* we're only interested in STDIN */
957     FD_ZERO(&readset);
958     FD_SET(STDIN_FILENO, &readset);
959 
960     /* how long to block for - this must be > 0.0, but could be changed
961     to some other setting. 10-18msec seems to work well and only
962     minimally load the system (0% CPU loading) */
963     select_time.tv_sec = 0;
964     select_time.tv_usec = 10;
965 
966     /* is there a keystroke there? */
967     if (select(1, &readset, NULL, NULL, &select_time))
968     {
969         /* yes, remember it */
970         return_value = 1;
971     }
972 
973 
974     /* return with what we found out */
975     return return_value;
976 }
977 struct termios keyboard_origtty;
978 #endif // defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
979 
980 
981 /***************************** PrepareKeyboardTtySettings ***************/
982 /** Set the keyboard tty to be able to check for new characters via kbhit
983 getting them via getch
984 */
985 
PrepareKeyboardTtySettings(void)986 void PrepareKeyboardTtySettings(void)
987 {
988 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
989     /* store the current tty settings */
990     if (!tcgetattr(0, &keyboard_origtty))
991     {
992         struct termios tty;
993         /* start with the current settings */
994         tty = keyboard_origtty;
995         /* make modifications to put it in raw mode, turn off echo */
996         tty.c_lflag &= ~ICANON;
997         tty.c_lflag &= ~ECHO;
998         tty.c_lflag &= ~ISIG;
999         tty.c_cc[VMIN] = 1;
1000         tty.c_cc[VTIME] = 0;
1001 
1002         /* put the settings into effect */
1003         tcsetattr(0, TCSADRAIN, &tty);
1004     }
1005 #endif
1006 }
1007 
1008 
1009 /***************************** ResetKeyboardTtySettings *****************/
1010 /** Reset the keyboard tty to original settings
1011 */
ResetKeyboardTtySettings(void)1012 void ResetKeyboardTtySettings(void)
1013 {
1014 #if defined COMPILE_FOR_LINUX || defined COMPILE_FOR_CYGWIN
1015     /* reset the tty to its original settings */
1016     tcsetattr(0, TCSADRAIN, &keyboard_origtty);
1017 #endif
1018 }
1019 
1020 
1021 #if !defined COMPILE_FOR_LPC21
1022 /***************************** ControlModemLines ************************/
1023 /**  Controls the modem lines to place the microcontroller into various
1024 states during the programming process.
1025 error rather abruptly terminates the program.
1026 \param [in] DTR the state to set the DTR line to.
1027 \param [in] RTS the state to set the RTS line to.
1028 */
ControlModemLines(ISP_ENVIRONMENT * IspEnvironment,unsigned char DTR,unsigned char RTS)1029 static void ControlModemLines(ISP_ENVIRONMENT *IspEnvironment, unsigned char DTR, unsigned char RTS)
1030 {
1031     //handle wether to invert the control lines:
1032     DTR ^= IspEnvironment->ControlLinesInverted;
1033     RTS ^= IspEnvironment->ControlLinesInverted;
1034 
1035     //handle wether to swap the control lines
1036     if (IspEnvironment->ControlLinesSwapped)
1037     {
1038         unsigned char tempRTS;
1039         tempRTS = RTS;
1040         RTS = DTR;
1041         DTR = tempRTS;
1042     }
1043 
1044 #if defined COMPILE_FOR_LINUX
1045     int status;
1046 
1047     if (ioctl(IspEnvironment->fdCom, TIOCMGET, &status) == 0)
1048     {
1049         DebugPrintf(3, "ioctl get ok, status = %X\n",status);
1050     }
1051     else
1052     {
1053         DebugPrintf(1, "ioctl get failed\n");
1054     }
1055 
1056     if (DTR) status |=  TIOCM_DTR;
1057     else    status &= ~TIOCM_DTR;
1058 
1059     if (RTS) status |=  TIOCM_RTS;
1060     else    status &= ~TIOCM_RTS;
1061 
1062     if (ioctl(IspEnvironment->fdCom, TIOCMSET, &status) == 0)
1063     {
1064         DebugPrintf(3, "ioctl set ok, status = %X\n",status);
1065     }
1066     else
1067     {
1068         DebugPrintf(1, "ioctl set failed\n");
1069     }
1070 
1071     if (ioctl(IspEnvironment->fdCom, TIOCMGET, &status) == 0)
1072     {
1073         DebugPrintf(3, "ioctl get ok, status = %X\n",status);
1074     }
1075     else
1076     {
1077         DebugPrintf(1, "ioctl get failed\n");
1078     }
1079 
1080 #endif // defined COMPILE_FOR_LINUX
1081 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
1082 
1083     if (DTR) EscapeCommFunction(IspEnvironment->hCom, SETDTR);
1084     else    EscapeCommFunction(IspEnvironment->hCom, CLRDTR);
1085 
1086     if (RTS) EscapeCommFunction(IspEnvironment->hCom, SETRTS);
1087     else    EscapeCommFunction(IspEnvironment->hCom, CLRRTS);
1088 
1089 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
1090 
1091 #if defined COMPILE_FOR_LPC21
1092     LPC_RESET(DTR);
1093     LPC_BSL(RTS);
1094 #endif
1095 
1096     DebugPrintf(3, "DTR (%d), RTS (%d)\n", DTR, RTS);
1097 }
1098 
1099 
1100 /***************************** ClearSerialPortBuffers********************/
1101 /**  Empty the serial port buffers.  Cleans things to a known state.
1102 */
ClearSerialPortBuffers(ISP_ENVIRONMENT * IspEnvironment)1103 void ClearSerialPortBuffers(ISP_ENVIRONMENT *IspEnvironment)
1104 {
1105 #if defined COMPILE_FOR_LINUX
1106     /* variables to store the current tty state, create a new one */
1107     struct termios origtty, tty;
1108 
1109     /* store the current tty settings */
1110     tcgetattr(IspEnvironment->fdCom, &origtty);
1111 
1112     // Flush input and output buffers
1113     tty=origtty;
1114     tcsetattr(IspEnvironment->fdCom, TCSAFLUSH, &tty);
1115 
1116     /* reset the tty to its original settings */
1117     tcsetattr(IspEnvironment->fdCom, TCSADRAIN, &origtty);
1118 #endif // defined COMPILE_FOR_LINUX
1119 #if defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
1120     PurgeComm(IspEnvironment->hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
1121 #endif // defined COMPILE_FOR_WINDOWS || defined COMPILE_FOR_CYGWIN
1122 }
1123 #endif // !defined COMPILE_FOR_LPC21
1124 
1125 
1126 #if defined COMPILE_FOR_LINUX
1127 /***************************** Sleep ************************************/
1128 /**  Provide linux replacement for windows function.
1129 \param [in] Milliseconds the time to wait for in milliseconds.
1130 */
Sleep(unsigned long MilliSeconds)1131 void Sleep(unsigned long MilliSeconds)
1132 {
1133     usleep(MilliSeconds*1000); //convert to microseconds
1134 }
1135 #endif // defined COMPILE_FOR_LINUX
1136 
1137 
1138 #if defined COMPILE_FOR_LPC21
1139 /**  Provide linux replacement for windows function.
1140 \note I implement that one in my private header file today...
1141 \param [in] Milliseconds the time to wait for in milliseconds.
1142 */
1143 /*static void Sleep(unsigned long MilliSeconds)
1144 {
1145 #   warning Sleep function not implemented
1146 }
1147 */
1148 #endif // defined COMPILE_FOR_LPC21
1149 
1150 
1151 
1152 /************* Applicationlayer.                                        */
1153 
1154 #if !defined COMPILE_FOR_LPC21
1155 /***************************** DebugPrintf ******************************/
1156 /**  Prints a debug string depending the current debug level. The higher
1157 the debug level the more detail that will be printed.  Each print
1158 has an associated level, the higher the level the more detailed the
1159 debugging information being sent.
1160 \param [in] level the debug level of the print statement, if the level
1161 is less than or equal to the current debug level it will be printed.
1162 \param [in] fmt a standard printf style format string.
1163 \param [in] ... the usual printf parameters.
1164 */
1165 #if !defined INTEGRATED_IN_WIN_APP
DebugPrintf(int level,const char * fmt,...)1166 void DebugPrintf(int level, const char *fmt, ...)
1167 {
1168     va_list ap;
1169 
1170     if (level <= debug_level)
1171     {
1172         char pTemp[2000];
1173         va_start(ap, fmt);
1174         //vprintf(fmt, ap);
1175         vsprintf(pTemp, fmt, ap);
1176         TRACE(pTemp);
1177         va_end(ap);
1178         fflush(stdout);
1179     }
1180 }
1181 #endif
1182 #endif // !defined COMPILE_FOR_LPC21
1183 
1184 
1185 /***************************** ReceiveComPort ***************************/
1186 /**  Receives a buffer from the open com port. Returns when the buffer is
1187 filled, the numer of requested linefeeds has been received or the timeout
1188 period has passed. The bootloaders may send 0x0d,0x0a,0x0a or 0x0d,0x0a as
1189 linefeed pattern
1190 2013-06-28 Torsten Lang
1191 Note: We *could* filter out surplus 0x0a characters like in <CR><LF><LF>
1192 but as we don't know how the individual bootloader behaves we don't want
1193 to wait for possible surplus <LF> (which would slow down the transfer).
1194 Thus, we just terminate after the expected number of <CR><LF> sequences
1195 and leave it to the command handler in lpcprog.c to filter out surplus
1196 <LF> characters which then occur as leading character in answers or
1197 echoed commands.
1198 \param [in] ISPEnvironment.
1199 \param [out] Answer buffer to hold the bytes read from the serial port.
1200 \param [in] MaxSize the size of buffer pointed to by Answer.
1201 \param [out] RealSize pointer to a long that returns the amout of the
1202 buffer that is actually used.
1203 \param [in] WantedNr0x0A the maximum number of linefeeds to accept before
1204 returning.
1205 \param [in] timeOutMilliseconds the maximum amount of time to wait before
1206 reading with an incomplete buffer.
1207 */
ReceiveComPort(ISP_ENVIRONMENT * IspEnvironment,const char * Ans,unsigned long MaxSize,unsigned long * RealSize,unsigned long WantedNr0x0A,unsigned timeOutMilliseconds)1208 void ReceiveComPort(ISP_ENVIRONMENT *IspEnvironment,
1209                                     const char *Ans, unsigned long MaxSize,
1210                                     unsigned long *RealSize, unsigned long WantedNr0x0A,
1211                                     unsigned timeOutMilliseconds)
1212 {
1213     unsigned long tmp_realsize;
1214     unsigned long nr_of_0x0A = 0;
1215     unsigned long nr_of_0x0D = 0;
1216     int eof = 0;
1217     unsigned long p;
1218     unsigned char *Answer;
1219     unsigned char *endPtr;
1220     char tmp_string[32];
1221     static char residual_data[128] = {'\0'};
1222     int lf = 0;
1223 
1224     Answer  = (unsigned char*) Ans;
1225 
1226     SerialTimeoutSet(IspEnvironment, timeOutMilliseconds);
1227 
1228     *RealSize = 0;
1229     endPtr = NULL;
1230 
1231     do
1232     {
1233         if (residual_data[0] == '\0')
1234         {
1235             /* Receive new data */
1236             ReceiveComPortBlock(IspEnvironment, Answer + (*RealSize), MaxSize - (*RealSize), &tmp_realsize);
1237         }
1238         else
1239         {
1240             /* Take over any old residual data */
1241             strcpy((char *)Answer, residual_data);
1242             tmp_realsize = strlen((char *)Answer);
1243             residual_data[0] = '\0';
1244         }
1245 
1246         if (tmp_realsize != 0)
1247         {
1248             for (p = (*RealSize); p < (*RealSize) + tmp_realsize; p++)
1249             {
1250                 /* Torsten Lang 2013-05-06 Scan for 0x0d,0x0a,0x0a and 0x0d,0x0a as linefeed pattern */
1251                 if (Answer[p] == 0x0a)
1252                 {
1253                     if (lf != 0)
1254                     {
1255                         nr_of_0x0A++;
1256                         lf = 0;
1257                         if (nr_of_0x0A >= WantedNr0x0A)
1258                         {
1259                             endPtr = &Answer[p+1];
1260                         }
1261                     }
1262                 }
1263                 else if (Answer[p] == 0x0d)
1264                 {
1265                     nr_of_0x0D++;
1266                     lf = 1;
1267                 }
1268                 else if (((signed char) Answer[p]) < 0)
1269                 {
1270                     eof = 1;
1271                     lf  = 0;
1272                 }
1273                 else if (lf != 0)
1274                 {
1275                     nr_of_0x0D++;
1276                     nr_of_0x0A++;
1277                     lf = 0;
1278                     if (nr_of_0x0A >= WantedNr0x0A)
1279                     {
1280                         endPtr = &Answer[p+1];
1281                     }
1282                 }
1283             }
1284             (*RealSize) += tmp_realsize;
1285         }
1286     } while (((*RealSize) < MaxSize) && (SerialTimeoutCheck(IspEnvironment) == 0) && (nr_of_0x0A < WantedNr0x0A) && !eof);
1287 
1288     /* Torsten Lang 2013-05-06 Store residual data and cut answer after expected nr. of 0x0a */
1289     Answer[*RealSize] = '\0';
1290     if (endPtr != NULL)
1291     {
1292         strcpy(residual_data, (char *)endPtr);
1293         *endPtr = '\0';
1294         /* Torsten Lang 2013-06-28 Update size info */
1295         *RealSize = endPtr-Answer;
1296     }
1297 
1298     sprintf(tmp_string, "Answer(Length=%ld): ", (*RealSize));
1299     DumpString(3, Answer, (*RealSize), tmp_string);
1300 }
1301 
1302 
1303 #if !defined COMPILE_FOR_LPC21
1304 
1305 /***************************** ReceiveComPortBlockComplete **************/
1306 /**  Receives a fixed block from the open com port. Returns when the
1307 block is completely filled or the timeout period has passed
1308 \param [out] block buffer to hold the bytes read from the serial port.
1309 \param [in] size the size of the buffer pointed to by block.
1310 \param [in] timeOut the maximum amount of time to wait before guvung up on
1311 completing the read.
1312 \return 0 if successful, non-zero otherwise.
1313 */
ReceiveComPortBlockComplete(ISP_ENVIRONMENT * IspEnvironment,void * block,size_t size,unsigned timeout)1314 int ReceiveComPortBlockComplete(ISP_ENVIRONMENT *IspEnvironment,
1315                                                     void *block, size_t size, unsigned timeout)
1316 {
1317     unsigned long realsize = 0, read;
1318     char *result;
1319     char tmp_string[32];
1320 
1321     result = (char*) block;
1322 
1323     SerialTimeoutSet(IspEnvironment, timeout);
1324 
1325     do
1326     {
1327         ReceiveComPortBlock(IspEnvironment, result + realsize, size - realsize, &read);
1328 
1329         realsize += read;
1330 
1331     } while ((realsize < size) && (SerialTimeoutCheck(IspEnvironment) == 0));
1332 
1333     sprintf(tmp_string, "Answer(Length=%ld): ", realsize);
1334     DumpString(3, result, realsize, tmp_string);
1335 
1336     if (realsize != size)
1337     {
1338         return 1;
1339     }
1340     return 0;
1341 }
1342 
1343 /***************************** ReadArguments ****************************/
1344 /**  Reads the command line arguments and parses it for the various
1345 options. Uses the same arguments as main.  Used to separate the command
1346 line parsing from main and improve its readability.  This should also make
1347 it easier to modify the command line parsing in the future.
1348 \param [in] argc the number of arguments.
1349 \param [in] argv an array of pointers to the arguments.
1350 */
ReadArguments(ISP_ENVIRONMENT * IspEnvironment,unsigned int argc,char * argv[])1351 static void ReadArguments(ISP_ENVIRONMENT *IspEnvironment, unsigned int argc, char *argv[])
1352 {
1353     unsigned int i;
1354 
1355     if (argc >= 5)
1356     {
1357         for (i = 1; i < argc - 3; i++)
1358         {
1359             if (stricmp(argv[i], "-wipe") == 0)
1360             {
1361                 IspEnvironment->WipeDevice = 1;
1362                 DebugPrintf(3, "Wipe entire device before writing.\n");
1363                 continue;
1364             }
1365 
1366             if (stricmp(argv[i], "-bin") == 0)
1367             {
1368                 IspEnvironment->FileFormat = FORMAT_BINARY;
1369                 DebugPrintf(3, "Binary format file input.\n");
1370                 continue;
1371             }
1372 
1373             if (stricmp(argv[i], "-hex") == 0)
1374             {
1375                 IspEnvironment->FileFormat = FORMAT_HEX;
1376                 DebugPrintf(3, "Hex format file input.\n");
1377                 continue;
1378             }
1379 
1380             if (stricmp(argv[i], "-logfile") == 0)
1381             {
1382                 IspEnvironment->LogFile = 1;
1383                 DebugPrintf(3, "Log terminal output.\n");
1384                 continue;
1385             }
1386 
1387             if (stricmp(argv[i], "-detectonly") == 0)
1388             {
1389                 IspEnvironment->DetectOnly  = 1;
1390                 IspEnvironment->ProgramChip = 0;
1391                 DebugPrintf(3, "Only detect LPC chip part id.\n");
1392                 continue;
1393             }
1394 
1395             if(strnicmp(argv[i],"-debug", 6) == 0)
1396             {
1397                 char* num;
1398                 num = argv[i] + 6;
1399                 while(*num && isdigit(*num) == 0) num++;
1400                 if(isdigit(*num) != 0) debug_level = atoi( num);
1401                 else debug_level = 4;
1402                 DebugPrintf(3, "Turn on debug, level: %d.\n", debug_level);
1403                 continue;
1404             }
1405 
1406             if (stricmp(argv[i], "-boothold") == 0)
1407             {
1408                 IspEnvironment->BootHold = 1;
1409                 DebugPrintf(3, "hold EnableBootLoader asserted throughout programming sequence.\n");
1410                 continue;
1411             }
1412 
1413             if (stricmp(argv[i], "-donotstart") == 0)
1414             {
1415                 IspEnvironment->DoNotStart = 1;
1416                 DebugPrintf(3, "Do NOT start MCU after programming.\n");
1417                 continue;
1418             }
1419 
1420             if(strnicmp(argv[i],"-try", 4) == 0)
1421             {
1422                 int
1423                     retry;
1424                 retry=atoi(&argv[i][4]);
1425                 if(retry>0)
1426                 {
1427                     IspEnvironment->nQuestionMarks=retry;
1428                     DebugPrintf(3, "Retry count: %d.\n", IspEnvironment->nQuestionMarks);
1429                 }
1430                 else
1431                 {
1432                     fprintf(stderr,"invalid argument for -try: \"%s\"\n",argv[i]);
1433                 }
1434                 continue;
1435             }
1436 
1437 
1438             if (stricmp(argv[i], "-control") == 0)
1439             {
1440                 IspEnvironment->ControlLines = 1;
1441                 DebugPrintf(3, "Use RTS/DTR to control target state.\n");
1442                 continue;
1443             }
1444 
1445             if (stricmp(argv[i], "-controlswap") == 0)
1446             {
1447                 IspEnvironment->ControlLinesSwapped = 1;
1448                 DebugPrintf(3, "Use RTS to control reset, and DTR to control P0.14(ISP).\n");
1449                 continue;
1450             }
1451 
1452             if (stricmp(argv[i], "-controlinv") == 0)
1453             {
1454                 IspEnvironment->ControlLinesInverted = 1;
1455                 DebugPrintf(3, "Invert state of RTS & DTR (0=true/assert/set, 1=false/deassert/clear).\n");
1456                 continue;
1457             }
1458 
1459             if (stricmp(argv[i], "-halfduplex") == 0)
1460             {
1461                 IspEnvironment->HalfDuplex = 1;
1462                 DebugPrintf(3, "halfduplex serial communication.\n");
1463                 continue;
1464             }
1465 
1466             if (stricmp(argv[i], "-writedelay") == 0)
1467             {
1468                 IspEnvironment->WriteDelay = 1;
1469                 DebugPrintf(3, "Write delay enabled.\n");
1470                 continue;
1471             }
1472 
1473             if (stricmp(argv[i], "-ADARM") == 0)
1474             {
1475                 IspEnvironment->micro = ANALOG_DEVICES_ARM;
1476                 DebugPrintf(2, "Target: Analog Devices.\n");
1477                 continue;
1478             }
1479 
1480             if (stricmp(argv[i], "-NXPARM") == 0 || stricmp(argv[i], "-PHILIPSARM") == 0)
1481             {
1482                 IspEnvironment->micro = NXP_ARM;
1483                 DebugPrintf(2, "Target: NXP.\n");
1484                 continue;
1485             }
1486 
1487             if (stricmp(argv[i], "-Verify") == 0)
1488             {
1489                 IspEnvironment->Verify = 1;
1490                 DebugPrintf(2, "Verify after copy RAM to Flash.\n");
1491                 continue;
1492             }
1493 
1494 #ifdef INTEGRATED_IN_WIN_APP
1495             if (stricmp(argv[i], "-nosync") == 0)
1496             {
1497                 IspEnvironment->NoSync = 1;
1498                 DebugPrintf(2, "Performing no syncing, already done.\n");
1499                 continue;
1500             }
1501 #endif
1502 
1503 #ifdef TERMINAL_SUPPORT
1504             if (CheckTerminalParameters(IspEnvironment, argv[i]))
1505             {
1506                 continue;
1507             }
1508 #endif
1509 
1510             if(*argv[i] == '-') DebugPrintf( 2, "Unknown command line option: \"%s\"\n", argv[i]);
1511             else
1512             {
1513                 int ret_val;
1514                 if(IspEnvironment->FileFormat == FORMAT_HEX)
1515                 {
1516                     ret_val = AddFileHex(IspEnvironment, argv[i]);
1517                 }
1518                 else
1519                 {
1520                     ret_val = AddFileBinary(IspEnvironment, argv[i]);
1521                 }
1522                 if( ret_val != 0)
1523                 {
1524                     DebugPrintf( 2, "Unknown command line option: \"%s\"\n", argv[i]);
1525                 }
1526             }
1527         }
1528 
1529         // Newest cygwin delivers a '\x0d' at the end of argument
1530         // when calling lpc21isp from batch file
1531         for (i = 0; i < strlen(argv[argc - 1]) && i < (sizeof(IspEnvironment->StringOscillator) - 1) &&
1532             argv[argc - 1][i] >= '0' && argv[argc - 1][i] <= '9'; i++)
1533         {
1534             IspEnvironment->StringOscillator[i] = argv[argc - 1][i];
1535         }
1536         IspEnvironment->StringOscillator[i] = 0;
1537 
1538         IspEnvironment->serial_port = argv[argc - 3];
1539         IspEnvironment->baud_rate = argv[argc - 2];
1540     }
1541 
1542     if (argc < 5)
1543     {
1544         debug_level = (debug_level < 2) ? 2 : debug_level;
1545     }
1546 
1547     if (argc < 5)
1548     {
1549         DebugPrintf(2, "\n"
1550                        "Portable command line ISP\n"
1551                        "for NXP LPC family and Analog Devices ADUC 70xx\n"
1552                        "Version " VERSION_STR " compiled for " COMPILED_FOR ": " __DATE__ ", " __TIME__ "\n"
1553                        "Copyright (c) by Martin Maurer, 2003-2013, Email: Martin.Maurer@clibb.de\n"
1554                        "Portions Copyright (c) by Aeolus Development 2004, www.aeolusdevelopment.com\n"
1555                        "\n");
1556 
1557         DebugPrintf(1, "Syntax:  lpc21isp [Options] file[ file[ ...]] comport baudrate Oscillator_in_kHz\n\n"
1558                        "Example: lpc21isp test.hex com1 115200 14746\n\n"
1559                        "Options: -bin         for uploading binary file\n"
1560                        "         -hex         for uploading file in intel hex format (default)\n"
1561                        "         -term        for starting terminal after upload\n"
1562                        "         -termonly    for starting terminal without an upload\n"
1563                        "         -localecho   for local echo in terminal\n"
1564                        "         -detectonly  detect only used LPC chiptype (NXPARM only)\n"
1565                        "         -debug0      for no debug\n"
1566                        "         -debug3      for progress info only\n"
1567                        "         -debug5      for full debug\n"
1568                        "         -donotstart  do not start MCU after download\n"
1569                        "         -try<n>      try n times to synchronise\n"
1570                        "         -wipe        Erase entire device before upload\n"
1571                        "         -control     for controlling RS232 lines for easier booting\n"
1572                        "                      (Reset = DTR, EnableBootLoader = RTS)\n"
1573                        "         -boothold    hold EnableBootLoader asserted throughout sequence\n"
1574 #ifdef INTEGRATED_IN_WIN_APP
1575                        "         -nosync      Do not synchronize device via '?'\n"
1576 #endif
1577                        "         -controlswap swap RS232 control lines\n"
1578                        "                      (Reset = RTS, EnableBootLoader = DTR)\n"
1579                        "         -controlinv  Invert state of RTS & DTR \n"
1580                        "                      (0=true/assert/set, 1=false/deassert/clear).\n"
1581                        "         -verify      Verify the data in Flash after every writes to\n"
1582                        "                      sector. To detect errors in writing to Flash ROM\n"
1583                        "         -logfile     for enabling logging of terminal output to lpc21isp.log\n"
1584                        "         -halfduplex  use halfduplex serial communication (i.e. with K-Line)\n"
1585                        "         -writedelay  Add delay after serial port writes (for compatibility)\n"
1586                        "         -ADARM       for downloading to an Analog Devices\n"
1587                        "                      ARM microcontroller ADUC70xx\n"
1588                        "         -NXPARM      for downloading to a chip of NXP LPC family (default)\n");
1589 
1590         exit(1);
1591     }
1592 
1593     if (IspEnvironment->micro == NXP_ARM)
1594     {
1595         // If StringOscillator is bigger than 100 MHz, there seems to be something wrong
1596         if (strlen(IspEnvironment->StringOscillator) > 5)
1597         {
1598             DebugPrintf(1, "Invalid crystal frequency %s\n", IspEnvironment->StringOscillator);
1599             exit(1);
1600         }
1601     }
1602 }
1603 
1604 /***************************** ResetTarget ******************************/
1605 /**  Resets the target leaving it in either download (program) mode or
1606 run mode.
1607 \param [in] mode the mode to leave the target in.
1608 */
ResetTarget(ISP_ENVIRONMENT * IspEnvironment,TARGET_MODE mode)1609 void ResetTarget(ISP_ENVIRONMENT *IspEnvironment, TARGET_MODE mode)
1610 {
1611 #if defined(__linux__) && defined(GPIO_RST) && defined(GPIO_ISP)
1612 
1613 // This code section allows using Linux GPIO pins to control the -RST and -ISP
1614 // signals of the target microcontroller.
1615 //
1616 // Build lpc21isp to use Linux GPIO like this:
1617 //
1618 // make CFLAGS="-Wall -DGPIO_ISP=23 -DGPIO_RST=18"
1619 //
1620 // The GPIO pins must be pre-configured in /etc/rc.local (or other startup script)
1621 // similar to the following:
1622 //
1623 // # Configure -ISP signal
1624 // echo 23 >/sys/class/gpio/export
1625 // echo out >/sys/class/gpio/gpio23/direction
1626 // echo 1 >/sys/class/gpio/gpio23/value
1627 // chown root.gpio /sys/class/gpio/gpio23/value
1628 // chmod 660 /sys/class/gpio/gpio23/value
1629 //
1630 // # Configure -RST signal
1631 // echo 18 >/sys/class/gpio/export
1632 // echo out >/sys/class/gpio/gpio18/direction
1633 // echo 1 >/sys/class/gpio/gpio18/value
1634 // chown root.gpio /sys/class/gpio/gpio18/value
1635 // chmod 660 /sys/class/gpio/gpio18/value
1636 //
1637 // Then if the user is a member of the gpio group, lpc21isp will not requre any
1638 // special permissions to access the GPIO signals.
1639 
1640   char gpio_isp_filename[256];
1641   char gpio_rst_filename[256];
1642   int gpio_isp;
1643   int gpio_rst;
1644 
1645   memset(gpio_isp_filename, 0, sizeof(gpio_isp_filename));
1646   sprintf(gpio_isp_filename, "/sys/class/gpio/gpio%d/value", GPIO_ISP);
1647 
1648   memset(gpio_rst_filename, 0, sizeof(gpio_rst_filename));
1649   sprintf(gpio_rst_filename, "/sys/class/gpio/gpio%d/value", GPIO_RST);
1650 
1651   gpio_isp = open(gpio_isp_filename, O_WRONLY);
1652   if (gpio_isp < 0)
1653   {
1654     fprintf(stderr, "ERROR: open() for %s failed, %s\n", gpio_isp_filename, strerror(errno));
1655     exit(1);
1656   }
1657 
1658   gpio_rst = open(gpio_rst_filename, O_WRONLY);
1659   if (gpio_rst < 0)
1660   {
1661     fprintf(stderr, "ERROR: open() for %s failed, %s\n", gpio_rst_filename, strerror(errno));
1662     exit(1);
1663   }
1664 
1665   switch (mode)
1666   {
1667     case PROGRAM_MODE :
1668       write(gpio_isp, "0\n", 2);  // Assert -ISP
1669       Sleep(100);
1670       write(gpio_rst, "0\n", 2);  // Assert -RST
1671       Sleep(500);
1672       write(gpio_rst, "1\n", 2);  // Deassert -RST
1673       Sleep(100);
1674       write(gpio_isp, "1\n", 2);  // Deassert -ISP
1675       Sleep(100);
1676       break;;
1677 
1678     case RUN_MODE :
1679       write(gpio_rst, "0\n", 2);  // Assert -RST
1680       Sleep(500);
1681       write(gpio_rst, "1\n", 2);  // Deassert -ISP
1682       Sleep(100);
1683       break;;
1684   }
1685 
1686   close(gpio_isp);
1687   close(gpio_rst);
1688 
1689   return;
1690 #endif
1691 
1692     if (IspEnvironment->ControlLines)
1693     {
1694         switch (mode)
1695         {
1696         /* Reset and jump to boot loader.                       */
1697         case PROGRAM_MODE:
1698             ControlModemLines(IspEnvironment, 1, 1);
1699             Sleep(100);
1700             ClearSerialPortBuffers(IspEnvironment);
1701             Sleep(100);
1702             ControlModemLines(IspEnvironment, 0, 1);
1703             //Longer delay is the Reset signal is conected to an external rest controller
1704             Sleep(500);
1705             // Clear the RTS line after having reset the micro
1706             // Needed for the "GO <Address> <Mode>" ISP command to work */
1707             if(!IspEnvironment->BootHold)
1708             {
1709                 ControlModemLines(IspEnvironment, 0, 0);
1710             }
1711             break;
1712 
1713         /* Reset and start uploaded program                     */
1714         case RUN_MODE:
1715             ControlModemLines(IspEnvironment, 1, 0);
1716             Sleep(100);
1717             ClearSerialPortBuffers(IspEnvironment);
1718             Sleep(100);
1719             ControlModemLines(IspEnvironment, 0, 0);
1720             Sleep(100);
1721             break;
1722         }
1723     }
1724 }
1725 
1726 
1727 /***************************** Ascii2Hex ********************************/
1728 /**  Converts a hex character to its equivalent number value. In case of an
1729 error rather abruptly terminates the program.
1730 \param [in] c the hex digit to convert.
1731 \return the value of the hex digit.
1732 */
Ascii2Hex(unsigned char c)1733 static unsigned char Ascii2Hex(unsigned char c)
1734 {
1735     if (c >= '0' && c <= '9')
1736     {
1737         return (unsigned char)(c - '0');
1738     }
1739 
1740     if (c >= 'A' && c <= 'F')
1741     {
1742         return (unsigned char)(c - 'A' + 10);
1743     }
1744 
1745     if (c >= 'a' && c <= 'f')
1746     {
1747         return (unsigned char)(c - 'a' + 10);
1748     }
1749 
1750     DebugPrintf(1, "Wrong Hex-Nibble %c (%02X)\n", c, c);
1751     exit(1);
1752 
1753     return 0;  // this "return" will never be reached, but some compilers give a warning if it is not present
1754 }
1755 
1756 
1757 /***************************** AddFileHex *******************************/
1758 /**  Add a file to the list of files to read in, flag it as hex format.
1759 \param [in] IspEnvironment Programming environment.
1760 \param [in] arg The argument that was passed to the program as a file name.
1761 \return 0 on success, an error code otherwise.
1762 */
AddFileHex(ISP_ENVIRONMENT * IspEnvironment,const char * arg)1763 static int AddFileHex(ISP_ENVIRONMENT *IspEnvironment, const char *arg)
1764 {
1765     FILE_LIST *entry;
1766 
1767     // Add file to list.  If cannot allocate storage for node return an error.
1768     entry = malloc(sizeof(FILE_LIST));
1769     if( entry == 0)
1770     {
1771         DebugPrintf(1, "Error %d Could not allocated memory for file node %s\n", ERR_ALLOC_FILE_LIST, arg);
1772         return  ERR_ALLOC_FILE_LIST;
1773     }
1774 
1775     // Build up entry and insert it at the start of the list.
1776     entry->name = arg;
1777     entry->prev = IspEnvironment->f_list;
1778     entry->hex_flag = 1;
1779     IspEnvironment->f_list = entry;
1780 
1781     return 0;       // Success.
1782 }
1783 
1784 
1785 /***************************** AddFileBinary ****************************/
1786 /**  Add a file to the list of files to read in, flag it as binary format.
1787 \param [in] IspEnvironment Programming environment.
1788 \param [in] arg The argument that was passed to the program as a file name.
1789 \return 0 on success, an error code otherwise.
1790 */
AddFileBinary(ISP_ENVIRONMENT * IspEnvironment,const char * arg)1791 static int AddFileBinary(ISP_ENVIRONMENT *IspEnvironment, const char *arg)
1792 {
1793     FILE_LIST *entry;
1794 
1795     // Add file to list. If cannot allocate storage for node return an error.
1796     entry = malloc(sizeof(FILE_LIST));
1797     if( entry == 0)
1798     {
1799         DebugPrintf( 1, "Error %d Could not allocated memory for file node %s\n", ERR_ALLOC_FILE_LIST, arg);
1800         return  ERR_ALLOC_FILE_LIST;
1801     }
1802 
1803     // Build up entry and insert it at the start of the list.
1804     entry->name = arg;
1805     entry->prev = IspEnvironment->f_list;
1806     entry->hex_flag = 0;
1807     IspEnvironment->f_list = entry;
1808 
1809     return 0;       // Success.
1810 }
1811 
1812 #if 0
1813 void ReadHexFile(ISP_ENVIRONMENT *IspEnvironment)
1814 {
1815     LoadFile(IspEnvironment);
1816 
1817     if (IspEnvironment->BinaryLength)
1818     {
1819         BINARY* FileContent = IspEnvironment->FileContent;
1820 
1821         unsigned long  Pos;
1822         unsigned char  RecordLength;
1823         unsigned short RecordAddress;
1824         unsigned long  RealAddress = 0;
1825         unsigned char  RecordType;
1826         unsigned char  Hexvalue;
1827         unsigned long  StartAddress;
1828         int            BinaryOffsetDefined = 0;
1829         unsigned char  i;
1830 
1831 
1832         DebugPrintf(3, "Converting file %s to binary format...\n", IspEnvironment->input_file);
1833 
1834         Pos = 0;
1835         while (Pos < IspEnvironment->BinaryLength)
1836         {
1837             if (FileContent[Pos] == '\r')
1838             {
1839                 Pos++;
1840                 continue;
1841             }
1842 
1843             if (FileContent[Pos] == '\n')
1844             {
1845                 Pos++;
1846                 continue;
1847             }
1848 
1849             if (FileContent[Pos] != ':')
1850             {
1851                 DebugPrintf(1, "Missing start of record (':') wrong byte %c / %02X\n", FileContent[Pos], FileContent[Pos]);
1852                 exit(1);
1853             }
1854 
1855             Pos++;
1856 
1857             RecordLength   = Ascii2Hex(FileContent[Pos++]);
1858             RecordLength <<= 4;
1859             RecordLength  |= Ascii2Hex(FileContent[Pos++]);
1860 
1861             DebugPrintf(4, "RecordLength = %02X\n", RecordLength);
1862 
1863             RecordAddress   = Ascii2Hex(FileContent[Pos++]);
1864             RecordAddress <<= 4;
1865             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
1866             RecordAddress <<= 4;
1867             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
1868             RecordAddress <<= 4;
1869             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
1870 
1871             DebugPrintf(4, "RecordAddress = %04X\n", RecordAddress);
1872 
1873             RealAddress = RealAddress - (RealAddress & 0xffff) + RecordAddress;
1874 
1875             DebugPrintf(4, "RealAddress = %08lX\n", RealAddress);
1876 
1877             RecordType      = Ascii2Hex(FileContent[Pos++]);
1878             RecordType    <<= 4;
1879             RecordType     |= Ascii2Hex(FileContent[Pos++]);
1880 
1881             DebugPrintf(4, "RecordType = %02X\n", RecordType);
1882 
1883             if (RecordType == 0x00)          // 00 - Data record
1884             {
1885                 /*
1886                 * Binary Offset is defined as soon as first data record read
1887                 */
1888 
1889                 //BinaryOffsetDefined = 1;
1890 
1891                 // Memory for binary file big enough ?
1892                 while ((RealAddress + RecordLength - IspEnvironment->BinaryOffset) > IspEnvironment->BinaryMemSize)
1893                 {
1894                     IspEnvironment->BinaryMemSize <<= 1;    // Double the size allocated !!!
1895                     IspEnvironment->BinaryContent = (BINARY*) realloc(IspEnvironment->BinaryContent, IspEnvironment->BinaryMemSize);
1896                 }
1897 
1898                 // We need to know, what the highest address is,
1899                 // how many bytes / sectors we must flash
1900                 if (RealAddress + RecordLength - IspEnvironment->BinaryOffset > IspEnvironment->BinaryLength)
1901                 {
1902                     IspEnvironment->BinaryLength = RealAddress + RecordLength - IspEnvironment->BinaryOffset;
1903                     DebugPrintf(3, "Image size now: %ld\n", IspEnvironment->BinaryLength);
1904                 }
1905 
1906                 for (i = 0; i < RecordLength; i++)
1907                 {
1908                     Hexvalue        = Ascii2Hex(FileContent[Pos++]);
1909                     Hexvalue      <<= 4;
1910                     Hexvalue       |= Ascii2Hex(FileContent[Pos++]);
1911                     IspEnvironment->BinaryContent[RealAddress + i - IspEnvironment->BinaryOffset] = Hexvalue;
1912                 }
1913             }
1914             else if (RecordType == 0x01)     // 01 - End of file record
1915             {
1916                 break;
1917             }
1918             else if (RecordType == 0x02)     // 02 - Extended segment address record
1919             {
1920                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1921                 {
1922                     RealAddress <<= 4;
1923                     if (i == 0)
1924                     {
1925                         RealAddress  = Ascii2Hex(FileContent[Pos++]);
1926                     }
1927                     else
1928                     {
1929                         RealAddress |= Ascii2Hex(FileContent[Pos++]);
1930                     }
1931                 }
1932                 RealAddress <<= 4;
1933             }
1934             else if (RecordType == 0x03)     // 03 - Start segment address record
1935             {
1936                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1937                 {
1938                     RealAddress <<= 4;
1939                     if (i == 0)
1940                     {
1941                         RealAddress  = Ascii2Hex(FileContent[Pos++]);
1942                     }
1943                     else
1944                     {
1945                         RealAddress |= Ascii2Hex(FileContent[Pos++]);
1946                     }
1947                 }
1948                 RealAddress <<= 8;
1949             }
1950             else if (RecordType == 0x04)     // 04 - Extended linear address record, used by IAR
1951             {
1952                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1953                 {
1954                     RealAddress <<= 4;
1955                     if (i == 0)
1956                     {
1957                         RealAddress  = Ascii2Hex(FileContent[Pos++]);
1958                     }
1959                     else
1960                     {
1961                         RealAddress |= Ascii2Hex(FileContent[Pos++]);
1962                     }
1963                 }
1964                 RealAddress <<= 16;
1965                 if (!BinaryOffsetDefined)
1966                 {
1967                     // set startaddress of BinaryContent
1968                     // use of LPC_FLASHMASK to allow a memory range, not taking the first
1969                     // [04] record as actual start-address.
1970                     IspEnvironment->BinaryOffset = RealAddress & LPC_FLASHMASK;
1971                 }
1972                 else
1973                 {
1974                     if ((RealAddress & LPC_FLASHMASK) != IspEnvironment->BinaryOffset)
1975                     {
1976                         DebugPrintf(1, "New Extended Linear Address Record [04] out of memory range\n"
1977                                        "Current Memory starts at: 0x%08X, new Address is: 0x%08X",
1978                                        IspEnvironment->BinaryOffset, RealAddress);
1979                         exit(1);
1980                     }
1981                 }
1982             }
1983             else if (RecordType == 0x05)     // 05 - Start linear address record
1984             {
1985                 StartAddress = 0;
1986                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
1987                 {
1988                     StartAddress <<= 4;
1989                     if (i == 0)
1990                     {
1991                         StartAddress  = Ascii2Hex(FileContent[Pos++]);
1992                     }
1993                     else
1994                     {
1995                         StartAddress |= Ascii2Hex(FileContent[Pos++]);
1996                     }
1997                 }
1998                 DebugPrintf(1,"Start Address = 0x%08X\n", StartAddress);
1999                 IspEnvironment->StartAddress = StartAddress;
2000             }
2001 
2002             while (FileContent[Pos++] != 0x0a)      // Search till line end
2003             {
2004             }
2005         }
2006 
2007         DebugPrintf(2, "\tconverted to binary format...\n");
2008 
2009         // When debugging is switched on, output result of conversion to file debugout.bin
2010         if (debug_level >= 4)
2011         {
2012             int fdout;
2013             fdout = open("debugout.bin", O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0777);
2014             write(fdout, IspEnvironment->BinaryContent, IspEnvironment->BinaryLength);
2015             close(fdout);
2016         }
2017     }
2018 }
2019 #endif // #if 0
2020 
2021 
2022 /***************************** LoadFile *********************************/
2023 /**  Loads the requested file to download into memory.
2024 \param [in] IspEnvironment  structure containing input filename
2025 \param [in] filename  the name of the file to read in.
2026 \param [in] FileFormat  the format of the file to read in (FORMAT_HEX or FORMAT_BINARY)
2027 \return 0 if successful, otherwise an error code.
2028 */
LoadFile(ISP_ENVIRONMENT * IspEnvironment,const char * filename,int FileFormat)2029 static int LoadFile(ISP_ENVIRONMENT *IspEnvironment, const char *filename, int FileFormat)
2030 {
2031     int            fd;
2032     int            i;
2033     int            BinaryOffsetDefined;
2034     unsigned long  Pos;
2035     unsigned long  FileLength;
2036     BINARY        *FileContent;              /**< Used to store the content of a hex */
2037                                              /*   file before converting to binary.  */
2038     unsigned long  BinaryMemSize;
2039 
2040     fd = open(filename, O_RDONLY | O_BINARY);
2041     if (fd == -1)
2042     {
2043         DebugPrintf(1, "Can't open file %s\n", filename);
2044         return ERR_FILE_OPEN_HEX;
2045     }
2046 
2047     FileLength = lseek(fd, 0L, 2);      // Get file size
2048 
2049     if (FileLength == (size_t)-1)
2050     {
2051         DebugPrintf(1, "\nFileLength = -1 !?!\n");
2052         return ERR_FILE_SIZE_HEX;
2053     }
2054 
2055     lseek(fd, 0L, 0);
2056 
2057     // Just read the entire file into memory to parse.
2058     FileContent = (BINARY*) malloc(FileLength);
2059 
2060     if( FileContent == 0)
2061     {
2062         DebugPrintf( 1, "\nCouldn't allocate enough memory for file.\n");
2063         return ERR_FILE_ALLOC_HEX;
2064     }
2065 
2066     BinaryOffsetDefined = 0;
2067 
2068     BinaryMemSize = IspEnvironment->BinaryLength;
2069 
2070     read(fd, FileContent, FileLength);
2071 
2072     close(fd);
2073 
2074     DebugPrintf(2, "File %s:\n\tloaded...\n", filename);
2075 
2076     // Intel-Hex -> Binary Conversion
2077 
2078     if (FileFormat == FORMAT_HEX)
2079     {
2080         unsigned char  RecordLength;
2081         unsigned short RecordAddress;
2082         unsigned long  RealAddress = 0;
2083         unsigned char  RecordType;
2084         unsigned char  Hexvalue;
2085         unsigned long  StartAddress;
2086 
2087         DebugPrintf(3, "Converting file %s to binary format...\n", filename);
2088 
2089         Pos = 0;
2090         while (Pos < FileLength)
2091         {
2092             if (FileContent[Pos] == '\r')
2093             {
2094                 Pos++;
2095                 continue;
2096             }
2097 
2098             if (FileContent[Pos] == '\n')
2099             {
2100                 Pos++;
2101                 continue;
2102             }
2103 
2104             if (FileContent[Pos] != ':')
2105             {
2106                 DebugPrintf(1, "Missing start of record (':') wrong byte %c / %02X\n", FileContent[Pos], FileContent[Pos]);
2107                 exit(1);
2108             }
2109 
2110             Pos++;
2111 
2112             RecordLength   = Ascii2Hex(FileContent[Pos++]);
2113             RecordLength <<= 4;
2114             RecordLength  |= Ascii2Hex(FileContent[Pos++]);
2115 
2116             DebugPrintf(4, "RecordLength = %02X\n", RecordLength);
2117 
2118             RecordAddress   = Ascii2Hex(FileContent[Pos++]);
2119             RecordAddress <<= 4;
2120             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
2121             RecordAddress <<= 4;
2122             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
2123             RecordAddress <<= 4;
2124             RecordAddress  |= Ascii2Hex(FileContent[Pos++]);
2125 
2126             DebugPrintf(4, "RecordAddress = %04X\n", RecordAddress);
2127 
2128             RealAddress = RealAddress - (RealAddress & 0xffff) + RecordAddress;
2129 
2130             DebugPrintf(4, "RealAddress = %08lX\n", RealAddress);
2131 
2132             RecordType      = Ascii2Hex(FileContent[Pos++]);
2133             RecordType    <<= 4;
2134             RecordType     |= Ascii2Hex(FileContent[Pos++]);
2135 
2136             DebugPrintf(4, "RecordType = %02X\n", RecordType);
2137 
2138             if (RecordType == 0x00)          // 00 - Data record
2139             {
2140                 /*
2141                 * Binary Offset is defined as soon as first data record read
2142                 */
2143                 BinaryOffsetDefined = 1;
2144                 // Memory for binary file big enough ?
2145                 while (RealAddress + RecordLength - IspEnvironment->BinaryOffset > BinaryMemSize)
2146                 {
2147                     if(!BinaryMemSize) BinaryMemSize = FileLength * 2;
2148                     else BinaryMemSize <<= 1;
2149                     IspEnvironment->BinaryContent = realloc(IspEnvironment->BinaryContent, BinaryMemSize);
2150                 }
2151 
2152                 // We need to know, what the highest address is,
2153                 // how many bytes / sectors we must flash
2154                 if (RealAddress + RecordLength - IspEnvironment->BinaryOffset > IspEnvironment->BinaryLength)
2155                 {
2156                     IspEnvironment->BinaryLength = RealAddress + RecordLength - IspEnvironment->BinaryOffset;
2157                     DebugPrintf(3, "Image size now: %ld\n", IspEnvironment->BinaryLength);
2158                 }
2159 
2160                 for (i = 0; i < RecordLength; i++)
2161                 {
2162                     Hexvalue        = Ascii2Hex(FileContent[Pos++]);
2163                     Hexvalue      <<= 4;
2164                     Hexvalue       |= Ascii2Hex(FileContent[Pos++]);
2165                     IspEnvironment->BinaryContent[RealAddress + i - IspEnvironment->BinaryOffset] = Hexvalue;
2166                 }
2167             }
2168             else if (RecordType == 0x01)     // 01 - End of file record
2169             {
2170                 break;
2171             }
2172             else if (RecordType == 0x02)     // 02 - Extended segment address record
2173             {
2174                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
2175                 {
2176                     RealAddress <<= 4;
2177                     if (i == 0)
2178                     {
2179                         RealAddress  = Ascii2Hex(FileContent[Pos++]);
2180                     }
2181                     else
2182                     {
2183                         RealAddress |= Ascii2Hex(FileContent[Pos++]);
2184                     }
2185                 }
2186                 RealAddress <<= 4;
2187             }
2188             else if (RecordType == 0x03)     // 03 - Start segment address record
2189             {
2190                 unsigned long cs,ip;
2191                 StartAddress = 0;
2192                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
2193                 {
2194                     StartAddress <<= 4;
2195                     if (i == 0)
2196                     {
2197                         StartAddress  = Ascii2Hex(FileContent[Pos++]);
2198                     }
2199                     else
2200                     {
2201                         StartAddress |= Ascii2Hex(FileContent[Pos++]);
2202                     }
2203                 }
2204                 cs = StartAddress >> 16; //high part
2205                 ip = StartAddress & 0xffff; //low part
2206                 StartAddress = cs*16+ip; //segmented 20-bit space
2207                 DebugPrintf(1,"Start Address = 0x%08X\n", StartAddress);
2208                 IspEnvironment->StartAddress = StartAddress;
2209             }
2210             else if (RecordType == 0x04)     // 04 - Extended linear address record, used by IAR
2211             {
2212                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
2213                 {
2214                     RealAddress <<= 4;
2215                     if (i == 0)
2216                     {
2217                         RealAddress  = Ascii2Hex(FileContent[Pos++]);
2218                     }
2219                     else
2220                     {
2221                         RealAddress |= Ascii2Hex(FileContent[Pos++]);
2222                     }
2223                 }
2224                 RealAddress <<= 16;
2225                 if (!BinaryOffsetDefined)
2226                 {
2227                     // set startaddress of BinaryContent
2228                     // use of LPC_FLASHMASK to allow a memory range, not taking the first
2229                     // [04] record as actual start-address.
2230                     IspEnvironment->BinaryOffset = RealAddress & LPC_FLASHMASK;
2231                 }
2232                 else
2233                 {
2234                     if ((RealAddress & LPC_FLASHMASK) != IspEnvironment->BinaryOffset)
2235                     {
2236                         DebugPrintf(1, "New Extended Linear Address Record [04] out of memory range\n");
2237                         DebugPrintf(1, "Current Memory starts at: 0x%08X, new Address is: 0x%08X",
2238                             IspEnvironment->BinaryOffset, RealAddress);
2239                         return ERR_MEMORY_RANGE;
2240                     }
2241                 }
2242             }
2243             else if (RecordType == 0x05)     // 05 - Start linear address record
2244             {
2245                 StartAddress = 0;
2246                 for (i = 0; i < RecordLength * 2; i++)   // double amount of nibbles
2247                 {
2248                     StartAddress <<= 4;
2249                     if (i == 0)
2250                     {
2251                         StartAddress  = Ascii2Hex(FileContent[Pos++]);
2252                     }
2253                     else
2254                     {
2255                         StartAddress |= Ascii2Hex(FileContent[Pos++]);
2256                     }
2257                 }
2258                 DebugPrintf(1,"Start Address = 0x%08X\n", StartAddress);
2259                 IspEnvironment->StartAddress = StartAddress;
2260             }
2261             else
2262             {
2263                 free( FileContent);
2264                 DebugPrintf( 1, "Error %d RecordType %02X not yet implemented\n", ERR_RECORD_TYPE_LOADFILE, RecordType);
2265                 return( ERR_RECORD_TYPE_LOADFILE);
2266             }
2267 
2268             while (FileContent[Pos++] != 0x0a)      // Search till line end
2269             {
2270             }
2271         }
2272 
2273         DebugPrintf(2, "\tconverted to binary format...\n");
2274 
2275         // When debugging is switched on, output result of conversion to file debugout.bin
2276         if (debug_level >= 4)
2277         {
2278             int fdout;
2279             fdout = open("debugout.bin", O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0777);
2280             write(fdout, IspEnvironment->BinaryContent, IspEnvironment->BinaryLength);
2281             close(fdout);
2282         }
2283 
2284         free( FileContent);   // Done with file contents
2285     }
2286     else // FORMAT_BINARY
2287     {
2288         IspEnvironment->BinaryContent = FileContent;
2289         IspEnvironment->BinaryLength = FileLength;
2290     }
2291 
2292     DebugPrintf(2, "\timage size : %ld\n", IspEnvironment->BinaryLength);
2293 
2294     return 0;
2295 }
2296 
2297 /***************************** LoadFiles1 ********************************/
2298 /**  Loads the requested files to download into memory.
2299 \param [in] IspEnvironment structure containing input filename(s).
2300 \param [in] file simple linked list of files to read
2301 \return 0 if successful, otherwise an error code.
2302 */
LoadFiles1(ISP_ENVIRONMENT * IspEnvironment,const FILE_LIST * file)2303 static int LoadFiles1(ISP_ENVIRONMENT *IspEnvironment, const FILE_LIST *file)
2304 {
2305     int ret_val;
2306 
2307     if( file->prev != 0)
2308     {
2309         DebugPrintf( 3, "Follow file list %s\n", file->name);
2310 
2311         ret_val = LoadFiles1( IspEnvironment, file->prev);
2312     if( ret_val != 0)
2313     {
2314       return ret_val;
2315     }
2316     }
2317 
2318     DebugPrintf( 3, "Attempt to read File %s\n", file->name);
2319     if(file->hex_flag != 0)
2320     {
2321         ret_val = LoadFile(IspEnvironment, file->name, FORMAT_HEX);
2322     }
2323     else
2324     {
2325     ret_val = LoadFile(IspEnvironment, file->name, FORMAT_BINARY);
2326     }
2327     if( ret_val != 0)
2328     {
2329     return ret_val;
2330     }
2331 
2332     return 0;
2333 }
2334 
2335 /***************************** LoadFiles ********************************/
2336 /**  Loads the requested files to download into memory.
2337 \param [in] IspEnvironment structure containing input filename(s).
2338 \param [in] file simple linked list of files to read
2339 \return 0 if successful, otherwise an error code.
2340 */
LoadFiles(ISP_ENVIRONMENT * IspEnvironment)2341 static int LoadFiles(ISP_ENVIRONMENT *IspEnvironment)
2342 {
2343   int ret_val;
2344 
2345     ret_val = LoadFiles1(IspEnvironment, IspEnvironment->f_list);
2346     if( ret_val != 0)
2347     {
2348     exit(1); // return ret_val;
2349     }
2350 
2351   DebugPrintf( 2, "Image size : %ld\n", IspEnvironment->BinaryLength);
2352 
2353     // check length to flash for correct alignment, can happen with broken ld-scripts
2354     if (IspEnvironment->BinaryLength % 4 != 0)
2355     {
2356         unsigned long NewBinaryLength = ((IspEnvironment->BinaryLength + 3)/4) * 4;
2357 
2358         DebugPrintf( 2, "Warning:  data not aligned to 32 bits, padded (length was %lX, now %lX)\n", IspEnvironment->BinaryLength, NewBinaryLength);
2359 
2360         IspEnvironment->BinaryLength = NewBinaryLength;
2361     }
2362 
2363   // When debugging is switched on, output result of conversion to file debugout.bin
2364     if(debug_level >= 4)
2365     {
2366          int fdout;
2367      DebugPrintf( 1, "Dumping image file.\n");
2368          fdout = open("debugout.bin", O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 0777);
2369          write(fdout, IspEnvironment->BinaryContent, IspEnvironment->BinaryLength);
2370          close(fdout);
2371     }
2372     return 0;
2373 }
2374 #endif // !defined COMPILE_FOR_LPC21
2375 
2376 #ifndef COMPILE_FOR_LPC21
PerformActions(ISP_ENVIRONMENT * IspEnvironment)2377 int PerformActions(ISP_ENVIRONMENT *IspEnvironment)
2378 {
2379     int downloadResult = -1;
2380 
2381     DebugPrintf(2, "lpc21isp version " VERSION_STR "\n");
2382 
2383     /* Download requested, read in the input file.                  */
2384     if (IspEnvironment->ProgramChip)
2385     {
2386         LoadFiles(IspEnvironment);
2387     }
2388 
2389     OpenSerialPort(IspEnvironment);   /* Open the serial port to the microcontroller. */
2390 
2391     ResetTarget(IspEnvironment, PROGRAM_MODE);
2392 
2393     ClearSerialPortBuffers(IspEnvironment);
2394 
2395     /* Perform the requested download.                              */
2396     if (IspEnvironment->ProgramChip || IspEnvironment->DetectOnly)
2397     {
2398         switch (IspEnvironment->micro)
2399         {
2400 #ifdef LPC_SUPPORT
2401         case NXP_ARM:
2402             downloadResult = NxpDownload(IspEnvironment);
2403             break;
2404 #endif
2405 
2406 #ifdef AD_SUPPORT
2407         case ANALOG_DEVICES_ARM:
2408             downloadResult = AnalogDevicesDownload(IspEnvironment);
2409             break;
2410 #endif
2411         }
2412 
2413         if (downloadResult != 0)
2414         {
2415             CloseSerialPort(IspEnvironment);
2416             exit(downloadResult);
2417         }
2418     }
2419 
2420     if (IspEnvironment->StartAddress == 0 || IspEnvironment->TerminalOnly)
2421     {
2422         /* Only reset target if startaddress = 0
2423         * Otherwise stay with the running program as started in Download()
2424         */
2425         ResetTarget(IspEnvironment, RUN_MODE);
2426     }
2427 
2428     debug_level = 1;    /* From now on there is no more debug output !! */
2429                                         /* Therefore switch it off...                   */
2430 
2431 #ifdef TERMINAL_SUPPORT
2432     // Pass control to Terminal which will provide a terminal if one was asked for
2433     // User asked for terminal emulation, provide a really dumb terminal.
2434     Terminal(IspEnvironment);
2435 #endif
2436 
2437     CloseSerialPort(IspEnvironment);  /*  All done, close the serial port to the      */
2438 
2439     return 0;
2440 }
2441 #endif
2442 
2443 /***************************** main *************************************/
2444 /**  main. Everything starts from here.
2445 \param [in] argc the number of arguments.
2446 \param [in] argv an array of pointers to the arguments.
2447 */
2448 
2449 #if !defined COMPILE_FOR_LPC21
2450 
2451 #if defined INTEGRATED_IN_WIN_APP
AppDoProgram(int argc,char * argv[])2452 int AppDoProgram(int argc, char *argv[])
2453 #else
2454 int main(int argc, char *argv[])
2455 #endif
2456 {
2457     ISP_ENVIRONMENT IspEnvironment;
2458 
2459     // Initialize debug level
2460     debug_level = 2;
2461 
2462     // Initialize ISP Environment
2463     memset(&IspEnvironment, 0, sizeof(IspEnvironment));       // Clear the IspEnviroment to a known value
2464     IspEnvironment.micro       = NXP_ARM;                     // Default Micro
2465     IspEnvironment.FileFormat  = FORMAT_HEX;                  // Default File Format
2466     IspEnvironment.ProgramChip = TRUE;                        // Default to Programming the chip
2467     IspEnvironment.nQuestionMarks = 100;
2468     IspEnvironment.DoNotStart = 0;
2469     IspEnvironment.BootHold = 0;
2470     ReadArguments(&IspEnvironment, argc, argv);               // Read and parse the command line
2471 
2472     return PerformActions(&IspEnvironment);                   // Do as requested !
2473 }
2474 
2475 #endif // !defined COMPILE_FOR_LPC21
2476 
2477 /***************************** DumpString ******************************/
2478 /**  Prints an area of memory to stdout. Converts non-printables to hex.
2479 \param [in] level the debug level of the block to be dumped.  If this is
2480 less than or equal to the current debug level than the dump will happen
2481 otherwise this just returns.
2482 \param [in] b pointer to an area of memory.
2483 \param [in] size the length of the memory block to print.
2484 \param [in] prefix string is a pointer to a prefix string.
2485 */
DumpString(int level,const void * b,size_t size,const char * prefix_string)2486 void DumpString(int level, const void *b, size_t size, const char *prefix_string)
2487 {
2488     size_t i;
2489     const char * s = (const char*) b;
2490     unsigned char c;
2491 
2492     DebugPrintf(level, prefix_string);
2493 
2494     DebugPrintf(level, "'");
2495     for (i = 0; i < size; i++)
2496     {
2497         c = s[i];
2498         if (c >= 0x20 && c <= 0x7e) /*isprint?*/
2499         {
2500             DebugPrintf(level, "%c", c);
2501         }
2502         else
2503         {
2504             DebugPrintf(level, "(%02X)", c);
2505         }
2506     }
2507     DebugPrintf(level, "'\n");
2508 }
2509 
2510