I have a very basic question regarding how the whole system works for TelosB. I have gone through the data manual and how TelosB operates.
Now I need to send some specific data through the TelosB nodes. I saw the packet format of the TinyOS. and defined the payload.
typedef nx_struct packet {
nx_uint16_t id; /* Mote id of sending mote. */
nx_uint16_t count; } packet_t;
In the radio count leds code I changed few small things
#include "Timer.h"
#include "RadioCountToLeds.h"
module RadioCountToLedsC #safe() {
uses {
interface Leds;
interface Boot;
interface Receive;
interface AMSend;
interface Timer<TMilli> as MilliTimer;
interface SplitControl as AMControl;
interface Packet;
}
}
implementation {
message_t packet;
bool locked;
uint16_t counter = 0;
event void Boot.booted() {
call AMControl.start();
}
event void AMControl.startDone(error_t err) {
if (err == SUCCESS) {
call MilliTimer.startPeriodic(250);
}
else {
call AMControl.start();
}
}
event void AMControl.stopDone(error_t err) {
// do nothing
}
event void MilliTimer.fired() {
counter++;
dbg("RadioCountToLedsC", "RadioCountToLedsC: timer fired, counter is
%hu.\n", counter);
if (locked) {
return;
}
else {
radio_count_msg_t* rcm = (radio_count_msg_t*)call
Packet.getPayload(&packet, sizeof(radio_count_msg_t));
if (rcm == NULL) {
return;
}
rcm->counter = 11110000;
if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_count_msg_t)) == SUCCESS) {
dbg("RadioCountToLedsC", "RadioCountToLedsC: packet sent.\n", counter);
locked = TRUE;
}
}
}
The counter is the data I want to transmit. It is 11110000. When this TinyOS code is run in the Telosb mote, how is the 11110000 interpreted? I need to be very specific about what data is going into the DAC of the telosb or OQPSK.
I want to know in details how the data is read and interpreted.
I guess I got my answer. cc2420 chip
http://www.ti.com/lit/ds/symlink/cc2420.pdf
Related
I'm using nghttp2 to implement a REST server which should use HTTP/2 and server-sent events (to be consumed by an EventSource in the browser). However, based on the examples it is unclear to me how to implement SSE. Using res.push() as in asio-sv.cc doesn't seem to be the right approach.
What would be the right way to do it? I'd prefer to use nghttp2's C++ API, but the C API would do as well.
Yup, I did something like that back in 2018. The documentation was rather sparse :).
First of all, ignore response::push because that's the HTTP2 push -- something for proactively sending unsolicited objects to the client before it requests them. I know it sounds like what you need, but it is not -- the typical use case would be proactively sending a CSS file and some images along with the originally requested HTML page.
The key thing is that your end() callback must eventually return NGHTTP2_ERR_DEFERRED whenever you run out of data to send. When your application somehow obtains more data to be sent, call http::response::resume().
Here's a simple code. Build it as g++ -std=c++17 -Wall -O3 -ggdb clock.cpp -lssl -lcrypto -pthread -lnghttp2_asio -lspdlog -lfmt. Be careful, modern browsers don't do HTTP/2 over a plaintext socket, so you'll need to reverse-proxy it via something like nghttpx -f '*,8080;no-tls' -b '::1,10080;;proto=h2'.
#include <boost/asio/io_service.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/signals2.hpp>
#include <chrono>
#include <list>
#include <nghttp2/asio_http2_server.h>
#define SPDLOG_FMT_EXTERNAL
#include <spdlog/spdlog.h>
#include <thread>
using namespace nghttp2::asio_http2;
using namespace std::literals;
using Signal = boost::signals2::signal<void(const std::string& message)>;
class Client {
const server::response& res;
enum State {
HasEvents,
WaitingForEvents,
};
std::atomic<State> state;
std::list<std::string> queue;
mutable std::mutex mtx;
boost::signals2::scoped_connection subscription;
size_t send_chunk(uint8_t* destination, std::size_t len, uint32_t* data_flags [[maybe_unused]])
{
std::size_t written{0};
std::lock_guard lock{mtx};
if (state != HasEvents) throw std::logic_error{std::to_string(__LINE__)};
while (!queue.empty()) {
auto num = std::min(queue.front().size(), len - written);
std::copy_n(queue.front().begin(), num, destination + written);
written += num;
if (num < queue.front().size()) {
queue.front() = queue.front().substr(num);
spdlog::debug("{} send_chunk: partial write", (void*)this);
return written;
}
queue.pop_front();
spdlog::debug("{} send_chunk: sent one event", (void*)this);
}
state = WaitingForEvents;
return written;
}
public:
Client(const server::request& req, const server::response& res, Signal& signal)
: res{res}
, state{WaitingForEvents}
, subscription{signal.connect([this](const auto& msg) {
enqueue(msg);
})}
{
spdlog::warn("{}: {} {} {}", (void*)this, boost::lexical_cast<std::string>(req.remote_endpoint()), req.method(), req.uri().raw_path);
res.write_head(200, {{"content-type", {"text/event-stream", false}}});
}
void onClose(const uint32_t ec)
{
spdlog::error("{} onClose", (void*)this);
subscription.disconnect();
}
ssize_t process(uint8_t* destination, std::size_t len, uint32_t* data_flags)
{
spdlog::trace("{} process", (void*)this);
switch (state) {
case HasEvents:
return send_chunk(destination, len, data_flags);
case WaitingForEvents:
return NGHTTP2_ERR_DEFERRED;
}
__builtin_unreachable();
}
void enqueue(const std::string& what)
{
{
std::lock_guard lock{mtx};
queue.push_back("data: " + what + "\n\n");
}
state = HasEvents;
res.resume();
}
};
int main(int argc [[maybe_unused]], char** argv [[maybe_unused]])
{
spdlog::set_level(spdlog::level::trace);
Signal sig;
std::thread timer{[&sig]() {
for (int i = 0; /* forever */; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds{666});
spdlog::info("tick: {}", i);
sig("ping #" + std::to_string(i));
}
}};
server::http2 server;
server.num_threads(4);
server.handle("/events", [&sig](const server::request& req, const server::response& res) {
auto client = std::make_shared<Client>(req, res, sig);
res.on_close([client](const auto ec) {
client->onClose(ec);
});
res.end([client](uint8_t* destination, std::size_t len, uint32_t* data_flags) {
return client->process(destination, len, data_flags);
});
});
server.handle("/", [](const auto& req, const auto& resp) {
spdlog::warn("{} {} {}", boost::lexical_cast<std::string>(req.remote_endpoint()), req.method(), req.uri().raw_path);
resp.write_head(200, {{"content-type", {"text/html", false}}});
resp.end(R"(<html><head><title>nghttp2 event stream</title></head>
<body><h1>events</h1><ul id="x"></ul>
<script type="text/javascript">
const ev = new EventSource("/events");
ev.onmessage = function(event) {
const li = document.createElement("li");
li.textContent = event.data;
document.getElementById("x").appendChild(li);
};
</script>
</body>
</html>)");
});
boost::system::error_code ec;
if (server.listen_and_serve(ec, "::", "10080")) {
return 1;
}
return 0;
}
I have a feeling that my queue handling is probably too complex. When testing via curl, I never seem to run out of buffer space. In other words, even if the client is not reading any data from the socket, the library keep invoking send_chunk, asking for up to 16kB of data at a time for me. Strange. I have no idea how it works when pushing more data more heavily.
My "real code" used to have a third state, Closed, but I think that blocking events via on_close is enough here. However, I think you never want to enter send_chunk if the client has already disconnected, but before the destructor gets called.
I have a program comunication communication between two telosb. It is a example of tinyos: https://github.com/tinyos/tinyos-release/tree/tinyos-2_1_2/apps/RadioCountToLeds. This code will send and receive a value count, if the conditions meet, it will turn on the corresponding led. I want to split the code into 2 parts: Send and Receive. And i create 2 app:
Receive:
//RadioCountToLedC.nc
#include "Timer.h"
#include "RadioCountToLeds.h"
module RadioCountToLedsC #safe() {
uses {
interface Leds;
interface Boot;
interface Receive;
interface Packet;
}
}
implementation {
message_t packet;
uint16_t counter = 0;
event void Boot.booted()
{
}
event message_t* Receive.receive(message_t* bufPtr,
void* payload, uint8_t len) {
call Leds.led0On();
dbg("RadioCountToLedsC", "Received packet of length %hhu.\n", len);
if (len != sizeof(radio_count_msg_t)) {return bufPtr;}
else {
radio_count_msg_t* rcm = (radio_count_msg_t*)payload;
if (rcm->counter%3 == 0) {
call Leds.led0On();
}
else {
call Leds.led0Off();
}
if (rcm->counter%3 == 1) {
call Leds.led1On();
}
else {
call Leds.led1Off();
}
if (rcm->counter%3 == 2) {
call Leds.led2On();
}
else {
call Leds.led2Off();
}
return bufPtr;
}
}
}
//RadioToLedAppC.nc
#include "RadioCountToLeds.h"
configuration RadioCountToLedsAppC {}
implementation {
components MainC, RadioCountToLedsC as App, LedsC;
components new AMReceiverC(AM_RADIO_COUNT_MSG);
components new TimerMilliC();
components ActiveMessageC;
}
Send:
//RadioCountToLedC.nc
#include "Timer.h"
#include "RadioCountToLeds.h"
module RadioCountToLedsC #safe() {
uses {
interface Leds;
interface Boot;
interface AMSend;
interface Timer<TMilli> as MilliTimer;
interface SplitControl as AMControl;
interface Packet;
}
}
implementation {
message_t packet;
bool locked;
uint16_t counter = 0;
event void Boot.booted() {
call MilliTimer.startPeriodic(250);
call AMControl.start();
}
event void AMControl.startDone(error_t err) {
if (err == SUCCESS) {
call MilliTimer.startPeriodic(250);
}
else {
call AMControl.start();
}
}
event void AMControl.stopDone(error_t err) {
// do nothing
}
event void MilliTimer.fired() {
if(counter<100){
counter++;
}else{
counter=0;
}
dbg("RadioCountToLedsC", "RadioCountToLedsC: timer fired, counter is %hu.\n", counter);
if (locked) {
return;
}
else {
radio_count_msg_t* rcm = (radio_count_msg_t*)call Packet.getPayload(&packet, sizeof(radio_count_msg_t));
if (rcm == NULL) {
return;
}
rcm->counter = counter;
if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_count_msg_t)) == SUCCESS) {
dbg("RadioCountToLedsC", "RadioCountToLedsC: packet sent.\n", counter);
locked = TRUE;
}
}
}
event void AMSend.sendDone(message_t* bufPtr, error_t error) {
if (&packet == bufPtr) {
locked = FALSE;
}
}
}
//RadioToLedAppC.nc
#include "RadioCountToLeds.h"
configuration RadioCountToLedsAppC {}
implementation {
components MainC, RadioCountToLedsC as App, LedsC;
components new AMSenderC(AM_RADIO_COUNT_MSG);
components new AMReceiverC(AM_RADIO_COUNT_MSG);
components new TimerMilliC();
components ActiveMessageC;
App.Boot -> MainC.Boot;
App.AMSend -> AMSenderC;
App.AMControl -> ActiveMessageC;
App.Leds -> LedsC;
App.MilliTimer -> TimerMilliC;
App.Packet -> AMSenderC;
}
RadioCountToLed.h
#ifndef RADIO_COUNT_TO_LEDS_H
#define RADIO_COUNT_TO_LEDS_H
typedef nx_struct radio_count_msg {
nx_uint16_t counter;
} radio_count_msg_t;
enum {
AM_RADIO_COUNT_MSG = 6,
};
#endif
But when i run it don't work. If i write Receive and Send in same file RadioCountToLedC.nc as above example. It will work well. What's wrong with my application?
I think you need to
call AMControl.start();
In your booted function of your Receiver. This will turn the radio on and allow you to receive messages.
PS If this doesn't completely solve your problem please provide more detail on what you observe happening when you run.
The are a number of easy ways to tackle this, the easiest way is to just have a variable that controls program flow or alternatively use each nodes TinyOS ID to control flow.
For example you could have (Only 4 small changes have been made):
#include "Timer.h"
#include "RadioCountToLeds.h"
/**
* Implementation of the RadioCountToLeds application. RadioCountToLeds
* maintains a 4Hz counter, broadcasting its value in an AM packet
* every time it gets updated. A RadioCountToLeds node that hears a counter
* displays the bottom three bits on its LEDs. This application is a useful
* test to show that basic AM communication and timers work.
*
* #author Philip Levis
* #date June 6 2005
*/
module RadioCountToLedsC #safe() {
uses {
interface Leds;
interface Boot;
interface Receive;
interface AMSend;
interface Timer<TMilli> as MilliTimer;
interface SplitControl as AMControl;
interface Packet;
}
}
implementation {
message_t packet;
bool locked;
uint16_t counter = 0;
enum state {TX, RX} mode; //Change 1: Define States
event void Boot.booted() {
call AMControl.start();
mode = RX; // CHANGE 2: Set States - "RX" for receiver & "TX" for transmitter
}
event void AMControl.startDone(error_t err) {
if (err == SUCCESS) {
if(mode == TX) //CHANGE 3: Only the transmitter sends
call MilliTimer.startPeriodic(250);
}
else {
call AMControl.start();
}
}
event void AMControl.stopDone(error_t err) {
// do nothing
}
event void MilliTimer.fired() {
counter++;
dbg("RadioCountToLedsC", "RadioCountToLedsC: timer fired, counter is %hu.\n", counter);
if (locked) {
return;
}
else {
radio_count_msg_t* rcm = (radio_count_msg_t*)call Packet.getPayload(&packet, sizeof(radio_count_msg_t));
if (rcm == NULL) {
return;
}
rcm->counter = counter;
if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_count_msg_t)) == SUCCESS) {
dbg("RadioCountToLedsC", "RadioCountToLedsC: packet sent.\n", counter);
locked = TRUE;
}
}
}
event message_t* Receive.receive(message_t* bufPtr,
void* payload, uint8_t len) {
dbg("RadioCountToLedsC", "Received packet of length %hhu.\n", len);
if(mode == TX) return bufPtr; //CHANGE 4: Only RX processes packets
if (len != sizeof(radio_count_msg_t)) {return bufPtr;}
else {
radio_count_msg_t* rcm = (radio_count_msg_t*)payload;
if (rcm->counter & 0x1) {
call Leds.led0On();
}
else {
call Leds.led0Off();
}
if (rcm->counter & 0x2) {
call Leds.led1On();
}
else {
call Leds.led1Off();
}
if (rcm->counter & 0x4) {
call Leds.led2On();
}
else {
call Leds.led2Off();
}
return bufPtr;
}
}
event void AMSend.sendDone(message_t* bufPtr, error_t error) {
if (&packet == bufPtr) {
locked = FALSE;
}
}
}
Instead of setting the mode in the Booted event, you can alternatively use the C preprocessor to set the mode variable if you wish.
The problem with the receiver application that you made is that it
i) Does not start the transceiver as it does not call AMControl.start() in the Boot.Booted() event.
ii) The wiring in the RadioCountToLedsAppC is not correct as no interfaces are connected. You need to connect all interfaces (Boot, Leds, Receive and AMControl). Similar to how you had connected them in the sender.
I make an http operation(get,post etc...) by using QNetworkAccessManager. I run a few "get" operation in paralel. For this , I use QtConcurrent::run(this,&RestWebservice::GetHTTPData) to make multi HTTP operations.
My problem is When I close the app before HTTP operation does not complete , App is crashed.Application Output write this line QMutex: destroying locked mutex then write The program has unexpectedly finished.
I guest problem occurs in this line
void RestWebservice::get()
{
// mutex.lock();
m_networkManager.get(m_networkrequest);
// mutex.unlock();
}
But I am not sure because QtCreater Debugger is not good like VS.By the way , GetHTTPData is in different class.
MY CODE for start network Operation:(MobileOperation.cpp).For exapmle getUserAccount metod start a http operation.
void MobileOperations::getWorkOrderListT(int ekipId) {
MyGlobal::Metods metod=MyGlobal::EkipIsEmriListesi;
QString parameters="{EkipId}";
QMap<QString,QVariant> paramlist;
paramlist["EkipId"]=ekipId;
GetHTTPData(metod,parameters,paramlist);
if(m_workorder.IsSuccess==true)
{
// emit successupdatewo();
if(m_workorder.workorders.count()>0)
{
InsertWo(json.workorder->workorders);
emit processstop("İş Emri Listesi Güncellendi");
// QThread::sleep(2);
}
else
{
emit processstop(json.workorder->ReturnMessage);
}
emit successworkstart();
}
else
{
emit processstop("Bağlantı Başarısız Oldu");
}
}
void MobileOperations::getUserAccount(QString kullaniciAdi, QString sifre,bool isremember)
{
json.user=m_user;
QtConcurrent::run(this,&MobileOperations::getUserAccountT,kullaniciAdi,sifre,isremember);
// getUserAccountT(kullaniciAdi,sifre,isremember);
processstart("Baglaniyor");
}
void MobileOperations::GetHTTPData(MyGlobal::Metods MetodName, QString Parameters, QMap<QString, QVariant> paramlist)
{
try
{
parameter=new HttpRequest();
parameter->url=m_url;
parameter->metodname=MetodName;
parameter->resource=m_path;
parameter->appid=m_appid;
parameter->apppass=m_apppass;
parameter->parametersname=Parameters;
parameter->params=paramlist;
rest= new RestWebservice(parameter->GenerateHTTPQuery(),MetodName);
// json=new JSonParser();
// loop=new QEventLoop();
loop=new QEventLoop();
QObject::connect(rest,SIGNAL(sendhttpdata(QByteArray,MyGlobal::Metods)),&json,SLOT(onGetData(QByteArray,MyGlobal::Metods)));
QObject::connect(&json,SIGNAL(serilazitionCompleted()),loop,SLOT(quit()));
rest->get();
loop->exec();
}
catch(std::string &exp)
{
qDebug()<<"Sonlandırıldı";
}
}
MY CODE of classes For HTTP operatins :
#include "restwebservice.h"
#include <QJsonDocument>
#include<QJsonArray>
#include <QJsonObject>
#include<QJsonValue>
#include<QList>
#include <QThread>
RestWebservice::RestWebservice(QNetworkRequest request,
MyGlobal::Metods metod,
QObject* parent):QObject(parent),m_networkrequest(request),m_metodname(metod)
{
connect(&m_networkManager, SIGNAL(finished(QNetworkReply*)),this, SLOT(onResult(QNetworkReply*)));
// connect(&m_networkManager,SIGNAL())
}
void RestWebservice::get()
{
// mutex.lock();
m_networkManager.get(m_networkrequest);
// mutex.unlock();
}
void RestWebservice::post(QString request)
{
QByteArray requestA= request.toUtf8();
m_networkManager.post(m_networkrequest,requestA);
}
void RestWebservice::onResult(QNetworkReply* reply)
{
try
{
if (reply->error() != QNetworkReply::NoError)
{
qDebug()<<reply->error()<<":"<<reply->errorString();
MyGlobal::NetworkStatus=reply->errorString();
emit sendhttpdata(m_data,m_metodname);
return;
// throw(reply->errorString().toStdString());
}
QByteArray data = reply->readAll();
reply->deleteLater();
m_data=data;
MyGlobal::NetworkStatus="Tablolar Yüklendi";
emit sendhttpdata(m_data,m_metodname);
}
catch(std::string exp)
{
qDebug()<<"Exception:"<<QString::fromStdString(exp);
}
catch(std::exception &exp)
{
qDebug()<<"Exception:"<<QString::fromStdString(exp.what());
}
}
void RestWebservice::onError()
{
qDebug()<<"Hata VAR";
}
HttpRequest::HttpRequest(QObject *parent) :
QObject(parent)
{
}
QNetworkRequest HttpRequest::GenerateHTTPQuery()
{
// QString path="";
QString path=QString("/%1/%2/%3/%4/%5").arg(resource).arg(MyGlobal::getMetodName(metodname)).arg(appid).arg(apppass).arg(parametersname);
foreach (QString param, params.keys()) {
path.replace("{"+param+"}",params[param].toString());
}
QUrl m_url(url);
m_url.setPath(path);
m_request.setUrl(m_url);
m_request.setRawHeader("Content-Type","application/json;charset=utf-8");
// m_request.setRawHeader("SOAPAction","http://tempuri.org/IMobileClient/UserAuth");
qDebug()<<m_url.url();
return m_request;
}
QNetworkRequest HttpRequest::GenerateHTTPQueryPost()
{
// QString path="";
QString path=QString("/%1/%2").arg(resource).arg(MyGlobal::getMetodName(metodname));
QUrl m_url(url);
m_url.setPath(path);
m_request.setUrl(m_url);
m_request.setRawHeader("Content-Type","application/json;charset=utf-8");
// m_request.setRawHeader("SOAPAction","http://tempuri.org/IMobileClient/UserAuth");
qDebug()<<m_url.url();
return m_request;
}
Is you mutex a member of your class. In that case the mutex is destructed before it is unlocked (as I presume the containing class goes out of scope), which causes the message you see. The destructor of the mutex is called when the class is destructed, while the lock is held. This is a problem. Typically you will have to find a way to not block indefinitely during your network request.
I am trying to multiple request with QNetworkAccessManager even I connect slots QNetworkAccessManager cant emit finished() signal.
Here is the code I implemented.
void GetNetwork::getAction(QStringList *urls, QList<QByteArray> *result)
{
uint size=urls->size();
multiGetResult=result;
getUrls=urls;
setFlags();
for(uint x=0;x<size;x++)
{
int test=caluculateIndex(x);
getNAM[test]->get(QNetworkRequest(QUrl(urls->at(x))));
}
//qDebug()<<reply->readAll();
while (!waitWithFlag()) QThread::msleep(15);
delete threadFlag;
}
bool GetNetwork::setMultipleGet(uint number)
{
int diff=number-(getNAM.size()-1);
if(((getNAM.size()-1)+diff)<0)
return false;
for(int i=0;i<diff;i++)
{
getNAM.append(new QNetworkAccessManager(this));
connect(getNAM[getNAM.size()-1],SIGNAL(finished(QNetworkReply*)),this,SLOT(handleMultiRequest(QNetworkReply*)));
}
for(int i=diff;i<0;i++)
{
disconnect(getNAM[getNAM.size()-1],SIGNAL(finished(QNetworkReply*)),this,SLOT(handleMultiRequest(QNetworkReply*)));
delete getNAM[getNAM.size()-1];
getNAM.remove(getNAM.size()-1);
}
return true;
}
void GetNetwork::handleMultiRequest(QNetworkReply * reply)
{
int index=getUrls->indexOf(reply->url().toString());
if(reply->error()!=QNetworkReply::NoError||index==-1)
{
QString error=QString("Network Error file:%1 line:%2 error:%3")
.arg(__FILE__)
.arg(__LINE__)
.arg(reply->errorString());
emit errorOccured(error);
return;
}
multiGetResult->insert(index,reply->readAll());
threadFlag[index]=true;
}
What's wrong in these codes? I cant figure it out.
Thank you.
First of all you don't need a separate thread for QNetworkAccessManager as it internally runs in a separate thread (asynchronous) since Qt 4.8.1.
Secondly you are only connecting the last instance of QNetworkAccessManager with a finished slot, instead of doing that, connect each instance of QNetworkAccessManager with handleMultiRequest Slot and keep increasing the count whenever the slot is invoked. You don't need sleep and all that stuff, it is all event driven.
So,
void GetNetwork::handleMultiRequest(QNetworkReply * reply)
{
int index=getUrls->indexOf(reply->url().toString());
if(reply->error()!=QNetworkReply::NoError||index==-1)
{
QString error=QString("Network Error file:%1 line:%2 error:%3")
.arg(__FILE__)
.arg(__LINE__)
.arg(reply->errorString());
emit errorOccured(error);
return;
}
count++;
if(count == num_get_requests)
{
emit
allDone()
}
}
and I changed fucntions like Adnan idea
void GetNetwork::handleMultiRequest(QNetworkReply * reply)
{
int index=getUrls->indexOf(reply->url().toString());
if(reply->error()!=QNetworkReply::NoError||index==-1)
{
QString error=QString("Network Error file:%1 line:%2 error:%3")
.arg(__FILE__)
.arg(__LINE__)
.arg(reply->errorString());
emit errorOccured(error);
return;
}
multiGetResult->insert(index,reply->readAll());
threadDoneCounter++;
if(threadDoneCounter==getUrls->size())
emit threadsAreDone();
}
and
void GetNetwork::getAction(QStringList *urls, QList<QByteArray> *result)
{
uint size=urls->size();
multiGetResult=result;
getUrls=urls;
threadDoneCounter=0;
for(uint x=0;x<size;x++)
{
int test=caluculateIndex(x);
getNAM[test]->get(QNetworkRequest(QUrl(urls->at(x))));
}
QEventLoop eLoop;
connect(this,SIGNAL(threadsAreDone()),&eLoop,SLOT(quit()));
eLoop.exec();
disconnect(this,SIGNAL(threadsAreDone()),&eLoop,SLOT(quit()));
}
I am developing for a touch screen and need to detect touch events to turn the screen back on. I am using Qt and sockets and have run into an interesting issue.
Whenever my QSocketNotifier detects the event it sends me infinite notices about it. Therefore I need to close and open the event file to cycle the notifier (inputNotifier in the below code). The problem usually arises several minutes after the device has been running and the file (inputDevice) suddenly changes it's handle from 24 to something else (usually 17).
I am not sure what to do, because the initial connect statement is linked to the initial Notifier pointer. If I create a new Notifier using the new handle, the connect is invalid. As far as I can tell there is no option to set a new socket value on a running QSocketNotifier. Suggestions? The relevant code is below:
#include "backlightcontroller.h"
#include <QTimer>
#include <QFile>
#include <syslog.h>
#include <QDebug>
#include <QSocketNotifier>
BacklightController::BacklightController(QObject *parent) :
QObject(parent)
{
backlightActive = true;
// setup timer
trigger = new QTimer;
trigger->setSingleShot(false);
connect(trigger, SIGNAL(timeout()), SLOT(deactivateBacklight()));
idleTimer = new QTimer;
idleTimer->setInterval(IDLE_TIME * 1000);
idleTimer->setSingleShot(false);
connect(idleTimer, SIGNAL(timeout()), SIGNAL(idled()));
idleTimer->start();
// setup socket notifier
inputDevice = new QFile(USERINPUT_DEVICE);
if (!inputDevice->open(QIODevice::ReadOnly))
{
syslog (LOG_ERR, "Input file for Backlight controller could not been opened.");
}
else
{
inputNotifier = new QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
inputNotifier->setEnabled(true);
connect(inputNotifier, SIGNAL(activated(int)), SLOT(activateBacklight()));
}
qDebug()<<"backlight socket: "<<inputNotifier->socket();
// read out settings-file
QString intensity = Global::system_settings->getValue("BelatronUS_backlight_intensity");
if (intensity.length() == 0) intensity = "100";
QString duration = Global::system_settings->getValue("BelatronUS_backlight_duration");
if (duration.length() == 0) duration = "180";
QString always_on = Global::system_settings->getValue("BelatronUS_backlight_always_on");
if (always_on.length() == 0) always_on = "0";
setIntensity(intensity.toInt());
setDuration(duration.toInt());
if (always_on == "0")
setAlwaysOn(false);
else
setAlwaysOn(true);
}
BacklightController::~BacklightController()
{
trigger->stop();
inputNotifier->setEnabled(false);
inputDevice->close();
delete trigger;
delete inputDevice;
delete inputNotifier;
}
void BacklightController::setCurrentIntensity(int intensity)
{
// adapt backlight intensity
QFile backlightFile("/sys/class/backlight/atmel-pwm-bl/brightness");
if (!backlightFile.open(QIODevice::WriteOnly))
{
syslog (LOG_ERR, "Backlight intensity file could not been opened.");
}
else
{
QString intensityString = QString::number(TO_BRIGHTNESS(intensity));
if (backlightFile.write(
qPrintable(intensityString), intensityString.length()
) < intensityString.length())
{
syslog (LOG_ERR, "Backlight intensity could not been changed.");
}
backlightFile.close();
}
}
void BacklightController::resetNotifier()
{
inputDevice->close();
if (!inputDevice->open(QIODevice::ReadOnly))
{
syslog (LOG_ERR, "BacklightController::%s: Input file could not been opened.", __FUNCTION__);
}
qDebug()<<"reset, handle: "<<inputDevice->handle();
//inputNotifier=QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
// restart timer after user input
idleTimer->start();
}
void BacklightController::activateBacklight()
{
// only activate backlight, if it's off (avoid to useless fileaccess)
if (!backlightActive)
{
setCurrentIntensity(_intensity);
backlightActive = true;
emit backlightActivated();
}
// restart backlight timeout, but only if we don't want the backlight to shine all the time
if (!_alwaysOn)
trigger->start();
// reset notifier to be able to catch the next userinput
resetNotifier();
}
void BacklightController::deactivateBacklight()
{
// don't turn it off, if it's forced on
if (!_alwaysOn)
{
if (backlightActive)
{
// only deactivate backlight, if it's on (avoid to useless fileaccess)
setCurrentIntensity(BACKLIGHT_INTENSITY_OFF);
backlightActive = false;
emit backlightDeactivated();
}
}
qDebug()<<"trigger stopping";
trigger->stop();
}
void BacklightController::setIntensity(int intensity)
{
if (intensity > 100)
intensity = 100;
else if (intensity < 0)
intensity = 0;
_intensity = intensity;
// write new intensity to file if it's active at the moment
if (backlightActive)
{
setCurrentIntensity(_intensity);
trigger->start();
}
}
void BacklightController::setDuration(int duration)
{
if (duration < 1)
duration = 1;
_duration = duration;
trigger->setInterval(_duration * MS_IN_SEC);
// reset trigger after changing duration
if (backlightActive)
{
trigger->start();
}
}
void BacklightController::setAlwaysOn(bool always_on)
{
_alwaysOn = always_on;
// tell the timer what to to now
if (_alwaysOn)
{
this->activateBacklight();
trigger->stop();
}
else
{
trigger->start();
}
}
I seem to have found a working solution for now. It's not the greatest so if there are better solutions I would be interested to hear them. The reason I did not think of this before is because I thought if I had a new connect statement in a function it would have limited scope as the function ended.
The solution was to simply check for an occurrence of the handle change in the file and then create a new pointer for the notifier using that handle. Then re-enable the notifier because it has likely been disabled by now and then create a new connect statement for the pointer. This is the code I used, added just below the closing and reopening of the event file:
if(inputDevice->handle()!=inputNotifier->socket()){
inputNotifier = new QSocketNotifier(inputDevice->handle(), QSocketNotifier::Read);
inputNotifier->setEnabled(true);
connect(inputNotifier, SIGNAL(activated(int)), SLOT(activateBacklight()));
}