Browse Source

Initial commit

Matthias Vogelgesang 9 years ago
commit
e78b594d91
2 changed files with 146 additions and 0 deletions
  1. 6 0
      README.md
  2. 140 0
      wg1220.py

+ 6 - 0
README.md

@@ -0,0 +1,6 @@
+### Python interface for WG1220 waveform generator
+
+Import the `wg1220.Generator` class or use the command line interface to talk to
+the M&R WG1220 waveform generator:
+
+    $ python wg1220.py --frequency 100 --amplitude 1.5 --offset 0.25 --dutycycle 10

+ 140 - 0
wg1220.py

@@ -0,0 +1,140 @@
+import serial
+import operator
+import logging
+import struct
+import math
+import argparse
+
+
+log = logging.getLogger(__name__)
+
+
+def checksum(msg):
+    return reduce(operator.xor, (ord(x) for x in msg))
+
+
+class Generator(object):
+
+    def __init__(self):
+        self.conn = serial.Serial(
+                port='/dev/ttyUSB0',
+                baudrate=57600,
+                bytesize=serial.EIGHTBITS,
+                parity=serial.PARITY_NONE,
+                stopbits=serial.STOPBITS_ONE,
+                timeout=1,
+            )
+
+    def send_command(self, cmd):
+        if len(cmd) != 5:
+            raise ValueError("cmd must be five characters")
+
+        def fmt(msg):
+            return ' '.join(hex(ord(x)) for x in msg)
+
+        message = 'X{}{}'.format(cmd, chr(checksum(cmd)))
+        log.debug("send {}".format(fmt(message)))
+
+        self.conn.write(message)
+        result = self.conn.read(7)
+        log.debug("recv {}".format(fmt(result)))
+
+        if checksum(result[1:6]) != ord(result[6]):
+            raise IOError("Wrong checksum")
+
+        return result[2:5]
+
+    def set_remote(self, enable):
+        self.send_command('R{}xxx'.format(chr(int(not enable))))
+        r = self.send_command('rxxxx')
+
+    @property
+    def remote_enabled(self):
+        r = self.send_command('rxxxx')
+        return r[0] == '0'
+
+    @property
+    def frequency(self):
+        r = self.send_command('fxxxx')
+        hi, lo, exp = struct.unpack('BBB', r)
+        return ((hi << 8) | lo) / 1000.0 * 10**exp
+
+    @frequency.setter
+    def frequency(self, freq):
+        exp = int(math.log(freq, 10))
+        mantissa = int(round(freq / math.exp(exp * math.log(10)))) * 1000
+        hi, lo = mantissa >> 8, mantissa & 0xff 
+        self.send_command('F{}{}{}{}'.format(chr(hi), chr(lo), chr(exp), chr(0xff)))
+
+    @property
+    def amplitude(self):
+        r = self.send_command('axxxx')
+        hi, lo = struct.unpack('BB', r[:2])
+        return ((hi << 8) | lo) / 1000.0
+
+    @amplitude.setter
+    def amplitude(self, amp):
+        val = int(amp * 1000)
+        hi, lo = val >> 8, val & 0xff
+        self.send_command('A{}{}x{}'.format(chr(hi), chr(lo), chr(0xff)))
+
+    @property
+    def offset(self):
+        r = self.send_command('oxxxx')
+        hi, lo = struct.unpack('BB', r[:2])
+        return ((hi << 8) | lo) / 1000.0
+
+    @offset.setter
+    def offset(self, off):
+        val = int(off * 1000)
+        hi, lo = val >> 8, val & 0xff
+        self.send_command('O{}{}x{}'.format(chr(hi), chr(lo), chr(0xff)))
+
+    @property
+    def dutycycle(self):
+        r = self.send_command('dxxxx')
+        return ord(r[0])
+
+    @dutycycle.setter
+    def dutycycle(self, cycle):
+        if cycle < 0 or cycle > 100:
+            raise ValueError("cycle must be between 0 and 100")
+
+        self.send_command('D{}xx{}'.format(chr(cycle), chr(0xff)))
+
+
+def main():
+    logging.basicConfig(level=logging.INFO, format="[%(asctime)s]  %(message)s")
+    g = Generator()
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-f', '--frequency', type=float, default=None)
+    parser.add_argument('-a', '--amplitude', type=float, default=None)
+    parser.add_argument('-o', '--offset', type=float, default=None)
+    parser.add_argument('-d', '--dutycycle', type=float, default=None)
+    args = parser.parse_args()
+
+    g.set_remote(True)
+
+    if args.frequency:
+        g.frequency = args.frequency
+
+    if args.amplitude:
+        g.amplitude = args.amplitude
+
+    if args.offset:
+        g.offset = args.offset
+
+    if args.dutycycle:
+        g.dutycycle = argsycle
+
+    print("Frequency: {} Hz".format(g.frequency))
+    print("Amplitude: {} V".format(g.amplitude))
+    print("Offset: {} V".format(g.offset))
+    print("Duty cycle: {} %".format(g.dutycycle))
+
+    g.set_remote(False)
+    
+
+if __name__ == '__main__':
+    main()