Support für BiDiB

Was sind Features?

Zum Verwalten heterogener Strukturen und Eigenschaften verwendet BiDiB ein feature-System. Features sind Eigenschaften des jeweiligen Knotens, welche abgefragt und verändert werden können. Hierzu sind für eine bestimmte Klasse eines Knotens auch die möglichen Features einheitlich festgelegt.

Feature-Abfrage

Einzelne, bestimmte Features werden wie folgt abgefragt:

Host Knoten
MSG_FEATURE_GET (3) 
  MSG_FEATURE (3, value)

Sollte der Knoten das Feature nicht kennen, dann ergibt sich folgender Dialog:

Host Knoten
MSG_FEATURE_GET (3) 
  MSG_FEATURE_NA (3)

Alle Features abfragen

Wenn man alle Features eines Knotens abfragen will, geht man wie folgt vor:

Host Knoten
MSG_FEATURE_GETALL  
  MSG_FEATURE_COUNT
MSG_FEATURE_GETNEXT 
  MSG_FEATURE (3, value)
MSG_FEATURE_GETNEXT 
  MSG_FEATURE (5, value)
MSG_FEATURE_GETNEXT 
  MSG_FEATURE (7, value)
MSG_FEATURE_GETNEXT 
  MSG_FEATURE_NA (255)

Der Host beginnt mit einer Abfrage der Anzahl. Dadurch wird im Knoten der Abfragezähler zurückgesetzt. Mit einer Reihe von MSG_FEATURE_GETNEXT werden dann die Features abgeholt (hier im Beispiel 3,5, und 7), bis der Knoten mit einer MSG_FEATURE_NA (255) anzeigt, dass alles übertragen wurde.

Wichtig: Die Nachrichten müssen nicht so verzahnt hin- und hergeschickt werden, es ist zulässig (und aus Performancegründen wünschenswert), dass mehrere Nachrichten gebündelt werden, also z. B. ein MSG_FEATURE_GETALL und gleich noch mehrere MSG_FEATURE_GETNEXT mit dazu. Dann wird man in Gegenrichtung auch die entsprechende Zahl an Antworten bekommen. Hierbei ist zu beachten, dass ein Nachrichtenblock den jeweiligen Antwortkanal nicht überfordert, weil sonst der Knoten gezwungen ist, Nachrichten unbeantwortet zu lassen. (siehe MSG_STALL).

Wenn man nach den verfügbaren Features weitere MSG_FEATURE_GETNEXT an den Knoten sendet, so werden diese alle mit MSG_FEATURE_NA(255) beantwortet.

Feature im Knoten

Dieses Beispiel zeigt, wie man solche Features leicht implementieren kann. Für das Feature-Systems wird hier zuerst eine Struktur deklariert, mit der man dann die Features angeben kann:


typedef struct
{
  unsigned char num;              // feature index (aus bidib_messages.h)
  unsigned char value;            // der aktuelle Wert
  unsigned char min;              // unsere Grenzen
  unsigned char max;
  void (*notify_function)(void);  // Diese Funktion wird gerufen, wenn das Feature beschrieben wird
} t_feature;

Alle features des Knotens werden dann in einer Tabelle angelegt:


t_feature my_feature[] =
{   // num                        value min max notify_function
  { FEATURE_BM_SIZE,              8,    0,  8,  NULL},
  { FEATURE_BM_ON,                0,    0,  1,  NULL},
  { FEATURE_BM_SECACK_AVAILABLE,  0,    0,  0,  NULL},
  { FEATURE_BM_SECACK_ON,         0,    0,  0,  NULL},
};

Als weitere Zutat werden noch Funktionen zum Absenden der Antworten benötigt:


static void bidib_send_feature(unsigned char fnum, unsigned char f_value)
{
  t_node_message2 message;
  message.header.node_addr = 0;
  bidib_tx0_msg_num++;
  if (bidib_tx0_msg_num == 0) bidib_tx0_msg_num++;
  message.header.index = bidib_tx0_msg_num;
  message.header.msg_type = MSG_FEATURE;
  message.data[0] = fnum;
  message.data[1] = f_value;
  message.header.size = 3+2;
  send_bidib_message((unsigned char *)&message);
}

static void bidib_send_feature_na(unsigned char fnum)
{
  bidib_send_onepara_msg(MSG_FEATURE_NA, fnum);
}

static void bidib_send_feature_count(unsigned char fcount)
{
  bidib_send_onepara_msg(MSG_FEATURE_COUNT, fcount);
}

Jetzt kann man eine Funktion bauen, welche angefragte Features in der Tabelle sucht: wenn das Feature vorhanden ist, dann wird es zurückmeldet. Beim Setzen eines Features wird auf die Grenzen (min, max) verglichen und fallweise die bei Veränderungen die notify_function aufgerufen, damit die Veränderung auch wirkt.


static void get_feature(unsigned char fnum)
{
  unsigned char i;
  for (i=0; i<sizeof(my_feature)/sizeof(my_feature[0]); i++)
    {
      if (fnum == feature0[i].num)
        {
          bidib_send_feature(fnum, my_feature[i].value);    // feature zuruecksenden
          return;
        }
    }
  bidib_send_feature_na(fnum);                            // kein Feature gefunden
}

static void bidib_send_next_feature(void)
{
  if (bidib_feature2send < sizeof(feature)/sizeof(feature[0]))
    {
      bidib_send_feature(feature[bidib_feature2send].num, feature[bidib_feature2send].value);
      bidib_feature2send++;
    }
  else
    {
      bidib_send_feature_na(255);                           // alle gesendet
    }
}

static void set_feature(unsigned char fnum, unsigned char f_value)
{
  unsigned char i;
  void (*fp)(void);                               // declare pointer to function

  for (i=0; i<sizeof(my_feature)/sizeof(my_feature[0]); i++)
    {
      if (fnum == feature0[i].num)
        {
          if (f_value < my_feature[i].min) f_value = my_feature[i].min;
          if (f_value > my_feature[i].max) f_value = my_feature[i].max;
          if (my_feature[i].value != f_value)
            {
              my_feature[i].value = f_value;
              fp = my_feature[i].notify_function;
              if (fp) (*fp)();                    // call this function, if not NULL
            }
          bidib_send_feature(fnum, my_feature[i].value);    // feature zuruecksenden
          return;
        }
    }
  bidib_send_feature_na(fnum);                            // kein Feature gefunden
}

Weitere Features lassen sich damit einfach durch Erweitern der Tabelle hinzufügen.