record background to file.

This commit is contained in:
Blake Leverington 2023-09-07 13:31:49 +02:00
parent d36d943ce0
commit 77af9c7ef3
117 changed files with 54228 additions and 3 deletions

File diff suppressed because one or more lines are too long

View File

@ -120,6 +120,9 @@ void DisplayServer::plot()
}
}
int DisplayServer::isActive()
{
return active;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 11.0.0, 2023-09-07T10:15:01. -->
<!-- Written by QtCreator 11.0.2, 2023-09-07T11:46:05. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 11.0.0, 2023-09-07T10:15:01. -->
<!-- Written by QtCreator 11.0.0, 2023-09-07T10:55:49. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>

46
hit2023v2/Q_DebugStream.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef Q_DEBUGSTREAM_H
#define Q_DEBUGSTREAM_H
#include <iostream>
#include <streambuf>
#include <string>
#include <QTextBrowser>
#include <QtGlobal>
#define DS_DEBUG 0x01
#define DS_INFO 0x02
#define DS_WARNING 0x04
#define DS_CRITICAL 0x08
#define DS_FATAL 0x10
class Q_DebugStream : public std::basic_streambuf<char>
{
public:
Q_DebugStream(std::ostream &stream, QTextBrowser* text_edit);
~Q_DebugStream();
static void registerQDebugMessageHandler();
int displayMask;
int detailsMask;
private:
static void myQDebugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
protected:
//This is called when a std::endl has been inserted into the stream
virtual int_type overflow(int_type v);
virtual std::streamsize xsputn(const char *p, std::streamsize n);
private:
std::ostream &m_stream;
std::streambuf *m_old_buf;
QTextBrowser* log_window;
};
#endif // Q_DEBUGSTREAM_H

143
hit2023v2/cbuffer.h Normal file
View File

@ -0,0 +1,143 @@
#ifndef CBUFFER_H
#define CBUFFER_H
#include <QMutex>
template <class T> class CBuffer
{
public:
CBuffer(int queueSize)
{
data = new T[queueSize];
size = queueSize;
push_ptr = 0;
pop_ptr = 0;
};
~CBuffer()
{
delete[] data;
};
int nrItems()
{
int result;
mutex.lock();
result = prvNrItems();
mutex.unlock();
return result;
};
int push(const T &to_push)
{
mutex.lock();
if (prvNrItems() >= (size - 1))
{
mutex.unlock();
return 0; //queue full!
}
data[push_ptr++] = to_push;
if (push_ptr >= size)
push_ptr = 0;
mutex.unlock();
return 1;
};
int pop(T &popped)
{
mutex.lock();
if (prvNrItems() == 0)
{
mutex.unlock();
return 0;
}
popped = data[pop_ptr++];
if (pop_ptr >= size)
pop_ptr = 0;
mutex.unlock();
return 1;
};
T pop()
{
mutex.lock();
T popped;
if (prvNrItems() >0)
{
popped = data[pop_ptr++];
if (pop_ptr >= size)
pop_ptr = 0;
}
mutex.unlock();
return popped;
};
//just look at the next element to be popped
int look(T &looked)
{
mutex.lock();
if (prvNrItems() == 0)
{
mutex.unlock();
return 0;
}
looked = data[pop_ptr];
mutex.unlock();
return 1;
};
T look()
{
mutex.lock();
T looked;
if (prvNrItems() >0)
looked = data[pop_ptr];
mutex.unlock();
return looked;
};
//just remove what would be popped
void dump()
{
mutex.lock();
if (prvNrItems() >0)
{
if (++pop_ptr >= size)
pop_ptr = 0;
}
mutex.unlock();
}
void clear()
{
mutex.lock();
push_ptr = 0;
pop_ptr = 0;
mutex.unlock();
};
protected:
T* data;
int push_ptr;
int pop_ptr;
int size;
QMutex mutex;
int prvNrItems()
{
int result = push_ptr - pop_ptr;
if (result < 0)
result += size;
return result;
};
};
#endif // CBUFFER_H

168
hit2023v2/datareceiver.cpp Normal file
View File

@ -0,0 +1,168 @@
#include "datareceiver.h"
#include "dev_commands.h"
#include "helpers.h"
DataReceiver::DataReceiver(QObject *parent) : QObject(parent), dataBuffer(RECEIVER_BUFFER_SIZE)
{
connect(this, DataReceiver::sigInit, this, DataReceiver::onInit);
connect(this, DataReceiver::sigDeinit, this, DataReceiver::onDeinit);
connect(this, DataReceiver::sigConfigureEthSettings, this, DataReceiver::onConfigureEthSettings);
moveToThread(&thread);
thread.start();
init();
}
DataReceiver::~DataReceiver()
{
deinit();
thread.quit();
thread.wait();
}
//********************** Receiving data **************************
void DataReceiver::readData()
{
int size_received_bytes;
while ((size_received_bytes = dataSocket->readDatagram(tmpBuffer, DATA_PACKET_SIZE)) > 0)
{
//look if the packet isn't too short
int expected_size_bytes = ethBunch * (DATA_PACKET_HEADER_SIZE + DATA_SYNC_HEADER_SIZE + dmaBunch*DATA_BLOCK_SIZE);
if (size_received_bytes < expected_size_bytes)
continue;
for (int ethb = 0; ethb < ethBunch; ethb++)
{
int baseaddr = ethb * (DATA_PACKET_HEADER_SIZE + DATA_SYNC_HEADER_SIZE + dmaBunch*DATA_BLOCK_SIZE);
//check the header
if (BYTES2SHORT(tmpBuffer+baseaddr+0) != 0x5555)
continue;
if (BYTES2SHORT(tmpBuffer+baseaddr+2) != COMMAND_DATA_TRANSFER)
continue;
if ((BYTES2SHORT(tmpBuffer+baseaddr+4)*2) != (DATA_SYNC_HEADER_SIZE + dmaBunch*DATA_BLOCK_SIZE))
continue;
//read sync data;
SyncFrame sync;
sync.local_ctr = BYTES2SHORT(tmpBuffer+baseaddr+DATA_PACKET_HEADER_SIZE);
sync.global_ctr = BYTES2SHORT(tmpBuffer+baseaddr+DATA_PACKET_HEADER_SIZE+2);
sync.sma_state = BYTES2SHORT(tmpBuffer+baseaddr+DATA_PACKET_HEADER_SIZE+4);
sync.device_nr = devNr;
sync.data_ok = 1;
for (int dmab=0; dmab<dmaBunch; dmab++)
{
framesReceived++;
int baseaddr2 = baseaddr + dmab*DATA_BLOCK_SIZE;
if (outputEnabled)
{
BufferData data_to_push(sensorsPerBoard * DATA_SAMPLES_PER_SENSOR);
data_to_push.sync_frame = sync;
int baseaddr3 = baseaddr2 + DATA_PACKET_HEADER_SIZE + DATA_SYNC_HEADER_SIZE;
for (int s = 0; s < (sensorsPerBoard * DATA_SAMPLES_PER_SENSOR); s++)
data_to_push.sensor_data[s] = 65535 - BYTES2SHORT(tmpBuffer + baseaddr3 + 2*s);
dataBuffer.push(data_to_push);
framesFromLastSig++;
}
}
}
}
if (framesFromLastSig >= RECEIVER_FRAMES_PER_SIG)
{
framesFromLastSig = 0;
emit sigDataReady(this);
}
}
//********************** Internal slots ************************
void DataReceiver::onTimer()
{
frameRate = framesReceived * 1000 / RECEIVER_TIMER_PERIOD_MS;
framesReceived = 0;
}
void DataReceiver::onInit()
{
if (dataSocket == NULL)
{
dataSocket = new QUdpSocket(this);
connect(dataSocket, QUdpSocket::readyRead, this, DataReceiver::readData);
}
if (timer == NULL)
{
timer = new QTimer(this);
connect(timer, QTimer::timeout, this, onTimer);
timer->start(RECEIVER_TIMER_PERIOD_MS);
}
initSemaphore.release();
}
void DataReceiver::onDeinit()
{
if (dataSocket != NULL)
{
delete dataSocket;
dataSocket = NULL;
}
if (timer != NULL)
{
delete timer;
timer = NULL;
}
initSemaphore.release();
}
void DataReceiver::onConfigureEthSettings()
{
dataSocket->close();
dataSocket->bind(address, port);
}
//********************** Controlling DataReceiver************************
void DataReceiver::init()
{
emit sigInit();
initSemaphore.acquire(); //wait for initialization
}
void DataReceiver::deinit()
{
emit sigDeinit();
initSemaphore.acquire(); //wait for deinitialization
}
void DataReceiver::configureEthSettings(QHostAddress address_to_set, quint16 port_to_set)
{
address = address_to_set;
port = port_to_set;
emit sigConfigureEthSettings();
}
void DataReceiver::configureBunchSize(int dma, int eth)
{
dmaBunch = dma;
ethBunch = eth;
}
void DataReceiver::outputEnable (int en)
{
outputEnabled = en;
if (!en)
dataBuffer.clear();
}

149
hit2023v2/datareceiver.h Normal file
View File

@ -0,0 +1,149 @@
#ifndef DATARECEIVER_H
#define DATARECEIVER_H
#include <QObject>
#include <QUdpSocket>
#include <QTimer>
#include <QThread>
#include <QSemaphore>
#include "cbuffer.h"
#define DATA_PACKET_HEADER_SIZE 6
#define DATA_SYNC_HEADER_SIZE 6
#define DATA_BYTES_PER_SAMPLE 2
#define DATA_SAMPLES_PER_SENSOR 64
#define DATA_MAX_SENSORS_PER_BOARD 5
#define DATA_MAX_BUNCH 16 //max. product of dmaBunch * ethBunch
//#define DATA_BLOCK_SIZE (DATA_SENSORS_PER_BOARD * DATA_SAMPLES_PER_SENSOR * DATA_BYTES_PER_SAMPLE)
#define DATA_BLOCK_SIZE (sensorsPerBoard * DATA_SAMPLES_PER_SENSOR * DATA_BYTES_PER_SAMPLE)
#define DATA_PACKET_SIZE ( DATA_MAX_BUNCH * (DATA_PACKET_HEADER_SIZE + DATA_SYNC_HEADER_SIZE + DATA_BLOCK_SIZE ) )
#define DATA_MAX_BLOCK_SIZE (DATA_MAX_SENSORS_PER_BOARD * DATA_SAMPLES_PER_SENSOR * DATA_BYTES_PER_SAMPLE)
#define DATA_MAX_PACKET_SIZE ( DATA_MAX_BUNCH * (DATA_PACKET_HEADER_SIZE + DATA_SYNC_HEADER_SIZE + DATA_MAX_BLOCK_SIZE ) )
#define RECEIVER_BUFFER_SIZE 10000
#define RECEIVER_TIMER_PERIOD_MS 200 //The period of the timer to measure data rate. The measurement is always properly scaled.
#define RECEIVER_FRAMES_PER_SIG 100 //The DataReady signal is transmitted only every N frames, not to overload queued signals framework.
typedef struct
{
//unsigned short channel_id;
unsigned short local_ctr;
unsigned short global_ctr;
unsigned short sma_state;
//these files are additional compared to STM side
unsigned short dummy = 0xFFFF; //for nice structure packing
int device_nr;
int data_ok;
} SyncFrame;
class BufferData
{
public:
SyncFrame sync_frame;
int buffer_size;
unsigned short* sensor_data;
BufferData() : buffer_size(0), sensor_data(NULL) {}
BufferData(int size) : buffer_size(0), sensor_data(NULL)
{
resize(size);
}
void resize(int size)
{
if (size == buffer_size)
return; //no need to change
if (sensor_data)
{
delete[] sensor_data;
sensor_data = NULL;
}
buffer_size = size;
if (size) //do not allocate memory for an empty buffer
sensor_data = new unsigned short[size];
}
BufferData(const BufferData& master) : buffer_size(0), sensor_data(NULL)
{
sync_frame = master.sync_frame;
resize(master.buffer_size);
memcpy(sensor_data, master.sensor_data, buffer_size*sizeof(unsigned short));
}
BufferData& operator=(const BufferData& master)
{
if (this == &master)
return *this; //self-assignment
sync_frame = master.sync_frame;
resize(master.buffer_size);
memcpy(sensor_data, master.sensor_data, buffer_size*sizeof(unsigned short));
return *this;
}
~BufferData()
{
resize(0); // :)
}
//unsigned short sensor_data[DATA_SENSORS_PER_BOARD * DATA_SAMPLES_PER_SENSOR];
};
typedef CBuffer<BufferData> DataBuffer;
class DataReceiver : public QObject
{
Q_OBJECT
public:
explicit DataReceiver(QObject *parent = 0);
~DataReceiver();
void configureEthSettings(QHostAddress address_to_set, quint16 port_to_set);
void configureBunchSize(int dma, int eth);
void outputEnable(int en);
int frameRate = 0;
int devNr = 0;
int sensorsPerBoard = 2;
DataBuffer dataBuffer;
signals:
void sigInit();
void sigDeinit();
void sigConfigureEthSettings();
void sigDataReady(DataReceiver* ptr);
public slots:
void onTimer();
protected:
void init();
void deinit();
QThread thread;
QSemaphore initSemaphore;
QTimer* timer = NULL;
QUdpSocket* dataSocket = NULL;
QHostAddress address;
quint16 port;
int outputEnabled = 0;
int dmaBunch = 1;
int ethBunch = 1;
char tmpBuffer[DATA_MAX_PACKET_SIZE];
int framesReceived = 0; //to calculate frame rate
int framesFromLastSig = 0;
protected slots:
void readData();
void onInit();
void onDeinit();
void onConfigureEthSettings();
};
#endif // DATARECEIVER_H

123
hit2023v2/dev_commands.h Normal file
View File

@ -0,0 +1,123 @@
#ifndef DEV_COMMANDS_H
#define DEV_COMMANDS_H
#define COMMAND_PING 0x0001
//L: 0
//D: []
//Return the same
#define COMMAND_DEBUG_LED_OFF 0x0010
//L: 0
//D: [];
//Turn off green LED
#define COMMAND_DEBUG_LED_ON 0x0011
//L: 0
//D: [];
//Turn on green LED
// ***DEVICE CONTROL***
#define COMMAND_LEDS_DISABLE 0x0110
//L: 0
//D: [];
//Disable and turn off all LEDs
#define COMMAND_LEDS_ENABLE 0x0111
//L: 0
//D: [];
//Enable all LEDs
// ***TRIGGER SETTING***
#define COMMAND_TRIGGER_DISABLE 0x0210
//L: 0
//D: [];
//Disable trigger generation in master mode
#define COMMAND_TRIGGER_ENABLE 0x0211
//L: 0
//D: [];
//Enable trigger generation in master mode
#define COMMAND_TRIGGER_SET_SLAVE 0x0220
//L: 0
//D: [];
//Set trigger to slave mode
#define COMMAND_TRIGGER_SET_MASTER 0x0221
//L: 0
//D: [];
//Set trigger to master mode
#define COMMAND_TRIGGER_SET_PERIOD 0x0230
//L: 1 L: 0
//D: [Period_ticks] D: []
//Set trigger period for master mode in timer ticks
#define COMMAND_TRIGGER_SET_TINT 0x0240
//L: 1 L: 0
//D: [Tint_ticks] D: []
//Set integration time in timer ticks
#define COMMAND_SET_GAIN 0x0250
//L: 1 L:0
//D: [gain] D: []
#define COMMAND_TRIGGER_SET_MASTER_DELAY 0x0260
//L: 1 L: 0
//D: [Tdelay_ticks] D: []
//Set trigger delay time in timer ticks for master mode.
#define COMMAND_TRIGGER_SET_SLAVE_DELAY 0x0270
//L: 1 L: 0
//D: [Tdelay_ticks] D: []
//Set trigger delay time in timer ticks for slave mode.
// ***DAQ CONTROL***
#define COMMAND_DAQ_DISABLE 0x0310
//L: 0
//D: [];
//Disable sending data
#define COMMAND_DAQ_ENABLE 0x0311
//L: 0
//D: [];
//Enable sending data
#define COMMAND_DAQ_RESET_COUNTERS 0x0321
//L: 0
//D: []
//Reset synchronization counters
#define COMMAND_DAQ_FLUSH_DATA 0x0322
//L: 0
//D: []
//Send all remaining data over data socket
#define COMMAND_DAQ_CONFIG_PEER 0x0331
//L: 5 L: 0
//D: [ip ip ip ip port] D: []
//Set connection settings (peer IP and port) for data transfer
//Warning: IP is sent as 4 shorts with MSB=0!
// ***SLOW CONTROL***
#define COMMAND_SLOWCTRL_SNAPSHOT 0x0410
//L: 0 L: 10
//D:[] D: [(Readout of 5 ADC channels as 32-bit integers)]
//Slow control snapshot - read all channels of ADC
// ***DATA TRANSFER - SOCKET 1!!!!***
#define COMMAND_DATA_TRANSFER 0x8000
//(no incoming packet) L: 64*daq_dma_frame_bunch*daq_eth_frame_bunch
//(no incoming packet) D: [(Readout of 5 ADC channels as 32-bit integers)]
//Slow control snapshot - read all channels of ADC
#endif // DEV_COMMANDS_H

482
hit2023v2/device.cpp Normal file
View File

@ -0,0 +1,482 @@
#include "device.h"
#include "dev_commands.h"
#include "helpers.h"
#include <QtGlobal>
//************** Constructor ********************
// Qt5
/*
Device::Device(QObject *parent) : QObject(parent), controlSocket(this)
{
connect(&controlSocket, QTcpSocket::connected, this, Device::onConnected);
connect(&controlSocket,
static_cast<void(QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error),
this, Device::onSocketError);
connect(&controlSocket, QTcpSocket::disconnected, this, Device::onDisconnected);
*/
/*dataReceiver.moveToThread(&receiverThread);
receiverThread.start();
dataReceiver.init();*/
//}
//Qt6
Device::Device(QObject *parent) : QObject(parent), controlSocket(this)
{
connect(&controlSocket, &QTcpSocket::connected, this, &Device::onConnected);
connect(&controlSocket, &QAbstractSocket::errorOccurred,
[this](QAbstractSocket::SocketError socketError) {
this->onSocketError(socketError);
});
connect(&controlSocket, &QTcpSocket::disconnected, this, &Device::onDisconnected);
/*dataReceiver.moveToThread(&receiverThread);
receiverThread.start();
dataReceiver.init();*/
}
Device::~Device()
{
if (connected)
{
stopAcq();
disconnectDevice();
}
/*receiverThread.quit();
receiverThread.wait();*/
}
//************** Device configuration ********************
void Device::configure(DeviceConfig &cfg)
{
int ip_changed = 0;
for (int i = 0; i < 4; i++)
if (cfg.device_ip[i] != deviceConfig.device_ip[i])
ip_changed = 1;
deviceConfig = cfg;
//update data receiver settings
quint32 ip32 = 0;
unsigned short ipshort[4];
for (int i = 0; i < 4; i++)
{
ip32 <<= 8;
ip32 |= (qint32)(unsigned char)deviceConfig.own_ip[i];
ipshort[i] = (unsigned short)(unsigned char)deviceConfig.own_ip[i];
}
dataReceiver.configureEthSettings(QHostAddress(ip32), DEV_BASE_DATA_PORT + deviceConfig.device_id);
dataReceiver.configureBunchSize(deviceConfig.dma_bunch, deviceConfig.eth_bunch);
dataReceiver.devNr = deviceConfig.device_id;
dataReceiver.sensorsPerBoard = deviceConfig.max_sensors();
if (connected)
{
//re-connect if needed
if (ip_changed)
{
disconnectDevice();
while(connected);
connectDevice();
int ctr = 0;
while (!connected)
{
QThread::msleep(10);
if (++ctr > 100)
{
qWarning(qPrintable(QString("Device %1: IP change: reconnection failed!").arg(deviceConfig.device_id)));
return;
}
}
}
//update device settings
qInfo(qPrintable(QString("Device %1: setting up.").arg(deviceConfig.device_id)));
ctrlMaster(deviceConfig.master);
ctrlSetPeriod(deviceConfig.period);
ctrlSetTint(deviceConfig.tint);
ctrlSetMasterDelay(deviceConfig.master_delay);
ctrlSetSlaveDelay(deviceConfig.slave_delay);
ctrlSetGain(deviceConfig.gain);
ctrlConfigBunch(deviceConfig.dma_bunch, deviceConfig.eth_bunch);
ctrlConfigPeer(ipshort, DEV_BASE_DATA_PORT+ deviceConfig.device_id);
}
}
//************** Device connection ********************
void Device::connectDevice()
{
QString addr_txt = QString("%1.%2.%3.%4")
.arg(deviceConfig.device_ip[0])
.arg(deviceConfig.device_ip[1])
.arg(deviceConfig.device_ip[2])
.arg(deviceConfig.device_ip[3]);
if (connected)
{
qWarning(qPrintable(QString("Device %1: connect: already connected, reconnecting!").arg(deviceConfig.device_id)));
disconnectDevice();
while (connected)
QThread::msleep(1);
}
qInfo(qPrintable(QString("Device %1: trying to connect to %2").arg(deviceConfig.device_id).arg(addr_txt)));
controlSocket.connectToHost(addr_txt, 4000);
}
void Device::disconnectDevice()
{
if (!connected)
qWarning(qPrintable(QString("Device %1: disconnect: device not connected!").arg(deviceConfig.device_id)));
controlSocket.disconnectFromHost();
}
void Device::onConnected()
{
qInfo(qPrintable(QString("Device %1: connected with %2.%3.%4.%5")
.arg(deviceConfig.device_id)
.arg(deviceConfig.device_ip[0])
.arg(deviceConfig.device_ip[1])
.arg(deviceConfig.device_ip[2])
.arg(deviceConfig.device_ip[3]) ));
connected = 1;
configure(deviceConfig);
}
void Device::onSocketError(QAbstractSocket::SocketError socketError)
{
qWarning(qPrintable(QString("Device %1: socket error %2!").arg(deviceConfig.device_id).arg((int)socketError)));
if (controlSocket.state() != QAbstractSocket::ConnectedState)
connected = 0;
else
connected = 1;
}
void Device::onDisconnected()
{
qInfo(qPrintable(QString("Device %1: disconnected.").arg(deviceConfig.device_id)));
connected = 0;
}
//************** Controlling device ********************
void Device::startAcq()
{
qInfo(qPrintable(QString("Device %1: starting data taking...").arg(deviceConfig.device_id)));
if (!connected)
{
qWarning(qPrintable(QString("Device %1: not connected!").arg(deviceConfig.device_id)));
return;
}
dataReceiver.dataBuffer.clear();
dataReceiver.outputEnable(1);
ctrlResetCounters();
ctrlDaq(1);
ctrlTrigger(1);
}
void Device::stopAcq()
{
qInfo(qPrintable(QString("Device %1: stopping data taking...").arg(deviceConfig.device_id)));
if (!connected)
{
qWarning(qPrintable(QString("Device %1: not connected!").arg(deviceConfig.device_id)));
return;
}
ctrlTrigger(0);
QThread::msleep(10);
ctrlFlushData();
ctrlDaq(0);
QThread::msleep(10);
//QThread::msleep(10);
dataReceiver.outputEnable(0);
}
void Device::leds(int leds_enable, int debug_led)
{
if (connected)
{
ctrlLeds(leds_enable);
ctrlDebugLed(debug_led);
}
else
qWarning(qPrintable(QString("Device %1: not connected!").arg(deviceConfig.device_id)));
}
int Device::getFrameRate()
{
return dataReceiver.frameRate;
}
//************** Data exchange ********************
int Device::sendCtrl(unsigned short command, QVector<unsigned short> &data)
{
if (!connected)
{
qWarning(qPrintable(QString("Device %1: not connected!").arg(deviceConfig.device_id)));
return DEV_CTRL_ERROR;
}
int dl = data.length();
char buffer[2*dl + 6];
buffer[0] = 0x55;
buffer[1] = 0x55;
buffer[2] = HI(command);
buffer[3] = LO(command);
buffer[4] = HI(dl);
buffer[5] = LO(dl);
for (int i = 0; i < dl; i++)
{
buffer[2*i+6] = HI(data[i]);
buffer[2*i+7] = LO(data[i]);
}
return (int)controlSocket.write(buffer, 2*dl + 6);
}
int Device::receiveCtrl(unsigned short &command, QVector<unsigned short> &data)
{
if (!connected)
{
qWarning(qPrintable(QString("Device %1: not connected!").arg(deviceConfig.device_id)));
return DEV_CTRL_ERROR;
}
//Wait for data
if (!controlSocket.waitForReadyRead(DEV_CTRL_READ_TIMEOUT))
{
qWarning(qPrintable(QString("Device %1: no data received!").arg(deviceConfig.device_id)));
return DEV_CTRL_ERROR;
}
//Find sync characters
int sync_found = 0;
char buffer;
while (sync_found < 2)
{
if (controlSocket.read(&buffer, 1) <= 0)
{
qWarning(qPrintable(QString("Device %1: no data received!").arg(deviceConfig.device_id)));
return DEV_CTRL_ERROR;
}
if (buffer == 0x55)
sync_found++;
else
qWarning( qPrintable(QString("Device %1: 0x%2 found instead of sync character(0x55)!")
.arg(deviceConfig.device_id).arg((int)(unsigned int)buffer,(int)2,(int)16,QLatin1Char('0'))) );
}
char header[4];
if (controlSocket.read(header,4) < 4)
{
qWarning(qPrintable(QString("Device %1: data receive error when getting header!").arg(deviceConfig.device_id)));
return DEV_CTRL_ERROR;
}
command = BYTES2SHORT(header);
unsigned short dl = BYTES2SHORT(header+2);
char data_buf[2*dl];
if (controlSocket.read(data_buf, 2*dl) < (2*dl))
{
qWarning(qPrintable(QString("Device %1: data receive error when getting data!").arg(deviceConfig.device_id)));
return DEV_CTRL_ERROR;
}
data.clear();
for (int i = 0; i < dl; i++)
data.append(BYTES2SHORT(data_buf + 2*i));
return dl;
}
int Device::queryCtrl(unsigned short command, QVector<unsigned short> &txdata, QVector<unsigned short> &rxdata)
{
if (sendCtrl(command, txdata) == DEV_CTRL_ERROR)
return DEV_CTRL_ERROR;
unsigned short command_rx;
if (receiveCtrl(command_rx, rxdata) == DEV_CTRL_ERROR)
return DEV_CTRL_ERROR;
if (command_rx != command)
return DEV_CTRL_ERROR;
return DEV_CTRL_OK;
}
//************** Simple commands ********************
int Device::ctrlPing()
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
return queryCtrl(COMMAND_PING, txdata, rxdata);
}
int Device::ctrlDebugLed(int state)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
if (state)
return queryCtrl(COMMAND_DEBUG_LED_ON, txdata, rxdata);
else
return queryCtrl(COMMAND_DEBUG_LED_OFF, txdata, rxdata);
}
int Device::ctrlLeds(int en)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
if (en)
return queryCtrl(COMMAND_LEDS_ENABLE, txdata, rxdata);
else
return queryCtrl(COMMAND_LEDS_DISABLE, txdata, rxdata);
}
int Device::ctrlTrigger(int en)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
if (en)
return queryCtrl(COMMAND_TRIGGER_ENABLE, txdata, rxdata);
else
return queryCtrl(COMMAND_TRIGGER_DISABLE, txdata, rxdata);
}
int Device::ctrlMaster(int en)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
if (en)
return queryCtrl(COMMAND_TRIGGER_SET_MASTER, txdata, rxdata);
else
return queryCtrl(COMMAND_TRIGGER_SET_SLAVE, txdata, rxdata);
}
int Device::ctrlSetPeriod(int period)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
txdata.append((unsigned short)period);
return queryCtrl(COMMAND_TRIGGER_SET_PERIOD, txdata, rxdata);
}
int Device::ctrlSetTint(int tint)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
txdata.append((unsigned short)tint);
return queryCtrl(COMMAND_TRIGGER_SET_TINT, txdata, rxdata);
}
int Device::ctrlSetMasterDelay(int tint)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
txdata.append((unsigned short)tint);
return queryCtrl(COMMAND_TRIGGER_SET_MASTER_DELAY, txdata, rxdata);
}
int Device::ctrlSetSlaveDelay(int tint)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
txdata.append((unsigned short)tint);
return queryCtrl(COMMAND_TRIGGER_SET_SLAVE_DELAY, txdata, rxdata);
}
int Device::ctrlDaq(int en)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
if (en)
return queryCtrl(COMMAND_DAQ_ENABLE, txdata, rxdata);
else
return queryCtrl(COMMAND_DAQ_DISABLE, txdata, rxdata);
}
int Device::ctrlResetCounters()
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
return queryCtrl(COMMAND_DAQ_RESET_COUNTERS, txdata, rxdata);
}
int Device::ctrlFlushData()
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
return queryCtrl(COMMAND_DAQ_FLUSH_DATA, txdata, rxdata);
}
int Device::ctrlConfigPeer(unsigned short* ip, unsigned short port)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
for (int i = 0; i < 4; i++)
txdata.append(ip[i]);
txdata.append(port);
return queryCtrl(COMMAND_DAQ_CONFIG_PEER, txdata, rxdata);
}
int Device::ctrlSetGain(int val)
{
QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
txdata.append((unsigned short)(val?1:0));
return queryCtrl(COMMAND_SET_GAIN, txdata, rxdata);
}
int Device::ctrlConfigBunch(int dma, int eth)
{
qWarning("Bunch configuration not implemented!");
return DEV_CTRL_OK;
/*QVector<unsigned short> rxdata;
QVector<unsigned short> txdata;
if (en)
return queryCtrl(COMMAND_DAQ_ENABLE, txdata, rxdata);
else
return queryCtrl(COMMAND_DAQ_DISABLE, txdata, rxdata);*/
}

110
hit2023v2/device.h Normal file
View File

@ -0,0 +1,110 @@
#ifndef DEVICE_H
#define DEVICE_H
#include <QObject>
#include <QTcpSocket>
#include <QUdpSocket>
#include <QVector>
#include <QThread>
#include <QMutex>
#include "datareceiver.h"
#define DEV_CTRL_READ_TIMEOUT 500
#define DEV_CTRL_ERROR -1
#define DEV_CTRL_OK 0
#define DEV_BASE_DATA_PORT 4000
class DeviceConfig
{
public:
unsigned char own_ip[4];
unsigned char device_ip[4];
int device_id;
int hardware_ver;
int master;
int plane; //for ex. X may be 0 and Y may be 1
int position; //physical position within plane
int nr_sensors; //a device may be equipped with only one sensor
int period;
int tint;
int master_delay; //trigger delay values to synchronize boards
int slave_delay;
int gain; //0 (low) or 1 (high); TO BE DONE
int dma_bunch;
int eth_bunch;
int max_sensors()
{
switch(hardware_ver)
{
case 1: return 2; break;
case 2: return 5; break;
default: qCritical("Unsupported hardware version!"); return 0; break;
}
}
int max_channels() {return 64*max_sensors();}
int nr_channels() {return 64*nr_sensors;}
DeviceConfig() : own_ip({10,0,7,1}), device_ip({10,0,7,2}),
device_id(0), hardware_ver(0), master(1), plane(0), position(0), nr_sensors(0),
period(65535), tint(1), master_delay(1), slave_delay(1), gain(0), dma_bunch(1), eth_bunch(1) {}
};
class Device : public QObject
{
Q_OBJECT
public:
explicit Device(QObject *parent = 0);
~Device();
void connectDevice();
void disconnectDevice();
void configure(DeviceConfig &cfg);
void startAcq();
void stopAcq();
void leds(int leds_enable, int debug_led);
int getFrameRate();
DeviceConfig deviceConfig;
DataReceiver dataReceiver;
signals:
protected:
int connected = 0;
QTcpSocket controlSocket;
//QThread receiverThread;
int sendCtrl(unsigned short command, QVector<unsigned short> &data);
int receiveCtrl(unsigned short &command, QVector<unsigned short> &data);
int queryCtrl(unsigned short command, QVector<unsigned short> &txdata, QVector<unsigned short> &rxdata);
int ctrlPing();
int ctrlDebugLed(int state);
int ctrlLeds(int en);
int ctrlTrigger(int en);
int ctrlMaster(int en);
int ctrlSetPeriod(int period);
int ctrlSetTint(int tint);
int ctrlDaq(int en);
int ctrlResetCounters();
int ctrlFlushData();
int ctrlConfigPeer(unsigned short *ip, unsigned short port);
int ctrlSetGain(int val);
int ctrlConfigBunch(int dma, int eth);
int ctrlSetMasterDelay(int tint);
int ctrlSetSlaveDelay(int tint);
protected slots:
void onConnected();
void onSocketError(QAbstractSocket::SocketError socketError);
void onDisconnected();
};
#endif // DEVICE_H

288
hit2023v2/dialogbeta.cpp Normal file
View File

@ -0,0 +1,288 @@
#include "dialogbeta.h"
#include "ui_dialogbeta.h"
#include <QFileDialog>
#define RUNNING 1
#define STOPPED 0
#define STOP_ISSUED -1
DialogBeta::DialogBeta(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogBeta)
{
ui->setupUi(this);
runState = STOPPED;
nrRunsDone = 0;
maxSpeed = 1500;
}
DialogBeta::~DialogBeta()
{
timer.stop();
disconnect(&timer, QTimer::timeout, this, &DialogBeta::onTimer);
delete ui;
}
void DialogBeta::showEvent(QShowEvent * event)
{
if (!event->spontaneous())
{
ui->spinScanSpeed->setMaximum(maxSpeed);
ui->lineRunsDone->setText(QString("%1").arg(nrRunsDone));
//data logging possible only if global data logging is switched off
if (theHW->eventBuilder.isLogging())
ui->checkSaveRawData->setEnabled(FALSE);
connect(&timer, QTimer::timeout, this, &DialogBeta::onTimer);
timer.start(250);
}
}
//************** Timer event ***************
void DialogBeta::onTimer()
{
theStepper->command_GAP(STEPPER_SAP_ACTUAL_POSITION, &currentPosition);
QString to_print = QString("%1").arg(currentPosition);
ui->lineStepperPosition->setText(to_print);
}
//************** Processing ***************
void DialogBeta::run(QString raw_data_filename)
{
runState = RUNNING;
//Prepare measurement
ui->plotResultsMean->clearGraphs();
ui->plotResultsStd->clearGraphs();
int nr_devices = theHW->devices.length();
int start_pos = ui->spinStartPos->value();
int end_pos = ui->spinEndPos->value();
int scan_speed = ui->spinScanSpeed->value();
//Data structures for plot
QVector<double> xdata;
QVector<double> ymeandata;
QVector<double> ystddata;
ui->plotResultsMean->addGraph();
ui->plotResultsStd->addGraph();
for (int ch = 0; ch < nr_devices*128; ch++)
xdata.append(ch);
double ymeanmin = 1e+10;
double ymeanmax = -1e+10;
double ystdmin = 1e+10;
double ystdmax = -1e+10;
//Set up stepper drive
qInfo("Setting up stepper drive...");
theStepper->command_SAP(4,maxSpeed);
theStepper->command_MVP(STEPPER_MVP_ABSOLUTE, start_pos);
while (currentPosition != start_pos)
{
QCoreApplication::processEvents();
QThread::msleep(10);
if (runState == STOP_ISSUED)
{
theStepper->command_MST();
runState = STOPPED;
return;
}
}
//Measure!
qInfo("Scanning...");
theStepper->command_SAP(4,scan_speed);
theStepper->command_MVP(STEPPER_MVP_ABSOLUTE, end_pos);
if (raw_data_filename.length())
theHW->eventBuilder.startLogging(raw_data_filename);
theHW->eventBuilder.startTakingHistos(-1);
while ((runState != STOP_ISSUED) && (currentPosition != end_pos))
{
QCoreApplication::processEvents();
QThread::msleep(10);
if (runState == STOP_ISSUED)
{
theStepper->command_MST();
runState = STOPPED;
return;
}
}
theHW->eventBuilder.stopTakingHistos();
if (raw_data_filename.length())
theHW->eventBuilder.stopLogging();
//Process results
qInfo("Processing data...");
BetaTestResult result;
//Collect sensor data
QVector<Histogram> histos = theHW->eventBuilder.getHistos();
result.mean.fill(0, nr_devices*128);
result.std.fill(0, nr_devices*128);
for (int i = 0; i < result.mean.length(); i++)
{
histos[i].MS(&(result.mean[i]), &(result.std[i]));
}
//Add other information
result.nracqs = histos[0].getNrSamples();
result.startpos = start_pos;
result.endpos = end_pos;
result.motorspeed = scan_speed;
//Store result
results.append(result);
//Plot data...
ymeandata.clear();
ymeandata.fill(0, nr_devices*128);
ystddata.clear();
ystddata.fill(0,nr_devices*128);
for (int ch = 0; ch < (nr_devices*128); ch++)
{
ymeandata[ch] = result.mean[ch];
if (result.mean[ch] > ymeanmax)
ymeanmax = result.mean[ch];
if (result.mean[ch] < ymeanmin)
ymeanmin = result.mean[ch];
ystddata[ch] = result.std[ch];
if (result.std[ch] > ystdmax)
ystdmax = result.std[ch];
if (result.std[ch] < ystdmin)
ystdmin = result.std[ch];
}
ui->plotResultsMean->xAxis->setRange(0, nr_devices*128-1);
ui->plotResultsMean->yAxis->setRange(ymeanmin, ymeanmax);
ui->plotResultsStd->xAxis->setRange(0, nr_devices*128-1);
ui->plotResultsStd->yAxis->setRange(ystdmin, ystdmax);
ui->plotResultsMean->graph(0)->setData(xdata, ymeandata);
ui->plotResultsStd->graph(0)->setData(xdata, ystddata);
ui->plotResultsMean->replot();
ui->plotResultsStd->replot();
nrRunsDone++;
ui->lineRunsDone->setText(QString("%1").arg(nrRunsDone));
qInfo("Scan finished!");
runState = STOPPED;
}
//************** Slots ****************
void DialogBeta::onHistogramCompleted()
{
histoReady = 1;
}
void DialogBeta::on_pushRun_pressed()
{
if (runState)
{
runState = STOP_ISSUED;
}
else
{
ui->pushRun->setText("Stop");
ui->pushClear->setEnabled(false);
ui->pushSave->setEnabled(false);
QString raw_data_filename = QString("");
if (ui->checkSaveRawData->isChecked())
raw_data_filename = QFileDialog::getSaveFileName(this, "Select file for saving data", "", tr("Binary log files (*.dat)"));
if (raw_data_filename.length())
{
//Make copy of current settings
QString ini_filename = raw_data_filename/*.left(filename.lastIndexOf(QString("."))) */ + QString(".ini");
QSettings* settings_copy = new QSettings(ini_filename,QSettings::IniFormat);
copyQSettings (deviceSettings, settings_copy);
settings_copy->sync();
delete settings_copy;
}
run(raw_data_filename);
ui->pushRun->setText("Run");
ui->pushClear->setEnabled(true);
ui->pushSave->setEnabled(true);
}
}
void DialogBeta::on_pushSave_pressed()
{
QString filename = QFileDialog::getSaveFileName(this, "Select file for saving data", "", tr("Comma separated files (*.csv)"));
QString delimiter = QString(",");
if (filename.length() == 0)
return;
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << qSetFieldWidth(14) << qSetRealNumberPrecision(8);
for (int row = 0; row < results.length(); row++)
{
out << results[row].nracqs << delimiter
<< results[row].startpos << delimiter
<< results[row].endpos << delimiter
<< results[row].motorspeed;
for (int col = 0; (col < results[row].mean.length()) && (col < results[row].std.length()); col++)
out << delimiter << results[row].mean[col] << delimiter << results[row].std[col];
out << QString("\n");
}
file.close();
}
void DialogBeta::on_pushClear_pressed()
{
nrRunsDone = 0;
results.clear();
ui->lineRunsDone->setText(QString("%1").arg(nrRunsDone));
}
void DialogBeta::on_pushLeft_pressed()
{
theStepper->command_ROL(maxSpeed);
}
void DialogBeta::on_pushLeft_released()
{
theStepper->command_MST();
}
void DialogBeta::on_pushRight_pressed()
{
theStepper->command_ROR(maxSpeed);
}
void DialogBeta::on_pushRight_released()
{
theStepper->command_MST();
}
void DialogBeta::on_pushResetCtr_pressed()
{
theStepper->command_SAP(STEPPER_SAP_ACTUAL_POSITION, 0);
}

69
hit2023v2/dialogbeta.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef DIALOGBETA_H
#define DIALOGBETA_H
#include <QDialog>
#include <QVector>
#include <QList>
#include <QTimer>
#include <QSettings>
#include "hw.h"
#include "stepper.h"
#include "histogram.h"
#include "helpers.h"
typedef struct
{
int nracqs;
int startpos;
int endpos;
int motorspeed;
QVector<double> mean;
QVector<double> std;
} BetaTestResult;
namespace Ui {
class DialogBeta;
}
class DialogBeta : public QDialog
{
Q_OBJECT
public:
explicit DialogBeta(QWidget *parent = 0);
~DialogBeta();
HW* theHW;
Stepper* theStepper;
QSettings* deviceSettings;
int maxSpeed;
int currentPosition;
public slots:
void showEvent(QShowEvent *event);
void onHistogramCompleted();
void onTimer();
protected:
int runState;
int histoReady;
int nrRunsDone;
QList<BetaTestResult> results;
QTimer timer;
void run(QString raw_data_filename);
private slots:
void on_pushRun_pressed();
void on_pushSave_pressed();
void on_pushClear_pressed();
void on_pushLeft_pressed();
void on_pushLeft_released();
void on_pushRight_pressed();
void on_pushRight_released();
void on_pushResetCtr_pressed();
private:
Ui::DialogBeta *ui;
};
#endif // DIALOGLINEARITY_H

425
hit2023v2/dialogbeta.ui Normal file
View File

@ -0,0 +1,425 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogBeta</class>
<widget class="QDialog" name="DialogBeta">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>844</width>
<height>632</height>
</rect>
</property>
<property name="windowTitle">
<string>Beta Scanner</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>490</x>
<y>590</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>821</width>
<height>571</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Motor control</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QPushButton" name="pushLeft">
<property name="text">
<string>Left!</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="pushRight">
<property name="text">
<string>Right!</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="lineStepperPosition">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushResetCtr">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Scan settings</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Start pos:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Scanning speed</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinScanSpeed">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>2048</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinStartPos">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1800000</number>
</property>
<property name="singleStep">
<number>10000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>End pos:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinEndPos">
<property name="maximum">
<number>1800000</number>
</property>
<property name="singleStep">
<number>10000</number>
</property>
<property name="value">
<number>1800000</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushRun">
<property name="text">
<string>Run!</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkSaveRawData">
<property name="text">
<string>Save raw data</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Runs:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineRunsDone">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="pushClear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushSave">
<property name="text">
<string>Save results...</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_12">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Signal mean</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="plotResultsMean" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Signal standard deviation</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="plotResultsStd" native="true"/>
</item>
</layout>
</item>
</layout>
</widget>
<zorder>buttonBox</zorder>
<zorder>horizontalLayoutWidget</zorder>
<zorder>verticalSpacer_4</zorder>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogBeta</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogBeta</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

238
hit2023v2/dialogdevices.cpp Normal file
View File

@ -0,0 +1,238 @@
#include "dialogdevices.h"
#include "ui_dialogdevices.h"
#include "helpers.h"
DialogDevices::DialogDevices(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogDevices)
{
ui->setupUi(this);
}
DialogDevices::~DialogDevices()
{
delete ui;
}
//***************** Initialization ******************
void DialogDevices::showEvent(QShowEvent * event)
{
if (!event->spontaneous())
{
if (deviceSettings != NULL)
{
top(deviceSettings);
deviceSettings->beginGroup("Global");
ui->spinNrDevices->setValue(deviceSettings->value("NrDevices", int(1)).toInt());
ui->tableDevices->setColumnCount(8);
QStringList h_header;
h_header.append("IP Address");
h_header.append("Hardware ver.");
h_header.append("Layer");
h_header.append("Position");
h_header.append("Sensors");
h_header.append("Master");
h_header.append("Master dly");
h_header.append("Slave dly");
ui->tableDevices->setHorizontalHeaderLabels(h_header);
importSettings();
}
initialized = 1;
}
QDialog::showEvent(event);
}
//***************** Processing ******************
void DialogDevices::accept()
{
// qInfo("Accepted!");
if (validateAndSave())
QDialog::accept();
}
void DialogDevices::importSettings()
{
int nr_devices = ui->spinNrDevices->value();
ui->tableDevices->setRowCount(nr_devices);
for (int dev_nr = 0; dev_nr < nr_devices; dev_nr++)
{
if (dev_nr >= last_nr_devices) //update only new rows!
{
top(deviceSettings);
QString group_label = QString("Device%1").arg(dev_nr);
deviceSettings->beginGroup(group_label);
QTableWidgetItem* newItem;
newItem = new QTableWidgetItem(deviceSettings->value("IP","0.0.0.0").toString());
ui->tableDevices->setItem(dev_nr, 0, newItem );
newItem = new QTableWidgetItem(deviceSettings->value("HardwareVer","1").toString());
ui->tableDevices->setItem(dev_nr, 1, newItem );
newItem = new QTableWidgetItem(deviceSettings->value("Plane","0").toString());
ui->tableDevices->setItem(dev_nr, 2, newItem );
newItem = new QTableWidgetItem(deviceSettings->value("Position","0").toString());
ui->tableDevices->setItem(dev_nr, 3, newItem );
newItem = new QTableWidgetItem(deviceSettings->value("Sensors","2").toString());
ui->tableDevices->setItem(dev_nr, 4, newItem );
newItem = new QTableWidgetItem(deviceSettings->value("Master","0").toString());
ui->tableDevices->setItem(dev_nr, 5, newItem );
newItem = new QTableWidgetItem(deviceSettings->value("MasterDelay","22").toString());
ui->tableDevices->setItem(dev_nr, 6, newItem );
newItem = new QTableWidgetItem(deviceSettings->value("SlaveDelay","1").toString());
ui->tableDevices->setItem(dev_nr, 7, newItem );
}
}
last_nr_devices = nr_devices;
}
int DialogDevices::validateAndSave()
{
if (deviceSettings == NULL)
return 0;
int nr_devices = ui->spinNrDevices->value();
int data_ok = 1;
//check each table row
for (int dev_nr = 0; dev_nr < nr_devices; dev_nr++)
{
//first the IP
QString user_data = ui->tableDevices->item(dev_nr,0)->text();
QString generated = ip2num(user_data);
//if the strings are identical, save the value and return 1
if (generated.compare(user_data) != 0)
data_ok = 0;
ui->tableDevices->item(dev_nr,0)->setText(generated);
//hardware version
user_data = ui->tableDevices->item(dev_nr,1)->text();
int num_hw = user_data.toInt();
if (num_hw < 1)
num_hw = 1;
if (num_hw > 2)
num_hw = 2;
generated = QString("%1").arg(num_hw);
//if the strings are identical, save the value and return 1
if (generated.compare(user_data) != 0)
data_ok = 0;
ui->tableDevices->item(dev_nr,1)->setText(generated);
//now the plane
user_data = ui->tableDevices->item(dev_nr,2)->text();
int num_value = user_data.toInt();
if (num_value < 0)
num_value = 0;
generated = QString("%1").arg(num_value);
//if the strings are identical, save the value and return 1
if (generated.compare(user_data) != 0)
data_ok = 0;
ui->tableDevices->item(dev_nr,2)->setText(generated);
//now physical position
user_data = ui->tableDevices->item(dev_nr,3)->text();
num_value = user_data.toInt();
if (num_value < 0)
num_value = 0;
generated = QString("%1").arg(num_value);
//if the strings are identical, save the value and return 1
if (generated.compare(user_data) != 0)
data_ok = 0;
ui->tableDevices->item(dev_nr,3)->setText(generated);
//now number of sensors
user_data = ui->tableDevices->item(dev_nr,4)->text();
num_value = user_data.toInt();
int max_sensors = (num_hw == 1) ? 2 : 5;
if (num_value < 1)
num_value = 1;
if (num_value > max_sensors)
num_value = max_sensors;
generated = QString("%1").arg(num_value);
//if the strings are identical, save the value and return 1
if (generated.compare(user_data) != 0)
data_ok = 0;
ui->tableDevices->item(dev_nr,4)->setText(generated);
//now master selector
user_data = ui->tableDevices->item(dev_nr,5)->text();
num_value = user_data.toInt();
if (num_value < 0)
num_value = 0;
if (num_value > 1)
num_value = 1;
generated = QString("%1").arg(num_value);
//if the strings are identical, save the value and return 1
if (generated.compare(user_data) != 0)
data_ok = 0;
ui->tableDevices->item(dev_nr,5)->setText(generated);
//now master delay
user_data = ui->tableDevices->item(dev_nr,6)->text();
num_value = user_data.toInt();
if (num_value < 1)
num_value = 1;
if (num_value > 255)
num_value = 255;
generated = QString("%1").arg(num_value);
//if the strings are identical, save the value and return 1
if (generated.compare(user_data) != 0)
data_ok = 0;
ui->tableDevices->item(dev_nr,6)->setText(generated);
//now slave delay
user_data = ui->tableDevices->item(dev_nr,7)->text();
num_value = user_data.toInt();
if (num_value < 1)
num_value = 1;
if (num_value > 255)
num_value = 255;
generated = QString("%1").arg(num_value);
//if the strings are identical, save the value and return 1
if (generated.compare(user_data) != 0)
data_ok = 0;
ui->tableDevices->item(dev_nr,7)->setText(generated);
}
//now store the data
if (!data_ok)
return 0;
top(deviceSettings);
deviceSettings->beginGroup("Global");
deviceSettings->setValue("NrDevices", nr_devices);
for (int dev_nr = 0; dev_nr < nr_devices; dev_nr++)
{
top(deviceSettings);
QString group_label = QString("Device%1").arg(dev_nr);
deviceSettings->beginGroup(group_label);
deviceSettings->setValue("IP", ui->tableDevices->item(dev_nr,0)->text());
deviceSettings->setValue("HardwareVer", ui->tableDevices->item(dev_nr,1)->text());
deviceSettings->setValue("Plane", ui->tableDevices->item(dev_nr,2)->text());
deviceSettings->setValue("Position", ui->tableDevices->item(dev_nr,3)->text());
deviceSettings->setValue("Sensors", ui->tableDevices->item(dev_nr,4)->text());
deviceSettings->setValue("Master", ui->tableDevices->item(dev_nr,5)->text());
deviceSettings->setValue("MasterDelay", ui->tableDevices->item(dev_nr,6)->text());
deviceSettings->setValue("SlaveDelay", ui->tableDevices->item(dev_nr,7)->text());
}
return 1;
}
void DialogDevices::on_spinNrDevices_valueChanged(int arg1)
{
if (initialized)
importSettings();
}

36
hit2023v2/dialogdevices.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef DIALOGDEVICES_H
#define DIALOGDEVICES_H
#include <QDialog>
#include <QSettings>
#include <QShowEvent>
namespace Ui {
class DialogDevices;
}
class DialogDevices : public QDialog
{
Q_OBJECT
public:
explicit DialogDevices(QWidget *parent = 0);
~DialogDevices();
QSettings* deviceSettings = NULL;
public slots:
void showEvent(QShowEvent *event);
void accept();
protected:
int validateAndSave();
void importSettings();
int last_nr_devices = -1;
int initialized = 0;
private slots:
void on_spinNrDevices_valueChanged(int arg1);
private:
Ui::DialogDevices *ui;
};
#endif // DIALOGDEVICES_H

101
hit2023v2/dialogdevices.ui Normal file
View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogDevices</class>
<widget class="QDialog" name="DialogDevices">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>573</width>
<height>233</height>
</rect>
</property>
<property name="windowTitle">
<string>Devices</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>210</x>
<y>190</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>10</y>
<width>531</width>
<height>171</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Number of devices</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinNrDevices">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="tableDevices"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogDevices</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogDevices</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,74 @@
#include "dialoghostip.h"
#include "ui_dialoghostip.h"
#include "helpers.h"
#include <QStringList>
DialogHostIp::DialogHostIp(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogHostIp)
{
ui->setupUi(this);
}
DialogHostIp::~DialogHostIp()
{
delete ui;
}
//***************** Initialization ******************
void DialogHostIp::showEvent(QShowEvent * event)
{
if (!event->spontaneous())
if (deviceSettings != NULL)
{
top(deviceSettings);
deviceSettings->beginGroup("Global");
QString ip = deviceSettings->value("HostIp", QString("0.0.0.0")).toString();
ui->lineIp->setText(ip);
}
QDialog::showEvent(event);
}
//***************** Processing ******************
void DialogHostIp::accept()
{
// qInfo("Accepted!");
if (validateAndSave())
QDialog::accept();
}
int DialogHostIp::validateAndSave()
{
if (deviceSettings == NULL)
return 0;
QString user_data = ui->lineIp->text();
QString generated = ip2num(user_data);
//if the strings are identical, save the value and return 1
if (generated.compare(user_data) == 0)
{
top(deviceSettings);
deviceSettings->beginGroup("Global");
deviceSettings->setValue("HostIp", generated);
return 1;
}
else
//if not, display the parsed value and return 0
{
ui->lineIp->setText(generated);
return 0;
}
}

33
hit2023v2/dialoghostip.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef DIALOGHOSTIP_H
#define DIALOGHOSTIP_H
#include <QDialog>
#include <QSettings>
#include <QShowEvent>
namespace Ui {
class DialogHostIp;
}
class DialogHostIp : public QDialog
{
Q_OBJECT
public:
explicit DialogHostIp(QWidget *parent = 0);
~DialogHostIp();
QSettings* deviceSettings = NULL;
public slots:
void showEvent(QShowEvent *event);
void accept();
protected:
int validateAndSave();
private slots:
private:
Ui::DialogHostIp *ui;
};
#endif // DIALOGHOSTIP_H

90
hit2023v2/dialoghostip.ui Normal file
View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogHostIp</class>
<widget class="QDialog" name="DialogHostIp">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>185</width>
<height>99</height>
</rect>
</property>
<property name="windowTitle">
<string>Host IP</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>10</x>
<y>60</y>
<width>161</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>160</width>
<height>41</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Host IP:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineIp"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogHostIp</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogHostIp</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,204 @@
#include "dialoglinearity.h"
#include "ui_dialoglinearity.h"
#define RUNNING 1
#define STOPPED 0
#define STOP_ISSUED -1
DialogLinearity::DialogLinearity(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogLinearity)
{
ui->setupUi(this);
runState = STOPPED;
}
DialogLinearity::~DialogLinearity()
{
delete ui;
}
//************** Processing ***************
void DialogLinearity::run()
{
runState = RUNNING;
qInfo("Starting linearity test...");
//Prepare measurement
ui->plotResultsMean->clearGraphs();
ui->plotResultsStd->clearGraphs();
results.clear();
int nr_devices = theHW->devices.length();
int decimation = ui->spinPLotDecimation->value();
int tdelay = ui->spinDelay->value();
int nacqs = ui->spinAcquisitions->value();
double vstart = ui->doubleSpinVstart->value();
double vend = ui->doubleSpinVend->value();
double vinc = ui->doubleSpinVinc->value();
double vcurrent = vstart;
//Plot data
QVector<double> xdata;
QList<QVector<double>> ymeandata;
QList<QVector<double>> ystddata;
for (int ch = 0; ch < (nr_devices*128); ch+= decimation)
{
ymeandata.append(xdata); //just add empty vectors to the list
ystddata.append(xdata); //just add empty vectors to the list
}
//The number of plotted lines is smaller than number of channels - see decimation
for (int plotnr = 0; plotnr < nr_devices*128; plotnr++)
{
ui->plotResultsMean->addGraph();
ui->plotResultsStd->addGraph();
}
double xmin = 1e+10;
double xmax = -1e+10;
double ymeanmin = 1e+10;
double ymeanmax = -1e+10;
double ystdmin = 1e+10;
double ystdmax = -1e+10;
theKeithley->setVoltage(vcurrent);
theKeithley->on(1);
//Measure!
while ((runState != STOP_ISSUED) && (vcurrent <= vend))
{
//Set LED voltage
qInfo(qPrintable(QString("LED voltage: %1 V").arg(vcurrent)));
theKeithley->setVoltage(vcurrent);
//Wait
msleep2(tdelay);
TestResult result;
//Collect sensor data
histoReady = 0;
connect(&(theHW->eventBuilder), EventBuilder::sigHistoCompleted, this, DialogLinearity::onHistogramCompleted);
theHW->eventBuilder.startTakingHistos(nacqs);
while (!histoReady)
{
QCoreApplication::processEvents();
QThread::msleep(10);
}
disconnect(&(theHW->eventBuilder), EventBuilder::sigHistoCompleted, this, DialogLinearity::onHistogramCompleted);
QVector<Histogram> histos = theHW->eventBuilder.getHistos();
result.mean.fill(0, nr_devices*128);
result.std.fill(0, nr_devices*128);
for (int i = 0; i < result.mean.length(); i++)
{
histos[i].MS(&(result.mean[i]), &(result.std[i]));
//result.mean[i] = histos[i].mean();
//result.std[i] = histos[i].stdev();
}
//Add LED/PD information
result.vled = vcurrent;
result.ipd = theKeithley->getCurrent();
results.append(result);
//Plot data...
xdata.append(result.ipd);
if (result.ipd > xmax)
xmax = result.ipd;
if (result.ipd < xmin)
xmin = result.ipd;
for (int ch = 0, i = 0; ch < (nr_devices*128); ch+= decimation, i++)
{
ymeandata[i].append(result.mean[ch]);
if (result.mean[ch] > ymeanmax)
ymeanmax = result.mean[ch];
if (result.mean[ch] < ymeanmin)
ymeanmin = result.mean[ch];
ystddata[i].append(result.std[ch]);
if (result.std[ch] > ystdmax)
ystdmax = result.std[ch];
if (result.std[ch] < ystdmin)
ystdmin = result.std[ch];
}
ui->plotResultsMean->xAxis->setRange(xmin, xmax);
ui->plotResultsMean->yAxis->setRange(ymeanmin, ymeanmax);
ui->plotResultsStd->xAxis->setRange(xmin, xmax);
ui->plotResultsStd->yAxis->setRange(ystdmin, ystdmax);
for (int ch = 0, i = 0; ch < (nr_devices*128); ch+= decimation, i++)
{
ui->plotResultsMean->graph(i)->setData(xdata, ymeandata[i]);
ui->plotResultsStd->graph(i)->setData(xdata, ystddata[i]);
}
ui->plotResultsMean->replot();
ui->plotResultsStd->replot();
//Roll over
vcurrent += vinc;
QCoreApplication::processEvents();
}
theKeithley->on(0);
qInfo("Linearity test finished!");
runState = STOPPED;
}
//************** Slots ****************
void DialogLinearity::onHistogramCompleted()
{
histoReady = 1;
}
void DialogLinearity::on_pushRun_pressed()
{
if (runState)
{
runState = STOP_ISSUED;
}
else
{
ui->pushRun->setText("Stop");
ui->pushSave->setEnabled(false);
run();
ui->pushRun->setText("Run");
ui->pushSave->setEnabled(true);
}
}
void DialogLinearity::on_pushSave_pressed()
{
QString filename = QFileDialog::getSaveFileName(this, "Select file for saving data", "", tr("Comma separated files (*.csv)"));
QString delimiter = QString(",");
if (filename.length() == 0)
return;
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << qSetFieldWidth(14) << qSetRealNumberPrecision(8);
for (int row = 0; row < results.length(); row++)
{
out << results[row].vled << delimiter << results[row].ipd;
for (int col = 0; (col < results[row].mean.length()) && (col < results[row].std.length()); col++)
out << delimiter << results[row].mean[col] << delimiter << results[row].std[col];
out << QString("\n");
}
file.close();
}

View File

@ -0,0 +1,52 @@
#ifndef DIALOGLINEARITY_H
#define DIALOGLINEARITY_H
#include <QDialog>
#include <QVector>
#include <QList>
#include "hw.h"
#include "keithley_thr.h"
#include "histogram.h"
#include "helpers.h"
typedef struct
{
double vled;
double ipd;
QVector<double> mean;
QVector<double> std;
} TestResult;
namespace Ui {
class DialogLinearity;
}
class DialogLinearity : public QDialog
{
Q_OBJECT
public:
explicit DialogLinearity(QWidget *parent = 0);
~DialogLinearity();
HW* theHW;
keithley_thr* theKeithley;
public slots:
void onHistogramCompleted();
protected:
int runState;
int histoReady;
QList<TestResult> results;
void run();
private slots:
void on_pushRun_pressed();
void on_pushSave_pressed();
private:
Ui::DialogLinearity *ui;
};
#endif // DIALOGLINEARITY_H

View File

@ -0,0 +1,386 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogLinearity</class>
<widget class="QDialog" name="DialogLinearity">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>844</width>
<height>632</height>
</rect>
</property>
<property name="windowTitle">
<string>Linearity Test</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>490</x>
<y>590</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>821</width>
<height>571</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Scan settings</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>V</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Measurement delay:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinDelay">
<property name="minimum">
<number>100</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>1500</number>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="label_9">
<property name="text">
<string>ms</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label_7">
<property name="text">
<string>V</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>V</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Acqs/point:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="spinAcquisitions">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000000</number>
</property>
<property name="singleStep">
<number>1000</number>
</property>
<property name="value">
<number>10000</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>End LED voltage:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinVend">
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>6.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinVstart">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>2.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Start LED voltage:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Voltage increment:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinVinc">
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Plot decimation:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="spinPLotDecimation">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>128</number>
</property>
<property name="value">
<number>16</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushRun">
<property name="text">
<string>Run!</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushSave">
<property name="text">
<string>Save results...</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_12">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Signal mean</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="plotResultsMean" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Signal standard deviation</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="plotResultsStd" native="true"/>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogLinearity</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogLinearity</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,56 @@
#include "dialoglogsettings.h"
#include "ui_dialoglogsettings.h"
#include "Q_DebugStream.h"
#include <QShowEvent>
DialogLogSettings::DialogLogSettings(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogLogSettings)
{
ui->setupUi(this);
}
DialogLogSettings::~DialogLogSettings()
{
delete ui;
}
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
void DialogLogSettings::showEvent(QShowEvent * event)
{
if (!event->spontaneous())
{
ui->checkDisplayDebug->setChecked((bool)(displayMask & DS_DEBUG));
ui->checkDisplayInfo->setChecked((bool)(displayMask & DS_INFO));
ui->checkDisplayWarning->setChecked((bool)(displayMask & DS_WARNING));
ui->checkDisplayCritical->setChecked((bool)(displayMask & DS_CRITICAL));
ui->checkDisplayFatal->setChecked((bool)(displayMask & DS_FATAL));
ui->checkDetailsDebug->setChecked((bool)(detailsMask & DS_DEBUG));
ui->checkDetailsInfo->setChecked((bool)(detailsMask & DS_INFO));
ui->checkDetailsWarning->setChecked((bool)(detailsMask & DS_WARNING));
ui->checkDetailsCritical->setChecked((bool)(detailsMask & DS_CRITICAL));
ui->checkDetailsFatal->setChecked((bool)(detailsMask & DS_FATAL));
}
QDialog::showEvent(event);
}
void DialogLogSettings::on_buttonGroup_buttonReleased(int arg1)
{
displayMask = 0;
if (ui->checkDisplayDebug->isChecked()) displayMask |= DS_DEBUG;
if (ui->checkDisplayInfo->isChecked()) displayMask |= DS_INFO;
if (ui->checkDisplayWarning->isChecked()) displayMask |= DS_WARNING;
if (ui->checkDisplayCritical->isChecked()) displayMask |= DS_CRITICAL;
if (ui->checkDisplayFatal->isChecked()) displayMask |= DS_FATAL;
detailsMask = 0;
if (ui->checkDetailsDebug->isChecked()) detailsMask |= DS_DEBUG;
if (ui->checkDetailsInfo->isChecked()) detailsMask |= DS_INFO;
if (ui->checkDetailsWarning->isChecked()) detailsMask |= DS_WARNING;
if (ui->checkDetailsCritical->isChecked()) detailsMask |= DS_CRITICAL;
if (ui->checkDetailsFatal->isChecked()) detailsMask |= DS_FATAL;
}

View File

@ -0,0 +1,28 @@
#ifndef DIALOGLOGSETTINGS_H
#define DIALOGLOGSETTINGS_H
#include <QDialog>
namespace Ui {
class DialogLogSettings;
}
class DialogLogSettings : public QDialog
{
Q_OBJECT
public:
explicit DialogLogSettings(QWidget *parent = 0);
~DialogLogSettings();
int displayMask;
int detailsMask;
private slots:
void on_buttonGroup_buttonReleased(int arg1);
void showEvent(QShowEvent *event);
private:
Ui::DialogLogSettings *ui;
};
#endif // DIALOGLOGSETTINGS_H

View File

@ -0,0 +1,321 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogLogSettings</class>
<widget class="QDialog" name="DialogLogSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>284</width>
<height>239</height>
</rect>
</property>
<property name="windowTitle">
<string>Log window settings</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>80</x>
<y>190</y>
<width>181</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QWidget" name="gridLayoutWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>20</y>
<width>241</width>
<height>161</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Details</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Debug</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Warning</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Message type</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Critical</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Info</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Display</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Fatal</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkDisplayDebug">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="checkDetailsDebug">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="checkDisplayInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="2" column="2">
<widget class="QCheckBox" name="checkDetailsInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="checkDisplayWarning">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="3" column="2">
<widget class="QCheckBox" name="checkDetailsWarning">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="checkDisplayCritical">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="4" column="2">
<widget class="QCheckBox" name="checkDetailsCritical">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="checkDisplayFatal">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="5" column="2">
<widget class="QCheckBox" name="checkDetailsFatal">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogLogSettings</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogLogSettings</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
<buttongroups>
<buttongroup name="buttonGroup">
<property name="exclusive">
<bool>false</bool>
</property>
</buttongroup>
</buttongroups>
</ui>

View File

@ -0,0 +1,199 @@
#include "dialogprofiler.h"
#include "ui_dialogprofiler.h"
#define RUNNING 1
#define STOPPED 0
#define STOP_ISSUED -1
DialogProfiler::DialogProfiler(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogProfiler)
{
ui->setupUi(this);
runState = STOPPED;
nrRunsDone = 0;
}
DialogProfiler::~DialogProfiler()
{
delete ui;
}
//************** Processing ***************
void DialogProfiler::run(int nr_loops)
{
runState = RUNNING;
qInfo("Starting profile acquisition");
//Prepare measurement
ui->plotResultsMean->clearGraphs();
ui->plotResultsStd->clearGraphs();
int nr_devices = theHW->devices.length();
int nacqs = ui->spinAcquisitions->value();
//Data structures for plot
QVector<double> xdata;
QVector<double> ymeandata;
QVector<double> ystddata;
ui->plotResultsMean->addGraph();
ui->plotResultsStd->addGraph();
for (int ch = 0; ch < nr_devices*128; ch++)
xdata.append(ch);
double ymeanmin = 1e+10;
double ymeanmax = -1e+10;
double ystdmin = 1e+10;
double ystdmax = -1e+10;
//Measure!
int loop_nr = 0;
while ((runState != STOP_ISSUED) && ((loop_nr < nr_loops) || (nr_loops == -1)))
{
ProfilerTestResult result;
//Collect sensor data
histoReady = 0;
connect(&(theHW->eventBuilder), EventBuilder::sigHistoCompleted, this, DialogProfiler::onHistogramCompleted);
theHW->eventBuilder.startTakingHistos(nacqs);
while (!histoReady)
{
QCoreApplication::processEvents();
QThread::msleep(10);
}
disconnect(&(theHW->eventBuilder), EventBuilder::sigHistoCompleted, this, DialogProfiler::onHistogramCompleted);
QVector<Histogram> histos = theHW->eventBuilder.getHistos();
result.mean.fill(0, nr_devices*128);
result.std.fill(0, nr_devices*128);
for (int i = 0; i < result.mean.length(); i++)
{
histos[i].MS(&(result.mean[i]), &(result.std[i]));
}
//Add LED/PD information
result.nracqs = nacqs;
results.append(result);
//Plot data...
ymeandata.clear();
ymeandata.fill(0, nr_devices*128);
ystddata.clear();
ystddata.fill(0,nr_devices*128);
for (int ch = 0; ch < (nr_devices*128); ch++)
{
ymeandata[ch] = result.mean[ch];
if (result.mean[ch] > ymeanmax)
ymeanmax = result.mean[ch];
if (result.mean[ch] < ymeanmin)
ymeanmin = result.mean[ch];
ystddata[ch] = result.std[ch];
if (result.std[ch] > ystdmax)
ystdmax = result.std[ch];
if (result.std[ch] < ystdmin)
ystdmin = result.std[ch];
}
ui->plotResultsMean->xAxis->setRange(0, nr_devices*128-1);
ui->plotResultsMean->yAxis->setRange(ymeanmin, ymeanmax);
ui->plotResultsStd->xAxis->setRange(0, nr_devices*128-1);
ui->plotResultsStd->yAxis->setRange(ystdmin, ystdmax);
ui->plotResultsMean->graph(0)->setData(xdata, ymeandata);
ui->plotResultsStd->graph(0)->setData(xdata, ystddata);
ui->plotResultsMean->replot();
ui->plotResultsStd->replot();
//Roll over
loop_nr++;
nrRunsDone++;
ui->lineRunsDone->setText(QString("%1").arg(nrRunsDone));
QCoreApplication::processEvents();
}
qInfo("Profile acquisition finished!");
runState = STOPPED;
}
void DialogProfiler::runHelper(int nr_loops)
{
if (runState)
{
runState = STOP_ISSUED;
}
else
{
ui->pushRun->setText("Stop");
ui->pushRunOnce->setEnabled(false);
ui->pushRunInfinite->setEnabled(false);
ui->pushClear->setEnabled(false);
ui->pushSave->setEnabled(false);
run(nr_loops);
ui->pushRun->setText("Run");
ui->pushRunOnce->setEnabled(true);
ui->pushRunInfinite->setEnabled(true);
ui->pushClear->setEnabled(true);
ui->pushSave->setEnabled(true);
}
}
//************** Slots ****************
void DialogProfiler::onHistogramCompleted()
{
histoReady = 1;
}
void DialogProfiler::on_pushRun_pressed()
{
runHelper(ui->spinRuns->value());
}
void DialogProfiler::on_pushRunOnce_pressed()
{
runHelper(1);
}
void DialogProfiler::on_pushRunInfinite_pressed()
{
runHelper(-1);
}
void DialogProfiler::on_pushSave_pressed()
{
QString filename = QFileDialog::getSaveFileName(this, "Select file for saving data", "", tr("Comma separated files (*.csv)"));
QString delimiter = QString(",");
if (filename.length() == 0)
return;
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << qSetFieldWidth(14) << qSetRealNumberPrecision(8);
for (int row = 0; row < results.length(); row++)
{
out << results[row].nracqs;
for (int col = 0; (col < results[row].mean.length()) && (col < results[row].std.length()); col++)
out << delimiter << results[row].mean[col] << delimiter << results[row].std[col];
out << QString("\n");
}
file.close();
}
void DialogProfiler::on_pushClear_pressed()
{
nrRunsDone = 0;
results.clear();
ui->lineRunsDone->setText(QString("%1").arg(nrRunsDone));
}

View File

@ -0,0 +1,59 @@
#ifndef DIALOGPROFILER_H
#define DIALOGPROFILER_H
#include <QDialog>
#include <QVector>
#include <QList>
#include "hw.h"
#include "keithley_thr.h"
#include "histogram.h"
#include "helpers.h"
typedef struct
{
int nracqs;
QVector<double> mean;
QVector<double> std;
} ProfilerTestResult;
namespace Ui {
class DialogProfiler;
}
class DialogProfiler : public QDialog
{
Q_OBJECT
public:
explicit DialogProfiler(QWidget *parent = 0);
~DialogProfiler();
HW* theHW;
keithley_thr* theKeithley;
public slots:
void onHistogramCompleted();
protected:
int runState;
int histoReady;
int nrRunsDone;
QList<ProfilerTestResult> results;
void run(int nr_loops);
void runHelper(int nr_loops);
private slots:
void on_pushRun_pressed();
void on_pushSave_pressed();
void on_pushRunOnce_pressed();
void on_pushRunInfinite_pressed();
void on_pushClear_pressed();
private:
Ui::DialogProfiler *ui;
};
#endif // DIALOGLINEARITY_H

314
hit2023v2/dialogprofiler.ui Normal file
View File

@ -0,0 +1,314 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogProfiler</class>
<widget class="QDialog" name="DialogProfiler">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>844</width>
<height>632</height>
</rect>
</property>
<property name="windowTitle">
<string>Profile Viewer</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>490</x>
<y>590</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>821</width>
<height>571</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Scan settings</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Acqs/run:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinAcquisitions">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000000</number>
</property>
<property name="singleStep">
<number>1000</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Nr runs:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinRuns">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>128</number>
</property>
<property name="value">
<number>16</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushRun">
<property name="text">
<string>Run!</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushRunOnce">
<property name="text">
<string>Run once!</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushRunInfinite">
<property name="text">
<string>Run infinite!</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Runs:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineRunsDone">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="pushClear">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushSave">
<property name="text">
<string>Save results...</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_12">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Signal mean</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="plotResultsMean" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Signal standard deviation</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="plotResultsStd" native="true"/>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogProfiler</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogProfiler</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

230
hit2023v2/dialogtiscan.cpp Normal file
View File

@ -0,0 +1,230 @@
#include "dialogtiscan.h"
#include "ui_dialogtiscan.h"
#define RUNNING 1
#define STOPPED 0
#define STOP_ISSUED -1
DialogTiScan::DialogTiScan(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogTiScan)
{
ui->setupUi(this);
runState = STOPPED;
}
DialogTiScan::~DialogTiScan()
{
delete ui;
}
void DialogTiScan::showEvent(QShowEvent * event)
{
if (!event->spontaneous())
{
if (!theKeithley->isOpen)
ui->checkUseLED->setEnabled(false);
}
QDialog::showEvent(event);
}
//************** Processing ***************
void DialogTiScan::run()
{
runState = RUNNING;
qInfo("Starting integration time scan...");
//Prepare measurement
ui->plotResultsMean->clearGraphs();
ui->plotResultsStd->clearGraphs();
results.clear();
int nr_devices = theHW->devices.length();
int use_led = ui->checkUseLED->isChecked();
double ledv = ui->doubleSpinLEDV->value();
int decimation = ui->spinPLotDecimation->value();
int nacqs = ui->spinAcquisitions->value();
int tstart = ui->spintStart->value();
int tend = ui->spinTEnd->value();
int tinc = ui->spinTIncrement->value();
int tcurrent = tstart;
//Plot data
QVector<double> xdata;
QList<QVector<double>> ymeandata;
QList<QVector<double>> ystddata;
for (int ch = 0; ch < (nr_devices*128); ch+= decimation)
{
ymeandata.append(xdata); //just add empty vectors to the list
ystddata.append(xdata); //just add empty vectors to the list
}
//The number of plotted lines is smaller than number of channels - see decimation
for (int plotnr = 0; plotnr < nr_devices*128; plotnr++)
{
ui->plotResultsMean->addGraph();
ui->plotResultsStd->addGraph();
}
double xmin = 1e+10;
double xmax = -1e+10;
double ymeanmin = 1e+10;
double ymeanmax = -1e+10;
double ystdmin = 1e+10;
double ystdmax = -1e+10;
if (use_led)
{
theKeithley->setVoltage(ledv);
theKeithley->on(1);
}
theHW->run();
//Measure!
while ((runState != STOP_ISSUED) && (tcurrent <= tend))
{
//Set LED voltage
qInfo(qPrintable(QString("Integration time: %1 ").arg(tcurrent)));
//set up integration time for all devices
theHW->stop();
for (int dev_nr = 0; dev_nr < theHW->devices.length(); dev_nr++)
{
DeviceConfig dc = theHW->devices[dev_nr]->deviceConfig;
dc.tint = tcurrent;
theHW->devices[dev_nr]->configure(dc);
}
theHW->run();
TiScanResult result;
//Collect sensor data
histoReady = 0;
connect(&(theHW->eventBuilder), EventBuilder::sigHistoCompleted, this, DialogTiScan::onHistogramCompleted);
theHW->eventBuilder.startTakingHistos(nacqs);
while (!histoReady)
{
QCoreApplication::processEvents();
QThread::msleep(10);
}
disconnect(&(theHW->eventBuilder), EventBuilder::sigHistoCompleted, this, DialogTiScan::onHistogramCompleted);
QVector<Histogram> histos = theHW->eventBuilder.getHistos();
result.mean.fill(0, nr_devices*128);
result.std.fill(0, nr_devices*128);
for (int i = 0; i < result.mean.length(); i++)
{
histos[i].MS(&(result.mean[i]), &(result.std[i]));
//result.mean[i] = histos[i].mean();
//result.std[i] = histos[i].stdev();
}
//Add information on integration time
result.tint = tcurrent;
results.append(result);
//Plot data...
xdata.append(result.tint);
if (result.tint > xmax)
xmax = result.tint;
if (result.tint < xmin)
xmin = result.tint;
for (int ch = 0, i = 0; ch < (nr_devices*128); ch+= decimation, i++)
{
ymeandata[i].append(result.mean[ch]);
if (result.mean[ch] > ymeanmax)
ymeanmax = result.mean[ch];
if (result.mean[ch] < ymeanmin)
ymeanmin = result.mean[ch];
ystddata[i].append(result.std[ch]);
if (result.std[ch] > ystdmax)
ystdmax = result.std[ch];
if (result.std[ch] < ystdmin)
ystdmin = result.std[ch];
}
ui->plotResultsMean->xAxis->setRange(xmin, xmax);
ui->plotResultsMean->yAxis->setRange(ymeanmin, ymeanmax);
ui->plotResultsStd->xAxis->setRange(xmin, xmax);
ui->plotResultsStd->yAxis->setRange(ystdmin, ystdmax);
for (int ch = 0, i = 0; ch < (nr_devices*128); ch+= decimation, i++)
{
ui->plotResultsMean->graph(i)->setData(xdata, ymeandata[i]);
ui->plotResultsStd->graph(i)->setData(xdata, ystddata[i]);
}
ui->plotResultsMean->replot();
ui->plotResultsStd->replot();
//Roll over
tcurrent += tinc;
QCoreApplication::processEvents();
}
if (use_led)
theKeithley->on(0);
theHW->stop();
qInfo("Integration time scan finished!");
runState = STOPPED;
}
//************** Slots ****************
void DialogTiScan::onHistogramCompleted()
{
histoReady = 1;
}
void DialogTiScan::on_pushRun_pressed()
{
if (runState)
{
runState = STOP_ISSUED;
}
else
{
ui->pushRun->setText("Stop");
ui->pushSave->setEnabled(false);
run();
ui->pushRun->setText("Run");
ui->pushSave->setEnabled(true);
}
}
void DialogTiScan::on_pushSave_pressed()
{
QString filename = QFileDialog::getSaveFileName(this, "Select file for saving data", "", tr("Comma separated files (*.csv)"));
QString delimiter = QString(",");
if (filename.length() == 0)
return;
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << qSetFieldWidth(14) << qSetRealNumberPrecision(8);
for (int row = 0; row < results.length(); row++)
{
out << results[row].tint;
for (int col = 0; (col < results[row].mean.length()) && (col < results[row].std.length()); col++)
out << delimiter << results[row].mean[col] << delimiter << results[row].std[col];
out << QString("\n");
}
file.close();
}

52
hit2023v2/dialogtiscan.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef DIALOGTISCAN_H
#define DIALOGTISCAN_H
#include <QDialog>
#include <QVector>
#include <QList>
#include "hw.h"
#include "keithley_thr.h"
#include "histogram.h"
#include "helpers.h"
typedef struct
{
int tint;
QVector<double> mean;
QVector<double> std;
} TiScanResult;
namespace Ui {
class DialogTiScan;
}
class DialogTiScan : public QDialog
{
Q_OBJECT
public:
explicit DialogTiScan(QWidget *parent = 0);
~DialogTiScan();
HW* theHW;
keithley_thr* theKeithley;
public slots:
void onHistogramCompleted();
void showEvent(QShowEvent *event);
protected:
int runState;
int histoReady;
QList<TiScanResult> results;
void run();
private slots:
void on_pushRun_pressed();
void on_pushSave_pressed();
private:
Ui::DialogTiScan *ui;
};
#endif // DIALOGTISCAN_H

383
hit2023v2/dialogtiscan.ui Normal file
View File

@ -0,0 +1,383 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogTiScan</class>
<widget class="QDialog" name="DialogTiScan">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>844</width>
<height>632</height>
</rect>
</property>
<property name="windowTitle">
<string>Integration Time Scan</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>490</x>
<y>590</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>821</width>
<height>571</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Scan settings</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Time increment:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Use LED:</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Plot decimation:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QSpinBox" name="spinPLotDecimation">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>128</number>
</property>
<property name="value">
<number>16</number>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>LED voltage:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>V</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QSpinBox" name="spinAcquisitions">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000000</number>
</property>
<property name="singleStep">
<number>1000</number>
</property>
<property name="value">
<number>10000</number>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Acqs/point:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinLEDV">
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>6.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Start integration time:</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>End integration time:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinTEnd">
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="value">
<number>8549</number>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="spinTIncrement">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkUseLED">
<property name="text">
<string>CheckBox</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spintStart">
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushRun">
<property name="text">
<string>Run!</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushSave">
<property name="text">
<string>Save results...</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Signal mean</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="plotResultsMean" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Signal standard deviation</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="plotResultsStd" native="true"/>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogTiScan</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogTiScan</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,156 @@
#include "dialogtriggersettings.h"
#include "ui_dialogtriggersettings.h"
#include "helpers.h"
DialogTriggerSettings::DialogTriggerSettings(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogTriggerSettings)
{
ui->setupUi(this);
}
DialogTriggerSettings::~DialogTriggerSettings()
{
delete ui;
}
//***************** Initialization ******************
void DialogTriggerSettings::showEvent(QShowEvent * event)
{
if (!event->spontaneous())
{
if (deviceSettings != NULL)
{
top(deviceSettings);
deviceSettings->beginGroup("Trigger");
ui->spinPeriodTicks->setValue( deviceSettings->value("Period", (int)9000).toInt() );
ui->spinTintTicks->setValue( deviceSettings->value("Tint", (int)1000).toInt() );
if (deviceSettings->value("Gain", (int)0).toInt() == 0)
ui->radioLow->setChecked(true);
else
ui->radioHigh->setChecked(true);
ui->spinPeriodTicks_v2->setValue( deviceSettings->value("Period_v2", (int)2500).toInt() );
ui->spinTintTicks_v2->setValue( deviceSettings->value("Tint_v2", (int)1000).toInt() );
if (deviceSettings->value("Gain_v2", (int)0).toInt() == 0)
ui->radioLow_v2->setChecked(true);
else
ui->radioHigh_v2->setChecked(true);
}
updateCalculations();
}
QDialog::showEvent(event);
}
//***************** Processing ******************
void DialogTriggerSettings::accept()
{
// qInfo("Accepted!");
if (validateAndSave())
QDialog::accept();
}
int DialogTriggerSettings::validateAndSave()
{
if (deviceSettings == NULL)
return 0;
if (!data_ok)
return 0;
top(deviceSettings);
deviceSettings->beginGroup("Trigger");
deviceSettings->setValue("Period", ui->spinPeriodTicks->value());
deviceSettings->setValue("Tint", ui->spinTintTicks->value());
if (ui->radioHigh->isChecked())
deviceSettings->setValue("Gain", 1);
else
deviceSettings->setValue("Gain", 0);
deviceSettings->setValue("Period_v2", ui->spinPeriodTicks_v2->value());
deviceSettings->setValue("Tint_v2", ui->spinTintTicks_v2->value());
if (ui->radioHigh_v2->isChecked())
deviceSettings->setValue("Gain_v2", 1);
else
deviceSettings->setValue("Gain_v2", 0);
return 1;
}
void DialogTriggerSettings::updateCalculations()
{
data_ok = 1;
// ***** V1 *****
double period_us = (double)(ui->spinPeriodTicks->value()+1) / 90.0;
ui->linePeriodUs->setText(QString("%1").arg(period_us, 0, 'f', 2));
double freq_kHz = 1e+3/period_us;
ui->lineFreqKhz->setText((QString("%1").arg(freq_kHz, 0, 'f', 3)));
ui->linePeriodOK->setText("OK");
double tint_us = (double)(ui->spinTintTicks->value()+1) / 90.0; //45.0;
ui->lineTintUs->setText(QString("%1").arg(tint_us, 0, 'f', 2));
if (tint_us > (period_us - (20.0/4)))
{
ui->lineTintOK->setText("Too long!");
data_ok = 0;
}
else
ui->lineTintOK->setText("OK");
// ***** V2 *****
double period_us_v2 = (double)(ui->spinPeriodTicks_v2->value()+1) / 25.0;
ui->linePeriodUs_v2->setText(QString("%1").arg(period_us_v2, 0, 'f', 2));
double freq_kHz_v2 = 1e+3/period_us_v2;
ui->lineFreqKhz_v2->setText((QString("%1").arg(freq_kHz_v2, 0, 'f', 3)));
ui->linePeriodOK_v2->setText("OK");
double tint_us_v2 = (double)(ui->spinTintTicks_v2->value()+1) / (50.0/14.0); //makes these 3.5714... MHz
ui->lineTintUs_v2->setText(QString("%1").arg(tint_us_v2, 0, 'f', 2));
if (tint_us_v2 > (period_us_v2 - (20.0/(50.0/14.0))))
{
ui->lineTintOK_v2->setText("Too long!");
data_ok = 0;
}
else
ui->lineTintOK_v2->setText("OK");
}
void DialogTriggerSettings::on_spinPeriodTicks_valueChanged(int arg1)
{
updateCalculations();
}
void DialogTriggerSettings::on_spinTintTicks_valueChanged(int arg1)
{
updateCalculations();
}
void DialogTriggerSettings::on_spinPeriodTicks_v2_valueChanged(int arg1)
{
updateCalculations();
}
void DialogTriggerSettings::on_spinTintTicks_v2_valueChanged(int arg1)
{
updateCalculations();
}

View File

@ -0,0 +1,41 @@
#ifndef DIALOGTRIGGERSETTINGS_H
#define DIALOGTRIGGERSETTINGS_H
#include <QDialog>
#include <QSettings>
#include <QShowEvent>
namespace Ui {
class DialogTriggerSettings;
}
class DialogTriggerSettings : public QDialog
{
Q_OBJECT
public:
explicit DialogTriggerSettings(QWidget *parent = 0);
~DialogTriggerSettings();
QSettings* deviceSettings = NULL;
public slots:
void showEvent(QShowEvent *event);
void accept();
protected:
int validateAndSave();
void updateCalculations();
int data_ok = 0;
private slots:
void on_spinPeriodTicks_valueChanged(int arg1);
void on_spinTintTicks_valueChanged(int arg1);
void on_spinPeriodTicks_v2_valueChanged(int arg1);
void on_spinTintTicks_v2_valueChanged(int arg1);
private:
Ui::DialogTriggerSettings *ui;
};
#endif // DIALOGTRIGGERSETTINGS_H

View File

@ -0,0 +1,412 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogTriggerSettings</class>
<widget class="QDialog" name="DialogTriggerSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>443</width>
<height>281</height>
</rect>
</property>
<property name="windowTitle">
<string>Trigger configuration</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>90</x>
<y>240</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>421</width>
<height>221</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Hardware v.1</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>=</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Period:</string>
</property>
</widget>
</item>
<item row="1" column="7">
<widget class="QLineEdit" name="lineTintOK">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="QLineEdit" name="linePeriodOK">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLineEdit" name="lineFreqKhz">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QLabel" name="label_4">
<property name="text">
<string>kHz</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="linePeriodUs">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Tint:</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLineEdit" name="lineTintUs">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_7">
<property name="text">
<string>us</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="label_3">
<property name="text">
<string>us =&gt;</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>=</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinPeriodTicks">
<property name="minimum">
<number>8000</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Gain:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinTintTicks">
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QRadioButton" name="radioLow">
<property name="text">
<string>Lo</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup_2</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioHigh">
<property name="text">
<string>Hi</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup_2</string>
</attribute>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Harware v.2</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="2">
<widget class="QLabel" name="label_12">
<property name="text">
<string>=</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Period:</string>
</property>
</widget>
</item>
<item row="1" column="7">
<widget class="QLineEdit" name="lineTintOK_v2">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="QLineEdit" name="linePeriodOK_v2">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLineEdit" name="lineFreqKhz_v2">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QLabel" name="label_14">
<property name="text">
<string>kHz</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="linePeriodUs_v2">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Tint:</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLineEdit" name="lineTintUs_v2">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_16">
<property name="text">
<string>us</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="label_17">
<property name="text">
<string>us =&gt;</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_18">
<property name="text">
<string>=</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinPeriodTicks_v2">
<property name="minimum">
<number>2000</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Gain:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinTintTicks_v2">
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="radioLow_v2">
<property name="text">
<string>Lo</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioHigh_v2">
<property name="text">
<string>Hi</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogTriggerSettings</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogTriggerSettings</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
<buttongroups>
<buttongroup name="buttonGroup_2"/>
<buttongroup name="buttonGroup"/>
</buttongroups>
</ui>

162
hit2023v2/display.cpp Normal file
View File

@ -0,0 +1,162 @@
#include "display.h"
#include "ui_display.h"
#include <QMessageBox>
#include <QFileDialog>
#include <QCheckBox>
Display::Display(QWidget *parent) :
QDialog(parent),
ui(new Ui::display)
{
ui->setupUi(this);
// Copy/Create and initialize radio buttons
radioButtonFixedScale = ui->radioButtonFixedScale;//new QRadioButton("Fixed Scale", this);
radioButtonAutoscale = ui->radioButtonAutoscale;//new QRadioButton("Autoscale", this);
// Copy/Create and initialize the button group
buttonGroup = ui->buttonGroup;//new QButtonGroup(this);
buttonGroup->setExclusive(true); // Ensure exclusivity
// Add radio buttons to the button group
buttonGroup->addButton(ui->radioButtonFixedScale);
buttonGroup->addButton(ui->radioButtonAutoscale);
buttonGroup->addButton(ui->radioButtonMaxScale);
// Connect the buttonClicked signal of the button group
connect(buttonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(onButtonClicked(QAbstractButton*)));
connect(ui->pushButton_savebkg, &QPushButton::clicked, this, &Display::onSaveBackgroundClicked);
}
Display::~Display()
{
delete ui;
}
void Display::showEvent(QShowEvent * event)
{
if (!event->spontaneous())
{
ui->plot->addGraph();
}
QDialog::showEvent(event);
}
//***********************************************
void Display::plot(const QVector<unsigned short> &data)
{
//resize data vectors and fill X values - only if needed
if (data.length() != nrPoints)
{
nrPoints = data.length();
dataX.clear();
dataY.clear();
dataX.resize(nrPoints);
dataY.resize(nrPoints);
ui->plot->xAxis->setRange(0,nrPoints-1);
//ui->plot->yAxis->setRange(-1000,66000);
for (int i = 0; i < nrPoints; i++)
dataX[i] = i;
}
//fill Y values
double min = 65535;
double max = 0;
for (int i = 0; i < nrPoints; i++)
{
dataY[i] = /*65535 -*/ data[i];
if (dataY[i] < min)
min = dataY[i];
if (dataY[i] > max)
max = dataY[i];
}
if (ui->radioButtonAutoscale->isChecked())
ui->plot->yAxis->setRange(min-0.05*(max-min),max+0.05*(max-min));
else if (ui->radioButtonFixedScale ->isChecked())
ui->plot->yAxis->setRange(ui->spinBox_fixedmin->value(), ui->spinBox_fixedmax->value());
else
ui->plot->yAxis->setRange(-1000,66000);
//feed plotter
ui->plot->graph(0)->setData(dataX, dataY);
//plot
ui->plot->replot();
}
void Display::plot()
{
plot(buffer);
}
void Display::setTitle(QString title)
{
ui->lineTitle->setText(title);
}
// Slot to handle button clicks
void Display::onButtonClicked(QAbstractButton *button)
{
// Handle button clicks here
if (button == radioButtonFixedScale)
{
// Fixed Scale radio button clicked
// Handle the Fixed Scale selection
// Perform actions when Fixed Scale is selected
radioButtonFixedScale->setChecked(true); // Enable relevant controls
radioButtonAutoscale->setChecked(false); // Disable other controls
}//
else if (button == radioButtonAutoscale)
{
// Autoscale radio button clicked
// Handle the Autoscale selection
// Perform actions when Autoscale is selected
ui->radioButtonFixedScale->setChecked(false); // Disable relevant controls
ui->radioButtonAutoscale->setChecked(true); // setEnabled(true); // Enable other controls
}
}
void Display::onSaveBackgroundClicked()
{
// Check if there is data to save
if (buffer.isEmpty()) {
// No data to save
return;
}
// Get the plane's name (you might need to adjust how you retrieve it)
QString planeName = ui->lineTitle->text();
// Remove invalid characters from the plane name (e.g., spaces)
planeName.remove(QChar(' '));
// Generate the filename with the plane name appended
QString filename = QString("bkg/background_%1.txt").arg(planeName);
// Open the file for writing
QFile file(filename);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&file);
// Write the data to the file
for (int i = 0; i < buffer.size(); ++i) {
stream << QString::number(buffer[i]) << "\n";
}
// Close the file
file.close();
// Notify the user that the data has been saved
qDebug() << "Data saved to" << filename;
} else {
// Failed to open the file
qDebug() << "Error: Failed to open" << filename << "for writing";
}
}

47
hit2023v2/display.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef DISPLAY_H
#define DISPLAY_H
#include <QDialog>
#include <QVector>
#include <QRadioButton>
#include <QButtonGroup>
#include <QTextStream>
#include <QFile>
namespace Ui {
class display;
}
class Display : public QDialog
{
Q_OBJECT
public:
explicit Display(QWidget *parent = 0);
~Display();
void plot(const QVector<unsigned short> &data);
void plot();
void setTitle(QString title);
QVector<unsigned short> buffer;
public slots:
void showEvent(QShowEvent *event);
void onButtonClicked(QAbstractButton *button);
void onSaveBackgroundClicked();
protected:
int nrPoints = 0;
QVector<double> dataX;
QVector<double> dataY;
private:
Ui::display *ui;
QRadioButton *radioButtonFixedScale; // Pointer to the Fixed Scale radio button
QRadioButton *radioButtonAutoscale; // Pointer to the Autoscale radio button
QButtonGroup *buttonGroup;
};
#endif // DISPLAY_H

161
hit2023v2/display.ui Normal file
View File

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>display</class>
<widget class="QDialog" name="display">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>602</width>
<height>390</height>
</rect>
</property>
<property name="windowTitle">
<string>Online Display</string>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>9</x>
<y>10</y>
<width>581</width>
<height>341</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="lineTitle">
<property name="frame">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCustomPlot" name="plot" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QRadioButton" name="radioButtonAutoscale">
<property name="text">
<string>Auto Y-Scale</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonMaxScale">
<property name="text">
<string>Max Y-Scale</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonFixedScale">
<property name="text">
<string>Fixed Y-Scale</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_fixedmin">
<property name="minimum">
<number>-1000</number>
</property>
<property name="maximum">
<number>66000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>-1000</number>
</property>
<property name="displayIntegerBase">
<number>10</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox_fixedmax">
<property name="minimum">
<number>1000</number>
</property>
<property name="maximum">
<number>65000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>65000</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QPushButton" name="pushButton_savebkg">
<property name="geometry">
<rect>
<x>510</x>
<y>360</y>
<width>80</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string>save bkg</string>
</property>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
<buttongroups>
<buttongroup name="buttonGroup"/>
</buttongroups>
</ui>

129
hit2023v2/displayserver.cpp Normal file
View File

@ -0,0 +1,129 @@
#include "displayserver.h"
DisplayServer::DisplayServer(QObject *parent) : QObject(parent)
{
}
DisplayServer::~DisplayServer()
{
unsetup();
}
//********************************************
PlaneConfig* DisplayServer::findPlane(int plane_nr)
{
for (int plane = 0; plane < planeConfig.length(); plane++)
{
if (planeConfig[plane]->nr == plane_nr)
return planeConfig[plane];
}
//create new plane if not found
PlaneConfig* new_plane = new PlaneConfig;
new_plane->nr = plane_nr;
new_plane->name = QString("Plane %1").arg(plane_nr);
new_plane->nr_devices = 0;
new_plane->nr_sensors = 0;
planeConfig.append(new_plane);
return new_plane;
}
void DisplayServer::setup(HW* hw)
{
unsetup(); //hide is inside;)
theHW = hw;
for (int dev_nr = 0; dev_nr < theHW->devices.length(); dev_nr++)
{
PlaneConfig* current_plane = findPlane(theHW->devices[dev_nr]->deviceConfig.plane);
current_plane->devices.append(theHW->devices[dev_nr]);
current_plane->nr_devices++;
current_plane->nr_sensors += theHW->devices[dev_nr]->deviceConfig.nr_sensors;
}
}
void DisplayServer::unsetup()
{
hide();
for (int plane_nr = 0; plane_nr < planeConfig.length(); plane_nr++)
{
delete planeConfig[plane_nr];
planeConfig[plane_nr] = NULL;
}
planeConfig.clear();
}
//********************************************
void DisplayServer::show()
{
hide();
displays.clear();
for (int plane = 0; plane < planeConfig.length(); plane++)
{
Display* newDisplay = new Display;
newDisplay->setTitle(planeConfig[plane]->name);
newDisplay->show();
displays.append(newDisplay);
}
active = 1;
}
void DisplayServer::hide()
{
if (active)
{
for (int plane = 0; plane < displays.length(); plane++)
{
displays[plane]->close();
delete displays[plane];
}
displays.clear();
active = 0;
}
}
void DisplayServer::plot()
{
if (!active)
return;
QVector<BufferData> lastFrame = theHW->eventBuilder.getLastFrame();
if (lastFrame.length() == 0)
return;
for (int plane = 0; plane < planeConfig.length(); plane++)
{
//initialize buffer
displays[plane]->buffer.resize(planeConfig[plane]->nr_sensors*64);
//fill with data
int current_base = 0;
for (int dev_nr = 0; dev_nr < planeConfig[plane]->nr_devices; dev_nr++)
{
int dev_id = planeConfig[plane]->devices[dev_nr]->deviceConfig.device_id;
int nr_channels = planeConfig[plane]->devices[dev_nr]->deviceConfig.nr_channels();
if (nr_channels > lastFrame[dev_id].buffer_size)
nr_channels = lastFrame[dev_id].buffer_size; //check if there's really some data in the buffer
//WARNING!!! Device order is not yet implemented!!! (probably)
for (int i = 0; i < nr_channels; i++)
displays[plane]->buffer[current_base+i] = lastFrame[dev_id].sensor_data[i];
current_base += nr_channels;
}
//plot
displays[plane]->plot();
}
}
int DisplayServer::isActive()
{
return active;
}

46
hit2023v2/displayserver.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef DISPLAYSERVER_H
#define DISPLAYSERVER_H
#include <QObject>
#include <QVector>
#include "hw.h"
#include "display.h"
typedef struct
{
int nr;
QString name;
int nr_sensors; //this is commonly 2*nr_devices or 2*nr_devices-1
int nr_devices;
QVector<Device*> devices;
} PlaneConfig;
class DisplayServer : public QObject
{
Q_OBJECT
public:
explicit DisplayServer(QObject *parent = 0);
void setup(HW *hw);
void show();
void hide();
void plot();
int isActive();
~DisplayServer();
void unsetup();
signals:
public slots:
protected:
int active = 0;
HW* theHW;
QVector<PlaneConfig*> planeConfig;
QVector<Display*> displays;
PlaneConfig *findPlane(int plane_nr);
};
#endif // DISPLAYSERVER_H

304
hit2023v2/eventbuilder.cpp Normal file
View File

@ -0,0 +1,304 @@
#include "eventbuilder.h"
EventBuilder::EventBuilder(QObject *parent) : QObject(parent)
{
connect(this, EventBuilder::sigInit, this, EventBuilder::onInit);
connect(this, EventBuilder::sigDeinit, this, EventBuilder::onDeinit);
connect(this, EventBuilder::sigStartLogging, this, EventBuilder::onStartLogging);
connect(this, EventBuilder::sigStopLogging, this, EventBuilder::onStopLogging);
connect(this, EventBuilder::sigStartTakingHistos, this, EventBuilder::onStartTakingHistos);
connect(this, EventBuilder::sigStopTakingHistos, this, EventBuilder::onStopTakingHistos);
moveToThread(&thread);
thread.start();
init();
}
EventBuilder::~EventBuilder()
{
deinit();
thread.quit();
thread.wait();
}
//************************* Data processing framework ********************
//main processing slot
void EventBuilder::onNewData(DataReceiver* receiver)
{
while (checkBufferOccupancies())
{
//find lowest global sync value
int lowest_id = findLowestId();
//get and validate data from buffers
for (int dev_nr = 0; dev_nr < nrReceivers; dev_nr++)
{
BufferData data = receivers[dev_nr]->dataBuffer.look();
if (data.sync_frame.global_ctr == lowest_id)
{
receivers[dev_nr]->dataBuffer.dump(); //right data, dump it from the buffer
}
else
{
data.sync_frame.data_ok = 0; //wrong data, mark as bad
}
//store data for complete frame
currentFrame[dev_nr] = data;
}
lastFrameMutex.lock();
if (newDataSemaphore.available() == 0)
newDataSemaphore.release(1);
lastFrame = currentFrame;
lastFrameMutex.unlock();
//histogram stuff
if (histogramSamplesToTake)
{
for (int dev_nr = 0; dev_nr < nrReceivers; dev_nr++)
for (int ch = 0; ch < channelCounts[dev_nr]; ch++)
histograms[baseAddresses[dev_nr] + ch].shoot(currentFrame[dev_nr].sensor_data[ch]);
if (histogramSamplesToTake != -1)
histogramSamplesToTake--;
if (histogramSamplesToTake == 0)
emit sigHistoCompleted();
}
//log data
if (loggingData)
logDataToFile();
//************ TODO ************
//Here we can do something more with the complete frame
}
}
//return 1 if buffer levels allow/force data processing
int EventBuilder::checkBufferOccupancies()
{
int result = 1;
for (int dev_nr = 0; dev_nr < nrReceivers; dev_nr++)
{
int nr_items = receivers[dev_nr]->dataBuffer.nrItems();
if (nr_items > EVB_MAX_BUFFER_OCCUPANCY)
return 1; //if at least one buffer is above high threshold - return immediately
if (nr_items < EVB_MIN_BUFFER_OCCUPANCY)
result = 0;
}
return result;
}
int EventBuilder::findLowestId()
{
int min1 = INT_MAX, min2 = INT_MAX;
int max1 = INT_MIN, max2 = INT_MIN;
for (int dev_nr = 0; dev_nr < nrReceivers; dev_nr++)
{
int value = receivers[dev_nr]->dataBuffer.look().sync_frame.global_ctr;
//for non-zero-crossing case
if (value < min1) min1 = value;
if (value > max1) max1 = value;
//for zero-crossing case
if (value > 256) value -= 512;
if (value < min2) min2 = value;
if (value > max2) max2 = value;
}
if ((max1-min1) < (max2-min2))
{
//non-zero-crossing
return min1;
}
else
{
//zero-crossing
if (min2 < 0) min2 += 512;
return min2;
}
}
void EventBuilder::logDataToFile()
{
/*
* Write data in binary format:
* - number of boards: N = 1 x unsigned short
* - number of channels per each board Cn: N x unsigned short
* - N times the following sequence:
* - SyncFrame S = 1 x SyncFrame (== 16 bytes)
* - Data D = Cn x unsigned short
*/
logFile.write((const char*)&totalBoards, sizeof(unsigned short));
logFile.write((const char*)channelCounts.constData(), totalBoards * sizeof(unsigned short));
for (int board = 0; board < totalBoards; board++)
{
logFile.write((const char*)&(currentFrame[board].sync_frame), sizeof(SyncFrame));
logFile.write((const char*)currentFrame[board].sensor_data, currentFrame[board].buffer_size*sizeof(unsigned short));
}
//write data in native binary format. All devices written as 5-sensor-wide!
//logFile.write((const char*)currentFrame.constData(), nrReceivers*sizeof(BufferData));
}
void EventBuilder::recalculateChannels()
{
totalBoards = baseAddresses.count();
if (totalBoards == 0)
return;
for (int i = 1; i < totalBoards; i++)
baseAddresses[i] = baseAddresses[i-1] + channelCounts[i-1];
totalChannels = 0;
for (int i = 0; i < channelCounts.count(); i++)
totalChannels += channelCounts[i];
}
void EventBuilder::setChannelCount(int sensor_nr, int nr_channels)
{
channelCounts[sensor_nr] = nr_channels;
recalculateChannels();
}
//************************* Protected slots ********************
void EventBuilder::onInit()
{
//Still nothing? Strange...
initSemaphore.release();
}
void EventBuilder::onDeinit()
{
//Still nothing? Strange...
initSemaphore.release();
}
void EventBuilder::onStartLogging()
{
if (loggingData)
onStopLogging();
logFile.setFileName(logFileName);
logFile.open(QIODevice::WriteOnly);
loggingData = 1;
}
void EventBuilder::onStopLogging()
{
loggingData = 0;
logFile.close();
}
void EventBuilder::onStartTakingHistos(int sample_count)
{
histograms.resize(totalChannels);
for (int ch = 0; ch < histograms.length(); ch++)
histograms[ch].resize(65536);
histogramSamplesToTake = sample_count;
}
void EventBuilder::onStopTakingHistos()
{
histogramSamplesToTake = 0;
emit sigHistoCompleted();
}
//******************** Thread-safe interface *******************
void EventBuilder::init()
{
emit sigInit();
initSemaphore.acquire(); //wait for initialization
}
void EventBuilder::deinit()
{
emit sigDeinit();
initSemaphore.acquire(); //wait for deinitialization
}
void EventBuilder::addSource(DataReceiver* source)
{
baseAddresses.push_back(0);
channelCounts.push_back(0);
receivers.append(source);
nrReceivers = receivers.length();
currentFrame.resize(nrReceivers);
connect(source, DataReceiver::sigDataReady, this, EventBuilder::onNewData);
}
void EventBuilder::deleteSources()
{
for (int i = 0; i < receivers.length(); i++)
disconnect(receivers[i], DataReceiver::sigDataReady, this, EventBuilder::onNewData);
receivers.clear();
nrReceivers = receivers.length();
baseAddresses.clear();
channelCounts.clear();
}
void EventBuilder::startLogging(QString filename)
{
logFileName = filename;
emit sigStartLogging();
}
void EventBuilder::stopLogging()
{
emit sigStopLogging();
}
int EventBuilder::isLogging()
{
return loggingData;
}
void EventBuilder::startTakingHistos(int sample_count)
{
emit sigStartTakingHistos(sample_count);
}
void EventBuilder::stopTakingHistos()
{
emit sigStopTakingHistos();
}
QVector<Histogram>& EventBuilder::getHistos()
{
return histograms;
}
QVector<BufferData> EventBuilder::getLastFrame()
{
QMutexLocker locker(&lastFrameMutex);
return lastFrame;
}
QVector<BufferData> EventBuilder::getNewFrame()
{
//wait for new data
newDataSemaphore.acquire(1);
//and return it
return getLastFrame();
}

91
hit2023v2/eventbuilder.h Normal file
View File

@ -0,0 +1,91 @@
#ifndef EVENTBUILDER_H
#define EVENTBUILDER_H
#include <QObject>
#include <QVector>
#include <QList>
#include <QFile>
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
//#include "hw.h"
#include "datareceiver.h"
#include "histogram.h"
//The event builder will constantly keep some data in the buffers to enable synchronization of the devices. So:
#define EVB_MIN_BUFFER_OCCUPANCY (RECEIVER_BUFFER_SIZE / 8) //the EVB will wait until so much data is in each device buffer
#define EVB_MAX_BUFFER_OCCUPANCY (RECEIVER_BUFFER_SIZE / 2) //or so much in at least one
class EventBuilder : public QObject
{
Q_OBJECT
public:
explicit EventBuilder(QObject *parent = 0);
~EventBuilder();
void addSource(DataReceiver *source);
void deleteSources();
void startLogging(QString filename);
void stopLogging();
int isLogging();
void startTakingHistos(int sample_count);
void stopTakingHistos();
QVector<Histogram> &getHistos();
QVector<BufferData> getLastFrame();
QVector<BufferData> getNewFrame(); //as getLastFrame(), but ensures that the frame is new, i.e. no frame will be read twice
void recalculateChannels(); //recalculate baseAddresses
void setChannelCount(int sensor_nr, int nr_channels);
signals:
void sigInit();
void sigDeinit();
void sigStartLogging();
void sigStopLogging();
void sigStartTakingHistos(int);
void sigStopTakingHistos();
void sigHistoCompleted(); //this is a public signal which can be used to notify user that the histo is ready
public slots:
void onNewData(DataReceiver *receiver);
protected:
int checkBufferOccupancies();
int findLowestId();
void logDataToFile();
void init(); //run after moving to thread
void deinit();
QThread thread;
QSemaphore initSemaphore;
QVector<DataReceiver*> receivers;
QVector<BufferData> currentFrame;
QVector<BufferData> lastFrame;
QVector<Histogram> histograms;
int histogramSamplesToTake = 0;
QVector<unsigned short> baseAddresses; //base channel numbers for receivers
QVector<unsigned short> channelCounts; //and numbers of channels
unsigned short totalChannels; //we like unsigned shorts to put them directly into the data file
unsigned short totalBoards;
QMutex lastFrameMutex;
QSemaphore newDataSemaphore;
int nrReceivers;
QString logFileName;
QFile logFile;
int loggingData = 0;
protected slots:
void onInit();
void onDeinit();
void onStartLogging();
void onStopLogging();
void onStartTakingHistos(int sample_count);
void onStopTakingHistos();
};
#endif // EVENTBUILDER_H

97
hit2023v2/helpers.cpp Normal file
View File

@ -0,0 +1,97 @@
#include "helpers.h"
QString ip2num(QString input, unsigned char* numbers)
{
QStringList ip_sl = input.split(".");
unsigned char ip_arr[4];
for (int i = 0; i < 4; i++)
if (i < ip_sl.length())
ip_arr[i] = (unsigned char) ip_sl.at(i).toInt();
else
ip_arr[i] = 0;
QString generated = QString("%1.%2.%3.%4")
.arg(ip_arr[0])
.arg(ip_arr[1])
.arg(ip_arr[2])
.arg(ip_arr[3]);
if (numbers)
{
for (int i = 0; i < 4; i++)
numbers[i] = ip_arr[i];
}
return generated;
}
void top (QSettings* settings)
{
while(settings->group().length() != 0)
settings->endGroup();
}
void copyQSettingsHelper(QSettings* from, QSettings* to)
{
//copy own keys
QStringList keys = from->childKeys();
for(int i = 0; i < keys.length(); i++)
{
to->setValue(keys[i], from->value(keys[i]));
}
//recursively copy child groups
QStringList groups = from->childGroups();
for(int i = 0; i < groups.length(); i++)
{
from->beginGroup(groups[i]);
to->beginGroup(groups[i]);
copyQSettingsHelper(from, to);
from->endGroup();\
to->endGroup();
}
}
void copyQSettings(QSettings* from, QSettings* to)
{
to->clear();
top(from);
copyQSettingsHelper(from, to);
}
void msleep2(unsigned int ms, unsigned int resolution)
{
QTimer timer;
timer.setSingleShot(1);
timer.start(ms);
while(timer.isActive())
{
QCoreApplication::processEvents();
QThread::msleep(resolution);
}
}
void saveCsvFile(QString filename, QList<QVector<double>> params, QList<QVector<double>> sensormean, QList<QVector<double>> sensorstd, QString delimiter)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << qSetFieldWidth(14) << qSetRealNumberPrecision(8);
for (int row = 0; (row < params.length()) && (row < sensormean.length()) && (row < sensorstd.length()); row++)
{
int col;
for (col = 0; col < params[row].length(); col++)
out << params[row][col] << delimiter;\
for (col = 0; (col < (sensormean[row].length() - 1)) && (col < (sensorstd[row].length() - 1)); col++)
out << sensormean[row][col] << delimiter << sensorstd[row][col] << delimiter;
out << sensormean[row][col+1] << delimiter << sensorstd[row][col+1] << QString("\n");
}
file.close();
}

38
hit2023v2/helpers.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef HELPERS_H
#define HELPERS_H
#include <QString>
#include <QStringList>
#include <QSettings>
#include <QTimer>
#include <QCoreApplication>
#include <QThread>
#include <QList>
#include <QVector>
#include <QFile>
#include <QTextStream>
//byte array <-> unsiged short conversion
#define SHORT2BYTES(sh,by) {by[0] = (sh>>8) & 0xFF; by[1] = sh & 0xFF;}
#define LO(x) (x & 0xFF)
#define HI(x) ((x>>8) & 0xFF)
#define BYTES2SHORT(by) ( ((unsigned short)(unsigned char)((by)[0]) << 8) | ((unsigned short)(unsigned char)((by)[1])) ) //safe way
//#define BYTES2SHORT(by) ( *((unsigned short*)by) ) //faster
//convert textual representation of IP to array of numbers and/or well-formatted string
QString ip2num(QString input, unsigned char* numbers = NULL);
//go to the main branch of settings
void top (QSettings* settings);
//copy settings table
void copyQSettings(QSettings* from, QSettings* to);
//sleep with processing queues
void msleep2(unsigned int ms, unsigned int resolution = 10);
//Save data in form of CSV file. The three tables should have the same number of rows. They will be concatenated. Sensormean and sensorstd will be interlaced.
void saveCsvFile(QString filename, QList<QVector<double>> params, QList<QVector<double>> sensormean, QList<QVector<double>> sensorstd, QString delimiter = QString(","));
#endif // HELPERS_H

144
hit2023v2/histogram.cpp Normal file
View File

@ -0,0 +1,144 @@
#include "histogram.h"
Histogram::Histogram()
{
resize(1);
}
Histogram::Histogram(const Histogram& other)
{
length = other.getLength();
data = other.data;
}
Histogram::Histogram(int newlength)
{
resize(newlength);
}
Histogram::~Histogram()
{
data.clear();
}
void Histogram::resize(int newlength)
{
length = newlength;
data.clear();
data.resize(length);
clear();
}
void Histogram::clear()
{
data.fill(0);
}
int Histogram::getLength() const
{
return length;
}
int& Histogram::operator[](int pos)
{
if (pos < 0)
pos = 0;
if (pos >= length)
pos = length-1;
return data[pos];
}
Histogram& Histogram::operator=(const Histogram& other)
{
if (this != &other)
{
length = other.getLength();
data = other.data;
}
return *this;
}
void Histogram::shoot(int channel)
{
if ((channel >= 0) && (channel < length))
data[channel]++;
}
int Histogram::getNrSamples()
{
int result = 0;
for (int ch = 0; ch < length; ch++)
result += data[ch];\
return result;
}
double Histogram::moment(int n)
{
double result;
for (int ch = 0; ch < length; ch++)
result += (pow(ch,n) * data[ch]);
result /= getNrSamples();
return result;
}
double Histogram::cmoment(int n)
{
double result;
double EX = moment(1);
for (int ch = 0; ch < length; ch++)
result += (pow((ch-EX),n) * data[ch]);
result /= getNrSamples();
return result;
}
double Histogram::mean()
{
//return moment(1);
//faster:
double result;
for (int ch = 0; ch < length; ch++)
result += ((long int)ch * (long int)data[ch]);
return (double) result / getNrSamples();
}
double Histogram::var()
{
//return moment(2) - pow(mean(),2);
//faster:
double result;
for (int ch = 0; ch < length; ch++)
result += ((double)ch * (double)ch * (double)data[ch]);
return (double) result / getNrSamples();
}
double Histogram::stdev()
{
return sqrt(var());
}
void Histogram::MS(double* mean, double* stdev)
{
double nr_samples = 0;
double EX = 0;
double EX2 = 0;
double tmp;
for (int ch = 0; ch < length; ch++)
{
tmp = (double)ch * (double)data[ch];
nr_samples += data[ch];
EX += tmp;
EX2 += (double)ch * tmp;
}
EX /= nr_samples;
EX2 /= nr_samples;
*mean = EX;
*stdev = sqrt( EX2 - EX*EX );
}

36
hit2023v2/histogram.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef HISTOGRAM_H
#define HISTOGRAM_H
#include <QVector>
class Histogram
{
public:
Histogram();
Histogram(const Histogram &other);
Histogram(int newlength);
~Histogram();
void resize(int newlength);
void clear();
int getLength() const;
int &operator [](int pos);
int length;
QVector<int> data;
Histogram &operator =(const Histogram &other);
void shoot(int channel); //add one event to the histogram
int getNrSamples();
double moment(int n);
double cmoment(int n);
double mean();
double var();
double stdev();
void MS(double *mean, double *stdev); //calculate mean and stdev
protected:
};
#endif // HISTOGRAM_H

77
hit2023v2/hit2023v2.pro Normal file
View File

@ -0,0 +1,77 @@
#-------------------------------------------------
#
# Project created by QtCreator 2017-08-21T15:59:19
#
#-------------------------------------------------
QT += core gui network serialport
QMAKE_CXXFLAGS += -Wa,-mbig-obj
greaterThan(QT_MAJOR_VERSION, 5): QT += widgets printsupport
TARGET = hit2023v2
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
q_debugstream.cpp \
dialoglogsettings.cpp \
device.cpp \
datareceiver.cpp \
hw.cpp \
dialoghostip.cpp \
dialogtriggersettings.cpp \
dialogdevices.cpp \
helpers.cpp \
eventbuilder.cpp \
qcustomplot.cpp \
display.cpp \
displayserver.cpp \
keithley.cpp \
keithley_thr.cpp \
dialoglinearity.cpp \
histogram.cpp \
dialogtiscan.cpp \
dialogprofiler.cpp \
stepper.cpp \
dialogbeta.cpp
HEADERS += mainwindow.h \
Q_DebugStream.h \
dialoglogsettings.h \
device.h \
dev_commands.h \
datareceiver.h \
hw.h \
dialoghostip.h \
dialogtriggersettings.h \
dialogdevices.h \
helpers.h \
cbuffer.h \
eventbuilder.h \
qcustomplot.h \
display.h \
displayserver.h \
keithley.h \
keithley_thr.h \
dialoglinearity.h \
histogram.h \
dialogtiscan.h \
dialogprofiler.h \
stepper.h \
dialogbeta.h
FORMS += mainwindow.ui \
dialoglogsettings.ui \
dialoghostip.ui \
dialogtriggersettings.ui \
dialogdevices.ui \
display.ui \
dialoglinearity.ui \
dialogtiscan.ui \
dialogprofiler.ui \
dialogbeta.ui

107
hit2023v2/hw.cpp Normal file
View File

@ -0,0 +1,107 @@
#include "hw.h"
HW::HW(QObject *parent) : QObject(parent)
{
/*eventBuilder.moveToThread(&eventBuilderThread);
eventBuilderThread.start();
eventBuilder.init();*/
}
HW::~HW()
{
eventBuilder.stopLogging();
removeDevices();
}
Device& HW::operator[](int nr)
{
return *(devices[nr]);
}
void HW::addDevices(int nr_devices)
{
for (int i = 0; i < nr_devices; i++)
{
Device* new_dev = new Device;
devices.push_back(new_dev);
eventBuilder.addSource(&(new_dev->dataReceiver));
}
}
void HW::removeDevices()
{
eventBuilder.deleteSources();
for (int i = 0; i < devices.length(); i++)
delete devices[i];
devices.clear();
}
void HW::configureDevice(int dev_nr, DeviceConfig dc)
{
(*this)[dev_nr].configure(dc);
eventBuilder.setChannelCount(dev_nr, dc.max_channels());
}
void HW::connectDevices()
{
qInfo("Connecting devices...");
for (int i = 0; i < devices.length(); i++)
devices[i]->connectDevice();
}
void HW::disconnectDevices()
{
qInfo("Disconnecting devices...");
for (int i = 0; i < devices.length(); i++)
devices[i]->disconnectDevice();
}
void HW::run()
{
//No need to start EVB. It's running all the time.
//run slave(s)
for (int i = 0; i < devices.length(); i++)
if (devices[i]->deviceConfig.master == 0)
devices[i]->startAcq();
//run master(s)
for (int i = 0; i < devices.length(); i++)
if (devices[i]->deviceConfig.master != 0)
devices[i]->startAcq();
}
void HW::stop()
{
//stop master(s)
for (int i = 0; i < devices.length(); i++)
if (devices[i]->deviceConfig.master != 0)
devices[i]->stopAcq();
//stop slave(s)
for (int i = 0; i < devices.length(); i++)
if (devices[i]->deviceConfig.master == 0)
devices[i]->stopAcq();
//EVB is running all the time.
}
QString HW::report()
{
int nr_devices = devices.length();
QString result;
for (int dev_nr = 0; dev_nr < nr_devices; dev_nr++)
{
double buffer_ocupancy = 100.0 * (double)(devices[dev_nr]->dataReceiver.dataBuffer.nrItems()) / (double)RECEIVER_BUFFER_SIZE;
double ksps = (double)(devices[dev_nr]->getFrameRate())/1000.0;
result += QString("%1: %2kfps, %3% ").arg(dev_nr).arg(ksps,5,'f',2,'0').arg(buffer_ocupancy,4,'f',1,'0');
}
return result;
}

41
hit2023v2/hw.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef HW_H
#define HW_H
#include <QObject>
#include <QVector>
#include <QThread>
#include "device.h"
#include "eventbuilder.h"
class HW : public QObject
{
Q_OBJECT
public:
explicit HW(QObject *parent = 0);
~HW();
QVector<Device*> devices;
EventBuilder eventBuilder;
Device &operator [](int nr);
void addDevices(int nr_devices);
void removeDevices();
void connectDevices();
void disconnectDevices();
void run();
void stop();
QString report();
void configureDevice(int dev_nr, DeviceConfig dc);
signals:
public slots:
protected:
};
#endif // HW_H

241
hit2023v2/keithley.cpp Normal file
View File

@ -0,0 +1,241 @@
#include "keithley.h"
//THIS IS KEITHLEY 6487 (PICOAMMETER) RS-232 LIBRARY!
keithley::keithley()
{
isOpen = 0;
}
/*void keithley::ps_printf(const char* fmt, ...)
{
QString result;
va_list args;
va_start(args, fmt);
result.vsprintf(fmt, args);
va_end(args);
//char toWrite[result.length()+1];
//strcpy(toWrite, qPrintable(result));
//serialPort.write(toWrite, strlen(toWrite));
socket.write(qPrintable(result), result.length());
socket.waitForBytesWritten(500);
}
//read a CR-LF terminated string from PS
int keithley::ps_read(char* dest, int maxSize)
{
int ptr = 0;
while (1)
{
if (socket.read(dest+ptr,1) <= 0)
{
if (!socket.waitForReadyRead(10))
break; //no new data - break
}
else
ptr++;
if (dest[ptr-1] == '\n')
{
ptr--;
break; //newline found - delete and break
}
if (dest[ptr-1] == '\r')
ptr--; //CR found - delete it
if (ptr >= (maxSize-1))
break; //buffer full = break
}
dest[ptr] = 0;
//return number of read characters
return ptr;
}*/
//Qt5
/*
void keithley::ps_printf(const char* fmt, ...)
{
QString result;
va_list args;
va_start(args, fmt);
result.vsprintf(fmt, args);
va_end(args);
//char toWrite[result.length()+1];
//strcpy(toWrite, qPrintable(result));
//serialPort.write(toWrite, strlen(toWrite));
serialPort.write(qPrintable(result), result.length());
serialPort.waitForBytesWritten(500);
}
*/
//Qt6
void keithley::ps_printf(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
QString result = QString::vasprintf(fmt, args);
va_end(args);
serialPort.write(result.toUtf8());
serialPort.waitForBytesWritten(500);
}
//read a CR-LF terminated string from PS
int keithley::ps_read(char* dest, int maxSize)
{
int ptr = 0;
while (1)
{
if (serialPort.read(dest+ptr,1) <= 0)
{
if (!serialPort.waitForReadyRead(500))
break; //no new data - break
}
else
{
ptr++;
if (dest[ptr-1] == '\n')
{
ptr--;
break; //newline found - delete and break
}
if (dest[ptr-1] == '\r')
{
ptr--; //CR found - delete and break
break;
}
if (ptr >= (maxSize-1))
break; //buffer full = break
}
}
dest[ptr] = 0;
return ptr;
}
void keithley::ps_flush()
{
char buffer[32];
while (ps_read(buffer, 32));
}
//**************************************************************************
int keithley::connect()
{
/*disconnect(); //just if we were connected
socket.connectToHost(hostName, port);
if (socket.waitForConnected(5000))
{
isOpen = 1;
return 1;
}
return 0;*/
QList<QSerialPortInfo> list = QSerialPortInfo::availablePorts();
disconnect(); //close port if it's open
if (list.size() == 0)
return -1; //no serial ports found
for (int port = 0; port < list.size(); port++)
{
serialPort.setPort(list[port]);
serialPort.setBaudRate(57600);
if (serialPort.open(QIODevice::ReadWrite))
{
serialPort.setBaudRate(57600);
ps_printf("*IDN?\n");
QThread::msleep(100);
char buffer[128];
ps_read(buffer,128);
if (strstr(buffer, "KEITHLEY INSTRUMENTS INC.,MODEL 6487"))
{ //gotta our PS!
isOpen = 1;
portName = list[port].portName();
//configure for measurement
QThread::msleep(100);
ps_printf("CONF\n");
//setup medium readout reate (Tint = 20 ms)
QThread::msleep(100);
ps_printf("NPLC 1\n");
QThread::msleep(100);
ps_printf("RANG:AUTO 0\n");
QThread::msleep(100);
ps_printf("RANG 2e-5\n");
QThread::msleep(100);
//setup source
ps_printf("SOUR:VOLT:RANG 10\n");
QThread::msleep(100);
ps_printf("SOUR:VOLT:ILIM 2.5e-2\n");
QThread::msleep(100);
break;
}
serialPort.close();
}
}
return isOpen;
}
void keithley::disconnect()
{
if (!isOpen)
return;
//socket.close();
serialPort.close();
isOpen = 0;
}
void keithley::setVoltage(double voltage)
{
if (!isOpen)
return;
//ps_printf("smua.source.func=smua.OUTPUT_DCVOLTS\n");
//ps_printf("smua.source.levelv=%1.2f\n", voltage);
ps_printf("SOUR:VOLT %1.2f\n", voltage);
}
void keithley::on(int state)
{
if (!isOpen)
return;
if (state)
{
//ps_printf("smua.source.output=smua.OUTPUT_ON\n");
ps_printf("SOUR:VOLT:STAT ON\n");
}
else
{
//ps_printf("smua.source.output=smua.OUTPUT_OFF\n");
ps_printf("SOUR:VOLT:STAT OFF\n");
}
}
void keithley::reset()
{
if (!isOpen)
return;
//ps_printf("smua.reset()\n");
ps_printf("*RST\n");
}
double keithley::getCurrent()
{
char reply[128];
ps_flush();
//ps_printf("print(smua.measure.i())\n");
//ps_printf("MEAS?\n");
ps_printf("READ?\n");
//QThread::msleep(250);
while (!ps_read(reply, 128));
double result = atof(reply);
return result;
}

30
hit2023v2/keithley.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef KEITHLEY_H
#define KEITHLEY_H
//THIS IS KEITHLEY 6487 (PICOAMMETER) RS-232 LIBRARY!
#include <QtSerialPort/QtSerialPort>
#include <QSerialPortInfo>
#include <QSerialPort>
class keithley
{
public:
keithley();
//QTcpSocket socket;
int isOpen;
QString portName;
QSerialPort serialPort;
int connect();
void disconnect();
void ps_printf(const char *fmt...);
int ps_read(char* dest, int maxSize);
void setVoltage(double voltage);
void on(int state);
void reset();
double getCurrent();
void ps_flush();
};
#endif // KEITHLEY_H

150
hit2023v2/keithley_thr.cpp Normal file
View File

@ -0,0 +1,150 @@
#include "keithley_thr.h"
//THIS IS KEITHLEY 6487 (PICOAMMETER) RS-232 LIBRARY!
//************************** worker class ******************
keithleyWorker::keithleyWorker()
{
QObject::connect(&timer, &QTimer::timeout, this, &keithleyWorker::timerEvent);
timer.setSingleShot(true);
}
void keithleyWorker::connect()
{
int isOpen = theKeithley.connect();
emit sig_isOpen(isOpen, theKeithley.portName);
}
void keithleyWorker::disconnect()
{
theKeithley.disconnect();
}
void keithleyWorker::runTimer(const int state)
{
if (state)
timer.start(readoutDelay);
else
timer.stop();
}
void keithleyWorker::timerEvent()
{
//do the readout
lastCurrentReadout = theKeithley.getCurrent();
emit sig_currentReadout(lastCurrentReadout);
//run the timer again
timer.start(readoutDelay);
}
void keithleyWorker::on(const int state)
{
theKeithley.on(state);
}
void keithleyWorker::setVoltage(const double voltage)
{
theKeithley.setVoltage(voltage);
}
void keithleyWorker::reset()
{
theKeithley.reset();
}
//************************** constructor and destructor ******************
keithley_thr::keithley_thr()
{
lastCurrentReadout = -1;
isOpen = 0;
keithleyWorker *worker = new keithleyWorker;
//worker->theKeithley = &theKeithley;
worker->moveToThread(&workerThread);
worker->timer.moveToThread(&workerThread);
worker->theKeithley.serialPort.moveToThread(&workerThread);
//controller -> worker
QObject::connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
QObject::connect(this, &keithley_thr::sig_connect, worker, &keithleyWorker::connect);
QObject::connect(this, &keithley_thr::sig_disconnect, worker, &keithleyWorker::disconnect);
QObject::connect(this, &keithley_thr::sig_on, worker, &keithleyWorker::on);
QObject::connect(this, &keithley_thr::sig_setVoltage, worker, &keithleyWorker::setVoltage);
QObject::connect(this, &keithley_thr::sig_reset, worker, &keithleyWorker::reset);
QObject::connect(this, &keithley_thr::sig_runTimer, worker, &keithleyWorker::runTimer);
//worker -> controller
QObject::connect(worker, &keithleyWorker::sig_currentReadout, this, &keithley_thr::on_currentReadout);
QObject::connect(worker, &keithleyWorker::sig_isOpen, this, &keithley_thr::on_isOpen);
workerThread.start();
}
keithley_thr::~keithley_thr()
{
workerThread.quit();
workerThread.wait();
}
//************************** slots for communication with worker thread ******************
//called on each current readout
keithley_thr::on_currentReadout(const double value)
{
lastCurrentReadout = value;
emit esig_newCurrentReadout(lastCurrentReadout);
}
//called after opening the socket
int keithley_thr::on_isOpen(const int state, const QString givenPortName)
{
isOpen = state;
portName = givenPortName;
}
//************************** class keithley mirror ******************
int keithley_thr::connect()
{
isOpen = -1;
emit sig_connect();
//wait until the socket opens or fails
while (isOpen == -1)
qApp->processEvents();
//run readout if opened succesfully
emit sig_runTimer(isOpen);
return isOpen;
}
void keithley_thr::disconnect()
{
emit sig_runTimer(0);
emit sig_disconnect();
}
void keithley_thr::setVoltage(double voltage)
{
emit sig_setVoltage(voltage);
}
void keithley_thr::on(int state)
{
emit sig_on(state);
}
void keithley_thr::reset()
{
emit sig_reset();
}
double keithley_thr::getCurrent()
{
return lastCurrentReadout;
}

81
hit2023v2/keithley_thr.h Normal file
View File

@ -0,0 +1,81 @@
#ifndef KEITHLEY_THR_H
#define KEITHLEY_THR_H
//THIS IS KEITHLEY 6487 (PICOAMMETER) RS-232 LIBRARY!
#include <QtCore>
#include <QObject>
#include <QThread>
#include <QTimer>
#include "keithley.h"
class keithleyWorker : public QObject
{
Q_OBJECT
public:
keithleyWorker();
keithley theKeithley;
QTimer timer;
double lastCurrentReadout;
int readoutDelay = 100;
public slots:
void on(const int state);
void setVoltage(const double voltage);
void reset();
void timerEvent();
void runTimer(const int state);
void connect();
void disconnect();
signals:
//void resultReady(const QString &result);
void sig_currentReadout(const double value);
void sig_isOpen(const int state, const QString portName);
};
class keithley_thr : public QObject
{
Q_OBJECT
public:
keithley_thr();
~keithley_thr();
//keithley theKeithley;
int isOpen;
int connect();
void disconnect();
void ps_printf(const char *fmt...);
int ps_read(char *dest, int maxSize);
void setVoltage(double voltage);
void on(int state);
void reset();
double getCurrent();
void ps_flush();
QThread workerThread;
double lastCurrentReadout;
QString portName;
int recognizeSpillState(double current);
public slots:
on_currentReadout(const double value);
int on_isOpen(const int state, const QString givenPortName);
signals:
void sig_connect();
void sig_disconnect(void);
void sig_on(const int);
void sig_setVoltage(const double);
void sig_reset(void);
void sig_runTimer(const int);
void esig_newCurrentReadout(const double);
};
#endif // KEITHLEY_THR_H

28
hit2023v2/main.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Apply the stylesheet to each display
qDebug() << "App path : " << qApp->applicationDirPath();
qApp->setStyleSheet("");
QString stylesheetPath = qApp->applicationDirPath()+"/styles/Medize.qss";
// Load and apply the new stylesheet
QFile styleFile(stylesheetPath);
if (styleFile.open(QFile::ReadOnly | QFile::Text)) {
QString style = QTextStream(&styleFile).readAll();
qApp->setStyleSheet(style);
styleFile.close();
} else {
qWarning("Failed to open stylesheet file: %s", qPrintable(stylesheetPath));
}
MainWindow w;
w.show();
return a.exec();
}

481
hit2023v2/mainwindow.cpp Normal file
View File

@ -0,0 +1,481 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialoglogsettings.h"
#include "dialoghostip.h"
#include "dialogtriggersettings.h"
#include "dialogdevices.h"
#include "dialoglinearity.h"
#include "dialogtiscan.h"
#include "dialogprofiler.h"
#include "dialogbeta.h"
#include "helpers.h"
#include <QShowEvent>
#include <QMessageBox>
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
debugStream = new Q_DebugStream(std::cout, ui->logWindow); //Redirect Console output to QTextEdit
Q_DebugStream::registerQDebugMessageHandler(); //Redirect qDebug() output to QTextEdit
deviceSettings = new QSettings("./device_config.ini", QSettings::IniFormat);
theHW = new HW;
theDisplay = new DisplayServer;
theKeithley = new keithley_thr;
theStepper = new Stepper;
connect(&timer, QTimer::timeout, this, on_timer);
connect(theKeithley, keithley_thr::esig_newCurrentReadout, this, MainWindow::on_newCurrentReadout);
}
MainWindow::~MainWindow()
{
delete ui;
delete deviceSettings;
delete theHW;
delete theDisplay;
delete theKeithley;
}
//***************** Initialization ******************
void MainWindow::showEvent(QShowEvent * event)
{
if (!event->spontaneous())
{
status1.setReadOnly(true);
statusBar()->addWidget(&status1,2);
statusKeithley.setReadOnly(true);
statusBar()->addWidget(&statusKeithley,1);
statusKeithley.setText("Keithley disconnected");
std::cout << "Hello, World!" << std::endl;
std::cout << "Everyone likes log windows!" << std::endl;
log_separator();
timer.start(100);
setupDeviceList();
setupHardware();
}
QMainWindow::showEvent(event);
}
void MainWindow::closeEvent(QCloseEvent * event)
{
stopDisplay();
theKeithley->disconnect();
QMainWindow::closeEvent(event);
}
//******************** Debug window *************************
//put horizontal line
void MainWindow::log_separator()
{
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
}
//******************** Helpers *************************
void MainWindow::setupHardware()
{
qInfo("Setting up hardware...");
DeviceConfig dc;
unsigned char ip[4];
top(deviceSettings);
deviceSettings->beginGroup("Global");
int nr_devices = deviceSettings->value("NrDevices").toInt();
ip2num(deviceSettings->value("HostIp").toString(), ip);
for (int i = 0; i < 4; i++)
dc.own_ip[i] = ip[i];
dc.eth_bunch = 1; //must be left as is for v2
dc.dma_bunch = 1; //must be left as is for v2
top(deviceSettings);
deviceSettings->beginGroup("Trigger");
int period_v1 = deviceSettings->value("Period").toInt();
int tint_v1 = deviceSettings->value("Tint").toInt();
int gain_v1 = deviceSettings->value("Gain").toInt();
int period_v2 = deviceSettings->value("Period_v2").toInt();
int tint_v2 = deviceSettings->value("Tint_v2").toInt();
int gain_v2 = deviceSettings->value("Gain_v2").toInt();
for (int dev_nr = 0; dev_nr < nr_devices; dev_nr++)
{
top(deviceSettings);
QString group_label = QString("Device%1").arg(dev_nr);
deviceSettings->beginGroup(group_label);
dc.device_id = dev_nr;
dc.hardware_ver = deviceSettings->value("HardwareVer").toInt();
ip2num(deviceSettings->value("IP").toString(), ip);
for (int i = 0; i < 4; i++)
dc.device_ip[i] = ip[i];
dc.master = deviceSettings->value("Master").toInt();
dc.plane = deviceSettings->value("Plane").toInt();
dc.position = deviceSettings->value("Position").toInt();
dc.nr_sensors = deviceSettings->value("Sensors").toInt();
dc.master_delay = deviceSettings->value("MasterDelay").toInt();
dc.slave_delay = deviceSettings->value("SlaveDelay").toInt();
switch (dc.hardware_ver)
{
case 1:
dc.period = period_v1;
dc.tint = tint_v1;
dc.gain = gain_v1;
break;
case 2:
dc.period = period_v2;
dc.tint = tint_v2;
dc.gain = gain_v2;
break;
default:
qCritical("Unsupported hardware version!");
break;
}
theHW->configureDevice(dev_nr, dc); //configure the device and an entry in base address table in the event builder
}
//theDisplay.setup(&theHW);
}
void MainWindow::setupDeviceList()
{
qInfo("Setting up device list...");
ui->pushRun->setEnabled(false);
theHW->removeDevices();
top(deviceSettings);
deviceSettings->beginGroup("Global");
theHW->addDevices(deviceSettings->value("NrDevices", (int)1).toInt());
}
void MainWindow::run()
{
if (running)
stop();
theHW->run();
ui->pushRun->setText("Stop!");
running = 1;
}
void MainWindow::stop()
{
if (!running)
return;
theHW->stop();
ui->pushRun->setText("Run!");
running = 0;
}
void MainWindow::startLogging()
{
if (logging)
stopLogging();
QString filename = QFileDialog::getSaveFileName(this, "Select file for saving data", "", tr("Binary log files (*.da2)"));
if (filename.length())
{
//Make copy of current settings
QString ini_filename = filename/*.left(filename.lastIndexOf(QString(".")))*/ + QString(".ini");
QSettings* settings_copy = new QSettings(ini_filename,QSettings::IniFormat);
copyQSettings (deviceSettings, settings_copy);
settings_copy->sync();
delete settings_copy;
//Start logging
theHW->eventBuilder.startLogging(filename);
logging = 1;
ui->pushLogging->setText("Stop logging!");
}
}
void MainWindow::stopLogging()
{
theHW->eventBuilder.stopLogging();
logging = 0;
ui->pushLogging->setText("Start logging!");
}
void MainWindow::startDisplay()
{
ui->pushDisplay->setText("Hide display!");
theDisplay->setup(theHW);
theDisplay->show();
}
void MainWindow::stopDisplay()
{
ui->pushDisplay->setText("Show display!");
theDisplay->hide();
}
//******************** Slots *************************
void MainWindow::on_timer()
{
status1.setText(theHW->report());
if (theDisplay->isActive())
theDisplay->plot();
}
void MainWindow::on_pushLogSettings_pressed()
{
DialogLogSettings dlg;
dlg.displayMask = debugStream->displayMask;
dlg.detailsMask = debugStream->detailsMask;
if (dlg.exec() == QDialog::Accepted)
{
debugStream->displayMask = dlg.displayMask;
debugStream->detailsMask = dlg.detailsMask;
std::cout << "(logger settings changed)" << std::endl;
}
}
void MainWindow::on_actionConnect_triggered()
{
stop();
theHW->connectDevices();
ui->pushRun->setEnabled(true);
}
void MainWindow::on_actionDisconnect_triggered()
{
stop();
theHW->disconnectDevices();
ui->pushRun->setEnabled(false);
}
void MainWindow::on_actionHost_IP_triggered()
{
DialogHostIp dlg;
dlg.deviceSettings = deviceSettings;
if (dlg.exec() == QDialog::Accepted)
{
stop();
setupHardware();
}
}
void MainWindow::on_actionTrigger_config_triggered()
{
DialogTriggerSettings dlg;
dlg.deviceSettings = deviceSettings;
if (dlg.exec() == QDialog::Accepted)
{
stop();
setupHardware();
}
}
void MainWindow::on_actionDevices_triggered()
{
DialogDevices dlg;
dlg.deviceSettings = deviceSettings;
if (dlg.exec() == QDialog::Accepted)
{
stop();
if (theDisplay->isActive())
stopDisplay();
setupDeviceList();
setupHardware();
}
}
void MainWindow::on_pushRun_pressed()
{
if (!running)
run();
else
stop();
}
void MainWindow::on_pushLogging_pressed()
{
if (!logging)
startLogging();
else
stopLogging();
}
void MainWindow::on_pushDisplay_pressed()
{
if (theDisplay->isActive())
stopDisplay();
else
startDisplay();
}
void MainWindow::on_actionLinearity_test_triggered()
{
if (!theKeithley->isOpen)
{
qWarning("Keithley not connected! Aborting linearity test!");
return;
}
if (!running)
{
qWarning("Run is stopped! Aborting linearity test!");
return;
}
DialogLinearity dlg;
dlg.theHW = theHW;
dlg.theKeithley = theKeithley;
dlg.exec();
}
void MainWindow::on_actionIntegration_time_scan_triggered()
{
/*if (!theKeithley->isOpen)
{
qWarning("Keithley not connected! Aborting integration time scan!");
return;
}*/
if (!ui->pushRun->isEnabled())
{
qWarning("Run cannot be started! Aborting integration time scan!");
return;
}
int was_running = running;
stop();
DialogTiScan dlg;
dlg.theHW = theHW;
dlg.theKeithley = theKeithley;
dlg.exec();
//recover previous state
setupHardware();
if (was_running)
run();
}
void MainWindow::on_actionProfile_viewer_triggered()
{
if (!running)
{
qWarning("Run is stopped! Aborting profile viewer run!");
return;
}
DialogProfiler dlg;
dlg.theHW = theHW;
dlg.theKeithley = theKeithley;
dlg.exec();
}
void MainWindow::on_actionBeta_Scanner_triggered()
{
if (!running)
{
qWarning("Run is stopped! Aborting beta scanner run!");
return;
}
if (!theStepper->isOpen)
{
qWarning("Stepper controller not connected! Aborting beta scanner run!");
return;
}
if (theHW->eventBuilder.isLogging())
{
qWarning("Data logging active! No raw data logging for the scan will be possible!");
}
DialogBeta dlg;
dlg.theHW = theHW;
dlg.theStepper = theStepper;
dlg.deviceSettings = deviceSettings;
dlg.exec();
}
//************** Keithley support *******************
//Qt5
/*void MainWindow::on_newCurrentReadout(const double currentReadout)
{
QString text;
text.sprintf("I=%1.8f nA", 1e+9*currentReadout);
statusKeithley.setText(text);
}*/
//Qt6
void MainWindow::on_newCurrentReadout(const double currentReadout)
{
QString text = QString("I=%1 nA").arg(1e+9 * currentReadout, 0, 'f', 8);
statusKeithley.setText(text);
}
void MainWindow::on_actionConnect_Keithley_triggered()
{
if (theKeithley->connect())
{
qInfo(qPrintable(QString("Keithley connected at port %1").arg(theKeithley->portName)));
}
else
{
qInfo("Keithley connection failed!");
}
}
void MainWindow::on_actionDisconnect_Keithley_triggered()
{
theKeithley->disconnect();
qInfo("Keithley disconnected.");
statusKeithley.setText("Keithley disconnected");
}
//***************** Stepper support *********************
void MainWindow::on_actionConnect_Stepper_triggered()
{
theStepper->connect(1);
if (theStepper->isOpen)
{
qInfo(qPrintable(QString("Stepper controller connected at port %1").arg(theStepper->portName)));
}
else
{
qInfo("Stepper connection failed!");
}
}
void MainWindow::on_actionDisconnect_Stepper_triggered()
{
theStepper->disconnect();
qInfo("Stepper controller disconnected.");
}

96
hit2023v2/mainwindow.h Normal file
View File

@ -0,0 +1,96 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSettings>
#include <QList>
#include <QVector>
#include <QTimer>
#include <QLineEdit>
#include "Q_DebugStream.h"
#include "device.h"
#include "hw.h"
#include "displayserver.h"
#include "keithley_thr.h"
#include "stepper.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Q_DebugStream* debugStream;
HW* theHW;
DisplayServer* theDisplay;
keithley_thr* theKeithley;
Stepper* theStepper;
QSettings* deviceSettings;
int running = 0;
int logging = 0;
void run();
void stop();
void startLogging();
void stopLogging();
void startDisplay();
void stopDisplay();
public slots:
void showEvent(QShowEvent *event);
void closeEvent(QCloseEvent *event);
void on_timer();
void on_newCurrentReadout(const double currentReadout);
protected:
void log_separator();
void setupHardware();
void setupDeviceList();
QTimer timer;
QLineEdit status1;
QLineEdit statusKeithley;
private slots:
void on_pushLogSettings_pressed();
void on_actionConnect_triggered();
void on_actionDisconnect_triggered();
void on_actionHost_IP_triggered();
void on_actionTrigger_config_triggered();
void on_actionDevices_triggered();
void on_pushRun_pressed();
void on_pushLogging_pressed();
void on_pushDisplay_pressed();
void on_actionConnect_Keithley_triggered();
void on_actionDisconnect_Keithley_triggered();
void on_actionLinearity_test_triggered();
void on_actionIntegration_time_scan_triggered();
void on_actionProfile_viewer_triggered();
void on_actionConnect_Stepper_triggered();
void on_actionDisconnect_Stepper_triggered();
void on_actionBeta_Scanner_triggered();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

Some files were not shown because too many files have changed in this diff Show More