WORKING in and outputgit status
This commit is contained in:
parent
a3a7c37548
commit
49ee42bb01
@ -19,7 +19,8 @@ cdef extern from "lasp_cppthread.h" nogil:
|
||||
CPPThread(F threadfunction, T data)
|
||||
void join()
|
||||
|
||||
void CPPsleep(unsigned int ms)
|
||||
void CPPsleep_ms(unsigned int ms)
|
||||
void CPPsleep_us(unsigned int us)
|
||||
|
||||
cdef extern from "lasp_cppqueue.h" nogil:
|
||||
cdef cppclass SafeQueue[T]:
|
||||
|
@ -23,7 +23,10 @@ class CPPThread {
|
||||
|
||||
};
|
||||
|
||||
void CPPsleep(unsigned int ms) {
|
||||
void CPPsleep_ms(unsigned int ms) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
void CPPsleep_us(unsigned int us) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(us));
|
||||
}
|
||||
#endif // LASP_CPPTHREAD_H
|
||||
|
@ -49,9 +49,9 @@ class DeviceInfo:
|
||||
@dataclass
|
||||
class DAQChannel:
|
||||
channel_enabled: bool
|
||||
channel_name: str
|
||||
sensitivity: float
|
||||
qty: Qty
|
||||
channel_name: str = 'Unnamed channel'
|
||||
sensitivity: float = 1.0
|
||||
qty: Qty = SIQtys.default
|
||||
range_: str = 'Undefined'
|
||||
IEPE_enabled: bool = False
|
||||
|
||||
|
@ -422,7 +422,7 @@ cdef void audioCallbackPythonThreadFunction(void* voidstream) nogil:
|
||||
while stream.outputQueue.size() > 10 and not stream.stopThread.load():
|
||||
# printf('Sleeping...\n')
|
||||
# No input queue to wait on, so we relax a bit here.
|
||||
CPPsleep(1);
|
||||
CPPsleep_ms(1);
|
||||
|
||||
# Outputbuffer is free'ed by the audiothread, so should not be touched
|
||||
# here.
|
||||
@ -693,7 +693,7 @@ cdef class RtAudio:
|
||||
self._stream.thread = new CPPThread[void*, void (*)(void*)](audioCallbackPythonThreadFunction,
|
||||
<void*> self._stream)
|
||||
# Allow it to start
|
||||
CPPsleep(500)
|
||||
CPPsleep_ms(500)
|
||||
pass
|
||||
|
||||
return nFramesPerBlock
|
||||
|
@ -1,5 +1,6 @@
|
||||
include "lasp_common_decls.pxd"
|
||||
|
||||
|
||||
cdef extern from "uldaq.h" nogil:
|
||||
|
||||
ctypedef enum DaqDeviceInterface:
|
||||
@ -24,6 +25,8 @@ cdef extern from "uldaq.h" nogil:
|
||||
long long currentIndex
|
||||
char reserved[64]
|
||||
|
||||
UlError ulGetErrMsg(UlError, char* errMsg)
|
||||
|
||||
ctypedef enum UlError:
|
||||
ERR_NO_ERROR
|
||||
ERR_UNHANDLED_EXCEPTION
|
||||
@ -136,11 +139,6 @@ cdef extern from "uldaq.h" nogil:
|
||||
ERR_NET_BUFFER_OVERRUN
|
||||
ERR_BAD_NET_BUFFER
|
||||
|
||||
ctypedef enum AiInputMode:
|
||||
AI_DIFFERENTIAL = 1,
|
||||
AI_SINGLE_ENDED = 2,
|
||||
AI_PSEUDO_DIFFERENTIAL = 3
|
||||
|
||||
ctypedef enum Range:
|
||||
BIP10VOLTS
|
||||
BIP5VOLTS
|
||||
@ -241,10 +239,11 @@ cdef extern from "uldaq.h" nogil:
|
||||
DAQINSCAN_FF_NOCALIBRATEDATA
|
||||
DAQINSCAN_FF_NOCLEAR
|
||||
|
||||
ctypedef enum DaqOutScanFlag:
|
||||
DAQOUTSCAN_FF_DEFAULT
|
||||
DAQOUTSCAN_FF_NOSCALEDATA
|
||||
DAQOUTSCAN_FF_NOCALIBRATEDATA
|
||||
ctypedef enum AOutScanFlag:
|
||||
AOUTSCAN_FF_DEFAULT
|
||||
AOUTSCAN_FF_NOSCALEDATA
|
||||
AOUTSCAN_FF_NOCALIBRATEDATA
|
||||
AOUTSCAN_FF_NOCLEAR
|
||||
|
||||
ctypedef enum DaqInChanType:
|
||||
DAQI_ANALOG_DIFF
|
||||
@ -260,15 +259,6 @@ cdef extern from "uldaq.h" nogil:
|
||||
DaqInChanType type
|
||||
Range range
|
||||
|
||||
ctypedef enum DaqOutChanType:
|
||||
DAQO_ANALOG
|
||||
DAQO_DIGITAL
|
||||
|
||||
ctypedef struct DaqOutChanDescriptor:
|
||||
int channel
|
||||
DaqOutChanType type
|
||||
Range range
|
||||
|
||||
ctypedef enum DaqEventType:
|
||||
DE_NONE
|
||||
DE_ON_DATA_AVAILABLE
|
||||
@ -359,29 +349,13 @@ cdef extern from "uldaq.h" nogil:
|
||||
UlError ulDaqInScanStop(DaqDeviceHandle daqDeviceHandle);
|
||||
UlError ulDaqInScanWait(DaqDeviceHandle daqDeviceHandle, WaitType waitType, long long waitParam, double timeout);
|
||||
|
||||
UlError ulDaqOutScan(DaqDeviceHandle daqDeviceHandle, DaqOutChanDescriptor chanDescriptors[], int numChans, int samplesPerChan, double* rate, ScanOption options, DaqOutScanFlag flags, double data[]);
|
||||
UlError ulDaqOutScanStatus(DaqDeviceHandle daqDeviceHandle, ScanStatus* status, TransferStatus* xferStatus);
|
||||
UlError ulDaqOutScanStop(DaqDeviceHandle daqDeviceHandle);
|
||||
UlError ulDaqOutSetTrigger(DaqDeviceHandle daqDeviceHandle, TriggerType type, DaqInChanDescriptor trigChanDescriptor, double level, double variance, unsigned int retriggerSampleCount);
|
||||
ctypedef void (*DaqEventCallback)(DaqDeviceHandle, DaqEventType, unsigned long long, void*)
|
||||
|
||||
UlError ulEnableEvent(DaqDeviceHandle daqDeviceHandle, DaqEventType eventTypes, unsigned long long eventParameter, DaqEventCallback eventCallbackFunction, void* userData);
|
||||
UlError ulDisableEvent(DaqDeviceHandle daqDeviceHandle, DaqEventType eventTypes)
|
||||
|
||||
# UlError ulAIGetConfigDbl(DaqDeviceHandle daqDeviceHandle, AiConfigItemDbl configItem, unsigned int index, double* configValue);
|
||||
# UlError ulAIGetConfigStr(DaqDeviceHandle daqDeviceHandle, AiConfigItemStr configItem, unsigned int index, char* configStr, unsigned int* maxConfigLen);
|
||||
# ctypedef enum AiIn
|
||||
# {
|
||||
# /** Returns the minimum scan rate in samples per second to the \p infoValue argument. Index is ignored. */
|
||||
# AI_INFO_MIN_SCAN_RATE = 1000,
|
||||
|
||||
# /** Returns the maximum scan rate in samples per second to the \p infoValue argument. Index is ignored. */
|
||||
# AI_INFO_MAX_SCAN_RATE = 1001,
|
||||
|
||||
# /** Returns the maximum throughput in samples per second to the \p infoValue argument. Index is ignored. */
|
||||
# AI_INFO_MAX_THROUGHPUT = 1002,
|
||||
|
||||
# /** Returns the maximum scan rate in samples per second when using the ::SO_BURSTIO ScanOption to the \p infoValue argument. Index is ignored. */
|
||||
# AI_INFO_MAX_BURST_RATE = 1003,
|
||||
|
||||
# /** Returns the maximum throughput in samples per second when using the ::SO_BURSTIO ScanOption to the \p infoValue argument. Index is ignored. */
|
||||
# AI_INFO_MAX_BURST_THROUGHPUT = 1004
|
||||
# }AiInfoItemDbl
|
||||
|
||||
UlError ulAOutScan(DaqDeviceHandle daqDeviceHandle,int lowChan,int highChan,Range range,int samplesPerChan,double * rate,ScanOption options,AOutScanFlag flags,double data[])
|
||||
UlError ulAOutScanStatus(DaqDeviceHandle daqDeviceHandle,ScanStatus * status,TransferStatus * xferStatus)
|
||||
UlError ulAOutScanStop(DaqDeviceHandle daqDeviceHandle)
|
||||
UlError ulAOutScanWait(DaqDeviceHandle daqDeviceHandle,WaitType waitType,long long waitParam,double timeout)
|
||||
UlError ulAOutSetTrigger(DaqDeviceHandle daqDeviceHandle,TriggerType type,int trigChan,double level,double variance,unsigned int retriggerSampleCount)
|
||||
|
@ -6,6 +6,7 @@ from .lasp_avtype import AvType
|
||||
__all__ = ['UlDT9837A', 'UlDaq']
|
||||
|
||||
DEF MAX_DEF_COUNT = 100
|
||||
DEF UL_ERR_MSG_LEN = 512
|
||||
|
||||
cdef struct DaqThreadData:
|
||||
|
||||
@ -14,103 +15,290 @@ cdef struct DaqThreadData:
|
||||
|
||||
DaqDeviceHandle handle
|
||||
|
||||
SafeQueue[void*] *inputQueue
|
||||
SafeQueue[void*] *outputQueue
|
||||
SafeQueue[void*] *inQueue
|
||||
SafeQueue[void*] *outQueue
|
||||
|
||||
DaqInChanDescriptor* inChanDescriptors
|
||||
unsigned ninputChanDescriptors
|
||||
|
||||
DaqOutChanDescriptor* outChanDescriptors
|
||||
unsigned noutputChanDescriptors
|
||||
unsigned ninChanDescriptors
|
||||
unsigned noutChanDescriptors
|
||||
|
||||
atomic[bool] stopThread
|
||||
CPPThread[void*, void (*)(void*)] *thread
|
||||
|
||||
cdef void eventCallbackFunction(DaqDeviceHandle handle, DaqEventType eventType,
|
||||
unsigned long long eventData, void* userData):
|
||||
CPPThread[void*, void (*)(void*)] *inThread
|
||||
CPPThread[void*, void (*)(void*)] *outThread
|
||||
|
||||
pass
|
||||
double* inbuffer
|
||||
double* outbuffer
|
||||
|
||||
cdef void ulThreadFunction(void* threaddata_void) nogil:
|
||||
|
||||
cdef void showErr(UlError err) nogil:
|
||||
cdef:
|
||||
char errmsg[UL_ERR_MSG_LEN]
|
||||
ulGetErrMsg(err, errmsg)
|
||||
fprintf(stderr, 'UlError: %s\n', errmsg)
|
||||
|
||||
|
||||
cdef void inThreadFunction(void* threaddata_void) nogil:
|
||||
"""
|
||||
Stream thread function
|
||||
Stream input thread function
|
||||
"""
|
||||
cdef:
|
||||
DaqThreadData* td = <DaqThreadData*> threaddata_void
|
||||
TransferStatus instatus
|
||||
TransferStatus outstatus
|
||||
|
||||
UlError err
|
||||
|
||||
ScanOption scanoptions
|
||||
DaqInScanFlag inscanflags
|
||||
DaqOutScanFlag outscanflags
|
||||
# AScanFlag inscanflags
|
||||
double* outbuffer, inbuffer
|
||||
TransferStatus xstat
|
||||
ScanStatus scanstat
|
||||
double samplerate
|
||||
bint top_enqueued, bottom_enqueued
|
||||
unsigned buffer_mid_idx, chan, sample
|
||||
|
||||
# inbuffer = NULL
|
||||
# outbuffer = NULL
|
||||
double sleep_time
|
||||
double *inbuffer_cpy
|
||||
unsigned sleep_time_mus # Thread sleep time in ms
|
||||
|
||||
inscanflags = DAQINSCAN_FF_NOSCALEDATA
|
||||
outscanflags = DAQOUTSCAN_FF_NOSCALEDATA
|
||||
samplerate = td.samplerate
|
||||
sleep_time = td.samplesPerBlock / td.samplerate / 2
|
||||
sleep_time_mus = <unsigned> (sleep_time * 1e6)
|
||||
|
||||
scanoptions = SO_CONTINUOUS
|
||||
inscanflags = DAQINSCAN_FF_DEFAULT
|
||||
scanoptions = <ScanOption> SO_CONTINUOUS
|
||||
|
||||
if td.noutputChanDescriptors > 0:
|
||||
buffer_mid_idx = td.samplesPerBlock*td.ninChanDescriptors
|
||||
top_enqueued = True
|
||||
bottom_enqueued = True
|
||||
|
||||
# Enable input and outputs
|
||||
err = ulDaqOutScan(td.handle,
|
||||
td.outChanDescriptors,
|
||||
td.noutputChanDescriptors,
|
||||
td.samplesPerBlock,
|
||||
&td.samplerate,
|
||||
fprintf(stderr, 'Starting input thread\n')
|
||||
|
||||
err = ulDaqInScan(td.handle,
|
||||
td.inChanDescriptors,
|
||||
td.ninChanDescriptors,
|
||||
2*td.samplesPerBlock, # Watch the 2 here!
|
||||
&samplerate,
|
||||
scanoptions,
|
||||
outscanflags,
|
||||
outbuffer)
|
||||
if err:
|
||||
fprintf(stderr, 'Error starting data output\n')
|
||||
inscanflags,
|
||||
td.inbuffer)
|
||||
|
||||
fprintf(stderr, 'Actual input sampling rate: %0.2f\n', samplerate)
|
||||
if err != ERR_NO_ERROR:
|
||||
fprintf(stderr, 'Error starting data in\n')
|
||||
showErr(err)
|
||||
return
|
||||
|
||||
|
||||
err = ulDaqInScanStatus(td.handle, &scanstat, &xstat)
|
||||
if err != ERR_NO_ERROR:
|
||||
fprintf(stderr, 'Error obtaining input scan status\n')
|
||||
showErr(err)
|
||||
return
|
||||
|
||||
if td.ninputChanDescriptors > 0:
|
||||
# Enable input and outputs
|
||||
# err = ulDaqOutScan(td.handle,
|
||||
# td.outChanDescriptors,
|
||||
# td.noutputChanDescriptors,
|
||||
# td.samplesPerBlock,
|
||||
# &td.samplerate,
|
||||
# scanoptions,
|
||||
# outscanflags,
|
||||
# outbuffer)
|
||||
# if err:
|
||||
# fprintf(stderr, 'Error starting data output\n')
|
||||
# return
|
||||
pass
|
||||
while td.stopThread.load() == False and err == ERR_NO_ERROR:
|
||||
err = ulDaqInScanStatus(td.handle, &scanstat, &xstat)
|
||||
if err != ERR_NO_ERROR:
|
||||
showErr(err)
|
||||
|
||||
if xstat.currentIndex < buffer_mid_idx:
|
||||
top_enqueued = False
|
||||
if not bottom_enqueued:
|
||||
# Copy the bottom of the buffer to the queue, while transposing
|
||||
# it.
|
||||
inbuffer_cpy = <double*> malloc(sizeof(double)*td.samplesPerBlock*td.ninChanDescriptors)
|
||||
for chan in range(td.ninChanDescriptors):
|
||||
for sample in range(td.samplesPerBlock):
|
||||
inbuffer_cpy[chan*td.samplesPerBlock+sample] = td.inbuffer[buffer_mid_idx+sample*td.ninChanDescriptors+chan]
|
||||
td.inQueue.enqueue(inbuffer_cpy)
|
||||
|
||||
bottom_enqueued = True
|
||||
else:
|
||||
# fprintf(stderr,'sleep...\n')
|
||||
CPPsleep_us(sleep_time_mus)
|
||||
# fprintf(stderr,'awake...\n')
|
||||
else:
|
||||
bottom_enqueued = False
|
||||
if not top_enqueued:
|
||||
inbuffer_cpy = <double*> malloc(sizeof(double)*td.samplesPerBlock*td.ninChanDescriptors)
|
||||
for chan in range(td.ninChanDescriptors):
|
||||
for sample in range(td.samplesPerBlock):
|
||||
inbuffer_cpy[chan*td.samplesPerBlock+sample] = td.inbuffer[sample*td.ninChanDescriptors+chan]
|
||||
td.inQueue.enqueue(inbuffer_cpy)
|
||||
|
||||
# Enqueue the top part of the queue
|
||||
top_enqueued = True
|
||||
else:
|
||||
# fprintf(stderr,'sleep...\n')
|
||||
CPPsleep_us(sleep_time_mus)
|
||||
# fprintf(stderr,'awake...\n')
|
||||
|
||||
fprintf(stderr, 'Exit while loop input thread\n')
|
||||
|
||||
err = ulDaqInScanStop(td.handle)
|
||||
if err != ERR_NO_ERROR:
|
||||
fprintf(stderr, "Error stopping DAQ input thread\n")
|
||||
showErr(err)
|
||||
|
||||
return
|
||||
|
||||
cdef void outThreadFunction(void* threaddata_void) nogil:
|
||||
"""
|
||||
Stream output thread function
|
||||
"""
|
||||
cdef:
|
||||
DaqThreadData* td = <DaqThreadData*> threaddata_void
|
||||
|
||||
UlError err
|
||||
|
||||
ScanOption scanoptions
|
||||
AOutScanFlag outscanflags
|
||||
TransferStatus xstat
|
||||
ScanStatus scanstat
|
||||
bint top_enqueued, bottom_enqueued
|
||||
unsigned buffer_mid_idx, chan, sample
|
||||
|
||||
double sleep_time
|
||||
double *outbuffer_cpy
|
||||
unsigned sleep_time_mus # Thread sleep time in ms
|
||||
double samplerate
|
||||
|
||||
samplerate = td.samplerate
|
||||
sleep_time = td.samplesPerBlock / td.samplerate / 2
|
||||
sleep_time_mus = <unsigned> (sleep_time * 1e6)
|
||||
|
||||
# CAREFULL, a MEMCPY here is only allowed for a single channel!!
|
||||
if not td.noutChanDescriptors == 1:
|
||||
fprintf(stderr, 'Error: multiple output channels not implemented!\n')
|
||||
return
|
||||
|
||||
# Copy first queue blob to top of outbuffer
|
||||
outbuffer_cpy = <double*> td.outQueue.dequeue()
|
||||
memcpy(td.outbuffer, outbuffer_cpy, sizeof(double)*td.samplesPerBlock)
|
||||
free(outbuffer_cpy)
|
||||
|
||||
outscanflags = AOUTSCAN_FF_DEFAULT
|
||||
scanoptions = <ScanOption> SO_CONTINUOUS
|
||||
|
||||
buffer_mid_idx = td.samplesPerBlock
|
||||
|
||||
top_enqueued = True
|
||||
bottom_enqueued = False
|
||||
|
||||
fprintf(stderr, 'Starting output thread\n')
|
||||
|
||||
err = ulAOutScan(td.handle,
|
||||
0,
|
||||
0,
|
||||
BIP10VOLTS,
|
||||
2*td.samplesPerBlock, # Watch the 2 here!
|
||||
&samplerate,
|
||||
scanoptions,
|
||||
outscanflags,
|
||||
td.outbuffer)
|
||||
fprintf(stderr, 'Actual output sampling rate: %0.2f\n', samplerate)
|
||||
|
||||
if err != ERR_NO_ERROR:
|
||||
fprintf(stderr, 'Error starting data out\n')
|
||||
showErr(err)
|
||||
return
|
||||
|
||||
|
||||
err = ulAOutScanStatus(td.handle, &scanstat, &xstat)
|
||||
if err != ERR_NO_ERROR:
|
||||
showErr(err)
|
||||
return
|
||||
|
||||
while td.stopThread.load() == False:
|
||||
err = ulAOutScanStatus(td.handle, &scanstat, &xstat)
|
||||
if err != ERR_NO_ERROR:
|
||||
showErr(err)
|
||||
break
|
||||
|
||||
if xstat.currentIndex < buffer_mid_idx:
|
||||
top_enqueued = False
|
||||
if not bottom_enqueued:
|
||||
# Copy the bottom of the buffer to the queue, while transposing
|
||||
# it.
|
||||
if not td.outQueue.empty():
|
||||
outbuffer_cpy = <double*> td.outQueue.dequeue()
|
||||
else:
|
||||
outbuffer_cpy = <double*> malloc(sizeof(double)*td.noutChanDescriptors*td.samplesPerBlock)
|
||||
for chan in range(td.noutChanDescriptors):
|
||||
for sample in range(td.samplesPerBlock):
|
||||
outbuffer_cpy[chan*td.samplesPerBlock+sample] = 0.0
|
||||
fprintf(stderr, 'Output buffer queue empty! Filling with zeros\n')
|
||||
|
||||
for chan in range(td.noutChanDescriptors):
|
||||
for sample in range(td.samplesPerBlock):
|
||||
# td.outbuffer[buffer_mid_idx+sample*td.noutChanDescriptors+chan] = outbuffer_cpy[chan*td.samplesPerBlock+sample]
|
||||
# Simpler, valid for single chan
|
||||
td.outbuffer[buffer_mid_idx+sample] = outbuffer_cpy[sample]
|
||||
free(outbuffer_cpy)
|
||||
|
||||
bottom_enqueued = True
|
||||
else:
|
||||
CPPsleep_us(sleep_time_mus)
|
||||
else:
|
||||
bottom_enqueued = False
|
||||
if not top_enqueued:
|
||||
if not td.outQueue.empty():
|
||||
outbuffer_cpy = <double*> td.outQueue.dequeue()
|
||||
else:
|
||||
outbuffer_cpy = <double*> malloc(sizeof(double)*td.noutChanDescriptors*td.samplesPerBlock)
|
||||
for chan in range(td.noutChanDescriptors):
|
||||
for sample in range(td.samplesPerBlock):
|
||||
outbuffer_cpy[chan*td.samplesPerBlock+sample] = 0.0
|
||||
fprintf(stderr, 'Output buffer queue empty! Filling with zeros\n')
|
||||
|
||||
for chan in range(td.noutChanDescriptors):
|
||||
for sample in range(td.samplesPerBlock):
|
||||
# td.outbuffer[sample*td.noutChanDescriptors+chan] = outbuffer_cpy[chan*td.samplesPerBlock+sample]
|
||||
# Simpler, valid for single chan
|
||||
td.outbuffer[sample] = outbuffer_cpy[sample]
|
||||
|
||||
free(outbuffer_cpy)
|
||||
|
||||
# Enqueue the top part of the queue
|
||||
top_enqueued = True
|
||||
else:
|
||||
CPPsleep_us(sleep_time_mus)
|
||||
|
||||
fprintf(stderr, 'Exit while loop output thread\n')
|
||||
|
||||
err = ulAOutScanStop(td.handle)
|
||||
if err != ERR_NO_ERROR:
|
||||
fprintf(stderr, "Error stopping AOut output thread\n")
|
||||
showErr(err)
|
||||
|
||||
|
||||
cdef class UlDT9837A:
|
||||
cdef:
|
||||
DaqDeviceHandle handle
|
||||
bint handle_connected
|
||||
bint stream_running
|
||||
unsigned int ninputchannels
|
||||
unsigned int noutputchannels
|
||||
|
||||
unsigned int ninchannels
|
||||
unsigned int noutchannels
|
||||
object input_range
|
||||
object enabled_inputs
|
||||
|
||||
bint output_enabled
|
||||
bint monitor_gen
|
||||
DaqThreadData *threaddata
|
||||
|
||||
DaqThreadData *td
|
||||
|
||||
def __cinit__(self, unsigned int deviceno):
|
||||
self.handle = 0
|
||||
self.handle_connected = False
|
||||
self.ninputchannels = 4
|
||||
self.noutputchannels = 1
|
||||
|
||||
self.ninchannels = 4
|
||||
self.noutchannels = 1
|
||||
self.input_range = 4*[False]
|
||||
self.enabled_inputs = 4*[False]
|
||||
|
||||
self.output_enabled = False
|
||||
self.threaddata = NULL
|
||||
self.monitor_gen = False
|
||||
|
||||
self.td = NULL
|
||||
|
||||
cdef:
|
||||
DaqDeviceDescriptor devdescriptors[MAX_DEF_COUNT]
|
||||
DaqDeviceDescriptor descriptor
|
||||
@ -140,82 +328,176 @@ cdef class UlDT9837A:
|
||||
if err != ERR_NO_ERROR:
|
||||
raise RuntimeError(f'Unable to connect to device: {err}')
|
||||
|
||||
|
||||
cdef void startScan(self,
|
||||
unsigned int samplesPerBlock,
|
||||
SafeQueue[void*] *inputQueue,
|
||||
SafeQueue[void*] *outputQueue):
|
||||
double samplerate,
|
||||
SafeQueue[void*] *inQueue,
|
||||
SafeQueue[void*] *outQueue):
|
||||
|
||||
cdef:
|
||||
int i, j
|
||||
int i, j, nnormalinchannels, neninchannels
|
||||
|
||||
# Sanity checks
|
||||
if inputQueue and (not any(self.enabled_inputs) and (not self.monitor_gen)):
|
||||
if inQueue and (not any(self.enabled_inputs) and (not self.monitor_gen)):
|
||||
raise ValueError('Input queue given, but no input channels enabled and monitor output disabled')
|
||||
if outputQueue and not self.output_enabled:
|
||||
if outQueue and not self.output_enabled:
|
||||
raise ValueError('Output queue given, but output channel is not enabled')
|
||||
# End sanity checks
|
||||
|
||||
cdef:
|
||||
DaqThreadData *threaddata
|
||||
threaddata = <DaqThreadData*> malloc(sizeof(threaddata))
|
||||
if not threaddata:
|
||||
DaqThreadData *td
|
||||
|
||||
td = <DaqThreadData*> malloc(sizeof(DaqThreadData))
|
||||
|
||||
if not td:
|
||||
raise MemoryError()
|
||||
|
||||
threaddata.samplesPerBlock = samplesPerBlock
|
||||
threaddata.handle = self.handle
|
||||
threaddata.inputQueue = inputQueue
|
||||
threaddata.outputQueue = outputQueue
|
||||
threaddata.inChanDescriptors = NULL
|
||||
threaddata.outChanDescriptors = NULL
|
||||
threaddata.ninputChanDescriptors = 0
|
||||
threaddata.noutputChanDescriptors = 0
|
||||
with nogil:
|
||||
td.samplesPerBlock = samplesPerBlock
|
||||
td.samplerate = <double> samplerate
|
||||
|
||||
neninputchannels = sum([1 if self.enabled_inputs == True else 0])
|
||||
td.handle = self.handle
|
||||
td.inQueue = inQueue
|
||||
td.outQueue = outQueue
|
||||
|
||||
threaddata.inputQueue = inputQueue
|
||||
threaddata.outputQueue = inputQueue
|
||||
threaddata.thread = NULL
|
||||
td.inChanDescriptors = NULL
|
||||
td.ninChanDescriptors = 0
|
||||
td.noutChanDescriptors = 0
|
||||
|
||||
td.inThread = NULL
|
||||
td.outThread = NULL
|
||||
|
||||
td.stopThread.store(False)
|
||||
|
||||
td.inbuffer = NULL
|
||||
td.outbuffer = NULL
|
||||
|
||||
# Configure INPUTS
|
||||
py_nnormalinchannels = sum([1 if en_input else 0 for en_input in
|
||||
self.enabled_inputs])
|
||||
nnormalinchannels = py_nnormalinchannels
|
||||
|
||||
j = 0
|
||||
neninchannels = nnormalinchannels
|
||||
if self.monitor_gen:
|
||||
neninputchannels +=1
|
||||
j+=1
|
||||
neninchannels += 1
|
||||
|
||||
threaddata.inChanDescriptors = <DaqInChanDescriptor*> malloc(neninputchannels*sizeof(DaqInChanDescriptor))
|
||||
if not threaddata.inChanDescriptors:
|
||||
self.cleanupThreadData(threaddata)
|
||||
fprintf(stderr, 'neninchannels: %u\n', neninchannels)
|
||||
|
||||
if neninchannels > 0:
|
||||
td.inChanDescriptors = <DaqInChanDescriptor*> malloc(neninchannels*
|
||||
sizeof(DaqInChanDescriptor))
|
||||
if not td.inChanDescriptors:
|
||||
self.cleanupThreadData(td)
|
||||
raise MemoryError()
|
||||
td.ninChanDescriptors = neninchannels
|
||||
td.inbuffer = <double*> malloc(2*sizeof(double)*td.samplesPerBlock*
|
||||
neninchannels)
|
||||
if not td.inbuffer:
|
||||
self.cleanupThreadData(td)
|
||||
raise MemoryError()
|
||||
|
||||
if self.monitor_gen:
|
||||
threaddata.inChanDescriptors[0].chantype = DAQI_DAC
|
||||
threaddata.inChanDescriptors[0].channel = 7
|
||||
threaddata.inChanDescriptors[0].range = BIP10VOLTS
|
||||
|
||||
for i in range(neninputchannels):
|
||||
j = 0
|
||||
for i in range(4):
|
||||
if self.enabled_inputs[i]:
|
||||
threaddata.inChanDescriptors[j].chantype = DAQI_ANALOG_DIFF
|
||||
threaddata.inChanDescriptors[j].channel = i
|
||||
threaddata.inChanDescriptors[j].range = BIP10VOLTS if self.input_range[i] else BIP1VOLTS
|
||||
td.inChanDescriptors[j].type = DAQI_ANALOG_SE
|
||||
td.inChanDescriptors[j].channel = i
|
||||
td.inChanDescriptors[j].range = BIP10VOLTS if self.input_range[i] else BIP1VOLTS
|
||||
j+=1
|
||||
|
||||
threaddata.ninputChanDescriptors = neninputchannels
|
||||
|
||||
if self.output_enabled:
|
||||
threaddata.outChanDescriptors = <DaqOutChanDescriptor*> malloc(sizeof(DaqInChanDescriptor))
|
||||
if not threaddata.outChanDescriptors:
|
||||
self.cleanupThreadData(threaddata)
|
||||
td.inbuffer = <double*> malloc(2*sizeof(double)*td.samplesPerBlock*neninchannels)
|
||||
if not td.inbuffer:
|
||||
self.cleanupThreadData(td)
|
||||
raise MemoryError()
|
||||
self.threaddata.outChanDescriptors[0].channel = 0
|
||||
self.threaddata.outChanDescriptors[0].type = DAQO_ANALOG
|
||||
self.threaddata.outChanDescriptors[0].range = BIP10VOLTS
|
||||
|
||||
self.threaddata.thread = new CPPThread[void*, void (*)(void*)](
|
||||
ulThreadFunction,
|
||||
self.threaddata)
|
||||
# Create input channel descriptors
|
||||
if self.monitor_gen:
|
||||
td.inChanDescriptors[neninchannels-1].type = DAQI_DAC
|
||||
td.inChanDescriptors[neninchannels-1].channel = 0
|
||||
td.inChanDescriptors[neninchannels-1].range = BIP10VOLTS
|
||||
|
||||
fprintf(stderr, 'SFSG12\n')
|
||||
|
||||
# CONFIGURE OUTPUTS
|
||||
if self.output_enabled:
|
||||
fprintf(stderr, 'SFSG13\n')
|
||||
td.noutChanDescriptors = 1
|
||||
# WATCH THE TWO HERE!!!
|
||||
td.outbuffer = <double*> malloc(2*sizeof(double)*td.samplesPerBlock)
|
||||
if not td.outbuffer:
|
||||
self.cleanupThreadData(td)
|
||||
raise MemoryError()
|
||||
|
||||
# Create DAQ Threads
|
||||
with nogil:
|
||||
fprintf(stderr, 'SFSG14\n')
|
||||
if self.output_enabled:
|
||||
td.outThread = new CPPThread[void*, void (*)(void*)](
|
||||
outThreadFunction, <void*> td)
|
||||
|
||||
if not td.outThread:
|
||||
self.cleanupThreadData(td)
|
||||
raise RuntimeError('Error creating thread')
|
||||
|
||||
if neninchannels > 0:
|
||||
fprintf(stderr, 'SFSG15\n')
|
||||
td.inThread = new CPPThread[void*, void (*)(void*)](
|
||||
inThreadFunction, <void*> td)
|
||||
|
||||
if not td.inThread:
|
||||
self.cleanupThreadData(td)
|
||||
raise RuntimeError('Error creating thread')
|
||||
self.td = td
|
||||
|
||||
def start(self):
|
||||
cdef:
|
||||
SafeQueue[void*] *inqueue
|
||||
SafeQueue[void*] *outqueue
|
||||
int i, sample, samples, samplesperbuf
|
||||
double meas_seconds, samplerate
|
||||
double* inbuf
|
||||
double* outbuf
|
||||
|
||||
inqueue = new SafeQueue[void*]()
|
||||
outqueue = new SafeQueue[void*]()
|
||||
|
||||
samplesperbuf = 512
|
||||
samplerate = 10000
|
||||
meas_seconds = 4
|
||||
|
||||
for i in range(int(meas_seconds*samplerate/samplesperbuf)):
|
||||
outbuf = <double*> malloc(sizeof(double)*samplesperbuf)
|
||||
for sample in range(samplesperbuf):
|
||||
outbuf[sample] = <double> 1
|
||||
outqueue.enqueue(<void*> outbuf)
|
||||
|
||||
self.startScan(
|
||||
samplesperbuf,
|
||||
samplerate, # Sample rate
|
||||
inqueue,
|
||||
outqueue)
|
||||
|
||||
CPPsleep_ms(int(0.5*1000*meas_seconds))
|
||||
self.stop()
|
||||
while not inqueue.empty():
|
||||
inbuf = <double*> inqueue.dequeue()
|
||||
for sample in range(samplesperbuf):
|
||||
print(f'Value monitor: {inbuf[sample]:1.2f}, value input: {inbuf[samplesperbuf+sample]:1.2f}')
|
||||
pass
|
||||
free(inbuf)
|
||||
|
||||
while not outqueue.empty():
|
||||
outbuf = <double*> outqueue.dequeue()
|
||||
free(outbuf)
|
||||
del inqueue
|
||||
del outqueue
|
||||
|
||||
def stop(self):
|
||||
self.cleanupThreadData(self.td)
|
||||
self.td = NULL
|
||||
|
||||
def setInputChannelConfig(self, unsigned chnum, channelconfig: DAQChannel):
|
||||
if self.threaddata:
|
||||
if self.td:
|
||||
raise RuntimeError('Cannot change settings while sampling')
|
||||
cdef:
|
||||
int i
|
||||
@ -223,11 +505,11 @@ cdef class UlDT9837A:
|
||||
IepeMode iepe
|
||||
CouplingMode cm
|
||||
|
||||
if chnum >= self.ninputchannels:
|
||||
if chnum >= self.ninchannels:
|
||||
raise RuntimeError('Invalid input channel number')
|
||||
|
||||
self.input_range[chnum] = True if channelconfig.range_ == pyRange.tenV else False
|
||||
self.enabled_input[chnum] = channelconfig.channel_enabled
|
||||
self.enabled_inputs[chnum] = channelconfig.channel_enabled
|
||||
|
||||
iepe = IEPE_ENABLED if channelconfig.IEPE_enabled else IEPE_DISABLED
|
||||
cm = CM_AC if channelconfig.IEPE_enabled else CM_DC
|
||||
@ -248,39 +530,56 @@ cdef class UlDT9837A:
|
||||
|
||||
def setOutputChannelConfig(self, unsigned chnum, channelconfig:
|
||||
DAQChannel, bint monitor_gen):
|
||||
if self.threaddata:
|
||||
if self.td:
|
||||
raise RuntimeError('Cannot change settings while sampling')
|
||||
if chnum >= self.noutputchannels:
|
||||
if chnum > 0:
|
||||
raise RuntimeError('Invalid output channel number')
|
||||
|
||||
if monitor_gen and not channelconfig.channel_enabled:
|
||||
raise RuntimeError('Output channel should be enabled to enable channel monitoring')
|
||||
|
||||
self.output_enabled = channelconfig.channel_enabled
|
||||
self.monitor_gen = monitor_gen
|
||||
|
||||
def __dealloc__(self):
|
||||
fprintf(stderr, '__dealloc__\n')
|
||||
self.cleanupThreadData(self.td)
|
||||
self.td = NULL
|
||||
|
||||
if self.handle_connected:
|
||||
ulDisconnectDaqDevice(self.handle)
|
||||
ulReleaseDaqDevice(self.handle)
|
||||
|
||||
cdef cleanupThreadData(self, DaqThreadData* td):
|
||||
cdef void cleanupThreadData(self, DaqThreadData* td) nogil:
|
||||
fprintf(stderr, 'cleanupThreadData()\n')
|
||||
|
||||
if td is NULL:
|
||||
return
|
||||
if td.thread:
|
||||
|
||||
td.stopThread.store(True)
|
||||
td.thread.join()
|
||||
del td.thread
|
||||
td.thread = NULL
|
||||
if td.inThread:
|
||||
td.inThread.join()
|
||||
del td.inThread
|
||||
fprintf(stderr, 'SFSG0\n')
|
||||
|
||||
if td.outThread:
|
||||
td.outThread.join()
|
||||
del td.outThread
|
||||
fprintf(stderr, 'SFSG1\n')
|
||||
|
||||
if td.inChanDescriptors:
|
||||
free(td.inChanDescriptors)
|
||||
td.inChanDescriptors = NULL
|
||||
|
||||
if td.outChanDescriptors:
|
||||
free(td.outChanDescriptors)
|
||||
td.outChanDescriptors = NULL
|
||||
fprintf(stderr, 'SFSG1\n')
|
||||
if td.inbuffer:
|
||||
free(td.inbuffer)
|
||||
fprintf(stderr, 'SFSG2\n')
|
||||
if td.outbuffer:
|
||||
free(td.outbuffer)
|
||||
fprintf(stderr, 'SFSG3\n')
|
||||
|
||||
free(td)
|
||||
fprintf(stderr, 'end cleanupThreadData()\n')
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user