Document ID: /fineweb-2-swissfilter-quality_10-filterrobots/filtered/03291.jsonl.gz/204

Im vorangegangenen Teil ging es lediglich um die Aufteilung des ankommenden Befehlsstrings und wenn man sich den Code angesehen hat, dann war vermutlich nicht auf den ersten Blick ersichtlich, weshalb man das Ergebnis des Vorganges in einer Struktur zwischenspeichert, die dann auch noch etwas umständlich daher kommt.
Nach dem Tokenisieren muss nun Fleisch an den Knochen kommen und man könnte versucht sein, jetzt die String in einem if() else Block abzufragen oder, wenn es viele unterschiedliche Befehle sind, dies in einem grossen switch() nach Funktionen aufzuteilen.
Mit einem etwas grösseren Code wäre man aber auch in der Lage, viele Befehle zu implementieren ohne dabei jedes mal eine If() oder eine case zu implementieren.
Mit diesem Ziel versuchte ich den Vorgang, tokenisieren, Befehl evaluieren und den Befehl ausführen mittels einer Tabelle zu „normalisieren“. Dabei lege ich die Tabelle im Flash der CPU ab, da jegliche Daten die sich im Code Segment befinden, bei den kleinen Atmelprozessoren zuerst vom Flash ins Ram gebracht werden müssen, was unnötig RAM belegt, aber etwas mehr CPU Zeit beansprucht.
Bei meinem kleinen Beipielprogramm sind fürs Erste lediglich zwei Befehle leer implementiert, um die Lösung zu demonstrieren. Anstelle des Aufrufs der cmd_tokenizeCmdString() Funktion im main(), wird nun die Funktion cmd_Exec(strCommand) aufgerufen. Als einzigen Parameter bekommt die Funktion das Befehlsstring. Diese Funktion kopiert dann das strCommand string in einen temporären Buffer, der dynamisch vom Stackmemory zur Verfügung gestellt wird. Die Lösung mit __builtin_alloca() habe ich auch erst kürzlich entdeckt und wollte sie hier mal ausprobieren. Anschliessend wird der String wie bereits gezeigt mit der Funktion cmd_tokenizeCmdString() zerlegt. Im Parameter-Array der Struktur StructCmdPara steht nun auf dem ersten Eintrag das zu behandelnde Befehlswort (z.B: get). Mittels einer Helperfunktion tool_lookUpName_P () sucht das Programm in der Tabelle CmdTable, die sich ausschliesslich im Flash befindet, nach dem Befehl abgesucht. Die Funktion liefert in der Para Struktur im Feld CmdIdx dann den entsprechenden Index ab, an welcher Stelle der Befehl gefunden wurde. Wurde der Befehl nicht gefunden, dann liefert die Funktion den Indexwert 255 zurück.
Wurde ein Eintrag gefunden, wird ein Strukturzeiger in die Tabelle erzeugt
const __flash StructCmdTable *pCmdEntry = &CmdTable[Para.CmdIdx];
der Zeiger nochmals geprüft und dann die zugehörende Funktion via eines Funktionszeiger in der Tabelle aufgerufen. Im Falle des Befehls «get» setzt das Programm die Fortführung direkt auf
int fp_get(StructCmdPara * pPara )
{
return 0;
}
fort. Die Parameter Struktur vom Tokenizer wird als Parameter an die Funktion übergeben. Damit kann die Funktion nun erledigen was sie will und die Parameter entnehmen, gegebenenfalls konvertieren und ausführen was sie auszuführen hat.
Um eine neue Funktion (help) zu implementieren muss man:
Den Stringnamen im Flash hinterlegen:
const __flash char cmdName_help[] = "help";
Eine Funktion implementieren:
int fp_help(StructCmdPara * pPara )
{
return 0; // hier tut man das was der Befehl help tun soll
}
Und die Beiden in der Tabelle CmdTable eintragen. Damit ist der Overhead für einen neuen Befehl sizeof (cmdName_help) + sizeof(StructCmdTable) + der Code der Funktion.
Das wars von mir, für dieses Jahr und ich wünsche Allen Lesern einen Guten Rutsch ins 2022.
Pius