From 3f63276da71250dd8bdcb3c72235d1813bc96296 Mon Sep 17 00:00:00 2001 From: Dustin Brunner Date: Sat, 27 Aug 2022 11:45:59 +0200 Subject: [PATCH] V1 --- README.md | 62 + helper_scripts/auto_detect_port.py | 17 + helper_scripts/list_serial_ports.py | 16 + influxdb_config.py | 10 + jds6600.py | 1893 +++++++++++++++++++++++++++ readfreq_influxdb.py | 101 ++ readfreq_terminal.py | 54 + 7 files changed, 2153 insertions(+) create mode 100644 README.md create mode 100644 helper_scripts/auto_detect_port.py create mode 100644 helper_scripts/list_serial_ports.py create mode 100644 influxdb_config.py create mode 100644 jds6600.py create mode 100644 readfreq_influxdb.py create mode 100644 readfreq_terminal.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..0dc7398 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# Influx-DB frequency logger with JDS6600 signal generator + +A simple python script to write measured frequency values into a Influx-DB database. + +## Python installation on Ubuntu +``` +sudo apt-get update +sudo apt-get install python3 +sudo apt-get install python3-pip +``` + +## Python Dependencies: +``` +pip install pyserial +pip install influxdb +``` + +## running the script (automatically) +The script is auto-detecting the USB-port, where the signal generator is connected to. After that it connects to a Influx-DB-server and then publishes the measured frequency value every second to this server. Make sure to fill your login credentials into the `influxdb_config.py`-file. + +To auto start the script at the sotartup of the server we configure a systemd-service. I assume the repository with this script is cloned into the home directory of one user. + +``` +sudo nano /etc/systemd/system/readfreq_influxdb.service +``` +Write into this file: +``` +[Unit] +Description=readfreq_influxdb python script +After=multi-user.target + +[Service] +Type=simple +Restart=always +RestartSec=5 +ExecStart=/usr/bin/python3 /home/user/software_python/readfreq_influxdb.py +StandardOutput=syslog +StandardError=syslog + +[Install] +WantedBy=multi-user.target +``` + +No the autostart can be activated: +``` +sudo systemctl enable readfreq_influxdb.service +sudo systemctl start readfreq_influxdb.service +sudo systemctl status readfreq_influxdb.service +``` +To deactivate it, use the command `sudo systemctl disable readfreq_influxdb.service`. + + +# Sources/useful links: +- Python Lib (MIT License): https://github.com/on1arf/jds6600_python +- https://github.com/thomaseichhorn/funcgen +- https://www.thomaschristlieb.de/ein-python-script-mit-systemd-als-daemon-systemd-tut-garnicht-weh/ + + +

+

This work by Dustin Brunner is licensed under CC BY 4.0

+ +Creative Commons Lizenzvertrag
Dieses Werk von Dustin Brunner ist lizenziert unter einer Creative Commons Namensnennung 4.0 International Lizenz. diff --git a/helper_scripts/auto_detect_port.py b/helper_scripts/auto_detect_port.py new file mode 100644 index 0000000..38dba1c --- /dev/null +++ b/helper_scripts/auto_detect_port.py @@ -0,0 +1,17 @@ +import warnings +import serial +import serial.tools.list_ports + +found_ports = [ + p.device + for p in serial.tools.list_ports.comports() + if 'CH340' in p.description or 'USB Serial' in p.description #CH340 for Windows, USB Serial for Linux +] + +if not found_ports: + raise IOError("No JDS6600-device found") +if len(found_ports) > 1: + warnings.warn('Multiple JDS6600-devices found - using the first') + +portname = found_ports[0] +print(portname) \ No newline at end of file diff --git a/helper_scripts/list_serial_ports.py b/helper_scripts/list_serial_ports.py new file mode 100644 index 0000000..7e38b25 --- /dev/null +++ b/helper_scripts/list_serial_ports.py @@ -0,0 +1,16 @@ +import os +import serial.tools.list_ports + +ports = serial.tools.list_ports.comports(include_links=True) + +print("Serial Ports:") +print("path \t\t| name \t\t| description") +print("-------------------------------------------------------------------------") + +for port in ports : + print(port.device + " \t\t| " + port.name + "\t\t| " + port.description) + +print("-------------------------------------------------------------------------") + +os.system("pause") + \ No newline at end of file diff --git a/influxdb_config.py b/influxdb_config.py new file mode 100644 index 0000000..809b3f4 --- /dev/null +++ b/influxdb_config.py @@ -0,0 +1,10 @@ +# ---------------- +# Config file +# ---------------- + +# Config for the Influxdb-server +influxdb_host = '192.168.1.10' +influxdb_port = 8086 +influxdb_user = 'user' +influxdb_password = '123456' +influxdb_dbname = 'frequency' diff --git a/jds6600.py b/jds6600.py new file mode 100644 index 0000000..feb179e --- /dev/null +++ b/jds6600.py @@ -0,0 +1,1893 @@ +# jds6600.py +# library to remote-control a JDS6600 signal generator + +# Kristoff Bonne (c) 2018 +# published under MIT license. See file "LICENSE" for full license text + +# Revisions: +# Version 0.0.1: 2018/01/19: initial release, reading basic parameters +# version 0.0.2: 2018/01/28: added "measure" menu + support functions, documentation +# version 0.0.3: 2018/02/07: added "counter" and "sweep" menu +# version 0.0.4: 2018/02/14: added "pulse" and "burst" menu + code cleanup +# version 0.0.5: 2018/02/16: added system menu +# version 0.1.0: 2018/02/17: added arbitrary waveform + + +import serial +import binascii + + +########### +# Errors # +########### + +class UnknownChannelError(ValueError): + pass + +class UnexpectedValueError(ValueError): + pass + +class UnexpectedReplyError(ValueError): + pass + +class FormatError(ValueError): + pass + +class WrongMode(RuntimeError): + # called when commands are issued with the jds6600 not in the correct + # mode + pass + + +################# +# jds6600 class # +################# + +class jds6600: + 'jds6600 top-level class' + + # serial device (opened during object init)) + ser = None + + # commands + DEVICETYPE=0 + SERIALNUMBER=1 + + CHANNELENABLE=20 + WAVEFORM1=21 + WAVEFORM2=22 + FREQUENCY1=23 + FREQUENCY2=24 + AMPLITUDE1=25 + AMPLITUDE2=26 + OFFSET1=27 + OFFSET2=28 + DUTYCYCLE1=29 + DUTYCYCLE2=30 + PHASE=31 + + ACTION=32 + MODE=33 + + MEASURE_COUP=36 # coupling (AC or DC) + MEASURE_GATE=37 # gatetime + MEASURE_MODE=38 # mode (Freq or Periode) + + COUNTER_COUPL=MEASURE_COUP + COUNTER_RESETCOUNTER=39 + + SWEEP_STARTFREQ=40 + SWEEP_ENDFREQ=41 + SWEEP_TIME=42 + SWEEP_DIRECTION=43 + SWEEP_MODE=44 # mode: linair or Log + + PULSE_PULSEWIDTH=45 + PULSE_PERIOD=46 + PULSE_OFFSET=47 + PULSE_AMPLITUDE=48 + + BURST_NUMBER=49 + BURST_MODE=50 + + + SYSTEM_SOUND=51 + SYSTEM_BRIGHTNESS=52 + SYSTEM_LANGUAGE=53 + SYSTEM_SYNC=54 + SYSTEM_ARBMAXNUM=55 + + PROFILE_SAVE=70 + PROFILE_LOAD=71 + PROFILE_CLEAR=72 + + COUNTER_DATA_COUNTER=80 + + MEASURE_DATA_FREQ_LOWRES=81 # low resolution freq counter, used for mode "frequency" + MEASURE_DATA_FREQ_HIGHRES=82 # high resolution freq. counter, usef for mode "period". UI: valid up to 2 Khz + MEASURE_DATA_PW1=83 + MEASURE_DATA_PW0=84 + MEASURE_DATA_PERIOD=85 + MEASURE_DATA_DUTYCYCLE=86 + MEASURE_DATA_U1=87 + MEASURE_DATA_U2=88 + MEASURE_DATA_U3=89 + + + + + # waveforms: registers 21 (ch1) and 22 (ch2)) + # 0 to 16: predefined waveforms + __wave=("SINE","SQUARE","PULSE","TRIANGLE","PARTIALSINE","CMOS","DC","HALF-WAVE","FULL-WAVE","POS-LADDER","NEG-LADDER", "NOISE", "EXP-RIZE","EXP-DECAY","MULTI-TONE","SINC","LORENZ") + # 101 to 160: arbitrary waveforms + __awave=[] + for a in range(1,10): + __awave.append("ARBITRARY0"+str(a)) + for a in range(10,61): + __awave.append("ARBITRARY"+str(a)) + # end for + + + # modes: register 33 + # note: use lowest 4 bits for wrting + # note: use highest 4 bits for reading + __modes = ((0,"WAVE_CH1"),(0,"WAVE_CH1"),(1,"WAVE_CH2"),(1,"WAVE_CH2"),(2,"SYSTEM"),(2,"SYSTEM"),(-1,""),(-1,""),(4,"MEASURE"),(5,"COUNTER"),(6,"SWEEP_CH1"),(7,"SWEEP_CH2"),(8,"PULSE"),(9,"BURST")) + + # action: register 32 + __actionlist=(("STOP","0,0,0,0"),("COUNT","1,0,0,0"),("SWEEP","0,1,0,0"),("PULSE","1,0,1,1"),("BURST","1,0,0,1")) + __action={} + for (actionname,actioncode) in __actionlist: + __action[actionname]=actioncode + # end for + + + # measure mode parameters + __measure_coupling=("AC(EXT.IN)","DC(EXT.IN)") + __measure_mode=("M.FREQ","M.PERIOD") + + + # sweep parameters + __sweep_direction=("RISE","FALL","RISE&FALL") + __sweep_mode=("LINEAR","LOGARITHM") + + + # burst parameters + __burst_mode=["MANUAL TRIG.","CH2 TRIG.","EXT.TRIG(AC)","EXT.TRIG(DC)"] + + # frequency multiplier + __freqmultiply=(1,1,1,1/1000,1/1000000) + + + # language + __system_language=("ENGLISH","CHINESE") + + ############### + # oonstructor # + ############### + + def __init__(self,fname): + jds6600.ser = serial.Serial( + port= fname, + baudrate=115200, + parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE, + bytesize=serial.EIGHTBITS, + timeout=1 ) + # end constructor + + + + ##################### + # support functions # + ##################### + + ##### + # low-level support function + + # parse data from read command + def __parsedata(self,reg,data,a): + if a not in (0,1): raise RuntimeError(a) + + try: + (one,two)=data.split("=") + except ValueError: + raise FormatError("Parsing Returned data: Invalid format, missing \"=\"") + + two_b=two.split(".") + + # reads from register are terminated by a "." + # reads of arbitrary waveform are not + if a == 0: + if len(two_b) < 2: + raise FormatError("Parsing Returned data: Invalid format, missing \".\"") + + if len(two_b) > 2: + raise FormatError("Parsing Returned data: Invalid format, too many \".\"") + # end if + + # command to look for; + # "r" for register read, "b" for arbitrary waveform read + c = 'r' if a == 0 else 'b' + + # check if returned data matches reg that was send + if reg != None: + if one != ":"+c+reg: + errmsg="Parsing Return data: send/received reg mismatch: "+data+" / expected :"+c+reg + raise FormatError(errmsg) + # end if + # end if + + # done: return data: part between "=" and ".", split on "," + return two_b[0].split(",") + # end __parsedata + + # command in textual form + def __reg2txt(self,reg): + return "0"+str(reg) if int(reg) < 10 else str(reg) + # end reg2txt + + # send read command (for n datapoint) + def __sendreadcmd(self,reg,n,a): + if type(n) != int: raise TypeError(n) + if a not in (0,1): raise ValueError(a) + + regtxt=self.__reg2txt(reg) + if (n < 1): + raise ValueError(n) + + if a == 0: + # a (arbitrary waveform) is 0 -> register read + c='r' # register + else: + c='b' # arbitrary waveform + # for n to 1 + n=1 + # end else - if + + # "n" in command start with 0 for 1 read-request + n -= 1 + + if self.ser.is_open == True: + tosend=":"+c+regtxt+"="+str(n)+"."+chr(0x0a) + self.ser.write(tosend.encode()) + # end __sendreadcmd + + + + # get responds of read-request and parse ("n" reads) + def __getrespondsandparse(self,reg, n, a): + if type(n) != int: raise ValueError(n) + if a not in (0,1): raise ValueError(a) # a=0-> register read, a=1 -> arbitrary waveform read + + ret=[] # return value + + c = int(reg) # counter + c_expect=self.__reg2txt(c) + for l in range(n): + # get one line responds from serial device + retserial=self.ser.readline() + # convert bytearray into string, then strip off terminating \n and \r + retserial=str(retserial,'utf-8').rstrip() + + # get parsed data + # assume all data are single-value fields + parseddata=self.__parsedata(c_expect,retserial,a) + + # we receive a list of strings, all containing numeric (integer) values + + if len(parseddata) == 1: + # if list with one value, return that value (converted to integer) + ret.append(int(parseddata[0])) + else: + # if list with multiple values, convert all strings to integers and return list + retlist=[] + retcount=0 + for data in parseddata: + if data == "": + # we should not receive empty datafields, except for after the last element of an arbitrary waveform + if not ((a == 1) and (retcount == 2048)): + raise UnexpectedValueError(parseddata) + else: + retlist.append(int(data)) + # end else - if + + retcount += 1 + # end for + ret.append(retlist) + # end else - if + + # increase next expected to-receive data + c += 1 + c_expect=self.__reg2txt(c) + # end for + + # return parsed data + # if only one element, return that element + # if multiple elements, return list + return ret[0] if n == 1 else ret + # end __get responds and parse 1 + + + # get data + def __getdata(self,reg, n=1, a=0): + if type(reg) != int: raise TypeError(reg) + if type(n) != int: raise TypeError(n) + + # a is "arbitrary waveform or register" + # a=0 -> register read + # a=1 -> arbitrary waveform read + + # send "read" commandline for "n" lines + # copy "a" parameter from calling function + self.__sendreadcmd(reg,n,a) + + return self.__getrespondsandparse(reg,n,a) + # end __getdata 1 + + + # send write command and wait for "ok" + def __sendwritecmd(self,reg, val, a=0): + # note: a = "arbitrary waveform?": 0 = no (register write), 1 = yes (arb. waveform write) + # add a "0" to the command if it one single character + reg=self.__reg2txt(reg) + + # command to send: "w" for register write, "b" for arbitrary waveform write + cmd = "w" if a == 0 else "a" + + if self.ser.is_open == True: + if type(val) == int: val = str(val) + if type(val) != str: raise TypeError(val) + + tosend=":"+cmd+reg+"="+val+"."+chr(0x0a) + self.ser.write(tosend.encode()) + + # wait for "ok" + + # get one line responds from serial device + ret=self.ser.readline() + # convert bytearray into string, then strip off terminating \n and \r + ret=str(ret,'utf-8').rstrip() + + if ret != ":ok": + raise UnexpectedReplyError(ret) + # end if + + #end if + # end __sendwritecmd + + + ##### + # high-level support function + + # set action + def __setaction(self,action): + # type check + if type(action) != str: + raise TypeError(action) + # end if + + try: + self.__sendwritecmd(jds6600.ACTION,jds6600.__action[action]) + except KeyError: + errmsg="Unknown Action: "+action + raise ValueError(errmsg) + # end try + + # end set action + + ################### + # DEBUG functions # + ################### + + def DEBUG_readregister(self,register,count): + if self.ser.is_open == True: + regtxt=self.__reg2txt(register) + tosend=":r"+regtxt+"="+str(count)+"."+chr(0x0a) + self.ser.write(tosend.encode()) + + ret=self.ser.readline() + while ret != b'': + print(str(ret)) + ret=self.ser.readline() + # end while + # end if + # end readregister + + def DEBUG_writeregister(self,register,value): + if self.ser.is_open == True: + regtxt=self.__reg2txt(register) + if type(value) == int: + value=str(value) + + tosend=":w"+regtxt+"="+value+"."+chr(0x0a) + self.ser.write(tosend.encode()) + + ret=self.ser.readline() + while ret != b'': + print(str(ret)) + ret=self.ser.readline() + # end while + # end if + + # end write register + + + ############## + # PUBLIC API # + ############## + + ######################### + # Part 0: API information + + + # API version + def getAPIinfo_version(self): + return 1 + # end getAPIversion + + # API release number + def getAPIinfo_release(self): + return "0.1.0 2018-02-17" + # end get API release + + + ############################# + # Part 1: information queries + + # list of waveforms + def getinfo_waveformlist(self): + waveformlist=list(enumerate(jds6600.__wave)) + for aw in (enumerate(jds6600.__awave,101)): + waveformlist.append(aw) + # end for + + return waveformlist + # end get waveform list + + + # get list of modes + def getinfo_modelist(self): + modelist=[] + + lastmode=-1 + + # create list of modes, removing dups + for (modeid,modetxt) in jds6600.__modes: + # ignore modes with modeid < 0 (unused mode) + if modeid < 0: + continue + # end if + + if modeid != lastmode: + modelist.append((modeid,modetxt)) + lastmode = modeid + # end if + # end for + + return modelist + # end getinfo modelist + + + ################################## + # Part 2: reading basic parameters + + # get device type + def getinfo_devicetype(self): + return self.__getdata(jds6600.DEVICETYPE) + # end get device type + + + # get serial number + def getinfo_serialnumber(self): + return self.__getdata(jds6600.SERIALNUMBER) + # end get serial number + + + # get channel enable status + def getchannelenable(self): + (ch1,ch2)=self.__getdata(jds6600.CHANNELENABLE) + try: + return (False,True)[ch1], (False,True)[ch2] + except IndexError: + errmsg="Unexpected value received: {},{}".format(ch1,ch2) + raise UnexpectedValueError(errmsg) + # end get channel enable status + + # get waveform + def getwaveform(self, channel): + if type(channel) != int: raise TypeError(channel) + if not (channel in (1,2)): raise ValueError(channel) + + #WAVEFORM for channel 2 is WAVEFORM1 + 1 + waveform=self.__getdata(jds6600.WAVEFORM1+channel-1) + + # waveform 0 to 16 are in "wave" list, 101 to 160 are in __awave + try: + return (waveform,jds6600.__wave[waveform]) + except IndexError: + pass + + try: + return (waveform,jds6600.__awave[waveform-101]) + except IndexError: + raise UnexpectedValueError(waveform) + # end getwaveform + + # get frequency _with multiplier + def getfrequency_m(self,channel): + if type(channel) != int: raise TypeError(channel) + if not (channel in (1,2)): raise ValueError(channel) + + (f1,f2)=self.__getdata(jds6600.FREQUENCY1+channel-1) + + # parse multiplier (value after ",") + # 0=Hz, 1=KHz,2=MHz, 3=mHz,4=uHz) + # note f1 is frequency / 100 + try: + return((f1/100*self.__freqmultiply[f2],f2)) + except IndexError: + # unexptected value of frequency multiplier + raise UnexpectedValueError(f2) + # end elsif + # end function getfreq + + # get frequency _no multiplier information + def getfrequency(self,channel): + if type(channel) != int: raise TypeError(channel) + if not (channel in (1,2)): raise ValueError(channel) + + (f1,f2)=self.__getdata(jds6600.FREQUENCY1+channel-1) + + # parse multiplier (value after ","): 0=Hz, 1=KHz,2=MHz, 3=mHz,4=uHz) + # note1: frequency unit is Hz / 100 + # note2: multiplier 1 (khz) and 2 (mhz) only changes the visualisation on the + # display of the jfs6600. The frequency itself is calculated in + # the same way as for multiplier 0 (Hz) + # mulitpliers 3 (mHZ) and 4 (uHz) do change the calculation of the frequency + try: + return(f1/100*self.__freqmultiply[f2]) + except IndexError: + # unexptected value of frequency multiplier + raise UnexpectedValueError(f2) + # end elsif + # end function getfreq + + + # get amplitude + def getamplitude(self, channel): + if type(channel) != int: raise TypeError(channel) + if not (channel in (1,2)): raise ValueError(channel) + + amplitude=self.__getdata(jds6600.AMPLITUDE1+channel-1) + + # amplitude is mV -> so divide by 1000 + return amplitude/1000 + # end getamplitude + + + # get offset + def getoffset(self, channel): + if type(channel) != int: raise TypeError(channel) + if not (channel in (1,2)): raise ValueError(channel) + + offset=self.__getdata(jds6600.OFFSET1+channel-1) + + # offset unit is 10 mV, and then add 1000 + return (offset-1000)/100 + # end getoffset + + # get dutcycle + def getdutycycle(self, channel): + if type(channel) != int: raise TypeError(channel) + if not (channel in (1,2)): raise ValueError(channel) + + dutycycle=self.__getdata(jds6600.DUTYCYCLE1+channel-1) + + # dutycycle unit is 0.1 %, so divide by 10 + return dutycycle/10 + # end getdutycycle + + + # get phase + def getphase(self): + phase=self.__getdata(jds6600.PHASE) + + # phase unit is 0.1 degrees, so divide by 10 + return phase/10 + # end getphase + + + ################################## + # Part 3: writing basic parameters + + + # set channel enable + def setchannelenable(self,ch1,ch2): + if type(ch1) != bool: raise TypeError(ch1) + if type(ch2) != bool: raise TypeError(ch1) + + # channel 1 + if ch1 == True: enable = "1" + else: enable = "0" # end else - if + + if ch2 == True: enable += ",1" + else: enable += ",0" # end else - if + + # write command + self.__sendwritecmd(jds6600.CHANNELENABLE,enable) + # end set channel enable + + # set waveform + def setwaveform(self,channel,waveform): + if type(channel) != int: raise TypeError(channel) + if (type(waveform) != int) and (type(waveform) != str): raise TypeError(waveform) + + if not (channel in (1,2)): raise ValueError(channel) + + # wzveform can be integer or string + w=None + + if type(waveform) == int: + # waveform is an integer + if waveform < 101: + try: + jds6600.__wave[waveform] + except IndexError: + raise ValueError(waveform) + # end try + + else: + try: + jds6600.__awave[waveform-101] + except IndexError: + raise ValueError(waveform) + # end try + # end if + + # ok, it exists! + w=waveform + + else: + # waveform is a string + + # make everything uppercase + waveform=waveform.upper() + # check all waveform descriptions in wave and __awave + # w is already initialised as "none" above + + try: + # try in "wave" list + w=jds6600.__wave.index(waveform) + except ValueError: + pass + + if w == None: + #if not found in "wave", try the "awave" list + try: + w=jds6600.__awave.index(waveform)+101 # arbitrary waveforms state are index 101 + except ValueError: + pass + # end try + # end if + + if w == None: + # not in "wave" and "awave" error + errmsg="Unknown waveform "+waveform + raise ValueError (errmsg) + # end if + + # ens else - if + + + self.__sendwritecmd(jds6600.WAVEFORM1+channel-1,w) + + # end function set waveform + + + # set frequency (with multiplier) + def setfrequency(self,channel,freq,multiplier=0): + if type(channel) != int: raise TypeError(channel) + if (type(freq) != int) and (type(freq) != float): raise TypeError(freq) + if type(multiplier) != int: raise TypeError(multiplier) + + if not (channel in (1,2)): raise ValueError(channel) + + + if (freq < 0): + raise ValueError(freq) + + # do not execute set-frequency when the device is in sweepfrequency mode + currentmode=self.getmode() + + if (channel == 1) and (currentmode[1] == "SWEEP_CH1"): + # for channel 1 + raise WrongMode() + elif (channel == 2) and (currentmode[1] == "SWEEP_CH2"): + # for channel 2 + raise WrongMode() + # end elsif - if + + + + # freqmultier should be one of the "frequency multiply" values + try: + self.__freqmultiply[multiplier] + except IndexError: + raise ValueError[multiplier] + + # frequency limit: + # 60 Mhz for multiplier 0 (Hz), 1 (KHz) and 2 (MHz) + # 80 Khz for multiplier 3 (mHz) + # 80 Hz for multiplier 4 (uHz) + # trying to configure a higher value can result in incorrect frequencies + + if multiplier < 3: + if freq > 60000000: + errmsg="Maximum frequency using multiplier {} is 60 MHz.".format(multiplier) + raise ValueError(errmsg) + # end if + elif multiplier == 3: + if freq > 80000: + errmsg="Maximum frequency using multiplier 3 is 80 KHz." + raise ValueError(errmsg) + # end if + else: # multiplier == 4 + if freq > 80: + errmsg="Maximum frequency using multiplier 4 is 80 Hz." + raise ValueError(errmsg) + # end if + # end else - elsif - if + + + + # round to nearest 0.01 value + freq=int(round(freq*100/jds6600.__freqmultiply[multiplier])) + value=str(freq)+","+str(multiplier) + + self.__sendwritecmd(jds6600.FREQUENCY1+channel-1,value) + # end set frequency (with multiplier) + + + # set amplitude + def setamplitude(self, channel, amplitude): + if type(channel) != int: raise TypeError(channel) + if (type(amplitude) != int) and (type(amplitude) != float): raise TypeError(amplitude) + + if not (channel in (1,2)): raise ValueError(channel) + + # amplitude is between 0 and 20 V + if not (0 <= amplitude <= 20): + raise ValueError(amplitude) + + # round to nearest 0.001 value + amplitude=int(round(amplitude*1000)) + + self.__sendwritecmd(jds6600.AMPLITUDE1+channel-1,amplitude) + # end setamplitude + + + + # set offset + def setoffset(self, channel, offset): + if type(channel) != int: raise TypeError(channel) + if (type(offset) != int) and (type(offset) != float): raise TypeError(offset) + + if not (channel in (1,2)): raise ValueError(channel) + + # offset is between -10 and +10 volt + if not (-10 <= offset <= 10): + raise ValueError(offset) + + # note: althou the value-range for offset is able + # to accomodate an offset between -10 and +10 Volt + # the actual offset seams to be lmited to -2.5 to +2.5 + + # round to nearest 0.01 value + offset=int(round(offset*100))+1000 + + self.__sendwritecmd(jds6600.OFFSET1+channel-1, offset) + # end set offset + + # set dutcycle + def setdutycycle(self, channel, dutycycle): + if type(channel) != int: raise TypeError(channel) + if (type(dutycycle) != int) and (type(dutycycle) != float): raise TypeError(dutycycle) + + if not (channel in (1,2)): raise ValueError(channel) + + # dutycycle is between 0 and 100 % + if not (0 <= dutycycle <= 100): + raise ValueError(dutycycle) + + # round to nearest 0.1 value + dutycycle=int(round(dutycycle*10)) + + self.__sendwritecmd(jds6600.DUTYCYCLE1+channel-1,dutycycle) + # end set dutycycle + + + # set phase + def setphase(self,phase): + if (type(phase) != int) and (type(phase) != float): + raise TypeError(phase) + + # hase is between -360 and 360 + if not (-360 <= phase <= 360): + raise ValueError(phase) + + if phase < 0: + phase += 3600 + + # round to nearest 0.1 value + phase=int(round(phase*10)) + + self.__sendwritecmd(jds6600.PHASE,phase) + # end getphase + + + ####################### + # Part 4: reading / changing mode + # get mode + def getmode(self): + mode=self.__getdata(jds6600.MODE) + + + # mode is in the list "modes". mode-name "" means undefinded + mode=int(mode)>>3 + + try: + (modeid,modetxt)=jds6600.__modes[mode] + except IndexError: + raise UnexpectedValueError(mode) + + # modeid 3 is not valid and returns an id of -1 + if modeid >= 0: + return modeid,modetxt + # end if + + + # modeid 4 + raise UnexpectedValueError(mode) + + # end getmode + + + # set mode + def setmode(self,mode, nostop=False): + if (type(mode) != int) and (type(mode) != str): raise TypeError(mode) + + + modeid=-1 + # if mode is an integer, it should be between 0 and 9 + if type(mode) == int: + if not (0 <= mode <= 9): + raise ValueError(mode) + # end if + + # modeid 3 / modetxt "" does not exist + if mode == 3: + raise ValueError("mode 3 does not exist") + # end if + + + # valid modeid + modeid = mode + + else: + # modeid 3 / modetxt "" does not exist + if mode == "": + raise ValueError("mode 3 does not exist") + # end if + + # mode is string -> check list + # (note: the modes-list is not enumerated like the other lists, so an "array.index("text")" search is not possible + for mid,mtxt in jds6600.__modes: + if mode.upper() == mtxt: + # found it!!! + modeid=mid + break + # end if + else: + # mode not found -> error + raise ValueError(mode) + # end for + # end else - if + + # before changing mode, disable all actions (unless explicitally asked not to do) + if nostop == False: + self.__setaction("STOP") + # endif + + # set mode + self.__sendwritecmd(jds6600.MODE,modeid) + + # if new mode is "burst", reset burst counter + if modeid == 9: + self.burst_resetcounter() + # end if + + # end setmode + + ####################### + # Part 5: functions common for all modes + def stopallactions(self): + # just send stop + self.__setaction("STOP") + # end stop all actions + + + ####################### + # Part 6: "measure" mode + + # get coupling parameter (measure mode) + def measure_getcoupling(self): + coupling=self.__getdata(jds6600.MEASURE_COUP) + + try: + return (coupling,jds6600.__measure_coupling[coupling]) + except IndexError: + raise UnexpectedValueError(coupling) + # end try + # end get coupling (measure mode) + + # get gate time (measure mode) + # get (measure mode) + def measure_getgate(self): + gate=self.__getdata(jds6600.MEASURE_GATE) + + + # gate unit is 0.01 seconds + return gate / 100 + # end get gate (measure mode) + + + # get Measure mode (freq or period) + def measure_getmode(self): + mode=self.__getdata(jds6600.MEASURE_MODE) + + try: + return (mode,jds6600.__measure_mode[mode]) + except IndexError: + raise UnexpectedValueError(mode) + # end try + # end get mode (measure) + + + + # set measure coupling + def measure_setcoupling(self,coupling): + # type checks + if (type(coupling) != int) and (type(coupling) != str): raise TypeError(coupling) + + + if type(coupling) == int: + # coupling is 0 (DC) or 1 (AC) + if not (coupling in (0,1)): + raise ValueError(coupling) + + coupl=coupling + + else: + # string based + + coupling=coupling.upper() + # spme shortcuts: + if coupling == "AC": coupling = "AC(EXT.IN)" + if coupling == "DC": coupling = "DC(EXT.IN)" + + try: + coupl=jds6600.__measure_coupling.index(coupling) + except ValueError: + errmsg="Unknown measure-mode coupling: "+coupling + raise ValueError(errmsg) + # end try + # end else ) if (type is int or str?) + + # set mode + self.__sendwritecmd(jds6600.MEASURE_COUP,coupl) + + # end set measure_coupling + + # set gate time (measure mode) + def measure_setgate(self, gate): + # check type + if (type(gate) != int) and (type(gate) != float): raise TypeError(gate) + + # gate unit is 0.01 and is between 0 and 10 + if not (0 < gate <= 1000): + raise ValueError(gate) + + gate = int(round(gate*100)) + + # minimum is 0.01 second + if gate == 0: + gate = 0.01 + + # set gate + self.__sendwritecmd(jds6600.MEASURE_GATE,gate) + # end get gate (measure mode) + + + # set measure mode + def measure_setmode(self,mode): + # type checks + if (type(mode) != int) and (type(mode) != str): raise TypeError(mode) + + + if type(mode) == int: + # mode is 0 (M.FREQ) or 1 (M.PRERIOD) + if not (mode in (0,1)): + raise ValueError(mode) + + else: + # string based + + # make uppercase + mode=mode.upper() + + # spme shortcuts: + if mode== "FREQ": mode = "M.FREQ" + if mode== "PERIOD": mode = "M.PERIOD" + + try: + mode=jds6600.__measure_mode.index(mode) + except ValueError: + errmsg="Unknown measure mode: "+mode + raise ValueError(errmsg) + # end try + + # end else ) if (type is int or str?) + + # set mode + self.__sendwritecmd(jds6600.MEASURE_MODE,mode) + + # end set measure_coupling + + # get Measure freq. (lowres / Freq-mode) + def measure_getfreq_f(self): + freq=self.__getdata(jds6600.MEASURE_DATA_FREQ_LOWRES) + + # unit is 0.1 Hz + return freq/10 + # end get freq-Lowres (measure) + + # get Measure freq. (highes / Periode-mode) + def measure_getfreq_p(self): + freq=self.__getdata(jds6600.MEASURE_DATA_FREQ_HIGHRES) + + # unit is 0.001 Hz + return freq/1000 + # end get freq-Lowres (measure) + + # get Measure pulsewith + + def measure_getpw1(self): + pw=self.__getdata(jds6600.MEASURE_DATA_PW1) + + # unit is 0.01 microsecond + return pw/100 + # end get pulsewidth - + + # get Measure pulsewidth - + def measure_getpw0(self): + pw=self.__getdata(jds6600.MEASURE_DATA_PW0) + + # unit is 0.01 microsecond + return pw/100 + # end get pulsewidth + + + # get Measure total period + def measure_getperiod(self): + period=self.__getdata(jds6600.MEASURE_DATA_PERIOD) + + # unit is 0.01 microsecond + return period/100 + # end get total period + + # get Measure dutycycle + def measure_getdutycycle(self): + dutycycle=self.__getdata(jds6600.MEASURE_DATA_DUTYCYCLE) + + # unit is 0.1 % + return dutycycle/10 + # end get freq-Lowres (measure) + + # get Measure unknown value 1 (related to freq, inverse-related to gatetime) + def measure_getu1(self): + # unit is unknown, just return it + return self.__getdata(jds6600.MEASURE_DATA_U1) + # end get freq-Lowres (measure) + + # get Measure unknown value 2 (inverse related to freq) + def measure_getu2(self): + # unit is unknown, just return it + return self.__getdata(jds6600.MEASURE_DATA_U2) + # end get freq-Lowres (measure) + + # get Measure unknown value 3 (nverse related to freq) + def measure_getu3(self): + # unit is unknown, just return it + return self.__getdata(jds6600.MEASURE_DATA_U3) + # end get freq-Lowres (measure) + + + # get Measure all (all usefull data: freq_f, freq_p, pw1, pw0, period, dutycycle + def measure_getall(self): + + # do query for 6 values (start with freq_q) + (freq_f, freq_p, pw1, pw0, period, dutycycle)=self.__getdata(jds6600.MEASURE_DATA_FREQ_LOWRES,6) + + # return all + return (freq_f / 10, freq_p / 1000, pw1/100, pw0/100, period/100, dutycycle/10) + # end get freq-Lowres (measure) + + + + ####################### + # Part 7: "Counter" mode + + # counter getcoupling is the same as measure getcoupling + def counter_getcoupling(self): + return self.measure_getcoupling() + # end counter get coupling + + # get counter - counter + def counter_getcounter(self): + # unit is 1, just return data + return self.__getdata(jds6600.COUNTER_DATA_COUNTER) + # end get counter - counter + + # counter setcoupling is the same as measure setcoupling + def counter_setcoupling(self,coupling): + self.measure_setcoupling(coupling) + # end counter get coupling + + + # counter - reset counter + def counter_reset(self): + # write 0 to register "COUNTER_RESETCOUNTER" + self.__sendwritecmd(jds6600.COUNTER_RESETCOUNTER,0) + # end counter reset counter + + # start counter mode + def counter_start(self): + mode=self.getmode() + + if mode[1] != "COUNTER": + raise WrongMode() + # end if + + # action start BURST mode + self.__setaction("COUNT") + # end counter_start + + + def counter_stop(self): + # just send stop + self.__setaction("STOP") + # end counter_stop + + + + + + ####################### + # Part 8: "Sweep" mode + + # note, there are two "setmode" commands to enter "sweep" mode: "sweep_ch1' (mode 6) and "sweep_ch2" (mode 7) + + def sweep_getstartfreq(self): + # unit is 0.01Hz -> divide by 100 + return self.__getdata(jds6600.SWEEP_STARTFREQ)/100 + # end get sweep - startfreq + + def sweep_getendfreq(self): + # unit is 0.01 Hz -> divide by 100 + return self.__getdata(jds6600.SWEEP_ENDFREQ)/100 + # end get sweep - startfreq + + def sweep_gettime(self): + # unit is 0.1 sec -> divide by 10 + return self.__getdata(jds6600.SWEEP_TIME)/10 + # end get sweep - startfreq + + + # get sweep direction + def sweep_getdirection(self): + direction=self.__getdata(jds6600.SWEEP_DIRECTION) + + try: + return (direction,jds6600.__sweep_direction[direction]) + except IndexError: + raise UnexpectedValueError(direction) + # end try + # end get direction (sweep) + + # get sweep mode + def sweep_getmode(self): + mode=self.__getdata(jds6600.SWEEP_MODE) + + try: + return (mode,jds6600.__sweep_mode[mode]) + except IndexError: + raise UnexpectedValueError(mode) + # end try + # end get mode (measure) + + def sweep_setstartfreq(self, frequency): + if (type(frequency) != int) and (type(frequency) != float): raise TypeError(frequency) + + # frequency should be between 0 and 60 MHz + if not (0 <= frequency <= 60000000): + raise ValueError(frequency) + + # frequency unit is 0.01 Hz + freq=int(round(frequency*100)) + + self.__sendwritecmd(jds6600.SWEEP_STARTFREQ,freq) + # end set start freq + + def sweep_setendfreq(self, frequency): + if (type(frequency) != int) and (type(frequency) != float): raise TypeError(frequency) + + # frequency should be between 0 and 60 MHz + if not (0 <= frequency <= 60000000): + raise ValueError(frequency) + + # frequency unit is 0.01 Hz + freq=int(round(frequency*100)) + + self.__sendwritecmd(jds6600.SWEEP_ENDFREQ,freq) + # end set end freq + + + def sweep_settime(self, time): + if (type(time) != int) and (type(time) != float): raise TypeError(time) + + # time should be between 0 and 999.9 seconds + if not (0 < time <= 999.9): + raise ValueError(time) + + # time unit is 0.1 second + t=int(round(time*10)) + + self.__sendwritecmd(jds6600.SWEEP_TIME,t) + # end set end freq + + + def sweep_setdirection(self, direction): + if (type(direction) != int) and (type(direction) != str): raise TypeError(direction) + + if type(direction) == int: + # mode is 0 (RISE), 1 (FALL) or 2 (RISE&FALL) + if not (direction in (0,1,2)): + raise ValueError(direction) + + else: + # string based + + # make uppercase + direction=direction.upper() + + # spme shortcuts: + if direction == "RISEFALL": direction = "RISE&FALL" + if direction == "BOTH": direction = "RISE&FALL" + + try: + direction=jds6600.__sweep_direction.index(direction) + except ValueError: + errmsg="Unknown sweep direction: "+direction + raise ValueError(errmsg) + # end else - for + # end else ) if (type is int or str?) + + # set mode + self.__sendwritecmd(jds6600.SWEEP_DIRECTION,direction) + # end set direction (sweep) + + + def sweep_setmode(self, mode): + if (type(mode) != int) and (type(mode) != str): raise TypeError(mode) + + if type(mode) == int: + # mode is 0 (LINEAR) or 1 (LOGARITHM)) + if not (mode in (0,1)): + raise ValueError(mode) + + else: + # string based + + # make uppercase + mode=mode.upper() + + # spme shortcuts: + if mode == "LIN": mode = "LINEAR" + if mode == "LOG": mode = "LOGARITHM" + + try: + mode=jds6600.__sweep_mode.index(mode) + except ValueError: + errmsg="Unknown sweep mode: "+mode + raise ValueError(errmsg) + # end else - for + # end else ) if (type is int or str?) + + # set mode + self.__sendwritecmd(jds6600.SWEEP_MODE,mode) + # end set direction (sweep) + + + + + # get sweep channel + def sweep_getchannel(self): + mode=self.getmode() + + if mode[1] == "SWEEP_CH1": + return 1 + elif mode[1] == "SWEEP_CH2": + return 2 + # end if - elif + + # not channel 1 or channel 2, return 0 + return 0 + # end sweep get_channel + + # set sweep channel + def sweep_setchannel(self,channel): + if type(channel) != int: raise TypeError(channel) + + # new channel should be 1 or 2 + if not (channel in (1,2)): + raise ValueError(channel) + # end if + + # get current channel (1 or 2, or 0 if not in sweep mode) + currentchannel=self.sweep_getchannel() + + # only swich if already in sweep mode + if currentchannel == 0: + raise WrongMode() + #endif + + # switch if the new channel is different from current channel + if channel != currentchannel: + if channel == 1: + self.setmode("SWEEP_CH1",nostop=True) + else: + self.setmode("SWEEP_CH2",nostop=True) + # end else - if + # end if + # end sweep set channel + + + # start sweep + def sweep_start(self): + mode=self.getmode() + + if (mode[1] != "SWEEP_CH1") and (mode[1] != "SWEEP_CH2"): + raise WrongMode() + # end if + + # action start BURST mode + self.__setaction("SWEEP") + # end sweep_start + + + # stop sweep + def sweep_stop(self): + # just send stop + self.__setaction("STOP") + # end sweep_start + + + + ################################## + + + ####################### + # Part 9: PULSE + + + # get pulsewidth, normalised to s + def pulse_getpulsewidth(self): + # pulsewith returns two datafiels, periode + multiplier + time,multi = self.__getdata(jds6600.PULSE_PULSEWIDTH) + + if multi==0: return time / 1000000000 # ns + elif multi == 1: return time / 1000000 # us + else: + UnexptectedValue(multi) + # end else - elsif - if + # end + + # get pulsewidth, not normalised + def pulse_getpulsewidth_m(self): + # pulsewith returns two datafiels, periode + multiplier + return self.__getdata(jds6600.PULSE_PULSEWIDTH) + # end + + + # get period, normalised to s + def pulse_getperiod(self): + # period returns two datafiels, periode + multiplier + time,multi = self.__getdata(jds6600.PULSE_PERIOD) + + if multi==0: return time / 1000000000 # ns + elif multi == 1: return time / 1000000 # us + else: + UnexptectedValue(multi) + # end else - elsif - if + # end + + + # get period, not normalised + def pulse_getperiod_m(self): + # period returns two datafiels, periode + multiplier + return self.__getdata(jds6600.PULSE_PERIOD) + # end + + # get offset + def pulse_getoffset(self): + # unit is %, just return data + return self.__getdata(jds6600.PULSE_OFFSET) + # end + + # get amplitude + def pulse_getamplitude(self): + # unit 0.01, divide by 100 + return self.__getdata(jds6600.PULSE_AMPLITUDE)/100 + # end + + # set pulsewith or period (backend function) + def __pulse_setpw_period(self, var, data, multiplier, normalised): + maxval=([4e9,4e9],(4,4000)) # maximum data value + minval=((30,1),(30e-9,1e-6)) # minimum data value + multi=(1e9,1e6) # unit is 1ns or 1 us + data2reg=(jds6600.PULSE_PULSEWIDTH,jds6600.PULSE_PERIOD) + data2txt=("pulsewidth","period") + + if (type(var) != int) or ((var != 0) and (var != 1)): raise RuntimeError("error __pulse_setpw_period: var") # var is 0 (for pulsewidth) or 1 (period) + if (type(data) != int) and (type(data) != float): raise TypeError(period) + if (type(normalised) != int) or not (normalised in (0,1)): raise RuntimeError("error __pulse_setpw_period: normalised") + + if type(multiplier) != int: raise TypeError(multiplier) + + # multiplier should be 0 or 1 + if not (multiplier in (0,1)): + errmsg="multiplier must be 0 (ns) or 1 (us)" + raise ValueError(errmsg) + # end if + + # data must be between to allocated limits: + # not normalised: allowed values: 30 to 400000000 (multi=0) / 1 to 4000000000 (multi=1) + # normalised: allowed values: 30 ns to 4 sec. (multi=0) / 1 us to 4000 sec (multi=2) + if not (minval[normalised][multiplier] <= data <= maxval[normalised][multiplier]): + errmsg="{} must be between {} and {}".format(data2txt[var],minval[normalised][multiplier],maxval[normalised][multiplier]) + raise ValueError(errmsg) + # end if + + + # convert from s to ns/us, if needed + if normalised == 1: + data = str(round(data * multi[multiplier]))+","+str(multiplier) + else: + data = str(int(data))+","+str(multiplier) + # end if + + # done: now write + self.__sendwritecmd(data2reg[var],data) + # end set pw/period, low-level function + + + # set pw, normalised + def pulse_setpulsewidth(self,pw,multiplier=0): + # convert to low-level function + self.__pulse_setpw_period(0,pw,multiplier,1) + # end pulse_setpw (normalised) + + # set pw, not normalised + def pulse_setpulsewidth_m(self,pw,multiplier): + # convert to low-level function + self.__pulse_setpw_period(0,pw,multiplier,0) + # end pulse_setpw (normalised) + + # set period, normalised + def pulse_setperiod(self,pw,multiplier=0): + # convert to low-level function + self.__pulse_setpw_period(1,pw,multiplier,1) + # end pulse_setperiod (normalised) + + # set period, not normalised + def pulse_setperiod_m(self,pw,multiplier): + # convert to low-level function + self.__pulse_setpw_period(1,pw,multiplier,0) + # end pulse_setperiod (normalised) + + + # set pulse offset + def pulse_setoffset(self,offset): + if (type(offset) != int) and (type(offset) != float): raise TypeError(offset) + + # offset is between 0 and 120 % + if not (0 <= offset <= 120): + errmsg="Offset must be between 0 and 120 %" + raise ValueError(errmsg) + # end if + + # unit = 1 -> just send + self.__sendwritecmd(jds6600.PULSE_OFFSET,offset) + # end off + + + # set pulse amplitude + def pulse_setamplitude(self,amplitude): + if (type(amplitude) != int) and (type(amplitude) != float): raise TypeError(amplitude) + + # amplitude is between 0 and 10 V + if not (0 <= amplitude <= 10): + errmsg="Amplitude must be between 0 and 10 Volt" + raise ValueError(errmsg) + # end if + + # unit is 0.01V + amplitude=int(round(amplitude*100)) + self.__sendwritecmd(jds6600.PULSE_AMPLITUDE,amplitude) + # end off + + + def pulse_start(self): + mode=self.getmode() + + if mode[1] != "PULSE": + raise WrongMode() + # end if + + # action start BURST mode + self.__setaction("PULSE") + # end pulse_start + + + def pulse_stop(self): + # just send stop + self.__setaction("STOP") + # end pulse_stop + + + ####################### + # Part 10: BURST + + + def burst_getnumberofbursts(self): + # unit is 1, just return value + return self.__getdata(jds6600.BURST_NUMBER) + # end burst get number of bursts + + def burst_getmode(self): + mode = self.__getdata(jds6600.BURST_MODE) + + try: + return(mode,jds6600.__burst_mode[mode]) + except IndexError: + raise UnexpectedValue(mode) + + # end try + # end burst get mode + + + def burst_setnumberofbursts(self,burst): + if type(burst) != int: raise TypeError(burst) + + # number of burst should be between 1 and 1048575 + if not (1 <= burst <= 1048575): + errmsg="Number of bursts should be between 1 and 1048575" + raise ValueError(errmsg) + # end if + + # unit is 1, just return value + self.__sendwritecmd(jds6600.BURST_NUMBER,burst) + # end burst get number of bursts + + + def burst_setmode(self,mode): + if (type(mode) != int) and (type(mode) != str): raise TypeError(mode) + + if type(mode) == int: + # mode input is an integer + # mode should be between 0 and 3 + if not (0 <= mode <= 3): + errmsg="Burst mode should between 0 and 3" + raise ValueError(mode) + # end if + else: + # mode input is a string + + mode=mode.upper() + + # shortcuts + if mode == "MANUAL": mode = "MANUAL TRIG." + if mode == "CH2": mode = "CH2 TRIG." + if mode == "EXT.AC": mode = "EXT.TRIG(AC)" + if mode == "EXT.DC": mode = "EXT.TRIG(DC)" + + try: + mode=jds6600.__burst_mode.index(mode.upper()) + except ValueError: + errmsg="Unknown burst mode: "+mode + raise ValueError(errmsg) + # end try + + # end else - if + + # stop if the burst-mode is running + self.burst_stop() + + # write command + self.__sendwritecmd(jds6600.BURST_MODE,mode) + + def burst_resetcounter(self): + # reset counter: same as counter_reset_counter + self.counter_reset() + # end reset counter + + + def burst_start(self): + mode=self.getmode() + + if mode[1] != "BURST": + raise WrongMode() + # end if + + # action start BURST mode + self.__setaction("BURST") + # end burst_start + + + def burst_stop(self): + # just send stop + self.__setaction("STOP") + # end burst_start + + ####################### + # Part 11: SYSTEM + + ######## + # part 11.1: system parameters + + # NOTE: there is a strange behaviour in some jds6600 devices where that the register to + # read the sysem-parameters is one higher then the registernumber use to write + # the parameter-value. + # This is probably a bug. The bug-fix code to deal with this situation can be + # be overwriten adding a "bugfix=0" option in the system_get* API-calls + + # get sound setting + def system_getsound(self, bugfix=True): + if bugfix == True: + sound=self.__getdata(jds6600.SYSTEM_SOUND+1) + elif bugfix == False: + sound=self.__getdata(jds6600.SYSTEM_SOUND) + else: TypeError(bugfix) + + # we should receive a 0 or 1 + try: + return (False,True)[sound] + except IndexError: + raise UnexpectedValueError(sound) + #end system_getsound + + # get brightness setting + def system_getbrightness(self, bugfix=True): + if bugfix == True: + return self.__getdata(jds6600.SYSTEM_BRIGHTNESS+1) + elif bugfix == False: + return self.__getdata(jds6600.SYSTEM_BRIGHTNESS) + else: TypeError(bugfix) + #end system_getbrightness + + # get language setting + def system_getlanguage(self, bugfix=True): + if bugfix == True: + language=self.__getdata(jds6600.SYSTEM_LANGUAGE+1) + elif bugfix == False: + language=self.__getdata(jds6600.SYSTEM_LANGUAGE) + else: TypeError(bugfix) + + # we should receive a 0 or a 1 + try: + return language,jds6600.__system_language[language] + except KeyError: + raise UnexpectedValueError(sound) + #end system_getlanguage + + def system_getsync(self, bugfix=True): + if bugfix == True: + sync=self.__getdata(jds6600.SYSTEM_SYNC+1) + elif bugfix == False: + sync=self.__getdata(jds6600.SYSTEM_SYNC) + else: TypeError(bugfix) + + # returns a list of 5 fields: frequency, wave, amplitude, dutycycle and offset + if len(sync) != 5: + raise UnexpectedValueError(sync) + # end if + + # return data + ret=[] + for s in sync: + if s not in (0,1): raise UnexpectedValueError(sync) + + ret.append((False,True)[s]) + # end for + + # return data + return ret + # end system_getsync + + + # get maximum number of arbitrary waveforms + def system_getarbmaxnum(self, bugfix=True): + if bugfix == True: + return self.__getdata(jds6600.SYSTEM_ARBMAXNUM+1) + elif bugfix == False: + return self.__getdata(jds6600.SYSTEM_ARBMAXNUM) + else: TypeError(bugfix) + #end system_getlanguage + + + # set system sound + def system_setsound(self,sound): + if type(sound) != bool: raise TypeError(sound) + + if sound == True: + self.__sendwritecmd(jds6600.SYSTEM_SOUND,1) + else: + self.__sendwritecmd(jds6600.SYSTEM_SOUND,0) + # end set sound + + # set system brightness + def system_setbrightness(self,brightness): + if type(brightness) != int: raise TypeError(brightness) + + # should be between 1 and 12 + if not(1 <= brightness <= 12): + raise ValueError(brightness) + + self.__sendwritecmd(jds6600.SYSTEM_BRIGHTNESS,brightness) + # end set sound + + + # set system language + def system_setlanguage(self,language): + if (type(language) != int) and (type(language) != str): raise TypeError(language) + + if type(language) == int: + # integer + if language not in (0,1): raise ValueError(sound) + else: + # string + # shortcuts: + if language == "EN": language = "ENGLISH" + if language == "CH": language = "CHINESE" + + try: + language=jds6600.__system_language.index(language.upper()) + except ValueError: + errmsg="Unknown language: "+language + raise ValueError(errmsg) + # end try + # end else - if + + self.__sendwritecmd(jds6600.SYSTEM_LANGUAGE,language) + + # reinit "mode" to refresh screen for language change to become active + (mode,modetxt)=self.getmode() + self.setmode(mode) + # end set language + + # set system sync + def system_setsync(self,freq,wave,ampl,duty,offs): + + if type(freq) != bool: raise TypeError(freq) + if type(wave) != bool: raise TypeError(wave) + if type(ampl) != bool: raise TypeError(ampl) + if type(duty) != bool: raise TypeError(duty) + if type(offs) != bool: raise TypeError(offs) + + # create command to send + sync=[freq,wave,ampl,duty,offs] + for i in range(5): + sync[i] = '1' if sync[i] == True else '0' + + + # merge all 5 elements in one command, seperated by "," + self.__sendwritecmd(jds6600.SYSTEM_SYNC,",".join(sync)) + # end set sync + + # set maximum number of arbitrary waveforms + def system_setarbmaxnum(self,arbmaxnum): + if type(arbmaxnum) != int: raise TypeError(arbmaxnum) + + # abrmaxnum should be between 1 and 60 + if not(1 <= arbmaxnum <= 60): + raise ValueError(arbmaxnum) + + self.__sendwritecmd(jds6600.SYSTEM_ARBMAXNUM,arbmaxnum) + # end set arbmaxnum + + + + + ###### + # part 11.2: save / read / clear profile + + def system_saveprofile(self,profile): + if type(profile) != int: raise TypeError(profile) + + # profile is between 0 and 99 + if not(0 <= profile <= 99): raise ValueError(errmsg) + + # write profile to "PROFILE_SAVE" + self.__sendwritecmd(jds6600.PROFILE_SAVE,profile) + # end profile save + + def system_loadprofile(self,profile): + if type(profile) != int: raise TypeError(profile) + + # profile is between 0 and 99 + if not(0 <= profile <= 99): raise ValueError(errmsg) + + # write profile to "PROFILE_LOAD" + self.__sendwritecmd(jds6600.PROFILE_LOAD,profile) + # end profile load + + def system_clearprofile(self,profile): + if type(profile) != int: raise TypeError(profile) + + # profile is between 0 and 99 + if not(0 <= profile <= 99): raise ValueError(errmsg) + + # write profile to "PROFILE_CLEAR" + self.__sendwritecmd(jds6600.PROFILE_CLEAR,profile) + # end profile clear + + + + ####################### + # Part 12: Arbitrary waveform operations + + def arb_getwave(self,waveid): + if type(waveid) != int: raise TypeError(waveid) + + # waveid is between 1 and 60 + if not(1 <= waveid <= 60): raise ValueError(waveid) + + # getdata, reg=waveform id, data = 1, a=1 (register/waveform selector) + return self.__getdata(waveid,1,a=1) + # end get arbtrary waveform + + + def arb_setwave(self,waveid,wave): + if type(waveid) != int: raise TypeError(waveid) + if (type(wave) != tuple) and (type(wave) != list): raise TypeError(wave) + + # waveid is between 1 and 60 + if not(1 <= waveid <= 60): raise ValueError(waveid) + + # wave should be a list or tuple of 2048 elements, all integers, with a value between 0 and 4095 + if len(wave) != 2048: raise ValueError(wave) + + tosend="" + for val in wave: + if type(val) != int: raise ValueError(wave) + if not (0 <= val <= 4095): raise ValueError(wave) + + tosend += (str(val) if tosend=="" else ","+str(val)) + # end for + + # write waveform, reg=waveform id, data = waveform, a=1 (register/waveform selector) + self.__sendwritecmd(waveid,tosend,a=1) + + # end set arbirtary waveform + + ################################## + +# end class jds6600 diff --git a/readfreq_influxdb.py b/readfreq_influxdb.py new file mode 100644 index 0000000..48715e3 --- /dev/null +++ b/readfreq_influxdb.py @@ -0,0 +1,101 @@ +from jds6600 import jds6600 +import warnings +import serial +import serial.tools.list_ports +import time +from influxdb import InfluxDBClient +from datetime import datetime +import influxdb_config + +print("-----------------JDS6600-Reader-----------------") +print("Searching Device ...") + +found_ports = [ + p.device + for p in serial.tools.list_ports.comports() + if 'CH340' in p.description or 'USB Serial' in p.description #CH340 for Windows, USB Serial for Linux +] +if not found_ports: + raise IOError("No JDS6600-device found") +if len(found_ports) > 1: + warnings.warn('Multiple JDS6600-devices found - using the first') + +portname = found_ports[0] +print("JDS6600 device found!") +print("Using Port ", portname) + +jds = jds6600(portname) +#jds = jds6600("COM4") + +print("--------------------------") +# API information calls +print("Devicetype: ", jds.getinfo_devicetype()) +print("Serialnumber:", jds.getinfo_serialnumber()) +print("--------------------------") + +#Disable Both outputs +#print(jds.getchannelenable()) +jds.setchannelenable(bool(0), bool(0)) +print("Disabeling Outputs ... \t\t OK") + +#print(jds.getmode()) +jds.setmode('MEASURE') +print("Set Mode Measure ... \t\t OK") + +jds.measure_setcoupling('AC') +jds.measure_setgate(1) #Gatetime 1s +jds.measure_setmode("PERIOD") +print("Configure Measurement ... OK") +print("--------------------------") + + +print("Connecting to Influx-DB ... OK") +dbclient = InfluxDBClient( influxdb_config.influxdb_host, + influxdb_config.influxdb_port, + influxdb_config.influxdb_user, + influxdb_config.influxdb_password, + influxdb_config.influxdb_dbname) +freq_value = 0.0 +dbclient_success = False +dbclient_fail_counter = 0 + +print("--------------------------") +print("Starting to read data ...") +print("--------------------------") + +log_count = 0 + +while 1: + if jds.getmode()[0] != 4: # 4 means mode 'MEASURE' + raise IOError("Measurement-mode is not enabled!") + freq_value = jds.measure_getfreq_p() + + + + json_body = [ + { + "measurement": "freq_Hz", + "fields": { + "value": freq_value + } + } + ] + + dbclient_success = dbclient.write_points(json_body, time_precision='ms') + + if dbclient_success == True: + log_count = log_count + 1 + if log_count >= 10: + print("f = ", freq_value, " DB OK") + log_count = 0 + else: + dbclient_fail_counter = dbclient_fail_counter + 1 + print("f = ", freq_value, " DB ERROR ", dbclient_fail_counter) + if dbclient_fail_counter >= 5: + raise IOError("Writing DB entry failed 5 times ... exiting!") + else: + dbclient_fail_counter = 0 + + + time.sleep(1) + diff --git a/readfreq_terminal.py b/readfreq_terminal.py new file mode 100644 index 0000000..70a58ce --- /dev/null +++ b/readfreq_terminal.py @@ -0,0 +1,54 @@ + +from jds6600 import jds6600 +import warnings +import serial +import serial.tools.list_ports +import time + +print("-----------------JDS6600-Reader-----------------") +print("Searching Device ...") + +found_ports = [ + p.device + for p in serial.tools.list_ports.comports() + if 'CH340' in p.description or 'USB Serial' in p.description #CH340 for Windows, USB Serial for Linux +] +if not found_ports: + raise IOError("No JDS6600-device found") +if len(found_ports) > 1: + warnings.warn('Multiple JDS6600-devices found - using the first') + +portname = found_ports[0] +print("JDS6600 device found!") +print("Using Port ", portname) + +jds = jds6600(portname) +#jds = jds6600("COM4") + +print("--------------------------") +# API information calls +print("Devicetype: ", jds.getinfo_devicetype()) +print("Serialnumber:", jds.getinfo_serialnumber()) +print("--------------------------") + +#Disable Both outputs +#print(jds.getchannelenable()) +jds.setchannelenable(bool(0), bool(0)) +print("Disabeling Outputs ... \t\t OK") + +#print(jds.getmode()) +jds.setmode('MEASURE') +print("Set Mode Measure ... \t\t OK") + +jds.measure_setcoupling('AC') +jds.measure_setgate(1) #Gatetime 1s +jds.measure_setmode("PERIOD") +print("Configure Measurement ... OK") +print("--------------------------") + +while 1: + if jds.getmode()[0] != 4: # 4 means mode 'MEASURE' + raise IOError("Measurement-mode is not enabled!") + print(jds.measure_getfreq_p()) + time.sleep(1) +