#include "loadhex.h"
#include <setjmp.h>
#include <stdio.h>
struct Hexfile {
const char*text,*end;
int line;
jmp_buf env;
unsigned linaddr;
enum{ MAXLEN=32 };
Hexfile(const char*t,unsigned l):text(t),end(t+l),line(1) {}
char readChar() {
if (text==end) longjmp(env,2); // Fehler: EOF
char c=*text++;
if (c=='\n') ++line; // Zeile mitzählen
return c;
}
byte readNibble() {
char c=readChar();
if (c>=0x40) c&=~0x20;
if (c<'0' || (c>'9' && c<'A') || c>'F') longjmp(env,3); // Fehler: Falsches Ziffernzeichen
c-='0'; if (c>9) c-='A'-'9'-1; // 0..15
return c;
}
byte readByte() {return readNibble()<<4|readNibble();}
char readLine(byte buf[]) {
char c;
do c=readChar(); while (c!=':' && c!='S');
if (c==':') { // Intel-Hex
byte cs=buf[0]=readByte();
if (cs>32) longjmp(env,4); // Fehler: Zu lange Zeilenlänge
for (int i=1; i<buf[0]+5; i++) cs+=buf[i]=readByte();
if (cs) longjmp(env,5); // Fehler: Falsche Prüfsumme
}else{ // Motorola-Hex (S-Hex)
buf[0]=readNibble();
byte cs=buf[1]=readByte();
if (cs>35) longjmp(env,4); // Zu lange (hier nicht unterstützte) Zeilenlänge
for (int i=2; i<buf[1]; i++) cs+=buf[i]=readByte();
if (cs!=0xFF) longjmp(env,5);
}
return c;
}
int load(bool eeprom) {
linaddr=eeprom?0x810000:0;
int ret=setjmp(env);
if (ret) return ret; // Fehler
byte buf[MAXLEN+5]; // 5 = Länge+AddresseH+AdresseL+Typ+Prüfsumme
for(;;) {
buf[3]=0xFF;
switch (readLine(buf)) {
case ':': {
unsigned addr=buf[1]<<8|buf[2];
if (buf[3]&&addr) longjmp(env,8); // Außer für Daten ist eine Adresse nicht erlaubt
switch (buf[3]) {
case 0: store_buffer(buf+4,buf[0],linaddr+addr); break;
case 1: return 0; // Erfolgreiches Ende
case 2: if (buf[0]!=2) longjmp(env,7); // Falsche Nutzdatenlänge
linaddr=(buf[4]<<8|buf[5])<<4;
break;
case 3:
case 5: if (buf[0]!=4) longjmp(env,7); // Falsche Nutzdatenlänge
break;
case 4: if (buf[0]!=2) longjmp(env,7); // Falsche Nutzdatenlänge
linaddr=(buf[4]<<8|buf[5])<<16;
default:longjmp(env,6); // unbekannter Satztyp
}
}break;
case 'S': {
int adrlen=0;
switch (buf[0]) {
case 0: break;
case 1: adrlen=2; break;
case 2: adrlen=3; break;
case 3: adrlen=4; break;
case 4: break;
case 5:
case 6:
case 7: return 0;
default: longjmp(env,6);
}
if (adrlen) {
if (buf[1]<=adrlen+2) longjmp(env,7);
unsigned addr=0;
for (int i=0; i<adrlen; i++) {
addr=addr<<8|buf[2+i];
}
store_buffer(buf+2+adrlen,buf[1]-2-adrlen,addr);
}
}break;
}
}
}
};
bool loadhex(const byte*text,unsigned len,bool eeprom) {
Hexfile f(reinterpret_cast<const char*>(text),len);
int e=f.load(eeprom);
if (e) fprintf(stderr,"Error %d loading hex file at line %d!",e,f.line);
return !e;
}
Detected encoding: UTF-8 | 0
|