From 09381c6097773b08622c810428a84840b5b08070 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 6 Jan 2010 17:55:16 +0000 Subject: AVR SP12 programmer --- src/buffer.c | 691 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 691 insertions(+) create mode 100644 src/buffer.c (limited to 'src/buffer.c') diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..5d37e14 --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,691 @@ +/* SP12: A serial programmer for working with Atmel AVR uCs */ +/* Copyright (C) 1997-2003 Ken Huntington, Kevin Towers, 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 */ + +#include +#include +#include +#include +#include "sp12.h" + + +/* Converts address or data string to number, automatically */ +/* selecting hex (0xNNN), oct (0NNN), binary (BNNN) or */ +/* dec (NNN) input. */ + +unsigned int str2num(char *addressOrData) { + + unsigned int number; + + /* + * Determine format (hex, decimal or binary) by looking at prefix + * and convert data to unsigned int using base 2, 8, 10 or 16 + */ + if (addressOrData[1] == 'x') + number = (unsigned int) strtol(addressOrData, NULL, 16); + else if (addressOrData[0] == '0') + number = (unsigned int) strtol(addressOrData, NULL, 8); + else if (addressOrData[0] == 'B') + number = (unsigned int) strtol(&addressOrData[1], NULL, 2); + else + number = (unsigned int) strtol(addressOrData, NULL, 10); + + return(number); +} + +/* convert unsigned int to a string-representation of the */ +/* binary number (ascii `0' is 48, ascii `1' is 49) */ + +void num2bin(unsigned char buffer, char *binary) { + + int Bi; + + for (Bi = 7; Bi >= 0; Bi--) { + binary[Bi] = (buffer & 0x01) + 48; + buffer = buffer >> 1; + } + binary[8] = '\0'; +} + +/* Reads program file in Atmel generic format (address:data) or */ +/* Intel HEX format; stores data into into flashBuf by address. */ +/* flashBuf by address. The two numbers in the generic format are */ +/* hex without `0x'. For example: 00000c:99e1 */ +/* Note: the 16-bit bufLimit is not suitable for Mega address space. */ + +int readFlashFile(char flashPath[], unsigned int flashBuf[], long bufLimit) { + + FILE *flashBufPtr; + char wordstring[WORDLEN]; + long address; + unsigned int data; + char buffer[MAXLEN]; + long offsetAddress = 0L; + int dataByteCount; + unsigned int lineAddress; + int recordType; + int idx; + int checksum; + int tmp; + + if ((flashBufPtr = fopen(flashPath, "r")) == NULL) { + return(1); + } else { + if (fgets(wordstring, WORDLEN, flashBufPtr) != NULL) { + /* + * Try Atmel generic format (default of the Atmel assembler). + */ + if (wordstring[FLASH_DATAPTR] == ':') { + fseek(flashBufPtr, 0, SEEK_SET); + while (fgets(wordstring, WORDLEN, flashBufPtr) != NULL) { + sscanf(wordstring, "%lx", &address); + if (wordstring[FLASH_DATAPTR] != ':') { + return(1); + } + sscanf(&wordstring[FLASH_DATAPTR + 1], "%x", &data); + if (address < bufLimit) + flashBuf[address] = data; + else + return(1); + } + fclose(flashBufPtr); + return(0); + } + /* + * Try Intel HEX format. + */ + if (wordstring[0] == ':') { + fseek(flashBufPtr, 0, SEEK_SET); + while (fgets(buffer, MAXLEN, flashBufPtr) != NULL) { + checksum = 0; + sscanf(&buffer[1], "%2x", &dataByteCount); + checksum += dataByteCount; + sscanf(&buffer[3], "%4x", &lineAddress); + sscanf(&buffer[3], "%2x", &tmp); + checksum += tmp; + sscanf(&buffer[5], "%2x", &tmp); + checksum += tmp; + sscanf(&buffer[7], "%2x", &recordType); + checksum += recordType; + /* + * Record type 02 means update offset address + */ + if (recordType == 2) { + sscanf(&buffer[9], "%4lx", &offsetAddress); + sscanf(&buffer[9], "%2x", &tmp); + checksum += tmp; + sscanf(&buffer[11], "%2x", &tmp); + checksum += tmp; + checksum = (unsigned char) (0x100 - (unsigned char) checksum); + sscanf(&buffer[13], "%2x", &tmp); + if (checksum != tmp) + return(1); + } + if (recordType == 0) { + for (idx = 9; idx < 9 + dataByteCount * 2; idx += 2) { + sscanf(&buffer[idx], "%2x", &data); + /* + * Use word addresses for the AT90 2-byte data format + */ + address = lineAddress / 2; + address = address + (offsetAddress * 0x10) / 2; + if (address < bufLimit) { + if (lineAddress & 0x0001) /* is it an odd address? */ + /* then set MSB of data */ + flashBuf[address] &= (data << 8) | 0x00ff; + else /* else set LSB of data */ + flashBuf[address] &= data | 0xff00; + } else { + return(1); + } + lineAddress++; + checksum += data; + } + checksum = (unsigned char) (0x100 - (unsigned char) checksum); + sscanf(&buffer[idx], "%2x", &tmp); + if (checksum != tmp) + return(1); + } + } + fclose(flashBufPtr); + return(0); + } + } + } + return(1); +} + +/* Reads eeprom file in format address:data, stores data into */ +/* eepromBuf by address. Both numbers can be hexadecimal (0xC4), */ +/* decimal (196), octal (0304) or binary (B11000100). */ + +int readEepromFile(char eepromPath[], unsigned int eepromBuf[], long bufLimit) { + + FILE *eepromBufPtr; + char wordstring[WORDLEN]; + long address; + unsigned int data; + char buffer[MAXLEN]; + char *dataPtr; + long offsetAddress = 0L; + int dataByteCount; + unsigned int lineAddress; + int recordType; + int idx; + int checksum; + int tmp; + + if ((eepromBufPtr = fopen(eepromPath, "r")) == NULL) { + return(1); + } else { + if (fgets(wordstring, WORDLEN, eepromBufPtr) != NULL) { + /* + * Try sp12 eeprom format. + */ + if (strchr(wordstring, ':') != &wordstring[0]) { + fseek(eepromBufPtr, 0, SEEK_SET); + while (fgets(wordstring, WORDLEN, eepromBufPtr) != NULL) { + if ((dataPtr = strchr(wordstring, ':')) == NULL) { + return(1); + } + dataPtr[0] = '\0'; + address =str2num(wordstring); + data = str2num(++dataPtr); + if (address < bufLimit) + eepromBuf[address] = data; + else + return(1); + } + fclose(eepromBufPtr); + return(0); + } + /* + * Try Intel HEX format. + */ + if (strchr(wordstring, ':') == &wordstring[0]) { + fseek(eepromBufPtr, 0, SEEK_SET); + while (fgets(buffer, MAXLEN, eepromBufPtr) != NULL) { + checksum = 0; + sscanf(&buffer[1], "%2x", &dataByteCount); + checksum += dataByteCount; + sscanf(&buffer[3], "%4x", &lineAddress); + sscanf(&buffer[3], "%2x", &tmp); + checksum += tmp; + sscanf(&buffer[5], "%2x", &tmp); + checksum += tmp; + sscanf(&buffer[7], "%2x", &recordType); + checksum += recordType; + /* + * Record type 02 means update offset address + */ + if (recordType == 2) { + sscanf(&buffer[9], "%4lx", &offsetAddress); + sscanf(&buffer[9], "%2x", &tmp); + checksum += tmp; + sscanf(&buffer[11], "%2x", &tmp); + checksum += tmp; + checksum = (unsigned char) (0x100 - (unsigned char) checksum); + sscanf(&buffer[13], "%2x", &tmp); + if (checksum != tmp) + return(1); + } + if (recordType == 0) { + address = lineAddress; + address = address + (offsetAddress * 0x10) / 2; + /* + * Use byte addresses for single byte eeprom data format. + */ + for (idx = 9; idx < 9 + dataByteCount * 2; idx += 2) { + sscanf(&buffer[idx], "%2x", &data); + if (address < bufLimit) + eepromBuf[address] = data; + else + return(1); + address++; + checksum += data; + } + checksum = (unsigned char) (0x100 - (unsigned char) checksum); + sscanf(&buffer[idx], "%2x", &tmp); + if (checksum != tmp) + return(1); + } + } + fclose(eepromBufPtr); + return(0); + } + } + } + return(1); +} + +/* Calculate checksum over buffer[]; int bufLimit is number of */ +/* elements in buffer. */ + +unsigned int checksum(unsigned int buffer[], long bufLimit) { + + long idx; + unsigned int chksum = 0; + + /* + * cyclic right shift 1 of chksum + buffer element + */ + for (idx = 0; idx < bufLimit; idx++) { + if (buffer[idx] == 0xfff) + buffer[idx] = 0xff; + chksum = ((chksum>>1) + ((chksum & 1) ?0x8000:0) + buffer[idx]) & 0xffff; + } + return(chksum); +} + +/* Routines to write the flash or eeprom buffer into a file, */ +/* using Intel HEX format or as a hex dump with ascii translation. */ + +#define BYTES_PER_LINE 16 + +static int flash_intel_hex (FILE *filePtr, unsigned int *buffer, + long addr, long length) { + + int line_cnt = 0; /* line byte count */ + int line_len = 0; /* expected line length */ + unsigned char checksum = 0; + unsigned char byt; + + length *= 2; + while (length > 0) { + if (addr > 0xFFFF) { /* add record type 02 */ + fprintf (filePtr, ":020000021000EC\n"); + addr = 0x10000 - addr; + } + if (line_cnt == 0) { /* write line header */ + line_len = (length > BYTES_PER_LINE) ? BYTES_PER_LINE : length; + fprintf (filePtr, ":%02X%04lX00", line_len, addr); + checksum = line_len; + checksum += addr & 0xff; + checksum += addr >> 8; + } + + if (addr & 0x0001) { /* is it an odd address? */ + byt = *buffer >> 8; /* write MSB */ + buffer++; + } else { + byt = *buffer & 0x00ff; /* write LSB */ + } + fprintf (filePtr, "%02X", byt); + checksum += byt; + + if (++line_cnt == line_len) { /* write checksum */ + fprintf (filePtr, "%02X\n", -checksum & 0xff); + line_cnt = 0; + } + addr++; + length--; + } + fprintf (filePtr, ":00000001FF\n"); /* write the terminator */ + return (0); +} + +static int eeprom_intel_hex (FILE *filePtr, unsigned int *buffer, + unsigned int addr, long length) { + int line_cnt = 0; /* line byte count */ + int line_len = 0; /* expected line length */ + unsigned char checksum = 0; + + while (length > 0) { + if (line_cnt == 0) { /* write line header */ + line_len = (length > BYTES_PER_LINE) ? BYTES_PER_LINE : length; + fprintf (filePtr, ":%02X%04X00", line_len, addr); + checksum = line_len; + checksum += addr & 0xff; + checksum += addr >> 8; + } + fprintf (filePtr, "%02X", *buffer); + checksum += *buffer; + if (++line_cnt == line_len) { /* write checksum */ + fprintf (filePtr, "%02X\n", -checksum & 0xff); + line_cnt = 0; + } + buffer++; + addr++; + length--; + } + fprintf (filePtr, ":00000001FF\n"); /* write the terminator */ + return (0); +} + +int file_hex_ascii(FILE *filePtr, unsigned int buffer[], + int bufLimit, int twoByteFlag) { + + unsigned long address; + char dataStr[MAXLEN]; + char asciiStr[MAXLEN]; + char lineBuf[MAXLEN]; + unsigned char loByte, hiByte; + int addressPerLine = 0x10; + + dataStr[0] = '\0'; + asciiStr[0] = '\0'; + for (address = 0; address < bufLimit; address++) { + if ((address > 0) && (address % addressPerLine) == 0) { + if ((fprintf(filePtr, "%06lx %s %s\n", + address - addressPerLine, dataStr, asciiStr)) == EOF) + return(1); + dataStr[0] = '\0'; + asciiStr[0] = '\0'; + } + if (twoByteFlag) { + addressPerLine = 0x08; + loByte = (unsigned char) buffer[address]; + hiByte = (unsigned char) (buffer[address] >> 8); + sprintf(lineBuf, "%02x %02x ", hiByte, loByte); + strcat(dataStr, lineBuf); + if ((hiByte > 31) && (hiByte < 127)) + sprintf(lineBuf, "%c", hiByte); + else + sprintf(lineBuf, "."); + strcat(asciiStr, lineBuf); + if ((loByte > 31) && (loByte < 127)) + sprintf(lineBuf, "%c", loByte); + else + sprintf(lineBuf, "."); + strcat(asciiStr, lineBuf); + } else { + sprintf(lineBuf, "%02x ", buffer[address]); + strcat(dataStr, lineBuf); + if ((buffer[address] > 31) && (buffer[address] < 127)) + sprintf(lineBuf, "%c", buffer[address]); + else + sprintf(lineBuf, "."); + strcat(asciiStr, lineBuf); + } + } + if ((fprintf(filePtr, "%06lx %s %s\n", + address - addressPerLine, dataStr, asciiStr)) == EOF) + return(1); + fprintf(filePtr, "Checksum: %04x\n", + checksum(buffer, bufLimit)); + return(0); +} + +/* Writes flashBuf[] into FILE *flashBufPtr using either Intel HEX */ +/* or the `native' format. */ +/* If write to file fails, return(1), else return(0) */ + +int fileFlashBuf(unsigned int flashBuf[], long bufLimit, + char flashPath[], int intel_flag, int hex_ascii_flag) { + + FILE *flashBufPtr; + long address; + + if ((flashBufPtr = fopen(flashPath, "w")) == NULL) + return(1); + + if (hex_ascii_flag) { + file_hex_ascii(flashBufPtr, flashBuf, bufLimit, 1); + } else if (intel_flag) { + flash_intel_hex(flashBufPtr, flashBuf, 0, bufLimit); + } else { + for (address = 0; address < bufLimit; address++) { + if ((fprintf(flashBufPtr, "%06lx:%04x\n", + address, flashBuf[address])) == EOF) + return(1); + } + } + fclose(flashBufPtr); + return(0); +} + +/* Writes eepromBuf[] into FILE *eepromBufPtr; */ +/* If write to file fails, return(1), else return(0) */ + +int fileEepromBuf(unsigned int eepromBuf[], long bufLimit, + char eepromPath[], int intel_flag, int hex_ascii_flag) { + + FILE *eepromBufPtr; + long address; + char binary[9] = "76543210"; + + if ((eepromBufPtr = fopen(eepromPath, "w")) == NULL) + return(1); + + if (hex_ascii_flag) { + file_hex_ascii(eepromBufPtr, eepromBuf, bufLimit, 0); + } else if (intel_flag) { + eeprom_intel_hex(eepromBufPtr, eepromBuf, 0, bufLimit); + } else { + if ((fprintf(eepromBufPtr, + "Address: Data in hex, dec, oct, bin\n")) == EOF) + return(1); + for (address = 0; address < bufLimit; address++) { + num2bin((unsigned char) eepromBuf[address], binary); + if ((fprintf(eepromBufPtr, + " %#06lx: %#04x %3d %#4o %s\n", + address, eepromBuf[address], eepromBuf[address], + eepromBuf[address], binary)) == EOF) + return(1); + } + } + fclose(eepromBufPtr); + return(0); +} + +/* Writes buffer[] to stdout as a hex dump with ascii translation */ + +void printBuffer(unsigned int buffer[], long bufLimit, int twoByteFlag) { + + long address; + char dataStr[MAXLEN]; + char asciiStr[MAXLEN]; + char lineBuf[MAXLEN]; + unsigned char loByte, hiByte; + int addressPerLine = 0x10; + + dataStr[0] = '\0'; + asciiStr[0] = '\0'; + for (address = 0; address < bufLimit; address++) { + if ((address > 0) && (address % addressPerLine) == 0) { + printf("%06lx %s %s\n", address - addressPerLine, dataStr, asciiStr); + dataStr[0] = '\0'; + asciiStr[0] = '\0'; + } + if (twoByteFlag) { + addressPerLine = 0x08; + loByte = (unsigned char) buffer[address]; + hiByte = (unsigned char) (buffer[address] >> 8); + sprintf(lineBuf, "%02x %02x ", hiByte, loByte); + strcat(dataStr, lineBuf); + if ((hiByte > 31) && (hiByte < 127)) + sprintf(lineBuf, "%c", hiByte); + else + sprintf(lineBuf, "."); + strcat(asciiStr, lineBuf); + if ((loByte > 31) && (loByte < 127)) + sprintf(lineBuf, "%c", loByte); + else + sprintf(lineBuf, "."); + strcat(asciiStr, lineBuf); + } else { + sprintf(lineBuf, "%02x ", buffer[address]); + strcat(dataStr, lineBuf); + if ((buffer[address] > 31) && (buffer[address] < 127)) + sprintf(lineBuf, "%c", buffer[address]); + else + sprintf(lineBuf, "."); + strcat(asciiStr, lineBuf); + } + } + printf("%06lx %s %s\n", address - addressPerLine, dataStr, asciiStr); + printf("Checksum: %04x\n", checksum(buffer, bufLimit)); +} + +/* Add spaces until lenght or max is reached */ +/* Try to break line if necessary */ + +void formatStr(char *logStr, int length, int max) { + + int idx; + int limit; + int idxL = 0; + + limit = length; + for (idx = 0; idx < limit; idx++) { + if (idx == max) { + logStr[idx] = '\0'; + break; + } + if ((++idxL > length / 2) && logStr[idx] == ' ') { + logStr[idx] = '\n'; + limit = limit + idxL; + idxL = 0; + } + if (logStr[idx] == '\0') { + logStr[idx] = ' '; + logStr[idx + 1] = '\0'; + } + } +} + +/* Add a line to the log about a write command */ + +int logWrites(char *commandStr, unsigned int address, int data, + char *path, unsigned int buffer[], int overlayFlag, int *error) { + + FILE *logPtr; + time_t curTime; + struct tm *locTime; + unsigned int areaChksum = 0; + unsigned int *queryBuf; + int idx; + long adrsCnt; + char deviceName[MAXLEN]; + char fileName[MAXLEN]; + char *fileNamePtr; + + if (log.logging != 1) + return(0); + + formatStr(commandStr, 6, MAXLEN); + strcpy(deviceName, device.name); + if (strcmp(deviceName, "AT90(L)S2343 or Tiny22(L)") == 0) + strcpy(deviceName, "2343/Tiny22"); + formatStr(deviceName, 12, MAXLEN); + queryBuf = malloc(FLASHBUF_UPPERLIMIT * sizeof (unsigned int)); + if (queryBuf == NULL) { + printf ("ERROR: No memory available for buffer!\n"); + return(0); + } + + curTime = time(NULL); + locTime = localtime(&curTime); + + if ((logPtr = fopen(log.logPath, "a")) == NULL) { + free(queryBuf); + return(1); + } + fprintf(logPtr, "%s %s ", deviceName, commandStr); + if (strchr(commandStr, 'f') != NULL) { + strcpy(fileName, path); + fileNamePtr = fileName; + idx = strlen(fileName); + while (idx-- > 0 && fileName[idx] != '\\' && fileName[idx] != '/') + fileNamePtr = &fileName[idx]; + formatStr(fileNamePtr, 14, MAXLEN - idx); + fprintf(logPtr, "%s ", fileNamePtr); + if (log.query) { + if (strchr(commandStr, 'p') != NULL) { + readFlashArea(queryBuf, device.flashLimit); + areaChksum = checksum(queryBuf, device.flashLimit); + *error = 0; + for (adrsCnt = 0; adrsCnt < device.flashLimit; adrsCnt++) { + if (overlayFlag && buffer[adrsCnt] == 0xffff) + continue; + if (queryBuf[adrsCnt] != buffer[adrsCnt]) { + *error = 1; + break; + } + } + } else { + readEepromArea(queryBuf, device.eepromLimit); + areaChksum = checksum(queryBuf, device.eepromLimit); + *error = 0; + for (adrsCnt = 0; adrsCnt < device.eepromLimit; adrsCnt++) { + if (overlayFlag && buffer[adrsCnt] > 0xFF) + continue; + if (queryBuf[adrsCnt] != (unsigned char) buffer[adrsCnt]) { + *error = 1; + break; + } + } + } + if (*error) + fprintf(logPtr, "readback ERROR %s", asctime(locTime)); + else + fprintf(logPtr, "checksum %04x %s", areaChksum, asctime(locTime)); + } else { + fprintf(logPtr, "not queried %s", asctime(locTime)); + } + } else { + if (strchr(commandStr, 'p') != NULL) + fprintf(logPtr, "%08x:%#06x ", address, data); + else + fprintf(logPtr, "%08x:%#04x ", address, data); + if (*error) + fprintf(logPtr, "readback ERROR %s", asctime(locTime)); + else + fprintf(logPtr, "verified %s", asctime(locTime)); + } + fclose(logPtr); + free(queryBuf); + return(0); +} + +/* Add a line to the log about a lock command */ + +int logLocks(unsigned int buffer[], char *lockBits) { + + FILE *logPtr; + time_t curTime; + struct tm *locTime; + unsigned int areaChksum = 0; + char deviceName[MAXLEN]; + char lBits[MAXLEN] = ""; + + if (log.logging != 1) + return(0); + + sprintf(lBits, "%02lx", strtol(lockBits, NULL, 2)); + + strcpy(deviceName, device.name); + formatStr(deviceName, 12, MAXLEN); + curTime = time(NULL); + locTime = localtime(&curTime); + + if ((logPtr = fopen(log.logPath, "a")) == NULL) + return(1); + fprintf(logPtr, "%s -L%s ", deviceName, lBits); + readFlashArea(buffer, device.flashLimit); + areaChksum = checksum(buffer, device.flashLimit); + fprintf(logPtr, "flash %04x ", areaChksum); + readEepromArea(buffer, device.eepromLimit); + areaChksum = checksum(buffer, device.eepromLimit); + fprintf(logPtr, "eeprom %04x %s", areaChksum, asctime(locTime)); + fclose(logPtr); + return(0); +} -- cgit v1.2.3