📜 ⬆️ ⬇️

About the experience of communicating with the signal generator through QTcpSocket and SCPI

Intro


In the third year I came to practice in one of the enterprises of the domestic rocket and space industry. I was an ambitious trainee and quite active until I had seen the routine work at a Russian state-owned enterprise and, at my request, was assigned to a department engaged in the development of test equipment (hereafter referred to as KPA ). By the way, a large part of the development of the CPA is writing a software part for the equipment. Including, for checking the developed hardware, the department has various monitoring and measuring devices , all of them are connected to a common network. As a result, as one of my first assignments was to write an application to control the signal generator.

This article will be discussed.

Start


All applications in the department are developed using C ++ tools and Qt libraries. I had experience with this framework, so there were no difficulties on this side. In addition, Qt has extensive documentation, and you can always copy-paste the code from StackOverflow to consult with the curator.

Since all devices are connected to the same network, the question of how to connect to them is also decided very quickly - we use the network part of Qt in the form of QTcpSocket.
')
The most interesting question arose when I had to decide how to communicate with these devices, how to activate one or another function, or to transfer this or that value. At the same time, it turned out that everything was rather trivial: there is a protocol for standard commands for programmable tools — SCPI. It allows using standard commands to control any devices that support this standard.

Begin to code


Everything in the header file is standard and uninteresting:
#ifndef SIGGENCONTROL_H #define SIGGENCONTROL_H #include <QMainWindow> #include <QTcpSocket> #include <QString> namespace Ui { class sigGenControl; } class sigGenControl : public QMainWindow { Q_OBJECT public: explicit sigGenControl(QWidget *parent = 0); ~sigGenControl(); //      ,      QString host; //= "192.168.1.109"; ip   int port;// = 5025;   void clearErr(); //   bool rfOn; //    bool pset = false; bool hset = false; private: Ui::sigGenControl *ui; QTcpSocket* socket; private slots: //,     .cpp  void connectToHostSlot(); void sendToHostSlot(); void readyReadSlot(); void setFreq(); void setPow(); void activateRF(); void checkErrSlot(); void setPort(); void setHost(); void setDefault(); void dialValChangedSlot(); }; #endif // SIGGENCONTROL_H 


The interface was decided to do this:



It is quite simple and intuitive. In two lines, the host and port of the device are specified at the top. It is also possible to choose standard values, then they will take the following form:

 port = 5025; host = "192.168.1.109"; 

Next comes the text field of the log, the response from the device (errors will also come there, if any). Below are the buttons to connect to the device, send commands, error checking. In the last three linelines, you can either set your own command and send it to the device, or separately set the frequency and amplitude. The radio button on the right turns on / off the RF output. A twist adjusts the frequency when the checkbox is cleared and amplitude when activated.

Continue and end


The most interesting things start in the .cpp file:
 #include "siggencontrol.h" #include "ui_siggencontrol.h" #include "qdebug.h" #include <QTime> sigGenControl::sigGenControl(QWidget *parent) : QMainWindow(parent), ui(new Ui::sigGenControl) { ui->setupUi(this); ui->history->setReadOnly(true); ui->history->setText("host : not set\nport : not set"); ui->history->append(QTime::currentTime().toString() + " : No connection"); socket = new QTcpSocket(this); //     //       -  //    ,       //           connect(ui->connPb,QPushButton::clicked,this,sigGenControl::connectToHostSlot); connect(ui->sendToHostPb,QPushButton::clicked,this,sigGenControl::sendToHostSlot); connect(ui->input,QLineEdit::returnPressed,this,sigGenControl::sendToHostSlot); connect(socket,QTcpSocket::readyRead,this,sigGenControl::readyReadSlot); connect(ui->freqEdit,QLineEdit::returnPressed,this,sigGenControl::setFreq); connect(ui->amptdEdit,QLineEdit::returnPressed,this,sigGenControl::setPow); connect(ui->radioButton,QRadioButton::clicked,this,sigGenControl::activateRF); connect(ui->errPb,QPushButton::clicked,this,sigGenControl::clearErr); connect(ui->hostEdit,QLineEdit::returnPressed,this,sigGenControl::setHost); connect(ui->portEdit,QLineEdit::returnPressed,this,sigGenControl::setPort); connect(ui->checkBox,QCheckBox::clicked,this,sigGenControl::setDefault); connect(ui->dial, QDial::valueChanged,this,sigGenControl::dialValChangedSlot); ui->hist->setReadOnly(true); QString deactRF = ":OUTP 0\n"; //  SCPI ,        socket->write(deactRF.toLocal8Bit()); //      this->rfOn = false; //   ui->input->setReadOnly(true); ui->freqEdit->setReadOnly(true); ui->amptdEdit->setReadOnly(true); ui->radioButton->setEnabled(false); ui->sendToHostPb->setEnabled(false); ui->errPb->setEnabled(false); ui->connPb->setDisabled(true); } sigGenControl::~sigGenControl() { delete ui; } void sigGenControl::connectToHostSlot(){ socket->connectToHost(host,port); //   //     qDebug()    if (socket->waitForConnected(1000)) qDebug("Connected!"); ui->history->append(QTime::currentTime().toString() + " : Connected"); //   ui->input->setReadOnly(false); ui->freqEdit->setReadOnly(false); ui->amptdEdit->setReadOnly(false); ui->radioButton->setEnabled(true); ui->sendToHostPb->setEnabled(true); ui->errPb->setEnabled(true); ui->input->setText("*IDN?"); //    } void sigGenControl::sendToHostSlot(){ //     socket->write(ui->input->text().toLocal8Bit()+"\n"); } void sigGenControl::readyReadSlot(){ //     qDebug("ready read!"); QByteArray dataArr; //    dataArr = socket->readAll(); //   ui->hist->append(QTime::currentTime().toString() + " " + dataArr); } void sigGenControl::clearErr(){ // ,   ,  ,   QString errTxt = ":SYST:ERR?\n"; socket->write(errTxt.toLocal8Bit()); } void sigGenControl::setFreq(){ QString fr = " kHz"; QString cmd = ":FREQ "; //    QString command = cmd+ui->freqEdit->text()+fr+"\n"; //  qDebug() << command; socket->write(command.toLocal8Bit()); //   } void sigGenControl::setPow(){ QString amp = " dBm"; QString cmd = ":POW "; //    socket->write(cmd.toLocal8Bit() + ui->amptdEdit->text().toLocal8Bit() + amp.toLocal8Bit() + "\n"); //  } void sigGenControl::activateRF(){ //       //   QString actRF = ":OUTP 1\n"; //   QString deactRF = ":OUTP 0\n"; //   if(this->rfOn == false){ socket->write(actRF.toLocal8Bit()); rfOn = true; }else{ socket->write(deactRF.toLocal8Bit()); rfOn = false; } } void sigGenControl::checkErrSlot(){ clearErr(); } void sigGenControl::setHost(){ //   this->host = ui->hostEdit->text(); ui->history->append("host: " + host); ui->checkBox->setEnabled(true); hset = true; //  if((pset && hset) == true){ ui->connPb->setEnabled(true); } } void sigGenControl::setPort(){ //   this->port = ui->portEdit->text().toInt(); ui->history->append("port: " + QString::number(port)); ui->checkBox->setEnabled(true); pset = true; //  if((pset && hset) == true){ ui->connPb->setEnabled(true); } } void sigGenControl::setDefault(){ //     port = 5025; host = "192.168.1.109"; ui->history->append(QTime::currentTime().toString() + " " + "host: " + host); ui->history->append(QTime::currentTime().toString() + " " + "port: " + QString::number(port)); ui->checkBox->setDisabled(true); ui->connPb->setEnabled(true); ui->hostEdit->setText(host); ui->portEdit->setText(QString::number(port)); } void sigGenControl::dialValChangedSlot(){ //   ,       qDebug()<< "value : " << ui->dial->value(); if(ui->amplCheckBox->isChecked() == false){ //  ,      ui->dial->setMinimum(100); ui->dial->setMaximum(20000000); QString fr = " kHz"; QString cmd = ":FREQ "; //    QString command = cmd+QString::number(ui->dial->value())+fr+"\n"; qDebug() << command; socket->write(command.toLocal8Bit()); ui->label->setText("FREQUENCY :" + QString::number(ui->dial->value()) + " kHz" ); }else if(ui->amplCheckBox->isChecked() == true){ //  ,       ui->dial->setMinimum(-130); ui->dial->setMaximum(15); QString pw = " dBm"; QString cmd = ":POW "; //    QString command = cmd+QString::number(ui->dial->value())+pw+"\n"; qDebug() << command; socket->write(command.toLocal8Bit()); ui->label->setText("AMPLITUDE :" + QString::number(ui->dial->value()) + " dBm" ); } } 


After reading


I understand that the article may seem divorced from life and reality for a large number of readers, but remote control of instrumentation in the field of engineering is a fairly common topic that brings many benefits and convenience (for example, you do not need to run to the instruments and press buttons) .

The rest of this article is informational and entertaining in nature and is aimed more at enthusiasts and at people involved in the development and testing of boards and other hardware. The rest would just like to talk about their little software development experience for such specific purposes.

Source: https://habr.com/ru/post/435448/


All Articles