Skapa ett programvalsystem i C

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Hej!

Skulle behöva lite vägledning från er o programmeringsgurus.
Jag vill skapa ett menysystem med programval i C och skulle behöva en knuff i rätt riktning. Här kommer lite mer ingående förklaring:

Min enhet har en knapp och när denna hålls nere länge (säg 5+ sek) så går enheten in i "programvalsläge". När enheten är i detta läge så innebär ett snabbt knapptryck nästa program. När man knappat sig till rätt program så hålls knappen in länge igen och detta nya program låses.

Att sätta enheten i programvalsläge genom ett långt knapptryck kan jag nog lösa men jag vet inte vilket tänk jag ska använda mig av när det kommer programmen.

Min idé är att ha en "programvariabel", där varje bit i variabeln har en funktion. Genom att kombinera olika bitar så skapas dom olika programmen.
En switch() case kan sedan stegas runt genom att maska av bit för bit för att veta vilken funktion i programmet som ska köras.
Hur skulle ni gjort? Hur gör ni allmänt när det kommer till "menyhantering" och liknande i kod? Är det här en typisk situation där goto används?

Väldigt svårt att förklara sånt här i skrift för det blir snabbt en massa text som ingen orkar läsa. Men fråga gärna!
datajompa
Inlägg: 232
Blev medlem: 5 november 2010, 10:35:54

Re: Skapa ett programvalsystem i C

Inlägg av datajompa »

Förstår jag syftet rätt här? Du har en apparat som bara har en knapp vilket gör den krånglig att använda. Du vill tillverka en manick som låter dig välja olika menyalternativ på ett mer naturligt sätt, och sedan simulerar knappnedhållning osv. för att styra apparaten?
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Nej, inte riktigt, men det är jag som är otydlig.
Kan ta mitt aktuella projekt och försöka göra det tydligare:

Jag har en pannlampa som jag moddat lite och nu sitter det en µC i lampan. Lampan vill jag ha olika program för. Tex med program 1 inställt så slår av/på-knappen enbart lampan fullt på eller fullt av.
Har man tex program 2 inställt så växlar lampan mellan hel, halv och av. Program 3 kanske är hel, halv, S.O.S och av osv.

Det är alltså detta programsystem jag försöker få till. Vill man ha ett nytt program (eller mönster) som ett knapptryck ska växla mellan så håller man inne av/på-knappen för att sätta den i "programvalsläge", knappar fram till nytt program, håller inne knappen igen för att låsa programmet.

Jag behöver en liten spark i rätt riktigt om hur ett lämpligt flöde i koden skulle kunna se ut.
datajompa
Inlägg: 232
Blev medlem: 5 november 2010, 10:35:54

Re: Skapa ett programvalsystem i C

Inlägg av datajompa »

Nåt sådant här? Helt otestat, har inte kodat C på evigheter heller.

Kod: Markera allt

#define MILLISECOND_CONSTANT (123.4) /* ticks / millisecond */
#define PROGMODE_THRESHOLD (5000 * MILLISECOND_CONSTANT)

typedef enum { false, true } bool;

#define MIN_BUTTON_LENGTH (10 * MILLISECOND_CONSTANT)

#define MAX_BUTTON_LENGTH (1000 * MILLISECOND_CONSTANT) /* only presses shorter than this counts as regular button presses */

bool key_is_down (void) {
	// insert code here
}

void toggle_light_onoff(void) {
	// insert code here
}

int main(void) {

   typedef enum {
      apelsin, banan, citron
   } menu_state_e;

  menu_state_e menu_state = apelsin;

   bool progmode_active = false;

   int key_down_count = 0;
   
   while(1) { /* main loop */
      if(key_is_down()) {
         key_down_count++;
      } else {
          if(key_down_count >= PROGMODE_THRESHOLD) {
             progmode_active = !progmode_active;

          } else if (key_down_count >= MIN_BUTTON_LENGTH && key_down_count <= MAX_BUTTON_LENGTH) {
              if(progmode_active) {
                  menu_state ++;
                  if(menu_state > citron) menu_state=apelsin;
              } else {
                  toggle_light_onoff();
              }
          }

          key_down_count = 0; /* reset keypress counter. I'm assuming hardware debounce is present. */             
      }
   }

}
Senast redigerad av datajompa 26 mars 2017, 18:27:50, redigerad totalt 1 gång.
datajompa
Inlägg: 232
Blev medlem: 5 november 2010, 10:35:54

Re: Skapa ett programvalsystem i C

Inlägg av datajompa »

Jag följde inte din spec alls i kodsnutten ovan... Bara tänkt som en lös "skiss". Det finns säkert syntaxfel också.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Tackar datajompa!

Förstår i stort hur du skulle "lagt upp det", och det tackar jag för.
Är nyfiken på hur man i regel resonerar när man ska göra menysystem och annat i kod.
Vill man helst sätta programmet i olika "states" eller kan man även göra koden så programmet skickas till olika loopar, beroende på vart i menyn man är?

Äsch, svårt att förklara men är jättetacksam om någon vill ventilera lite hur just reat resonemang låter.
hummel
Inlägg: 2267
Blev medlem: 28 november 2009, 10:40:52
Ort: Stockholm

Re: Skapa ett programvalsystem i C

Inlägg av hummel »

Att använda en tillståndsmaskin är väldigt bra. Då kan man på ett relativt enkelt sätt verkligen testa varenda rad kod!
datajompa
Inlägg: 232
Blev medlem: 5 november 2010, 10:35:54

Re: Skapa ett programvalsystem i C

Inlägg av datajompa »

Försökte mest göra nåt kort och enkelt att läsa, fortfarande svårt att veta EXAKT vad du frågar efter?

Jag skulle ha gjort nåt mer som nedanstående med funktionspekare. Denna gång testkört under Ubuntu, funkar endast i riktig virtual terminal (Ctrl+Alt+F1). Jag hade ingen Windowsmaskin att testa en lämplig key_is_down() på men det borde ju vara enkelt. Jag tror dock inte att kbhit() räcker för den signalerar väl bara lägesväxlingar?

Vänster Ctrl simulerar din knapp som jag förmodar ska vara hårdvara på en uC, shift avslutar. Så på en uC så borde key_is_down() kunna vara bara typ

Kod: Markera allt

return *0xABCD;
Måste länkas med ncurses på linux,

Kod: Markera allt

gcc pannlampameny.c -o pannlampameny -lncurses

Kod: Markera allt

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>

typedef enum { false, true } bool;

#define MILLISECOND_CONSTANT (10.1) /* ticks / millisecond */
#define PROGMODE_THRESHOLD (5000 * MILLISECOND_CONSTANT)
#define MIN_BUTTON_LENGTH (10 * MILLISECOND_CONSTANT)
#define MAX_BUTTON_LENGTH (1000 * MILLISECOND_CONSTANT) /* only presses shorter than this counts as regular button presses */

#ifdef __linux__
bool key_is_down (void)
{
    char shift_state;

    shift_state = 6;
    if (ioctl(0, TIOCLINUX, &shift_state) < 0) {
        perror("ioctl TIOCLINUX 6 (get shift state)");
        exit(1);
    }
    if(shift_state == 1) {
        exit(1);    // lshift quits, ctrl is key
    }
    return shift_state == 4;  //  Returns true if pressed otherwise false
}
#elif _WIN32
#error Implement your own non-blocking key-down code, must return true _while_ target key is _held down_
#else
#error Implement your own non-blocking key-down code, must return true _while_ target key is _held down_
#endif

/* callbacks gives maximum flexibility with regards to what different menu programs can do */

#define NEXT_STATE(x,y) x++;if(x>=y)x=0;

void do_prog1(void)
{
    typedef enum {on, off, num_states} state_e;
    static state_e state = 0;
    switch(state) {
    case on:
        printf("Prog1 on\n");
        break;
    case off:
        printf("Prog1 off\n");
        break;
    }
    NEXT_STATE(state,num_states);
}

void do_prog2(void)
{
    typedef enum {full, half, off, num_states} state_e;
    static state_e state = 0;
    switch(state) {
    case full:
        printf("Prog2 hel\n");
        break;
    case half:
        printf("Prog2 halv\n");
        break;
    case off:
        printf("Prog2 av\n");
        break;
    }
    NEXT_STATE(state,num_states);
}

void do_prog3(void)
{
    typedef enum {full, half, sos, off, num_states} state_e;
    static state_e state = 0;
    switch(state) {
    case full:
        printf("Prog3 hel\n");
        break;
    case half:
        printf("Prog3 halv\n");
        break;
    case sos:
        printf("Prog3 S.O.S.\n");
        break;
    case off:
        printf("Prog3 off\n");
        break;
    }
    NEXT_STATE(state,num_states);
}

int main(void)
{
    void (*functions[])(void) = {&do_prog1, &do_prog2, &do_prog3};
    int menu_length = sizeof(functions) / sizeof(functions[0]);

    int menu_state = 0;
    bool progmode_active = false;

    int key_down_count = 0;

    printf("LCtrl simulates GPIO button. Press to shift states. Hold down 5 secs to activate programming mode. LShift quits.\r\n");

    while(1) { /* main loop */
        usleep(1); // slow things down, for testing purposes

        if(key_is_down()) {
            key_down_count++;
            if(key_down_count == PROGMODE_THRESHOLD) {
                progmode_active = !progmode_active;

                printf("Progmode: %d\n", progmode_active);
            }
        } else {
//          if(key_down_count != 0) printf("ms%f\n", key_down_count / (MILLISECOND_CONSTANT)); //uncomment to tune MILLISECOND_CONSTANT
            if (key_down_count >= MIN_BUTTON_LENGTH && key_down_count <= MAX_BUTTON_LENGTH) {
                if(progmode_active) {
                    NEXT_STATE(menu_state,menu_length);
                    printf("Selected menu item: %d\n", menu_state);
                } else {
                    (*functions[menu_state])();
                }
            }
            key_down_count = 0; // reset keypress counter. I'm assuming hardware debounce is present.
        }
    }
}
Senast redigerad av datajompa 27 mars 2017, 16:31:03, redigerad totalt 6 gånger.
datajompa
Inlägg: 232
Blev medlem: 5 november 2010, 10:35:54

Re: Skapa ett programvalsystem i C

Inlägg av datajompa »

Mer allmänt så finns det inga enkla och snygga lösningar i C. Det du pratar om är när du vill ha menyer i flera nivåer, i en hierarki osv? I C vill måste du nog bita i det sura äpplet och göra det med funktionspekare, ungefär som i mitt ovanstående exempel, fast med mer indirekta pekare till strukturer osv.

Om du använt ett språk med vettiga inbyggda strukturer så är det ju enkelt att göra t.ex.

Kod: Markera allt

var menu = [[("Meny1 alt 1",m1a1func),("Meny1 alt 2", m1a2func)],[("Meny2 alt 1",m2a1func)]]
i Javascript, Python, osv.

Ska man göra något liknande i C så blir det alltid hisnande någonstans. Antingen hisnande komplexa och fragila #define-grejer, eller hisnande "kluriga" lösningar som man inte förstår veckan efter att man skrev dem.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Verkligen himla snällt att du lagt ner sån här tid på att svara.
Suttit och klurat en del på koden och jag har lite svårt att läsa precis vad den gör. Vad händer tex här -> state = (state<num_states-1) ? state+1:0; ?

Du skriver "eller hisnande "kluriga" lösningar som man inte förstår veckan efter att man skrev dem.". Exakt så känner jag.
Kläcker en "smart" lösning en dag, och antecknar denna. Ett par dagar efteråt så undrar jag hur i hela friden jag kunde komma fram till det resultatet.

Men enligt din erfarenhet så är blir det alltså ganska lätt rörigt att göra det här i C?
gunnerfeldt
Inlägg: 87
Blev medlem: 29 november 2010, 00:32:55

Skapa ett programvalsystem i C

Inlägg av gunnerfeldt »

Jag hävdar att det går alldeles utmärkt att göra menysystem i C.
State machines är brukligt .. och i mina ögon både enkelt och snyggt.

Det som är bra med state machines tycker jag är att det är lätt att hoppa ur och avbryta inmatningen. Bara resetta alla states.
Samt överskådligt om man vill implementera undo eller konfigurera "offline" parametrar.

Googla state machine och C om du vill se hur det brukar se ut.

Jag har verkligen inget emot Javascript och Python. Men jag lovar att det är minst lika lätt att skriva en callbacktrasslig sörja som är totalt oläslig som att trassla till det med funktionspekare etc.

Beklagar det schizofrena term-språkbruket.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Skapa ett programvalsystem i C

Inlägg av Magnus_K »

Googlar "state machine c" för fulla muggar och får bra resultat!
Får för mig att hittar man bara rätt "tänk" så borde det gå att få till på ett ganska ok sätt.

Tackar för tipsen. Ska försöka få ihop en psuedo-kod nu!
datajompa
Inlägg: 232
Blev medlem: 5 november 2010, 10:35:54

Re: Skapa ett programvalsystem i C

Inlägg av datajompa »

Magnus_K skrev:Vad händer tex här -> state = (state<num_states-1) ? state+1:0; ?
Oj det var ju lite dumt, det där är en oneliner som gör samma som detta:

Kod: Markera allt

state++;
if(state >= num_states) {
   state = 0;
}
Men den viktiga biten var

Kod: Markera allt

void (*functions[])(void) = {&do_prog1, &do_prog2, &do_prog3};
Alltså en array med funktionspekare som kan indexeras så att functions[1] == do_prog2.

Så om man skriver

Kod: Markera allt

(functions[2])();
så körs samma kod som om man skrev

Kod: Markera allt

do_prog3();
Om man sedan vill ha ett mer komplext menysystem så får man utöka denna array till en trädstruktur där varje nod har en funktionspekare och kanske en datapekare.

Det rätta sättet att göra detta i C är att använda ett färdigt bibliotek, för det blir snabbt väldigt komplext om man ska skriva ut all kod för hand.

Jag försökte faktiskt göra detta med en liten 2-nivås hierarkiell meny för att visa, men jag körde fast på pekarkonverteringarna någonstans...
Men enligt din erfarenhet så är blir det alltså ganska lätt rörigt att göra det här i C?
Jag gnäller mest lite på C för att det är så primitivt och omständigt, så alla exempel kommer bli långa. Men det är klart att det går att göra.

Du vill använda datastrukturen Tree i alla fall.
datajompa
Inlägg: 232
Blev medlem: 5 november 2010, 10:35:54

Re: Skapa ett programvalsystem i C

Inlägg av datajompa »

Mitt exempel är för övrigt en state machine, med tillstånden definierade i en tabell.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43176
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Skapa ett programvalsystem i C

Inlägg av sodjan »

Sen så lär man varken köra Javascript eller Python i en liten
processer inbyggd i en pannlampa. Det verkar som att några
har tappat fokus lite här på vad problem faktiskt var.

Jag är inte helt med på vad som är så krångligt. Du måste ju ändå ha
en rutin som känner av knappen regelbundet. Och om den har varit
intryckt 5 sek eller mer så kör du rutinen för "programval" (vilket ju
sannolikt inte kommer att vara "program" i den vanliga betydelsen, utan
bara en variabel/flagga som senare kommer att styra ditt enda program).

Sedan, när din knapp-rutin ser ett vanligt "klick" på knappen så stegar du
bara upp en variabel som sedan tillsammans med "program" variabeln styr
vad som ska hända med pannlampan. Några tabeller (de olika "programmen")
och lite logik för att stega igenom tabellerna vid varje tryck.

Bestäm först vilka olika "modes" som du vill ha, t.ex.:

0: av
1: halvljus
2: helljus
3: SOS (menar du kort-kort-kort-lång-lång-lång-kort-kort-kort ?)
4: Ett kort nöd-blink var 10s.

Sedan gör du några "programtabeller":

0: 0-1-2
1: 0-1-2-3

O.s.v.

Långa trycket roterar mellan de 2 "programmen" och korta tryck
roterar mellan de olika "modes" inom valt program. Kalla det gärna
"state machine" om du behöver ett namn på det...

Fast jag ser inte riktigt nyttan med att ha olika "program" över huvud
taget här, verkar bara onödigt komplicerat den gång man behöver "SOS"
funktionen och man inte råkar ha det "programmet" aktiverat...

"Funktionspekare" och annat lull-lull har sannolikt ingenting i denna applikation att göra.
Skriv svar