@@ -6398,6 +6398,32 @@ def read_analog_waveform(
63986398 # TODO: AB#3228924 - if the read was short, set waveform.sample_count before throwing the exception
63996399 self .check_for_error (error_code , samps_per_chan_read = samples_read )
64006400
6401+ def read_analog_waveforms (
6402+ self ,
6403+ task_handle : object ,
6404+ number_of_samples_per_channel : int ,
6405+ timeout : float ,
6406+ waveforms : Sequence [AnalogWaveform [numpy .float64 ]]
6407+ ) -> None :
6408+ """Read a set of analog waveforms with timing and attributes. All of the waveforms must be the same size."""
6409+ error_code , samples_read , timestamps , sample_intervals = self .internal_read_analog_waveform_per_chan (
6410+ task_handle ,
6411+ number_of_samples_per_channel ,
6412+ timeout ,
6413+ [waveform .raw_data for waveform in waveforms ],
6414+ [waveform .extended_properties for waveform in waveforms ]
6415+ )
6416+
6417+ for i , waveform in enumerate (waveforms ):
6418+ waveform .timing = Timing (
6419+ sample_interval_mode = SampleIntervalMode .REGULAR ,
6420+ timestamp = timestamps [i ],
6421+ sample_interval = sample_intervals [i ],
6422+ )
6423+
6424+ # TODO: AB#3228924 - if the read was short, set waveform.sample_count before throwing the exception
6425+ self .check_for_error (error_code , samps_per_chan_read = samples_read )
6426+
64016427 def _internal_read_analog_waveform_ex (
64026428 self ,
64036429 task_handle : object ,
@@ -6470,6 +6496,87 @@ def set_wfm_attr_callback(
64706496
64716497 return error_code , samps_per_chan_read .value , timestamps , sample_intervals
64726498
6499+ def internal_read_analog_waveform_per_chan (
6500+ self ,
6501+ task_handle : object ,
6502+ num_samps_per_chan : int ,
6503+ timeout : float ,
6504+ read_arrays : Sequence [numpy .typing .NDArray [numpy .float64 ]],
6505+ properties : Sequence [ExtendedPropertyDictionary ]
6506+ ) -> Tuple [
6507+ int , # error code
6508+ int , # The number of samples per channel that were read
6509+ Sequence [ht_datetime ], # The timestamps for each sample, indexed by channel
6510+ Sequence [ht_timedelta ], # The sample intervals, indexed by channel
6511+ ]:
6512+ assert isinstance (task_handle , TaskHandle )
6513+ samps_per_chan_read = ctypes .c_int ()
6514+
6515+ channel_count = len (read_arrays )
6516+ assert channel_count > 0
6517+ array_size = read_arrays [0 ].size
6518+ assert all (read_array .size == array_size for read_array in read_arrays )
6519+
6520+ cfunc = lib_importer .windll .DAQmxInternalReadAnalogWaveformPerChan
6521+ if cfunc .argtypes is None :
6522+ with cfunc .arglock :
6523+ if cfunc .argtypes is None :
6524+ cfunc .argtypes = [
6525+ TaskHandle ,
6526+ ctypes .c_int ,
6527+ ctypes .c_double ,
6528+ wrapped_ndpointer (dtype = numpy .int64 , flags = ("C" , "W" )),
6529+ wrapped_ndpointer (dtype = numpy .int64 , flags = ("C" , "W" )),
6530+ ctypes .c_uint ,
6531+ CSetWfmAttrCallbackPtr ,
6532+ ctypes .c_void_p ,
6533+ ctypes .POINTER (ctypes .POINTER (ctypes .c_double )),
6534+ ctypes .c_uint ,
6535+ ctypes .c_uint ,
6536+ ctypes .POINTER (ctypes .c_int ),
6537+ ctypes .POINTER (c_bool32 ),
6538+ ]
6539+
6540+ t0_array = numpy .zeros (channel_count , dtype = numpy .int64 )
6541+ dt_array = numpy .zeros (channel_count , dtype = numpy .int64 )
6542+
6543+ read_array_ptrs = (ctypes .POINTER (ctypes .c_double ) * channel_count )()
6544+ for i , read_array in enumerate (read_arrays ):
6545+ read_array_ptrs [i ] = read_array .ctypes .data_as (ctypes .POINTER (ctypes .c_double ))
6546+
6547+ def set_wfm_attr_callback (
6548+ channel_index : int ,
6549+ attribute_name : str ,
6550+ attribute_type : WfmAttrType ,
6551+ value : ExtendedPropertyValue ,
6552+ callback_data : object ,
6553+ ) -> int :
6554+ properties [channel_index ][attribute_name ] = value
6555+ return 0
6556+
6557+ error_code = cfunc (
6558+ task_handle ,
6559+ num_samps_per_chan ,
6560+ timeout ,
6561+ t0_array ,
6562+ dt_array ,
6563+ 0 if t0_array is None else t0_array .size ,
6564+ self ._get_wfm_attr_callback_ptr (set_wfm_attr_callback ),
6565+ None ,
6566+ read_array_ptrs ,
6567+ channel_count ,
6568+ array_size ,
6569+ ctypes .byref (samps_per_chan_read ),
6570+ None ,
6571+ )
6572+ self .check_for_error (error_code , samps_per_chan_read = samps_per_chan_read .value )
6573+
6574+ timestamps = [_T0_EPOCH + ht_timedelta (seconds = t0 * _INT64_WFM_SEC_PER_TICK ) for t0 in t0_array ]
6575+ sample_intervals = [ht_timedelta (seconds = dt * _INT64_WFM_SEC_PER_TICK ) for dt in dt_array ]
6576+
6577+ return error_code , samps_per_chan_read .value , timestamps , sample_intervals
6578+
6579+
64736580 def _get_wfm_attr_value (
64746581 self , attribute_type : int , value : ctypes .c_void_p , value_size_in_bytes : int
64756582 ) -> ExtendedPropertyValue :
0 commit comments