## 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)

- Antworten:
  - Re: [ct-bot] eeprom@pc
    - From: Timo Sandmann
  - Re: [ct-bot] eeprom@pc
    - From: Timo Sandmann

- Referenzen:
  - [ct-bot] Kaibrierung
    - From: Carsten Giesen
  - Re: [ct-bot] Re: Kalibrierung der Distanzsensren mittels EEPROM-Tabelle
    - From: Achim Pankalla
  - Re: [ct-bot] Re: Kalibrierung der Distanzsensren mittels EEPROM-Tabelle
    - From: Benjamin Benz
  - Re: [ct-bot] Re: Kalibrierung der Distanzsensren mittels EEPROM-Tabelle
    - From: Timo Sandmann
  - Re: [ct-bot] Re: Kalibrierung der Distanzsensren mittels EEPROM-Tabelle
    - From: Achim Pankalla
  - Re: [ct-bot] Re: Kalibrierung der Distanzsensren mittels EEPROM-Tabelle
    - From: Timo Sandmann
  - [ct-bot] Kalibrierung der Distanzsensren mittels EEPROM-Tabelle
    - From: Achim Pankalla
  - Re: [ct-bot] Kalibrierung der Distanzsensren mittels EEPROM-Tabelle
    - From: Timo Sandmann
  - Re: [ct-bot] Kalibrierung der Distanzsensren mittels EEPROM-Tabelle und eeprom@pc
    - From: Achim Pankalla
  - Re: [ct-bot] Kalibrierung der Distanzsensren mittels EEPROM-Tabelle und eeprom@pc
    - From: Timo Sandmann
  - Re: [ct-bot] Kalibrierung der Distanzsensren mittels EEPROM-Tabelle und eeprom@pc
    - From: Achim Pankalla
  - Re: [ct-bot] eeprom@pc
    - From: Achim Pankalla
  - Re: [ct-bot] eeprom@pc
    - From: Timo Sandmann
  - Re: [ct-bot] eeprom@pc
    - From: Achim Pankalla
  - Re: [ct-bot] eeprom@pc
    - From: Timo Sandmann
  - Re: [ct-bot] eeprom@pc
    - From: Achim Pankalla
  - Re: [ct-bot] eeprom@pc
    - From: Achim Pankalla
  - Re: [ct-bot] eeprom@pc
    - From: Timo Sandmann
  - Re: [ct-bot] eeprom@pc
    - From: Achim Pankalla
  - Re: [ct-bot] eeprom@pc
    - From: Achim Pankalla
  - Re: [ct-bot] eeprom@pc
    - From: Timo Sandmann
  - Re: [ct-bot] eeprom@pc
    - From: Timo Sandmann
  - Re: [ct-bot] eeprom@pc
    - From: Achim Pankalla
  - Re: [ct-bot] eeprom@pc
    - From: Timo Sandmann

- Voriger (Datum): Re: [ct-bot] eeprom@pc, Timo Sandmann
- Nächster (Datum): Re: [ct-bot] eeprom@pc, Timo Sandmann
- Voriger (Thread): Re: [ct-bot] eeprom@pc, Timo Sandmann
- Nächster (Thread): Re: [ct-bot] eeprom@pc, Timo Sandmann
- Indizes:
  - Datum
  - Thread