C quiz για τους καλοκαιρινούς μήνες

Christos Houtouridis hoo2.ch.pub at gmail.com
Mon Jul 18 13:14:53 EEST 2011


Χαιρετώ τη λίστα!

Ας φανταστούμε τα εξής αρχεία:


/*===============    VS_UI.h   ===============*/
#ifndef __VS_UI_h__
#define __VS_UI_h__

//#include "VS_Core.h"
#include <stdio.h>

#define  UP       ('a')
#define  DOWN     ('b')
#define  ESC      ('c')
#define  LEFT     ('d')
#define  ENTER    ('e')
#define  RIGHT    ('f')

typedef const char* Caption_t;
typedef struct MenuObject* MenuObject_pt;
typedef void (*MenuFunc_pt) (void);

typedef union node
{
   MenuFunc_pt    task;
   MenuObject_pt  menu;
}Node_t;

typedef struct MenuObject
{
   Caption_t      cap;
   Node_t         link;
   int8_t         isMenu;
}MenuObject_t;


static uint8_t UI_retFlag = 0;

extern const MenuObject_t Menu_Main[];
extern const MenuObject_t Menu_Sub[];


void task_a(void);
void task_b(void);
void task_C (void);


/*===  UI Functions   ====*/
void UI_Menu (MenuObject_pt mo);
#ifdef   __INLINE
  __INLINE void UI_MenuBack (void) { UI_retFlag = 1; }
#else
  #define UI_MenuBack()   (UI_retFlag = 1)
#endif

#endif //#ifndef __VS_UI_h__


/*===============    VS_UI.c   ===============*/
#include "VS_UI.h"

/* Menu Diagram */
const MenuObject_t Menu_Main[] =
{
  {"",0,0},
  {">A ",  task_A,      0},
  {"sub",  Menu_Sub,    1},
  {"ESC",  UI_MenuBack, 0},
  {0,0,0}
};
const MenuObject_t Menu_Sub[];[] =
{
  {"",0,0},
  {">B ",  task_B,  0},
  {">C ",  task_C,  0},
  {0,0,0}
};

void task_A (void) { printf ("tza"); return; }
void task_B (void) { printf ("tza"); return; }
void task_C (void) { printf ("tza"); return; }

void UI_Menu (MenuObject_pt mo)
{
  uint8_t i;
  int16_t InChar = 0;

  UI_retFlag = 0;   //RST flag
  if (mo[0].link.task)    mo[0].link.task(); //Optional function call

   for ( printf("\f"), i=1 ; mo[i].link.task ;  )
   {
      printf("\r%s", mo[i].cap); //Print each caption
      InChar = getchar(); //Get user choice

      switch (InChar)
      {
         case UP:   --i; break;   //Navigating
         case DOWN: ++i; break;
         case ESC:                //Actions
         case LEFT:
            UI_retFlag = 0;
            return;
         case RIGHT:
         case ENTER:
            if (mo[i].isMenu)
               UI_Menu( mo[i].link.menu ); //Call menu
            else
               mo[i].link.task();   //Call function
         default:
            break;
      }
      if (!i)
      {
         for ( i=1 ; mo[i].link.task ; ++i);
         --i;
      }
      if (! mo[i].link.task) i = 1;
      if (UI_retFlag) { UI_retFlag = 0; return; }
   }
   return;
}


/*===========       main.c      ============*/
#include "VS_UI.h"

int main (void)
{
  UI_Menu (Menu_Main);     //Stop Monitoring
  while (1)   // Main loop
     ;
}

Να απολογηθώ εδώ ότι έχω ψαλιδίσει "αρκετά" τον κώδικα για να χωρέσει αλλά
ίσως κάποιος να έλεγε ότι έπρεπε να κάνω καλύτερη δουλειά.

Το παραπάνω κομμάτι κώδικα υποτίθεται πως εμφανίζει ένα υποτυπώδες μενού σε
μια μικροσκοπική συσκευή με έναν ARM Cortex-M3.
Η λογική είναι η εξής. Κάνοντας πίνακες με ένα συγκεκριμένο τρόπο έτσι ώστε
να αρχικοποιείται σωστά η δομή MenuObject μπορείς να δημιουργήσεις ότι δομή
θέλεις στο menu σου. Η UI_Menu() δέχεται ένα δείκτη στον πίνακα με
αντικείμενα τύπου MenuObject_t που έκανες και εμφανίζει τις επιλογές που
υπάρχουν εκεί μέσα. O χρήστης(το πλάσμα που χειρίζεται το τελικό προϊόν)
μπορεί να πλοηγηθεί στο τρέχον μενού (τρέχον πίνακας) βλέποντας ένα μήνυμα
στην κάθε τρέχουσα επιλογή. Αν επιλέξει μία (πατήσει ENTER) τότε ελέγχεται
αν το member isMenu είναι true. Αν ναι τότε το τρέχον αντικείμενο είναι
υπομενού και έχουμε recursive call της UI_Menu() με τον νέο πίνακα. Αν το
isMenu είναι false τότε κάνουμε call σαν συνάρτηση μέσω του δείκτη σε void
(*) (void) στο τρέχον task που εμφανιζόταν εκείνη τη στιγμή.

Το παραπάνω κομμάτι κώδικα το έχω χρησημοποιήσει παλιότερα με τον compiler
keil για 8051 και δούλευε μια χαρά (απλά εκεί έπρεπε να δηλώσεις ότι τη
UI_Menu() σαν reentrant).

- Όταν προσπαθώ να το κάνω compile με τον CC_ARM της keil πάλι (πλέον
mdk-arm) με εμπέζει και μου λέει
error:  #144: a value of type "const MenuObject_t *" cannot be used to
initialize an entity of type "MenuFunc_pt"
στην γραμμή της αρχικοποίησης του πίνακα με το Menu_Sub.
- Αν δεν χρησιμοποιήσω υπομενού το compile γίνεται κανονικά και το
εκτελέσιμο "παίζει" κανονικά μόνο με tasks (ένα layer menu)
- Αν αλλάξω τη σειρά των member στο union τότε o compiler παραπονιέται ΚΑΙ
για:
error:  #144: a value of type "void (*)(void)" cannot be used to initialize
an entity of type "MenuObject_pt"

"Υποτίθεται" πως ο compiler είναι ANSI C plus μερικά μπλιμπλίκια και δεν
έχει διαφορές. Απλά παραπάνω μπιχλιμπίδια.

Any ideas?


Φιλικά
Χρήστος
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.hellug.gr/pipermail/linux-greek-users/attachments/20110718/8a7f9e9b/attachment.html>


More information about the Linux-greek-users mailing list