c't

c't-Projekte - Mailinglisten


[Voriger (Datum)] [Nächster (Datum)] [Voriger (Thread)] [Nächster (Thread)]
[Nach Datum][Nach Thread]

Re: [ct-bot] eeprom@pc

Absender: Achim Pankalla
Datum: Sa, 07.07.2007 18:42:02
In-reply-to: <EB302B19-E327-4736-A0DE-588E25D2EE48@xxxxxxxxxxxxxxx>
References: <BCF016D5ED5AC34FBB655D109519ABCF083EBE@xxxxxxxxxxxxxxxxxxxx> <45F135B9.5030203@xxxxxx> <45F13A91.6090904@xxxxxxxx> <D053B7F5-6BDD-4052-B45F-28FCF0EF45F8@xxxxxxxxxxxxxxx> <45F2B74F.8090706@xxxxxx> <38A4BFD9-CA32-436A-9A1E-B4E6E0652A5D@xxxxxxxxxxxxxxx> <463E0782.1050406@xxxxxx> <0FBD95CF-DA3B-461B-B12B-9FDCD84984D2@xxxxxxxxxxxxxxx> <463F3E0A.7020605@xxxxxx> <8D5B90F4-74FD-45D4-B5B8-DDCAC0B81932@xxxxxxxxxxxxxxx> <464092F7.30605@xxxxxx> <465DB1F9.5030404@xxxxxx> <CF925D4D-FD5A-4581-8480-1C5D35EFEDC9@xxxxxxxxxxxxxxx> <4663027F.4040301@xxxxxx> <F71477F0-03AD-4F06-87E3-AC5DA5BFD1B2@xxxxxxxxxxxxxxx> <466D6849.1020109@xxxxxx> <46756694.9010906@xxxxxx> <6566D2F2-ADE4-4656-86C0-6533B3462B64@xxxxxxxxxxxxxxx> <46866046.7040108@xxxxxx> <4686813D.8020405@xxxxxx> <70929B57-E069-4B5F-AC22-3E1E51ACD696@xxxxxxxxxxxxxxx> <5E0B9EC1-1718-4319-95D6-54862E9ECA42@xxxxxxxxxxxxxxx> <468CB5B0.3000408@xxxxxx> <EB302B19-E327-4736-A0DE-588E25D2EE48@xxxxxxxxxxxxxxx>


hallo,
anbei eine überarbeitete version der eeprom-emulation. sie sollte nun auch mit macosx und linux funktionieren, vorrausgesetzt: 1) meine positionsangaben für die dateien stimmen (sollte so sein, ausser sie enthalten TABs) 2)die ausgabe von objdump von den avr compiler von windows ist identisch zu der bei linux und macos. die werte können mit konstanten am anfang von eeprom-emu_pc.c angepasst werden, die zählung erfolgt ab 0 und bei den adressen / groessenangaben sollten die letzten 4 stellen erfasst werden. ausserdem habe ich die eeprom.bin gecached, dh die werte werden aus den ram gelesen und geschrieben in ram und datei. ausserdem noch weiter kleinigkeiten...
für (hoffentliche) postive rückmeldungen bin ich dankbar....

mit freundlichen gruessen
   achim
Index: E:/eclipse/ct-bot test/ct-Bot/pc/eeprom-emu_pc.c
===================================================================
--- E:/eclipse/ct-bot test/ct-Bot/pc/eeprom-emu_pc.c	(revision 1176)
+++ E:/eclipse/ct-bot test/ct-Bot/pc/eeprom-emu_pc.c	(working copy)
@@ -1,480 +1,512 @@
-/*
- * c't-Bot
- * 
- * 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.
- * 
- */
-
-/*! 
- * @file 	eeprom-emu_pc.c  
- * @brief 	Low-Level Routinen fuer den Zugriff auf das emulierte EEPROM des Sim-c't-Bots
- * @author 	Achim Pankalla (achim.pankalla@xxxxxx)
- * @date 	07.06.2007
- */
-
-#include "ct-Bot.h"
-
-#ifdef PC
-
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <sys/time.h>
-
-#include "log.h"
-#include "gui.h"
-
-//#define DEBUG_EEPROM		// Schalter um LOG-Ausgaben anzumachen
-
-#ifndef DEBUG_EEPROM
-	#undef LOG_INFO
-	#define LOG_INFO(a, ...) {}
-#endif
-
-extern uint8 __attribute__ ((section (".s1eeprom"),aligned(1))) _eeprom_start1__;
-extern uint8 __attribute__ ((section (".s2eeprom"),aligned(1))) _eeprom_start2__;
-
-/*! Normiert PC EEPROM Adressen*/
-#define EEPROM_ADDR(x) ((uint32)x - (uint32)&_eeprom_start2__ - ((uint32)&_eeprom_start2__ - (uint32)&_eeprom_start1__))
-/*! Defines zum Mitloggen von EEPROM Zugriffen*/
-#define LOG_LOAD 	if(addrconv) {LOG_DEBUG("LOAD: %s : %d", ctab[lastctabi].varname, (uint16)dataline[0] + (uint16)dataline[1]*256);}\
-					else {LOG_DEBUG("load-addr=0x%x/%d", address,(uint16)dataline[0] + (uint16)dataline[1]*256);}
-#define LOG_STORE 	if(addrconv) {LOG_DEBUG("STORE: %s : %d", ctab[lastctabi].varname, data);}\
-					else {LOG_DEBUG("load-addr=0x%x/%d", address, data);}
-									
-#ifdef __AVR_ATmega644__  // Dieser Prozessor hat 2048 Bytes EEPROM
-	#define EE_SIZE 2048
-#else
-	#define EE_SIZE 1024
-#endif
-
-#define EEPROM_FILENAME	"./eeprom.bin" 		/*<! Name und Pfad der EEPROM Datei. Verzeichnis muss existieren. Backslash doppeln!*/
-#define MAX_VAR 200  						/*<! Maximale Anszahl von Variablen*/
-#define EEMAP_PC  "./eeprom_pc.map"					/*<! Pfad fuer PC-MAP Datei */
-#define EEP_PC    "./ct-Bot.eep"					/*<! Pfad fuer PC-EEP Datei */
-#ifdef WIN32
-	/* Windows */
-	#define EEMAP_MCU "../debug-mcu-w32/eeprom_mcu.map"		/*<! Pfade fuer MAP / EEP Dateien */
-#else
-	/* Linux und OS X */
-	#define EEMAP_MCU "../Debug-MCU-Linux/eeprom_mcu.map"	/*<! Pfade fuer MAP / EEP Dateien */
-#endif
-
-typedef struct addrtab {
-	char varname[20];
-	uint32 simaddr;
-	uint32 botaddr;
-	uint32 size;
-	uint32 access;
-} AddrCTab_t;								/*<! Spezieller Datentyp fuer Adresskonvertierung */
-
-static AddrCTab_t ctab[MAX_VAR]; 			/*<! Adresskonvertierungstabelle */
-static uint16 tsize=0; 						/*<! Anzahl Eintraege in der Tabelle */
-static uint8 addrconv = 0;                  /*<! Adresskonvertierung ein-/ausschalten */
-static uint16 lastctabi = 0;                /*<! Letzter Zugriffsindex auf ctab */
-
-/*! 
- * Diese Funktion konvertiert die Adressen der EEPROM Variablen des PC so,
- * dass sie den Adressen im realen ct-Bot entsprechen. Dafuer wird mit der Funktion
- * create_ctab ein Adresstabelle angelegt, diese nutzt diese Funktion.
- * @param addr Adresse im EEPROM zwischen 0 und EE_SIZE-1
- * @return Die neue Adresse fuer den realen Bot
- */
-static uint32 conv_eeaddr(uint32 addr){
-	int8 i;
-	int32 adiff;
-
-	if(!addrconv) //Keine Adresskonvertierung
-		return(addr);
-	for(i=0; i<tsize; i++){
-		adiff = addr - ctab[i].simaddr;
-		if(adiff < 0)
-			return(0xffffffff);
-		if(adiff < ctab[i].size){
-			lastctabi = i; //Letzer guelten Index merken
-			return(ctab[i].botaddr + adiff);
-		}
-	}
-	return(0xffffffff);
-}
-
-/*!
- * Diese Funktion uberprueft das vorhanden sein der eeprom.bin und initialisiert sie
- * gegebenenfalls mit der Initwerten der eep Datei.
- * Es wird dabei die Adresskovertierung benutzt, wenn die EEPROM Simulation im MCU-Modus 
- * ist.
- * -----
- *  0 = EEPROM Datei OK
- *  1 = Fehler aufgetreten
- * -----
- * @param initfile		EEP-Datei des PC Codes
- * @param eeprom_init	Flag fuer Initialisierung (1 ja, 0 nein)
- * @return Status der Funktion
- */
-static uint16 check_eeprom_file(char *initfile, uint8_t eeprom_init){
-	FILE *fpr, *fpw; //Filepointer fuer Dateizugriffe
-	uint16 i; //Laufvariable
-	char data[2]; //Datenspeicher
-	
-	/*eeprom file vorhanden*/
-	if(!(fpw = fopen(EEPROM_FILENAME, "r+b"))){ //Testen, ob Datei vorhanden ist.
-		if(!(fpw = fopen(EEPROM_FILENAME, "w+b"))){ //wenn nicht, dann erstellen
-			LOG_INFO("->Kann EEPROM-Datei nicht erstellen");
-			return(1);
-		}
-		if(!addrconv) {
-			/* EEPROM mit .eeprom-Section des .elf-Files initialisieren, wenn PC Modus */
-			uint8_t * ram_dump = (uint8_t *)(&_eeprom_start2__ + (&_eeprom_start2__ - &_eeprom_start1__));
-			fwrite(ram_dump, EE_SIZE, 1, fpw);
-		} else {
-			/* alternativ: leeres EEPROM erstellen und init setzen bei MCU Modus*/	
-			for(i = 0; i < EE_SIZE; i++)
-				fwrite("\377", 1, 1, fpw);
-			eeprom_init = 1;
-		}
-
-		fclose(fpw);
-		LOG_INFO("->Leere EEPROM-Datei erstellt");
- 	}
-	
-	/*Initialsieren der eeprom.bin, wenn gewuenscht*/
-	if(eeprom_init){
-		if(!(fpr = fopen(initfile, "rb"))){ //Datei oeffnen
-			LOG_INFO("->EEP nicht gefunden");
-			return(1);
-		}
-		if(!(fpw = fopen(EEPROM_FILENAME, "rb+"))){ //Datei oeffnen
-			LOG_INFO("->EEPROM-Datei kann nicht beschrieben werden");
-			return(1);
-		}
-		
-		/*EEP-Datei in EEPROM-Datei kopieren*/
-		for(i=0; i<EE_SIZE; i++){
-			/*Daten kopieren*/
-			if(!fread(data, 1, 1, fpr))
-				break;
-			if(addrconv){ //EEPROM-Datei im MCU-Modus
-				uint32 naddr;//Konvertierte Adresse
-				
-				naddr = conv_eeaddr((uint32)i);
-				if(naddr != 0xffffffff){
-					fseek(fpw, (int32)naddr, SEEK_SET);
-				}
-				else{
-					continue; //Nichts schreiben Adresse nicht belegt
-				}
-			}
-			fwrite(data, 1, 1, fpw);
-		}
-		fclose(fpr);
-		fclose(fpw);
-		LOG_INFO("->EEPROM-Datei mit Daten init.");
-	}
-	return(0);
-}
-
-/*!
- * Diese Funktion erstellt aus den beiden im Post erstellten MAP Dateien eine Tabelle
- * zum umrechnen der PC-Adressen in die des avr-Compilers. Dadurch kann die EEPROM 
- * Datei in einen zum EEPROM des Bot kompatiblen Format gehalten werden.
- * Wichtige Informationen werden ueber LOG_INFO angezeigt.
- * ----
- * Ergebniscodes der Funktion
- * 0 = Fehlerfrei
- * 1 = Sim Mapfile nicht vorhanden
- * 2 = Bot Mapfile nicht vorhanden
- * 3 = Unterschiedlicher Variablenbestand
- * 4 = Zuviele Variablen
- * 5 = EEPROM voll
- * 6 = Unterschiedliche Variablenanzahl
- * 
- * @param simfile MAP mit den Adressen der EEPROM-Variablen in der PC exe/elf
- * @param botfile MAP mit den Adressen der EEPROM-Variablen im MCU elf
- * @return Statuscode
- */
-static uint16 create_ctab(char *simfile, char *botfile){
-	FILE *fps, *fpb;
-	char sline[250], bline[250]; //Textzeilen aus Dateien
-	char d[30], d1[30], d2[30], vname_s[30], vname_b[20]; //Dummy und Variablennamen
-	int32 addr_s, addr_b; //Adressen der Variablen
-	char saddr[30], ssize[30]; //Stringvarianten fuer die Bot Daten
-	uint32 size; //Variablengroesse
-	int16 i, ii; //Laufvariablen
-	uint16 vc = 0; //Variablenzaehler
-
-	/*Dateien oeffnen*/
-	if(!(fps=fopen(simfile,"r"))){
-		LOG_INFO("->EEPROM-MAP fuer PC fehlt");
-		return(1);
-	}
-	if(!(fpb=fopen(botfile,"r"))){
-		LOG_INFO("->EEPROM-MAP fuer MCU fehlt");		
-		return(2);
-	}
-
-	/*Anzahl Variablen vergleichen*/
-	while(fgets(sline, 249, fps)) vc++;
-	while(fgets(sline, 249, fpb)) vc--;
-	if(vc){
-		fclose(fps);
-		fclose(fpb);
-		LOG_INFO("->Unterschiedliche Variablenanzahl");
-		return(6);
-	}
-	rewind(fps);
-	rewind(fpb);
-
-	/*Tabelle erstellen*/
-	while(fgets(sline, 249, fps)){
-		rewind(fpb);
-		sscanf(&sline[47], "%x %s", &addr_s, vname_s);
-		while(fgets(bline, 249, fpb)){
-			/*Variablennamen suchen*/
-			sscanf(&bline[4], "%s %s %s %s %s %s", d1, d, d, d, d2, vname_b);
-			sprintf(saddr, "0x%s", d1);
-			sscanf(saddr, "%x", &addr_b);
-			sprintf(ssize, "0x%s", &d2[4]);
-			sscanf(ssize, "%x", &size);
-			if(!strcmp(&vname_s[1], vname_b)){
-				/*Daten kopieren*/
-				strcpy(ctab[tsize].varname, vname_b);
-				ctab[tsize].simaddr = addr_s;
-				ctab[tsize].botaddr = addr_b;
-				ctab[tsize].size    = size;
-				ctab[tsize++].access  = 0;
-
-				/*Fehlerabbrueche*/
-				if(tsize == MAX_VAR){
-					LOG_INFO("->Mehr als %n Variablen",MAX_VAR);
-					return(4);
-				}
-				if(addr_s > EE_SIZE){
-					LOG_INFO("->EEPROM voll");
-					return(5);
-				}
-				
-				/*Erfolg markieren*/
-				addr_b = -1;
-				break;
-			}
-		}
-		if(addr_b > -1){ //Keine passende Variable gefunden
-			LOG_INFO("->Unterschiedliche Variablen");
-			return(3);
-		}
-	}
-
-	/*Dateien schliessen*/
-	fclose(fps);
-	fclose(fpb);
-	
-	/*Tabelle nach Sim-Adressen sortieren*/
-	for(ii=tsize-1; ii > 0; ii--){
-		for(i=0; i < ii; i++){
-			if(ctab[i].simaddr > ctab[i+1].simaddr){
-				long simaddr, botaddr, size;
-				char vname[30];
-			
-				/*Daten umkopieren*/
-				strcpy(vname, ctab[i+1].varname);
-				simaddr = ctab[i+1].simaddr;
-				botaddr = ctab[i+1].botaddr;
-				size    = ctab[i+1].size;
-
-				strcpy(ctab[i+1].varname, ctab[i].varname);
-				ctab[i+1].simaddr = ctab[i].simaddr;
-				ctab[i+1].botaddr = ctab[i].botaddr;
-				ctab[i+1].size    = ctab[i].size;
-
-				strcpy(ctab[i].varname, vname);
-				ctab[i].simaddr = simaddr;
-				ctab[i].botaddr = botaddr;
-				ctab[i].size    = size;
-			}
-		}
-	}
-	return(0);
-}
-
-/*! 
- * Diese Funktion initialisiert die eeprom-emulation. Sie sorgt fuer die Erstellung der
- * eeprom.bin, falls nicht vorhanden und erstellt ueber eine Hilfsfunktion eine Adress-
- * konvertierungstabelle fuer die EEPROM-Adressen, wenn die benoetigten Daten vorliegen.
- * Statusinformationen werden ueber DEBUG_INFO angezeigt.
- * @param init	gibt an, ob das EEPROM mit Hilfer einer eep-Datei initialisiert werden soll (0 nein, 1 ja)
- */
-uint8_t init_eeprom_man(uint8_t init) {
-	uint16 status; //Status von create_ctab
-	uint16 sflag; //Sectionstatus
-	
-	LOG_INFO("EEPROM-Manager");
-
-	/*Adresskonvertierungstabelle anlegen*/
-	if((status=create_ctab(EEMAP_PC, EEMAP_MCU))){
-			LOG_INFO("->EEPROM im PC-Modus");
-	}
-	else {
-			LOG_INFO("->EEPROM im MCU-Modus");
-			addrconv = 1;
-	}
-	
-	/*Sections ueberpruefen*/
-	if((&_eeprom_start2__ - &_eeprom_start1__) > 0 && (&resetsEEPROM - &_eeprom_start2__) >0){
-		LOG_INFO("->Sections liegen wohl korrekt");
-		LOG_INFO("->Section Abstand 0x%X", (&_eeprom_start2__ - &_eeprom_start1__));
-		sflag = 0;
-	}
-	else{
-		LOG_INFO("->Sections liegen falsch");
-		sflag = 1;
-	}
-	
-	/*eeprom.bin checken*/ 
-	if(sflag || check_eeprom_file(EEP_PC, init)){
-		LOG_INFO("EEPROM-Emulation fehlerhaft");
-		return 1;
-	}
-	else{
-		LOG_INFO("->EEPROM Groesse %d Bytes", EE_SIZE);
-		LOG_INFO("EEPROM-Emulation einsatzbereit");
-	}
-	return 0;
-}
-
-/*! 
- * Traegt die uebergebenen Daten in das simulierte EEPROM ein. Dieses simulierte EEPROM 
- * besteht aus einer Datei. 
- * Es koennen Bytes (uint8 size = 1) und Words (uint16 size = 2) uebergeben werden.
- * @param address Adresse im EEPROM zwischen 0 und EE_SIZE-1
- * @param data Daten die abgelegt werden sollen
- * @param size Groesse der Daten in Byte
- */  
-static void store_parameter(uint16 address, uint16 data, uint8 size) {
-	FILE  *fpw; 	//Dateizeiger
-	uint8 dataline[2];	//Speicher fuer Datenausgabe
-
-//	LOG_STORE
-	if(address > (size == 1 ? EE_SIZE-1 : EE_SIZE-2)) //Adresse checken
-		return;
-
-	if(!(fpw = fopen(EEPROM_FILENAME, "r+b"))){ //Testen, ob Datei vorhanden ist.
-			return;
-	}
-
-	//Daten eintragen
-	fseek(fpw, address, SEEK_SET); //Schreibzeiger setzen
-	dataline[0] = data%256;
-	dataline[1] = data/256;
-	fwrite(dataline, 1, size, fpw);	//Daten schreiben
-
-	fclose(fpw);
-	return;	
-}
-
-/*! 
- * Liest die gewuenschten Daten aus eine simulierten EEPROM. Dieses simulierte EEPROM 
- * besteht aus der Datei eeprom.bin. 
- * @param address Adresse im EEPROM zwischen 0 und EE_SIZE-1
- * @param size Groesse der Daten in Byte
- * @return Aus dem EEPROM gelesener Wert
- */  
-static uint16 load_parameter(uint16 address, uint8 size) {
-	FILE *fpr; 	//Dateizeiger
-	uint8 dataline[2] = {0,0};	//String fuer Datenausgabe
-
-	if(address > (size == 1 ? EE_SIZE-1 : EE_SIZE-2)) //Adresse checken
-		return((size == 1 ? 0xff : 0xffff));
-
-	if(!(fpr = fopen(EEPROM_FILENAME, "rb"))){ //Datei oeffnen
-		return((size == 1 ? 0xff : 0xffff));
-	}
-
-	//Daten holen
-	fseek(fpr, address, SEEK_SET); //Lesezeiger setzen
-	fread(dataline, 1, size, fpr);	//Daten lesen
-	fclose(fpr);
-//	LOG_LOAD
-	return((uint16)dataline[0] + (uint16)dataline[1]*256);	
-}
-
-/*! 
- * Laedt ein Byte aus dem EEPROM.
- * @param addr	Adresse im EEPROM zwischen 0 und 1023
- * @return 		Wert der Speicheraddresse im EEPROM
- */ 
-uint8_t eeprom_read_byte(const uint8_t * addr) {
-	return((uint8)load_parameter((uint16)conv_eeaddr(EEPROM_ADDR(addr)), 1));
-}
-
-/*! 
- * Laedt ein Word aus dem EEPROM.
- * @param addr	Adresse im EEPROM zwischen 0 und 1023
- * @return 		Wert der Speicheraddresse im EEPROM
- */
-uint16_t eeprom_read_word(const uint16_t * addr) {
-	return(load_parameter((uint16)conv_eeaddr(EEPROM_ADDR(addr)), 2));
-}
-
-/*!
- * Speichert ein Byte im EEPROM.
- * @param addr	Adresse im EEPROM zwischen 0 und 1023
- * @param value	Das abzulegende Byte
- */   
-void eeprom_write_byte(uint8_t * addr, uint8_t value) {
-	store_parameter((uint16)conv_eeaddr(EEPROM_ADDR(addr)), (uint16)value, 1);
-}
-
-/*!
- * Speichert ein Word im EEPROM.
- * @param addr	Adresse im EEPROM zwischen 0 und 1023
- * @param value	Das abzulegende Word
- */
-void eeprom_write_word(uint16_t * addr, uint16_t value) {
-	store_parameter((uint16)conv_eeaddr(EEPROM_ADDR(addr)), value, 2);
-}
-
-/*! 
- * Kopiert einen Block aus dem EEPROM ins RAM
- * @param pointer_ram		Adresse im RAM
- * @param pointer_eeprom	Adresse im EEPROM
- * @param size				Groesse des Blocks in Byte
- */ 
-void eeprom_read_block(void *pointer_ram, const void *pointer_eeprom, size_t size) {
-	uint32 i;
-	uint8 *ram;
-	
-	ram = (uint8 *)pointer_ram;
-	for(i=0; i< size; i++){
-		ram[i]=(uint16)load_parameter((uint16)conv_eeaddr(EEPROM_ADDR(pointer_eeprom)) + i, 1);
-	}
-}
-
-/*! 
- * Kopiert einen Block vom RAM in das EEPROM
- * @param pointer_ram		Adresse im RAM
- * @param pointer_eeprom	Adresse im EEPROM
- * @param size				Groesse des Blocks in Byte
- */ 
-void eeprom_write_block(const void *pointer_ram, void *pointer_eeprom, size_t size) {
-	uint32 i;
-	uint8 *ram;
-	
-	ram = (uint8 *)pointer_ram;
-	for(i=0; i< size; i++){
-		store_parameter((uint16)conv_eeaddr(EEPROM_ADDR(pointer_eeprom)) + i, (uint16)ram[i] ,1);
-	}
-}
-
-#endif	// PC
+/*
+ * c't-Bot
+ * 
+ * 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.
+ * 
+ */
+
+/*! 
+ * @file 	eeprom-emu_pc.c  
+ * @brief 	Low-Level Routinen fuer den Zugriff auf das emulierte EEPROM des Sim-c't-Bots
+ * @author 	Achim Pankalla (achim.pankalla@xxxxxx)
+ * @date 	07.06.2007
+ */
+
+#include "ct-Bot.h"
+
+#ifdef PC
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "log.h"
+#include "gui.h"
+
+//#define DEBUG_EEPROM		// Schalter um LOG-Ausgaben anzumachen
+
+#ifndef DEBUG_EEPROM
+	#undef LOG_INFO
+	#define LOG_INFO(a, ...) {}
+#endif
+
+extern uint8 __attribute__ ((section (".s1eeprom"),aligned(1))) _eeprom_start1__;
+extern uint8 __attribute__ ((section (".s2eeprom"),aligned(1))) _eeprom_start2__;
+
+/*! Normiert PC EEPROM Adressen*/
+#define EEPROM_ADDR(x) ((uint32)x - (uint32)&_eeprom_start2__ - ((uint32)&_eeprom_start2__ - (uint32)&_eeprom_start1__))
+/*! Macros zum Mitloggen von EEPROM Zugriffen*/
+#define LOG_LOAD 	if(addrconv) {LOG_DEBUG("LOAD:%s : %u", ctab[lastctabi].varname, eeprom[address]);}\
+					else {LOG_DEBUG("load-addr=0x%x/%u", address, eeprom[address]);}
+#define LOG_STORE 	if(addrconv) {LOG_DEBUG("STORE:%s : %d", ctab[lastctabi].varname, value);}\
+					else {LOG_DEBUG("load-addr=0x%x/%d", address, value);}
+
+/*! Macros f�¼r das Einlesen der Informationen aus den MAP-Files*/
+#define GET_VAR_NAME(line, name) sscanf(line, "%s", name)
+#define GET_VAR_DATA(line, addr) sscanf(line,"%s",d),sprintf(d1,"0x%s",d),sscanf(d1,"%x",addr)
+
+/*! Positionen der Daten in den Map-Dateien */
+#ifdef WIN32
+	#define SADDR_POS 54	//Pos. der Adresse in PC Map Datei (ab 0 Zaehlen, letzte 4 Ziffern)
+	#define SNAME_POS 60	//Pos. des Variablennamen ohne _
+	#define BADDR_POS  4	//Pos. der Adresse in MCU Map Datei, letzte 4 Ziffern
+	#define BNAME_POS 34	//Pos. des Variablennamen in MCU Map 
+	#define BSIZE_POS 25	//Pos. der Variablengroesse in MCU Map letzte 4 Ziffern
+#endif					
+#ifdef __linux__
+	#define SADDR_POS 4
+	#define SNAME_POS 37
+	#define BADDR_POS  4
+	#define BNAME_POS 34
+	#define BSIZE_POS 25
+#endif					
+#ifdef __APPLE__
+	#define SADDR_POS 4
+	#define SNAME_POS 39
+	#define BADDR_POS  4
+	#define BNAME_POS 34
+	#define BSIZE_POS 25
+#endif					
+				
+#ifdef __AVR_ATmega644__  // Dieser Prozessor hat 2048 Bytes EEPROM
+	#define EE_SIZE 2048
+#else
+	#define EE_SIZE 1024
+#endif
+
+#define EEPROM_FILENAME	"./eeprom.bin" 		/*<! Name und Pfad der EEPROM Datei. Verzeichnis muss existieren. Backslash doppeln!*/
+#define MAX_VAR 200  						/*<! Maximale Anszahl von Variablen*/
+#define EEMAP_PC  "./eeprom_pc.map"			/*<! Pfad fuer PC-MAP Datei */
+#define EEP_PC    "./ct-Bot.eep"			/*<! Pfad fuer PC-EEP Datei */
+#ifdef WIN32
+	/* Windows */
+	#define EEMAP_MCU "../debug-mcu-w32/eeprom_mcu.map"		/*<! Pfade fuer MCU MAP Datei */
+#else
+	/* Linux und OS X */
+	#define EEMAP_MCU "../Debug-MCU-Linux/eeprom_mcu.map"	/*<! Pfade fuer MCU MAP Datei */
+#endif
+
+typedef struct addrtab {
+	char varname[20];
+	uint32 simaddr;
+	uint32 botaddr;
+	uint32 size;
+	uint32 access;
+} AddrCTab_t;								/*<! Spezieller Datentyp fuer Adresskonvertierung */
+
+static AddrCTab_t ctab[MAX_VAR]; 			/*<! Adresskonvertierungstabelle */
+static uint16 tsize=0; 						/*<! Anzahl Eintraege in der Tabelle */
+static uint16 esize=0;						/*<! Summe der EEPROM Variablen*/
+static uint8 addrconv = 0;                  /*<! Adresskonvertierung ein-/ausschalten */
+static uint16 lastctabi = 0;                /*<! Letzter Zugriffsindex auf ctab */
+static uint8 eeprom[EE_SIZE];               /*<! EEPROM Speicher im RAM*/
+
+/*! 
+ * Diese Funktion konvertiert die Adressen der EEPROM Variablen des PC so,
+ * dass sie den Adressen im realen ct-Bot entsprechen. Dafuer wird mit der Funktion
+ * create_ctab ein Adresstabelle angelegt, diese nutzt diese Funktion.
+ * @param addr Adresse im EEPROM zwischen 0 und EE_SIZE-1
+ * @return Die neue Adresse fuer den realen Bot
+ */
+static uint32 conv_eeaddr(uint32 addr){
+	int8 i;
+	int32 adiff;
+
+	if(!addrconv) //Keine Adresskonvertierung
+		return(addr);
+	for(i=0; i<tsize; i++){
+		adiff = addr - ctab[i].simaddr;
+		if(adiff < 0)
+			return(0xffffffff);
+		if(adiff < ctab[i].size){
+			lastctabi = i; //Letzer guelten Index merken
+			return(ctab[i].botaddr + adiff);
+		}
+	}
+	return(0xffffffff);
+}
+
+/*!
+ * Diese Funktion uberprueft das vorhanden sein der eeprom.bin und initialisiert sie
+ * gegebenenfalls mit der Initwerten der eep Datei.
+ * Es wird dabei die Adresskovertierung benutzt, wenn die EEPROM Simulation im MCU-Modus 
+ * ist.
+ * -----
+ *  0 = EEPROM Datei OK
+ *  1 = Fehler aufgetreten
+ * -----
+ * @param initfile		EEP-Datei des PC Codes
+ * @param eeprom_init	Flag fuer Initialisierung (1 ja, 0 nein)
+ * @return Status der Funktion
+ */
+static uint16 check_eeprom_file(char *initfile, uint8_t eeprom_init){
+	FILE *fpr, *fpw; //Filepointer fuer Dateizugriffe
+	uint16 i; //Laufvariable
+	char data[2]; //Datenspeicher
+	
+	/*eeprom file vorhanden*/
+	if(!(fpw = fopen(EEPROM_FILENAME, "r+b"))){ //Testen, ob Datei vorhanden ist.
+		if(!(fpw = fopen(EEPROM_FILENAME, "w+b"))){ //wenn nicht, dann erstellen
+			LOG_INFO("->Kann EEPROM-Datei nicht erstellen");
+			return(1);
+		}
+		if(!addrconv) {
+			/* EEPROM mit .eeprom-Section des .elf-Files initialisieren, wenn PC Modus */
+			uint8_t * ram_dump = (uint8_t *)(&_eeprom_start2__ + (&_eeprom_start2__ - &_eeprom_start1__));
+			fwrite(ram_dump, EE_SIZE, 1, fpw);
+		} else {
+			/* alternativ: leeres EEPROM erstellen und init setzen bei MCU Modus*/	
+			for(i = 0; i < EE_SIZE; i++)
+				fwrite("\377", 1, 1, fpw);
+			eeprom_init = 1;
+		}
+
+		fclose(fpw);
+		LOG_INFO("->Leere EEPROM-Datei erstellt");
+ 	}
+	
+	/*Initialsieren der eeprom.bin, wenn gewuenscht*/
+	if(eeprom_init){
+		if(!(fpr = fopen(initfile, "rb"))){ //Datei oeffnen
+			LOG_INFO("->EEP nicht gefunden");
+			return(1);
+		}
+		if(!(fpw = fopen(EEPROM_FILENAME, "rb+"))){ //Datei oeffnen
+			LOG_INFO("->EEPROM-Datei kann nicht beschrieben werden");
+			return(1);
+		}
+		
+		/*EEP-Datei in EEPROM-Datei kopieren*/
+		for(i=0; i<EE_SIZE; i++){
+			/*Daten kopieren*/
+			if(!fread(data, 1, 1, fpr))
+				break;
+			if(addrconv){ //EEPROM-Datei im MCU-Modus
+				uint32 naddr;//Konvertierte Adresse
+				
+				naddr = conv_eeaddr((uint32)i);
+				if(naddr != 0xffffffff){
+					fseek(fpw, (int32)naddr, SEEK_SET);
+				}
+				else{
+					continue; //Nichts schreiben Adresse nicht belegt
+				}
+			}
+			fwrite(data, 1, 1, fpw);
+		}
+		fclose(fpr);
+		fclose(fpw);
+		LOG_INFO("->EEPROM-Datei mit Daten init.");
+	}
+	return(0);
+}
+
+/*!
+ * Diese Funktion erstellt aus den beiden im Post erstellten MAP Dateien eine Tabelle
+ * zum umrechnen der PC-Adressen in die des avr-Compilers. Dadurch kann die EEPROM 
+ * Datei in einen zum EEPROM des Bot kompatiblen Format gehalten werden.
+ * Wichtige Informationen werden ueber LOG_INFO angezeigt.
+ * ----
+ * Ergebniscodes der Funktion
+ * 0 = Fehlerfrei
+ * 1 = Sim Mapfile nicht vorhanden
+ * 2 = Bot Mapfile nicht vorhanden
+ * 3 = Unterschiedlicher Variablenbestand
+ * 4 = Zuviele Variablen
+ * 5 = EEPROM voll
+ * 6 = Unterschiedliche Variablenanzahl
+ * 
+ * @param simfile MAP mit den Adressen der EEPROM-Variablen in der PC exe/elf
+ * @param botfile MAP mit den Adressen der EEPROM-Variablen im MCU elf
+ * @return Statuscode
+ */
+static uint16 create_ctab(char *simfile, char *botfile){
+	FILE *fps, *fpb;
+	char sline[250], bline[250]; //Textzeilen aus Dateien
+	char d[30], d1[30], vname_s[30], vname_b[20]; //Dummy und Variablennamen
+	int32 addr_s, addr_b; //Adressen der Variablen
+	uint32 size; //Variablengroesse
+	int16 i, ii; //Laufvariablen
+	uint16 vc = 0; //Variablenzaehler
+
+	/*Dateien oeffnen*/
+	if(!(fps=fopen(simfile,"r"))){
+		LOG_INFO("->EEPROM-MAP fuer PC fehlt");
+		return(1);
+	}
+	if(!(fpb=fopen(botfile,"r"))){
+		LOG_INFO("->EEPROM-MAP fuer MCU fehlt");		
+		return(2);
+	}
+
+	/*Anzahl Variablen vergleichen*/
+	while(fgets(sline, 249, fps)) vc++;
+	while(fgets(sline, 249, fpb)) vc--;
+	if(vc){
+		fclose(fps);
+		fclose(fpb);
+		LOG_INFO("->Unterschiedliche Variablenanzahl");
+		return(6);
+	}
+	rewind(fps);
+	rewind(fpb);
+
+	/*Tabelle erstellen*/
+	while(fgets(sline, 249, fps)){
+		rewind(fpb);
+		GET_VAR_NAME(&sline[SNAME_POS], vname_s);
+		GET_VAR_DATA(&sline[SADDR_POS], &addr_s);
+		while(fgets(bline, 249, fpb)){
+			/*Variablennamen suchen*/
+			GET_VAR_NAME(&bline[34], vname_b);
+			GET_VAR_DATA(&bline[4], &addr_b);
+			GET_VAR_DATA(&bline[25], &size);
+			if(!strcmp(vname_s, vname_b)){
+				/*Daten kopieren*/
+				strcpy(ctab[tsize].varname, vname_b);
+				ctab[tsize].simaddr = addr_s;
+				ctab[tsize].botaddr = addr_b;
+				ctab[tsize].size    = size;
+				ctab[tsize++].access  = 0;
+				esize += size;
+				/*Fehlerabbrueche*/
+				if(tsize == MAX_VAR){
+					LOG_INFO("->Mehr als %n Variablen",MAX_VAR);
+					return(4);
+				}
+				if(esize > EE_SIZE){
+					LOG_INFO("->EEPROM voll");
+					return(5);
+				}
+				
+				/*Erfolg markieren*/
+				addr_b = -1;
+				break;
+			}
+		}
+		if(addr_b > -1){ //Keine passende Variable gefunden
+			LOG_INFO("->Unterschiedliche Variablen");
+			return(3);
+		}
+	}
+
+	/*Dateien schliessen*/
+	fclose(fps);
+	fclose(fpb);
+	
+	/*Tabelle nach Sim-Adressen sortieren*/
+	for(ii=tsize-1; ii > 0; ii--){
+		for(i=0; i < ii; i++){
+			if(ctab[i].simaddr > ctab[i+1].simaddr){
+				long simaddr, botaddr, size;
+				char vname[30];
+			
+				/*Daten umkopieren*/
+				strcpy(vname, ctab[i+1].varname);
+				simaddr = ctab[i+1].simaddr;
+				botaddr = ctab[i+1].botaddr;
+				size    = ctab[i+1].size;
+
+				strcpy(ctab[i+1].varname, ctab[i].varname);
+				ctab[i+1].simaddr = ctab[i].simaddr;
+				ctab[i+1].botaddr = ctab[i].botaddr;
+				ctab[i+1].size    = ctab[i].size;
+
+				strcpy(ctab[i].varname, vname);
+				ctab[i].simaddr = simaddr;
+				ctab[i].botaddr = botaddr;
+				ctab[i].size    = size;
+			}
+		}
+	}
+	
+	/*Tabelle auf Startadresse 0 normieren, wenn noetig*/
+	if((ii = ctab[0].simaddr)){
+		LOG_INFO("->Adressen werden normiert");
+		for(i=0; i < tsize; i++)
+			ctab[i].simaddr -= ii;
+	}
+		
+	return(0);
+}
+
+/*! 
+ * Diese Funktion initialisiert die eeprom-emulation. Sie sorgt fuer die Erstellung der
+ * eeprom.bin, falls nicht vorhanden und erstellt ueber eine Hilfsfunktion eine Adress-
+ * konvertierungstabelle fuer die EEPROM-Adressen, wenn die benoetigten Daten vorliegen.
+ * Statusinformationen werden ueber DEBUG_INFO angezeigt.
+ * @param init	gibt an, ob das EEPROM mit Hilfer einer eep-Datei initialisiert werden soll (0 nein, 1 ja)
+ */
+uint8_t init_eeprom_man(uint8_t init) {
+	uint16 status; //Status von create_ctab
+	uint16 sflag; //Sectionstatus
+	
+	LOG_INFO("EEPROM-Manager");
+
+	/*Adresskonvertierungstabelle anlegen*/
+	if((status=create_ctab(EEMAP_PC, EEMAP_MCU))){
+			LOG_INFO("->EEPROM im PC-Modus");
+	}
+	else {
+			LOG_INFO("->EEPROM im MCU-Modus");
+			addrconv = 1;
+	}
+	
+	/*Sections ueberpruefen*/
+	if((&_eeprom_start2__ - &_eeprom_start1__) > 0 && (&resetsEEPROM - &_eeprom_start2__) >0){
+		LOG_INFO("->Sections liegen wohl korrekt");
+		LOG_INFO("->Section Abstand 0x%X", (&_eeprom_start2__ - &_eeprom_start1__));
+		sflag = 0;
+	}
+	else{
+		LOG_INFO("->Sections liegen falsch");
+		sflag = 1;
+	}
+	
+	/*eeprom.bin checken*/
+	if(sflag || check_eeprom_file(EEP_PC, init)){
+		LOG_INFO("EEPROM-Emulation fehlerhaft");
+		return 1;
+	}
+	else{
+		LOG_INFO("->EEPROM Groesse: %d Bytes", EE_SIZE);
+		if(addrconv)
+			LOG_INFO("->Belegter EEPROM Speicher: %d Bytes", esize);
+		LOG_INFO("EEPROM-Emulation einsatzbereit");
+	}
+	return 0;
+}
+
+/*! 
+ * Traegt die uebergebenen Daten in das simulierte EEPROM ein. Dieses simulierte EEPROM 
+ * besteht aus einer Datei, die jedoch �¼ber RAM gepuffert wird. 
+ * @param address Adresse im EEPROM zwischen 0 und EE_SIZE-1
+ * @param data Daten die abgelegt werden sollen
+ */  
+static void store_parameter(uint16 address, uint8 value) {
+	FILE  *fpw; 	//Dateizeiger
+
+//	LOG_STORE;
+	if(address > EE_SIZE-1) //Adresse checken
+		return;
+
+	//Daten eintragen
+	eeprom[address] = value;
+
+	//Daten in eeprom.bin aktualisieren
+	if(!(fpw = fopen(EEPROM_FILENAME, "w+"))) //Datei oeffnen
+			return;
+	fwrite(eeprom, 1, EE_SIZE, fpw);	//Daten schreiben
+	fclose(fpw);
+	return;	
+}
+
+/*! 
+ * Liest die gewuenschten Daten aus einen simulierten EEPROM. Dieses simulierte EEPROM 
+ * besteht aus der Datei eeprom.bin, welche jedoch nach dem ersten Zugriff im RAM ge-
+ * puffert wird, um den Zugriff zu beschleinigen. 
+ * @param address Adresse im EEPROM zwischen 0 und EE_SIZE-1
+ * @return Aus dem EEPROM gelesener Wert
+ */  
+static uint8 load_parameter(uint16 address) {
+	static uint8 ram = 0;
+	FILE *fpr; 	//Dateizeiger
+
+	if(address > EE_SIZE-1) //Adresse checken
+		return(0xff);
+
+	if(!ram){  //EEPROM ins RAM kopieren
+		if(!(fpr = fopen(EEPROM_FILENAME, "rb"))) //Datei oeffnen
+			return(0xff);
+		fread(eeprom, 1, EE_SIZE, fpr);
+		fclose(fpr);
+		ram++;
+	}
+
+//	LOG_LOAD;
+	return(eeprom[address]);	
+}
+
+/*! 
+ * Laedt ein Byte aus dem EEPROM.
+ * @param addr	Adresse im EEPROM zwischen 0 und 1023
+ * @return 		Wert der Speicheraddresse im EEPROM
+ */ 
+uint8_t eeprom_read_byte(const uint8_t * addr) {
+	return(load_parameter((uint16)conv_eeaddr(EEPROM_ADDR(addr))));
+}
+
+/*! 
+ * Laedt ein Word aus dem EEPROM.
+ * @param addr	Adresse im EEPROM zwischen 0 und 1023
+ * @return 		Wert der Speicheraddresse im EEPROM
+ */
+uint16_t eeprom_read_word(const uint16_t * addr) {
+	return((uint16_t)(load_parameter((uint16)conv_eeaddr(EEPROM_ADDR(addr)))+ 256*load_parameter((uint16)conv_eeaddr(EEPROM_ADDR(addr)))));
+}
+
+/*!
+ * Speichert ein Byte im EEPROM.
+ * @param addr	Adresse im EEPROM zwischen 0 und 1023
+ * @param value	Das abzulegende Byte
+ */   
+void eeprom_write_byte(uint8_t * addr, uint8_t value) {
+	store_parameter((uint16)conv_eeaddr(EEPROM_ADDR(addr)), value);
+}
+
+/*!
+ * Speichert ein Word im EEPROM.
+ * @param addr	Adresse im EEPROM zwischen 0 und 1023
+ * @param value	Das abzulegende Word
+ */
+void eeprom_write_word(uint16_t * addr, uint16_t value) {
+	store_parameter((uint16)conv_eeaddr(EEPROM_ADDR(addr)), (uint8)(value/256));
+	store_parameter((uint16)conv_eeaddr(EEPROM_ADDR(addr)+1), (uint8)(value%256));
+}
+
+/*! 
+ * Kopiert einen Block aus dem EEPROM ins RAM
+ * @param pointer_ram		Adresse im RAM
+ * @param pointer_eeprom	Adresse im EEPROM
+ * @param size				Groesse des Blocks in Byte
+ */ 
+void eeprom_read_block(void *pointer_ram, const void *pointer_eeprom, size_t size) {
+	uint32 i;
+	uint8 *ram;
+	
+	ram = (uint8 *)pointer_ram;
+	for(i=0; i< size; i++){
+		ram[i]=load_parameter((uint16)conv_eeaddr(EEPROM_ADDR(pointer_eeprom)) + i);
+	}
+}
+
+/*! 
+ * Kopiert einen Block vom RAM in das EEPROM
+ * @param pointer_ram		Adresse im RAM
+ * @param pointer_eeprom	Adresse im EEPROM
+ * @param size				Groesse des Blocks in Byte
+ */ 
+void eeprom_write_block(const void *pointer_ram, void *pointer_eeprom, size_t size) {
+	uint32 i;
+	uint8 *ram;
+	
+	ram = (uint8 *)pointer_ram;
+	for(i=0; i< size; i++){
+		store_parameter((uint16)conv_eeaddr(EEPROM_ADDR(pointer_eeprom)) + i, (uint16)ram[i]);
+	}
+}
+
+#endif	// PC
Index: E:/eclipse/ct-bot test/ct-Bot/Changelog.txt
===================================================================
--- E:/eclipse/ct-bot test/ct-Bot/Changelog.txt	(revision 1176)
+++ E:/eclipse/ct-bot test/ct-Bot/Changelog.txt	(working copy)
@@ -1,5 +1,7 @@
 CHANGELOG fuer c't-Bot
 ======================
+2007-07-07 Achim Pankalla [achim.pankalla@xxxxxx]: PC-EEPROM-Emulation überarbeitet. Sollte nun auch mit MacOSX und Linux gehen. EEPROM.bin wird gecached.
+
 2007-07-04 Timo Sandmann [mail@xxxxxxxxxxxxxxx]: 1st_init-Zeug umgebaut (fuer PC-EEPROM-Emulation, #88)
 
 2007-07-02 Benjamin Benz [bbe@xxxxxxxx]: Bugfix in map.c (Treppeneffekt unter Windows #126 + Map-shrink beim einlesen)