mirror of
https://github.com/ole00/afterburner.git
synced 2024-09-27 15:56:47 +00:00
babba5bca9
Previously the new line characters were expected to be part of the feed request message. This is not so on ESP32 based Arduino library implementation. The new line characters arrive later on separately after a small pause This code change fixes 'corrupted feed request' warning messages on such Arduino platforms.
1596 lines
45 KiB
C
1596 lines
45 KiB
C
/*
|
|
(banner font: aciiart.eu)
|
|
_____________________________________________________________
|
|
| _ __ _ _ \
|
|
| / \ / _| |_ ___ _ _| |__ _ _ _ __ ___ ___ _ _ |\
|
|
| / _ \| |_| '_/ _ \| '_/ '_ \| | | | '_/ _ \/ _ \| '_/ ||
|
|
| / ___ \ _| |_| __/| | | |_) | |_| | | | | | | __/| | ||
|
|
| /_/ \_\| \__\___||_| |____/\___,_|_| |_| |_|___||_| ||
|
|
\_____________________________________________________________||
|
|
'------------------------------------------------------------'
|
|
|
|
Afterburner: GAL IC Programmer for Arduino by -= olin =-
|
|
http://molej.cz/index_aft.html
|
|
|
|
Based on ATFblast 3.1 by Bruce Abbott
|
|
http://www.bhabbott.net.nz/atfblast.html
|
|
|
|
Based on GALBLAST by Manfred Winterhoff
|
|
http://www.armory.com/%7Erstevew/Public/Pgmrs/GAL/_ClikMe1st.htm
|
|
|
|
Supports:
|
|
* National GAL16V8
|
|
* Lattice GAL16V8A, GAL16V8B, GAL16V8D
|
|
* Lattice GAL22V10B
|
|
* Atmel ATF16V8B, ATF22V10B, ATF22V10CQZ
|
|
|
|
Requires:
|
|
* Arduino UNO with Afterburner sketch uploaded.
|
|
* simple programming circuit.
|
|
|
|
Changelog:
|
|
* use 'git log'
|
|
|
|
This is the PC part that communicates with Arduino UNO by serial line.
|
|
To compile: gcc -g3 -O0 -o afterburner afterburner.c
|
|
|
|
* 2024-02-02 Fixed: Command 'B9' (Calibration Offset = 0,25V) doesn't work
|
|
Note: Also requires elimination of a bug in the PC program afterburner.ino
|
|
Added: Sending B4, if b /wo -co is executed
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
|
|
#include "serial_port.h"
|
|
|
|
#define VERSION "v.0.5.8"
|
|
|
|
#ifdef GCOM
|
|
#define VERSION_EXTENDED VERSION "-" GCOM
|
|
#else
|
|
#define VERSION_EXTENDED VERSION
|
|
#endif
|
|
|
|
#define MAX_LINE (16*1024)
|
|
|
|
#define MAXFUSES 30000
|
|
#define GALBUFSIZE (256 * 1024)
|
|
|
|
#define JTAG_ID 0xFF
|
|
|
|
|
|
typedef enum {
|
|
UNKNOWN,
|
|
GAL16V8,
|
|
GAL18V10,
|
|
GAL20V8,
|
|
GAL20RA10,
|
|
GAL20XV10,
|
|
GAL22V10,
|
|
GAL26CV12,
|
|
GAL26V12,
|
|
GAL6001,
|
|
GAL6002,
|
|
ATF16V8B,
|
|
ATF20V8B,
|
|
ATF22V10B,
|
|
ATF22V10C,
|
|
ATF750C,
|
|
//jtag based PLDs at the end: they do not have a gal type in MCU software
|
|
ATF1502AS,
|
|
ATF1504AS,
|
|
} Galtype;
|
|
|
|
|
|
/* GAL info */
|
|
static struct {
|
|
Galtype type;
|
|
unsigned char id0, id1; /* variant 1, variant 2 (eg. 16V8=0x00, 16V8A+=0x1A)*/
|
|
char *name; /* pointer to chip name */
|
|
int fuses; /* total number of fuses */
|
|
int pins; /* number of pins on chip */
|
|
int rows; /* number of fuse rows */
|
|
int bits; /* number of fuses per row */
|
|
int uesrow; /* UES row number */
|
|
int uesfuse; /* first UES fuse number */
|
|
int uesbytes; /* number of UES bytes */
|
|
int eraserow; /* row adddeess for erase */
|
|
int eraseallrow; /* row address for erase all */
|
|
int pesrow; /* row address for PES read/write */
|
|
int pesbytes; /* number of PES bytes */
|
|
int cfgrow; /* row address of config bits */
|
|
int cfgbits; /* number of config bits */
|
|
}
|
|
galinfo[] = {
|
|
{UNKNOWN, 0x00, 0x00, "unknown", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0},
|
|
{GAL16V8, 0x00, 0x1A, "GAL16V8", 2194, 20, 32, 64, 32, 2056, 8, 63, 54, 58, 8, 60, 82},
|
|
{GAL18V10, 0x50, 0x51, "GAL18V10", 3540, 20, 36, 96, 36, 3476, 8, 61, 60, 58, 10, 16, 20},
|
|
{GAL20V8, 0x20, 0x3A, "GAL20V8", 2706, 24, 40, 64, 40, 2568, 8, 63, 59, 58, 8, 60, 82},
|
|
{GAL20RA10, 0x60, 0x61, "GAL20RA10", 3274, 24, 40, 80, 40, 3210, 8, 61, 60, 58, 10, 16, 10},
|
|
{GAL20XV10, 0x65, 0x66, "GAL20XV10", 1671, 24, 40, 40, 44, 1631, 5, 61, 60, 58, 5, 16, 31},
|
|
{GAL22V10, 0x48, 0x49, "GAL22V10", 5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, 20},
|
|
{GAL26CV12, 0x58, 0x59, "GAL26CV12", 6432, 28, 52, 122, 52, 6368, 8, 61, 60, 58, 12, 16},
|
|
{GAL26V12, 0x5D, 0x5D, "GAL26V12", 7912, 28, 52, 150, 52, 7848, 8, 61, 60, 58, 12, 16},
|
|
{GAL6001, 0x40, 0x41, "GAL6001", 8294, 24, 78, 75, 97, 8222, 9, 63, 62, 96, 8, 8, 68},
|
|
{GAL6002, 0x44, 0x44, "GAL6002", 8330, 24, 78, 75, 97, 8258, 9, 63, 62, 96, 8, 8, 104},
|
|
{ATF16V8B, 0x00, 0x00, "ATF16V8B", 2194, 20, 32, 64, 32, 2056, 8, 63, 54, 58, 8, 60, 82},
|
|
{ATF20V8B, 0x00, 0x00, "ATF20V8B", 2706, 24, 40, 64, 40, 2568, 8, 63, 59, 58, 8, 60, 82},
|
|
{ATF22V10B, 0x00, 0x00, "ATF22V10B", 5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, 20},
|
|
{ATF22V10C, 0x00, 0x00, "ATF22V10C", 5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, 20},
|
|
{ATF750C, 0x00, 0x00, "ATF750C", 14499, 24, 84, 171, 84, 14435, 8, 61, 60, 127, 10, 16, 71},
|
|
{ATF1502AS, JTAG_ID, JTAG_ID, "ATF1502AS", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0},
|
|
{ATF1504AS, JTAG_ID, JTAG_ID, "ATF1504AS", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0},
|
|
};
|
|
|
|
char verbose = 0;
|
|
char* filename = 0;
|
|
char* deviceName = 0;
|
|
char* pesString = NULL;
|
|
|
|
SerialDeviceHandle serialF = INVALID_HANDLE;
|
|
Galtype gal;
|
|
int security = 0;
|
|
unsigned short checksum;
|
|
char galbuffer[GALBUFSIZE];
|
|
char fusemap[MAXFUSES];
|
|
char noGalCheck = 0;
|
|
char varVppExists = 0;
|
|
char printSerialWhileWaiting = 0;
|
|
int calOffset = 0; //no calibration offset is applied
|
|
char enableSecurity = 0;
|
|
char bigRam = 0;
|
|
|
|
char opRead = 0;
|
|
char opWrite = 0;
|
|
char opErase = 0;
|
|
char opInfo = 0;
|
|
char opVerify = 0;
|
|
char opTestVPP = 0;
|
|
char opCalibrateVPP = 0;
|
|
char opMeasureVPP = 0;
|
|
char opSecureGal = 0;
|
|
char opWritePes = 0;
|
|
char flagEnableApd = 0;
|
|
char flagEraseAll = 0;
|
|
|
|
|
|
static int waitForSerialPrompt(char* buf, int bufSize, int maxDelay);
|
|
static char sendGenericCommand(const char* command, const char* errorText, int maxDelay, char printResult);
|
|
|
|
static void printGalTypes() {
|
|
int i;
|
|
for (i = 1; i < sizeof(galinfo) / sizeof(galinfo[0]); i++) {
|
|
if (i % 8 == 1) {
|
|
printf("\n\t");
|
|
} else
|
|
if (i > 1) {
|
|
printf(" ");
|
|
}
|
|
printf("%s", galinfo[i].name);
|
|
}
|
|
}
|
|
|
|
static void printHelp() {
|
|
printf("Afterburner " VERSION_EXTENDED " a GAL programming tool for Arduino based programmer\n");
|
|
printf("more info: https://github.com/ole00/afterburner\n");
|
|
printf("usage: afterburner command(s) [options]\n");
|
|
printf("commands: ierwvsbm\n");
|
|
printf(" i : read device info and programming voltage\n");
|
|
printf(" r : read fuse map from the GAL chip and display it, -t option must be set\n");
|
|
printf(" w : write fuse map, -f and -t options must be set\n");
|
|
printf(" v : verify fuse map, -f and -t options must be set\n");
|
|
printf(" e : erase the GAL chip, -t option must be set. Optionally '-all' can be set.\n");
|
|
printf(" p : write PES. -t and -pes options must be set. GAL must be erased with '-all' option.\n");
|
|
printf(" s : set VPP ON to check the programming voltage. Ensure the GAL is NOT inserted.\n");
|
|
printf(" b : calibrate variable VPP on new board designs. Ensure the GAL is NOT inserted.\n");
|
|
printf(" m : measure variable VPP on new board designs. Ensure the GAL is NOT inserted.\n");
|
|
printf("options:\n");
|
|
printf(" -v : verbose mode\n");
|
|
printf(" -t <gal_type> : the GAL type. use ");
|
|
printGalTypes();
|
|
printf("\n");
|
|
printf(" -f <file> : JEDEC fuse map file\n");
|
|
printf(" -d <serial_device> : name of the serial device. Without this option the device is guessed.\n");
|
|
printf(" serial params are: 57600, 8N1\n");
|
|
printf(" -nc : do not check device GAL type before operation: force the GAL type set on command line\n");
|
|
printf(" -sec: enable security - protect the chip. Use with 'w' or 'v' commands.\n");
|
|
printf(" -co <offset>: Set calibration offset. Use with 'b' command. Value: -20 (-0.2V) to 25 (+0.25V)\n");
|
|
printf(" -all: use with 'e' command to erase all data including PES.\n");
|
|
printf(" -pes <PES> : use with 'p' command to specify new PES. PES format is 8 hex bytes with a delimiter.\n");
|
|
printf(" For example 00:03:3A:A1:00:00:00:90\n");
|
|
printf("examples:\n");
|
|
printf(" afterburner i -t ATF16V8B : reads and prints the device info\n");
|
|
printf(" afterburner r -t ATF16V8B : reads the fuse map from the GAL chip and displays it\n");
|
|
printf(" afterburner wv -f fuses.jed -t ATF16V8B : reads fuse map from file and writes it to \n");
|
|
printf(" the GAL chip. Does the fuse map verification at the end.\n");
|
|
printf(" afterburner ep -t GAL20V8 -all -pes 00:03:3A:A1:00:00:00:90 Fully erases the GAL chip\n");
|
|
printf(" and writes new PES. Does not work with Atmel chips.\n");
|
|
printf("hints:\n");
|
|
printf(" - use the 'i' command first to check and set the right programming voltage (VPP)\n");
|
|
printf(" of the chip. If the programing voltage is unknown use 10V.\n");
|
|
printf(" - known VPP voltages as tested on Afterburner with Arduino UNO: \n");
|
|
printf(" Lattice GAL16V8D, GAL20V8B, GAL22V10D: 12V \n");
|
|
printf(" Atmel ATF16V8B, ATF16V8C, ATF22V10C: 11V \n");
|
|
}
|
|
|
|
static int8_t verifyArgs(char* type) {
|
|
if (!opRead && !opWrite && !opErase && !opInfo && !opVerify && !opTestVPP && !opCalibrateVPP && !opMeasureVPP && !opWritePes) {
|
|
printHelp();
|
|
printf("Error: no command specified.\n");
|
|
return -1;
|
|
}
|
|
if (opWritePes && (NULL == pesString || strlen(pesString) != 23)) {
|
|
printf("Error: invalid or no PES specified.\n");
|
|
return -1;
|
|
}
|
|
if ((opRead || opWrite || opVerify) && opErase && flagEraseAll) {
|
|
printf("Error: invalid command combination. Use 'Erase all' in a separate step\n");
|
|
return -1;
|
|
}
|
|
if ((opRead || opWrite || opVerify) && (opTestVPP || opCalibrateVPP || opMeasureVPP)) {
|
|
printf("Error: VPP functions can not be conbined with read/write/verify operations\n");
|
|
return -1;
|
|
}
|
|
if (0 == type && (opWrite || opRead || opErase || opVerify || opInfo || opWritePes)) {
|
|
printf("Error: missing GAL type. Use -t <type> to specify.\n");
|
|
return -1;
|
|
} else if (0 != type) {
|
|
int i;
|
|
for (i = 1; i < sizeof(galinfo) / sizeof(galinfo[0]); i++) {
|
|
if (strcmp(type, galinfo[i].name) == 0) {
|
|
gal = galinfo[i].type;
|
|
break;
|
|
}
|
|
}
|
|
if (UNKNOWN == gal) {
|
|
printf("Error: unknown GAL type. Types: ");
|
|
printGalTypes();
|
|
printf("\n");
|
|
return -1;
|
|
}
|
|
}
|
|
if (0 == filename && (opWrite == 1 || opVerify == 1)) {
|
|
printf("Error: missing %s filename (param: -f fname)\n", galinfo[gal].id0 == JTAG_ID ? ".xsvf" : ".jed");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int8_t checkArgs(int argc, char** argv) {
|
|
int i;
|
|
char* type = 0;
|
|
char* modes = 0;
|
|
|
|
gal = UNKNOWN;
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
char* param = argv[i];
|
|
if (strcmp("-t", param) == 0) {
|
|
i++;
|
|
type = argv[i];
|
|
} else if (strcmp("-v", param) == 0) {
|
|
verbose = 1;
|
|
} else if (strcmp("-f", param) == 0) {
|
|
i++;
|
|
filename = argv[i];
|
|
} else if (strcmp("-d", param) == 0) {
|
|
i++;
|
|
deviceName = argv[i];
|
|
} else if (strcmp("-nc", param) == 0) {
|
|
noGalCheck = 1;
|
|
} else if (strcmp("-sec", param) == 0) {
|
|
opSecureGal = 1;
|
|
} else if (strcmp("-all", param) == 0) {
|
|
flagEraseAll = 1;
|
|
} else if (strcmp("-pes", param) == 0) {
|
|
i++;
|
|
pesString = argv[i];
|
|
} else if (strcmp("-co", param) == 0) {
|
|
i++;
|
|
calOffset = atoi(argv[i]);
|
|
if (calOffset < -32 || calOffset > 32) {
|
|
printf("Calibration offset out of range (-32..32 inclusive).\n");
|
|
}
|
|
if (calOffset < -32) {
|
|
calOffset = -32;
|
|
} else if (calOffset > 32) {
|
|
calOffset = 32;
|
|
}
|
|
}
|
|
else if (param[0] != '-') {
|
|
modes = param;
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
while (modes != 0 && modes[i] != 0) {
|
|
switch (modes[i]) {
|
|
case 'r':
|
|
opRead = 1;
|
|
break;
|
|
case 'w':
|
|
opWrite = 1;
|
|
break;
|
|
case 'v':
|
|
opVerify = 1;
|
|
break;
|
|
case 'e':
|
|
opErase = 1;
|
|
break;
|
|
case 'i':
|
|
opInfo = 1;
|
|
break;
|
|
case 's':
|
|
opTestVPP = 1;
|
|
break;
|
|
case 'b':
|
|
opCalibrateVPP = 1;
|
|
break;
|
|
case 'm':
|
|
opMeasureVPP = 1;
|
|
break;
|
|
case 'p':
|
|
opWritePes = 1;
|
|
break;
|
|
default:
|
|
printf("Error: unknown operation '%c' \n", modes[i]);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (verifyArgs(type)) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static unsigned short checkSum(unsigned short n) {
|
|
unsigned short c, e, i;
|
|
unsigned long a;
|
|
|
|
c = e = 0;
|
|
a = 0;
|
|
for (i = 0; i < n; i++) {
|
|
e++;
|
|
if (e == 9) {
|
|
e = 1;
|
|
a += c;
|
|
c = 0;
|
|
}
|
|
c >>= 1;
|
|
if (fusemap[i]) {
|
|
c += 0x80;
|
|
}
|
|
}
|
|
return (unsigned short)((c >> (8 - e)) + a);
|
|
}
|
|
|
|
static int parseFuseMap(char *ptr) {
|
|
int i, n, type, checksumpos, address, pins, lastfuse;
|
|
int state = 0; // 0=outside JEDEC, 1=skipping comment or unknown, 2=read command
|
|
|
|
security = 0;
|
|
checksum = 0;
|
|
checksumpos = 0;
|
|
pins = 0;
|
|
lastfuse = 0;
|
|
|
|
for (n = 0; ptr[n]; n++) {
|
|
if (ptr[n] == '*') {
|
|
state = 2;
|
|
} else
|
|
switch (state) {
|
|
case 2:
|
|
if (!isspace(ptr[n]))
|
|
switch (ptr[n]) {
|
|
case 'L':
|
|
address = 0;
|
|
state = 3;
|
|
break;
|
|
case 'F':
|
|
state = 5;
|
|
break;
|
|
case 'G':
|
|
state = 13;
|
|
break;
|
|
case 'Q':
|
|
state = 7;
|
|
break;
|
|
case 'C':
|
|
checksumpos = n;
|
|
state = 14;
|
|
break;
|
|
default:
|
|
state = 1;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (!isdigit(ptr[n])) {
|
|
return n;
|
|
}
|
|
address = ptr[n] - '0';
|
|
state = 4;
|
|
break;
|
|
case 4:
|
|
if (isspace(ptr[n])) {
|
|
state = 6;
|
|
} else if (isdigit(ptr[n])) {
|
|
address = 10 * address + (ptr[n] - '0');
|
|
} else {
|
|
return n;
|
|
}
|
|
break;
|
|
case 5:
|
|
if (isspace(ptr[n])) break; // ignored
|
|
if (ptr[n] == '0' || ptr[n] == '1') {
|
|
memset(fusemap, ptr[n] - '0', sizeof(fusemap));
|
|
} else {
|
|
return n;
|
|
}
|
|
state = 1;
|
|
break;
|
|
case 6:
|
|
if (isspace(ptr[n])) break; // ignored
|
|
if (ptr[n] == '0' || ptr[n] == '1') {
|
|
fusemap[address++] = ptr[n] - '0';
|
|
} else {
|
|
return n;
|
|
}
|
|
break;
|
|
case 7:
|
|
if (isspace(ptr[n])) break; // ignored
|
|
if (ptr[n] == 'P') {
|
|
pins = 0;
|
|
state = 8;
|
|
} else if (ptr[n] == 'F') {
|
|
lastfuse = 0;
|
|
state = 9;
|
|
} else {
|
|
state = 2;
|
|
}
|
|
break;
|
|
case 8:
|
|
if (isspace(ptr[n])) break; // ignored
|
|
if (!isdigit(ptr[n])) return n;
|
|
pins = ptr[n] - '0';
|
|
state = 10;
|
|
break;
|
|
case 9:
|
|
if (isspace(ptr[n])) break; // ignored
|
|
if (!isdigit(ptr[n])) return n;
|
|
lastfuse = ptr[n] - '0';
|
|
state = 11;
|
|
break;
|
|
case 10:
|
|
if (isdigit(ptr[n])) {
|
|
pins = 10 * pins + (ptr[n] - '0');
|
|
} else if (isspace(ptr[n])) {
|
|
state = 12;
|
|
} else {
|
|
return n;
|
|
}
|
|
break;
|
|
case 11:
|
|
if (isdigit(ptr[n])) {
|
|
lastfuse = 10 * lastfuse + (ptr[n] - '0');
|
|
} else if (isspace(ptr[n])) {
|
|
state = 12;
|
|
} else {
|
|
return n;
|
|
}
|
|
break;
|
|
case 12:
|
|
if (!isspace(ptr[n])) {
|
|
return n;
|
|
}
|
|
break;
|
|
case 13:
|
|
if (isspace(ptr[n])) break; // ignored
|
|
if (ptr[n] == '0' || ptr[n] == '1') {
|
|
security = ptr[n] - '0';
|
|
} else {
|
|
return n;
|
|
}
|
|
state = 1;
|
|
break;
|
|
case 14:
|
|
if (isspace(ptr[n])) break; // ignored
|
|
if (isdigit(ptr[n])) {
|
|
checksum = ptr[n] - '0';
|
|
} else if (toupper(ptr[n]) >= 'A' && toupper(ptr[n]) <= 'F') {
|
|
checksum = toupper(ptr[n]) - 'A' + 10;
|
|
} else return n;
|
|
state = 15;
|
|
break;
|
|
case 15:
|
|
if (isdigit(ptr[n])) {
|
|
checksum = 16 * checksum + ptr[n] - '0';
|
|
} else if (toupper(ptr[n]) >= 'A' && toupper(ptr[n]) <= 'F') {
|
|
checksum = 16 * checksum + toupper(ptr[n]) - 'A' + 10;
|
|
} else if (isspace(ptr[n])) {
|
|
state = 2;
|
|
} else return n;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (lastfuse || pins) {
|
|
int cs = checkSum(lastfuse);
|
|
if (checksum && checksum != cs) {
|
|
printf("Checksum does not match! given=0x%04X calculated=0x%04X last fuse=%i\n", checksum, cs, lastfuse);
|
|
}
|
|
|
|
for (type = 0, i = 1; i < sizeof(galinfo) / sizeof(galinfo[0]); i++) {
|
|
if (
|
|
(lastfuse == 0 ||
|
|
galinfo[i].fuses == lastfuse ||
|
|
(galinfo[i].uesfuse == lastfuse && galinfo[i].uesfuse + 8 * galinfo[i].uesbytes == galinfo[i].fuses))
|
|
&&
|
|
(pins == 0 ||
|
|
galinfo[i].pins == pins ||
|
|
(galinfo[i].pins == 24 && pins == 28))
|
|
) {
|
|
if (gal == 0) {
|
|
type = i;
|
|
break;
|
|
} else if (!type) {
|
|
type = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (lastfuse == 2195 && gal == ATF16V8B) {
|
|
flagEnableApd = fusemap[2194];
|
|
if (verbose) {
|
|
printf("PD fuse detected: %i\n", fusemap[2194]);
|
|
}
|
|
}
|
|
if (lastfuse == 5893 && gal == ATF22V10C) {
|
|
flagEnableApd = fusemap[5892];
|
|
if (verbose) {
|
|
printf("PD fuse detected: %i\n", fusemap[5892]);
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static char readFile(int* fileSize) {
|
|
FILE* f;
|
|
int size;
|
|
|
|
if (verbose) {
|
|
printf("opening file: '%s'\n", filename);
|
|
}
|
|
f = fopen(filename, "rb");
|
|
if (f) {
|
|
size = fread(galbuffer, 1, GALBUFSIZE, f);
|
|
fclose(f);
|
|
galbuffer[size] = 0;
|
|
} else {
|
|
printf("Error: failed to open file: %s\n", filename);
|
|
return -1;
|
|
}
|
|
if (fileSize != NULL) {
|
|
*fileSize = size;
|
|
if (verbose) {
|
|
printf("file size: %d'\n", size);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static char checkForString(char* buf, int start, const char* key) {
|
|
int labelPos = strstr(buf + start, key) - buf;
|
|
return (labelPos > 0 && labelPos < 500) ? 1 : 0;
|
|
}
|
|
|
|
static int openSerial(void) {
|
|
char buf[512] = {0};
|
|
char devName[256] = {0};
|
|
int total;
|
|
int labelPos;
|
|
|
|
|
|
//open device name
|
|
if (deviceName == 0) {
|
|
serialDeviceGuessName(&deviceName);
|
|
}
|
|
snprintf(devName, sizeof(devName), "%s", (deviceName == 0) ? DEFAULT_SERIAL_DEVICE_NAME : deviceName);
|
|
serialDeviceCheckName(devName, sizeof(devName));
|
|
|
|
if (verbose) {
|
|
printf("opening serial: %s\n", devName);
|
|
}
|
|
|
|
serialF = serialDeviceOpen(devName);
|
|
if (serialF == INVALID_HANDLE) {
|
|
printf("Error: failed to open serial device: %s\n", devName);
|
|
return -2;
|
|
}
|
|
|
|
|
|
// prod the programmer to output it's identification
|
|
sprintf(buf, "*\r");
|
|
serialDeviceWrite(serialF, buf, 2);
|
|
|
|
//read programmer's message
|
|
total = waitForSerialPrompt(buf, 512, 3000);
|
|
buf[total] = 0;
|
|
|
|
//check we are communicating with Afterburner programmer
|
|
labelPos = strstr(buf, "AFTerburner v.") - buf;
|
|
|
|
bigRam = 0;
|
|
if (labelPos >= 0 && labelPos < 500 && buf[total - 3] == '>') {
|
|
// check for new board desgin: variable VPP
|
|
varVppExists = checkForString(buf, labelPos, " varVpp ");
|
|
if (verbose && varVppExists) {
|
|
printf("variable VPP board detected\n");
|
|
}
|
|
// check for Big Ram
|
|
bigRam = checkForString(buf, labelPos, " RAM-BIG");
|
|
if (verbose & bigRam) {
|
|
printf("MCU Big RAM detected\n");
|
|
}
|
|
//all OK
|
|
return 0;
|
|
}
|
|
if (verbose) {
|
|
printf("Output from programmer not recognised: %s\n", buf);
|
|
}
|
|
serialDeviceClose(serialF);
|
|
serialF = INVALID_HANDLE;
|
|
return -4;
|
|
}
|
|
|
|
static void closeSerial(void) {
|
|
if (INVALID_HANDLE == serialF) {
|
|
return;
|
|
}
|
|
serialDeviceClose(serialF);
|
|
serialF = INVALID_HANDLE;
|
|
}
|
|
|
|
|
|
static int checkPromptExists(char* buf, int bufSize) {
|
|
int i;
|
|
for (i = 0; i < bufSize - 2 && buf[i] != 0; i++) {
|
|
if (buf[i] == '>' && buf[i+1] == '\r' && buf[i+2] == '\n') {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static char* stripPrompt(char* buf) {
|
|
int len;
|
|
int i;
|
|
if (buf == 0) {
|
|
return 0;
|
|
}
|
|
len = strlen(buf);
|
|
i = checkPromptExists(buf, len);
|
|
if (i >= 0) {
|
|
buf[i] = 0;
|
|
len = i;
|
|
}
|
|
|
|
//strip rear new line characters
|
|
for (i = len - 1; i >= 0; i--) {
|
|
if (buf[i] != '\r' && buf[i] != '\n') {
|
|
break;
|
|
} else {
|
|
buf[i] = 0;
|
|
}
|
|
}
|
|
|
|
//strip frontal new line characters
|
|
for (i = 0; buf[i] != 0; i++) {
|
|
if (buf[0] == '\r' || buf[0] == '\n') {
|
|
buf++;
|
|
}
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
//finds beginnig of the last line
|
|
static char* findLastLine(char* buf) {
|
|
int i;
|
|
char* result = buf;
|
|
|
|
if (buf == 0) {
|
|
return 0;
|
|
}
|
|
for (i = 0; buf[i] != 0; i++) {
|
|
if (buf[i] == '\r' || buf[i] == '\n') {
|
|
result = buf + i + 1;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static char* printBuffer(char* bufPrint, int readSize) {
|
|
int i;
|
|
char doPrint = 1;
|
|
for (i = 0; i < readSize;i++) {
|
|
if (*bufPrint == '>') {
|
|
doPrint = 0;
|
|
}
|
|
if (doPrint) {
|
|
printf("%c", *bufPrint);
|
|
if (*bufPrint == '\n' || *bufPrint == '\r') {
|
|
fflush(stdout);
|
|
}
|
|
bufPrint++;
|
|
}
|
|
}
|
|
return bufPrint;
|
|
}
|
|
|
|
static int waitForSerialPrompt(char* buf, int bufSize, int maxDelay) {
|
|
char* bufStart = buf;
|
|
int bufTotal = bufSize;
|
|
int bufPos = 0;
|
|
int readSize;
|
|
char* bufPrint = buf;
|
|
char doPrint = printSerialWhileWaiting;
|
|
|
|
memset(buf, 0, bufSize);
|
|
|
|
while (maxDelay > 0) {
|
|
readSize = serialDeviceRead(serialF, buf, bufSize);
|
|
if (readSize > 0) {
|
|
bufPos += readSize;
|
|
if (checkPromptExists(bufStart, bufTotal) >= 0) {
|
|
maxDelay = 4; //force exit, but read the rest of the line
|
|
} else {
|
|
buf += readSize;
|
|
bufSize -= readSize;
|
|
if (bufSize <= 0) {
|
|
printf("ERROR: serial port read buffer is too small!\nAre you dumping large amount of data?\n");
|
|
return -1;
|
|
}
|
|
}
|
|
if (printSerialWhileWaiting) {
|
|
bufPrint = printBuffer(bufPrint, readSize);
|
|
}
|
|
}
|
|
if (maxDelay > 0) {
|
|
/* WIN_API handles timeout itself */
|
|
#ifndef _USE_WIN_API_
|
|
usleep(10 * 1000);
|
|
maxDelay -= 10;
|
|
#else
|
|
maxDelay -= 30;
|
|
#endif
|
|
if(maxDelay <= 0 && verbose) {
|
|
printf("waitForSerialPrompt timed out\n");
|
|
}
|
|
}
|
|
}
|
|
return bufPos;
|
|
}
|
|
|
|
static int sendBuffer(char* buf) {
|
|
int total;
|
|
int writeSize;
|
|
|
|
if (buf == 0) {
|
|
return -1;
|
|
}
|
|
total = strlen(buf);
|
|
// write the query into the serial port's file
|
|
// file is opened non blocking so we have to ensure all contents is written
|
|
while (total > 0) {
|
|
writeSize = serialDeviceWrite(serialF, buf, total);
|
|
if (writeSize < 0) {
|
|
printf("ERROR: written: %i (%s)\n", writeSize, strerror(errno));
|
|
return -4;
|
|
}
|
|
buf += writeSize;
|
|
total -= writeSize;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int sendLine(char* buf, int bufSize, int maxDelay) {
|
|
int total;
|
|
char* obuf = buf;
|
|
|
|
if (serialF == INVALID_HANDLE) {
|
|
return -1;
|
|
}
|
|
|
|
total = sendBuffer(buf);
|
|
if (total) {
|
|
return total;
|
|
}
|
|
|
|
total = waitForSerialPrompt(obuf, bufSize, (maxDelay < 0) ? 6 : maxDelay);
|
|
if (total < 0) {
|
|
return total;
|
|
}
|
|
obuf[total] = 0;
|
|
obuf = stripPrompt(obuf);
|
|
if (verbose) {
|
|
printf("read: %i '%s'\n", total, obuf);
|
|
}
|
|
|
|
return total;
|
|
}
|
|
|
|
static void updateProgressBar(char* label, int current, int total) {
|
|
int done = ((current + 1) * 40) / total;
|
|
if (current >= total) {
|
|
printf("%s%5d/%5d |########################################|\n", label, total, total);
|
|
} else {
|
|
printf("%s%5d/%5d |", label, current, total);
|
|
printf("%.*s%*s|\r", done, "########################################", 40 - done, "");
|
|
fflush(stdout); //flush the text out so that the animation of the progress bar looks smooth
|
|
}
|
|
}
|
|
|
|
// Upload fusemap in byte format (as opposed to bit format used in JEDEC file).
|
|
static char upload() {
|
|
char fuseSet;
|
|
char buf[MAX_LINE];
|
|
char line[64];
|
|
unsigned int i, j, n;
|
|
unsigned short csum;
|
|
int apdFuse = flagEnableApd;
|
|
int totalFuses = galinfo[gal].fuses;
|
|
|
|
if (apdFuse) {
|
|
totalFuses++;
|
|
}
|
|
|
|
// Start upload
|
|
sprintf(buf, "u\r");
|
|
sendLine(buf, MAX_LINE, 20);
|
|
|
|
//device type
|
|
sprintf(buf, "#t %c %s\r", '0' + (int) gal, galinfo[gal].name);
|
|
sendLine(buf, MAX_LINE, 300);
|
|
|
|
//fuse map
|
|
buf[0] = 0;
|
|
fuseSet = 0;
|
|
|
|
printf("Uploading fuse map...\n");
|
|
for (i = 0; i < totalFuses;) {
|
|
unsigned char f = 0;
|
|
if (i % 32 == 0) {
|
|
if (i != 0) {
|
|
strcat(buf, "\r");
|
|
//the buffer contains at least one fuse set to 1
|
|
if (fuseSet) {
|
|
#ifdef DEBUG_UPLOAD
|
|
printf("%s\n", buf);
|
|
#endif
|
|
sendLine(buf, MAX_LINE, 100);
|
|
buf[0] = 0;
|
|
}
|
|
fuseSet = 0;
|
|
}
|
|
sprintf(buf, "#f %04i ", i);
|
|
}
|
|
f = 0;
|
|
for (j = 0; j < 8 && i < totalFuses; j++,i++) {
|
|
if (fusemap[i]) {
|
|
f |= (1 << j);
|
|
fuseSet = 1;
|
|
}
|
|
}
|
|
|
|
sprintf(line, "%02X", f);
|
|
strcat(buf, line);
|
|
|
|
updateProgressBar("", i, totalFuses);
|
|
}
|
|
updateProgressBar("", totalFuses, totalFuses);
|
|
|
|
// send last unfinished fuse line
|
|
if (fuseSet) {
|
|
strcat(buf, "\r");
|
|
#ifdef DEBUG_UPLOAD
|
|
printf("%s\n", buf);
|
|
#endif
|
|
sendLine(buf, MAX_LINE, 100);
|
|
}
|
|
|
|
//checksum
|
|
csum = checkSum(totalFuses);
|
|
if (verbose) {
|
|
printf("sending csum: %04X\n", csum);
|
|
}
|
|
sprintf(buf, "#c %04X\r", csum);
|
|
sendLine(buf, MAX_LINE, 300);
|
|
|
|
//end of upload
|
|
return sendGenericCommand("#e\r", "Upload failed", 300, 0);
|
|
|
|
}
|
|
|
|
//returns 0 on success
|
|
static char sendGenericCommand(const char* command, const char* errorText, int maxDelay, char printResult) {
|
|
char buf[MAX_LINE];
|
|
int readSize;
|
|
|
|
sprintf(buf, "%s", command);
|
|
readSize = sendLine(buf, MAX_LINE, maxDelay);
|
|
if (readSize < 0) {
|
|
if (verbose) {
|
|
printf("%s\n", errorText);
|
|
}
|
|
return -1;
|
|
} else {
|
|
char* response = stripPrompt(buf);
|
|
char* lastLine = findLastLine(response);
|
|
if (lastLine == 0 || (lastLine[0] == 'E' && lastLine[1] == 'R')) {
|
|
printf("%s\n", response);
|
|
return -1;
|
|
} else if (printResult && printSerialWhileWaiting == 0) {
|
|
printf("%s\n", response);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static char operationWriteOrVerify(char doWrite) {
|
|
char buf[MAX_LINE];
|
|
int readSize;
|
|
|
|
char result;
|
|
|
|
if (readFile(NULL)) {
|
|
return -1;
|
|
}
|
|
|
|
result = parseFuseMap(galbuffer);
|
|
if (verbose) {
|
|
printf("parse result=%i\n", result);
|
|
}
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
// set power-down fuse bit (do it before upload to correctly calculate check-sum)
|
|
result = sendGenericCommand(flagEnableApd ? "z\r" : "Z\r", "APD set failed ?", 4000, 0);
|
|
if (result) {
|
|
goto finish;
|
|
}
|
|
result = upload();
|
|
if (result) {
|
|
return result;
|
|
}
|
|
|
|
// write command
|
|
if (doWrite) {
|
|
result = sendGenericCommand("w\r", "write failed ?", 8000, 0);
|
|
if (result) {
|
|
goto finish;
|
|
}
|
|
}
|
|
|
|
// verify command
|
|
if (opVerify) {
|
|
result = sendGenericCommand("v\r", "verify failed ?", 8000, 0);
|
|
}
|
|
finish:
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
|
|
static char operationReadInfo(void) {
|
|
|
|
char result;
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (verbose) {
|
|
printf("sending 'p' command...\n");
|
|
}
|
|
result = sendGenericCommand("p\r", "info failed ?", 4000, 1);
|
|
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
// Test of programming voltage. Most chips require +12V to start prograaming.
|
|
// This test function turns ON the ENable pin so the Programming voltage is set.
|
|
// After 20 seconds the ENable pin is turned OFF. This gives you time to turn the
|
|
// pot on the MT3608 module and calibrate the right voltage for the GAL chip.
|
|
static char operationTestVpp(void) {
|
|
|
|
char result;
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (verbose) {
|
|
printf("sending 't' command...\n");
|
|
}
|
|
if (varVppExists) {
|
|
printf("Turn the Pot on the MT3608 module to set the VPP to 16.5V (+/- 0.05V)\n");
|
|
} else {
|
|
printf("Turn the Pot on the MT3608 module to check / set the VPP\n");
|
|
}
|
|
//print the measured voltages if the feature is available
|
|
printSerialWhileWaiting = 1;
|
|
|
|
//Voltage testing takes ~20 seconds
|
|
result = sendGenericCommand("t\r", "info failed ?", 22000, 1);
|
|
printSerialWhileWaiting = 0;
|
|
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
static char operationCalibrateVpp(void) {
|
|
char result;
|
|
char cmd [8] = {0};
|
|
char val = (char)('0' + (calOffset + 32));
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
sprintf(cmd, "B%c\r", val);
|
|
if (verbose) {
|
|
printf("sending 'B%c' command...\n", val);
|
|
}
|
|
result = sendGenericCommand(cmd, "VPP cal. offset failed", 4000, 1);
|
|
|
|
if (verbose) {
|
|
printf("sending 'b' command...\n");
|
|
}
|
|
|
|
printf("VPP voltages are scanned - this might take a while...\n");
|
|
printSerialWhileWaiting = 1;
|
|
result = sendGenericCommand("b\r", "VPP calibration failed", 34000, 1);
|
|
printSerialWhileWaiting = 0;
|
|
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
static char operationMeasureVpp(void) {
|
|
char result;
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (verbose) {
|
|
printf("sending 'm' command...\n");
|
|
}
|
|
|
|
//print the measured voltages if the feature is available
|
|
printSerialWhileWaiting = 1;
|
|
result = sendGenericCommand("m\r", "VPP measurement failed", 40000, 1);
|
|
printSerialWhileWaiting = 0;
|
|
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
|
|
static char operationSetGalCheck(void) {
|
|
int readSize;
|
|
char result;
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
result = sendGenericCommand(noGalCheck ? "F\r" : "f\r", "noGalCheck failed ?", 4000, 0);
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
static char operationSetGalType(Galtype type) {
|
|
char buf[MAX_LINE];
|
|
int readSize;
|
|
char result;
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
if (verbose) {
|
|
printf("sending 'g' command type=%i\n", type);
|
|
}
|
|
sprintf(buf, "g%c\r", '0' + (int)type);
|
|
result = sendGenericCommand(buf, "setGalType failed ?", 4000, 0);
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
static char operationSecureGal() {
|
|
int readSize;
|
|
char result;
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
if (verbose) {
|
|
printf("sending 's' command...\n");
|
|
}
|
|
result = sendGenericCommand("s\r", "secure GAL failed ?", 4000, 0);
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
static char operationWritePes(void) {
|
|
char buf[MAX_LINE];
|
|
int readSize;
|
|
char result;
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
//Switch to upload mode to specify GAL
|
|
sprintf(buf, "u\r");
|
|
sendLine(buf, MAX_LINE, 300);
|
|
|
|
//set GAL type
|
|
sprintf(buf, "#t %c\r", '0' + (int) gal);
|
|
sendLine(buf, MAX_LINE, 300);
|
|
|
|
//set new PES
|
|
sprintf(buf, "#p %s\r", pesString);
|
|
sendLine(buf, MAX_LINE, 300);
|
|
|
|
//Exit upload mode (ensure the return texts are discarded by waiting 100 ms)
|
|
sprintf(buf, "#e\r");
|
|
sendLine(buf, MAX_LINE, 100);
|
|
|
|
if (verbose) {
|
|
printf("sending 'P' command...\n");
|
|
}
|
|
result = sendGenericCommand("P\r", "write PES failed ?", 4000, 0);
|
|
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
static char operationEraseGal(void) {
|
|
char buf[MAX_LINE];
|
|
int readSize;
|
|
char result;
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
//Switch to upload mode to specify GAL
|
|
sprintf(buf, "u\r");
|
|
sendLine(buf, MAX_LINE, 300);
|
|
|
|
//set GAL type
|
|
sprintf(buf, "#t %c\r", '0' + (int) gal);
|
|
sendLine(buf, MAX_LINE, 300);
|
|
|
|
//Exit upload mode (ensure the return texts are discarded by waiting 100 ms)
|
|
sprintf(buf, "#e\r");
|
|
sendLine(buf, MAX_LINE, 100);
|
|
|
|
if (flagEraseAll) {
|
|
result = sendGenericCommand("~\r", "erase all failed ?", 4000, 0);
|
|
} else {
|
|
result = sendGenericCommand("c\r", "erase failed ?", 4000, 0);
|
|
}
|
|
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
static char operationReadFuses(void) {
|
|
char* response;
|
|
char* buf = galbuffer;
|
|
int readSize;
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
//Switch to upload mode to specify GAL
|
|
sprintf(buf, "u\r");
|
|
sendLine(buf, MAX_LINE, 100);
|
|
|
|
//set GAL type
|
|
sprintf(buf, "#t %c\r", '0' + (int) gal);
|
|
sendLine(buf, MAX_LINE, 100);
|
|
|
|
//Exit upload mode (ensure the texts are discarded by waiting 100 ms)
|
|
sprintf(buf, "#e\r");
|
|
sendLine(buf, MAX_LINE, 1000);
|
|
|
|
//READ_FUSE command
|
|
sprintf(buf, "r\r");
|
|
readSize = sendLine(buf, GALBUFSIZE, 12000);
|
|
if (readSize < 0) {
|
|
return -1;
|
|
}
|
|
response = stripPrompt(buf);
|
|
printf("%s\n", response);
|
|
|
|
closeSerial();
|
|
|
|
if (response[0] == 'E' && response[1] == 'R') {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int readJtagSerialLine(char* buf, int bufSize, int maxDelay, int* feedRequest) {
|
|
char* bufStart = buf;
|
|
int readSize;
|
|
int bufPos = 0;
|
|
|
|
memset(buf, 0, bufSize);
|
|
|
|
while (maxDelay > 0) {
|
|
readSize = serialDeviceRead(serialF, buf, 1);
|
|
if (readSize > 0) {
|
|
bufPos += readSize;
|
|
buf[1] = 0;
|
|
//handle the feed request
|
|
if (buf[0] == '$') {
|
|
char tmp[5];
|
|
bufPos -= readSize;
|
|
buf[0] = 0;
|
|
//extra 5 bytes should be present: 3 bytes of size, 2 new line chars
|
|
readSize = serialDeviceRead(serialF, tmp, 3);
|
|
if (readSize == 3) {
|
|
int retry = 1000;
|
|
tmp[3] = 0;
|
|
*feedRequest = atoi(tmp);
|
|
maxDelay = 0; //force exit
|
|
|
|
//read the extra 2 characters (new line chars)
|
|
while (retry && readSize != 2) {
|
|
readSize = serialDeviceRead(serialF, tmp, 2);
|
|
retry--;
|
|
}
|
|
if (readSize != 2 || tmp[0] != '\r' || tmp[1] != '\n') {
|
|
printf("Warning: corrupted feed request ! %d \n", readSize);
|
|
}
|
|
} else {
|
|
printf("Warning: corrupted feed request! %d \n", readSize);
|
|
}
|
|
//printf("***\n");
|
|
} else
|
|
if (buf[0] == '\r') {
|
|
readSize = serialDeviceRead(serialF, buf, 1); // read \n coming from Arduino
|
|
//printf("-%c-\n", buf[0] == '\n' ? 'n' : 'r');
|
|
buf[0] = 0;
|
|
bufPos++;
|
|
maxDelay = 0; //force exit
|
|
} else {
|
|
//printf("(0x%02x %d) \n", buf[0], (int) buf[0]);
|
|
buf += readSize;
|
|
if (bufPos == bufSize) {
|
|
printf("ERROR: serial port read buffer is too small!\nAre you dumping large amount of data?\n");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
if (maxDelay > 0) {
|
|
/* WIN_API handles timeout itself */
|
|
#ifndef _USE_WIN_API_
|
|
usleep(1 * 1000);
|
|
maxDelay -= 10;
|
|
#else
|
|
maxDelay -= 30;
|
|
#endif
|
|
}
|
|
}
|
|
return bufPos;
|
|
}
|
|
|
|
static int playJtagFile(char* label, int fSize, int vpp, int showProgress) {
|
|
char buf[MAX_LINE] = {0};
|
|
int sendPos = 0;
|
|
int lastSendPos = 0;
|
|
char ready = 0;
|
|
int result = 0;
|
|
unsigned int csum = 0;
|
|
int feedRequest = 0;
|
|
// support for XCOMMENT messages which might be interrupted by a feed request
|
|
int continuePrinting = 0;
|
|
|
|
if (openSerial() != 0) {
|
|
return -1;
|
|
}
|
|
//compute check sum
|
|
if (verbose) {
|
|
int i;
|
|
for (i = 0; i < fSize; i++) {
|
|
csum += (unsigned char) galbuffer[i];
|
|
}
|
|
}
|
|
|
|
// send start-JTAG-player command
|
|
sprintf(buf, "j%d\r", vpp ? 1: 0);
|
|
sendBuffer(buf);
|
|
|
|
// read response from MCU and feed the XSVF player with data
|
|
while(1) {
|
|
int readBytes;
|
|
|
|
feedRequest = 0;
|
|
buf[0] = 0;
|
|
readBytes = readJtagSerialLine(buf, MAX_LINE, 3000, &feedRequest);
|
|
//printf(">> read %d len=%d cp=%d '%s'\n", readBytes, (int) strlen(buf), continuePrinting, buf);
|
|
|
|
//request to send more data was received
|
|
if (feedRequest > 0) {
|
|
if (ready) {
|
|
int chunkSize = fSize - sendPos;
|
|
if (chunkSize > feedRequest) {
|
|
chunkSize = feedRequest;
|
|
// make the initial chunk big so the data are buffered by the OS
|
|
if (sendPos == 0) {
|
|
chunkSize *= 2;
|
|
if (chunkSize > fSize) {
|
|
chunkSize = fSize;
|
|
}
|
|
}
|
|
}
|
|
if (chunkSize > 0) {
|
|
// send the data over serial line
|
|
int w = serialDeviceWrite(serialF, galbuffer + sendPos, chunkSize);
|
|
sendPos += w;
|
|
// print progress / file position
|
|
if (showProgress && (sendPos - lastSendPos >= 1024 || sendPos == fSize)) {
|
|
lastSendPos = sendPos;
|
|
updateProgressBar(label, sendPos, fSize);
|
|
}
|
|
}
|
|
}
|
|
if (readBytes > 2) {
|
|
continuePrinting = 1;
|
|
}
|
|
}
|
|
// when the feed request was detected, there might be still some data in the buffer
|
|
if (buf[0] != 0) {
|
|
//prevous line had a feed request - this is a continuation
|
|
if (feedRequest == 0 && continuePrinting) {
|
|
continuePrinting = 0;
|
|
printf("%s\n", buf);
|
|
} else
|
|
//print debug messages
|
|
if (buf[0] == 'D') {
|
|
if (feedRequest) { // the rest of the message will follow
|
|
printf("%s", buf + 1);
|
|
} else {
|
|
printf("%s\n", buf + 1);
|
|
}
|
|
}
|
|
// quit
|
|
if (buf[0] == 'Q') {
|
|
result = atoi(buf + 1);
|
|
//print error result
|
|
if (result != 0) {
|
|
printf("%s\n", buf + 1);
|
|
} else
|
|
// when all is OK and verbose mode is on, then print the checksum for comparison
|
|
if (verbose) {
|
|
printf("PC : 0x%08X\n", csum);
|
|
}
|
|
break;
|
|
} else
|
|
// ready to receive anouncement
|
|
if (strcmp("RXSVF", buf) == 0) {
|
|
ready = 1;
|
|
} else
|
|
// print important messages
|
|
if (buf[0] == '!') {
|
|
// in verbose mode print all messages, otherwise print only success or fail messages
|
|
if (verbose || 0 == strcmp("!Success", buf) || 0 == strcmp("!Fail", buf)) {
|
|
printf("%s\n", buf + 1);
|
|
}
|
|
}
|
|
#if 0
|
|
//print all the rest
|
|
else if (verbose) {
|
|
printf("'%s'\n", buf);
|
|
}
|
|
#endif
|
|
} else
|
|
// the buffer is empty but there was a feed request just before - print a new line
|
|
if (readBytes > 0 && continuePrinting) {
|
|
printf("\n");
|
|
continuePrinting = 0;
|
|
}
|
|
}
|
|
|
|
readJtagSerialLine(buf, MAX_LINE, 1000, &feedRequest);
|
|
closeSerial();
|
|
return result;
|
|
}
|
|
|
|
|
|
static int processJtagInfo(void) {
|
|
int result;
|
|
int fSize = 0;
|
|
char tmp[256];
|
|
|
|
if (!opInfo) {
|
|
return 0;
|
|
}
|
|
|
|
if (!(gal == ATF1502AS || gal == ATF1504AS)) {
|
|
printf("error: infor command is unsupported");
|
|
return 1;
|
|
}
|
|
|
|
// Use default .xsvf file for erase if no file is provided.
|
|
// if the file is provided while write operation is also requested
|
|
// then the file is specified for writing -> do not use it for erasing
|
|
sprintf(tmp, "xsvf/id_ATF150X.xsvf");
|
|
filename = tmp;
|
|
|
|
result = readFile(&fSize);
|
|
if (result) {
|
|
return result;
|
|
}
|
|
|
|
//play the info file and use high VPP
|
|
return playJtagFile("", fSize, 1, 0);
|
|
}
|
|
|
|
static int processJtagErase(void) {
|
|
int result;
|
|
int fSize = 0;
|
|
char tmp[256];
|
|
char* originalFname = filename;
|
|
|
|
if (!opErase) {
|
|
return 0;
|
|
}
|
|
// Use default .xsvf file for erase.
|
|
sprintf(tmp, "xsvf/erase_%s.xsvf", galinfo[gal].name);
|
|
filename = tmp;
|
|
|
|
result = readFile(&fSize);
|
|
if (result) {
|
|
filename = originalFname;
|
|
return result;
|
|
}
|
|
filename = originalFname;
|
|
|
|
//play the erase file and use high VPP
|
|
return playJtagFile("erase ", fSize, 1, 1);
|
|
}
|
|
|
|
static int processJtagWrite(void) {
|
|
int result;
|
|
int fSize = 0;
|
|
|
|
if (!opWrite) {
|
|
return 0;
|
|
}
|
|
|
|
// paranoid: this condition should be already checked during argument's check
|
|
if (0 == filename) {
|
|
return -1;
|
|
}
|
|
result = readFile(&fSize);
|
|
if (result) {
|
|
return result;
|
|
}
|
|
|
|
//play the file and use low VPP
|
|
return playJtagFile("write ", fSize, 0, 1);
|
|
}
|
|
|
|
|
|
static int processJtag(void) {
|
|
int result;
|
|
if (verbose) {
|
|
printf("JTAG\n");
|
|
}
|
|
|
|
if ((gal == ATF1502AS || gal == ATF1504AS) && (opRead || opVerify)) {
|
|
printf("error: read and verify operation is not supported\n");
|
|
return 1;
|
|
}
|
|
|
|
result = processJtagInfo();
|
|
if (result) {
|
|
return result;
|
|
}
|
|
|
|
result = processJtagErase();
|
|
if (result) {
|
|
return result;
|
|
}
|
|
|
|
result = processJtagWrite();
|
|
if (result) {
|
|
return result;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
char result = 0;
|
|
int i;
|
|
|
|
result = checkArgs(argc, argv);
|
|
if (result) {
|
|
return result;
|
|
}
|
|
if (verbose) {
|
|
printf("Afterburner " VERSION " \n");
|
|
}
|
|
|
|
// process JTAG operations
|
|
if (gal != 0 && galinfo[gal].id0 == JTAG_ID && galinfo[gal].id1 == JTAG_ID) {
|
|
result = processJtag();
|
|
goto finish;
|
|
}
|
|
|
|
result = operationSetGalCheck();
|
|
|
|
if (gal != UNKNOWN && 0 == result) {
|
|
result = operationSetGalType(gal);
|
|
}
|
|
|
|
if (opErase && 0 == result) {
|
|
result = operationEraseGal();
|
|
}
|
|
|
|
if (0 == result) {
|
|
if (opWrite) {
|
|
// writing fuses and optionally verification
|
|
result = operationWriteOrVerify(1);
|
|
} else if (opInfo) {
|
|
result = operationReadInfo();
|
|
} else if (opRead) {
|
|
result = operationReadFuses();
|
|
} else if (opVerify) {
|
|
// verification without writing
|
|
result = operationWriteOrVerify(0);
|
|
} else if (opTestVPP) {
|
|
result = operationTestVpp();
|
|
} else if (opWritePes) {
|
|
result = operationWritePes();
|
|
}
|
|
if (0 == result && (opWrite || opVerify)) {
|
|
if (opSecureGal) {
|
|
operationSecureGal();
|
|
}
|
|
}
|
|
//variable VPP functions (for new board designs)
|
|
if (varVppExists) {
|
|
if (0 == result && opCalibrateVPP) {
|
|
result = operationCalibrateVpp();
|
|
}
|
|
if (0 == result && opMeasureVPP) {
|
|
result = operationMeasureVpp();
|
|
}
|
|
}
|
|
}
|
|
|
|
finish:
|
|
if (verbose) {
|
|
printf("result=%i\n", (char)result);
|
|
}
|
|
return result;
|
|
}
|