Forum: Mikrocontroller und Digitale Elektronik Teilstring mit Konstante vergleichen


von S. L. (goldencue)


Lesenswert?

Hallo zusammen.

Leider komme ich nun schon 24h an der gleichen Stelle nicht weiter.

System:
Atmega8,STK500,BTM-222,Smartphone. Eine App in Java for Android hab ich 
bereits geschrieben, den AVR entwickle ich in C und AVRStudio. 
Kommuniziert wird über das Bluetoothmodul. Also 
AVR<->UART<->BTM-222<->Smartphone.

Zum Code und somit zum Problem:

Ich lese zunächst alle empfangenen Bytes am µC aus und schreibe sie in :
1
char BT_Receive_Data_Buffer[15];
2
3
BT_Receive_Data_Buffer[0] = '\0';  //mit erstem Zeichen befüllen
4
5
strcat(BT_Receive_Data_Buffer,BT_Receive_byte);  //BT_Receive_byte ist Array[2] mit Terminierung.
6
7
//danach erstelle ich mir eine Kopie von BT_Receive_Data_Buffer:
8
char *Datastream = NULL;
9
memcpy(Datastream,BT_Receive_Data_Buffer,sizeof(BT_Receive_Data_Buffer));
10
11
//danach Teile ich die Kopie:
12
char const delimiter[] = "#";
13
char *data_substr = NULL;
14
data_substr = strtok(Datastream, delimiter);
15
Datastream = data_substr;
und Datastream enthällt nun meinen gesuchten Teilstring.

Nun habe ich eine Kontante:
1
#define BT_Data1_OUT1     "OUT1"
und möchte sie mit dem Teilstring vergleichen:
1
if ( strncmp(DS1,BT_Data1_OUT1,4) == 0)....
und das klappt nicht. Terminiert sind die Strings, ich lasse sie mir 
auch beide anzeigen - gleich. Das es Zeiger sind ist mir klar. Dass sie 
auf verschiedene Adressen zeigen ist mir auch klar. Aber ich will nicht 
die Adressen, sondern natürlich die Werte vergleichen.

Was mache ich hier falsch? Was habe ich nicht verstanden? Hab schon echt 
Einiges versucht wie ihr euch vorstellen könnt. Bis hin zu:
1
if (!strncasecmp(DS1, PSTR("OUT1"), 4)){...oder
2
if (!strncasecmp(DS1, PSTR("OUT1\0"), 4)){...
war alles dabei.

Ich danke euch sehr für Hilfe.

von Karl H. (kbuchegg)


Lesenswert?

1
//danach erstelle ich mir eine Kopie von BT_Receive_Data_Buffer:
2
char *Datastream = NULL;
3
memcpy(Datastream,BT_Receive_Data_Buffer,sizeof(BT_Receive_Data_Buffer));

Äh, nein.
memcpy allokiert keinen Speicher.

Da musst schon du ein Array entsprechender Größe bereitstellen. Und 
anstelle von memcpy solltest du dann auch strcpy benutzen. Spart ein 
paar Bytes zum Umkopieren, wenn der String das Array nicht komplett 
ausfüllt.


Falls das alles dann richtig ist:
> data_substr = strtok(Datastream, delimiter);
> und Datastream enthällt nun meinen gesuchten Teilstring

auch nicht.
Der Teilstring ist immer noch in Datastream. Und data_substr zeigt auf 
den Anfang des Teilstrings in Datastream.

> if ( strncmp(DS1,BT_Data1_OUT1,4) == 0)....

Wo kommt da jetzt auf einmal DS1 her?

Wenn du sowieso auf die ersten n Bytes im Buffer vergleichen willst, 
wozu dann die ganze Zerlegerei. vergleich mit strncmp ob der String im 
Buffer mit deinen gesuchten Buchstaben anfängt und gut ists.

von S. L. (goldencue)


Lesenswert?

Hallo und zunächst dank für deine Antwort!

zum Code:

Karl Heinz Buchegger schrieb:
> //danach erstelle ich mir eine Kopie von BT_Receive_Data_Buffer:
> char *Datastream = NULL;
> memcpy(Datastream,BT_Receive_Data_Buffer,sizeof(BT_Receive_Data_Buffer)) ;

warum nicht? Datastream hat Adresse1 und BT_Receive_Data_Buffer 
Adresse2.
Wenn ich nun memcpy verwende. werden byte für byte alle Elemente an 
Adresse2 kopiert. Zumindest hab ich das so in der Function verstanden.

Matthias T. schrieb:
> data_substr = strtok(Datastream, delimiter);
> Datastream = data_substr;

mein String BT_Receive_Data_Buffer sieht in etwa so aus 
"OUT1#Tmon#HH:MM"
nach dem Zerlegen mit strdok sieht Datastream so "OUT1\0Tmon\0HH:MM" 
aus.
BT_Receive_Data_Buffer hat weiterhin "OUT1#Tmon#HH:MM".
data_substr hat "OUT1\0" angenommen und das übergebe ich Datastream.

Seh ich da was falsch? Es gibt mir ja auch "OUT1" aufs Handy zurück(also 
bereits auch terminiert).

Karl Heinz Buchegger schrieb:
> Wo kommt da jetzt auf einmal DS1 her?

Das war mein Fehler. DS1 ist Datastream. Sorry!

Karl Heinz Buchegger schrieb:
> Wenn du sowieso auf die ersten n Bytes im Buffer vergleichen willst,
> wozu dann die ganze Zerlegerei. vergleich mit strncmp ob der String im
> Buffer mit deinen gesuchten Buchstaben anfängt und gut ists.

Ich muss die anderen Teile des BT_Receive_Data_Buffer auch auswerten und 
die stehen nicht am Anfang.

von S. L. (goldencue)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Äh, nein.
> memcpy allokiert keinen Speicher.

was hab ich dann an der Funktion falsch verstanden?

http://home.fhtw-berlin.de/~junghans/cref/MAN/memcpy.htm

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> Karl Heinz Buchegger schrieb:
>> Äh, nein.
>> memcpy allokiert keinen Speicher.
>
> was hab ich dann an der Funktion falsch verstanden?

Das memcpy (genauso wie strcpy) sich irgendwie selber darum kümmert, das 
für das Ziel Speicher bereit steht. Dem ist nicht so.


  char source[10];
  char dest[10];

  memcpy( dest, source, sizeof( source ) );


Es ist dein Bier, dafür zu sorgen, dass der Pointer, den du für dest 
übergibst, auch wirklich auf Speicher zeigt in den du schreiben darfst. 
memcpy kümmert sich nicht darum, das kopiert einfach nur.

Merke: Nicht jeder Pointer in einer Funktionsargumentliste bedeutet, 
dass du nur eine Pointervariable anlegen musst und alles ist paletti. 
Manchmal (eigentlich recht häufig) bedeutet der Pointer in der 
Argumentliste: Gib mir die Startadresse von Speicher, in dem ich mich 
austoben darf.

von S. L. (goldencue)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Merke: Nicht jeder Pointer in einer Funktionsargumentliste bedeutet,
> dass du nur eine Pointervariable anlegen musst und alles ist paletti.
> Manchmal (eigentlich recht häufig) bedeutet der Pointer in der
> Argumentliste: Gib mir die Startadresse von Speicher, in dem ich mich
> austoben darf.

:) ...dass kenne ich leider zur Genüge :)

Ok. Ich werd es gleich mal umsetzen und dann mal sehen..

bis gleich

von Helmut L. (helmi1)


Lesenswert?

Matthias T. schrieb:
> Ich muss die anderen Teile des BT_Receive_Data_Buffer auch auswerten und
> die stehen nicht am Anfang.

Du weist aber wo dein "OUT1" im String steht und kennst seine Länge.
Dann gehst du im String um diese Länge weiter und dort steht dein Rest.
Und ab da suchst du weiter. So brauchst du den String nicht zu zerlegen.

von S. L. (goldencue)


Lesenswert?

Das Problem bleibt leider. Auch nach festsetzen der Arraygröße.

if ( strncmp(Datastream,BT_Data1_OUT1,4) == 0){... gibt einfach keine 0.

Datastream hat "OUT1" und BT_Data1_OUT1 ebenfalls. Ich lass es mir doch 
ausgeben?!?

Ich versteh das einfach nicht. Werden hier die Adressen verglichen? ( 
wie bei Java mit == )

if ( strncmp(Datastream,Datastream,4) == 0){... funzt natürlich :(

von S. L. (goldencue)


Lesenswert?

Helmut Lenzen schrieb:
> Du weist aber wo dein "OUT1" im String steht und kennst seine Länge.
> Dann gehst du im String um diese Länge weiter und dort steht dein Rest.
> Und ab da suchst du weiter. So brauchst du den String nicht zu zerlegen.

hatte ich mir auch überlegt. Aber der String kann auch so aussehen 
"SYST#Tson#1". Die Länge und der Inhalt der Teile kann variieren.

Abgesehen von den Verifizierungsbytes, die ich bereits schon auf diese 
Art aus dem Hauptstring entfernt hab ;)

von Helmut L. (helmi1)


Lesenswert?

Dann so:

char *p;

p = Datastream;

if (strncmp(p,"OUT1",4))
{
    p +=4;
} else
if (strncmp(p,"SYST",4))
{
    p+=4;
}


ab hier stehst du auf dem #
also

if (*p == '#') p++;

jetzt hinter dem #

und dann weiter mit

Tson

überprüfen mit

if (strncmp(p,"Tson",4))
{
   p+=4;
}

von S. L. (goldencue)


Lesenswert?

Das ist einläuchtend und ich danke dir auch sehr für deinen Vorschlag. 
Ist das nur nicht nen bischen zu viel Schreiberei für sowas? Ich wollte 
so nen "Buchkapitel" vermeiden.

Das zweite daran ist, dass ich dann nicht wirklich die bereits 
vorhandenen Functions nutze, wofür sie ja da sind.

Wenn ich noch weitere 24H an dem Ding hier sitz, werd ich es letztlich 
so oder ähnlich lösen - müssen. Das ist aber ne "Hintertür" und dafür 
sollte es elegantere Wege geben.

Aber es funktioniert. Letztlich zählt das.

Nur - wie kann es kommen, das zwei Strings nicht gleich sind, die 
offensichtlich gleich sind? Ich betone offensichtlich, denn der Fehler 
liegt mir hier nicht zu Füßen:(

von Helmut L. (helmi1)


Lesenswert?

Nun es gibt auch kompaktere Möglichkeiten.

Zuerst den String in Token zerlegen. Also wenn # dein Delimiter ist 
immer bis dahin scannen und dann den gewonnenen Teilstring mit einer 
Tabelle der Schlüsselworte vergleichen und dann die erforderliche Aktion 
ausführen. So wird das normalerweise gemacht

von S. L. (goldencue)


Lesenswert?

Helmut Lenzen schrieb:
> Zuerst den String in Token zerlegen. Also wenn # dein Delimiter ist
> immer bis dahin scannen und dann den gewonnenen Teilstring mit einer
> Tabelle der Schlüsselworte vergleichen und dann die erforderliche Aktion
> ausführen. So wird das normalerweise gemacht

so hab ich es ja - also von der Logik her.

von S. L. (goldencue)


Lesenswert?

Helmut Lenzen schrieb:
> Zuerst den String in Token zerlegen. Also wenn # dein Delimiter ist
> immer bis dahin scannen und dann den gewonnenen Teilstring mit einer
> Tabelle der Schlüsselworte vergleichen und dann die erforderliche Aktion
> ausführen. So wird das normalerweise gemacht

das klingt so schön. Wirklich! Nur ist da das Wort "vergleichen" 
enthalten. Und genau da hakt es eben :((((((

von S. L. (goldencue)


Lesenswert?

bitte bitte - ich weiss nicht weiter.

wenn ich Datastream "hardcodiere" ( also Datastream = "OUT1"; ) klappt 
der Vergleich zu BT_Receive_Data_Buffer natürlich.
Anders herum - wenn ich eine Ersatzvariable mit "OUT1" für 
BT_Receive_Data_Buffer hardcodiere, klappt es auch. Nur beide nicht 
zusammen :(

das darf doch nicht wahr sein! So ein gemeiner Fehler und ich find ihn 
einfach nicht...:(

von S. L. (goldencue)


Lesenswert?

Helmut Lenzen schrieb:
> Dann so:
>
> char *p;
>
> p = Datastream;
>
> if (strncmp(p,"OUT1",4))
> {
>     p +=4;
> } else
> if (strncmp(p,"SYST",4))
> {
>     p+=4;
> }

....


stimmt so leider nicht. die if fragt, ob strncmp != 0 ist. Damit ist sie 
bei NICHTÜBEREINSTIMMUNG wahr.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Du hast irgendwo nen Pufferüberlauf?

Oder kein Speicher reserviert?

Oder ein Endianess- oder anderes Codierungsproblemproblem?

Oder strtok missverstanden?
Es ist zB nicht reentrant: 
http://www.gnu.org/software/libc/manual/html_node/Finding-Tokens-in-a-String.html

RAM/Flash Verwirrung?
Oben steht an einigen Stellen PSTR.
Das Gegenstück muss dazu passen.

von S. L. (goldencue)


Lesenswert?

Johann L. schrieb:
> Du hast irgendwo nen Pufferüberlauf?

Beide Strings werden ordnungsgemäß ausgegeben ( sind also terminiert und 
gleich )

Johann L. schrieb:
> Oder kein Speicher reserviert?

wofür? sowohl Datastream als auch BT_Receive_Data_Buffer beinhalten die 
Strings bereits.

Johann L. schrieb:
> Oder strtok missverstanden?

Matthias T. schrieb:
> mein String BT_Receive_Data_Buffer sieht in etwa so aus
> "OUT1#Tmon#HH:MM"
> nach dem Zerlegen mit strdok sieht Datastream so "OUT1\0Tmon\0HH:MM"
> aus.
> BT_Receive_Data_Buffer hat weiterhin "OUT1#Tmon#HH:MM".
> data_substr hat "OUT1\0" angenommen und das übergebe ich Datastream.

Johann L. schrieb:
> Es ist zB nicht reentrant:

ich habe nur eine Instanz von strtok

Johann L. schrieb:
> RAM/Flash Verwirrung?
> Oben steht an einigen Stellen PSTR.
> Das Gegenstück muss dazu passen.

Ich hatte PSTR auch versucht. Quasi den zu vergleichenden Text im Flash 
liegend zu prüfen. Brachte aber nix. is obsolete ;)

Ich hab nen Zeiger auf nen String der als Teilstring extrahiert wurde 
und möchte ihn mit nem Zeiger auf eine "Vergleichs"konstante prüfen.
strncmp(Datastream, "OUT1",5) geht und
strncmp("OUT1", BT_Data1_OUT1,5) auch. nur beide zusammen nicht :(

Das sieht aus, als wenn strncmp die Adressen prüft und nicht die Werte. 
Was nicht so ist.

Johann L. schrieb:
> Oder ein Endianess- oder anderes Codierungsproblemproblem?

das verstehe ich nicht. was meinst du damit?

von S. L. (goldencue)


Lesenswert?

ich hab es jetzt mit:

char para1[5] ={'O','U','T','1','\0',};

if ( strcmp(Datastream, para1) == 0 ){...

realisiert. Es ist für meine Begriffe ne Assimethode um zu vergleichen. 
Aber ich kann mich jetzt nicht noch länger mit diesem String 
beschäftigen.
Was der Unterschied zwischen:

#define myconst "OUT1"   und
char para1[5] ={'O','U','T','1','\0',};

sein soll ist mir unklar. Aber mit

char para1[5] ={'O','U','T','1','\0',};

funktioniert das Ganze.


Danke euch allen für die Hilfe!!!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Matthias T. schrieb:
> mit
> char para1[5] ={'O','U','T','1','\0',};
> funktioniert das Ganze.
Probier mal das:
1
 char para1[5] = "OUT1";


> Was der Unterschied zwischen:
> #define myconst "OUT1"   und
> char para1[5] ={'O','U','T','1','\0',};
> sein soll ist mir unklar.
Naja, da ist schon ein ganz erheblicher Unterschied:
Das erste ist nur eine Textersetzung (vom Präprozessor),
das zweite ist eine Reservierung und Vorbelegung von Speicherplatz...


> #define BT_Data1_OUT1     "OUT1"
> if ( strncmp(DS1,BT_Data1_OUT1,4) == 0)....
Hier steht also genau das:
if (strncmp(DS1,"OUT1",4) == 0)....

Und bei mir funktioniert das:
http://codepad.org/YqrqZ0fF

von S. L. (goldencue)


Lesenswert?

Lothar Miller schrieb:
> Naja, da ist schon ein ganz erheblicher Unterschied:
> Das erste ist nur eine Textersetzung (vom Präprozessor),
> das zweite ist eine Reservierung und Vorbelegung von Speicherplatz...

Du hast Recht. Für strcmp sollte es in der Verwendung aber keinen 
Unterschied geben. Letztlich steht da in beiden Fällen "OUT1", da beides 
Zeiger auf einen String sind. Auch die Konstante aus #define heraus. Der 
Präprozessor ersetzt zwar dann den Platzhalter per hardcoding. Aber 
intern behandelt strncmp dann den hardcoded String als Pointer darauf. 
Daher - Eigendlich ja kein Unterschied. ( für strncmp)

Lothar Miller schrieb:
> Hier steht also genau das:
> if (strncmp(DS1,"OUT1",4) == 0)....

ich weiss. nur funktioniert das eben leider nicht bei strncmp. Das ist 
es warum ich verzweifel. Ich hatte all die Varianten schon durch von 
dir. wie gesagt- Datastream vs. Array - ja. BT_Receive_Data1_Buffer vs. 
Array - ja. Nur eben beide nicht:(

von Karl H. (kbuchegg)


Lesenswert?

Ich denke, es ist Zeit, dass du mal den richtigen Code möglichst 
komplett zeigst um die Ratespielchen, was du sonst noch so alles 
verbockt haben könntest abzustellen.

PS: Welcher Compiler?

von Helmut L. (helmi1)


Lesenswert?

Matthias T. schrieb:
> if fragt, ob strncmp != 0 ist.

Stimmt hatte ich uebersehen. Kommt davon wenn man Programme ohne 
Compiler einfach so schreibt und nebenbei noch fernsieht :=)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Matthias T. schrieb:
> Lothar Miller schrieb:
>> Hier steht also genau das:
>> if (strncmp(DS1,"OUT1",4) == 0)....
> ich weiss. nur funktioniert das eben leider nicht bei strncmp.
Doch, das funktioniert. Hast du den Link nicht gesehen?
Den Rest hat Karl Heinz gesagt...

von S. L. (goldencue)


Angehängte Dateien:

Lesenswert?

Karl Heinz Buchegger schrieb:
> Ich denke, es ist Zeit, dass du mal den richtigen Code möglichst
> komplett zeigst um die Ratespielchen, was du sonst noch so alles
> verbockt haben könntest abzustellen.
>
> PS: Welcher Compiler?

ok. der Code ist nicht fertig und es wird ne Menge zu Meckern geben für 
so manchen Profi. Aber hier mal die hauptschuldige Datei. Im Moment 
sieht sie etwas unaufgeräumt aus.

#define BT_Data1_OUT1  "OUT1"   // Data1
...
// Globale Variablen **********

u8 BT_Receive_Mode;               // 1 = Beginn - 2 Modus -3 Daten
unsigned int isTurnMode;
unsigned int isReceiveDataComplete;

char BT_Receive_Command1_Buffer[4];
char BT_Receive_Command2_Buffer[3];
char BT_Receive_Command3_Buffer[3];
char BT_Receive_Data_Buffer[15];

//sind in der globals.h definiert

in der Main.c hab ich:

Listen_RX_isdata();
if (isReceiveDataComplete == 1){   //wenn Daten kommen
BT_Receive_Data_processing();
}

und natürlich:

isTurnMode = 0;
isReceiveDataComplete = 0;
BT_Receive_Mode = 1;
BT_Receive_Command1_Buffer[0] = '\0';
BT_Receive_Command2_Buffer[0] = '\0';
BT_Receive_Command3_Buffer[0] = '\0';
BT_Receive_Data_Buffer[0] = '\0';


//////////////////////////////////////////////


so -ab jetzt erwarte ich sauren Regen ;)

PS: Ich wollte noch das Transfercodeschema mitsenden als pdf. Aber das 
nimmt die HP leider ne. Wenns von Nöten fürs Verständnis ist...bitte 
sagen.

von Karl H. (kbuchegg)


Lesenswert?

DU hast den Usninn immer noch
1
har * get_BT_Data1_Buffer(){
2
  
3
  char const delimiter[] = "#";
4
  char *data_substr = NULL;
5
  char *Datastream = NULL;
6
  
7
  Datastream = "";
8
  memcpy(Datastream,BT_Receive_Data_Buffer,sizeof(BT_Receive_Data_Buffer));

Du KANNST Datastream so nicht als das Ziel des memcpy benutzen!

DORT IST KEIN SPEICHER IN DEN DU SCHREIBEN DARFST!

Du scheinst dir extrem unsicher zu sein, wie du mit Pointern hantieren 
musst. Ein Pointer ist einfach nur eine Variable. Ihr Innhalt: Die 
Adresse eines Speicherbereichs, in dem Werte gespeichert werden können. 
Aber: Der Pointer ist NICHT dieser SPeicherbereich! Nur dadurch, dass du 
einen Pointer hast, hast du noch lange nicht die Speicherfläche in der 
du Werte ablegen kannst!

Benutzt werden soll das so


   Datastream
  +------------+
  |    o------------------+
  +------------+          |
                          |
                          v
                        +---+---+---+---+---+---+-...
                        |   |   |   |   |   |   |
                        +---+---+---+---+---+---+-...


Das ganze ist 2-teilig.
Da ist einmal der Pointer und zum anderen der Speicher auf den der 
Pointer zeigt. memcpy will in diesem Speicher die Bytes ablegen. Der 
Pointer ist nur der Wegweiser wie man dorthin kommt.


Du schreibst dir nach wie vor irgendwo im Speicher irgendwelche Bytes 
über den Haufen. Du musst nach den Regeln spielen, sonst wird das 
nichts.

von Karl H. (kbuchegg)


Lesenswert?

Ausserdem kommt mir das ganze höllisch kompliziert aufgebaut vor.
Wenn ich dich richtig verastanden habe, dann willst du doch nicht mehr 
oder weniger als einen String empfangen und den dann wie eine Command 
Line auffassen (also in Befehle und Argumente zerlegen und damit dann 
etwas tun).

Das ist eigentlich etwas recht banales und in weniger als, ich sag mal, 
25 Zeilen abgehandelt. Du machst da eine Wissenschaft draus.

von S. L. (goldencue)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Du schreibst dir nach wie vor irgendwo im Speicher irgendwelche Bytes
> über den Haufen. Du musst nach den Regeln spielen, sonst wird das
> nichts.

ja ich bin etwas unsicher mit den Pointern. Habe aber verstanden was sie 
sind und ( einigermaßen) wie zu handhaben sind.

Ich hatte es auch mit :

char Datastream[5];
Datastream[0] = '\0';

versucht, wie du sagtest. Nur ergab es keine Änderung - leider.

von S. L. (goldencue)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das ist eigentlich etwas recht banales und in weniger als, ich sag mal,
> 25 Zeilen abgehandelt. Du machst da eine Wissenschaft draus.

Kannst du mir die bessere Variante bitte sagen?! Ich verwende sie gern 
und lerne daraus.

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:

> Ich hatte es auch mit :
>
> char Datastream[5];
> Datastream[0] = '\0';
>
> versucht, wie du sagtest. Nur ergab es keine Änderung - leider.


Weil da noch mehr faul ist.
Das ist nur der erste Fehler von mehreren.

(Und wie kommt du auf die 5. Deine empfangene Zeile kann 15 Zeichen lang 
sein, nicht einfach nur 5. Du musst schon immer auch überlegen, was du 
da jeweils reinspeichern willst und wie lang das werden kann.)

Aber erst mal muss ich dein Chaos da mal durchblicken. Denn wie gesagt: 
Du scheinst mir das ganze höllisch kompliziert anzugehen.

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> Karl Heinz Buchegger schrieb:
>> Das ist eigentlich etwas recht banales und in weniger als, ich sag mal,
>> 25 Zeilen abgehandelt. Du machst da eine Wissenschaft draus.
>
> Kannst du mir die bessere Variante bitte sagen?! Ich verwende sie gern
> und lerne daraus.

Was sind deine Rahmenbedingungen?
Was genau kommt über die UART rüber?
Woran erkennst du, wo eine Übertragung anfängt und wo sie aufhört?

Das ganze ist im Prinzip ein 2 Stufen-Prozess:
* erst mal eine ganze 'Zeile' als String empfangen
* danach diese Zeile auswerten

Im Moment versuch ich noch deinen Code in diese beiden Basisdinge 
auseinanderzudividieren. Aber wahrscheinlich läuft es sowieso auf 
Neuschreiben raus.

von S. L. (goldencue)


Lesenswert?

Karl Heinz Buchegger schrieb:
> (Und wie kommt du auf die 5. Deine empfangene Zeile kann 15 Zeichen lang
> sein, nicht einfach nur 5. Du musst schon immer auch überlegen, was du
> da jeweils reinspeichern willst und wie lang das werden kann.)

Datastream ( der den ersten Datenstring enthalten und prüfen soll hatt 
IMMER nur 4 Zeichen. Deshalb die 5.

von Karl H. (kbuchegg)


Lesenswert?

Soll
void Listen_RX_isdata()
wie eine Statemaschine benutzt werden können, die asynchron den Empfang 
und die Auswertung macht?

von S. L. (goldencue)


Angehängte Dateien:

Lesenswert?

Karl Heinz Buchegger schrieb:
> Im Moment versuch ich noch deinen Code in diese beiden Basisdinge
> auseinanderzudividieren. Aber wahrscheinlich läuft es sowieso auf
> Neuschreiben raus.

vermute ich auch;(

hier mal ein Bild des Schemas

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> Karl Heinz Buchegger schrieb:
>> (Und wie kommt du auf die 5. Deine empfangene Zeile kann 15 Zeichen lang
>> sein, nicht einfach nur 5. Du musst schon immer auch überlegen, was du
>> da jeweils reinspeichern willst und wie lang das werden kann.)
>
> Datastream ( der den ersten Datenstring enthalten und prüfen soll hatt
> IMMER nur 4 Zeichen. Deshalb die 5.

Du kannst aber hier

  memcpy(Datastream,BT_Receive_Data_Buffer,sizeof(BT_Receive_Data_Buffer)) 
;

dann nicht einfach sizeof( BT_Receive_Data_Buffer ) Bytes drüberbügeln!

Das muss alles zusammenpassen. Wenn du 15 Bytes von 
BT_Receive_Data_Buffer nach Datastream kopierst, dann muss Datastream 
auch entsprechend gross sein. memcpy kopiert soviele Bytes wie du 
angegeben hast! UNd wenn der Platz im Zielarray nicht ausreicht, dann 
kopiert es einfach weiter. memcpy schert sich nicht darum!

Ausserdem denke ich hab ich dir schon mal gesagt, dass du dafür besser 
die strcpy Funktionen benutzt anstelle von mempcy.

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:

> hier mal ein Bild des Schemas


Ui. Wer hat sich denn das ausgedacht :-)

Seh ich das richtig:
Eine 'Zeile' geht immer vom einleitenden "$$$" bis zum abschliessenden 
"%%" und ist mit einem $ in Gegenrichtung zu quittieren.

von S. L. (goldencue)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Soll
> void Listen_RX_isdata()
> wie eine Statemaschine benutzt werden können, die asynchron den Empfang
> und die Auswertung macht?

Erstmal ja. Ich teile später das Ganze dann noch in strukturiertere 
Teile auf.

Karl Heinz Buchegger schrieb:
> dann nicht einfach sizeof( BT_Receive_Data_Buffer ) Bytes drüberbügeln!

da hast du recht! Das hatte ich nicht gesehen.

Karl Heinz Buchegger schrieb:
> Ausserdem denke ich hab ich dir schon mal gesagt, dass du dafür besser
> die strcpy Funktionen benutzt anstelle von mempcy.

ansich kein Problem. Gern doch. Aber ich wollte nicht einfach die 
Adresse kopieren, sondern die Daten an eine NEUE Adresse. Und da war ich 
mir bei strcpy nicht sicher.

von Karl H. (kbuchegg)


Lesenswert?

Nein Blödsinn. Das geht nicht zeilenweise, weil zwischendurch immer 
wieder geantwortet werden muss.

Dazu macht man am besten eine Statemaschine. Diese Idee von dir ist so 
schon mal nicht so schlecht.

von S. L. (goldencue)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Eine 'Zeile' geht immer vom einleitenden "$$$" bis zum abschliessenden
> "%%" und ist mit einem $ in Gegenrichtung zu quittieren.

jep - allerdings ist das "quittieren" im Moment nicht so wichtig. Das 
brauch ich dann in der AndroidApp und hab es im Mom noch nicht straight 
umgesetzt.

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:

> ansich kein Problem. Gern doch. Aber ich wollte nicht einfach die
> Adresse kopieren, sondern die Daten an eine NEUE Adresse. Und da war ich
> mir bei strcpy nicht sicher.

Es hilft nichts. Du brauchst ein C Buch und ein paar Tage Üben bei den 
Grundlagen der Stringprogrammierung.

von S. L. (goldencue)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Es hilft nichts. Du brauchst ein C Buch und ein paar Tage Üben bei den
> Grundlagen der Stringprogrammierung.

hm - und wenn ich dir jetzt sage, dass ich eines habe und es auch genau 
gelesen? Dann schlägst du mich sicher. Leider ist das ganze Thema 
Pointer und Strings ein schweres Thema und man braucht ( zum Buch ) auch 
Übung :(

von S. L. (goldencue)


Lesenswert?

bevor ich nun das Ganze neu konzipiere, muss ich eine bessere und 
genauer beschriebene Lösung kennen. Ich würde gern beginnen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Matthias T. schrieb:
> und man braucht ( zum Buch ) auch Übung :(
Richtig. Diesen Übungs-Prozess nennt man "Lernen".

Ich habe den Code aus dem Link im 
Beitrag "Re: Teilstring mit Konstante vergleichen" mal mit dem 
AVR-Studio simuliert: tut tadellos...

von S. L. (goldencue)


Lesenswert?

Lothar Miller schrieb:
> Ich habe den Code aus dem Link im
> Beitrag "Re: Teilstring mit Konstante vergleichen" mal mit dem
> AVR-Studio simuliert: tut tadellos...

ja :) Der Code ja. Nur vorher wollte ich den Teilstring "Datastream" mit 
einer Kostante vergleichen und DAS funktioniert nicht.

if ( strcmp(Datastream,BT_Data1_OUT1) == 0)....

obwohl in Datastream auch "OUT1" steht

von S. L. (goldencue)


Lesenswert?

Mal zwischendurch - sitzt ihr beide eigendlich zusammen?

Karl Heinz hat mir schon oft mal geholfen und dafür danke ich hier 
AUSDRÜCKLICH mal!!!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Matthias T. schrieb:
> Nur vorher wollte ich den Teilstring "Datastream" mit
> einer Kostante vergleichen und DAS funktioniert nicht.
Ja, aber genau DAS funktioniert bei mir: in allen 3 Fällen kommt das 
selbe heraus...
1
char s1[] = "teststring";
2
char p1[] = "test";
3
char p2[] = "text";
4
#define c1 "test"
5
#define c2 "text"
6
7
int main()
8
{ 
9
  if ( strncmp(s1,"test",4) )
10
     printf("un");
11
  printf("gleich\n");
12
13
  if ( strncmp(s1,"text",4) )
14
     printf("un");
15
  printf("gleich\n");
16
17
  if ( strncmp(s1,p1,4) )
18
     printf("un");
19
  printf("gleich\n");
20
21
  if ( strncmp(s1,p2,4) )
22
     printf("un");
23
  printf("gleich\n");  
24
25
  if ( strncmp(s1,c1,4) )
26
     printf("un");
27
  printf("gleich\n");
28
29
  if ( strncmp(s1,c2,4) )
30
     printf("un");
31
  printf("gleich\n");  
32
}

Ich vermute eher, dass die Verwendung der "Konstante" dir etwas im nicht 
allokierten Speicher zerhagelt, und du gar nicht mehr die vorgesehenen 
Strings miteinander vergleichst. Mach doch einfach mal einen Step in die 
Funktion hinein und beobachte die beiden Strings im "Watch"-Fenster...

von S. L. (goldencue)


Lesenswert?

ich versteh deinen Gedanken bei der Antwort komplett nicht. Was willst 
du mir damit zeigen? Ich brauch doch kein "ungleich"?! Das hab ich auch 
immer. Ich brauche doch das "istgleich"!


>>völlig konfus gerade<<

von S. L. (goldencue)


Lesenswert?

ich habe jetzt:

char * get_BT_Data1_Buffer(){

char const delimiter[] = "#";
char *data_substr = NULL;
char Datastream[15];

Datastream[0] = '\0';
memcpy(Datastream,BT_Receive_Data_Buffer,sizeof(BT_Receive_Data_Buffer)) 
;
data_substr = strtok(Datastream, delimiter);
*Datastream = data_substr;
return Datastream;
}

//und

if ( strcmp(DS1,BT_Data1_OUT1) == 0){ ... in BT_Data1_select(char *DS1) 
//versucht.

ergibt immer > 0 :(

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Matthias T. schrieb:
> ich versteh deinen Gedanken bei der Antwort komplett nicht.
> Was willst du mir damit zeigen?
Ich will dir zeigen, dass es schnurzegal ist, ob du
1. einen String deklarierst   oder
2. eine Konstante in den Funktionsaufruf nimmst   oder
3. ein define verwendest.
In allen 3 Fällen funktioniert strncmp() tadellos.

> Ich brauch doch kein "ungleich"?! Das hab ich auch immer.
Ich eben nicht.
Ich habe das ungleich nur, wenn die Strings tatsächlich ungleich sind!
Und sonst kommt das Wort "un" nicht vor das Wort "gleich"!
Deshalb wechseln sich auf der Ausgabe diese beiden Wörter fröhlich ab:
1
gleich
2
ungleich
3
gleich
4
ungleich
5
gleich
6
ungleich


> ergibt immer > 0 :(
Hast du mal mit dem Debugger nachgesehen, was da jetzt vor dem Aufruf 
von strcmp() tatsächlich im Speicher steht?

von S. L. (goldencue)


Lesenswert?

Lothar Miller schrieb:
> Deshalb wechseln sich auf der Ausgabe diese beiden Wörter fröhlich ab

ok - verstanden! bei mir geht es leider nicht mit meinem Teilstring und 
Konstante.

Lothar Miller schrieb:
> Hast du mal mit dem Debugger nachgesehen, was da jetzt tatsächlich im
> Speicher steht?

Nun ich simuliere nicht, sondern beschreibe immer direkt den µC und 
sende mit Phone. Ich lasse mir die Strings VOR und NACH strcmp aufs 
Display schreiben und sehe es so. Was genau innerhalb strcmp passiert 
sehe ich leider nicht.

von S. L. (goldencue)


Lesenswert?

Auch dir Lothar - zwischendurch VIELEN DANK für deine Zeit, deinen Rat 
und das Wissen, wodurch ich lerne!

von S. L. (goldencue)


Lesenswert?

bei mir ergibt:
1
if ( strcmp(Datastream,BT_Data1_OUT1) == 0){...      //ungleich
2
if ( strcmp(Datastream,"OUT1") == 0){...          //ungleich
3
if ( strcmp("OUT1",BT_Data1_OUT1) == 0){...      //ungleich
4
5
char test[] = {'O','U','T','1','\O'};
6
if ( strcmp(Datastream,test) == 0){...      //gleich
7
8
char test[] = "OUT1";
9
if ( strcmp(Datastream,test) == 0){...      //ungleich
10
11
if ( strcmp(test,test) == 0){...      //gleich

usw...

Ausf Display werfen sowohl Datatream als auch BT_Data1_OUT1 "OUT1" aus.

von Karl H. (kbuchegg)


Lesenswert?

Lothar.

Er hat sich ziemlich sicher vorher schon den Speicher zerschossen 
gehabt.
(Da wird eine Menge Zeugs unnötigerweise hin und her kopiert und ehrlich 
gesagt will ich mir da jetzt nicht gross den Kopf zerbrechen, wo wieder 
entweder über einen uninitialisierten Pointer oder NULL Pointer kopiert 
wird bzw. wo ein Array Overflow passiert.)

Ich muss aber jetzt erst mal sowas wie eine Statemaschine aufbauen, die 
seine Auswertungen macht. Nur hab ich im Moment auch nicht so die Zeit 
um mich da gross darum zu kümmern :-)

von S. L. (goldencue)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Er hat sich ziemlich sicher vorher schon den Speicher zerschossen
> gehabt.

ich habe nur diesen Code. Mehr ist nicht. Der Fehler MUSS also in dem 
Schnipsel liegen. Weiterer Code kommt später erst dazu.

von Unicode (Gast)


Lesenswert?

Ich werfe hier mal ein Wort ein: Unicode....

Der Junge progamiert für ein Handy Java und so....
Gibt doch mit strlen mal die Länge der Strings aus die Du empfängst....

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Matthias T. schrieb:
> Ich lasse mir die Strings VOR und NACH strcmp aufs
> Display schreiben und sehe es so.
Welches Display?

von S. L. (goldencue)


Lesenswert?

Lothar Miller schrieb:
> Welches Display?

vom Phone.

Ich hab jetzt Datastream globalisiert mit
1
char Datastream[15];
und:
1
char const delimiter[] = "#";
2
char *data_substr = NULL;
3
4
Datastream[0] = '\0';
5
6
strcpy(Datastream,BT_Receive_Data_Buffer);
7
  
8
data_substr = strtok(Datastream, delimiter);
9
*Datastream = data_substr;
10
return Datastream;
11
12
//Das Problem bleibt bei:
13
14
void BT_Data1_select(char *DS1){
15
if ( strcmp(DS1,BT_Data1_OUT1) == 0){valid = 1;BT_Data2_OUT1_select();}
16
}
17
18
//Bzw wird bei "return Datastream" der Teilstring ( nur um eine Speicherzelle versetzt ) übergeben???

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Hatten wir hier nicht letztens die Diskussion das ein Compiler konstante 
Strings in einen anderen Speicherbereich verschob?
Ich würde das ganze erst mal auf dem PC testen, da kann man auch 
leichter debuggen...

von S. L. (goldencue)


Lesenswert?

Läubi .. schrieb:
> Hatten wir hier nicht letztens die Diskussion das ein Compiler konstante
> Strings in einen anderen Speicherbereich verschob?

das hatte ich nicht gelesen

Läubi .. schrieb:
> Ich würde das ganze erst mal auf dem PC testen, da kann man auch
> leichter debuggen...

wie kann ich den Empfangenen String simulieren wenn ich debugge? Ich 
soll doch nicht jedesmal UDR einzeln setzen oder?

von S. L. (goldencue)


Lesenswert?

jetzt wird wieder Datastream mit richtiger Adresse übergeben:
1
char * get_BT_Data1_Buffer(){
2
  
3
  char const delimiter[] = "#";
4
  char *data_substr = NULL;
5
6
  Datastream[0] = '\0';
7
  strcpy(Datastream,BT_Receive_Data_Buffer);
8
  data_substr = strtok(Datastream, delimiter);
9
  strcpy(Datastream,data_substr);
10
return Datastream;
11
}

das Problem:
1
if ( strcmp(DS1,BT_Data1_OUT1) == 0){...   //ergibt != 0 besteht weiterhin

von Karl H. (kbuchegg)


Lesenswert?

So in etwa würde ich das aufbauen.

Beachte:
Ich hab das am PC geschrieben. Ich hab mir daher ein paar Dinge 
'simulieren' müssen, da ich keine UART habe :-)
Statt dessen hab ich einfach einen Input bereit gestellt und schleuse 
den durch die Funktion sukzessive durch. Da musst du anpassen. Genauso 
wie bei den Rückmeldungen.

Die Statemachine an sich ist soweit einfach getestet und funktioniert. 
Alle 'simulierten' Kommandos werden einwandfrei erkannt. Das 
Fehlerhandling könnte noch verbessert werden.
1
#include "stdafx.h"
2
#include <stdio.h>
3
#include <string.h>
4
5
typedef unsigned int uint8_t;
6
7
#define WAIT_FOR_START   0
8
#define GET_COMMAND1     1
9
#define GET_COMMAND2     2
10
#define GET_ARGS         3
11
#define GET_FINISH       4
12
13
uint8_t receiveState = WAIT_FOR_START;
14
uint8_t charCounter = 0;
15
uint8_t argCounter = 0;
16
char    receiveBuffer[20];
17
18
char Input[] = "$$$mm%%$$$ddOUT1%%$$$ddTmon#20:13%%";
19
int nextChar;
20
21
#define MM_COMMAND   0
22
#define DD_COMMAND   1
23
#define TT_COMMAND   2
24
25
uint8_t Command;
26
char    Args[2][10];
27
28
void PerformCommand( uint8_t Command, char* Arg1, char* Arg2 );
29
30
void Listen_RX_isdata()
31
{
32
33
  // Hier austauschen gegen
34
  // Wenn kein Zeichen vorhanden, dann return
35
  // Ansonsten Zeichen holen
36
  char c = Input[nextChar++];
37
  
38
  switch( receiveState ) {
39
40
    //
41
    // warte auf den Beginn einer Meldung
42
    // dieses Warten passiert ohne Ruckmeldung. beendet wird
43
    // es mit dem ersten empfangenen $. Ab da beginnt dann Command 1
44
    //
45
    case WAIT_FOR_START:
46
      charCounter = 0;
47
      if( c == '$' ) {
48
        charCounter++;
49
        receiveState = GET_COMMAND1;
50
      }
51
      break;
52
53
    //
54
    // Command 1 einlesen
55
    // Command 1 besteht immer aus 3 Stueck $    
56
    //
57
    case GET_COMMAND1:
58
      if( c == '$' ) {
59
        charCounter++;
60
        if( charCounter == 3 ) {
61
          charCounter = 0;
62
          printf( "$\n" );  // Empfang bestätigen
63
          receiveState = GET_COMMAND2;
64
        }
65
      }
66
      else {
67
        printf( "@\n" );
68
        receiveState = WAIT_FOR_START;
69
      }
70
      break;
71
    
72
    // nach dem Command 1, kommen 2 Buchstaben, die das eigentliche
73
    // Kommando beschreiben
74
    // Je nachdem welche das sind wird entsprechend verzweigt
75
    // Kann das Command 2 nicht erkannt werden, dann gehts unmittelbar
76
    // zurueck zum Warten auf den Messageanfang. Effektiv bedeutet das
77
    // das im Fehlerfall alles nachfolgende ignoriert wird, bis wieder
78
    // ein Kommandoanfang kommt.
79
    case GET_COMMAND2:
80
      receiveBuffer[charCounter++] = c;
81
      if( charCounter == 2 ) {
82
        receiveBuffer[charCounter] = '\0';
83
        
84
        Args[0][0] = '\0';
85
        Args[1][0] = '\0';
86
        argCounter = 0;
87
        
88
        if( strcmp( receiveBuffer, "mm" ) == 0 ) {
89
          Command = MM_COMMAND;
90
          printf( "$\n" );
91
          receiveState = GET_ARGS;
92
        }
93
        
94
        else if( strcmp( receiveBuffer, "tt" ) == 0 ) {
95
          Command = TT_COMMAND;
96
          printf( "$\n" );
97
          receiveState = GET_ARGS;
98
        }
99
        
100
        else if( strcmp( receiveBuffer, "dd" ) == 0 ) {
101
          Command = DD_COMMAND;
102
          printf( "$\n" );
103
          receiveState = GET_ARGS;
104
        }
105
        
106
        else {
107
          printf( "@\n" );
108
          receiveState = WAIT_FOR_START;
109
        }
110
111
        charCounter = 0;
112
      }
113
      break;        
114
  
115
    // Argumente:
116
    // Argumente hören mit einem # oder einem % auf
117
    // Bei einem % hat man den Anfang der Endesequenz gefunden
118
    // Bei einem # wird zum nächsten Argument weitergeschaltet
119
    case GET_ARGS:
120
      if( c == '%' ) {
121
        charCounter = 1;
122
        receiveState = GET_FINISH;
123
      }
124
      
125
      else if( c == '#' ) {
126
        Args[argCounter][charCounter] = '\0';
127
        charCounter = 0;
128
        argCounter++;
129
        if( argCounter >= 2 ) {    // Ooops, das sollte nicht sein -> Fehler. Alles abbrechen
130
          charCounter = 0;
131
          printf( "@\n" );
132
          receiveState = WAIT_FOR_START;
133
        }
134
      }
135
        
136
      else {
137
        Args[argCounter][charCounter] = c;
138
        charCounter++;
139
      }
140
      break;
141
            
142
    case GET_FINISH:
143
      if( c == '%' ) {
144
        charCounter++;
145
        if( charCounter == 2 ) {
146
          charCounter = 0;
147
          printf( "$\n" );  // Empfang bestätigen
148
          PerformCommand( Command, Args[0], Args[1] );
149
          receiveState = WAIT_FOR_START;
150
        }
151
      }
152
      else {
153
        printf( "@\n" );
154
        charCounter = 0;
155
        receiveState = WAIT_FOR_START;
156
      }
157
      break;
158
      
159
    default:
160
      charCounter = 0;
161
      receiveState = WAIT_FOR_START;
162
      break;      
163
  }
164
}
165
  
166
void PerformCommand( uint8_t Command, char* Arg1, char* Arg2 )
167
{
168
  printf( "Command %d  [%s] [%s]\n", Command, Arg1, Arg2 );
169
170
  if( Command == MM_COMMAND )
171
    ;
172
    
173
  else if( Command == TT_COMMAND )
174
    ;
175
  
176
  else if( Command == DD_COMMAND ) {
177
    if( strcmp( Arg1, "OUT1" ) == 0 )
178
      printf( "Out1\n" );
179
      
180
    else if( strcmp( Arg1, "Tmon" ) == 0 )
181
      printf( "Tmon, mach was mit %s\n", Arg2 );
182
  }
183
}
184
185
int _tmain(int argc, _TCHAR* argv[])
186
{
187
  while( nextChar < strlen( Input ) )
188
    Listen_RX_isdata();
189
}

von S. L. (goldencue)


Lesenswert?

erstmal kurzen Dank für die umfangreiche Arbeit. Ich werde mich morgen 
eingehend damit beschäftigen und hoffentlich viel lernen wie es besser 
geht.

I hope so ;)

von S. L. (goldencue)


Lesenswert?

ok. ich habe das Ganze nun durchgeforstet und verstanden. Ich werde das 
mal umsetzen und hoffen dass es funktioniert.

Was mir auffällt ist: Du hast ein zweidimensionales Array verwendet. 
Ansonsten ist es garnicht soooweit von meiner Idee entfernt. Allerdings 
vergleichst auch du mit hardcodierten Zeichen in strcmp. Genau das war 
der Knackpunkt weshalb ich nicht weiter kam mit meinem Konstrukt. Das 
hätte ich ebenfalls gern über Konstanten gelöst. Ich vermute, dass auch 
bei deiner Lösung es genau da haken wird. Ersteinmal werd ich es aber 
umsetzen und dann werden wir weiter sehen.

Ich danke sehr zunächst!

von Walter S. (avatar)


Lesenswert?

Matthias T. schrieb:
> *Datastream = data_substr;

das ist Blödsinn,
arbeite erst Mal dein C-Buch bezüglich Pointern und Strings durch
(mit Übungen!)

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:

> Was mir auffällt ist: Du hast ein zweidimensionales Array verwendet.

Für die Argumente. Ja.

Dadurch kann ich die Einzelzeichen in der Statemaschine einfacher in den 
jeweils richtigen String verteilen. Sonst müsste man da entweder wieder 
States einführen oder mit zusätzlichen Verezweigungen arbeiten.

> Ansonsten ist es garnicht soooweit von meiner Idee entfernt. Allerdings
> vergleichst auch du mit hardcodierten Zeichen in strcmp. Genau das war
> der Knackpunkt weshalb ich nicht weiter kam mit meinem Konstrukt.

Ich denke immer noch, dass du den falschen Baum anbellst. Dass deine 
Vergleiche nicht funktioniert haben, ist ein Symptom für irgendeinen 
anderen Fehler.

> Das
> hätte ich ebenfalls gern über Konstanten gelöst.

Kannst du doch. Mach dir ein paar #define für die Character bzw. Texte 
und gut ists.

> Ich vermute, dass auch
> bei deiner Lösung es genau da haken wird.

Nö.
Das funktioniert wunderbar, solange du nicht einen Compiler (und ich 
frag jetzt nicht zum 3.ten mal nach welcher es ist) benutzt, der sich 
nicht für Stringliterale eigenmächtig ein anderes Speicherschema 
ausdenkt.

von S. L. (goldencue)


Lesenswert?

so - hier mal die Lösung zum Problem:

Zugegeben - ich hätte den Fehler früher finden können, wenn ich den 
Debugger hätte bemüht.

strtok ersetzt nicht Delimiter mit Terminierungen, sondern mit 
Leerzeichen. Das hatte zur Folge, dass in meinem Datastream fünf Zeichen 
ohne Terminierung standen ( im Speicher ging der String aber weiter ). 
Angezeigt wurde mir nur "OUT1" ( warum auch immer ).
Das dann strcmp("OUT1 tmon 12:13","OUT1)... nicht hinhaut versteht sich.

Ich habe daraus gelernt, habe es umstrukturiert und danken aller Hilfe 
von euch!

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:

> strtok ersetzt nicht Delimiter mit Terminierungen, sondern mit
> Leerzeichen.

Mit Verlaub. Das halte ich für unwahrscheinlich.
So ein Fehler in der Stringlibrary schafft es normalerweise nicht bis in 
die Auslieferungsversion. Der fällt beim obligatorischen automatischen 
Test vor der Freigabe sofort auf.

> Das hatte zur Folge, dass in meinem Datastream fünf Zeichen
> ohne Terminierung standen ( im Speicher ging der String aber weiter ).
> Angezeigt wurde mir nur "OUT1" ( warum auch immer ).

Dann muss der Teil-String terminiert gewesen sein. Anders ist das nicht 
möglich.
Wenn ich tippen müsste, würde ich immer noch auf einen Buffer-Overflow 
oder einen unintialisierten Pointer irgendwo tippen. Die beobachteten 
Symptome sind starke Indizien dafür. Aber das jetzt im Original konkret 
zu analysieren ist ziemlich aufwändig.

von S. L. (goldencue)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Dann muss der Teil-String terminiert gewesen sein. Anders ist das nicht
> möglich.
> Wenn ich tippen müsste, würde ich immer noch auf einen Buffer-Overflow
> oder einen unintialisierten Pointer irgendwo tippen. Die beobachteten
> Symptome sind starke Indizien dafür. Aber das jetzt im Original konkret
> zu analysieren ist ziemlich aufwändig.

Ich habe bereits dein Konzept großteils übernommen und damit ja sowieso 
das Problem nicht mehr. U.A. Hat jedes Array mit String jetzt eine 
Vordefinition der Größe.

Wenn ich strcpy verwende, kopiert es mir bis zu einem Terminate. ( im 
meinem Falle ungewollt also >10 Bytes ). Auch in ein Array, was ich 
vorher mit [5] definiert hab. Wenn ich Datstream ausgeben lasse, gibt es 
eben nur meine [5] aus. Ich denke darin lag der Unterschied. Kann auch 
sein dass ich das immernoch falsch interpretiere.

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:

> Wenn ich strcpy verwende, kopiert es mir bis zu einem Terminate. ( im
> meinem Falle ungewollt also >10 Bytes ). Auch in ein Array, was ich
> vorher mit [5] definiert hab.

Ja. Das ist dein Bier als Programmierer, dich darum zu kümmern, dass es 
da kein Problem gibt :-)

> Wenn ich Datstream ausgeben lasse, gibt es
> eben nur meine [5] aus. Ich denke darin lag der Unterschied.

Dann ist deine Ausgabefunktion für Strings falsch.
Denn eine Ausgabefunktion für Strings gibt solange aus, bis sie auf die 
Terminierung stösst. D.h. auch die weiß nichts von den 5.

von Karl H. (kbuchegg)


Lesenswert?

Das zum Bleistift
1
  data_substr = strtok(Datastream, delimiter);
2
  strcpy(Datastream,data_substr);
ist eine undefinierte Operation. Bei einem strcpy dürfen sich Quelle und
Ziel nicht überlappen. strcpy ist nicht dafür zuständig rauszufinden ob
es jetzt von vorne nach hinten oder doch von hinten nach vorne vorgehen
muss. Das sind alles so Kleinigkeiten, die man sich alle einzeln ansehen
muss und die die Analyse, was da jetzt wirklich in deinem Code passiert,
und wie damit die beobachteten Symptome erklärt werden können, aufwändig
machen.

Und genau wegen solcher Kleinigkeiten ist es auch so wichtig, dass man C
systematisch von der Pieke auf lernt.

von Udo S. (urschmitt)


Lesenswert?

Matthias T. schrieb:
> Wenn ich strcpy verwende, kopiert es mir bis zu einem Terminate.

Dann benutze strncpy()

von Karl H. (kbuchegg)


Lesenswert?

Kurz und gut.
Ich denke, du hast es ja selbst auch schon gesehen. In deinem Code 
kopierst du viel zu viele Strings bzw. Stringteile durch die Gegend.
Brauchst du gar nicht.

C basiert oft darauf, dass man sich einfach nur Pointer auf den Anfang 
eines Stringteiles merkt. Der typische Anwendungsfall für strtok sieht 
so aus, dass man den String an Ort und Stelle belässt und sich über 
strtok immer nur Pointer auf den jeweiligen Anfang besorgt. Den Teil 
selbst kopiert man aber nicht um.
Es ist wie wenn man sich in ein Buch ein paar Lesezeichen einlegt um 
Stellen zu markieren. Man legt deswegen keine Kopien von den 
betreffenden Seiten an, sondern ist mit den Lesezeichen, die den Anfang 
des interessanten Abschnitts markieren glücklich.

In deinem speziellen Fall kommt noch dazu, dass du zwischendurch immer 
wieder Rückmeldungen an den Sender schicken musst, die die übliche 
Vorgehensweise

* Meldung komplett lesen
* Meldung zerlegen

nicht vernünftig implementierbar machen.
Daher komplette Trendumkehr: Statemachine, die im Grunde den Parser 
implementiert. Aber dann muss sie auch wirklich komplett parsen und die 
Einzelteile auseinanderpfriemeln. Leider muss man da dann ein wenig 
Syntax auf Einzelzeichenebene in den Parser einbringen, was im ersten 
Fall so nicht notwendig gewesen wäre. Wenn man aber schon mit 
Einzelzeichen arbeiten muss, dann sollte man es auch dabei belassen und 
dann nicht noch künstlich eine Stringschicht da drüber ziehen.

von S. L. (goldencue)


Lesenswert?

"...da strtok den String durch Leerzeichen ersetzt, arbeitet man 
üblicherweise mit einer Kopie des Strings".
So stand es irgendwo in den Tiefen des Netzes beschrieben.
Ich möchte den Originalstream aber behalten! Deshalb die Kopie.

Jetzt lasse ich mir erst die Daten alle empfangen und sende dann 
Antworten. So kann ich das Prüfen/Zerpflücken - wie du schon sagst - in 
einem Rutsch erledigen, anstatt Zeichen für Zeichen. Allerdings muss ich 
ausschließen, dass evtl einmal garkeine Comletebytes empfangen werden, 
weil z.B. der Kontakt zum Phone mitten in der Übertragung abbrach. Dann 
darf der µC nicht weiter auf "%%" warten.

von Karl H. (kbuchegg)


Lesenswert?

Matthias T. schrieb:
> "...da strtok den String durch Leerzeichen ersetzt, arbeitet man
> üblicherweise mit einer Kopie des Strings".
> So stand es irgendwo in den Tiefen des Netzes beschrieben.
> Ich möchte den Originalstream aber behalten! Deshalb die Kopie.

Bis auf die Sache mit den Leerzeichen (die Unsinn ist), ist das 
natürlich Ermessensfrage. Wenn du im Nachhinein den kompletten String 
noch benötigst, dann macht man sich eine Kopie (vom Originalstring, 
nicht von den Einzelteilen)

> Jetzt lasse ich mir erst die Daten alle empfangen und sende dann
> Antworten.

Das ist das, was ich in deinem GIF nicht sehen konnte.
Wartet der Sender auf die Rückmeldung, nachdem er $$$ gesendet hat, oder 
macht er gleich weiter. Wenn er wartet, dann funktioniert die Methode: 
"lesen vom $$$ bis zum %%" nicht. Ich bin von diesem Fall ausgegangen, 
weil ansonsten dieses Zwischendruch-Rückmeldung-geben sinnlos wäre. Das 
verkompliziert nur die Auswertung für den Sender, ob der Empfänger einen 
Fehler festgestellt hat.

> So kann ich das Prüfen/Zerpflücken - wie du schon sagst - in
> einem Rutsch erledigen, anstatt Zeichen für Zeichen. Allerdings muss ich
> ausschließen, dass evtl einmal garkeine Comletebytes empfangen werden,
> weil z.B. der Kontakt zum Phone mitten in der Übertragung abbrach. Dann
> darf der µC nicht weiter auf "%%" warten.

Den Fall erledigt die Statemachine von oben ebenfalls mit Bravur. Wenn 
die erwarteten Synchronisierzeichen nicht oder in falscher Anzahl 
eintreffen, dann geht es in den allerersten State, bei dem alles bis zum 
Eintreffen des nächsten $ ignoriert wird. Die Statemaschine 
synchronisiert sich also wieder selbst mit dem Sender nach einer 
Unterbrechung.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.