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 :
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:
Ä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.
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.
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.
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
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.
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 :(
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 ;)
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;
}
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:(
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
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.
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 :((((((
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...:(
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.
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.
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?
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!!!
Matthias T. schrieb:> mit> char para1[5] ={'O','U','T','1','\0',};> funktioniert das Ganze.
Probier mal das:
1
charpara1[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
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:(
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?
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 :=)
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...
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
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 :(
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
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
chars1[]="teststring";
2
charp1[]="test";
3
charp2[]="text";
4
#define c1 "test"
5
#define c2 "text"
6
7
intmain()
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...
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<<
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?
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.
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 :-)
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.
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....
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...
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?
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.
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 ;)
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!
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.
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!
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.
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.
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.
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.
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.
"...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.
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.