I create a "server" lib with a Qt GUI.
I don't and can't use QThreads because this is supposed to be as independent from Qt as possible, and because I have other threads already working like a Ethernet part.
The thread ExternalRs232Thread() is lauched by the public function RunExternalRs232()
RunExternalRs232() opens the serial port, returns -1 if can't open serial, and if is ok runs the function ExternalRs232Thread() in a detached thread.
Initially, I have tried to run this with Serialib, but this never works properly with the Qt project. So I decided to give QSerialPort a try like this:
Server.h
#ifndef SERVER_H
#define SERVER_H
#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <time.h>
#include <chrono>
#include <mutex>
#include <QObject>
#include "libs/json.hpp"
#include <QtSerialPort>
#include "hdlccsvparser.h"
using namespace std;
using json = nlohmann::json;
using std::chrono::milliseconds;
using std::chrono::duration_cast;
using std::chrono::seconds;
using std::chrono::system_clock;
struct Contact {
int port; //udp port of te contact
time_t time; //last communication date ( is still active ? )
};
class Server : public QObject
{
Q_OBJECT
public:
Server();
virtual ~Server();
[...]
//return 0 if sucess , 1 port is not usabe, 2 port already in use
int RunExternalRs232(string PortCom, unsigned int baudrate);
int StopExternalRs232(string PortCom);
[...]
//clean exit
void ExitServer();
signals:
[...]
private:
[...]
// External ThreadS and exiting loop of threadS in set (if key d'ont exist anymore, exit loop)
mutex mtxExternalRs232;
unordered_set<string> ExternalRs232PortActiveList;
void ExternalRs232Thread(QSerialPort* Rs232Connection, string port);
[...]
};
#endif // SERVER_H
Server.cpp
#include "Server/Server.h"
#include <winsock2.h>
/* Public Part*/
[...]
int Server::RunExternalRs232(string PortCom, unsigned int baudrate){
//PortCom = (char *)"COM1";
//baudrate = 9600;
QSerialPort Rs232Connection;
// Connection to serial port
// COMxx
Rs232Connection.setPortName(QString::fromStdString(PortCom));
Rs232Connection.setBaudRate(baudrate);
Rs232Connection.setDataBits(QSerialPort::Data8);
Rs232Connection.setParity(QSerialPort::NoParity);
Rs232Connection.setStopBits(QSerialPort::OneStop);
Rs232Connection.setFlowControl(QSerialPort::NoFlowControl);
int i = Rs232Connection.open(QIODevice::ReadWrite);
// If connection fails, errorOpening != 1
if(i != 1){
return i;
}
mtxExternalRs232.lock();
ExternalRs232PortActiveList.insert(PortCom);
mtxExternalRs232.unlock();
cout << "External Rs232 starting on " << PortCom << endl;
stringstream sstmp;
sstmp << PortCom;
emit LogMessage(QString::fromStdString("External Rs232 starting on " + sstmp.str()),0);
std::thread thServer(&Server::ExternalRs232Thread,this,&Rs232Connection,PortCom);
thServer.detach();
return 0;
}
int Server::StopExternalRs232(string PortCom){
PortCom = "COM1";
mtxExternalRs232.lock();
/*
if(ExternalRs232PortActiveList.count(PortCom) != 1){ //???
//port not in use
cerr << "close Failed Rs232 " << PortCom << endl;
mtxExternalRs232.unlock();
return 1;
}*/
cout << "close External Rs232 " << PortCom << endl;
ExternalRs232PortActiveList.erase(PortCom);
mtxExternalRs232.unlock();
return 0;
mtxExternalRs232.lock();
cout << ExternalRs232PortActiveList.count(PortCom) << " here " << endl;
mtxExternalRs232.unlock();
}
[...]
/* Private Part */
/* Thread part */
[...]
void Server::ExternalRs232Thread(QSerialPort * Rs232Connection, string port){
//char/binary read on rs232
char tmp;
//if rs232 has data
bool res = false;
stringstream message;
Rs232Connection->write("H");
mtxExternalRs232.lock();
int iscount = ExternalRs232PortActiveList.count(port);
mtxExternalRs232.unlock();
while(iscount == 1){
res = false;
if(!Rs232Connection->waitForReadyRead(300)){
//no data skipp
} else {
QByteArray datas = Rs232Connection->readAll();
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
string tmp = codec->toUnicode(datas).toStdString();
cout << tmp << endl;
}
mtxExternalRs232.lock();
iscount = ExternalRs232PortActiveList.count(port);
mtxExternalRs232.unlock();
}
Rs232Connection->flush();
Rs232Connection->close();
}
[...]
/* functions part */
[...]
Server::Server(){
//init winsock
if(WSAStartup(MAKEWORD(2,2),&wsa) != 0){
cerr << "Could not init winsock2 : " << WSAGetLastError();
}
//creating a socket
if((s = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET){
cerr << "Could not create a socket : " << WSAGetLastError();
}
}
Server::~Server(){
//dtor
}
at the end, I get
QObject::startTimer: Timers can only be used with threads started with QThreads
So how is possible to run Serial Rs232 without using QThreads?
Code:
using ColumnIndexVector = std::vector<int>;
using ByteVector = std::vector<BYTE>;
void CCreateReportDlg::GetColumnIndexesToExclude()
{
const CString strSection = theApp.GetActiveScheduleSection(_T("Options"));
ByteVector vData = theApp.GetProfileVector(strSection, _T("AssignStatesEx"));
ColumnIndexVector vTemp(vData.begin(), vData.end()); // This converts BYTE to int
m_vColumnIndexesToExclude = vTemp;
}
Is there any way to avoid the requirement for vTemp without manually iterating vData and casting from BYTE to int?
Yes, just use assign(). IDK if you need to use clear() as well, but probably not. Just step through the runtime code the first time to know.
m_vColumnIndexesToExclude.assign(vData.begin(), vData.end());
Here's a test program:
#include <windows.h>
#include <iostream>
#include <vector>
using namespace std;
using ColumnIndexVector = std::vector<int>;
using ByteVector = std::vector<BYTE>;
int main(int argc, char* argv[])
{
cout << "Test" << endl;
ByteVector bytes = {'A', 'B', 'C', 'D'};
ColumnIndexVector colVector;
for ( auto _val: bytes)
{
cout << _val << endl;
}
colVector.assign(bytes.begin(), bytes.end());
for ( auto _val : colVector)
{
cout << _val << endl;
}
return 0;
}
Can you please help me find the error in printing the reverse of sequence using stacks implemented by vector?
I am getting a Segmenattion fault
#include <iostream>
#include<vector>
using namespace std;
class stack{
public :
int top;
vector<int> data;
bool isempty(){return top == -1;}
void push(int x){data[++top] = x;}
void pop(){--top;}
int topper(){return data[top];}
};
int main()
{
stack s;
int n;
s.top = -1;
cout << "enter the number of integers" << endl;
cin >> n;
for(int i =0; i < n; i ++){
s.push(i);
}
while(!s.isempty()){
cout << s.topper();
s.pop();
}
return 0;
}
This problem occurs, because a vector has size = 0 by default.
You can either resize the vector, before you add values into it like so:
#include <iostream>
#include<vector>
using namespace std;
class stack {
public:
int top;
vector<int> data;
bool isempty() { return top == -1; }
void push(int x) { data.resize(++top+1); data[top] = x; }
void pop() { --top; }
int topper() { return data[top]; }
};
int main()
{
stack s;
int n;
s.top = -1;
cout << "enter the number of integers" << endl;
cin >> n;
for (int i = 0; i < n; i++) {
s.push(i);
}
while (!s.isempty()) {
cout << s.topper();
s.pop();
}
return 0;
}
Or you can use the built-in functionality for vectors like that, which I think is the far better solution:
#include <iostream>
#include<vector>
using namespace std;
class stack {
public:
vector<int> data;
bool isempty() { return data.size() == 0; }
void push(int x) { data.push_back(x); }
void pop() { data.pop_back(); }
int topper() { return data.back(); }
};
int main()
{
stack s = stack();
int n;
cout << "enter the number of integers" << endl;
cin >> n;
for (int i = 0; i < n; i++) {
s.push(i);
}
while (!s.isempty()) {
cout << s.topper();
s.pop();
}
return 0;
}
I need to assign a pointer to a custom class in qml using QQmlContext::setContextProperty(). Another qml object has Q_PROPERTY of the same type to retrieve it again.
A simple test showed me that the conversion does not work like i thought.
#include <QCoreApplication>
#include <QDebug>
#include <QMetaType>
class TestClass
{
public: TestClass() { qDebug() << "TestClass()::TestClass()"; }
};
Q_DECLARE_METATYPE(TestClass*)
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "metaTypeId =" << qMetaTypeId<TestClass*>();
auto testObject = new TestClass;
QVariant variant(qMetaTypeId<TestClass*>(), testObject);
auto test = variant.value<TestClass*>();
qDebug() << testObject << variant << test;
return 0;
}
This tiny test application gives me an output like this:
metaTypeId = 1024
TestClass::TestClass()
0x1b801e0 QVariant(TestClass*, ) 0x0
I would really like to get the same pointer out again after converting it down to a QVariant. Later I will assign it to a qml context and then the conversation must work correctly.
This works for me using Qt 5.9:
#include <QVariant>
#include <QDebug>
class CustomClass
{
public:
CustomClass()
{
}
};
Q_DECLARE_METATYPE(CustomClass*)
class OtherClass
{
public:
OtherClass()
{
}
};
Q_DECLARE_METATYPE(OtherClass*)
int main()
{
CustomClass *c = new CustomClass;
OtherClass *o = new OtherClass;
QVariant v;
v.setValue(c);
QVariant v2;
v2.setValue(o);
qDebug() << v.userType() << qMetaTypeId<CustomClass*>() << v2.userType() << qMetaTypeId<OtherClass*>();
qDebug() << v.value<CustomClass*>() << c << v2.value<OtherClass*>() << o;
return 0;
}
And the output i got:
1024 1024 1025 1025
0x81fca50 0x81fca50 0x81fca60 0x81fca60
As #thuga mentioned in the comments, you need to use void* and static_cast along with QVariant::fromValue.
#include <QCoreApplication>
#include <QDebug>
#include <QMetaType>
class TestClass
{
public: TestClass() { qDebug() << "TestClass()::TestClass()"; }
};
Q_DECLARE_METATYPE(TestClass*)
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "metaTypeId =" << qMetaTypeId<TestClass*>();
auto testObject = new TestClass;
QVariant variant(QVariant::fromValue(static_cast<void*>(testObject)));
auto test = static_cast<TestClass*>(variant.value<void*>());
qDebug() << testObject << variant << test;
return 0;
}
I am trying to port my program from Windows to Linux. The windows program uses Window CryptoAPI and linux is using libmcrypt.
Here is the Windows code:
#include <windows.h>
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <exception>
using namespace std;
class CryptError:public exception{
public:
CryptError(){}
};
#define CHECK_RET(x) if(x == FALSE) {retval = GetLastError(); throw CryptError();};
LONG Decrypt(const string &key, std::vector<BYTE> &data){
LONG retval = 0;
try{
HCRYPTPROV hCrypt;
HCRYPTHASH hHash;
HCRYPTKEY hKey;
CHECK_RET(CryptAcquireContext(&hCrypt, NULL, NULL, PROV_RSA_FULL, 0));
CHECK_RET(CryptCreateHash(hCrypt, CALG_MD5, 0, 0, &hHash));
CHECK_RET(CryptHashData(hHash, reinterpret_cast<const BYTE *>(key.c_str()), key.size(), 0));
CHECK_RET(CryptDeriveKey(hCrypt, CALG_RC2, hHash, MAKELPARAM(CRYPT_EXPORTABLE, 80), &hKey));
BYTE tempVal[200];
DWORD len = 200;
CryptGetKeyParam(hKey, KP_EFFECTIVE_KEYLEN, tempVal, &len, 0);
len = 200;
CryptGetKeyParam(hKey, KP_MODE, tempVal, &len, 0);
len = 200;
CryptExportKey(hKey, NULL, PLAINTEXTKEYBLOB, 0, tempVal, &len);
len = 200;
CryptGetKeyParam(hKey, KP_IV, tempVal, &len, 0);
DWORD count = data.size();
CHECK_RET(CryptDecrypt(hKey, 0, TRUE, 0, &(data[0]), &count));
data.resize(count);
}catch(CryptError &e){
}
return retval;
}
int main(void){
BYTE data[9] = {0xdc,0x3d,0x96,0x23,0x29,0xdd,0x1b,0x2f, 0};
vector<BYTE> vData(data, data + 8);
Decrypt("PNEMAIL", vData);
cerr << "vData: ";
int len = vData.size();
for(int i = 0; i < len; i++){
if(i > 0)
cerr << ',';
cerr << hex << setw(2) << setfill('0') << (int)(vData[i]);
}
cerr << endl;
return 0;
}
When the program is run, it returns:
vData: 42,46,30,41,43,34,31
The Q&D linux version looks like this:
#include <mcrypt.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <openssl/md5.h>
#include <stdint.h>
#include <stdexcept>
#include <vector>
#include <valarray>
#include <memory.h>
using namespace std;
class MCrypt{
private:
MCRYPT mcrypt;
public:
MCrypt(char *algorithm, char* algorithm_directory, char *mode, char* mode_directory){
mcrypt = mcrypt_module_open(algorithm, algorithm_directory, mode, mode_directory);
if(mcrypt == MCRYPT_FAILED)
throw runtime_error("MCrypt init failed");
}
int init(void *key, int lenofkey, void *IV){
return mcrypt_generic_init(mcrypt, key, lenofkey, IV);
}
int enc_get_iv_size(){
return mcrypt_enc_get_iv_size(mcrypt);
}
int deinit(){
return mcrypt_generic_deinit(mcrypt);
}
int decrypt(void *data, int len){
mdecrypt_generic(mcrypt, data, len);
}
~MCrypt(){
deinit();
mcrypt_module_close(mcrypt);
}
};
#ifdef DEBUG
void inline printArrayFunc(const char *start, const uint8_t *data, int len){
// DEBUG: print value of $key1
cerr << start;
for(int i = 0; i < len; i++){
if(i > 0)
cerr << ',';
cerr << hex << setw(2) << setfill('0') << (int)(data[i]);
}
cerr << endl;
}
#define printArray(start, data, len) printArrayFunc(start, data, len)
#else
#define printArray(start, data, len)
#endif
int main(void){
uint8_t data[8] = {0xdc,0x3d,0x96,0x23,0x29,0xdd,0x1b,0x2f};
const char *sKey1 = "PNEMAIL";
const int key1Len = 7;
uint8_t *dataPtr = &(data[0]);
uint8_t key1[17];
key1[16] = 0;
// Hash sKey1
MD5(reinterpret_cast<const unsigned char *>(sKey1), key1Len, key1);
MCrypt mcrypt(MCRYPT_RC2, NULL, MCRYPT_CBC, NULL);
vector<uint8_t> iv(mcrypt.enc_get_iv_size(), 0);
// Use the first 80-bits of key1
mcrypt.init(key1, 10, &(iv[0]));
mcrypt.decrypt(dataPtr, 8);
printArray("vData: ", dataPtr, 8);
return 0;
}
When the program is run, it returns:
vData: 4d,3d,82,71,88,d2,d5,4b
I've check that both programs are using the same data.
CryptDeriveKey creates a key 07,f1,e2,ea,d4,c8,79,74,03,a6 (according to CryptExportKey), the same as the first 10 bytes of the md5 generated in Linux (which I shorten to match the requested 80-bit key).
Neither are using a salt on the algorithm (or at least are not reporting as such)
They are both using an 8-byte IV of {0,0,0,0,0,0,0,0}
They are both using the RC2 algorithm
They are both using CBC mode
I cannot figure out why they are returning different data. Any assistance would be greatly appreciated.