Jag kör en del olika projekt där man ofta ska kunde ändra parameter och såklart läsa dom också.
Jag har tidigare haft "skrivbara-i-terminalprogram" men inte alltid så enkla/lätta att minnas koder och jag är ganska trött på det nu.
Jag har därför hittat ett kul sätt, möjligen finns det en bit overhead men ändå...:
1: Jag gör konstant strängar med alla orden som ska kunde användas.
t.ex. "Set", "Get", "Intensity", "Speed" osv.
2: Jag har gjort en tabell med pekare till dessa ord och har en definition som anger antal ord i tabellen.
3: Jag har skrivit en rutin som jag matar med tabellen och antal ord samt källtexten som jag har skickat via serieporten. Den rutin ger en nolla ut om ordet inte kunde matchas eller en 1 + index på ordet. Är det alltså 3'dje ordet i tabellen blir resultatet 4. Samtidig får jag en variabel med hur många tecken som gick åt, då kan jag flytta min pekare om jag vill.
4: Jag har ett slutresultat som jag startar med att nolla för varje kommando. Sedan tar jag, för varje ord som hittas i meningen, och multiplicerar det förra resultat med AC (Antal Commands = antal ord i tabellen) och adderar senaste index. Om det finns ett okänd ord avsluts det hela för den kommandosträng.
5: För varje kontroll kollas det i en switch() om det är ett fullgott kommando. T.ex. är "intensity" inte ett fullt kommando men "get intensity" är det, precis som "set intensity xxx". Jag har såklart en definition för varje giltig sekvens och bara när rätt sekvens kommer utlösas dessa.
6: Slutresultatet är att jag kan skriva "meningar" med kommandon som sedan kan utföras. De är syntax-stabila och enkla och såklart har jag "help" som ett ett-ords kommando, den skriver sedan ut en lista över de kombinationer som gäller.
Rutinen som jämför orden med tabellen jämför utan att ta hänsyn till gemen/versal och ja, den är inte perfekt: egentligen ska man kolla att ordet faktisk sluter så att det verkligen är rätt längd. För tillfället kommer "get" att ge utslag för "gettysburg" och jag ska nog lägga till att det ska finnas en whitespace på rätt plats innan den jämför.
Det är en del jobb innan men nu har jag ett resultat som är enkelt att använda och som gör det enkelt att lägga in parameter via en seriell port.
Dagens tips
Re: Dagens tips
Är inte säker på att jag fattade det där, men tolkar jag rätt att resultatet blir att du t.ex. kan skicka kommandot "set intensity 100" med "2 4 100" ?
Om du vill sätta intensity till 3, hur vet du då att det ska bli "set intensity 3" och inte t.e.x "set intensity speed"?
Eller är alla kommandon alltid uppbyggda av verb+objekt+värde?
/johan
Om du vill sätta intensity till 3, hur vet du då att det ska bli "set intensity 3" och inte t.e.x "set intensity speed"?
Eller är alla kommandon alltid uppbyggda av verb+objekt+värde?
/johan
Re: Dagens tips
sodjan: säkert nog rätt - men det är enkelt att komma ihåg när man står i vägkanten, regnet gör intensiv närkontakt med allt, det är mörkt och arbetsdagen närmar sig 8 timmar och det är fortfarande 3 timmars körning "hem". Och om anslutningen är via terminal med RS232 duger det jättebra.
Och är det en grej man har liggande på arbetsbänken är det guld värd att få satt rätt parameter under testfasen och även där är det trevligt. Man kan såklart ha ett program som lägger in parameter som en del av initieringen men jag har 4 kretskort som ska fungera i par, de ska har exakt samma program i men via en inställning fungera som sensor eller display.
johano: Snarare tvärtom. Skriver jag "help" får jag en lista över vilka kommandon som gäller + det inställda värdet just nu, t.ex:
Set Intensity 100
Jag kan skriva "Get Intensity" och får då svaret "Intensity: 100%"
Jag kan skriva "Set intensity 50" och får då svaret "Intensity Set to 50%"
Att komma ihåg 2 4 100 när himmel och helvetet står i ett och man bara vill HEM och det-kan-bara-ske-för-sakta är svårt! Speciellt eftersom olika projekt har olika inställningar och då att minnas att "i detta projekt är den 2 4 100 som gäller" är ju bara att glömma.
I slutändan ska det hela kunde justeras via radio men då måste jag kryptera kommunikationen och då blir det svårt att "handskriva" kommandon.
Krypteringen är inte så stark men säkert nog helt OK för mitt ändamål.
Och är det en grej man har liggande på arbetsbänken är det guld värd att få satt rätt parameter under testfasen och även där är det trevligt. Man kan såklart ha ett program som lägger in parameter som en del av initieringen men jag har 4 kretskort som ska fungera i par, de ska har exakt samma program i men via en inställning fungera som sensor eller display.
johano: Snarare tvärtom. Skriver jag "help" får jag en lista över vilka kommandon som gäller + det inställda värdet just nu, t.ex:
Set Intensity 100
Jag kan skriva "Get Intensity" och får då svaret "Intensity: 100%"
Jag kan skriva "Set intensity 50" och får då svaret "Intensity Set to 50%"
Att komma ihåg 2 4 100 när himmel och helvetet står i ett och man bara vill HEM och det-kan-bara-ske-för-sakta är svårt! Speciellt eftersom olika projekt har olika inställningar och då att minnas att "i detta projekt är den 2 4 100 som gäller" är ju bara att glömma.
I slutändan ska det hela kunde justeras via radio men då måste jag kryptera kommunikationen och då blir det svårt att "handskriva" kommandon.
Krypteringen är inte så stark men säkert nog helt OK för mitt ändamål.
Re: Dagens tips
Ja visst är det praktiskt!
Och användarvänligt.
Jag tänker t.ex på prylar som t.ex en sådan här 8 portas terminalserver:

Man loggar in med telnet och sedan för att t.ex ställa in serieport nr 3:
(Kopierat live just nu från just en sådan, Lantronix ETS8P, på mitt kontor)
Och glömmer man syntaxen eller alternativen så finns det hjälp:
Moderna terminalservers har mindre inuitiva gränsnitt eller enbart
web-konfigurering, vilket inte alls är lite flexibelt och lättåtkomligt.

Jag tänker t.ex på prylar som t.ex en sådan här 8 portas terminalserver:

Man loggar in med telnet och sedan för att t.ex ställa in serieport nr 3:
(Kopierat live just nu från just en sådan, Lantronix ETS8P, på mitt kontor)
Kod: Markera allt
Local_10>> set port 3 speed 9600
Local_10>> set port 3 flow none
Local_10>> set port 3 char 7
Local_10>> set port 3 parity even
Kod: Markera allt
Local_10>> help set port flow
->SET PORTS FLOW (STTY) :
Specify the type of flow control for transfer to and from a port.
CONTROL CTS DISABLED DSR
ENABLED NONE XON
SET PORTS FLOW Subtopic?
web-konfigurering, vilket inte alls är lite flexibelt och lättåtkomligt.
Re: Dagens tips
Lite uppdatering.
Jag har tidigare beskrivit hur jag har gjort en rutin som kan söka i en ordlista efter kommando-ord. Svaret den rutin ger är 0 = hittade inget av det, 1 = Det var första kommand, 2 = Det var #2 kommando osv. När ett ord är hittat flyttas text-pekaren till första tecken efter det ord och ett ord avgränsas alltid av minst 1 mellanslag.
Jag har tidigare lagt en "gigantisk" lista över vilka kombinationer som var vad och sedan gjort en enkel switch() på totalsumman.
Om man t.ex. har orden "Help", "Set", "Intensity", "Low", "High". Till det knyter jag en enum{}:
enum {Index_Help, Index_Set, Index_Intensity, Index_low, Index_High};
Det är 5 kommandoord så varje kombination ska få ett unikt värde.
"Set Intensity Low" ska alltså ge ((((1 * 5) + 2) * 5) + 3) = 38.
Så case 38: vill alltså reagera på kommandot "Set Intensity Low" i exakt den följd.
Det fungerade så att det blev kollat efter en kommando-sekvens och för varje ord som hittades skapades värdet och detta blev kollat mot den kända lista. Var det inte napp körde et ett ord mer och när texten var slut var det antingen goja eller ett känd kommando-kombination.
Varje case xx: tog sedan hand om vad som skulle hända som följd av kommandot.
Detta sätt fungerade - men jag blev aldrig glad för det. Talen som blev skapade blev snabbt mycket stora om det fanns ett antal kommandoord och en struktur som gav ett antal lager (t.ex. 4 ord = 1 kommando).
Själva programmeringen av det hela blev ganska svår att underhålla, allt lägga in nya kommando-sekvenser kändes besvärligt så jag tänkte om en aning.
Jag använder samma ord-sökning men resultatet läggs i en tabell. Första ord som hittas läggs i första plats i tabellen och räknaren för hittade ord uppdateras. Samtidig sätter jag en flagga som jag kallar "Done" till sann.
Därefter anropas min switch(). Om den t.ex. kommer till Index_Get och just Index_Get kräver minst en parameter mer kollar den räknaren för antal hittade ord och är den lägre än 2 sätts "Done" till falsk och switch() är klar.
Då "Done" indikerar att det ska hittats ytterligare ett ord testas detta och finns nästa ord läggs detta till i tabellen och switch() anropas igen.
Detta betyder att programmeringen blir enklare att överskåda (anser jag), min switch() består då av:
Detta kan jag bygga i det antal lager jag önskar och programmeringen känns mer överskådlig.
Självklart blir det mycket att skriva om det finns många kommando-sekvense att ta hand om men det är ju likadan hur jag än vänder på steken.
En fördel är att jag kan använda kommandoorden i svaren/listningar! Om jag t.ex. lister ett antal värden kan jag lägga med kommandoorden så att man kommer ihåg hur man gör:
sprintf(Buffer, "%s %s %s: %u\r\n", Com_Word[Index_Set], Com_Word[Index_Intensity], Com_Word[Index_Low], Config.Display.Intensity.Low);
om man sedan ändrar orden i listan ändras de automatisk i utskriften också.
Och ja, detta sätt (med kommandoord) tar såklart en del mer programminne än en funktion som kan ta hand om "Pxxx = yyy" men jag behöver inte ha en lista med vilket parameternummer som är vilken värde.
Jag har tidigare beskrivit hur jag har gjort en rutin som kan söka i en ordlista efter kommando-ord. Svaret den rutin ger är 0 = hittade inget av det, 1 = Det var första kommand, 2 = Det var #2 kommando osv. När ett ord är hittat flyttas text-pekaren till första tecken efter det ord och ett ord avgränsas alltid av minst 1 mellanslag.
Jag har tidigare lagt en "gigantisk" lista över vilka kombinationer som var vad och sedan gjort en enkel switch() på totalsumman.
Om man t.ex. har orden "Help", "Set", "Intensity", "Low", "High". Till det knyter jag en enum{}:
enum {Index_Help, Index_Set, Index_Intensity, Index_low, Index_High};
Det är 5 kommandoord så varje kombination ska få ett unikt värde.
"Set Intensity Low" ska alltså ge ((((1 * 5) + 2) * 5) + 3) = 38.
Så case 38: vill alltså reagera på kommandot "Set Intensity Low" i exakt den följd.
Det fungerade så att det blev kollat efter en kommando-sekvens och för varje ord som hittades skapades värdet och detta blev kollat mot den kända lista. Var det inte napp körde et ett ord mer och när texten var slut var det antingen goja eller ett känd kommando-kombination.
Varje case xx: tog sedan hand om vad som skulle hända som följd av kommandot.
Detta sätt fungerade - men jag blev aldrig glad för det. Talen som blev skapade blev snabbt mycket stora om det fanns ett antal kommandoord och en struktur som gav ett antal lager (t.ex. 4 ord = 1 kommando).
Själva programmeringen av det hela blev ganska svår att underhålla, allt lägga in nya kommando-sekvenser kändes besvärligt så jag tänkte om en aning.
Jag använder samma ord-sökning men resultatet läggs i en tabell. Första ord som hittas läggs i första plats i tabellen och räknaren för hittade ord uppdateras. Samtidig sätter jag en flagga som jag kallar "Done" till sann.
Därefter anropas min switch(). Om den t.ex. kommer till Index_Get och just Index_Get kräver minst en parameter mer kollar den räknaren för antal hittade ord och är den lägre än 2 sätts "Done" till falsk och switch() är klar.
Då "Done" indikerar att det ska hittats ytterligare ett ord testas detta och finns nästa ord läggs detta till i tabellen och switch() anropas igen.
Detta betyder att programmeringen blir enklare att överskåda (anser jag), min switch() består då av:
Kod: Markera allt
switch(Command[0])
{
case Index_Get:
if(Found < 2) Done = false;
else
{
switch(Command[1]
{
case Index_Intensity:
break;
}
}
break;
}
Självklart blir det mycket att skriva om det finns många kommando-sekvense att ta hand om men det är ju likadan hur jag än vänder på steken.
En fördel är att jag kan använda kommandoorden i svaren/listningar! Om jag t.ex. lister ett antal värden kan jag lägga med kommandoorden så att man kommer ihåg hur man gör:
sprintf(Buffer, "%s %s %s: %u\r\n", Com_Word[Index_Set], Com_Word[Index_Intensity], Com_Word[Index_Low], Config.Display.Intensity.Low);
om man sedan ändrar orden i listan ändras de automatisk i utskriften också.
Och ja, detta sätt (med kommandoord) tar såklart en del mer programminne än en funktion som kan ta hand om "Pxxx = yyy" men jag behöver inte ha en lista med vilket parameternummer som är vilken värde.