wg1220.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import serial
  2. import operator
  3. import logging
  4. import struct
  5. import math
  6. import argparse
  7. log = logging.getLogger(__name__)
  8. def checksum(msg):
  9. return reduce(operator.xor, (ord(x) for x in msg))
  10. class Generator(object):
  11. def __init__(self):
  12. self.conn = serial.Serial(
  13. port='/dev/ttyUSB0',
  14. baudrate=57600,
  15. bytesize=serial.EIGHTBITS,
  16. parity=serial.PARITY_NONE,
  17. stopbits=serial.STOPBITS_ONE,
  18. timeout=1,
  19. )
  20. def send_command(self, cmd):
  21. if len(cmd) != 5:
  22. raise ValueError("cmd must be five characters")
  23. def fmt(msg):
  24. return ' '.join(hex(ord(x)) for x in msg)
  25. message = 'X{}{}'.format(cmd, chr(checksum(cmd)))
  26. log.debug("send {}".format(fmt(message)))
  27. self.conn.write(message)
  28. result = self.conn.read(7)
  29. if len(result) == 0:
  30. raise IOError("No result returned")
  31. log.debug("recv {}".format(fmt(result)))
  32. if checksum(result[1:6]) != ord(result[6]):
  33. raise IOError("Wrong checksum")
  34. return result[2:5]
  35. def set_remote(self, enable):
  36. self.send_command('R{}xxx'.format(chr(int(not enable))))
  37. r = self.send_command('rxxxx')
  38. @property
  39. def remote_enabled(self):
  40. r = self.send_command('rxxxx')
  41. return r[0] == '0'
  42. @property
  43. def frequency(self):
  44. r = self.send_command('fxxxx')
  45. hi, lo, exp = struct.unpack('BBB', r)
  46. return ((hi << 8) | lo) / 1000.0 * 10**exp
  47. @frequency.setter
  48. def frequency(self, freq):
  49. exp = int(math.log(freq, 10))
  50. mantissa = int(round(freq / math.exp(exp * math.log(10)))) * 1000
  51. hi, lo = mantissa >> 8, mantissa & 0xff
  52. self.send_command('F{}{}{}{}'.format(chr(hi), chr(lo), chr(exp), chr(0xff)))
  53. @property
  54. def amplitude(self):
  55. r = self.send_command('axxxx')
  56. hi, lo = struct.unpack('BB', r[:2])
  57. return ((hi << 8) | lo) / 1000.0
  58. @amplitude.setter
  59. def amplitude(self, amp):
  60. val = int(amp * 1000)
  61. hi, lo = val >> 8, val & 0xff
  62. self.send_command('A{}{}x{}'.format(chr(hi), chr(lo), chr(0xff)))
  63. @property
  64. def offset(self):
  65. r = self.send_command('oxxxx')
  66. hi, lo = struct.unpack('BB', r[:2])
  67. return ((hi << 8) | lo) / 1000.0
  68. @offset.setter
  69. def offset(self, off):
  70. val = int(off * 1000)
  71. hi, lo = val >> 8, val & 0xff
  72. self.send_command('O{}{}x{}'.format(chr(hi), chr(lo), chr(0xff)))
  73. @property
  74. def dutycycle(self):
  75. r = self.send_command('dxxxx')
  76. return ord(r[0])
  77. @dutycycle.setter
  78. def dutycycle(self, cycle):
  79. if cycle < 0 or cycle > 100:
  80. raise ValueError("cycle must be between 0 and 100")
  81. self.send_command('D{}xx{}'.format(chr(cycle), chr(0xff)))
  82. def main():
  83. logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(message)s")
  84. g = Generator()
  85. parser = argparse.ArgumentParser()
  86. parser.add_argument('-f', '--frequency', type=float, default=None)
  87. parser.add_argument('-a', '--amplitude', type=float, default=None)
  88. parser.add_argument('-o', '--offset', type=float, default=None)
  89. parser.add_argument('-d', '--dutycycle', type=float, default=None)
  90. args = parser.parse_args()
  91. g.set_remote(True)
  92. if args.frequency:
  93. g.frequency = args.frequency
  94. if args.amplitude:
  95. g.amplitude = args.amplitude
  96. if args.offset:
  97. g.offset = args.offset
  98. if args.dutycycle:
  99. g.dutycycle = argsycle
  100. print("Frequency: {} Hz".format(g.frequency))
  101. print("Amplitude: {} V".format(g.amplitude))
  102. print("Offset: {} V".format(g.offset))
  103. print("Duty cycle: {} %".format(g.dutycycle))
  104. g.set_remote(False)
  105. if __name__ == '__main__':
  106. main()