Port MuxR I2C Interface

Most of the features of the Port MuxR in the serial menu are accessible as I2C registers. Commands with a get description denote a read command with expected response and commands with a set description denote a write command without a response. To simplify the firmware, the bytes below are all sent and returned as their ASCII representation (e.g. sending the number 1 should be sent as 0x31). Commands should have at least a 10ms delay between each one to make sure the Port MuxR has processed the previous command (new commands will be ignored if the previous hasn't completed).

The I2C address is configurable through the I2C ADDR header. The binary values of this header can be used to change the I2C slave address. The I2C base slave address starts at 0x50 and you short a pin to add the binary value to the base address (e.g. no shorts = 0x50, 4+1 shorted = 0x55).

The following are the list of write registers available:

a(0x61)[s]      - set all ports to state
                  e.g. a1 - all ports on
p(0x70)[p][c][s]- set port to state
                  e.g. p2a1 - port 2 channel a on
v(0x76)[p][s]   - set vcc, alternative to p[p]v[s]
                  e.g. v21 - port 2 vcc on
s(0x73)         - get port and vcc states. Will store 3 bytes in a read register that must be read in a 
                  separate I2C request command after 20ms.
g(0x67)[g][p][c]- add port to group
                  e.g. g21b - add port 1-b to group 2
G(0x47)[g][p][c]- remove port from group
x(0x78)[g][s]   - set group
                  e.g. x21 - group 2 on
r(0x72)         - reset group mappings
m(0x6d)[m]      - set operation mode
                  e.g. m1 - set break before make
d(0x64)[ms]     - mode switch delay ms<=900 - this is a delay between performing a make/break switching operation. Ms is 
                  as 1 to 3 ascii bytes representing the decimal value. E.g. 123 is sent as 0x31,0x32,0x33.
z(0x7a)         - check firmware version. Returns 5 ascii bytes.
[options]       - s = state (1(0x31)=on/0(0x30)=off) [ascii byte]
                  p = port (1(0x31)-8(0x38)) [ascii byte]
                  c = channel (a(0x61)/b((0x62)/v(0x76)=vcc) [ascii byte]
                  g = group number (1(0x31)-9(0x39)) [ascii byte]
                  m = mode (0(0x30) = manual toggle,
                            1(0x31) = break-before-make,
                            2(0x32) = make-before-break) [ascii byte]

The latest return bytes for some commands above will be stored in a read register. To retrieve them, perform an I2C read command and the Port MuxR will return the number of bytes belonging to the latest command send that expects return values (see example below).

To get you started, here are some c helper definitions:

/* Function Registers */
#define SET_ALL_PORTS  0x61
#define SET_PORT       0x70
#define SET_VCC        0x76
#define GET_PORTS      0x73
#define ADD_PORT_GROUP 0x67
#define DEL_PORT_GROUP 0x47
#define SET_GROUP      0x78
#define RESET_GROUPS   0x72
#define CHECK_FIRM     0x7a
#define MODE_DELAY     0x64
#define SET_MODE       0x6d

/* State Bytes */
#define STATE_ON       0x31
#define STATE_OFF      0x30

/* Channel Bytes */
#define CHANNEL_A      0x61
#define CHANNEL_B      0x62
#define CHANNEL_VCC    0x76

/* Mode Bytes */
#define MANUAL_TOG     0x30
#define BREAK_B4_MAKE  0x31
#define MAKE_B4_BREAK  0x32

#define ADDRESS 0x50

/* Port Byte Helper */
uint8_t PORT(uint8_t port_num)
{
  if (port_num > 0 && port_num <= 8) return port_num + 0x30;
}

/* Group Byte Helper */
uint8_t GROUP(uint8_t group_num)
{
  if (group_num > 0 && group_num <= 9) return group_num + 0x30;
}

And here is a quick Arduino example to cycle through and toggle the VCC ports and retrieve port status using the above helper definitions (default address of 0x50):

  for (int i = 1; i <= 8; i++)
  {
    /* Set VCC On */
    Wire.beginTransmission(ADDRESS);
    Wire.write(SET_PORT);
    Wire.write(PORT(i));
    Wire.write(CHANNEL_VCC);
    Wire.write(STATE_ON);
    Wire.endTransmission();
    
    delay(10); //Minimum delay between I2C transactions    

    /* Get port status */
    Wire.beginTransmission(ADDRESS);
    Wire.write(GET_PORTS);
    Wire.endTransmission();
    delay(20); //Wait for previous command to finish
    Wire.requestFrom(ADDRESS, 3);
    Serial.print(Wire.read());
    Serial.print(Wire.read());
    Serial.println(Wire.read());
    

    delay(200);
    
    /* Set VCC Off */
    Wire.beginTransmission(ADDRESS);
    Wire.write(SET_PORT);
    Wire.write(PORT(i));
    Wire.write(CHANNEL_VCC);
    Wire.write(STATE_OFF);
    Wire.endTransmission();

    delay(200);
  }