Chromophant/shimlccontroller.h
2025-09-24 20:28:18 +02:00

325 lines
8.4 KiB
C++

#ifndef SHIMLCCONTROLLER_H
#define SHIMLCCONTROLLER_H
#include <QtCore/QObject>
#include <QtNetwork>
#include <QDebug>
#include <QtLogging>
#include <QtEndian>
#include <QTextCodec>
#include <QObject>
#include <QList>
#include <tuple>
#include <cmath>
#include <QAbstractSocket>
#include <QMessageBox>
#include <QtEndian>
#define INBOUND(val, upper, lower) val >= lower && val <= upper
struct ShimLCCmdStackResult
{
ShimLCCmdStackResult(uint32_t id, QByteArray data)
: id(id), data(data) {}
uint32_t id;
QByteArray data;
};
enum ParserMode
{
ParseQuery, ParseCbmir, ParseCbmiw
};
// ---
class ShimTCPController : public QObject
{
Q_OBJECT
public:
int irPendingSize = -1;
void cbmquery(QString message);
void cbmir(quint8 filehandle, QByteArray* irDataRet = nullptr);
void cbmiw(quint8 filehandle, QByteArray* irDataToSend = nullptr);
explicit ShimTCPController(QObject *parent = 0);
~ShimTCPController();
private slots:
bool writeData(QByteArray *data);
void readData();
void displayError(QAbstractSocket::SocketError socketError);
void parseCbmquery(QByteArray data);
void parseCbmIr();
void parseCbmIw();
void dataAvailableErrorNoF(QByteArray data);
void emitConnectionStateChanged();
public slots:
void connectToHost(QString host, int port);
signals:
void irDone();
void dataAvailable(QByteArray data);
void connectionStateChanged(QAbstractSocket::SocketState state);
private:
QString TAG = "ShimTCPController";
QTcpSocket *socket;
QByteArray next_pkg{};
int irFileHandle = -1;
QByteArray* irData = nullptr;
QByteArray* pendingData = nullptr;
ParserMode mode = ParseQuery;
};
// ---
class ShimLCCommandStack : public QObject
{
Q_OBJECT
private slots:
void exitedIr();
void newResult(QByteArray data);
signals:
void dataAvailable(uint32_t id);
void connectionStateChanged(QAbstractSocket::SocketState state);
public:
explicit ShimLCCommandStack(QObject *parent = 0);
~ShimLCCommandStack();
uint32_t setVal(QString cmd, QByteArray *dest);
uint32_t getSetVal(QString cmd, QByteArray *dest);
uint32_t getActVal(QString cmd, QByteArray *dest);
uint32_t readFile(QString filename, QByteArray *dest, uint size);
uint32_t writeFile(QString filename, QByteArray *data);
void reconnect(QSettings *settings);
private:
QString TAG = "ShimLCCommandStack";
using Connection = std::tuple<QObject*, const char*>;
struct ShimLCCmd
{
ShimLCCmd(uint32_t id, char opcode, QString cmd, QByteArray* dest, uint32_t iSize)
: id(id), opcode(opcode), cmd(cmd), dest(dest), iSize(iSize) {}
uint32_t id;
char opcode;
QString cmd;
QByteArray* dest;
uint32_t iSize; // Only needed for I commands
};
ShimTCPController connection{};
QVector<ShimLCCmd> stackIn{};
uint32_t id = 0;
uint32_t busy_id = 0;
void next();
uint32_t addCmd(char opcode, QString cmd, QByteArray* dest, uint iSize = 0);
QObject* parent;
};
// ---
struct LCPort
{
LCPort(uint8_t port, uint8_t id, QString name, QString version, QString serial)
: port(port), id(id), name(name), version(version), serial(serial) {}
uint8_t port;
uint8_t id;
QString name;
QString version;
QString serial;
};
/* Param [Unit] | Range | Step | Default ... Desc
* X.Flow [ml/min] | 0 - 9.999 | 0.001 | 0 ... Pump X flow rate (0: A, 1: B, 2: C)
* X.Pres [bar(1)*] | 0, 10 - 392 | 1 | 0 ... Pump X Pressure
* (1)* > Can be changed to kgf/cm³, psi, MPa, bar
* See Page 170 of Maual for more Details! */
struct LCPump
{
LCPump()
: actPressure(0), setFlow(0) {}
void pPressure(uint32_t press_int)
{actPressure = 10.962565204644875*exp(82.61694351137422 * (((float)press_int - 1093764743)/1e9));}
float actPressure;
float setFlow;
};
/* Combined status struct
* SIL Status, Status 1 and Status 2 Params
* The label lists contain the label for the corrosponding bit (1, 2, 4, 8 ...)
* Empty String means unknown
*/
struct Stats
{
uint32_t silst;
uint32_t status1;
uint32_t status2;
const QStringList silst_labels = {"INSTALED", "INJECT", "TRANSMIT", "RINSE", "?16", "ERROR", "STOP"};
const QStringList status1_labels = {"READY", "CTONOTREADY", "RUN", "PAUSE", "?16", "HOLD", "ERROR", "?128", "ACTIVATE", "?512", "?1024", "PURGE", "?4096", "?8192", "WAITCTO", "SLEEP", "WARNING", "?131072", "PUMPAON", "PUMPBON", "PUMPCON", "PUMPDON", "?4194304", "?8388608", "?16777216", "?33554432", "CTOAON", "CTOBON", "CTOCON", "CTODON"};
const QStringList status2_labels = {"PPURGING_A", "PPURGING_B", "PPURGING_C", "PPURGING_D", "?16", "PUMPON", "OVENON", "?128", "?256", "?512", "?1024", "?2048", "?4096", "?8192", "?16384", "?32768", "?65536", "?131072", "?262144", "INJECT_READY", "?1048576", "?2097152", "?4194304", "?8388608", "?16777216", "?33554432", "?67108864", "IPURGING_R0", "IPURGING_R1", "IPURGING_R2", "IPURGING_RNS", "IPURGING_INJ"};
};
/* Param [Unit] | Range | Step | Default ... Desc
* WAVE [nm] | 190 - 600 | 1 | 254 ... Wavelength 1 (D2)
* WAVE2 [nm] | 190 - 600 | 1 | 254 ... Wavelength 2 (D2)
* LAMP [1] | 0,1 | 1 | 254 ... Lamp (0: Off, 1: On) (D2)
* See Page 177 of Manual for more TODOs */
struct LCDetector
{
float waveLen1 = 0;
float waveLen2 = 0;
float lamp = 0;
};
struct LCAutosampler
{
float rack = 0;
};
struct LCStatus
{
LCStatus(){}
uint32_t time = 0;
uint16_t buf_wait[7]{};
LCPump pump[3]{};
LCDetector detector[2]{};
LCAutosampler autosampler{};
float totalFlow = 0; // Total flow rate in gradient pumping
uint num_pumps = 0; // Set by
uint num_detectors = 0;
Stats stats;
};
// Config struct - TODO: Catigorize compleatly!
struct LCconfiguration
{
QList<LCPort> pumps{};
QList<LCPort> detectors{};
QList<LCPort> other{};
void clear() {
pumps.clear();
detectors.clear();
other.clear();
}
// Options
quint8 AD1 = 0;
quint8 AD2 = 0;
// TODO: Implement the rest of the options
};
struct BufSt
{
quint8 curFlag = 0;
double curValue = 0.0;
quint16 period = 0;
float convFact = 0;
float gainFact = 0;
quint8 databuf[4]{};
QList<double> vals{};
};
class CmdVal : public QObject
{
Q_OBJECT
public:
CmdVal(QString cmd, ShimLCCommandStack* cmdStack)
: cmd(cmd), cmdStack(cmdStack) {}
QByteArray set_value{};
QByteArray act_value{};
public slots:
void update()
{
updateSet();
updateAct();
}
void updateSet()
{
waitingForSet = 1;
idSet = cmdStack->getSetVal(cmd, &set_value);
connect(cmdStack, &ShimLCCommandStack::dataAvailable, this, &CmdVal::newData);
}
void updateAct()
{
waitingForAct = 1;
idAct = cmdStack->getActVal(cmd, &act_value);
connect(cmdStack, &ShimLCCommandStack::dataAvailable, this, &CmdVal::newData);
}
private slots:
void newData(uint32_t id)
{
if(id == idSet)
waitingForSet = 0;
if(id == idAct)
waitingForAct = 0;
if(!(waitingForAct | waitingForSet))
disconnect(cmdStack, &ShimLCCommandStack::dataAvailable, this, &CmdVal::newData);
}
signals:
void updated();
private:
QString cmd;
ShimLCCommandStack* cmdStack;
uint32_t idSet;
uint32_t idAct;
bool waitingForSet = 0;
bool waitingForAct = 0;
};
// ---
#define ID_CONF 0
#define ID_STATUS 1
#define ID_ENV 2
#define ID_CHK 3
#define ID_PIF 4
#define ID_BUF 4
class ShimLCController : public QObject
{
Q_OBJECT
public:
void updateConfig();
void updateStatus();
void updateEnv();
void updateChk();
void updatePif();
void updateBuf();
void reconnect(QSettings *settings);
LCconfiguration configuration{};
LCStatus lastStatus{};
BufSt bufst[6]{};
explicit ShimLCController(QObject *parent = nullptr);
~ShimLCController();
signals:
void newConfigAv();
void newStatusAv();
void connectionStateChanged(QAbstractSocket::SocketState state);
void newDataAv();
private:
void parseLcnf(uint32_t idVal);
void parseStatus(uint32_t idVal);
void parseEnv(uint32_t idVal);
void parseChk(uint32_t idVal);
void parsePif(uint32_t idVal);
void parseLbuf(uint32_t idVal);
uint32_t ids[6]; // 0 - config / 1 - status / 2 - env / 3 - chk / 4 - PIF / 5 - BUF
ShimLCCommandStack cmd{};
QByteArray data{};
int cur_buf = 0;
};
#endif // SHIMLCCONTROLLER_H