RCswitch tristate an ethernet.client schicken == verstümmelt

Hi Leute,
ich habe zwei Fragen:

Erste Frage:
ich versuche das ergebnis der funktion bin2tristate (static char) an einen etherne client zu schicken, aber nach den ersten 5 Zeichen habe ich immer nur sonderzeichen stehen.

static char* bin2tristate(char* bin) 
  {
   char returnValue[50];
   int pos = 0;
   int pos2 = 0;
   while (bin[pos]!='\0' && bin[pos+1]!='\0') 
     {     
     if (bin[pos]=='0' && bin[pos+1]=='0')
          {       
          returnValue[pos2] = '0';
          } 
      else if (bin[pos]=='1' && bin[pos+1]=='1')
           {       
           returnValue[pos2] = '1';
           }
      else if (bin[pos]=='0' && bin[pos+1]=='1')
           {
           returnValue[pos2] = 'F'; 
           } 
           else 
          {
          return "not applicable";
          }
      pos = pos+2;
      pos2++;
      }
   returnValue[pos2] = '\0';
   return returnValue; 
}

ich habe schon versucht das ergebnis in ein String zu kopieren, aber immer mit dem selben Ergebnis.
Wie könnte ich das hinbekommen?

Zweite Frage:
Ich habe eine Struktur mit nested Structure.

typedef struct a_sensor{
  unsigned long id; // decimal RC code
  String name; // readable name
  byte level;  // 0=always on, 1=nightmode, 2=full armed
  unsigned long lasttime;
  boolean      hastriggered;
  byte action;
  unsigned int timedelay;
  a_sensor* nextsensor;
} a_sensor;

Dadruch kann ich die eepromwriteanything methode nicht nutzen, um diese abzuspeichern.
Wie kann ich diese am eifachsten auf eine SD Karte schreiben und wieder einlesen?? (egal ob eine Datei oder für jeden Sensor/struktu eine eige Datei)

Viele Lieben Dank für jede Hilfe

GLG
Peter

infantilo:
char returnValue[50];

Diese Variable hat nur innerhalb der Funktion Gültigkeit, in der sie so deklariert ist. Der Speicher dieser Variablen wird nach Beendigung der Funktion sofort freigegeben und danach für andere Dinge verwendet.

Wenn der Speicher dieser Variablen das Ende der Funktion überleben soll, z.B. weil Du einen Zeiger auf diesen Speicher als Rückgabewert verwenden und von anderen Programmteilen darauf zugreifen möchtest, mußt Du den Speicher so deklarieren, dass er das Ende der Funktion überlebt und dauerhaft reserviert bleibt:

static char returnValue[50];

Das ist mal ne schöne Anwendung für Rekursion :slight_smile:

Write Anything macht nichts anderes als das struct auf ein Byte Array zu casten und verpackt das ganze in ein Template damit man beliebige Datentypen übergeben kann. Man kann das auch so schreiben:

typedef struct a_sensor
{
	byte test1;
	byte test2;
	byte test3;
        byte test4;
	a_sensor* ptr;
} a_sensor;

void writeSensors(a_sensor* sensor)
{
	for(int i = 0; i < sizeof(*sensor) - sizeof(sensor); i++)
          Serial.println( ((byte*)sensor)[i] );

        Serial.println();

	if(sensor->ptr != NULL)
	   writeSensors(sensor->ptr);
}

void loop()
{	a_sensor mySensor1;
	mySensor1.test1 = 50;
	mySensor1.test2 = 100;
	mySensor1.test3 = 150;
  	mySensor1.test4 = 200;
	mySensor1.ptr = NULL;

	a_sensor mySensor2;
	mySensor2.test1 = 5;
	mySensor2.test2 = 10;
	mySensor2.test3 = 15;
	mySensor1.test4 = 20;
	mySensor2.ptr = &mySensor1;

        writeSensors(&mySensor2);
}

Ich habe dabei die for-Schleife so angepasst, dass der Pointer nicht abgespeichert, bzw. ausgegeben wird. Du kannst natürlich auch die template Version verwenden, wenn du das mit beliebigen structs machen willst.

Rekursion kostet natürlich Platz auf dem Stack. Es ist hier aber auch kein Problem das zu einer while-Schleife aufzulösen:

        a_sensor* currentSensor = &mySensor2;
	do
	{
		for(int i = 0; i < sizeof(*currentSensor) - sizeof(currentSensor); i++)
			Serial.println( ((byte*)sensor)[i] );
         
                Serial.println();

		currentSensor = currentSensor->ptr;
	}
	while(currentSensor != NULL);

Rückwärts kannst du genauso einen byte* auf einen Pointer auf struct casten:

byte* ptr = (byte*)(&mySensor2);
a_sensor* readSensor = (a_sensor*)ptr;

Oder was du eher willst, ist die Daten von einem Array in ein struct mit memcpy() kopieren. z.B. wenn du von deiner SD-Karte erst mal in ein Byte-Array als Puffer einliest. Und dann wieder eine tiefe Kopie anlegen bis das Ende der Datei erreicht ist. Das einzige Problem dabei ist die Speicherverwaltung. Wenn die maximale Anzahl an structs bekannst ist, kann man ein Array aus structs anlegen und dann die Daten vom Array ins struct kopieren. Wenn nicht, ist dynamische Speicherverwaltung mit malloc() angesagt.

Man kann mit structs auch den Zuweisungs-Operator für Kopien verwenden, aber memcpy() wird im embedded Bereich glaube ich bevorzugt.

Vereinfacht für ein struct (nur eine flache Kopie!!):

byte* ptr = (byte*)(&mySensor2);
a_sensor readStruct;
memcpy(&readStruct, ptr, sizeof(readStruct));

Klar ist es hier Unsinn in der ersten Zeile das struct auf byte* zu casten, da memcpy() mit beliebigen Datentypen geht. Ist nur als allgemeines Beispiel gedacht.
In deinem Fall hättest du dann eine Byte-Array, das von der SD-Karten Auslese-Routine kommt. Und dieses kopiert man dann in ein struct das in einem Array aus structs stehen könnte. Oder wenn man mit malloc() arbeitet, ein Array aus Pointern auf structs.

Danach muss man noch die Pointer entsprechend eintragen.

Man muss halt schauen, dass die Bytes richtig zugeordnet werden. Da gibt es hier ein paar Feinheiten und Fallen. Deshalb würde ich das erst mal mit structs aus Bytes oder chars testen. Danach kann man auf größere und gemischte Datentypen umsteigen.

Hallo Leute!
Ihr seid echt spitze!!!! Danke für die raschen (und für mich verständliche Antwort(en))!!
Vielen Dank!
Jetzt bleibt noch eine Frage, wenn ich euch damit quälen dürfte:

wie kann ich die bin2tristate funktion eigentlich umkehren und aus dem char* wieder einen dezimalwert machen?
Für die RCswitch library wäre das - finde ich - wirklich interessant, denn wenn ich einen neuen Empfänger hinzufüge muss ich an diesem ja die dipswitched stellen, habe also den tristate, weiß zu diesem zeitpunkt aber den decimal wert nicht. Irgendwie bekomme ich das aber nicht gebacken. :frowning:

Was steht da genau drin? Wenn es ein einzelner Character ist kannst du einfach -48 machen, da '0' den ASCII Wert 48 hat. Oder auch -'0' oder -0x30

Wenn es ein String ist - z.B. "123" gibt es dafür atoi() und atol():
http://www.cplusplus.com/reference/cstdlib/atoi/
http://www.cplusplus.com/reference/cstdlib/atol/

hu...ich glaub der Schlafentzug hat jetzt endlich seine Spuren bei mir hinterlassen.
Tja, wäre natürlich nicht schlecht gewesen, wenn ich die Funktion gepostet hätee....sorry....mea culpa

static char* bin2tristate(char* bin) {   char returnValue[50];   int pos = 0;   int pos2 = 0;   while (bin[pos]!='\0' && bin[pos+1]!='\0') {     if (bin[pos]=='0' && bin[pos+1]=='0') {       returnValue[pos2] = '0';     } else if (bin[pos]=='1' && bin[pos+1]=='1') {       returnValue[pos2] = '1';     } else if (bin[pos]=='0' && bin[pos+1]=='1') {       returnValue[pos2] = 'F';     } else {       return "not applicable";     }     pos = pos+2;     pos2++;   }   returnValue[pos2] = '\0';   return returnValue; }

Das hattest du oben schon gepostet :slight_smile:

Aber nicht was da als Parameter übergeben wird. Es sieht aber nach einem ganzen String aus, da drüber iteriert wird bis der Null-Terminator kommt.

Ich würde dann mal sowas probieren:

int number = atoi(bin);

atoi = array to integer

also, einen Kaffee später und in der Firma sitzend probier ichs nochmal :blush:

char* b = dec2binWzerofill(decimal, length);
char* tristate = bin2tristate( b)

wobei

static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength){
   static char bin[64];
    unsigned int i=0;
    while (Dec > 0) {
     bin[32+i++] = (Dec & 1 > 0) ? '1' : '0'; 
    Dec = Dec >> 1;
   } 
   for (unsigned int j = 0; j< bitLength; j++) {
     if (j >= bitLength - i) {
       bin[j] = bin[ 31 + i - (j - (bitLength - i)) ];
     }else {
       bin[j] = '0';
     } 
  }
   bin[bitLength] = '\0';
      return bin;
 }

Mhh, Moment, du hast einen String mit einer Binärzahl und den willst du in eine Dezimalzahl wandeln?
Ich hoffe jetzt habe ichs :o

Dafür gibt es das hier:
http://www.cplusplus.com/reference/cstdlib/strtol/

Das ist im Prinzip wie atol() aber man kann die Basis frei wählen. Also wenn man das macht:

char str[] = "1010"
long number = strtol(str, NULL, 2);

..steht in number = 10

Noch besser ist vielleicht strtoul() für unsigned long, aber das ist nur eine Frage des Wertebereichs.

Ist das jetzt was du wolltest? Wenn nicht musst du das Problem mal allgemein in Worten erklären :slight_smile:

Danke für deine Geduld! Ich weis das sehr(!) zu schätzen.

Also, ich habe
decimal: 333073
length: 24 bit
und bekomme damit: 00FF0FFF0F0F

den deizmal wert nutze ich im programm.
nun müsste ich aber aus dem tristate 00FF0FFF0F0F wieder irgendwie auf die 333073 kommen.

Mhh, das ist ja kein Standard Format was du da hast

Du hast das:
00 = 0
11 = 1
01 = F

Dann musst du das erst mal wieder per Hand umwandeln. Also deine Funktion von oben einfach anders herum schreiben. Sollte nicht so schwer sein. Wenn du dann erst mal einen String in Binär hast (nur 0 und 1) kannst du strtol() verwenden um daraus eine Zahl zu machen. Man könnte vielleicht auch die Wertigkeiten (1,2,4,16,32...) gleich aufaddieren. Das braucht weniger Speicher.