Support for BiDiB

CONFIGX

BiDiB uses configurable ports. Depending on the port type, there are various adjustable parameters. These parameter are passed in a list (either from the node to the host or vice versa). These adjustable parameters are available in protocol version 0.6 or higher. Following is a sample implementation in a node that uses the type-based port model.

MSG_LC_CONFIGX_GET

Within the message parser, after decoding the message type, the next two bytes are interpreted as a port index (BiDiB port type) for the query:


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;

The routine bidib_send_port_configx() extracts the requested port parameters from the configuration memory and builds a response message (type MSG_LC_CONFIGX), exemplified below for a light port:


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;
       .....

If a port has no parameters, so the node responds:


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

To set these parameters the same list is used. Below is an example of the evaluation of the parameters of a light port:


// 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

In order to achieve a very fast reading of the entire configuration of a node, there is a message to query a complete range. By means of MSG_LC_CONFIGX_GETALL the node will be asked to send a whole range of port parameters. The node should use as much as possible of spare bandwitdh.

Inside the type parser the range is checked and the configx responder is activated:


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;

As long as bidib_cfgx2send is smaller than bidib_cfgx2last, the node tries to send a configx-message to the host.


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);
  }