Support für BiDiB

CONFIGX

BiDiB kennt parametrierbare Ports. Abhängig von Porttyp gibt es verschiedene Einstellparameter, ab Protokollversion 0.6 werden diese in einer Liste übergeben. Nachfolgend ist eine Beispielimplementierung in einem Knoten beschrieben, der das typorientierte Portmodell nutzt.

MSG_LC_CONFIGX_GET

Innerhalb des Nachrichtenparser werden für die Abfrage die beiden folgenden Bytes als Portindex eines BiDiB-Porttypes interpretiert:


case MSG_LC_CONFIGX_GET:
    // *(msg_type+1) = Typ
    // *(msg_type+2) = Port
    bidib_send_port_configx((t_bidib_port_idx*) (msg_type+1));
    break;

Die Routine bidib_send_port_configx() entnimmt zum angefragten Port die Parameter aus dem Konfigurationsspeicher und baut daraus eine Antwortnachricht vom Typ MSG_LC_CONFIGX, nachfolgend exemplarisch für einen Lichtport dargestellt:


static void bidib_send_port_configx(t_bidib_port_idx* port)
  {
    t_node_message18 message;
    switch(port->type)
      {
        case BIDIB_PORTTYPE_SWITCH:           // standard port
            ....
            break;
        case BIDIB_PORTTYPE_LIGHT:            // light port
            if (port->portnum >= NUM_OF_LIGHTS)
             {
               bidib_send_port_na(port);
               return; // out of range
             }
           else
             {
               uint8_t i = 0;
               message.header.node_addr = 0;
               message.header.index = get_tx_num();
               message.header.msg_type = MSG_LC_CONFIGX;
               message.data[i++] = port->type;
               message.data[i++] = port->portnum;
               message.data[i++] = BIDIB_PCFG_DIMM_DOWN_8_8;                       // Dimmgeschwindigkeit down
               message.data[i++] = LOW8(CVram.light_cfg[port->portnum].dimm_off);
               message.data[i++] = HIGH8(CVram.light_cfg[port->portnum].dimm_off);
               message.data[i++] = BIDIB_PCFG_DIMM_UP_8_8;
               message.data[i++] = LOW8(CVram.light_cfg[port->portnum].dimm_on);
               message.data[i++] = HIGH8(CVram.light_cfg[port->portnum].dimm_on);
               message.data[i++] = BIDIB_PCFG_LEVEL_PORT_OFF;
               message.data[i++] = CVram.light_cfg[port->portnum].brightness_off;
               message.data[i++] = BIDIB_PCFG_LEVEL_PORT_ON;
               message.data[i++] = CVram.light_cfg[port->portnum].brightness_on;
               message.header.size = sizeof(t_node_message_header)-1 +i;

               send_bidib_message((unsigned char *)&message);
               return;
             }
            break;
       .....

Sollte ein Port keine Parameter haben, so antwortet der Knoten:


static void bidib_send_configx_error(t_bidib_port_idx* port)
  {
    t_node_message10 message;
    message.header.node_addr = 0;
    message.header.index = get_tx_num();
    message.header.msg_type = MSG_LC_CONFIGX;
    message.data[0] = port->type;
    message.data[1] = port->portnum;
    message.data[2] = BIDIB_PCFG_NONE;            // Error / None
    message.data[3] = 0;
    message.header.size = 3+4;                    // 3= sizeof(t_node_message_header)-1
    send_bidib_message((unsigned char *)&message);
  }

MSG_LC_CONFIGX_SET

Zum setzen von Parameter wird die gleiche Liste verwendet, nachfolgend ein Beispiel für das Auswerten der Parameter eines Lichtports:


// Parameter: msg: points to a list of: type, portnum, [P_ENUM, P_VALUE]
//            length: number of bytes in list
// return: 0: port does not exist
//         1…x: wrong P_ENUM
//         255 if success
unsigned char configx_light(unsigned char *msg, signed char length)
  {
    msg++;                                  // skip type
    unsigned char myport = *msg++;          // get portnum
    if (myport >= NUM_OF_LIGHTS) return(0); // out of range

    length -= 2;
    while (length  > 0)
      {
        switch(*msg++)
          {
            default:
                return(*--msg);         // return wrong Enum
            case BIDIB_PCFG_LEVEL_PORT_OFF:
                save_cv(offsetof(t_cv_record, light_cfg[myport].brightness_off), *msg);
                msg++;
                length -= 2;
                break;
            case BIDIB_PCFG_LEVEL_PORT_ON:
                save_cv(offsetof(t_cv_record, light_cfg[myport].brightness_on), *msg);
                msg++;
                length -= 2;
                break;
            case BIDIB_PCFG_DIMM_UP_8_8:
                save_cv_int(offsetof(t_cv_record, light_cfg[myport].dimm_on), *(uint16_t *)msg);
                msg++;
                msg++;
                length -= 3;
                break;
            case BIDIB_PCFG_DIMM_DOWN_8_8:
                save_cv_int(offsetof(t_cv_record, light_cfg[myport].dimm_off), *(uint16_t *)msg);
                msg++;
                msg++;
                length -= 3;
                break;
          }
     }
    return(255);
  }

MSG_LC_CONFIGX_GET_ALL

Um ein sehr schnelles Einlesen der gesamten Konfiguration eines Knotens zu erreichen, gibt es eine Sammelabfrage. Mittels MSG_LC_CONFIGX_GETALL wird ein ganzer Bereich abgefragt, der Knoten sendet die Antwort so, dass er die ihm zur Verfügung stehende Bandbreite ausnutzt, aber trotzdem noch normal ansprechbar bleibt.

Innerhalb des Nachrichtenparser wird für diese Abfrage der Range kontrolliert und eine entsprechende Antwortroutine 'scharf' geschaltet:


static t_bidib_port_idx bidib_cfgx2send;          // start / counter for configx_get_all
static t_bidib_port_idx bidib_cfgx2last;          // end for configx_get_all
  case MSG_LC_CONFIGX_GET_ALL:
    if (rest == 1)                                // no para, get all
      {
        bidib_cfgx2send.type = 0;
        bidib_cfgx2send.portnum = 0;
        bidib_cfgx2last.type = 0xFF;
        bidib_cfgx2last.portnum = 0xFF;
      }
    else
      {
        bidib_cfgx2send.type = *(msg_type+1);
        bidib_cfgx2send.portnum = *(msg_type+2);
        bidib_cfgx2last.type = *(msg_type+3);
        bidib_cfgx2last.portnum = *(msg_type+4);
      }
    bidib_send_configx_all();                   // send a first answer
    break;

Solange nun bidib_cfgx2send kleiner als bidib_cfgx2last ist, wird versucht, eine CONFIGX-Nachricht Richtung Host abzuschicken:


    if (is_bidib_spontan_enabled())
      {
        if (bidib_send_configx_all()) return(0);    // come back asap
      }

// return: 1 if something is still to be transmitted, 0: all done
unsigned char bidib_send_configx_all(void)
  {
    if (port_type_in_range())
      {
        if (bidib_tx_fifo_okay())                // check if there is enough space in tx-fifo left
          {
            if (port_exits(&bidib_cfgx2send)) bidib_send_port_configx(&bidib_cfgx2send);
            increment_port_idx(&bidib_cfgx2send);
            if (port_type_in_range()) return(1);
            return(0);
          }
        return(1);
      }
    return(0);
  }