Ich habe ein Gerät was sich mit AT Befehlen steuern lässt.
Dem schicke ich einen AT Befehl bis es mir mit "OK" antwortet. Das macht es auch.
1
if(strstr((char*)usart1_buffer,"OK"))
2
{
3
HAL_GPIO_WritePin(LED_R_GPIO_Port,LED_R_Pin,RESET);//red LED ON
4
}
Beim zweiten Befehl frage ich das Gerät nach der Anzahl der gespeicherten Datensätze. Das Gerät antwortet auch (ASCI):
1
usart1_buffer[0]=53
2
usart1_buffer[1]=50
3
usart1_buffer[2]=/r
Das Problem: Er sendet erst die erste Ziffer, dann die zweite. Aber eben immer an eine Stelle des Arrays. "53" = 5, "50" = 2. Macht 52 Datensätze (das passt auch, hab auf der SD Karte nachgeschaut). Wie kriege ich das ganze in einen uint16, damit ich damit normal weiterrechnen kann? Ich habe dafür keinen string Befehl gefunden (oder kann ihn nicht richtig anwenden). Ich müsste ja alle Stellen im Array durchgehen bis "/r" kommt. Die Zahl kann auch drei oder vierstellig sein.
Ich bin mir fast sicher das es da was brauchbares "von der Stange" gibt, ich finde es nur nicht und komm nicht drauf.
Du könntest, wenn ich dich richtig verstanden habe, das erste Auftreten von '\r' im Array suchen, von da rückwärts gehen bis du etwas siehst, was keine Ziffer ist. Ab da+1 dann strtoul() aufrufen.
Komplett daneben. Davon abgesehen, dass es schlechter Stil ist, "magische" Zahlen wie "48" zu schreiben, darfst du mal drüber nachdenken, was aus deiner Rechnung heraus kommt … ganz davon abgesehen, dass sie die Bedingung, dass es auch drei oder vier Ziffern sein können, völlig ignoriert.
Dann hilft strtol() bzw. das schon genannte atoi().
OK, danke. Wenn ich das Beispiel von Steve nehme, dann klappt es. Dazu kopiere ich halt den ganzen "buffer" in den string "str". Dann kommt bei val = 52 raus. Passt erstmal soweit. Sollte ja auch mit 3 und 4 Stellen klappen. Für bessere Vorschläge bin ich offen, funktional ist es erstmal das was ich wollte. Danke!
Dazu kopiere ich halt den ganzen "buffer" in den string "str".
Du musst da nichts kopieren. Du kannst strtol() direkt auf deinen Buffer loslassen.
ps: Der Unterschied zwischen strtol() und atoi() ist, dass du bei der erstgenannten Funktion noch eine Variable angeben kannst, in der du erfährst, bis zu welcher Stelle der Parser gekommen ist. Das sollte bei dir ja immer ein '\r' sein, ansonsten ist was foul.
Wie kriege ich das
ganze in einen uint16, damit ich damit normal weiterrechnen kann? Ich
habe dafür keinen string Befehl gefunden
Doch, den gibt es. Typisch nimmt man sscanf, um formatierte Eingaben in Variablen zu speichern.
Und im Gegensatz zu atoi sagt Dir sscanf auch, wieviel Argumente es lesen konnte, d.h. Du weißt, ob wirklich eine "0" empfangen wurde.
This is a bug in the ISO C standard, and not an inherent design
7
issue with the API. However, current implementations are not
8
safe from that bug, so it is not recommended to use them.
9
Instead, programs should use functions such as strtol(3) to
10
parse numeric input. This manual page deprecates use of the
11
numeric conversion specifiers until they are fixed by ISO C.
Und im Gegensatz zu atoi sagt Dir sscanf auch, wieviel Argumente es
lesen konnte, d.h. Du weißt, ob wirklich eine "0" empfangen wurde.
strtol() sagt es noch genauer: einmal per *endptr und zusätzlich wird overflow erkannt (errno == ERANGE). Ich würde vorschlagen, gewöhn' dich gleich an strtol(), strtoul(), strtoll()...
in einer Schleife bis zum vorletzten iterieren (letztes ist ja "\r")
noch einfacher: bis zum ersten Zeichen, das keine gültige Ziffer ist. Genau das gibt es mit strtol() gratis. Bonus: strtol() funktioniert mit jeder Basis von 2 und 36, nicht nur dezimal und hex. Und erkennt optional den Prefix 0 und 0x und demnächst auch 0b.
Use of the numeric conversion specifiers produces Undefined
Behavior for invalid input.
Keine Ahnung, wie sie auf diese schräge Interpretation kommen. UB entsteht, wenn die Konvertierung nicht zum Typ des Arguments passt, bspw. für %s ein Zeiger auf int geliefert wird. Das Verhalten für fehlerhafte Eingaben ist sehr wohl definiert.
Ich würde trotzdem eher stro*l benutzen, wenn es nur um eine einzelne Zahl geht.
gleich am ersten Patch(-Versuch) sieht man, dass auf jeden Fall ein Bug drin steckt. Für den gibt es anscheinend keine gute Lösung. "Just remove any mention of the ERANGE error to avoid confusion" könnte von Microsoft stammen ;)
Der Link stammt aus einer langen Diskussion da nebenan:
All das wird durch einen typecast von strto*l nach (int) allerdings genauso wenig behoben – und ist mit an Sicherheit grenzender Wahrscheinlichkeit für das Thema des TEs völlig irrelevant.
Wenn man das wirklich vermeiden will, spielt es so gut wie keine Rolle, ob man in scanf() einfach nur "long"-Formate benutzt (und entsprechende Parameter natürlich), oder ob man das mit strto*l() macht – in jedem Falle muss man die domain boundary checks hinterher durchführen, wenn der Wertebereich kleiner als der von long sein soll.
Ich kann mich nicht erinnern, ob mir jemals eine nackte Zahl als Antwort an den Kopf geschmissen wurde. Ich parse meistens mehrere Argumente zusammen und das geht mit sscanf recht bequem. Bei Strings gebe ich auch immer die Pufferlänge mit an, damit kein Überlauf möglich ist.
Ich kann mich nicht erinnern, ob mir jemals eine nackte Zahl als Antwort
an den Kopf geschmissen wurde.
Naja, es geht hier ja nicht um menschliche Eingaben, sondern um eine AT-Protokoll-Antwort. Selbst bei den alten Modems gab es da schon genügend Befehle, die einem als Antwort einfach eine nackte Zahl produziert haben.