123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- 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)
- if len(result) == 0:
- raise IOError("No result returned")
- 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()
|