Controlling the DP0POL switching matrix with daisy chained MAX4820

Aus DL8RDS Wiki
Wechseln zu: Navigation, Suche

1 Background

DP0POL / DP0GVN is an amateur radio station on Neumayer3 station in Antarctica, hosting a unique WSPR station. As I have described in my article Red Pitaya Based WSPR Beacon for Antarctica DP0GVN, how the Red Pitaya platform of the first version was built, we now envisage another version 2:

It will be a 19" rack housing two (or possiby even four) Red Pitaya platforms. The reason is that the standard WSPR / FT8 software is only capale of processing EIGHT bands. However, we would want to monitor all shortwave bands, from long wave over the uneven bands up to 30 MHz.

Besides that, Antarctica is a rather tough place: The Antarctic winter brings us permanent darkness with temperatures possibly down to -50°C and since the antenna field is about two kilometers away from the main station, the SDR platforms will be literally out of reach for human beings. It is like a station on another planet. I guess, living conditions on planet Mars are more comfortable than in the Antarctic winter.

It will be simply impossible to diagnose antenna faults, and in case of a defective Red Pitaya we want to be able to simply switch one Red Pitaya from one antenna to another.

This all will be feasible through a switching matrix built by Helmut Berka DL2MAJ.

The matrix therefore employs a special chip: The MAX4820.

Maybe you have read my article about power switching with bistable latching relays: 8 Port Passive PoE Injector, Managed and Fused. This project is using a combination of I2C controlled PCF7485 16bit serial extensions to steer 8 relays. However, the drive power is too weak to control the relays directly. So we still require a darlington relay driver chip ULN2803 to drive the 5V relays there.

In the Antarctica project the number of relays is a little bigger: The switching matrix holds a total of 28 relays and thus leaves little space for I2C and driver chips. Besides that, I2c has the major disadvantage that each I2C chip normally only has three jumpers fur a selectable bus address space of 2³ and thus a total of 8 chips of the same type on the same bus. Even though it could be enough data lines with 16 bit * 8 ICs, the effort is still quite complex.

Helmut chose another approach: The MAX4820 can be daisy chained and thus requires some very different approach, but you can set many, many more relays with it. In fact, you're not really limited at all, except through a rather complex digital handling technique.

According to the datasheet, the MAX4820 is compatible with the Microwire and/or SPI protocol. I found this statement still rather tricky, because pure SPI does not support the RESET data line, but instead you must take care of a reset signal yourself.

As a consequence, I decided against the implementation directly on a Raspberry Pi with my GPIOs, also given that the timing of the according signals was a little tricky. Instead, I chose an Arduino as the immediate controller platform, which now offers a USB standard interface and thus can be employed together with any arbitrary main computer.

This approach was also a response to the fact that there is no document on the web whatsoever, employing the keywords "MAX4820" together wirh "Raspberry" and "Python".

For this reason the Arduino drives my MAX4820 chain with all its control data lines and the Raspberry hosts the Python program that generates the integers over the serial connection that will again set the MAC ICs accordingly.

2 MAX4820

Here is the datasheet, first of all:

https://datasheets.maximintegrated.com/en/ds/MAX4820-MAX4821.pdf

Read it carefully!

The MAX4820 needs four main data lines:

  • Serial Data (DIN). Sometimes also named "SDA".
  • Serial Clock (SCL).
  • Chip Select (CS): Drive CS low to select the device. When CS is low, data at DIN is clocked into the 8-bit shift register on SCLK’s rising edge. Drive CS from low to high to latch the data to the registers and activate the appropriate relays.
  • Reset (RESET): Reset Input. Drive RESET low to clear all latches and registers (all outputs are turned off). RESET overrides all other inputs. If RESET and SET are pulledlow at the same time, then RESET takes precedence

The DOUT connects to the DIN of the next IC of the chain. Note that the prior chip eats up the first eight data bits and leaves nothing to its successor but what comes after those eight bits:

  • Data Out (DOUT): Serial-Data Output. DOUT is the output of the 8-bit shift register. This output can be used to daisy chain multiple MAX4820s. The data at DOUT appears synchronous to SCLK’s falling edge.

Do not confuse the usage of SCL and SDA with I2C even though the naming is identical, this is no I2C at all. The MAX does not employ any addresses. There is really NO addressing whatsoever.

Here is how the interface is described in the datasheet:

The serial interface consists of an 8-bit shift register
and parallel latch controlled by SCLK and CS. The
input to the shift register is an 8-bit word. Each data bit
controls one of the eight outputs, with the most signifi-
cant bit (D7) corresponding to OUT8 and the least significant 
bit (D0) corresponding to OUT1 (see Table 1).
When CS is low (device is selected), data at DIN  is
clocked into the shift register synchronously with SCLK’s rising 
edge. Driving CS from low to high latches the data in the shift 
register to the parallel latch. 
DOUT is the output of the shift register. Data appears
on DOUT synchronously with SCLK’s falling edge and
is identical to the data at DIN delayed by eight clock
cycles. When shifting the input data, D7 is the first bit in
and out of the shift register. While CS is low, the switches always 
remain in their previous state. Drive CS high after 8 bits of 
data have been shifted in to update the output state and  
inhibit further data from entering the shift register. When  
CS is  high, transitions at DIN and SCLK have no effect  
on the output, and the first input bit (D7) is present at DOUT.
If the number of data bits entered while CS is low is
greater or less than 8, the shift register contains only
the last 8 data bits, regardless of when they were
entered.

Here is how I implemented the interface:

  • The standard period is 50 microseconds. Every time span will be a multiple of 50 microseconds.
  • It makes sense to start with the RESET line going LO in order to set all the latches to ZERO disregarding their previous state. The RESET line can go back to HI after 5 times the standard timespan.
  • Then we will start with Chip Select. We pull it to LO in order to enable programming. CS stays LO as long as there is programing activity on the DIN line.
  • Then we start a loop:
    • We write the due data bit, HI or LO as requested.
    • After writing, we produce a rising flank and a falling flank. Since the data bit will be shifted into the according register with the rising flank, we must ensure to have the data bit set slightly before the clock comes around.
  • After the end of the bits, there are no more clock cycles either.
  • We rise CS to HI in order to activate the latching. This is the moment when the relays will be switched.
  • Then we spend a long time of 50 Milliseconds in order to grant sufficient time to the relays to get the switching done.
  • Finally we do another round of RESET for 5*standard timespans to make sure every bit is cleared again.

This will leave our relays in the situation that the coils still operate under power. Remember that we want to switch RF signals, so operating an inductive element in immediate proximity of a RF signal line is no good idea at all, we will need to remove power from all the coils.

The procedure is exactly the same as above, yet without any data bits. The Data In line can be left to LO and the rest of the procedure is carried out just alike.

Given that OUT1 and OUT2 are antagonists, as OUT3/OUT4, OUT5/OUT6 and OUT7/OUT8, it should be forbidden to set them at the same time. I will not implement any safety procedures in the Arduino code, because I think that the control interface should so clever as to do that at the other side. I follow the idea to keep the static part of the implementation as minimal as possible in order to allow as few incorrectible faults as possible.

3 Measurement

I am proud owner of a R&S HAMEG HMO-3024 mixed signals oscilloscope.

This device is capable of storing a vast number of samples, across all digital channels.

I was using the logic analysis part together with the manual trigger subsystem, where the trigger voltage was set to 3,3V and the logic trigger on the according channels that would start ahead, notably the RESET signal going LO.

4 Arduino Code

Here is my implementation:


#define DEBUG 0

#define MAX_SCLK 4      // SCLK, Anschlusspin 1
#define MAX_RESET 5     // RESET, Anschlusspin 3
#define MAX_CS 6        // CS, Anschlusspin 4
#define MAX_SDA 7       // SDA, Anschlusspin 5


#define IN_MAX 50       // maximale Einleselaenge PLUS CR oder LF

int Wartezeit = 50;     // Verzoegerung bei Datenausgabe, hier 50µs

byte i = 0;             // Laufvariable
byte j = 0;             // Laufvariable
byte x;                 // Laufvariable
int inByte = 0;         // incoming serial byte
int inDaten[IN_MAX];    // Eingehende Daten
bool inBool[IN_MAX*8];  // Eingehende Daten
int datenCounter = 0;   // Datenzaehler
const int max_len = IN_MAX;

void setup() {
  pinMode(MAX_RESET, OUTPUT);
  pinMode(MAX_CS, OUTPUT);
  pinMode(MAX_SDA, OUTPUT);
  pinMode(MAX_SCLK, OUTPUT);

  digitalWrite(MAX_RESET, LOW);   // alle Ausgaenge zuruecksetzen
  delayMicroseconds (Wartezeit);
  digitalWrite(MAX_CS, HIGH);     // keinen Baustein selektieren
  delayMicroseconds (Wartezeit);
  digitalWrite(MAX_SDA, LOW);     // SDA=Din bei MAX4820 auf low setzen
  delayMicroseconds (Wartezeit);;
  digitalWrite(MAX_SCLK, LOW);    // SCLK bei MAX4820 auf low setzen
  delayMicroseconds (Wartezeit);
  digitalWrite(MAX_RESET, HIGH);  // Bausteine freigeben fuer Programmierung
  delayMicroseconds (Wartezeit);

  // start serial port at 9600 bps:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  delay(100); // 100ms warten
  Serial.print("OK >> ");
  
}

void SignalAusgabe(bool inBool[IN_MAX * 8], int datenCounter) {

  Serial.print("Signalausgabe, Zeichen ohne CR|LF >");
  Serial.println(datenCounter - 1);

  // /RESET setzen
  /*
  RESET: Reset Input. Drive RESET low to clear all latches and registers
  (all outputs are turned off). RESET overrides all other inputs. If 
  RESET and SET are pulled low at the same time, then RESET takes
  precedence.
  */
  digitalWrite(MAX_RESET, LOW); // alle Ausgaenge deaktivieren (open Drain, Impulsrelais !!! )
  delayMicroseconds(5* Wartezeit); 
  digitalWrite(MAX_RESET, HIGH);  // Bausteine freigeben fuer Programmierung

  // /CS aktivieren
  /*
  CS: Drive CS low to select the device. When CS is low, data at DIN is
  clocked into the 8-bit shift register on SCLK’s rising edge. Drive CS
  from low to high to latch the data to the registers and activate the
  appropriate relays.
  */
  digitalWrite(MAX_CS, LOW);
  delayMicroseconds (Wartezeit);
  
  for (int l = 0; l < (datenCounter -1 ) * 8; l++) {
    
    if (inBool[l] == 1) {
      digitalWrite(MAX_SDA, HIGH);
      
    } else {
      digitalWrite(MAX_SDA, LOW);
      
    }

    // Takterzeugung
    digitalWrite(MAX_SCLK, HIGH); // Taktimpuls wird erzeugt, Daten werden uebernommen
    delayMicroseconds(Wartezeit);   


    digitalWrite(MAX_SCLK, LOW); // Taktimpuls wird zurueckgenommen
    delayMicroseconds(Wartezeit);   
         
  }
  digitalWrite(MAX_SDA, LOW);

  // /CS deaktivieren = Daten auf Ausgaenge schalten
  digitalWrite(MAX_CS, HIGH);

#if DEBUG==1
  delayMicroseconds(10* Wartezeit);  // schnell, fuers Oszilloskop
#else
  delay(50); // 50ms warten
#endif

  // Sicherheitshalber danach auch noch mal RESET setzen
  /*
  RESET: Reset Input. Drive RESET low to clear all latches and registers
  (all outputs are turned off). RESET overrides all other inputs. If 
  RESET and SET are pulled low at the same time, then RESET takes
  precedence.
  */
  digitalWrite(MAX_RESET, LOW); // alle Ausgaenge deaktivieren (open Drain, Impulsrelais !!! )
  delayMicroseconds(5* Wartezeit);  // nur alternativ zum Debugging
  digitalWrite(MAX_RESET, HIGH);  // Bausteine freigeben fuer Programmierung

  // Und jetzt kommt die Zurücksetzung der ganzen Relais

    // /CS aktivieren
  /*
  CS: Drive CS low to select the device. When CS is low, data at DIN is
  clocked into the 8-bit shift register on SCLK’s rising edge. Drive CS
  from low to high to latch the data to the registers and activate the
  appropriate relays.
  */
  digitalWrite(MAX_CS, LOW);
  delayMicroseconds (Wartezeit);

  // Wir wollen alle Kanaele auf NULL Schalten
  digitalWrite(MAX_SDA, LOW);
  
  for (int l = 0; l < (datenCounter -1 ) * 8; l++) {
    
    // Takterzeugung
    digitalWrite(MAX_SCLK, HIGH); // Taktimpuls wird erzeugt, Daten werden uebernommen
    delayMicroseconds(Wartezeit);   


    digitalWrite(MAX_SCLK, LOW); // Taktimpuls wird zurueckgenommen
    delayMicroseconds(Wartezeit);   
         
  }
  digitalWrite(MAX_SDA, LOW);

  // /CS deaktivieren = Daten auf Ausgaenge schalten
  digitalWrite(MAX_CS, HIGH);

#if DEBUG==1
  delayMicroseconds(10* Wartezeit);  // schnell, fuers Oszilloskop
#else
  delay(50); // 50ms warten
#endif

  // Sicherheitshalber danach auch noch mal RESET setzen
  /*
  RESET: Reset Input. Drive RESET low to clear all latches and registers
  (all outputs are turned off). RESET overrides all other inputs. If 
  RESET and SET are pulled low at the same time, then RESET takes
  precedence.
  */
  digitalWrite(MAX_RESET, LOW); // alle Ausgaenge deaktivieren (open Drain, Impulsrelais !!! )
  delayMicroseconds(5* Wartezeit);  // nur alternativ zum Debugging
  digitalWrite(MAX_RESET, HIGH);  // Bausteine freigeben fuer Programmierung
  
}



void loop() {
  // if we get a valid byte, read analog ins:
  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read();
    
    Serial.print("datenCounter >");
    Serial.println(datenCounter);

    if (datenCounter < max_len) {
      Serial.print("Zeichen akzeptiert BIN>");
      Serial.print(inByte, BIN);
      Serial.print("< DEC>");
      Serial.print(inByte, DEC);
      char o = inByte;
      Serial.print("< CHA>");
      Serial.println(o);
      inDaten[datenCounter] = inByte;
      datenCounter++;
    } else {
      Serial.println("datenCounter OVERRUN");
      datenCounter = 0;
      for (int i = 0; i < max_len; i++) {
        inDaten[i] = 0;
      }
    }

    if ((inByte == 10) || (inByte == 13)) {
      // Abarbeitung
      for (int n = 0; n < datenCounter; n++) {
        for (int i = 0; i <= 7; i++) {
          inBool[n * 8 + i] = bitRead(inDaten[n], i);
        }
      }

      Serial.print("OUT>>>>>");
      for (int n = 0; n < datenCounter - 1; n++) {
        for (int i = 0; i <= 7; i++) {
          Serial.print(bitRead(inDaten[n], i));
        }
        if (n < datenCounter - 2)
          Serial.print(".");
      }
      Serial.print("<<<<<OUT");
      Serial.println();

      SignalAusgabe(inBool, datenCounter);

      // nach Verarbeitung setze alles auf NULL
      datenCounter = 0;
      for (int i = 0; i < IN_MAX; i++) {
        inDaten[i] = 0;
        for (int n = 0; n <= 7; n++) {
          inBool[i * 8 + n] = 0;
        }
      }

      Serial.print("OK >> ");

    }

  }
}




5 TEST

Here is the ASCII table, together with the binary representations:

2018-10-27-ascii conversion chart.gif

Note that we are using the reverse presentation of the binary bitstream.

As a test, I was using the input characters '*' and 'U', being nearly binary antagonists, while still being characters on my keyboard.

Here is the dialog of the serial monitor:

5.1 First Test

datenCounter >0
Zeichen akzeptiert BIN>101010< DEC>42< CHA>*
datenCounter >1
Zeichen akzeptiert BIN>101010< DEC>42< CHA>*
datenCounter >2
Zeichen akzeptiert BIN>1101< DEC>13< CHA>
OUT>>>>>01010100.01010100<<<<<OUT
Signalausgabe, Zeichen ohne CR|LF >2

resulting in the following logic diagram:

2018-10-10-scrn1.png

5.2 Second Test

datenCounter >0
Zeichen akzeptiert BIN>1010101< DEC>85< CHA>U
datenCounter >1
Zeichen akzeptiert BIN>1010101< DEC>85< CHA>U
datenCounter >2
Zeichen akzeptiert BIN>1101< DEC>13< CHA>
OUT>>>>>10101010.10101010<<<<<OUT
Signalausgabe, Zeichen ohne CR|LF >2

resulting in the following logic diagram:

2018-10-10-scrn2.png

6 The Python Program

On the computer side, there is a python program that generates the character stream to control the relays on the switching matrix.

Here is the source code of the python program.

6.1 The Code

#!/usr/bin/python

# Control for the switching matrix of the DB0GVN beacon

# (c) 2017,2018 Markus Heller M.A. DL8RDS <heller@relix.de>

import sys
import serial
import os
import time

ic5 = ['REL1-SHORT50','REL2-SHORT50','REL3-SHORT50','REL4-SHORT50']
ic4 = ['REL4-RP2B','REL4-RP2A','REL4-RP1B','REL4-RP1A']
ic3 = ['REL3-RP2B','REL3-RP2A','REL3-RP1B','REL3-RP1A']
ic2 = ['REL2-RP2B','REL2-RP2A','REL2-RP1B','REL2-RP1A']
ic1 = ['REL1-RP2B','REL1-RP2A','REL1-RP1B','REL1-RP1A']
ic7 = ['REL_GND-SHORT50','REL_50-SHORT50','REL_VNA-TXB1','REL_VNA-TXA1']
ic6 = ['REL_RP2A-MWSP2','REL_RP1A-MWSP2','','']
allRelays = ic5 + ic4 + ic3 + ic2 + ic1 + ic7 + ic6

class relais:

    '''
    Diese Klasse bildet ein Relais ab.
    Sie speichert den Schaltzustand und ermoeglicht das Auslesen.
    '''

    def __init__(self, name):
        self.name = name
        self.state = False

    def setOn(self):
        self.state = True

    def setOff(self):
        self.state = False

    def getState(self):
        return self.state

    def getName(self):
        return self.name

class max4820:

    '''
    Diese Klasse bildet einen MAX4820 mit seinen zugeordneten Relais ab.
    Fokus ist auf dem Setzen des jeweiligen Relaiszustandes.
    '''

    def __init__(self, name):
        self.name = name
        self.relaisList = []
        self.relaisIndex = {}

    def getName(self):
        return self.name

    def addRelaisList(self, rellist):
        for name in rellist:
            r = relais(name)
            self.relaisList.append(r)
            self.relaisIndex[name] = r

    def getStateByName(self, name):
        if self.relaisIndex.has_key(name):
            return self.relaisIndex[name].getState()

    def setOnByName(self, name):
        if self.relaisIndex.has_key(name):
            return self.relaisIndex[name].setOn()

    def setOffByName(self, name):
        if self.relaisIndex.has_key(name):
            return self.relaisIndex[name].setOff()

    def getStates(self):
        return [n.getState() for n in self.relaisList]

    def twoLine(self, state):
        if state:
            return '10'
        else:
            return '01'

    def getBinStates(self):
        return str(''.join([self.twoLine(n.getState()) for n in self.relaisList]))

    def getIntState(self):
        return str(int(''.join([self.twoLine(n.getState()) for n in self.relaisList]), 2))

class matrix:

    '''
    Diese Klasse bildet die Matrixplatine ab. 
    Fokus ist auf der Reihenfolge der ICs und die Reihenfolge der Relais
    '''

    def __init__(self):
        self.icList = []
        self.relayDict = {}
        self.icDict = {}

        self.allRelays = allRelays

        self.addMAX4820('ic5', ic5)
        self.addMAX4820('ic4', ic4)
        self.addMAX4820('ic3', ic3)
        self.addMAX4820('ic2', ic2)
        self.addMAX4820('ic1', ic1)
        self.addMAX4820('ic7', ic7)
        self.addMAX4820('ic6', ic6)

    def relayExists(self, name):
        if name in self.allRelays:
            return True
        return False

    def setRel(self, relName, state):
        self.relayDict[relName] = state

    def addMAX4820(self, name, relList):
        self.icList.append(name)
        m = max4820(name)
        m.addRelaisList(relList)
        self.icDict[name] = m
        for r in relList:
            self.relayDict[r] = m

    def setOnByRelName(self, name):
        self.relayDict[name].setOnByName(name)

    def setOffByRelName(self, name):
        self.relayDict[name].setOffByName(name)

    def getBitstring(self):
        # zur Diagnostik auf Bit-Ebene
        return str(''.join([self.icDict[x].getBinStates() + "." for x in self.icList])[:-1])

    def getIntegerArray(self):
        # Ausgabe des Integer-Arrays zur Uebergabe an den Arduino
        return ' '.join([self.icDict[x].getIntState()  for x in self.icList])

    def getCharArray(self):
        return ''.join([chr(int(self.icDict[x].getIntState()))  for x in self.icList])

class matrixlogik:

    '''
    Diese Klasse bildet die Anwendungslogik ab. 
    Wenn ein bestimmtes Relais geschaltet ist, duerfen bestimmte andere Relais nicht geschaltet sein.
    '''

    def __init__(self):
        self.matrix = matrix()

    def setOnByRelName(self, name):
        if not self.matrix.relayExists(name):
            print "Relay unknown: >" + name
            sys.exit(1)

        print "Relais >" + name + "< ON"  
        self.matrix.setOnByRelName(name)
        if name == 'REL_50-SHORT50':
            self.matrix.setOffByRelName('REL_GND-SHORT50')

        if name == 'REL_VNA-TXA1':
            self.matrix.setOffByRelName('REL_VNA-TXB1')
        if name == 'REL_VNA-TXB1':
            self.matrix.setOffByRelName('REL_VNA-TXA1')

        if name == 'REL_RP2A-MWSP2':
            self.matrix.setOffByRelName('REL_RP1A-MWSP2')
        if name == 'REL_RP1A-MWSP2':
            self.matrix.setOffByRelName('REL_RP2A-MWSP2')

    def setOffByRelName(self, name):
        print "Relais >" + name + "< OFF" 
        self.matrix.setOnByRelName(name)

    def getBitstring(self):
        return self.matrix.getBitstring()

    def getIntegerArray(self):
        return self.matrix.getIntegerArray()

    def getCharArray(self):
        return self.matrix.getCharArray()

def senddata(input):

    def interaction(input):
        ser.write(input + '\r')
        ser.flush()
        time.sleep(1)
        out = ''
        while ser.inWaiting() > 0:
            out += ser.read(1)
        return out[len(input)+2:]

    def singlecommand(input):

        test = 0
        while 1 :
            out = interaction("")
            print out
            if out.endswith(">> "):
                break
            if test > 2:
                print "Serial Port Communications FAIL"
                sys.exit(1)
            time.sleep(1)

        out = interaction(input)
        if not "OK" in out:
            print "Serial Port Communications FAIL"
            sys.exit(1)
        else:
            print "Serial Port Communications OK"
        return out

    # if offline (for debugging), then bail out now
    if options.offline:
        return input

    if not os.access(options.serialport, os.W_OK):
        print "Serial port not accessable >" + options.serialport
        sys.exit(1)
    else:
        print "Serial port access OK >" + options.serialport

    ser = serial.Serial(
        port=options.serialport,
        baudrate=9600,
        bytesize=serial.EIGHTBITS,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE
    )

    ser.isOpen()

    out = singlecommand(input)

    if options.verbose:
        print out

    ser.close()
    exit()

def handle_bitstring(bitstring):

    # parse in groups of 8 bits
    bitgroups = [bitstring[i:i+8] for i in range(0, len(bitstring), 8)]

    # bitgroup into byte
    outstring = ''.join([chr(int(bg[::-1], 2)) for bg in bitgroups])
    senddata(outstring)

def handle_relays(args):

    logik = matrixlogik()

    for r in args:
        logik.setOnByRelName(r)
    if options.verbose:
        print logik.getIntegerArray()
        print logik.getCharArray()

    senddata(logik.getCharArray())


if __name__ == "__main__":

    from optparse import OptionParser, OptionGroup

    desc  = """This program is the interface to the Arduino logic controller of the switching matrix."""

    usage = "usage: %prog [options] rel1 rel2 ..."

    parser = OptionParser(description=desc, usage=usage)

    group = OptionGroup(parser, "Possible relay names are", ' '.join(allRelays))
    parser.add_option_group(group)

    parser.add_option("-s", "--serialport",
                  dest="serialport",
                  action="store",
                  default="/dev/ttyACM0",
                  nargs=1,
                  help="serial device for the matrix. Default: /dev/ttyACM0")

    parser.add_option("-o", "--offline",
                  dest="offline",
                  action="store_true",
                  default=False,
                  help="Do not try to connect to serial port")

    parser.add_option("-b", "--bitstring",
                  dest="bitstring",
                  action="store",
                  nargs=1,
                  default=False,
                  help="Bitstring, if you know what you are doing :-)")

    parser.add_option("-v", "--verbose",
                  dest="verbose",
                  action="store_true",
                  default=False,
                  help="Be verbose. Return debugging data.")

    (options, args) = parser.parse_args() 

    if options.bitstring:
        handle_bitstring(options.bitstring)
        sys.exit(0)

    if len(args) == 0:
        print "Error: no relays given"
        sys.exit(1)

    handle_relays(args)

6.2 Interaction

Usage: polmatrix.py [options] rel1 rel2 ...

This program is the interface to the Arduino logic controller of the switching
matrix.

Options:
  -h, --help            show this help message and exit
  -s SERIALPORT, --serialport=SERIALPORT
                        serial device for the matrix. Default: /dev/ttyACM0
  -o, --offline         Do not try to connect to serial port
  -b BITSTRING, --bitstring=BITSTRING
                        Bitstring, if you know what you are doing :-)
  -v, --verbose         Be verbose. Return debugging data.

  Possible relay names are:
    REL1-SHORT50 REL2-SHORT50 REL3-SHORT50 REL4-SHORT50 REL4-RP2B
    REL4-RP2A REL4-RP1B REL4-RP1A REL3-RP2B REL3-RP2A REL3-RP1B REL3-RP1A
    REL2-RP2B REL2-RP2A REL2-RP1B REL2-RP1A REL1-RP2B REL1-RP2A REL1-RP1B
    REL1-RP1A REL_GND-SHORT50 REL_50-SHORT50 REL_VNA-TXB1 REL_VNA-TXA1
    REL_RP2A-MWSP2 REL_RP1A-MWSP2

6.3 Examples

dl8rds@raspberry:~/dp0pol$ ./polmatrix.py 
Error: no relays given

dl8rds@raspberry:~/dp0pol$ ./polmatrix.py REL_GND-SHORT50 REL_50-SHORT50 REL_VNA-TXB1 REL_VNA-TXA1
Relais >REL_GND-SHORT50< ON
Relais >REL_50-SHORT50< ON
Relais >REL_VNA-TXB1< ON
Relais >REL_VNA-TXA1< ON
Serial port not accessable >/dev/ttyACM0

dl8rds@raspberry:~/dp0pol$ ./polmatrix.py REL_VNA-TXA1erterter
Relay unknown: >REL_VNA-TXA1erterter

dl8rds@raspberry:~/dp0pol$ ./polmatrix.py -b 0101010110101010 
Serial port not accessable >/dev/ttyACM0

dl8rds@raspberry:~/dp0pol$ ./polmatrix.py REL_GND-SHORT50 REL_50-SHORT50 REL_VNA-TXB1 REL_VNA-TXA1 -v
Relais >REL_GND-SHORT50< ON
Relais >REL_50-SHORT50< ON
Relais >REL_VNA-TXB1< ON
Relais >REL_VNA-TXA1< ON
85 85 85 85 85 102 85
UUUUUfU
Serial port not accessable >/dev/ttyACM0

7 Images

2018-10-10-matrix1.jpg

2018-10-10-matrix2.jpg

2018-10-10-matrix3.jpg