summaryrefslogtreecommitdiff
path: root/src/sp12.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sp12.c')
-rw-r--r--src/sp12.c1136
1 files changed, 1136 insertions, 0 deletions
diff --git a/src/sp12.c b/src/sp12.c
new file mode 100644
index 0000000..738f404
--- /dev/null
+++ b/src/sp12.c
@@ -0,0 +1,1136 @@
+/* SP12: A serial programmer for working with Atmel AVR uCs */
+/* Copyright (C) 1997-2008 Ken Huntington, Kevin Towers, */
+/* Artur Pundsack, Pitronics. */
+
+/* This program is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU General Public License */
+/* as published by the Free Software Foundation; either version 2 */
+/* of the License, or (at your option) any later version. */
+
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, */
+/* MA 02111-1307, USA. */
+
+/* Pitronics can be reached by email: sbolt@xs4all.nl */
+/* Kevin Towers can be reached by email: ktowers@omnexcontrols.com */
+/* Ken Huntington can be reached by email: kenh@compmore.net */
+/* Artur Pundsack can be reached by email: ap@pa-tec.de */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "dos_cpt.h"
+#include <time.h>
+#include "sp12.h"
+
+#define VERSION "2.1.1"
+
+
+const char USAGE[] = {
+ " SP12/32 version %s: A serial programmer for Atmel AVR uCs.\n"
+ " Copyright (C) 1997-2008 Ken Huntington, Kevin Towers,\n"
+ " Artur Pundsack, Pitronics.\n"
+ "SYNOPSIS\n"
+ " sp12 {-options} [filename or address(:data)] {-options} [filename...\n"
+ "OPTIONS\n"
+ " i[nnn] - init E - chip erase\n"
+ " e - eprom area B - blank check\n"
+ " p - program area C - calculate checksum\n"
+ " w - write to L[n...n] - lock fuses\n"
+ " r - read from F[n...n] - fuses\n"
+ " a - address(:data) next H[n...n] - high fuses\n"
+ " f - filename next X[n...n] - extended fuses\n"
+ " I - create Intel Hex file c[nn] - calibration byte(s)\n"
+ " h - hex dump with ascii M<n.n> - match Sck to uC clock\n"
+ " o0, o1 - optimization P<nnn> - parallel port control\n"
+ " s - show supported uCs t - timing check\n"
+ "EXAMPLES\n"
+ " sp12 -M4 -wF10011 -wpfC prog.hex -wefC eep.hex -wL00 (sets timing \n"
+ " for 4MHz, sets fuses, then writes prog.hex into the program area\n"
+ " and eep.hex into the eeprom, providing checksums for both; and\n"
+ " finally a read/write lock is set)\n"
+ " sp12 -rF -rH -rL -rc (reads fuses, locks and calibration if possible)\n"
+ " sp12 -wea 0x01:0x99 (Writes 0x99 into eeprom address 0x01)\n\n"};
+
+static int initFlag = 0; /* i<nn> on command line; flag set nn */
+static int flashFlag = 0; /* p on command line */
+static int eepromFlag = 0; /* e */
+static int writeFlag = 0; /* w */
+static int readFlag = 0; /* r */
+static int lockFlag = 0; /* L */
+static int fusesFlag = 0; /* F */
+static int highFFlag = 0; /* H */
+static int extdFFlag = 0; /* X */
+static int calibFlag = 0; /* c */
+static unsigned long calibAddress = 0;
+static int fileFlag = 0; /* d */
+static int addressFlag = 0; /* a */
+static int eraseFlag = 0; /* E */
+static int blankChkFlag = 0; /* B */
+static int checksumFlag = 0; /* C */
+static int testFlag = 0; /* T */
+static int portFlag = 0; /* P */
+static int optimizeFlag = 0; /* o, 0, 1 */
+static int overlayFlag = 0; /* O */
+static float clkSpeed = 0; /* M, value between 0.1 and 12 */
+static float prevClkSpeed = 0; /* previous clkSpeed */
+static int IntelFlag = 0; /* I */
+static int hexAsciiFlag = 0; /* h */
+static int addressAvailable = 0;
+static int pathAvailable = 0;
+static char flashPath[MAXLEN]; /* path/filename source or destination */
+static char eepromPath[MAXLEN]; /* path/filename source or destination */
+static char checksumPath[MAXLEN]; /* path/filename source */
+static char commandStr[MAXLEN]; /* stores commands for logging */
+static char fusesBits[MAXLEN] = "";
+static char lockBits[MAXLEN] = "";
+static char calibByte[MAXLEN] = "";
+static char identifier[MAXLEN] = "";
+static unsigned int flashAddress = 0;
+static unsigned int flashData = 0;
+static unsigned int eepromAddress = 0;
+static unsigned int eepromData = 0;
+static unsigned int *flashBuf; /* flash buffer */
+static unsigned int *eepromBuf; /* eeprom buffer */
+static clock_t sp12Start, sp12End;
+static double sp12Elapsed;
+
+
+void exitSp12(int exitState) {
+
+ char binary[9] = "76543210"; /* Stores conversion num to binary */
+
+ portControl(DEFAULT_EXIT_STATE, 1);
+ num2bin((unsigned char) DEFAULT_EXIT_STATE, binary);
+ printf("Writing %#04x (%d, B%s) ",
+ DEFAULT_EXIT_STATE, DEFAULT_EXIT_STATE, binary);
+ printf("to the parallel port data bits.\n");
+ sp12End = clock();
+ sp12Elapsed = ((double) (sp12End - sp12Start)) / CLOCKS_PER_SEC;
+ printf("Sp12 was active for %#3.2f seconds.\n", sp12Elapsed);
+ if (flashBuf)
+ free(flashBuf);
+ if (eepromBuf)
+ free(eepromBuf);
+ exit(exitState);
+}
+
+
+/* Merely check whether options -L, -E, -F, -R, -S, -K, D, V, */
+/* A or U was used, and say something about it. */
+
+void reportLEFHXcFlag(void) {
+
+ if (lockFlag) {
+ printf("You have selected option -L to read or write lock fuses,\n");
+ printf("which has had no effect. Use this option only in combination\n ");
+ printf("with -r and -w, like -rL or -wL00\n");
+ lockFlag = 0;
+ }
+ if (eraseFlag) {
+ printf("You have selected option -E for erase, which has had no\n");
+ printf("effect. Options -w, -p and -f together cause an automatic\n");
+ printf("erase; -E should be used on its own or together with B if\n");
+ printf("you want a blank check afterwards.\n");
+ eraseFlag = 0;
+ }
+ if (fusesFlag) {
+ printf("You have selected option -F to read or write fuse bits,\n");
+ printf("which has had no effect. This option can only be used in\n");
+ printf("the commands -rF and -wF.\n");
+ fusesFlag = 0;
+ }
+ if (highFFlag) {
+ printf("You have selected option -H to read or write fuse bits,\n");
+ printf("which has had no effect. This option can only be used in\n");
+ printf("the commands -rH and -wH.\n");
+ highFFlag = 0;
+ }
+ if (extdFFlag) {
+ printf("You have selected option -X to read or write extended fuses,\n");
+ printf("which has had no effect. This option can only be used in\n");
+ printf("the commands -rX and -wX.\n");
+ extdFFlag = 0;
+ }
+ if (calibFlag) {
+ printf("You have selected option -c to read the calibration byte,\n");
+ printf("which has had no effect. This option can only be used in\n");
+ printf("the command -rc.\n");
+ calibFlag = 0;
+ }
+}
+
+/* Merely check whether option -B was used, */
+/* and say something about it. */
+
+void reportBflag(void) {
+
+ if (blankChkFlag) {
+ printf("You have selected option -B for blank check, which has had \n");
+ printf("no effect. Options -w, -p and -f together cause an automatic\n");
+ printf("erase; if you also want a blank check before programming,\n");
+ printf("use -Bwpf. Use -EB if you just want an erase followed by a\n");
+ printf("blank check, or -B on its own for a blank check without a\n");
+ printf("preceding erase.\n");
+ blankChkFlag = 0;
+ }
+}
+
+/* Blank check the device. */
+
+int blank_check(void) {
+
+ int signal = 0;
+
+ printf("Performing blank check...\n");
+ signal = blankCheck(device.flashLimit, device.eepromLimit);
+ if (signal == 0)
+ printf("The program and eeprom area's are blank.\n");
+ if ((signal & 0x01) == 1)
+ printf("The program area is NOT blank.\n");
+ if ((signal & 0x02) == 2)
+ printf("The eeprom area is NOT blank.\n");
+ return(signal);
+}
+
+/* The command processor */
+
+void processCommand(void) {
+
+ unsigned long command;
+ long address;
+ int error; /* Storing return value */
+ int deviceCode = 0;
+ char binary[9] = "76543210"; /* Stores conversion num to binary */
+ int rFlag = 0;
+ int idx = 0;
+
+ /*
+ * If it hasn't been done yet, then set the device parameters
+ * according to device code and option -i[NN]
+ */
+ if (!device.initPerformed) {
+ printf("Enabling AVR serial reading/programming...\n");
+ /*
+ * First see if it's a 1200, which doesn't echo 0x53
+ * on the third byte of PROGRAM_ENABLE.
+ * Initiating contact at low speed
+ */
+ strcpy(device.name, "AT90S1200(A)");
+ setSckTiming(0.1);
+ enableSPI(1200);
+ deviceCode = setDevicePars(initFlag, identifier);
+ if (deviceCode == 1) {
+ fprintf(stderr, "_sp12dev not found\n");
+ exitSp12(2);
+ }
+ if (deviceCode == 2) {
+ fprintf(stderr, "_sp12dev corrupt.\n");
+ exitSp12(2);
+ }
+ if (deviceCode == 3) {
+ /*
+ * It doesn't look like a 1200. If a uC is connected,
+ * the SPI shiftregister is not in synch. We'll now fail
+ * if it is an out of synch 1200, but other uCs do
+ * echo 0x53 on the third byte of PROGRAM_ENABLE.
+ * So we'll try synch pulses for a while.
+ */
+ enableSPI(0);
+ deviceCode = setDevicePars(initFlag, identifier);
+ if (deviceCode == 1) {
+ fprintf(stderr, "_sp12dev not found\n");
+ exitSp12(2);
+ }
+ if (deviceCode == 2) {
+ fprintf(stderr, "_sp12dev corrupt.\n");
+ exitSp12(2);
+ }
+ if (device.sigByte_0 == 0 && device.sigByte_1 == 1
+ && device.sigByte_2 == 2) {
+ printf("WARNING: You have connected an unidentifiable\n");
+ printf(" device, which may be locked mode 3. \n");
+ printf(" Access to a supported, mode 3 locked \n");
+ printf(" device can be regained, but only by \n");
+ printf(" erasing it first.\n");
+ printf(" Check SP12.doc for details.\n\n");
+ }
+ }
+ if (initFlag == 0) {
+ printf("The device code bytes 0,1,2: %#x, %#x, %#x were read\n",
+ device.sigByte_0, device.sigByte_1, device.sigByte_2);
+ printf("from parallel port %#x and indicate the following:\n",
+ portAddress);
+ printf("You have connected an %s\n", device.name);
+ printf("The device was made by %s\n\n", device.madeBy);
+ }
+ if (device.flashLimit == 0 || device.eepromLimit == 0) {
+ printf("Nothing to do for sp12.\n");
+ exitSp12(1);
+ }
+ if (initFlag != 0 && device.flashLimit != 0) {
+ printf("Device code check OVERRULED! Assuming an %s\n\n",
+ device.name);
+ }
+ /*
+ * Continue with the Sck wave form for the now known uC,
+ * at the default speed.
+ */
+ setSckTiming(clockSpdDefault);
+ }
+ /*
+ * Do a few command sanity checks
+ */
+ error = flashFlag + eepromFlag + writeFlag + readFlag + lockFlag \
+ + fusesFlag + highFFlag + extdFFlag + calibFlag + fileFlag \
+ + addressFlag + eraseFlag + blankChkFlag + checksumFlag + testFlag \
+ + portFlag + optimizeFlag + overlayFlag;
+ if (((fusesFlag || highFFlag || extdFFlag || lockFlag || calibFlag) \
+ && error > 2) || (!readFlag && !writeFlag)) {
+ if (fusesFlag) {
+ printf("Use F only in the commands -rF or -wF<fuses>\n");
+ exitSp12(2);
+ }
+ if (highFFlag) {
+ printf("Use H only in the commands -rH or -wH<fuses>\n");
+ exitSp12(2);
+ }
+ if (extdFFlag) {
+ printf("Use X only in the commands -rX or -wX<fuses>\n");
+ exitSp12(2);
+ }
+ if (lockFlag) {
+ printf("Use L only in the commands -rL or -wL<fuses>\n");
+ exitSp12(2);
+ }
+ if (calibFlag) {
+ printf("Use c only in the command -rc[n]\n");
+ exitSp12(2);
+ }
+ }
+ if (flashFlag && eepromFlag) {
+ printf("Do not use options -p and -e in a single command.\n");
+ exitSp12(2);
+ }
+ if (checksumFlag && !eepromFlag && !flashFlag) {
+ printf("Use C only in commands like -Ce, -Cp, -Cef <file>\n");
+ exitSp12(2);
+ }
+ /*
+ * Inititalize buffers
+ */
+ for (address = 0; address < device.flashLimit; address++)
+ flashBuf[address] = 0xFFFF;
+ for (address = 0; address < device.eepromLimit; address++)
+ eepromBuf[address] = 0xFFF;
+ /*
+ * Set Sck timing to match the now known uC's wave form
+ * and clock speed asked for by an -Mn.n command.
+ */
+ if (clkSpeed && clkSpeed != prevClkSpeed) {
+ printf("Sck timing set for %.1f MHz or higher.\n",
+ setSckTiming(clkSpeed));
+ prevClkSpeed = clkSpeed;
+ }
+ clkSpeed = 0;
+ /*
+ * if r --> p || e || F || L
+ * rp --> rpf --> read program area; write to file
+ * rpa --> read program address to stdout
+ * rp --> read program area to stdout
+ * re --> ref --> read eeprom area; write to file
+ * rea --> read eeprom address to stdout
+ * re --> read eeprom area to stdout
+ * rF --> read the fuse bits, if possible
+ * rL --> read the lock bits, if possible
+ * check for C
+ * check for E, B, R, S, but just report them
+ */
+ if (readFlag && writeFlag) {
+ printf("Do not use options -w and -r in a single command.\n");
+ exitSp12(2);
+ }
+ if (readFlag) {
+ readFlag = 0;
+ if ((!pathAvailable || addressAvailable) && IntelFlag) {
+ printf("The Intel hex format is only available when writing\n");
+ printf("an entire memory area to file.\n");
+ exitSp12(2);
+ }
+ if (addressAvailable && hexAsciiFlag) {
+ printf("A hex dump with ascii translation is only possible\n");
+ printf("when writing an entire memory area to file.\n");
+ exitSp12(2);
+ }
+ if (IntelFlag && hexAsciiFlag) {
+ printf("Select either (I)ntel hex format or (h)ex dump with\n");
+ printf("ascii translation; not both at the same time\n");
+ exitSp12(2);
+ }
+ if (flashFlag) {
+ flashFlag = 0;
+ if (addressAvailable) {
+ addressAvailable = 0;
+ flashData = readCodeWord(flashAddress);
+ printf("The word %#06x was read from program address %#08x\n",
+ flashData, flashAddress);
+ } else {
+ printf("Reading program area.\n");
+ readFlashArea(flashBuf, device.flashLimit);
+ if (pathAvailable) {
+ pathAvailable = 0;
+ printf("Writing program area content to %s\n", flashPath);
+ if (fileFlashBuf(flashBuf, device.flashLimit,
+ flashPath, IntelFlag, hexAsciiFlag) != 0) {
+ printf("%s %s\n", FILE_WRITE_ERROR, flashPath);
+ exitSp12(2);
+ }
+ IntelFlag = 0;
+ hexAsciiFlag = 0;
+ } else {
+ if (hexAsciiFlag) {
+ printBuffer(flashBuf, device.flashLimit, 1);
+ hexAsciiFlag = 0;
+ } else {
+ for (address = 0; address < device.flashLimit; address++)
+ printf("%06lx:%04x\n", address, flashBuf[address]);
+ }
+ }
+ }
+ if (checksumFlag) {
+ checksumFlag = 0;
+ readFlashArea(flashBuf, device.flashLimit);
+ printf("Checksum program area: %04x\n",
+ checksum(flashBuf, device.flashLimit));
+ }
+ }
+ if (eepromFlag) {
+ eepromFlag = 0;
+ if (addressAvailable) {
+ addressAvailable = 0;
+ eepromData = readDataByte(eepromAddress);
+ num2bin((unsigned char) eepromData, binary);
+ printf("The byte %#04x (%d, %#o, B%s) ", eepromData, eepromData,
+ eepromData, binary);
+ printf("was read from eeprom address %#06x\n", eepromAddress);
+ } else {
+ printf("Reading eeprom area.\n");
+ readEepromArea(eepromBuf, device.eepromLimit);
+ if (pathAvailable) {
+ pathAvailable = 0;
+ printf("Writing eeprom area content to %s\n", eepromPath);
+ if (fileEepromBuf(eepromBuf, device.eepromLimit,
+ eepromPath, IntelFlag, hexAsciiFlag) != 0) {
+ printf("%s %s\n", FILE_WRITE_ERROR, eepromPath);
+ exitSp12(2);
+ }
+ IntelFlag = 0;
+ hexAsciiFlag = 0;
+ } else {
+ if (hexAsciiFlag) {
+ printBuffer(eepromBuf, device.eepromLimit, 0);
+ hexAsciiFlag = 0;
+ } else {
+ printf("Address: Data in hex, dec, oct, bin\n");
+ for (address = 0; address < device.eepromLimit; address++) {
+ num2bin((unsigned char) eepromBuf[address], binary);
+ printf( " %#04lx: %#04x %3d %#4o %s\n",
+ address, eepromBuf[address], eepromBuf[address],
+ eepromBuf[address], binary);
+ }
+ }
+ }
+ }
+ if (checksumFlag) {
+ checksumFlag = 0;
+ readEepromArea(eepromBuf, device.eepromLimit);
+ printf("Checksum eeprom area: %04x\n",
+ checksum(eepromBuf, device.eepromLimit));
+ }
+ }
+ if (fusesFlag) {
+ fusesFlag = 0;
+ rFlag = readFuses(READ_FUSES, fusesBits, R_FUSESLSB, R_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Read_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else {
+ printf("%s are the fuse bits read from an %s\n",
+ fusesBits, device.name);
+ printf("%s\n", FUSES_MESSAGE);
+ }
+ }
+ if (highFFlag) {
+ highFFlag = 0;
+ rFlag = readFuses(READ_HIGH_FUSES, fusesBits, RH_FUSESLSB, RH_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Read_high_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else {
+ printf("%s are the high fuse bits read from an %s\n",
+ fusesBits, device.name);
+ printf("%s\n", H_FUSES_MESSAGE);
+ }
+ }
+ if (extdFFlag) {
+ extdFFlag = 0;
+ rFlag = readFuses(READ_EXTD_FUSES, fusesBits, RX_FUSESLSB, RX_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Read_extd_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else {
+ printf("%s are the extended fuse bits read from an %s\n",
+ fusesBits, device.name);
+ printf("%s\n", X_FUSES_MESSAGE);
+ }
+ }
+ if (lockFlag) {
+ lockFlag = 0;
+ rFlag = readFuses(READ_LOCK, lockBits, R_LOCKLSB, R_LOCKLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Read_locks not defined in _sp12dev.\n",
+ device.name);
+ } else {
+ printf("%s are the lock bits read from an %s\n", lockBits, device.name);
+ printf("%s\n", LOCK_MESSAGE);
+ }
+ }
+ if (calibFlag) {
+ calibFlag = 0;
+ command = READ_CALIBRATION | (calibAddress << 8);
+ rFlag = readFuses(command, calibByte, CALIBLSB, CALIBLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Read_calibration not defined in _sp12dev.\n",
+ device.name);
+ } else {
+ printf("0x%02lx is the calibration byte read from address 0x%02lx\n",
+ strtol(calibByte, NULL, 2), calibAddress);
+ printf("%s\n", CALIB_MESSAGE);
+ }
+ }
+
+ reportLEFHXcFlag();
+ reportBflag();
+ }
+ /*
+ * If w --> p || e
+ * wp --> f || a
+ * wpf --> chip erase;
+ * write file to program area
+ * wpa --> NO chip erase (warning);
+ * write address:data
+ * we --> f || a
+ * wef --> write file to eeprom area
+ * wpa --> write address:data
+ * wF --> write the fuse bits, if possible
+ * wL --> write the lock bits, if possible
+ * check for C; complete write before reading p || e
+ * back into array to compute the checksum
+ * check for E, R, S but just report them
+ */
+ if (writeFlag) {
+ writeFlag = 0;
+ timeConst.byteWrite = timeConst.byteWriteDefault;
+ timeConst.byteWriteAdjusted = 0;
+ timeConst.pageWrite = timeConst.pageWriteDefault;
+ timeConst.pageWriteAdjusted = 0;
+ writeRetries = 0;
+ if (flashFlag) {
+ flashFlag = 0;
+ if (addressAvailable) {
+ addressAvailable = 0;
+ if (device.pageMode) {
+ printf ("ERROR: Single address flash programming "
+ "not available in page mode.\n");
+ exitSp12(2);
+ }
+ printf("WARNING: writing to single address in program area.\n");
+ printf(" Chip erase is not automatic; unless you \n");
+ printf(" used a separate -E command, it may not be \n");
+ printf(" possible to correctly write new data.\n");
+ printf("Writing %#06x into address %#08x in program area.\n",
+ flashData, flashAddress);
+ error = writeFlashVerified(flashAddress, flashData, optimizeFlag);
+ if (logWrites(commandStr, flashAddress, flashData, flashPath,
+ flashBuf, overlayFlag, &error) != 0)
+ printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt");
+ if (error) {
+ printf("Readback ERROR at program address %#06x\n",
+ flashAddress);
+ exitSp12(3);
+ }
+
+ } else if (pathAvailable) { /* Write file to flash ////////////*/
+ pathAvailable = 0;
+ if (!overlayFlag) {
+ printf("Performing chip erase...\n");
+ eraseDevice();
+ }
+ if (blankChkFlag) {
+ blankChkFlag = 0;
+ if(blank_check())
+ exitSp12(3);
+ }
+ /* Read the HEX file */
+ printf("Writing content of %s into program area.\n", flashPath);
+ error = readFlashFile(flashPath, flashBuf, device.flashLimit);
+ if (error) {
+ printf("%s %s\n", flashPath, FILE_ERROR);
+ exitSp12(2);
+ }
+ /* Now copy file to flash */
+ error = writeFlashArea(flashBuf, device.flashLimit, optimizeFlag);
+ if (logWrites(commandStr, flashAddress, flashData, flashPath,
+ flashBuf, overlayFlag, &error) != 0)
+ printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt");
+ if (error) {
+ printf("Readback ERROR after %d write retries.\n", writeRetries);
+ if (overlayFlag)
+ printf("The error may be due to an overlay conflict.\n");
+ exitSp12(3);
+ } else {
+ printf("%s written and verified.\n", flashPath);
+ printf("write retries: %d\n", writeRetries);
+ }
+ } /* Up to here the file to flash functions///////////////////*/
+
+ if (checksumFlag) {
+ checksumFlag = 0;
+ readFlashArea(flashBuf, device.flashLimit);
+ printf("Checksum program area: %04x\n",
+ checksum(flashBuf, device.flashLimit));
+ }
+ }
+ if (eepromFlag) {
+ eepromFlag = 0;
+ if (addressAvailable) {
+ addressAvailable = 0;
+ printf("Writing %#x into address %#x in eeprom area.\n",
+ eepromData, eepromAddress);
+ error=writeEepromVerified(eepromAddress, eepromData, optimizeFlag);
+ if (logWrites(commandStr, eepromAddress, eepromData, eepromPath,
+ eepromBuf, overlayFlag, &error) != 0)
+ printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt");
+ if (error) {
+ printf("Readback ERROR at eeprom address %#04x\n",
+ eepromAddress);
+ exitSp12(3);
+ }
+ } else if (pathAvailable) {
+ pathAvailable = 0;
+ printf("Writing content of %s into eeprom area.\n", eepromPath);
+ error = readEepromFile(eepromPath, eepromBuf, device.eepromLimit);
+ if (error) {
+ printf("%s %s\n", eepromPath, FILE_ERROR);
+ exitSp12(2);
+ }
+ error = writeEepromArea(eepromBuf, device.eepromLimit,
+ optimizeFlag, overlayFlag);
+ if (logWrites(commandStr, eepromAddress, eepromData, eepromPath,
+ eepromBuf, overlayFlag, &error) != 0)
+ printf("%s %s\n", FILE_WRITE_ERROR, "sp12log.txt");
+ if (error) {
+ printf("Readback ERROR after %d write retries.\n", writeRetries);
+ exitSp12(3);
+ } else {
+ printf("%s written and verified.\n", eepromPath);
+ printf("write retries: %d, byteWrite: %ld percent of default\n",
+ writeRetries,
+ (timeConst.byteWrite * 100) / timeConst.byteWriteDefault);
+ }
+ }
+ if (checksumFlag) {
+ checksumFlag = 0;
+ readEepromArea(eepromBuf, device.eepromLimit);
+ printf("Checksum eeprom area: %04x\n",
+ checksum(eepromBuf, device.eepromLimit));
+ }
+ reportBflag();
+ }
+ if (lockFlag) {
+ lockFlag = 0;
+ logLocks(flashBuf, lockBits);
+ rFlag = writeFuses(WRITE_LOCK_HM, WRITE_LOCK_LM, lockBits, \
+ W_LOCKLSB, W_LOCKLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Write_lock not defined in _sp12dev.\n",
+ device.name);
+ } else if (rFlag == 2) {
+ fprintf(stderr, "For the %s: Wrong number of lock bits.\n", device.name);
+ } else {
+ for (idx = 0; idx < R_LOCKLEN - W_LOCKLEN; idx++)
+ printf(" ");
+ printf("%s are the lock bits written into an %s\n%s\n",
+ lockBits, device.name, LOCK_MESSAGE);
+ }
+ }
+ if (fusesFlag) {
+ fusesFlag = 0;
+ rFlag = writeFuses(WRITE_FUSES_HM, WRITE_FUSES_LM, fusesBits, \
+ W_FUSESLSB, W_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Write_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else if (rFlag == 2) {
+ fprintf(stderr, "For the %s; Wrong number of fuse bits.\n", device.name);
+ } else {
+ for (idx = 0; idx < (R_FUSESLEN - W_FUSESLEN) - W_FUSESLSB; idx++)
+ printf(" ");
+ printf("%s are the fuse bits written into an %s\n%s\n",
+ fusesBits, device.name, FUSES_MESSAGE);
+ }
+ }
+ if (highFFlag) {
+ highFFlag = 0;
+ rFlag = writeFuses(WRITE_HIGH_FUSES_HM, WRITE_HIGH_FUSES_LM, fusesBits, \
+ WH_FUSESLSB, WH_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Write_high_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else if (rFlag == 2) {
+ fprintf(stderr, "For the %s; Wrong number of high fuse bits.\n",
+ device.name);
+ } else {
+ for (idx = 0; idx < (RH_FUSESLEN - WH_FUSESLEN) - WH_FUSESLSB; idx++)
+ printf(" ");
+ printf("%s are the high fuse bits written into an %s\n%s\n",
+ fusesBits, device.name, H_FUSES_MESSAGE);
+ }
+ }
+ if (extdFFlag) {
+ extdFFlag = 0;
+ rFlag = writeFuses(WRITE_EXTD_FUSES_HM, WRITE_EXTD_FUSES_LM, fusesBits, \
+ WX_FUSESLSB, WX_FUSESLEN);
+ if (rFlag == 9) {
+ fprintf(stderr, "For the %s: Write_extd_fuses not defined in _sp12dev.\n",
+ device.name);
+ } else if (rFlag == 2) {
+ fprintf(stderr, "For the %s; Wrong number of high fuse bits.\n",
+ device.name);
+ } else {
+ for (idx = 0; idx < (RX_FUSESLEN - WX_FUSESLEN) - WX_FUSESLSB; idx++)
+ printf(" ");
+ printf("%s are the extended fuse bits written into an %s\n%s\n",
+ fusesBits, device.name, X_FUSES_MESSAGE);
+ }
+ }
+ reportLEFHXcFlag();
+ overlayFlag = 0;
+ }
+ /*
+ * if C --> (p || e) || ((p || e) && f)
+ * Cp(f) --> read program area (file) into
+ * device.flashLimit word array;
+ * calculate checksum for array
+ * Ce(f) --> read eeprom area (file) into
+ * device.eepromLimit byte array;
+ * calculate checksum for array
+ * check for L, E, B, F, R, S but just report them
+ */
+ if (checksumFlag) {
+ checksumFlag = 0;
+ if (eepromFlag) {
+ eepromFlag = 0;
+ if (pathAvailable) {
+ pathAvailable = 0;
+ if (readEepromFile(checksumPath, eepromBuf,
+ device.eepromLimit) != 0) {
+ printf("%s %s\n", checksumPath, FILE_ERROR);
+ exitSp12(2);
+ } else {
+ printf("Checksum eeprom file %s: %04x\n",
+ checksumPath, checksum(eepromBuf, device.eepromLimit));
+ }
+ } else {
+ readEepromArea(eepromBuf, device.eepromLimit);
+ printf("Checksum eeprom area: %04x\n",
+ checksum(eepromBuf, device.eepromLimit));
+ }
+ } else if (flashFlag) {
+ flashFlag = 0;
+ if (pathAvailable) {
+ pathAvailable = 0;
+ if (readFlashFile(checksumPath, flashBuf, device.flashLimit) != 0) {
+ printf("%s %s\n", checksumPath, FILE_ERROR);
+ exitSp12(2);
+ } else {
+ printf("Checksum program file %s: %04x\n",
+ checksumPath, checksum(flashBuf, device.flashLimit));
+ }
+ } else {
+ readFlashArea(flashBuf, device.flashLimit);
+ printf("Checksum program area: %04x\n",
+ checksum(flashBuf, device.flashLimit));
+ }
+ } else {
+ printf("you have selected option -C, but there is nothing\n");
+ printf("on the command line to calculate a checksum for.\n");
+ }
+ reportLEFHXcFlag();
+ reportBflag();
+ }
+ /*
+ * If E --> chip erase
+ */
+ if (eraseFlag) {
+ eraseFlag = 0;
+ printf("Performing chip erase...\n");
+ eraseDevice();
+ }
+ /*
+ * if B --> blank check
+ */
+ if (blankChkFlag) {
+ blankChkFlag = 0;
+ blank_check();
+ }
+ /*
+ * if i --> do nothing (init already done, device already reported)
+ * just clear initFlag
+ */
+ initFlag = 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int ascii; /* characters on command line */
+ int idx = 0; /* index arguments on command line */
+ char *dataPtr; /* for separating address:data */
+ int exitFlag = 0;
+ char binary[9] = "76543210"; /* Stores conversion num to binary */
+
+ device.initPerformed = 0;
+ flashPath[0] = '\0';
+ eepromPath[0] = '\0';
+ checksumPath[0] = '\0';
+ sp12Start = clock();
+
+#ifdef LINUX
+ /*
+ * Take control of LPT I/O ports
+ */
+ if (ioperm(0x278,3,1)) {perror("ioperm error at 0x278");exit(1);}
+ if (ioperm(0x378,3,1)) {perror("ioperm error at 0x378");exit(1);}
+ if (ioperm(0x3BC,3,1)) {perror("ioperm error at 0x3BC");exit(1);}
+ /*
+ * Revoke setuid/setguid-root status
+ */
+ setgid(getgid());
+ setuid(getuid());
+#endif
+#ifdef WIN32
+ win_giveio (); // get access to I/O ports in Windows NT/2000/XP
+#endif
+
+ /*
+ * Check if something is on the command line, print usage message
+ * if not, else do init; if in sp12 mode, put power on the device
+ * (using Centronics data bits as power source), enable serial
+ * reading/programming
+ */
+ if (argc < 2) {
+ printf(USAGE, VERSION);
+ exit(0);
+ } else {
+ printf("SP12 version %s performing init...\n", VERSION);
+ initSp12(argv[0]);
+ }
+ /*
+ * allocate our memory buffers
+ */
+ flashBuf = malloc(FLASHBUF_UPPERLIMIT * sizeof (unsigned int));
+ if (flashBuf == NULL) {
+ printf ("ERROR: No memory available for buffer!\n");
+ exitSp12(2);
+ }
+ eepromBuf = malloc(EEPROMBUF_UPPERLIMIT * sizeof (unsigned int));
+ if (eepromBuf == NULL) {
+ printf ("ERROR: No memory available for buffer!\n");
+ exitSp12(2);
+ }
+ /*
+ * Dissect the command line, acting on commands from left to right.
+ */
+ idx = 0;
+ while (++idx < argc) {
+ if (*argv[idx] != '-' && fileFlag) {
+ fileFlag = 0;
+ if (addressFlag) {
+ printf("Do not use options -f and -a in a single command.\n");
+ exitSp12(2);
+ }
+ if (checksumFlag && !readFlag && !writeFlag) {
+ strcpy(checksumPath, argv[idx]);
+ pathAvailable = 1;
+ processCommand();
+ } else if (flashFlag) {
+ strcpy(flashPath, argv[idx]);
+ pathAvailable = 1;
+ processCommand();
+ } else if (eepromFlag) {
+ strcpy(eepromPath, argv[idx]);
+ pathAvailable = 1;
+ processCommand();
+ } else {
+ printf("Option -f must be combined with option -e, -p or -C\n");
+ exitSp12(2);
+ }
+ } else if (*argv[idx] != '-' && addressFlag) {
+ addressFlag = 0;
+ dataPtr = argv[idx];
+ if (writeFlag && (dataPtr = strchr(argv[idx], ':')) == NULL) {
+ printf("Option -wa must be followed by address:data\n");
+ exitSp12(2);
+ }
+ if (writeFlag)
+ dataPtr[0] = '\0';
+ if (flashFlag) {
+ flashAddress =str2num(argv[idx]);
+ if (writeFlag)
+ flashData = str2num(++dataPtr);
+ addressAvailable = 1;
+ processCommand();
+ } else if (eepromFlag) {
+ eepromAddress =str2num(argv[idx]);
+ if (writeFlag)
+ eepromData = str2num(++dataPtr);
+ addressAvailable = 1;
+ processCommand();
+ } else {
+ printf("Option -a must be combined with option -e or -p\n");
+ exitSp12(2);
+ }
+ } else if (*argv[idx] != '-') {
+ printf("No -a or -f option preceding argument `%s'\n", argv[idx]);
+ }
+ if (*argv[idx] == '-') {
+ if (strchr(argv[idx], 'w') != NULL)
+ strcpy(commandStr, argv[idx]);
+ while ((ascii = *++argv[idx]) != '\0') {
+ switch(ascii) {
+ case 'i':
+ if (strlen(argv[idx]) > 1) {
+ initFlag = 1;
+ strcpy(identifier, ++argv[idx]);
+ argv[idx][1] = '\0';
+ }
+ if (idx > 1) {
+ printf("WARNING: option -i[NN] has no effect unless\n");
+ printf(" it is first on the command line.\n");
+ }
+ break;
+ case 'T':
+ if (strlen(argv[idx]) > 1)
+ testFlag = atoi(++argv[idx]);
+ break;
+ case 'M':
+ if (strlen(argv[idx]) > 1) {
+ clkSpeed = atof(++argv[idx]);
+ if (clkSpeed <= 0.1)
+ clkSpeed = 0.1;
+ argv[idx][1] = '\0';
+ }
+ break;
+ case 'P':
+ if (strlen(argv[idx]) > 1) {
+ if (argv[idx][2] == 'x')
+ portFlag = (int) strtol(++argv[idx], NULL, 16);
+ else
+ portFlag = (int) strtol(++argv[idx], NULL, 10);
+ if ((idx + 1) == argc)
+ exitFlag = 1;
+ else
+ exitFlag = 0;
+ portControl(portFlag, exitFlag);
+ num2bin((unsigned char) portFlag, binary);
+ printf("Writing %#04x (%d, B%s) ",
+ portFlag, portFlag, binary);
+ printf("to the parallel port data bits.\n");
+ if ((idx + 1) < argc)
+ portFlag = 0;
+ argv[idx][1] = '\0';
+ }
+ break;
+ case 'p':
+ flashFlag = 1;
+ break;
+ case 'e':
+ eepromFlag = 1;
+ break;
+ case 'w':
+ writeFlag = 1;
+ break;
+ case 'r':
+ readFlag = 1;
+ break;
+ case 'L':
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) {
+ strcpy(lockBits, ++argv[idx]);
+ argv[idx][1] = '\0';
+ }
+ lockFlag = 1;
+ break;
+ case '0':
+ if (optimizeFlag)
+ optimizeFlag = 10;
+ break;
+ case '1':
+ if (optimizeFlag && !POLL_RDY_BSY)
+ optimizeFlag = 11;
+ break;
+ case '2':
+ break;
+ case '3':
+ break;
+ case '4':
+ break;
+ case '5':
+ break;
+ case '6':
+ break;
+ case '7':
+ break;
+ case '8':
+ break;
+ case '9':
+ break;
+ case 'f':
+ fileFlag = 1;
+ break;
+ case 'a':
+ addressFlag = 1;
+ break;
+ case 'E':
+ eraseFlag = 1;
+ break;
+ case 'B':
+ blankChkFlag = 1;
+ break;
+ case 'C':
+ checksumFlag = 1;
+ break;
+ case 'F':
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) {
+ strcpy(fusesBits, ++argv[idx]);
+ argv[idx][1] = '\0';
+ }
+ fusesFlag = 1;
+ break;
+ case 'H':
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) {
+ strcpy(fusesBits, ++argv[idx]);
+ argv[idx][1] = '\0';
+ }
+ highFFlag = 1;
+ break;
+ case 'X':
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) {
+ strcpy(fusesBits, ++argv[idx]);
+ argv[idx][1] = '\0';
+ }
+ extdFFlag = 1;
+ break;
+ case 'I':
+ IntelFlag = 1;
+ break;
+ case 'c':
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) == '0' || *(argv[idx] + 1) == '1')) {
+ calibAddress = strtoul(++argv[idx], NULL, 2);
+ argv[idx][1] = '\0';
+ }
+ if (strlen(argv[idx]) > 1 \
+ && (*(argv[idx] + 1) != '0' && *(argv[idx] + 1) != '1')) {
+ calibAddress = strtoul(++argv[idx], NULL, 10);
+ argv[idx][1] = '\0';
+ }
+ calibFlag = 1;
+ break;
+ case 'h':
+ hexAsciiFlag = 1;
+ break;
+ case 'o':
+ optimizeFlag = 1;
+ break;
+ case 's':
+ supported();
+ exitSp12(0);
+ break;
+ case 't':
+ idx = 0;
+ printf("(-t)iming check, about 10 seconds\n");
+ printf("..................................................\r");
+ for (idx = 0; idx < 50; idx++) {
+ loopDelay(timeConst.resetPuls * 4);
+ putchar('o');
+ fflush(stdout);
+ }
+ printf(" STOP\n");
+ exitSp12(0);
+ break;
+ case 'O':
+ overlayFlag = 1;
+ break;
+ default:
+ printf("The character `%c' ", ascii);
+ printf("is not a valid option.\n");
+ break;
+ }
+ }
+ if (!fileFlag && !addressFlag)
+ processCommand();
+ }
+ }
+ if (fileFlag) {
+ printf("Option f used, but no path on command line.\n");
+ printf("Nothing to do for sp12.\n");
+ exitSp12(2);
+ }
+ /*
+ * Exiting with the byte `portFlag' on the parallel port data bits.
+ * When the -Tnn option is not (also) used as the final option on
+ * the command line, this defaults to 0x00.
+ */
+ if (SCK == S_SCK && testFlag) {
+ switch(testFlag) {
+ case 1:
+ portFlag = RESET;
+ break;
+ case 2:
+ portFlag = RESET | PORTPOWER;
+ break;
+ default:
+ break;
+ }
+ } else if (testFlag) {
+ printf("Option -T is not available in Kanda compatible mode.\n");
+ }
+ if (!portFlag) {
+ portFlag = DEFAULT_EXIT_STATE;
+ num2bin((unsigned char) portFlag, binary);
+ printf("Writing %#04x (%d, B%s) ",
+ portFlag, portFlag, binary);
+ printf("to the parallel port data bits.\n");
+ }
+ portControl(portFlag, 1);
+ if (SCK == S_SCK) {
+ if (portFlag & 0x02)
+ printf("Reset was left high.\n");
+ if (portFlag & 0x7C)
+ printf("One or more `power' bits were left high.\n");
+ }
+ sp12End = clock();
+ sp12Elapsed = ((double) (sp12End - sp12Start)) / CLOCKS_PER_SEC;
+ printf("Sp12 was active for %#3.2f seconds.\n", sp12Elapsed);
+ return(0);
+}