From 37f63a0db3f117aa4bbb6bd8d06bc1d6c1e631c4 Mon Sep 17 00:00:00 2001 From: Nanak Bandyopadhyay Date: Wed, 7 Oct 2020 16:14:49 +0530 Subject: [PATCH] Change instanced of ID1/2/3/4 -> LA1/2/3/4 and SEN -> RES and AN8 -> VOL and CNTR -> FRQ and W1/2 -> SI1/2 --- PSL/Peripherals.py | 2 +- PSL/README.md | 118 +++++++++++++++++------------------ PSL/achan.py | 14 ++--- PSL/commands_proto.py | 8 +-- PSL/digital_channel.py | 6 +- PSL/logic_analyzer.py | 58 ++++++++--------- PSL/oscilloscope.py | 8 +-- PSL/sciencelab.py | 48 +++++++------- tests/test_logic_analyzer.py | 40 ++++++------ tests/test_oscilloscope.py | 2 +- 10 files changed, 152 insertions(+), 152 deletions(-) diff --git a/PSL/Peripherals.py b/PSL/Peripherals.py index f224da6e..adfc996c 100644 --- a/PSL/Peripherals.py +++ b/PSL/Peripherals.py @@ -463,7 +463,7 @@ def capture(self, address, location, sample_length, total_samples, tg, *args): >>> from pylab import * >>> I=sciencelab.ScienceLab() - >>> x,y1,y2,y3,y4 = I.capture_multiple(800,1.75,'CH1','CH2','MIC','SEN') + >>> x,y1,y2,y3,y4 = I.capture_multiple(800,1.75,'CH1','CH2','MIC','RES') >>> plot(x,y1) >>> plot(x,y2) >>> plot(x,y3) diff --git a/PSL/README.md b/PSL/README.md index 138d2c80..a3705337 100644 --- a/PSL/README.md +++ b/PSL/README.md @@ -50,7 +50,7 @@ This section has commands related to analog measurement and control. These inclu + Blocking call that fetches an oscilloscope trace from the specified input channel + Arguments - + ch: Channel to select as input. ['CH1'..'CH3','SEN'] + + ch: Channel to select as input. ['CH1'..'CH3','RES'] + ns: Number of samples to fetch. Maximum 10000 + tg: Timegap between samples in microseconds + Return: Arrays X(timestamps),Y(Corresponding Voltage values) @@ -124,7 +124,7 @@ This section has commands related to analog measurement and control. These inclu ``` >>> from pylab import * >>> I = sciencelab.ScienceLab() ->>> x,y1,y2,y3,y4 = I.capture_multiple(800,1.75,'CH1','CH2','MIC','SEN') +>>> x,y1,y2,y3,y4 = I.capture_multiple(800,1.75,'CH1','CH2','MIC','RES') >>> plot(x,y1) >>> plot(x,y2) >>> plot(x,y3) @@ -140,7 +140,7 @@ This section has commands related to analog measurement and control. These inclu + Blocking call that fetches oscilloscope traces from a single oscilloscope channel at a maximum speed of 2MSPS + Arguments - + chan: Channel name 'CH1' / 'CH2' ... 'SEN' + + chan: Channel name 'CH1' / 'CH2' ... 'RES' + samples: Number of samples to fetch. Maximum 10000/(total specified channels) + \*args: Specify if SQR1 must be toggled right before capturing. + 'SET_LOW': Set SQR1 to 0V @@ -344,7 +344,7 @@ The following events take place when the above snippet runs + Return the voltage on the selected channel + Arguments - + channel_name : 'CH1','CH2','CH3', 'MIC','IN1','SEN','V+' + + channel_name : 'CH1','CH2','CH3', 'MIC','IN1','RES','V+' + sleep: Read voltage in CPU sleep mode. not particularly useful. Also, Buggy. + \*\*kwargs: Samples to average can be specified. Eg, samples=100 will average a hundred readings @@ -384,7 +384,7 @@ The following events take place when the above snippet runs + Instruct the ADC to start streaming 8-bit data. use stop_streaming to stop. + Arguments + tg: timegap. 250KHz clock - + channel: channel 'CH1'... 'CH9','IN1','SEN' + + channel: channel 'CH1'... 'CH9','IN1','RES' @@ -402,43 +402,43 @@ This section has commands related to digital measurement and control. These incl
get_high_freq(self, pin) -+ Retrieves the frequency of the signal connected to ID1. For frequencies > 1MHz ++ Retrieves the frequency of the signal connected to LA1. For frequencies > 1MHz + Also good for lower frequencies, but avoid using it since the oscilloscope cannot be used simultaneously due to hardware limitations. + The input frequency is fed to a 32 bit counter for a period of 100mS. + The value of the counter at the end of 100mS is used to calculate the frequency. + Arguments - + pin: The input pin to measure frequency from : ['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + pin: The input pin to measure frequency from : ['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + Return: frequency
-get_freq(self, channel = 'CNTR', timeout = 2) +get_freq(self, channel = 'FRQ', timeout = 2) + Frequency measurement on IDx. + Measures time taken for 16 rising edges of input signal. + Returns the frequency in Hertz + Arguments - + channel: The input to measure frequency from. ['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + channel: The input to measure frequency from. ['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + timeout: This is a blocking call which will wait for one full wavelength before returning the calculated frequency. Use the timeout option if you're unsure of the input signal. Returns 0 if timed out + Return: float: frequency -Connect SQR1 to ID1 +Connect SQR1 to LA1 ``` >>> I.sqr1(4000,25) ->>> self.__print__(I.get_freq('ID1')) +>>> self.__print__(I.get_freq('LA1')) 4000.0 ->>> self.__print__(I.r2r_time('ID1')) +>>> self.__print__(I.r2r_time('LA1')) #time between successive rising edges 0.00025 ->>> self.__print__(I.f2f_time('ID1')) +>>> self.__print__(I.f2f_time('LA1')) #time between successive falling edges 0.00025 ->>> self.__print__(I.pulse_time('ID1')) +>>> self.__print__(I.pulse_time('LA1')) #may detect a low pulse, or a high pulse. Whichever comes first 6.25e-05 ->>> I.duty_cycle('ID1') +>>> I.duty_cycle('LA1') #returns wavelength, high time (0.00025,6.25e-05) ``` @@ -450,7 +450,7 @@ Connect SQR1 to ID1 + Return a list of rising edges that occured within the timeout period. + Arguments - + channel: The input to measure time between two rising edges.['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + channel: The input to measure time between two rising edges.['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + skip_cycle: Number of points to skip. eg. Pendulums pass through light barriers twice every cycle. SO 1 must be skipped + timeout: Number of seconds to wait for datapoints. (Maximum 60 seconds) + Return: list: Array of points @@ -462,7 +462,7 @@ Connect SQR1 to ID1 + Return a list of falling edges that occured within the timeout period. + Arguments - + channel: The input to measure time between two falling edges.['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + channel: The input to measure time between two falling edges.['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + skip_cycle: Number of points to skip. eg. Pendulums pass through light barriers twice every cycle. SO 1 must be skipped + timeout: Number of seconds to wait for datapoints. (Maximum 60 seconds) + Return: list: Array of points @@ -473,11 +473,11 @@ Connect SQR1 to ID1 MeasureInterval(self, channel1, channel2, edge1, edge2, timeout = 0.1) + Measures time intervals between two logic level changes on any two digital inputs(both can be the same) and returns the calculated time. -+ For example, one can measure the time interval between the occurence of a rising edge on ID1, and a falling edge on ID3. ++ For example, one can measure the time interval between the occurence of a rising edge on LA1, and a falling edge on LA3. + If the returned time is negative, it simply means that the event corresponding to channel2 occurred first. + Arguments + channel1: The input pin to measure first logic level change - + channel2: The input pin to measure second logic level change -['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + channel2: The input pin to measure second logic level change -['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + edge1: The type of level change to detect in order to start the timer + 'rising' + 'falling' @@ -493,24 +493,24 @@ Connect SQR1 to ID1
-DutyCycle(self, channel = 'ID1', timeout = 1.) +DutyCycle(self, channel = 'LA1', timeout = 1.) + Duty cycle measurement on channel. Returns wavelength(seconds), and length of first half of pulse(high time) + Low time = (wavelength - high time) + Arguments - + channel: The input pin to measure wavelength and high time.['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + channel: The input pin to measure wavelength and high time.['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + timeout: Use the timeout option if you're unsure of the input signal time period. Returns 0 if timed out + Return: wavelength, duty cycle
-PulseTime(self, channel = 'ID1', PulseType = 'LOW', timeout = 0.1) +PulseTime(self, channel = 'LA1', PulseType = 'LOW', timeout = 0.1) + Duty cycle measurement on channel. Returns wavelength(seconds), and length of first half of pulse(high time) + Low time = (wavelength - high time) + Arguments - + channel: The input pin to measure wavelength and high time.['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + channel: The input pin to measure wavelength and high time.['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + PulseType: Type of pulse to detect. May be 'HIGH' or 'LOW' + timeout: Use the timeout option if you're unsure of the input signal time period. Returns 0 if timed out @@ -525,7 +525,7 @@ Connect SQR1 to ID1 + Arguments + channel1: The input pin to measure first logic level change + channel2: The input pin to measure second logic level change - -['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + -['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + edgeType1: The type of level change that should be recorded + 'rising' + 'falling' @@ -542,7 +542,7 @@ Connect SQR1 to ID1 + SQ1: Set the state of SQR1 output(LOW or HIGH) and then start the timer. eg. SQR1 = 'LOW' + zero: subtract the timestamp of the first point from all the others before returning. Default: True + Return: time -+ Example, Aim : Calculate value of gravity using time of flight. The setup involves a small metal nut attached to an electromagnet powered via SQ1. When SQ1 is turned off, the set up is designed to make the nut fall through two different light barriers(LED,detector pairs that show a logic change when an object gets in the middle) placed at known distances from the initial position. One can measure the timestamps for rising edges on ID1 ,and ID2 to determine the speed, and then obtain value of g. ++ Example, Aim : Calculate value of gravity using time of flight. The setup involves a small metal nut attached to an electromagnet powered via SQ1. When SQ1 is turned off, the set up is designed to make the nut fall through two different light barriers(LED,detector pairs that show a logic change when an object gets in the middle) placed at known distances from the initial position. One can measure the timestamps for rising edges on LA1 ,and LA2 to determine the speed, and then obtain value of g.
@@ -553,8 +553,8 @@ Connect SQR1 to ID1 + Arguments + waiting_time: Total time to allow the logic analyzer to collect data. This is implemented using a simple sleep routine, so if large delays will be involved, refer to :func:`start_one_channel_LA` to start the acquisition, and :func:`fetch_LA_channels` to retrieve data from the hardware after adequate time. The retrieved data is stored in the array self.dchans[0].timestamps. + keyword arguments - + channel: 'ID1',...,'ID4' - + trigger_channel: 'ID1',...,'ID4' + + channel: 'LA1',...,'LA4' + + trigger_channel: 'LA1',...,'LA4' + channel_mode: acquisition mode, default value: 3 + EVERY_SIXTEENTH_RISING_EDGE = 5 + EVERY_FOURTH_RISING_EDGE = 4 @@ -568,22 +568,22 @@ Connect SQR1 to ID1 ``` >>> from pylab import * >>> I = sciencelab.ScienceLab() ->>> I.capture_edges(0.2,channel = 'ID1',trigger_channel = 'ID1',channel_mode = 3,trigger_mode = 3) -#captures rising edges only. with rising edge trigger on ID1 +>>> I.capture_edges(0.2,channel = 'LA1',trigger_channel = 'LA1',channel_mode = 3,trigger_mode = 3) +#captures rising edges only. with rising edge trigger on LA1 ```
-start_one_channel_LA_backup__(self, trigger = 1, channel = 'ID1', maximum_time = 67, **args) +start_one_channel_LA_backup__(self, trigger = 1, channel = 'LA1', maximum_time = 67, **args) -+ Start logging timestamps of rising/falling edges on ID1 ++ Start logging timestamps of rising/falling edges on LA1 + Arguments - + trigger: Bool . Enable edge trigger on ID1. use keyword argument edge = 'rising' or 'falling' - + channel: ['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + trigger: Bool . Enable edge trigger on LA1. use keyword argument edge = 'rising' or 'falling' + + channel: ['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + maximum_time: Total time to sample. If total time exceeds 67 seconds, a prescaler will be used in the reference clock. + kwargs - + triggger_channels: array of digital input names that can trigger the acquisition. Eg, trigger = ['ID1','ID2','ID3'] will triggger when a logic change specified by the keyword argument 'edge' occurs on either or the three specified trigger inputs. + + triggger_channels: array of digital input names that can trigger the acquisition. Eg, trigger = ['LA1','LA2','LA3'] will triggger when a logic change specified by the keyword argument 'edge' occurs on either or the three specified trigger inputs. + edge: 'rising' or 'falling' . trigger edge type for trigger_channels. + Return: Nothing @@ -592,9 +592,9 @@ Connect SQR1 to ID1
start_one_channel_LA(self, **args) -+ Start logging timestamps of rising/falling edges on ID1 ++ Start logging timestamps of rising/falling edges on LA1 + Arguments - + channel: ['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + channel: ['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + channel_mode: Acquisition mode, default value: 1 + EVERY_SIXTEENTH_RISING_EDGE = 5 + EVERY_FOURTH_RISING_EDGE = 4 @@ -609,11 +609,11 @@ Connect SQR1 to ID1
start_two_channel_LA(self, **args) -+ Start logging timestamps of rising/falling edges on ID1, AD2 ++ Start logging timestamps of rising/falling edges on LA1, AD2 + Arguments - + trigger: Bool. Enable rising edge trigger on ID1 + + trigger: Bool. Enable rising edge trigger on LA1 + \*\*args - + chans: Channels to acquire data from . default ['ID1','ID2'] + + chans: Channels to acquire data from . default ['LA1','LA2'] + mode: modes for each channel. Array, default value: [1,1] + EVERY_SIXTEENTH_RISING_EDGE = 5 + EVERY_FOURTH_RISING_EDGE = 4 @@ -629,10 +629,10 @@ Connect SQR1 to ID1
start_three_channel_LA(self, **args) -+ Start logging timestamps of rising/falling edges on ID1, ID2, ID3 ++ Start logging timestamps of rising/falling edges on LA1, LA2, LA3 + Arguments + \*\*args - + trigger_channel: ['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + trigger_channel: ['LA1','LA2','LA3','LA4','RES','EXT','FRQ'] + mode: modes for each channel. Array, default value: [1,1,1] + EVERY_SIXTEENTH_RISING_EDGE = 5 + EVERY_FOURTH_RISING_EDGE = 4 @@ -649,9 +649,9 @@ Connect SQR1 to ID1
start_four_channel_LA(self, trigger = 1, maximum_time = 0.001, mode = [1, 1, 1, 1], **args) -+ Four channel Logic Analyzer. Start logging timestamps from a 64MHz counter to record level changes on ID1,ID2,ID3,ID4. ++ Four channel Logic Analyzer. Start logging timestamps from a 64MHz counter to record level changes on LA1,LA2,LA3,LA4. + Arguments - + trigger: Bool . Enable rising edge trigger on ID1 + + trigger: Bool . Enable rising edge trigger on LA1 + maximum_time: Maximum delay expected between two logic level changes.
If total time exceeds 1 mS, a prescaler will be used in the reference clock. However, this only refers to the maximum time between two successive level changes. If a delay larger than .26 S occurs, it will be truncated by modulo .26 S.
If you need to record large intervals, try single channel/two channel modes which use 32 bit counters capable of time interval up to 67 seconds. @@ -673,7 +673,7 @@ If you need to record large intervals, try single channel/two channel modes whic get_LA_initial_states(self) + Fetches the initial states of digital inputs that were recorded right before the Logic analyzer was started, and the total points each channel recorded -+ Returns: chan1 progress,chan2 progress,chan3 progress,chan4 progress,[ID1,ID2,ID3,ID4]. eg. [1,0,1,1] ++ Returns: chan1 progress,chan2 progress,chan3 progress,chan4 progress,[LA1,LA2,LA3,LA4]. eg. [1,0,1,1]
@@ -725,24 +725,24 @@ If you need to record large intervals, try single channel/two channel modes whic get_states(self) + Gets the state of the digital inputs. -+ Returns: dictionary with keys 'ID1','ID2','ID3','ID4' ++ Returns: dictionary with keys 'LA1','LA2','LA3','LA4'
get_state(self, input_id) -+ Returns the logic level on the specified input (ID1,ID2,ID3, or ID4) ++ Returns the logic level on the specified input (LA1,LA2,LA3, or LA4) + Arguments + input_id: the input channel - + 'ID1' -> state of ID1 - + 'ID4' -> state of ID4 + + 'LA1' -> state of LA1 + + 'LA4' -> state of LA4 + Return: boolean ``` >>> from pylab import * >>> I = sciencelab.ScienceLab() ->>> self.__print__(I.get_state(I.ID1)) +>>> self.__print__(I.get_state(I.LA1)) False ``` @@ -763,11 +763,11 @@ If you need to record large intervals, try single channel/two channel modes whic
-countPulses(self, channel = 'SEN') +countPulses(self, channel = 'RES') + Count pulses on a digital input. Retrieve total pulses using readPulseCount + Arguments - + channel: The input pin to measure rising edges on : ['ID1','ID2','ID3','ID4','SEN','EXT','CNTR'] + + channel: The input pin to measure rising edges on : ['LA1','LA2','LA3','LA4','RES','EXT','FRQ']
@@ -884,14 +884,14 @@ If you need to record large intervals, try single channel/two channel modes whic ## WAVEGEN SECTION -This section has commands related to waveform generators W1, W2, PWM outputs, servo motor control etc. +This section has commands related to waveform generators SI1, SI2, PWM outputs, servo motor control etc.
set_wave(self, chan, freq) + Set the frequency of wavegen + Arguments - + chan: Channel to set frequency for. W1 or W2 + + chan: Channel to set frequency for. SI1 or SI2 + frequency: Frequency to set on wave generator + Returns: frequency @@ -943,7 +943,7 @@ This section has commands related to waveform generators W1, W2, PWM outputs, se + Set the frequency of wavegen 1 + Arguments - + chan: Any of W1,W2,SQR1,SQR2,SQR3,SQR4 + + chan: Any of SI1,SI2,SQR1,SQR2,SQR3,SQR4 + Returns: frequency
@@ -965,16 +965,16 @@ This section has commands related to waveform generators W1, W2, PWM outputs, se + Load an arbitrary waveform to the waveform generators + Arguments - + chan: The waveform generator to alter. W1 or W2 + + chan: The waveform generator to alter. SI1 or SI2 + function: A function that will be used to generate the datapoints + span: The range of values in which to evaluate the given function ``` fn = lambda x:abs(x-50) #Triangular waveform -self.I.load_waveform('W1',fn,[0,100]) +self.I.load_waveform('SI1',fn,[0,100]) #Load triangular wave to wavegen 1 #Load sinusoidal wave to wavegen 2 -self.I.load_waveform('W2',np.sin,[0,2*np.pi]) +self.I.load_waveform('SI2',np.sin,[0,2*np.pi]) ```
@@ -984,7 +984,7 @@ self.I.load_waveform('W2',np.sin,[0,2*np.pi]) + Load an arbitrary waveform table to the waveform generators + Arguments - + chan: The waveform generator to alter. 'W1' or 'W2' + + chan: The waveform generator to alter. 'SI1' or 'SI2' + points: A list of 512 datapoints exactly + mode: Optional argument. Type of waveform. default value 'arbit'. accepts 'sine', 'tria' @@ -1258,7 +1258,7 @@ Set servo motor angles via SQ1-4. Control one stepper motor using SQ1-4 + Read data from ultrasonic distance sensor HC-SR04/HC-SR05. Sensors must have separate trigger and output pins. + First a 10uS pulse is output on SQR1. SQR1 must be connected to the TRIG pin on the sensor prior to use. -+ Upon receiving this pulse, the sensor emits a sequence of sound pulses, and the logic level of its output pin(which we will monitor via ID1) is also set high. The logic level goes LOW when the sound packet returns to the sensor, or when a timeout occurs. ++ Upon receiving this pulse, the sensor emits a sequence of sound pulses, and the logic level of its output pin(which we will monitor via LA1) is also set high. The logic level goes LOW when the sound packet returns to the sensor, or when a timeout occurs. + The ultrasound sensor outputs a series of 8 sound pulses at 40KHz which corresponds to a time period of 25uS per pulse. These pulses reflect off of the nearest object in front of the sensor, and return to it. The time between sending and receiving of the pulse packet is used to estimate the distance. If the reflecting object is either too far away or absorbs sound, less than 8 pulses may be received, and this can cause a measurement error of 25uS which corresponds to 8mm. + Ensure 5V supply. You may set SQR2 to HIGH [ I.set_state(SQR2 = True) ] , and use that as the power supply. + Return: 0 upon timeout diff --git a/PSL/achan.py b/PSL/achan.py index f8003d40..29efb74e 100644 --- a/PSL/achan.py +++ b/PSL/achan.py @@ -23,8 +23,8 @@ "CH3", "MIC", "CAP", - "SEN", - "AN8", + "RES", + "VOL", ) INPUT_RANGES = { @@ -33,8 +33,8 @@ "CH3": (-3.3, 3.3), # external gain control analog input "MIC": (-3.3, 3.3), # connected to MIC amplifier "CAP": (0, 3.3), - "SEN": (0, 3.3), - "AN8": (0, 3.3), + "RES": (0, 3.3), + "VOL": (0, 3.3), } PIC_ADC_MULTIPLEX = { @@ -43,9 +43,9 @@ "CH3": 1, "MIC": 2, "AN4": 4, - "SEN": 7, + "RES": 7, "CAP": 5, - "AN8": 8, + "VOL": 8, } @@ -54,7 +54,7 @@ class AnalogInput: Parameters ---------- - name : {'CH1', 'CH2', 'CH3', 'MIC', 'CAP', 'SEN', 'AN8'} + name : {'CH1', 'CH2', 'CH3', 'MIC', 'CAP', 'RES', 'VOL'} Name of the analog channel to model. device : :class:`Handler` Serial interface for communicating with the PSLab device. diff --git a/PSL/commands_proto.py b/PSL/commands_proto.py index 04687c76..1e204aea 100644 --- a/PSL/commands_proto.py +++ b/PSL/commands_proto.py @@ -113,10 +113,10 @@ GET_STATE = Byte.pack(1) GET_STATES = Byte.pack(2) -ID1 = Byte.pack(0) -ID2 = Byte.pack(1) -ID3 = Byte.pack(2) -ID4 = Byte.pack(3) +LA1 = Byte.pack(0) +LA2 = Byte.pack(1) +LA3 = Byte.pack(2) +LA4 = Byte.pack(3) LMETER = Byte.pack(4) # /*------TIMING FUNCTIONS-----*/ diff --git a/PSL/digital_channel.py b/PSL/digital_channel.py index d160a19b..67bf94e9 100644 --- a/PSL/digital_channel.py +++ b/PSL/digital_channel.py @@ -3,7 +3,7 @@ import numpy as np -DIGITAL_INPUTS = ("ID1", "ID2", "ID3", "ID4", "SEN", "EXT", "CNTR") +DIGITAL_INPUTS = ("LA1", "LA2", "LA3", "LA4", "RES", "EXT", "FRQ") MODES = { "sixteen rising": 5, @@ -20,13 +20,13 @@ class DigitalInput: Parameters ---------- - name : {"ID1", "ID2", "ID3", "ID4", "SEN", "EXT", "CNTR"} + name : {"LA1", "LA2", "LA3", "LA4", "RES", "EXT", "FRQ"} Name of the digital channel to model. Attributes ---------- name : str - One of {"ID1", "ID2", "ID3", "ID4", "SEN", "EXT", "CNTR"}. + One of {"LA1", "LA2", "LA3", "LA4", "RES", "EXT", "FRQ"}. number : int Number used to refer to this channel in the firmware. datatype : str diff --git a/PSL/logic_analyzer.py b/PSL/logic_analyzer.py index 6030c398..9df2b076 100644 --- a/PSL/logic_analyzer.py +++ b/PSL/logic_analyzer.py @@ -52,13 +52,13 @@ def __init__(self, device: packet_handler.Handler = None): self._channels = { d: digital_channel.DigitalInput(d) for d in digital_channel.DIGITAL_INPUTS } - self.trigger_channel = "ID1" - self._trigger_channel = self._channels["ID1"] + self.trigger_channel = "LA1" + self._trigger_channel = self._channels["LA1"] self.trigger_mode = "disabled" self._trigger_mode = 0 self._prescaler = 0 - self._channel_one_map = "ID1" - self._channel_two_map = "ID2" + self._channel_one_map = "LA1" + self._channel_two_map = "LA2" self._trimmed = 0 def measure_frequency( @@ -68,7 +68,7 @@ def measure_frequency( Parameters ---------- - channel : {"ID1", "ID2", "ID3", "ID4"} + channel : {"LA1", "LA2", "LA3", "LA4"} Name of the digital input channel in which to measure the frequency. simultaneous_oscilloscope: bool, optional Set this to True if you need to use the oscilloscope at the same time. @@ -145,7 +145,7 @@ def measure_interval( Parameters ---------- channels : List[str] - A pair of digital inputs, ID1, ID2, ID3, or ID4. Both can be the same. + A pair of digital inputs, LA1, LA2, LA3, or LA4. Both can be the same. modes : List[str] Type of logic event to listen for on each channel. See :class:`DigitalInput` for available modes. @@ -209,7 +209,7 @@ def measure_duty_cycle(self, channel: str, timeout: float = 1) -> Tuple[float]: Parameters ---------- - channel : {"ID1", "ID2", "ID3", "ID4"} + channel : {"LA1", "LA2", "LA3", "LA4"} Digital input on which to measure. timeout : float, optional Timeout in seconds before cancelling measurement. The default value is @@ -251,8 +251,8 @@ def capture( Parameters ---------- channels : {1, 2, 3, 4} - Number of channels to capture events on. Events will be captured on ID1, - ID2, ID3, and ID4, in that order. + Number of channels to capture events on. Events will be captured on LA1, + LA2, LA3, and LA4, in that order. events : int, optional Number of logic events to capture on each channel. The default and maximum value is 2500. @@ -302,7 +302,7 @@ def capture( start_time = time.time() for e, c in enumerate( - [self._channel_one_map, self._channel_two_map, "ID3", "ID4"][:channels] + [self._channel_one_map, self._channel_two_map, "LA3", "LA4"][:channels] ): c = self._channels[c] c.events_in_buffer = events @@ -396,10 +396,10 @@ def _capture_four(self, e2e_time: float): self._device.send_byte(CP.START_FOUR_CHAN_LA) self._device.send_int(CP.MAX_SAMPLES // 4) self._device.send_int( - self._channels["ID1"]._logic_mode - | (self._channels["ID2"]._logic_mode << 4) - | (self._channels["ID3"]._logic_mode << 8) - | (self._channels["ID4"]._logic_mode << 12) + self._channels["LA1"]._logic_mode + | (self._channels["LA2"]._logic_mode << 4) + | (self._channels["LA3"]._logic_mode << 8) + | (self._channels["LA4"]._logic_mode << 12) ) self._device.send_byte(self._prescaler) @@ -408,7 +408,7 @@ def _capture_four(self, e2e_time: float): self._trigger_channel.number ] | self._trigger_mode except KeyError: - e = "Triggering is only possible on ID1, ID2, or ID3." + e = "Triggering is only possible on LA1, LA2, or LA3." raise NotImplementedError(e) self._device.send_byte(trigger) @@ -433,7 +433,7 @@ def fetch_data(self) -> List[np.ndarray]: counter_values = [] channels = list( OrderedDict.fromkeys( - [self._channel_one_map, self._channel_two_map, "ID3", "ID4"] + [self._channel_one_map, self._channel_two_map, "LA3", "LA4"] ) ) for c in channels: @@ -530,7 +530,7 @@ def get_initial_states(self) -> Dict[str, bool]: ------- dict of four str: bool pairs Dictionary containing pairs of channel names and the corresponding initial - state, e.g. {'ID1': True, 'ID2': True, 'ID3': True, 'ID4': False}. + state, e.g. {'LA1': True, 'LA2': True, 'LA3': True, 'LA4': False}. True means HIGH, False means LOW. """ return self._get_initial_states_and_progress()[0] @@ -552,7 +552,7 @@ def get_xy(self, timestamps: List[np.ndarray]) -> List[np.ndarray]: xy = [] for e, c in enumerate( - [self._channel_one_map, self._channel_two_map, "ID3", "ID4"][ + [self._channel_one_map, self._channel_two_map, "LA3", "LA4"][ : len(timestamps) ] ): @@ -575,10 +575,10 @@ def _get_initial_states_and_progress(self) -> Tuple[Dict[str, bool], List[int]]: progress[3] = (self._device.get_int() - initial) // 2 - 3 * CP.MAX_SAMPLES // 4 s = self._device.get_byte() initial_states = { - "ID1": (s & 1 != 0), - "ID2": (s & 2 != 0), - "ID3": (s & 4 != 0), - "ID4": (s & 8 != 0), + "LA1": (s & 1 != 0), + "LA2": (s & 2 != 0), + "LA3": (s & 4 != 0), + "LA4": (s & 8 != 0), } self._device.get_byte() # INITIAL_DIGITAL_STATES_ERR self._device.get_ack() @@ -596,7 +596,7 @@ def configure_trigger(self, trigger_channel: str, trigger_mode: str): Parameters ---------- - trigger_channel : {"ID1", "ID2", "ID3", "ID4"} + trigger_channel : {"LA1", "LA2", "LA3", "LA4"} The digital input on which to trigger. trigger_condition : {"disabled", "falling", "rising"} The type of logic level change on which to trigger. @@ -640,7 +640,7 @@ def get_states(self) -> Dict[str, bool]: ------- dict of four str: bool pairs Dictionary containing pairs of channel names and the corresponding current - state, e.g. {'ID1': True, 'ID2': True, 'ID3': True, 'ID4': False}. + state, e.g. {'LA1': True, 'LA2': True, 'LA3': True, 'LA4': False}. True means HIGH, False means LOW. """ self._device.send_byte(CP.DIN) @@ -648,10 +648,10 @@ def get_states(self) -> Dict[str, bool]: s = self._device.get_byte() self._device.get_ack() return { - "ID1": (s & 1 != 0), - "ID2": (s & 2 != 0), - "ID3": (s & 4 != 0), - "ID4": (s & 8 != 0), + "LA1": (s & 1 != 0), + "LA2": (s & 2 != 0), + "LA3": (s & 4 != 0), + "LA4": (s & 8 != 0), } def count_pulses( @@ -664,7 +664,7 @@ def count_pulses( Parameters ---------- - channel : {"ID1", "ID2", "ID3", "ID4"} + channel : {"LA1", "LA2", "LA3", "LA4"} Digital input on which to count pulses. interval : float, optional Time in seconds during which to count pulses. The default value is diff --git a/PSL/oscilloscope.py b/PSL/oscilloscope.py index bd5f3d0d..dfd38d92 100644 --- a/PSL/oscilloscope.py +++ b/PSL/oscilloscope.py @@ -55,7 +55,7 @@ def capture(self, channels: int, samples: int, timegap: float,) -> np.ndarray: channels : {1, 2, 4} Number of channels to sample from simultaneously. By default, samples are captured from CH1, CH2, CH3 and MIC. CH1 can be remapped to any other - channel (CH2, CH3, MIC, CAP, SEN, AN8) by setting the channel_one_map + channel (CH2, CH3, MIC, CAP, RES, VOL) by setting the channel_one_map attribute of the Oscilloscope instance to the desired channel. samples : int Number of samples to fetch. Maximum 10000 divided by number of channels. @@ -93,7 +93,7 @@ def capture(self, channels: int, samples: int, timegap: float,) -> np.ndarray: ValueError If :channels: is not 1, 2 or 4, or :samples: > 10000 / :channels:, or - :channel_one_map: is not one of CH1, CH2, CH3, MIC, CAP, SEN, AN8, or + :channel_one_map: is not one of CH1, CH2, CH3, MIC, CAP, RES, VOL, or :timegap: is too low. """ xy = np.zeros([channels + 1, samples]) @@ -227,7 +227,7 @@ def fetch_data(self, channel: str) -> np.ndarray: Parameters ---------- - channel : {'CH1', 'CH2', 'CH3', 'MIC', 'CAP', 'SEN', 'AN8'} + channel : {'CH1', 'CH2', 'CH3', 'MIC', 'CAP', 'RES', 'VOL'} Name of the channel from which to fetch captured data. Example @@ -290,7 +290,7 @@ def configure_trigger(self, channel: str, voltage: float, prescaler: int = 0): Parameters ---------- - channel : {'CH1', 'CH2', 'CH3', 'MIC', 'CAP', 'SEN', 'AN8'} + channel : {'CH1', 'CH2', 'CH3', 'MIC', 'CAP', 'RES', 'VOL'} The name of the trigger channel. voltage : float The trigger voltage in volts. diff --git a/PSL/sciencelab.py b/PSL/sciencelab.py index 681228db..6cf18a76 100644 --- a/PSL/sciencelab.py +++ b/PSL/sciencelab.py @@ -59,7 +59,7 @@ class ScienceLab(): """ BAUD = 1000000 - WType = {'W1': 'sine', 'W2': 'sine'} + WType = {'SI1': 'sine', 'SI2': 'sine'} def __init__(self, timeout=1.0, **kwargs): self.verbose = kwargs.get('verbose', False) @@ -109,7 +109,7 @@ def __runInitSequence__(self, **kwargs): if self.H.connected: for a in ['CH1', 'CH2']: self.oscilloscope._channels[a].gain = 1 - for a in ['W1', 'W2']: self.load_equation(a, 'sine') + for a in ['SI1', 'SI2']: self.load_equation(a, 'sine') self.SPI.set_parameters(1, 7, 1, 0) self.hexid = hex(self.device_id()) @@ -120,7 +120,7 @@ def __runInitSequence__(self, **kwargs): self.DAC = MCP4728(self.H, 3.3, 0) def get_resistance(self): - V = self.get_average_voltage('SEN') + V = self.get_average_voltage('RES') if V > 3.295: return np.Inf I = (3.3 - V) / 5.1e3 res = V / I @@ -213,7 +213,7 @@ def get_average_voltage(self, channel_name, **kwargs): +------------+-----------------------------------------------------------------------------------------+ |Arguments |Description | +============+=========================================================================================+ - |channel_name| 'CH1','CH2','CH3', 'MIC','IN1','SEN','V+' | + |channel_name| 'CH1','CH2','CH3', 'MIC','IN1','RES','V+' | +------------+-----------------------------------------------------------------------------------------+ |sleep | read voltage in CPU sleep mode. not particularly useful. Also, Buggy. | +------------+-----------------------------------------------------------------------------------------+ @@ -245,7 +245,7 @@ def __get_raw_average_voltage__(self, channel_name, **kwargs): ============== ============================================================================================================ **Arguments** ============== ============================================================================================================ - channel_name 'CH1', 'CH2', 'CH3', 'MIC', '5V', 'IN1','SEN' + channel_name 'CH1', 'CH2', 'CH3', 'MIC', '5V', 'IN1','RES' sleep read voltage in CPU sleep mode ============== ============================================================================================================ @@ -301,7 +301,7 @@ def start_streaming(self, tg, channel='CH1'): **Arguments** ============== ============================================================================================ tg timegap. 250KHz clock - channel channel 'CH1'... 'CH9','IN1','SEN' + channel channel 'CH1'... 'CH9','IN1','RES' ============== ============================================================================================ """ @@ -682,7 +682,7 @@ def write_bulk_flash(self, location, data): # -------------------------------------------------------------------------------------------------------------------# # |===============================================WAVEGEN SECTION====================================================| - # |This section has commands related to waveform generators W1, W2, PWM outputs, servo motor control etc. | + # |This section has commands related to waveform generators SI1, SI2, PWM outputs, servo motor control etc. | # -------------------------------------------------------------------------------------------------------------------# def set_wave(self, chan, freq): @@ -694,16 +694,16 @@ def set_wave(self, chan, freq): ============== ============================================================================================ **Arguments** ============== ============================================================================================ - chan Channel to set frequency for. W1 or W2 + chan Channel to set frequency for. SI1 or SI2 frequency Frequency to set on wave generator ============== ============================================================================================ :return: frequency """ - if chan == 'W1': + if chan == 'SI1': self.set_w1(freq) - elif chan == 'W2': + elif chan == 'SI2': self.set_w2(freq) def set_sine1(self, freq): @@ -768,8 +768,8 @@ def set_w1(self, freq, waveType=None): if waveType: # User wants to set a particular waveform type. sine or tria if waveType in ['sine', 'tria']: - if (self.WType['W1'] != waveType): - self.load_equation('W1', waveType) + if (self.WType['SI1'] != waveType): + self.load_equation('SI1', waveType) else: print('Not a valid waveform. try sine or tria') @@ -818,8 +818,8 @@ def set_w2(self, freq, waveType=None): if waveType: # User wants to set a particular waveform type. sine or tria if waveType in ['sine', 'tria']: - if (self.WType['W2'] != waveType): - self.load_equation('W2', waveType) + if (self.WType['SI2'] != waveType): + self.load_equation('SI2', waveType) else: print('Not a valid waveform. try sine or tria') @@ -852,15 +852,15 @@ def readbackWaveform(self, chan): ============== ============================================================================================ **Arguments** ============== ============================================================================================ - chan Any of W1,W2,SQR1,SQR2,SQR3,SQR4 + chan Any of SI1,SI2,SQR1,SQR2,SQR3,SQR4 ============== ============================================================================================ :return: frequency """ - if chan == 'W1': + if chan == 'SI1': return self.sine1freq - elif chan == 'W2': + elif chan == 'SI2': return self.sine2freq elif chan[:3] == 'SQR': return self.sqrfreq.get(chan, None) @@ -958,7 +958,7 @@ def load_equation(self, chan, function, span=None, **kwargs): ============== ============================================================================================ **Arguments** ============== ============================================================================================ - chan The waveform generator to alter. W1 or W2 + chan The waveform generator to alter. SI1 or SI2 function A function that will be used to generate the datapoints span the range of values in which to evaluate the given function ============== ============================================================================================ @@ -966,11 +966,11 @@ def load_equation(self, chan, function, span=None, **kwargs): .. code-block:: python fn = lambda x:abs(x-50) #Triangular waveform - self.I.load_waveform('W1',fn,[0,100]) + self.I.load_waveform('SI1',fn,[0,100]) #Load triangular wave to wavegen 1 #Load sinusoidal wave to wavegen 2 - self.I.load_waveform('W2',np.sin,[0,2*np.pi]) + self.I.load_waveform('SI2',np.sin,[0,2*np.pi]) ''' if function == 'sine' or function == np.sin: @@ -998,7 +998,7 @@ def load_table(self, chan, points, mode='arbit', **kwargs): ============== ============================================================================================ **Arguments** ============== ============================================================================================ - chan The waveform generator to alter. 'W1' or 'W2' + chan The waveform generator to alter. 'SI1' or 'SI2' points A list of 512 datapoints exactly mode Optional argument. Type of waveform. default value 'arbit'. accepts 'sine', 'tria' ============== ============================================================================================ @@ -1010,11 +1010,11 @@ def load_table(self, chan, points, mode='arbit', **kwargs): ''' self.__print__('reloaded wave table for %s : %s' % (chan, mode)) self.WType[chan] = mode - chans = ['W1', 'W2'] + chans = ['SI1', 'SI2'] if chan in chans: num = chans.index(chan) + 1 else: - print('Channel does not exist. Try W2 or W2') + print('Channel does not exist. Try SI2 or SI2') return # Normalize and scale . @@ -1623,7 +1623,7 @@ def estimateDistance(self): First a 10uS pulse is output on SQR1. SQR1 must be connected to the TRIG pin on the sensor prior to use. Upon receiving this pulse, the sensor emits a sequence of sound pulses, and the logic level of its output - pin(which we will monitor via ID1) is also set high. The logic level goes LOW when the sound packet + pin(which we will monitor via LA1) is also set high. The logic level goes LOW when the sound packet returns to the sensor, or when a timeout occurs. The ultrasound sensor outputs a series of 8 sound pulses at 40KHz which corresponds to a time period diff --git a/tests/test_logic_analyzer.py b/tests/test_logic_analyzer.py index f25515c9..9f4f07d8 100644 --- a/tests/test_logic_analyzer.py +++ b/tests/test_logic_analyzer.py @@ -2,7 +2,7 @@ When integration testing, the PSLab's PWM output is used to generate a signal which is analyzed by the logic analyzer. Before running the integration tests, -connect SQ1->ID1->ID2->ID3->ID4. +connect SQ1->LA1->LA2->LA3->LA4. """ import time @@ -166,71 +166,71 @@ def test_capture_too_many_channels(la): def test_measure_frequency(la): - frequency = la.measure_frequency("ID1", timeout=0.1) + frequency = la.measure_frequency("LA1", timeout=0.1) assert FREQUENCY == pytest.approx(frequency) def test_measure_frequency_firmware(la): - frequency = la.measure_frequency("ID2", timeout=0.1, simultaneous_oscilloscope=True) + frequency = la.measure_frequency("LA2", timeout=0.1, simultaneous_oscilloscope=True) assert FREQUENCY == pytest.approx(frequency) def test_measure_interval(la): - la.configure_trigger("ID1", "falling") + la.configure_trigger("LA1", "falling") interval = la.measure_interval( - channels=["ID1", "ID2"], modes=["rising", "falling"], timeout=0.1 + channels=["LA1", "LA2"], modes=["rising", "falling"], timeout=0.1 ) expected_interval = FREQUENCY ** -1 * MICROSECONDS * 0.5 assert expected_interval == pytest.approx(interval, abs=ONE_CLOCK_CYCLE) def test_measure_interval_same_channel(la): - la.configure_trigger("ID1", "falling") + la.configure_trigger("LA1", "falling") interval = la.measure_interval( - channels=["ID1", "ID1"], modes=["rising", "falling"], timeout=0.1 + channels=["LA1", "LA1"], modes=["rising", "falling"], timeout=0.1 ) expected_interval = FREQUENCY ** -1 * DUTY_CYCLE * MICROSECONDS assert expected_interval == pytest.approx(interval, abs=ONE_CLOCK_CYCLE) def test_measure_interval_same_channel_any(la): - la.configure_trigger("ID1", "falling") + la.configure_trigger("LA1", "falling") interval = la.measure_interval( - channels=["ID1", "ID1"], modes=["any", "any"], timeout=0.1 + channels=["LA1", "LA1"], modes=["any", "any"], timeout=0.1 ) expected_interval = FREQUENCY ** -1 * DUTY_CYCLE * MICROSECONDS assert expected_interval == pytest.approx(interval, abs=ONE_CLOCK_CYCLE) def test_measure_interval_same_channel_four_rising(la): - la.configure_trigger("ID1", "falling") + la.configure_trigger("LA1", "falling") interval = la.measure_interval( - channels=["ID1", "ID1"], modes=["rising", "four rising"], timeout=0.1 + channels=["LA1", "LA1"], modes=["rising", "four rising"], timeout=0.1 ) expected_interval = FREQUENCY ** -1 * 3 * MICROSECONDS assert expected_interval == pytest.approx(interval, abs=ONE_CLOCK_CYCLE) def test_measure_interval_same_channel_sixteen_rising(la): - la.configure_trigger("ID1", "falling") + la.configure_trigger("LA1", "falling") interval = la.measure_interval( - channels=["ID1", "ID1"], modes=["rising", "sixteen rising"], timeout=0.1 + channels=["LA1", "LA1"], modes=["rising", "sixteen rising"], timeout=0.1 ) expected_interval = FREQUENCY ** -1 * 15 * MICROSECONDS assert expected_interval == pytest.approx(interval, abs=ONE_CLOCK_CYCLE) def test_measure_interval_same_channel_same_event(la): - la.configure_trigger("ID1", "falling") + la.configure_trigger("LA1", "falling") interval = la.measure_interval( - channels=["ID3", "ID3"], modes=["rising", "rising"], timeout=0.1 + channels=["LA3", "LA3"], modes=["rising", "rising"], timeout=0.1 ) expected_interval = FREQUENCY ** -1 * MICROSECONDS assert expected_interval == pytest.approx(interval, abs=ONE_CLOCK_CYCLE) def test_measure_duty_cycle(la): - period, duty_cycle = la.measure_duty_cycle("ID4", timeout=0.1) + period, duty_cycle = la.measure_duty_cycle("LA4", timeout=0.1) expected_period = FREQUENCY ** -1 * MICROSECONDS assert (expected_period, DUTY_CYCLE) == pytest.approx( (period, duty_cycle), abs=ONE_CLOCK_CYCLE @@ -238,14 +238,14 @@ def test_measure_duty_cycle(la): def test_get_xy_rising_trigger(la): - la.configure_trigger("ID1", "rising") + la.configure_trigger("LA1", "rising") t = la.capture(1, 100) _, y = la.get_xy(t) assert y[0] def test_get_xy_falling_trigger(la): - la.configure_trigger("ID1", "falling") + la.configure_trigger("LA1", "falling") t = la.capture(1, 100) _, y = la.get_xy(t) assert not y[0] @@ -279,12 +279,12 @@ def test_stop(la): def test_get_states(la): time.sleep(LOW_FREQUENCY ** -1) states = la.get_states() - expected_states = {"ID1": True, "ID2": True, "ID3": True, "ID4": True} + expected_states = {"LA1": True, "LA2": True, "LA3": True, "LA4": True} assert states == expected_states def test_count_pulses(la): interval = 0.2 - pulses = la.count_pulses("ID2", interval) + pulses = la.count_pulses("LA2", interval) expected_pulses = FREQUENCY * interval assert expected_pulses == pytest.approx(pulses, rel=0.1) # Pretty bad accuracy. diff --git a/tests/test_oscilloscope.py b/tests/test_oscilloscope.py index d0d53a5c..0389468f 100644 --- a/tests/test_oscilloscope.py +++ b/tests/test_oscilloscope.py @@ -114,7 +114,7 @@ def test_configure_trigger(scope): def test_configure_trigger_on_unmapped(scope): with pytest.raises(TypeError): - scope.configure_trigger(channel="AN8", voltage=1.5) + scope.configure_trigger(channel="VOL", voltage=1.5) def test_configure_trigger_on_remapped_ch1(scope):