Permission error on opening USB dongle using QSerialPort - c++

I'm trying to access a USB dongle (which has SIM card in it) using QSerialPort.
The dongle is successful identified but when trying to open it I get permission error. The description of the error message from Qt documentation states that this could be that the device is being accessed by another service or the user has no permission. I attempted to disconnect the dongle and connect it again with the same results. How can I solve this. I'm on Ubuntu 16.04 64bit using Qt 5.7. The code I'm running is as below.
#include <QApplication>
#include <QString>
#include <QDebug>
#include <QList>
#include <QSerialPortInfo>
#include <QSerialPort>
#include <QDebug>
int main(int argc, char *argv[])
{
QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
QSerialPort *port = nullptr;
QString portName;
int counter = 0;
while(counter < ports.size())
{
portName = ports[counter].portName();
quint16 productId = ports[counter].productIdentifier();
quint16 vendorId = ports[counter].vendorIdentifier();
QString manufacturerName = ports[counter].manufacturer();
qDebug() << "Port Name: " << portName;
qDebug() << "Product ID:" << productId;
qDebug() << "Vendor Id: " << vendorId;
qDebug() << "Manufacturer: " << manufacturerName;
++counter;
if(manufacturerName.contains("Huawei", Qt::CaseInsensitive))
{
qDebug() << "found!" << " name: " << portName;
port = new QSerialPort(portName);
break;
}
}
//Write and send the SMS
bool opened = port->open(QIODevice::ReadWrite);
if(!opened)
{
qDebug() << "Error: " << port->error();
}
// some more code here
return 0;
}
The output is as below:
Port Name: "ttyS4"
Product ID: 11799
Vendor Id: 32902
Manufacturer: ""
Port Name: "ttyUSB0"
Product ID: 5382
Vendor Id: 4817
Manufacturer: "HUAWEI"
found! name: "ttyUSB0"
Error: QSerialPort::SerialPortError(PermissionError)

Serial devices are usually located in the /dev/ folder and is owned by root. It is likely that you need root access to open the device.
For example, with your dongle plugged in, you could get the permissions on the device with the following command:
ls -l /dev/ttyUSB0
Does it work if you run the program with 'sudo' or as root?
In a terminal, try running your program prefixed with the 'sudo' command. This will elevate your privileges to the root level:
sudo ./my_program

Open (as root) /etc/udev/rules.d/90-my-usb-dongle.rules and write:
SUBSYSTEM=="usb", ATTR{idVendor}=="12d1", ATTR{idProduct}=="1506", MODE="0666"
This tells linux to set R/W permissions for all to your device (note that idVendor and idProduct are hexadecimal).
Now reload udev rules:
# udevadm control --reload-rules
and check again

Related

How to handle QTModbusTcpClient request in QTModbusTcpServer

I'm trying to create Modbus TCP server with QT libraries.
I have problem, because I can't find a way, to create correct response for request from Modbus Client.
As I understand it, after starting the application, the server listens for incoming messages all the time, but I can't find in documentation correct function to handle message (and how I will get information about new request, it is a signal?)
I checked in the sample application QT ModbusServer, but did not find a solution.
There is my code:
#include <QCoreApplication>
#include <QModbusTcpServer>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QModbusTcpServer* modbusDevice;
modbusDevice = new QModbusTcpServer();
modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "127.0.0.1");
modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, 502);
QModbusDataUnitMap reg;
reg.insert(QModbusDataUnit::Coils, { QModbusDataUnit::Coils, 0, 10 });
reg.insert(QModbusDataUnit::DiscreteInputs, { QModbusDataUnit::DiscreteInputs, 0, 10 });
reg.insert(QModbusDataUnit::InputRegisters, { QModbusDataUnit::InputRegisters, 0, 10 });
reg.insert(QModbusDataUnit::HoldingRegisters, { QModbusDataUnit::HoldingRegisters, 0, 10 });
modbusDevice->setMap(reg);
if(!modbusDevice->setMap(reg))
{
qDebug() << "setMap error";
}
modbusDevice->connectDevice();
return a.exec();
}
My goal is to read message from client with new register value and change that value in my application.
As a client, I am using the Modbus TCP sample application from QT.
You must set the server address with modbusDevice->setServerAddress(1) before calling connectDevice()
The parameter is the server instance. You can have at most 255 instances per IP address
modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "127.0.0.1");
modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, 502);
modbusDevice->setServerAddress(1);
Then you must connect to QModbusServer::dataWritten, which is emitted by the server when the client modifies an object in the tables.
Something like
QObject::connect(modbusDevice, &QModbusServer::dataWritten,
[&] (QModbusDataUnit::RegisterType table, int address, int size)
{
qDebug() << "onDataWritten: table: " << table
<< " | " << "address: " << address
<< " | " << "size: " << size
<< endl;
}
);

QNetworkConfigurationManager::allConfigurations() doesn't list WLAN

Running under Windows 10, tested with two different Systems:
When i run QNetworkConfigurationManager::allConfigurations() I don't get any WLAN configuration, even if I'm connected actively to a Wifi Network.
Header:
public:
NetworkManager(QObject* parent = 0);
private slots:
void onNetworkConfigUpdate();
private:
QNetworkConfiguration cfg;
QList<QNetworkConfiguration> netcfgList;
QNetworkConfigurationManager ncm;
.cpp
NetworkManager::NetworkManager(QObject* parent) : QObject(parent) {
ncm.updateConfigurations();
connect(&ncm, SIGNAL(updateCompleted()), this, SLOT(onNetworkConfigUpdate()));
}
void NetworkManager::onNetworkConfigUpdate() {
netcfgList = ncm.allConfigurations();
for (auto& x : netcfgList) {
if (x.bearerType() == QNetworkConfiguration::BearerWLAN) {
qDebug() << "Wifi found: " << x.name();
} else {
qDebug() << "Something else: " << x.bearerType() << " - name: " << x.name();
}
}
}
Output:
Something else: 0 - name: "Teredo Tunneling Pseudo-Interface"
Something else: 1 - name: "Ethernet"
Something else: 1 - name: "VirtualBox Host-Only Network"
I'm running on Windows 10; Qt 5.9.4 with MSVC2015
I checked with an Intel Wireless Card and an external USB Wifi-Stick. Why is it not showing any WLAN?
I had the same problem. To me was caused by a missing bearer plugin DLL.
To sort this out, I had to copy the QT "plugins/bearer" folder (containing qgenericbearer.dll and qnativewifibearer.dll) in my application root folder.
Like this:
ApplicationFolder/
Application.exe
...
Qt5Network.dll
bearer/
qgenericbearer.dll
qnativewifibearer.dll

Connecting to MS SQLServer from Qt Linux application

I'm trying to connect to a MS SQL Server on a remote box using QODBC in my Qt Linux application.
Here's what I have done so far:
Added QT += SQL in the .pro file.
Tested some db functions:
QStringList drivers = QSqlDatabase::drivers();
qDebug() << "Drivers: " ;
foreach(QString driver, drivers) {
qDebug() << ":: " << driver;
}
qDebug() << "Connection Names: ";
QStringList connames = QSqlDatabase::connectionNames();
foreach(QString conname, connames) {
qDebug() << ":: " << conname;
}
qDebug() << "---";
these both work, though connectionNames() is empty at this stage.
I have tried to added a database:
QString serverName = "server1";
QString dbName = "abc123";
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", "MyFirst");
db.setHostName(serverName);
QString myCon = QString("DRIVER={SQL Native Client};SERVER=%1;DATABASE=%2;Trusted_Connection = Yes").arg(serverName).arg(dbName);
db.setDatabaseName(myCon);
If I now list the connections, "MyFirst" is in the list.
Tried to open the database:
bool ok = db.open();
qDebug() << "OK: " << ok;
if (!ok) {
qDebug() << "error: " << db.lastError().text();
}
The db.open() fails with the following message:
"[unixODBC][Driver Manager]Can't open lib 'SQL Native Client' : file not found QODBC3: Unable to connect"
My questions are:
I picked up the connection string from a forum post, I figured it was as good a place to start as any, but what exactly should be in there? Where does "SQL NAtive Client" come from? What do I need to do to setup my Qt / Linux box to be able to connect to a remote MS SQL Server?
Sounds like you need to install the SQL Server ODBC Driver.
An explanation for how to do that is here:
https://technet.microsoft.com/en-us/library/hh568454(v=sql.110).aspx
In addition you need to refer to it by the correct name, which is "ODBC Driver 11 for SQL Server"

What is the interface I have to inspect for detecting connected USB?

I'm trying to detect that a USB device was plugged or removed from within a qt programm via the method: http://doc.qt.io/qt-4.8/qdbusconnection.html#connect
My current code of the corresponding class looks like this:
#include "usbhandler.h"
#include <QDebug>
USBHandler::USBHandler()
{
QDBusConnection *bus;
bool success;
bus = new QDBusConnection("DeviceAdded");
if (bus == NULL)
{
qDebug() << "Allocation Error";
return;
}
if (!QDBusConnection::systemBus().isConnected())
{
qDebug() << "Cannot connect to system bus";
}
success = QDBusConnection::systemBus().connect(
"org.freedesktop.UDisks",
"/org/freedesktop/UDisks",
"org.freedesktop.UDisks",
"DeviceAdded",
this, SLOT(deviceAdded(QDBusObjectPath)));
if (success != true)
{
qDebug() << "Unsuccesfully connected!";
delete bus;
return;
}
}
void USBHandler::deviceAdded(QDBusObjectPath dev)
{
qDebug() << "device added!"<<dev.path();
}
When I'm running solid-hardware listen I get when plugging / unplugging, the following notifications:
Device Added:
udi = '/org/freedesktop/UDisks2/block_devices/sdb'
"/org/freedesktop/UDisks2/block_devices/sdb1" has new interfaces: ("org.freedesktop.UDisks2.Block", "org.freedesktop.UDisks2.Filesystem", "org.freedesktop.UDisks2.Partition")
Device Added:
udi = '/org/freedesktop/UDisks2/block_devices/sdb1'
"/org/freedesktop/UDisks2/block_devices/sdb1" lost interfaces: ("org.freedesktop.UDisks2.Partition", "org.freedesktop.UDisks2.Filesystem", "org.freedesktop.UDisks2.Block")
Device Removed:
udi = '/org/freedesktop/UDisks2/block_devices/sdb1'
"/org/freedesktop/UDisks2/block_devices/sdb" lost interfaces: ("org.freedesktop.UDisks2.PartitionTable", "org.freedesktop.UDisks2.Block")
Device Removed:
udi = '/org/freedesktop/UDisks2/block_devices/sdb'
So I was sure that the system notifys the USB stickAnd I'm now allready playing around for hours with the for the usb named interfaces but I can't get any success for my apllication reacting on pluggining/unplugging the stick.
So what Am I doing wrong?
What should be the interface and name paramter of connect() be like?
And can you explain me what exactly they do?
Device Added:
udi = '/org/freedesktop/UDisks2/block_devices/sdb'
"/org/freedesktop/UDisks2/block_devices/sdb1" has new interfaces:
I am not sure it is your problem, but the udi contains UDisks2, not UDisks. I suggest you adjust your call to connect(). Something like this:
success = QDBusConnection::systemBus().connect(
"org.freedesktop.UDisks",
"/org/freedesktop/UDisks2",
"org.freedesktop.UDisks2",
[...]);

Connecting to SQL server 2005 through QT C++

I have a server of windows server 2003 and its IP on my local network is 192.168.1.220
This server has SOL server 2005 express edition installed. This SQL server has a database called amir.
I want to connect to it from a Linux client on the same network.
SQL server service using port 1617 on my server and I used this port to connect to the server using java.
Wow i want to use QT C++ but my code doesn't work.
This is my code:
#include <QtCore/QCoreApplication>
#include <iostream>
#include <QSqldatabase>
#include <QSqldriver>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
bool test=db.isValid();//true
test=db.isDriverAvailable("QODBC");//true
db.setHostName("192.168.1.220\\SQLEXPRESS");
db.setDatabaseName("DRIVER={SQL Server};SERVER=192.168.1.220\\SQLEXPRESS:1617;DATABASE=amir");
db.setUserName("sa");
db.setPassword("amir");
db.setPort(1617);
test=db.isValid();//true
if(!db.open())
{
cout<<endl<<"not connected"<<endl;
QString error=db.lastError().text();
cout<<error.toLocal8Bit().data();
return false;
}
else
cout<<endl<<"connected"<<endl;
return true;
}
Every time i try this it out "not connected" and the error is
[unixODBC][Driver Manager]Data source name not found, and no default driver specified QODBC3: Unable to connect
Using these parameters I can connect using java
So what is the wrong here? and if there is another fasting way to connect to the SQL server using qt c++ than ODBC driver.
You need to setup a data source name on your server to connect through ODBC. Here is some code that I use to setup a DSN:
QString SQLServerProvider::buildDSN(QString server, QString database, QString username, QString password)
{
#ifdef Q_WS_MACX
QString dsn = QString("DRIVER=/usr/local/lib/libtdsodbc.so;SERVER=%1;TDS_VERSION=8pClient;DATABASE=%2;PORT=1433;UID=%3;PWD=%4;").arg(server).arg(database).arg(username).arg(password);
#endif
#ifdef Q_WS_X11
QString dsn = QString("DRIVER={FreeTDS};SERVER=%1;TDS_VERSION=8.0;PORT=1433;DATABASE=%2;UID=%3;PWD=%4;").arg(server).arg(database).arg(username).arg(password);
#endif
#ifdef Q_WS_WIN
QString dsn = QString("DRIVER={SQL SERVER};SERVER=%1;DATABASE=%2;UID=%3;PWD=%4;").arg(server).arg(database).arg(username).arg(password);
#endif
return dsn;
}
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", databaseName);
db.setDatabaseName(buildDSN(server, database, username, password));
Here is some code that I forgot to put in the initial post:
#ifdef Q_WS_X11
QString dir = QDir::homePath();
QDir d;
QString libdir = d.absolutePath();
QFile odbcinst(dir + "/.odbcinst.ini");
if(!odbcinst.exists())
{
odbcinst.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&odbcinst);
out << "[FreeTDS]\n";
out << "Description = v0.91 with protocol v8.0\n";
out << "Driver = " + libdir + "/libtdsodbc.so\n";
out << "Setup = " + libdir + "/libtdsodbc.so\n";
out << "FileUsage = 1";
odbcinst.close();
}
else
{
QList<QString> lines;
odbcinst.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream readfile(&odbcinst);
int i = 0, lnbr = 0;
bool found = false;
while(!readfile.atEnd())
{
QString line = readfile.readLine();
if(line.contains("[FreeTDS]"))
{
lnbr = i;
found = true;
}
lines.append(line);
i++;
}
odbcinst.close();
// append to end
if(!found)
{
// append to the end
odbcinst.open(QIODevice::Append | QIODevice::Text);
QTextStream file(&odbcinst);
file << "\n[FreeTDS]\n";
file << "Description = v0.91 with protocol v8.0\n";
file << "Driver = " + libdir + "/libtdsodbc.so\n";
file << "Setup = " + libdir + "/libtdsodbc.so\n";
file << "FileUsage = 1";
odbcinst.close();
}
else // update existing entry
{
qDebug() << "Found an entry for FreeTDS. Updating driver to " + libdir + "/libtdsodbc.so.";
qDebug() << lines[lnbr+2];
qDebug() << lines[lnbr+3];
lines.replace(lnbr + 2, "Driver = " + libdir + "/libtdsodbc.so");
lines.replace(lnbr + 3, "Setup = " + libdir + "/libtdsodbc.so");
QString text;
for(int j = 0; j < lines.count(); j++)
{
text.append(lines[j] + "\n");
}
odbcinst.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream updatefile(&odbcinst);
updatefile << text;
odbcinst.close();
}
}
#endif
This code creates the .odbcinst.ini file in your home directory if it doesn't exist and adds an entry for FreeTDS. If it does exist, it will append to the end of the file. If an entry for FreeTDS exists in the file already, it will update the existing file. Here's a guide for setting up FreeTDS if you haven't already: http://pzuk.wordpress.com/2012/02/03/how-to-make-freetds-unixodbc-and-qt-working-together/
Note, that the code for configuring FreeTDS that I posted is only required if you want to bundle FreeTDS with your application and have the libary path setup correctly from where you launch. It runs as a standard user and not as root so everything is done in the local user account.