Hi currently I am working on project that require to connect to wifi and I am using libconnman-qt.
Everything goes well (enable/disable wifi, list of wifi), until I found a problem to connect to the wifi. So when I connect the service to wifi by :
mCurrentNetworkService->setPassphrase(ui->linePassword->text());
mCurrentNetworkService->requestConnect();
Occurs an error that says : "Not Registered". I don't know what happen, since the lib not give any clue for me. Or maybe there is step that I missed?
You must first register an "agent" that can respond to requests for input from the connman daemon. Here is a simple example.
#include <networkservice.h>
#include <useragent.h>
class Wifi : public QObject {
Q_OBJECT
public:
Wifi(QObject *parent = 0) :
QObject(parent), m_agent(NULL), m_service(NULL) {
//Register an agent to handle requests from connmand
m_agent = new UserAgent(this);
//Connect to UserAgent signal
connect(m_agent, SIGNAL(userInputRequested(QString, QVariantMap)),
this, SLOT(agentRequestedUserInput(QString, QVariantMap)));
}
~Wifi() {}
public Q_SLOTS:
void agentRequestedUserInput(QString path, QVariantMap fields) {
Q_UNUSED(path)
QVariantMap reply;
reply.insert("Passphrase", QString("pass1234"));
m_agent->sendUserReply(reply);
}
void connectToService(QString servicePath) {
// Add logic to find NetworkService pointer for the service you will connect to
// pseudo code
// m_service = findService(servicePath);
m_service->requestConnect();
}
private:
UserAgent *m_agent;
NetworkService *m_service;
}
Related
I have implemented a websocket server in a QCoreApplication. As soon as a connection is established with a client, I wish to send a series of messages to it immediately in real-time with a delay of 0.5 seconds between messages. However, the individual messages reach the client only after all the messages have been sent or right after sendMyMessages() method returns in the below implementation of my websocket server. If I have a huge number of messages to send, the client has to wait for a long time before getting all the messages in one go.
MyWebSocketServer.h
#ifndef MYWEBSOCKETSERVER_H
#define MYWEBSOCKETSERVER_H
#include <QtCore/QObject>
#include <QtCore/QList>
#include <QtCore/QByteArray>
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
QT_FORWARD_DECLARE_CLASS(QWebSocket)
class MyWebSocketServer : public QObject
{
Q_OBJECT
public:
explicit MyWebSocketServer(quint16 port,
bool debug = false,
QObject *parent = nullptr);
~MyWebSocketServer();
Q_SIGNALS:
void closed();
private Q_SLOTS:
void onNewConnection();
void socketDisconnected();
private:
void sendMyMessages(QWebSocket *client);
QWebSocketServer *m_pWebSocketServer;
QList<QWebSocket *> m_clients;
bool m_debug;
};
#endif // MYWEBSOCKETSERVER_H
MyWebSocketServer.cpp
#include "MyWebSocketServer.h"
#include <iostream>
#include <fstream>
#include <chrono>
#include <thread>
#include <QtWebSockets/qwebsocketserver.h>
#include <QtWebSockets/qwebsocket.h>
#include <QtCore/QDebug>
QT_USE_NAMESPACE
MyWebSocketServer::MyWebSocketServer(quint16 port,
bool debug,
QObject *parent)
: QObject(parent)
, m_pWebSocketServer(new QWebSocketServer(
QStringLiteral("My WebSocket Server"),
QWebSocketServer::NonSecureMode,
this))
, m_debug(debug)
{
connect(m_pWebSocketServer,
&QWebSocketServer::newConnection,
this,
&MyWebSocketServer::onNewConnection);
connect(m_pWebSocketServer,
&QWebSocketServer::closed,
this,
&MyWebSocketServer::closed);
m_pWebSocketServer->listen(QHostAddress::LocalHost, port);
}
MyWebSocketServer::~MyWebSocketServer()
{
m_pWebSocketServer->close();
qDeleteAll(m_clients.begin(), m_clients.end());
}
void MyWebSocketServer::onNewConnection()
{
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket,
&QWebSocket::disconnected,
this,
&MyWebSocketServer::socketDisconnected);
m_clients << pSocket;
sendMyMessages(pSocket);
}
void MyWebSocketServer::sendMyMessages(QWebSocket *client)
{
std::fstream jsonStringFileHandler;
jsonStringFileHandler.open("my-messages.txt", std::ios::in);
if (jsonStringFileHandler.is_open())
{
std::string message;
while(getline(jsonStringFileHandler, message))
{
// Individual messages don't go through immediately
// Only after this method returns, all the messages show up on the client's end
// Is it possible to send the individual messages immediately? (probably with a 0.5 second delay)
client->sendTextMessage(QString::fromUtf8(message.c_str()));
}
jsonStringFileHandler.close();
}
}
void MyWebSocketServer::socketDisconnected()
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (pClient)
{
m_clients.removeAll(pClient);
pClient->deleteLater();
}
}
Only after the sendMyMessages() returns, the client gets all the messages. It is not in real-time. I understand it would be possible to achieve what I am after using some asynchronous programming technique but I unable to figure out a way to set it up in my implementation of the websocket server.
Here is an implementation of the websocket server that worked for me in Python using the websockets and asyncio modules. However, I wish to implement the same logic in C++ using Qt.
import asyncio
import websockets
async def sendMyMessages(websocket, path):
with open("my-messages.txt") as fp:
lines = fp.readlines()
for line in lines:
await asyncio.sleep(0.5)
await websocket.send(line.strip())
start_server = websockets.serve(sendMyMessages, "127.0.0.1", 3000)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
One of the approaches I found uses QWebSocket::flush() immediately after a call to QWebSocket::sendTextMessage().
From the docs on QWebSocket::flush(),
This function writes as much as possible from the internal write buffer to the underlying network socket, without blocking. If any data was written, this function returns true; otherwise false is returned. Call this function if you need QWebSocket to start sending buffered data immediately. The number of bytes successfully written depends on the operating system. In most cases, you do not need to call this function, because QWebSocket will start sending data automatically once control goes back to the event loop.
However, I am not sure if this is the right approach as the doc indicates that the data may not be written to the underlying network socket reliably. I will be happy to know if there is a better technique out there!
client->sendTextMessage(QString::fromUtf8(message.c_str()));
client->flush();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
I would like to setup a handler for when my ESP8266 is connected, so that it returns the IP address (among other things). I am calling a Network class method from my main class's setup function, and am not sure how to provide the necessary parameters to the handler. I attempted the following, but I get an error about how ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.
I would love any feedback,
Thanks!
/* Network.h */
class Network{
public:
void connect(const char* ssid, const char* password);
WiFiEventHandler deviceDidConnect;
void onDeviceConnected(const WiFiEventStationModeGotIP& evt);
}
/* Network.cpp */
void Network::connect(const char* ssid, const char* password) {
WiFi.persistent(false);
if (WiFi.status() == WL_DISCONNECTED) {
deviceDidConnect = WiFi.onStationModeGotIP(&onDeviceConnected);
// Not sure how to handle it here...
}
}
void onDeviceConnected(const WiFiEventStationModeGotIP& evt) {
Serial.print("Station connected, IP: ");
Serial.println(WiFi.localIP());
}
/* MyApp */
#include "Network.h"
void setup(){
Serial.begin(115200);
network.connect(SSID, PASSWORD);
}
Updated on 11/08/18:
My goal is to create an Arduino library to handle my connections.
I noticed that if I leave the connect method and the WifiEventHandler in the header file, but move the onDeviceConnected method signature (void onDeviceConnected(const WiFiEventStationModeGotIP& evt);) to Network.cpp (after I include Network.h), then the sketch compiles and works fine.
It works. I was under the misguided notion that all methods in a custom Arduino library should be exposed either as Public or Private in the header file, whereas only methods that need to be shared need be exposed. It makes sense.
I know that how to send messages to the newly connected client whenever the QTcpServer newConnection is emitted. What I did is like this:
connect(serverConnection.tcpServer, &QTcpServer::newConnection, this, &ServerInterface::sendMessages);
void ServerInterface::sendMessages()
{
QByteArray messagesToClients;
QDataStream out(&messagesToClients, QIODevice::WriteOnly);
QTcpSocket *clientConnection = serverConnection.tcpServer->nextPendingConnection();
out << inputBox->toPlainText(); //get text from QTextEdit
clientConnection->write(messagesToClients);
}
But what I want to do is whenever the send messages button is clicked in the server, it will send messages to currently connected clients. The code I provide can only send only one new message to the newly connected client. I have no idea of how to achieve what I want to do, so can someone provide me a way to do that? I am kind of new to Qt networking.
Thanks.
Just store your connections in container. Like this:
in your ServerInterface h-file:
class ServerInterface {
// your stuff
public slots:
void onClientConnected();
void onClientDisconnected();
private:
QVector<QTcpSocket *> mClients;
};
in your ServerInterface cpp-file :
connect(serverConnection.tcpServer, SIGNAL(newConnection(), this, SLOT(onClientConnected());
void ServerInterface::onClientConnected() {
auto newClient = serverConnection.tcpServer->nextPendingConnection();
mClients->push_back( newClient );
connect(newClient, SIGNAL(disconnected()), this, SLOT(onClientDisconnected());
}
void ServerInterface::onClientDisconnected() {
if(auto client = dynamic_cast<QTcpSocket *>(sender()) {
mClients->removeAll(client);
}
void ServerInterface::sendMessages() {
out << inputBox->toPlainText();
for(auto &client : mClients) {
client->write(messagesToClients);
}
}
I am using RtMidi library to handle midi message in my Qt application and I am facing problem with slot trigger:
My PhMidiInput object is emiting signal from the RtMidi callback upon specific midi message but the slots are not always triggered.
Here is a part of the PhMidiInput class:
class PhMidiInput : QObject
{
Q_OBJECT
public:
void PhMidiInput() {}
signals:
void quarterFrame(unsigned char data);
private:
static void callback(double, std::vector< unsigned char > *message, void *userData ) {
PhMidiInput *midiInput = (PhMidiInput*)userData;
if(midiInput)
midiInput->onMessage(message);
}
void onMessage(std::vector<unsigned char> *message) {
...
emit quarterFrame(data);
...
}
}
Connecting to a lambda functor works:
PhMidiInput midiIn;
int quarterFrameCount;
connect(&midiIn, &PhMidiInput::quarterFrame, [&](unsigned char data) {
quarterFrameCount++;
});
Connecting to my application window works to:
// MyWindow inherits from QMainWindow
connect(_midiIn, &PhMidiInput::quarterFrame, this, &MyWindow::onQuarterFrame);
When trying to connect to a custom class (MidiTest) inheriting from QObject it does'nt trigger:
connect(_midiIn, &PhMidiInput::quarterFrame, this, &MidiTest::onQuarterFrame);
I was wondering if there was something around QObject::moveToThread() but since I don't create the thread myself (the signal is sent from a callback) I don't know if I need to use it or not.
It is as simple as calling emit obj->quarterFrame(data); from the callback. If the connection type is default then this will be perfectly thread safe.
Though you should create a QByteArray from data to pass around as data will likely not be valid by the time the slots get called.
void callback(..., void* user){
//user is the standard void* in most callbacks passed as reinterpret_cast<void*>(this)
unsigned char* data = ...;
QByteArray bytes(data);
emit reinterpret_cast<PhMidiInput>(user)->quarterFrame(bytes);//calling the signal which will behave as you'd expect
}
In the last connect() call you pass this and MidiTest::onQuarterFrame as the receiver object and method. I bet this is not an instance of MidiTest, is it?
The problem here is that you're passing SLOT method from MidiTest, while the receiver object is this, which is not instance of MidiTest. Change receiver from this to some instance of MidiTest.
I'm surprised this code doesn't crash your application when running.
and first of all sorry for my english
I have developed driver for fiscal printer using Qt. Driver specifics is communication between PC and device via RS232. Driver stored in shared object (Qt plugin) and server performs its loading by QPluginLoader.
So, about my problem... When i use one device and one driver instance all works fine, but when i attach many devices (3 for example), only last loaded device work. I have done many code checks, read many dumps of logs data, there is no error with devices and ports naming, but if i adress first device with command - 2 left devices receive the same command (according to log entries) and only last loaded device performs commands executing.
For example: from my server i send PrintReceipt command to device 1, at log file of device 1 i see entry : PrintReceipt, at log file of device 2 i see entry : PrintReceipt, : PrintReceipt, and at log file of device 3 i see 3 same entries. So, as i see my problem - QPluginLoader creates one instance for driver for first loaded device, then, when i try to load driver to second device - QPluginLoader creates new instance and replace driver for first device by recently created and so on for every device. So, at least, i have only one instance of driver (plugin) for many devices and my app logic crashes.
My question is: How to create multiple instances of the same plugin in Qt using QPluginLoader? My driver interface and loading code listed below.
class IPrinterDriver : public QObject
{
public:
// Printer driver initialization
virtual bool Init(QextSerialPort* port, const QString& deviceID) = 0;
// Driver identify name
virtual QString GetName() = 0;
// Gets current device state
virtual DeviceStates GetState() = 0;
// Gets device info and state test
virtual QString DeviceInfo() = 0;
// Set print mode to specified
virtual bool SetPrintMode(PrintModes mode) = 0;
// Get current print mode
virtual PrintModes PrintMode() const = 0;
// Sets device password from configuration
virtual void SetDevicePasswords(int operatorPassword, int adminPassword) = 0;
// Sets non-fiscal permissoin to device
virtual void SetNonFiscalModePermission(bool allowed) = 0;
// Gets device operator password
virtual int GetOperatorPassword() const = 0;
// Gets device administrator password
virtual int GetAdministratorPassword() const = 0;
// Gets non-fiscal mode permission
virtual bool GetNonFiscalModePermission() const = 0;
// Payment transaction
virtual bool PaymentTransaction(PaymentItem& item) = 0;
// Query device for X-Report
virtual bool GetXReport() = 0;
// Encashment transaction (Z-Report)
virtual bool Encash(bool fromBuffer) = 0;
// Print transaction
virtual bool Print(QString& text) = 0;
// Performs fiscal sale at device and returns receipt data
virtual FiscalReceiptData FPSSale(int requestID, int amount) = 0;
// Gets last fiscal receipt data
virtual FiscalReceiptData GetLastReceiptData() = 0;
// Gets serial port assigned to device
virtual QextSerialPort* GetDevicePort() = 0;
signals:
// Emits when device logging needed
virtual void DeviceLoggingNeeded(LogEntry entry, const QString& deviceID) = 0;
};
Q_DECLARE_INTERFACE(IPrinterDriver, "InfSys.Devices.IPrinterDriver/1.0")
And driver loading method:
// Performs loading specified driver for device at specified port
IPrinterDriver* PrintSystem::LoadDriver(PortConfiguration portConfig, const QString& driverName, const QString& adminPassword, const QString& operPassword, const QString& deviceID)
{
IPrinterDriver* result = NULL;
// Prepare plugin loader
QDir driversDir(_driversPath);
QStringList filesMask;
filesMask << tr("libdriver.%1.*").arg(driverName);
driversDir.setNameFilters(filesMask);
QStringList driversFiles = driversDir.entryList(QDir::Files);
// Load plugin with specified driver
foreach(QString driverFile, driversFiles)
{
// Load current driver;
QString driverFileName = driversDir.absoluteFilePath(driverFile);
QPluginLoader driversLoader(driverFileName);
// Try to init driver
QObject *driverObject = driversLoader.instance();
if (driverObject)
{
result = qobject_cast<IPrinterDriver *>(driverObject);
if (result && (result->GetName() == driverName))
{
QextSerialPort* devicePort = ConfigureSerialPort(portConfig);
if (devicePort == NULL)
{
driversLoader.unload();
return NULL;
}
// Init device
result->SetDevicePasswords(operPassword.toInt(), adminPassword.toInt());
result->SetNonFiscalModePermission(false);
result->SetPrintMode(Fiscal);
connect(result, SIGNAL(DeviceLoggingNeeded(LogEntry,QString)), App->LoggingModule, SLOT(OnDeviceLoggingNeeded(LogEntry,QString)), Qt::QueuedConnection);
bool initResult = result->Init(devicePort, deviceID);
if (!initResult)
{
driversLoader.unload();
return NULL;
}
}
else
driversLoader.unload();
}
}
return result;
}
I've been looking at this problem for a while now on my own project. I believe that there isn't any way to do this directly - QPluginLoader is working as designed.
The most straightforward way around the issue that I've come up with so far is to make the primary plugin interface function a factory for the objects you actually want.
In the example below, the thing I actually WANT is multiple IPlaybackDataSource objects. So I create a factory interface that the plugin implements. The plugin then returns as many objects of the type I desire as I want.
IPlaybackDataSource.h:
#include <QSharedPointer>
class IPlaybackDataSource {
public:
virtual bool open()=0;
};
// This is the interface that the plugin will implement
class IPlaybackDSFactory {
public:
virtual QSharedPointer<IPlaybackDataSource> newDataSource()=0;
};
Q_DECLARE_INTERFACE(IPlaybackDSFactory,
"com.moberg.DeviceSimulators.IPlaybackDSFactory/1.0")
TranFile.h:
#include <QtGui>
#include "TranFile_global.h"
#include "IPlaybackDataSource.h"
class TRANFILESHARED_EXPORT TranFile : public QObject, public IPlaybackDSFactory
{
Q_OBJECT
Q_INTERFACES(IPlaybackDSFactory)
public:
TranFile();
~TranFile();
virtual QSharedPointer<IPlaybackDataSource> newDataSource();
};
TranFile.cpp:
#include "TranFile.h"
Q_EXPORT_PLUGIN2(IPlaybackDSFactory, TranFile );
#include <QtCore>
#include <QDebug>
TranFile::TranFile(): QObject(), IPlaybackDSFactory() {}
TranFile::~TranFile() {}
QSharedPointer<IPlaybackDataSource> TranFile::newDataSource() {
return QSharedPointer<IPlaybackDataSource>();
}