I want to use QFtp for the first time and googled a lot to find out how it should be used. This, among others is a typical example:
#include <QCoreApplication>
#include <QFtp>
#include <QFile>
int main(int argc, char ** argv)
{
QCoreApplication app(argc, argv);
QFile *file = new QFile( "C:\\Devel\\THP\\tmp\\test.txt" );
file->open(QIODevice::ReadWrite);
QFtp *ftp = new QFtp();
ftp->setTransferMode(QFtp::Active);
ftp->connectToHost("ftp.trolltech.com");
ftp->login();
ftp->cd("qt");
ftp->get("INSTALL",file);
ftp->close();
QObject::connect(ftp, SIGNAL(done(bool)), &app, SLOT(quit()));
int ret = app.exec();
delete ftp;
delete file;
return ret;
}
The question:
As far as I understood, the QCoreApplication app is needed to handle the "done" signal, emmited upon finalization of ftp-get. Now, the ftp->get is called before the connect and even before the app handler is running at all (app.exec() is called afterwards).
What happens, if the file transfer has completed already before the "connect" statement? In fact, that will not happen, but I could put an artificial delay of, say 1 minute between ftp->close() and the connect(...). During this time, the ftp get will surely be finished. What would happen?
Note that QFtp is really only meant for legacy Qt applications and it is now suggested that QNetworkAccessManager and QNetworkReply are used instead, as detailed in the Qt documentation.
That being said, with your connect call being positioned after the connection to the FTP site and retrieving of the file, should the file be downloaded first, the 'quit' signal would never be reached. If you make the connection straight after creating the QFtp object, then this won't be an issue: -
QFtp *ftp = new QFtp();
QObject::connect(ftp, SIGNAL(done(bool)), &app, SLOT(quit()));
This guarantees that the 'quit' slot will be called when the QFtp object emits the 'done' signal.
QFtp *ftp = new QFtp();
QObject::connect(ftp, SIGNAL(done(bool)), &app, SLOT(quit()));
ftp->setTransferMode(QFtp::Active);
ftp->connectToHost("ftp.trolltech.com");
ftp->login();
ftp->cd("qt");
ftp->get("INSTALL",file);
ftp->close();
int ret = app.exec();
In reality though, I would expect the connect in your example would complete before the machine had time to negotiate a connection to another server, login and start the download of the file.
Related
I want to be able to recover from a Segmentation Fault in MyApplication by catching the SIGSEGV and restarting QApplication. So for testing purposes I'm injecting a segmentation fault in my code.
The issue is that the signal handler that catches the SIGSEGV is getting a non-stop stream of SIGSEGVs. At first I thought it was the while loop in my main but it still happens even though I comment out the while loop. So my questions are simple: Is it even possible to recover from a Segmentation Fault in Qt? Why am I getting rolling SIGSEGVs non-stop?
#include <QApplication>
#include <QDebug>
#include "MyApplication.h"
#include <initializer_list>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#define RESTART_CODE 1000
void catchUnixSignals(std::initializer_list<int> quitSignals)
{
auto handler = [](int sig) -> void
{
if (sig == SIGSEGV)
{
QCoreApplication::exit(RESTART_CODE);
}
else
{
QCoreApplication::quit();
}
};
sigset_t blocking_mask;
sigemptyset(&blocking_mask);
for (auto sig : quitSignals)
sigaddset(&blocking_mask, sig);
struct sigaction sa;
sa.sa_handler = handler;
sa.sa_mask = blocking_mask;
sa.sa_flags = 0;
for (auto sig : quitSignals)
sigaction(sig, &sa, nullptr);
}
int main(int argc, char *argv[])
{
catchUnixSignals({SIGSEGV, SIGQUIT, SIGINT, SIGTERM, SIGHUP, SIGKILL});
int i = 0;
do
{
QApplication app(argc, argv);
MyApp myapp;
MyApp.start();
app.exec();
if (app.exec() != RESTART_CODE) break;
} while(1);
return 0;
}
This does not directly answers your question, but is another way to achieve similar behavior.
To recover from a segmentation fault, an option is to use a watchdog, i.e. another independent process that checks the status of your main software and restarts it when needed.
When you start your software, you create another process that runs a 2nd software, the watchdog. Ensure to start it in "detached" mode to avoid that it gets closed if your main software crashes.
In the watchdog, frequently call "tasklist" on Windows or "ps" or "top" on Linux and parse the output to check whether your software is still running. OR, use a UDP or TCP port to communicate between the main software and the watchdog, to tell the watchdog that the main software is still running well.
In the watchdog, if the main software is no longer running, restart the main software process (also in detached).
CAUTION: You need to manage the case where the main software is exited correctly. In that case the main software should either kill the watchdog itself when exiting normally (calling "kill" on the pid), or send it a message so that the watchdog exits as well.
I am trying to create a simple Qt ble application that will send and receive data. Basically a le chat server.
I am unable to find any existing QT example codes that will help me achieve the same.
So I wanted to know how do I go about creating one.
If I am understanding Qt Ble properly then,
I have to construct a QLowEnergyAdvertisingData object
Set Discoverability
Set local name
Add a list of services
I am confused here. Which service do I use for a simple transmission and reception.
Do I now have to create a service and then register the local device to it?
And then follow the similar procedure to create a characteristic UUID.
I had created a simple Bluetooth le android application long back. And I remember that I would set up a service UUID on my client which was similar to the server and was able to communicate back and forth
The code was basically set up like this
public static String ServiceUUID = "11223344-5566-7788-99aa-bbccddeeff00";
Then I would connect to this service uuid and was able to communicate back and forth
Edit 1: So after doing some research. I wrote this code
int main(int argc, char *argv[])
{
//QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
static const QLatin1String serviceUuid("11223344-5566-7788-99aa-bbccddeeff00");
static const QLatin1String charUuid("11223344-5566-7788-99aa-bbccddeeff11");
QCoreApplication app(argc, argv);
//! [Advertising Data]
QLowEnergyAdvertisingData advertisingData;
advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral);
advertisingData.setIncludePowerLevel(true);
advertisingData.setLocalName("Test_server");
advertisingData.setServices(QList<QBluetoothUuid>() << QBluetoothUuid::HeartRate);
//! [Advertising Data]
//! [Service Data]
QLowEnergyCharacteristicData charData,rxData;
charData.setUuid(QBluetoothUuid(serviceUuid));
charData.setValue(QByteArray(2, 0));
charData.setProperties(QLowEnergyCharacteristic::Notify);
const QLowEnergyDescriptorData clientConfig(QBluetoothUuid::CharacteristicUserDescription,QByteArray(2, 0));
charData.addDescriptor(clientConfig);
rxData.setUuid(QBluetoothUuid(serviceUuid));
rxData.setValue(QByteArray(2, 0));
rxData.setProperties(QLowEnergyCharacteristic::Write);
const QLowEnergyDescriptorData discriptor(QBluetoothUuid::CharacteristicUserDescription,QByteArray(2, 0));
charData.addDescriptor(discriptor);
QLowEnergyServiceData serviceData;
serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
serviceData.setUuid(QBluetoothUuid(serviceUuid));
serviceData.addCharacteristic(charData);
serviceData.addCharacteristic(rxData);
//! [Service Data]
//! [Start Advertising]
const QScopedPointer<QLowEnergyController> leController(QLowEnergyController::createPeripheral());
QScopedPointer<QLowEnergyService> service(leController->addService(serviceData));
leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,advertisingData);
}
So now I can connect to the bluetooth with my app
But It keeps giving me an error
qt.bluetooth: Using BlueZ kernel ATT interface
qt.bluetooth.bluez: sending error response; request: 16 handle: 8 code: 10
qt.bluetooth.bluez: sending error response; request: 8 handle: 1 code: 10
qt.bluetooth.bluez: sending error response; request: 8 handle: 7 code: 10
qt.bluetooth.bluez: void QBluetoothSocketPrivateBluez::_q_readNotify() 9 error: -1 "Connection reset by peer"
What am I missing ?
I think you are missing some basic ble knowledge.
Basics:
Your phone app acts as a central device. The linux machine is the peripheral. On service can have different characteristics and a char can have different descriptors.
There are 4 basic setups for the communication:
write to peripheral
read from peripheral
notify from peripheral (let peripheral notify central device without request from ceantral device.)
indicate from peripheral (same as 3. but with ack from central device)
The heart rate game shows the notify setup.
Questions related:
In your project I would suggest creating a custom service with two characteristics which you can write to and read from. Notification requires the central to write certain char on the peripheral you can read up on that yourself.
Yes you can use custom Uuid. Just use different ones.
You need to define callbacks on write or on read to handle interactions with a central device. In Qt you can use QLowEnergyService::characteristicChangedas signal and a custom slot.
If you want to go further read Qt Doc on QLowEnergerController, QLowEnergyService, QLowEnergyCharacteristicand QLowEnergyDescriptor. The Qt docs are great.
Anyway I think you want this:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
static const QLatin1String serviceUuid("11223344-5566-7788-99aa-bbccddeeff00");
static const QLatin1String charWriteUuid("11223344-5566-7788-99aa-bbccddeeff11");
static const QLatin1String charReadUuid("11223344-5566-7788-99aa-bbccddeeff22");
QCoreApplication app(argc, argv);
//! [Advertising Data]
QLowEnergyAdvertisingData advertisingData;
advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral);
advertisingData.setIncludePowerLevel(true);
advertisingData.setLocalName("Test_server");
advertisingData.setServices(QList<QBluetoothUuid>() << QBluetoothUuid(serviceUuid));
//! [Advertising Data]
//! [Service Data]
QLowEnergyCharacteristicData charData,rxData;
charData.setUuid(QBluetoothUuid(charReadUuid));
charData.setProperties(QLowEnergyCharacteristic::Read);
rxData.setUuid(QBluetoothUuid(charWriteUuid));
rxData.setProperties(QLowEnergyCharacteristic::Write);
QLowEnergyServiceData serviceData;
serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
serviceData.setUuid(QBluetoothUuid(serviceUuid));
serviceData.addCharacteristic(charData);
serviceData.addCharacteristic(rxData);
//! [Service Data]
//! [Start Advertising]
const QScopedPointer<QLowEnergyController> leController(QLowEnergyController::createPeripheral());
QScopedPointer<QLowEnergyService> service(leController->addService(serviceData));
leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,advertisingData);
}
I have a code as simple as this:
int main() {
QUrl url("http://google.com");
if (!QDesktopServices::openUrl(url) )
qDebug() << "Failed to open url";
return 0;
}
Running the code gives "Failed to open url". Tried on Ubuntu with Qt 5.5.1 and on MS Windows with Qt 5.7. No difference.
Local files also do not open:
int main() {
QString file = "/home/user/testfile.pdf";
if (!QDesktopServices::openUrl( QUrl::fromLocalFile(file) ) )
qDebug() << "Failed to open file";
return 0;
}
Again, "Failed to open file". On both Ubuntu and Windows. I can see some discussion in stackoverflow about openUrl, but they are concerned with specific features, such as failing to open urls with spaces, etc. But here it just doesn't work at all, on two independent platforms. What do I miss?
QDesktopServices is part of the Qt GUI module. Therefore, in order to use any function related to QDesktopServices, you will need to instantiate at least a QGuiApplication :
Since the QGuiApplication object does so much initialization, it must
be created before any other objects related to the user interface are
created.
In fact, you can create a QApplication (as #Alex Spataru suggested), since it inherits QGuiApplication. To make your code work, you just need this :
int main(int argc, char *argv[]) {
QApplication app(argc, argv); // just this line
QUrl url("http://google.com");
if ( !QDesktopServices::openUrl(url) )
qDebug() << "Failed to open url";
return 0;
}
I am having problems with launching Nokia's own video player from my application that I just don't seem to be able to solve.
My first attempt included calling
Qt.openUrlExternally(url)
from QML and that seemed to do the trick just fine, except that it opened the browser every time and used it instead of the video-suite (native player).
Next I tried cuteTube -approach where I start new process like this:
QStringList args;
args << url;
QProcess *player = new QProcess();
connect(player, SIGNAL(finished(int, QProcess::ExitStatus)), player, SLOT(deleteLater()));
player->start("/usr/bin/video-suite", args);
That worked, except that it required video-suite to be closed upon calling player->start, otherwise it did nothing.
My third attempt involved starting the video-suite via QDBus, but that didn't work any better:
QList<QVariant> args;
QStringList urls;
urls << url;
args.append(urls);
QDBusMessage message = QDBusMessage::createMethodCall(
"com.nokia.VideoSuite",
"/",
"com.nokia.maemo.meegotouch.VideoSuiteInterface",
"play");
message.setArguments(args);
message.setAutoStartService(true);
QDBusConnection bus = QDBusConnection::sessionBus();
if (bus.isConnected()) {
bus.send(message);
} else {
qDebug() << "Error, QDBus is not connected";
}
The problem with this is that it requires video-suite to be up and running - autoStartService parameter didn't help either. If video-suite isn't running already, the call opens it just fine but, alas, no video starts to play.
Eventually I tried using also VideoSuiteInterface, but even having the program compile with it seemed to be difficult. When I eventually managed to compile and link all relevant libraries, the results didn't differ from option 3 above.
So, is there a way to use either VideoSuiteInterface directly or via DBus so that it would start video playback regardless of the current state of the application?
The solution was actually simpler than I really thought initially; the VideoSuiteInterface -approach worked after all. All it took was to use it properly. Here are the full sources should anyone want to try it themselves.
player.h:
#ifndef PLAYER_H
#define PLAYER_H
#include <QObject>
#include <maemo-meegotouch-interfaces/videosuiteinterface.h>
class Player : public QObject {
Q_OBJECT
private:
VideoSuiteInterface* videosuite;
public:
Player(QObject *parent = 0);
Q_INVOKABLE void play(QString url);
};
#endif // PLAYER_H
player.cpp:
#include "player.h"
#include <QObject>
#include <QStringList>
#include <QtDeclarative>
Player::Player(QObject *parent) : QObject(parent) {}
void Player::play(QString url) {
QList<QVariant> args;
QStringList urls;
urls << url;
args.append(urls);
videosuite = new VideoSuiteInterface();
videosuite->play(urls);
}
In addition you may want to connect some signals to make the UI more responsive, but basically that should do the trick.
Finally, you need to remember to add following to your .pro file and you are good to go:
CONFIG += videosuiteinterface-maemo-meegotouch
I have a console-based QCoreApplication which has timers and does socket communication and also uses locked mutex.
When I close the application manually, it gives error saying some mutex is locked and it is timed out. Is there any way I can do clean up in a console application when user closes it?
Cleanup should be handled by destructors and child-parent relationship.
Make your master object (the one in the main) a child of QApplication so it is destructed with all its childs before QApplication is.
Are you sure you killed all your threads? If it is a thread with an eventloop be sure to call QThread::quit() to exit the eventloop before you call QThread::wait()
You can also use the void QApplication::qAddPostRoutine ( QtCleanUpFunction ptr )
to do some special cleanup.
For debugging those messages you can use QtMsgHandler qInstallMsgHandler ( QtMsgHandler h ) and write your own message handler to capture those warnings. If you can simulate the problem you can set a breakpoint on the message and see on the stack where the message is coming from.
void debugMessageHandler( QtMsgType type, const char *msg ){
if(QString(msg).contains( "The message you can see in the console" )){
int breakPointOnThisLine(0);
}
switch ( type ) {
case QtDebugMsg:
fprintf( stderr, "Debug: %s\n", msg );
break;
case QtWarningMsg:
fprintf( stderr, "Warning: %s\n", msg );
break;
case QtFatalMsg:
fprintf( stderr, "Fatal: %s\n", msg );
abort();
}
}
In order to clean up with destructor and child-parent relation ship you can catch the console close signal and call QCoreApplication::exit() to the application instance.
#include <csignal>
#include <QtCore/QCoreApplication>
using namespace std;
struct CleanExit{
CleanExit() {
signal(SIGINT, &CleanExit::exitQt);
signal(SIGTERM, &CleanExit::exitQt);
signal(SIGBREAK, &CleanExit::exitQt) ;
}
static void exitQt(int sig) {
QCoreApplication::exit(0);
}
};
int main(int argc, char *argv[])
{
CleanExit cleanExit;
QCoreApplication a(argc, argv);
return a.exec();
}
Turns out that closing command line application (checked on Win7 & VS2010) by pressing 'close' (red x button on title bar) passes the STATUS_CONTROL_C_EXIT signal to the application. All threads are aborted with this code.
The thread 'Main Thread' (0x980) has exited with code -1073741510
(0xc000013a).
The thread 'QThread' (0x2388) has exited with code
-1073741510 (0xc000013a).
That means that there is no way to intercept this with the QCoreApplication::aboutToQuit() signal.
Take a look at winnt.h or ntstatus.h. That is the value assigned to the
manifest constant STATUS_CONTROL_C_EXIT. The runtime is just
choosing to end your program with the code to note the user's cancel
operation.
you can connect to QCoreApplication::aboutToQuit signal and do the necessary clean up there.