0

I am using the BGLib in my Qt application to communicate over BLE.

In the main thread the GUI is running (sensornode_gui.cpp). By clicking on a pushButton a different thread starts to scan for BLE devices (ble_connection). I get the resulting information from a callback function such as void ble_evt_gap_scan_response(const struct ble_msg_gap_scan_response_evt_t *msg). How can I emit signals from that callback function to update the GUI with some attributes from msg for example?

main.cpp

#include "sensornode_gui.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    SensorNode_GUI w;
    w.show();
    return a.exec();
}

sensornode_gui.h

#ifndef SENSORNODE_GUI_H
#define SENSORNODE_GUI_H

#include <QMainWindow>
#include <QThread>
#include "ble_connection.h"

namespace Ui {
class SensorNode_GUI;
}

class SensorNode_GUI : public QMainWindow
{
    Q_OBJECT

public:
    explicit SensorNode_GUI(QWidget *parent = 0);
    ~SensorNode_GUI();
    void printText(std::string s);

private slots:
    void on_pushButtonStartScanning_clicked();

private:
    Ui::SensorNode_GUI *ui;
    QThread *thread;
    BLE_Connection *ble_worker;

};

#endif // SENSORNODE_GUI_H

sensornode_gui.cpp

#include "sensornode_gui.h"
#include "ui_sensornode_gui.h"

SensorNode_GUI::SensorNode_GUI(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::SensorNode_GUI)
{
    ui->setupUi(this);

    thread = new QThread();
    ble_worker = new BLE_Connection();
    ble_worker->setGUI(this);

    ble_worker->moveToThread(thread);
    connect(ble_worker, SIGNAL(valueChanged(QString)), ui->textEdit, SLOT(append(QString)));
    connect(ble_worker, SIGNAL(workRequested()), thread, SLOT(start()));
    connect(thread, SIGNAL(started()), ble_worker, SLOT(doWork()));
}

SensorNode_GUI::~SensorNode_GUI()
{
    delete thread;
    delete ble_worker;

    delete ui;
}

void SensorNode_GUI::printText(std::string s){
    ui->textEdit->append(QString::fromStdString(s));
}

void SensorNode_GUI::on_pushButtonStartScanning_clicked()
{
    ble_worker->requestWork();
}

ble_connection.h

#ifndef BLE_CONNECTION_H
#define BLE_CONNECTION_H

#include <QObject>
#include <QMutex>
#include <QDebug>
#include <QThread>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "cmd_def.h"
#include "apitypes.h"
#include "sensornode_gui.h"

class SensorNode_GUI;

class BLE_Connection : public QObject
{
    Q_OBJECT

public:
    explicit BLE_Connection(QObject *parent = 0);
    static void output(uint8,uint8*,uint16,uint8*);
    int read_message();
    void connect();
    void disconnect();

    void requestWork();

private:
    bool _abort;
    bool _working;
    QMutex mutex;

signals:
    void workRequested();
    void valueChanged(const QString &value);

public slots:
    void doWork();
};

#endif // BLE_CONNECTION_H

ble_connection.cpp

#include "ble_connection.h"

volatile HANDLE serial_handle;
uint8 connection_handle;

BLE_Connection::BLE_Connection(QObject *parent) :
    QObject(parent)
{
    char str[80];
    snprintf(str,sizeof(str)-1,"\\\\.\\%s","COM3");
    //open I/O device
    ...

    bglib_output = output;

}


void BLE_Connection::setGUI(SensorNode_GUI *g)
{
    gui = g;
}

void BLE_Connection::requestWork()
{
    mutex.lock();
    _working = true;
    _abort = false;
    qDebug()<<"Request worker start in Thread "<<thread()->currentThreadId();
    mutex.unlock();

    emit workRequested();
}


void BLE_Connection::doWork()
{
    while(true){
        read_message();
        qDebug() << "Within doWork";
        emit valueChanged(QString::fromStdString("Test"));
    }
}

void BLE_Connection::output(uint8 len1,uint8* data1,uint16 len2,uint8* data2)
{
    ...
}

int BLE_Connection::read_message()
{
    DWORD rread;
    const struct ble_msg *apimsg;
    struct ble_header apihdr;
    unsigned char data[256];//enough for BLE
    //read header

    if(!ReadFile(serial_handle,
               (unsigned char*)&apihdr,
               4,
               &rread,
               NULL))
        {
            return GetLastError();
        }
    if(!rread)return 0;
    //read rest if needed
    if(apihdr.lolen)
    {
        if(!ReadFile(serial_handle,
                   data,
                   apihdr.lolen,
                   &rread,
                   NULL))
            {
                return GetLastError();
            }
    }
    apimsg=ble_get_msg_hdr(apihdr);
    if(!apimsg)
    {
        printf("ERROR: Message not found:%d:%d\n",(int)apihdr.cls,(int)apihdr.command);
        return -1;
    }
    apimsg->handler(data);

    return 0;
}


//=============FUNCTIONS FOR HANDELING EVENTS AND RESPONSES====================


void ble_evt_gap_scan_response(const struct ble_msg_gap_scan_response_evt_t *msg)
{
    int i;
    std::string buffAsStdStr;
    char buff[100];
    char *name = NULL;
    for(i=0;i<6;i++){
        snprintf(buff, sizeof(buff), "%02x%s",msg->sender.addr[5-i],i<5?":":"");
        buffAsStdStr += buff;
    }


    snprintf(buff, sizeof(buff), "\t%d",msg->rssi);
    buffAsStdStr += buff;
    //HERE I WANT TO EMIT THE SIGNAL VALUECHANGED
    //emit valueChanged(QString::fromStdString(buffAsStdStr));

    free(name);
}

Thanks in advance.

schnarchnase
  • 13
  • 1
  • 8

2 Answers2

1

I have faced to the same problem at using a different library. I have solved this issue by wrapping library class with mine (CameraWrapper), and put object of this class into my class (MeasurementSystem) inherited from QObject. So when this parent class creates wrapper for the class that sends callback, it passes pointer to itself QObject*. Child chass (CameraWrapper) stores this pointer and sends it within the callback.

Looks like this:

MeasurementSystem.h

#ifndef MEASUREMENTSYSTEM_H
#define MEASUREMENTSYSTEM_H
#include <vector>
#include "camerawrapper.h"
#include "qobject.h"

class MeasurementSystem : public QObject
{
    Q_OBJECT
public:
    MeasurementSystem();
    enum CamAlign {caTopInner = 0,caTopOuter,caBottomInner,caBottomOuter,caSide};   //cameras alignment in optical sysem


    void Connect();
    void Disconnect();
signals:
    void sigDataReceived(int,std::vector<int>);

private:
    std::vector<CameraWrapper*> _cams;
    friend void DataReceived(QObject * Sender, int &, std::vector<int>&);       //callback function for receiving data from any camera
};

#endif // MEASUREMENTSYSTEM_H

MeasurementSystem.cpp

#include "measurementsystem.h"
#include <QApplication>
MeasurementSystem::MeasurementSystem()
{
    QString path = QApplication::applicationDirPath();
    _cams.push_back(new CameraWrapper(this,*DataReceived,(path+"/CameraSettings/Ranger D50 TopInner.icx").toStdString(),"192.168.1.11","CamTopInner",caTopInner));
    _cams.push_back(new CameraWrapper(this,*DataReceived,(path+"/CameraSettings/Ranger D50 TopInner.icx").toStdString(),"192.168.1.12","CamTopOuter",caTopOuter));
    _cams.push_back(new CameraWrapper(this,*DataReceived,(path+"/CameraSettings/Ranger D50 TopInner.icx").toStdString(),"192.168.1.13","CamBottomInner",caBottomInner));
    _cams.push_back(new CameraWrapper(this,*DataReceived,(path+"/CameraSettings/Ranger D50 TopInner.icx").toStdString(),"192.168.1.14","CamBottomOuter",caBottomOuter));
    _cams.push_back(new CameraWrapper(this,*DataReceived,(path+"/CameraSettings/Ranger D50 TopInner.icx").toStdString(),"192.168.1.15","CamSide",caSide));
}

void MeasurementSystem::Connect()
{
    foreach (CameraWrapper* cam, _cams)
    {
        cam->Connect();
    }
}

void MeasurementSystem::Disconnect()
{
    foreach (CameraWrapper* cam, _cams)
    {
        cam->Disconnect();
    }
}

void DataReceived(QObject * Sender, int & CamId, std::vector<int> & Profile)
{
    MeasurementSystem * CamSys = reinterpret_cast<MeasurementSystem*>(Sender);
    emit CamSys->sigDataReceived(CamId,Profile);
}

CameraWrapper.h

#ifndef CAMERAWRAPPER_H
#define CAMERAWRAPPER_H

#include <QObject>
#include <icamerasystem.h>
#include <icamerasystemsubscriber.h>
#include <icon_error.h>
#include <windows.h>
typedef void CallbackDataT(QObject*,int&,std::vector<int>&);

class CameraWrapper : public icon::ICameraSystemSubscriber, public icon::ErrorHandler
{
public:
    CameraWrapper(QObject * Parent, CallbackDataT callback, std::string ConfigFileIcx, std::string IpAddr, std::string Name, int Id = -1);
    void Connect();
    void Disconnect();
    int AccessData(const icon::IconBuffer *buffer, std::string& resultString);
    virtual void onData(const icon::IconBuffer * buffer, const icon::IGrabStatus * status);
    virtual void onError(const icon::IError &error){};
    virtual void onStateChanged(const icon::IState * state){};

private:
    //IconAPI objects
    icon::ErrorCode _res;                                           //result of some camera operations
    icon::ICameraSystem * _camSystem;                               //the camera itself

    //callbacks
    void (*_callbackData)(QObject*,int&, std::vector<int>&);        //called when buffer is parsed

    //proprieties
    int _id;                                                        //camera identifier
    std::string _name;                                              //camera name

    //parent
    QObject * _parent;
};
#endif // CAMERAWRAPPER_H   

CameraWrapper.cpp

#include "camerawrapper.h"
#include <qdebug.h>             //qdebug()


CameraWrapper::CameraWrapper(QObject * Parent, CallbackDataT Callback, std::string ConfigFileIcx, std::string IpAddr, std::string Name, int Id):
    _parent(Parent), _callbackData(Callback), _id(Id), _name(Name)
{
    //Create the camera system object
    _camSystem = icon::createCameraSystem(icon::ICameraSystem::ETHERNET_CAMERA, Name.c_str());
    //smth else
}

void CameraWrapper::Connect()
{
    _res = _camSystem->subscribe(*this);
    _res = _camSystem->connect();
    _res = _camSystem->start();
}

void CameraWrapper::Disconnect()
{
    _res = _camSystem->stop();
    _res = _camSystem->disconnect();
}

int CameraWrapper::AccessData(const icon::IconBuffer * buffer, std::string& resultString)
{
    std::vector<int> vProfile;
    // Loop through all components in the buffer
    const icon::DataFormat *dataFormat = buffer->getDataFormat();
    for (unsigned int compIndex = 0; compIndex < dataFormat->numComponents(); compIndex++)
    {
        // Get handle to component.
        const icon::Component *component = dataFormat->getComponent(compIndex);

        // Loop through all subcomponents of the component.
        for (unsigned int subCompIndex = 0; subCompIndex < component->numSubComponents(); subCompIndex++)
        {
            const icon::SubComponent *subComponent = component->getSubComponent(subCompIndex);
            unsigned int subCompWidth = subComponent->getWidth();

            const unsigned short *wordData;
            unsigned short wordValue;
            buffer->getReadPointer(component->getName().c_str(), subComponent->getName().c_str(), 0, wordData);
            //rsv:push current scan into vector(profile view)
            for (size_t i = 0; i < subCompWidth; i++)
            {
                wordValue = *(wordData + i);
                vProfile.push_back(static_cast<int>(wordValue));
            } 
        }
    }
    //callback is here
    _callbackData(_parent,_id,vProfile);
    return 0;
}

void CameraWrapper::onData(const icon::IconBuffer * buffer, const icon::IGrabStatus * status)
{
    if (!(status->allOK()))
    {
        return;
    }
    AccessData(buffer, outString);
}
0

You May declare a global variable in "ble_connection.h"

static bool messageCaptured;
static std::string message;

in BLE_Connection class constructer initialization value is false;

messageCaptured = false;

Now; if your Callback function is called any time you should set

messageCaptured = true;

in your CallbackFunction.

Now you can emit Captured Message in your doWork function

void BLE_Connection::doWork()
{
    while(true){
        read_message();
        qDebug() << "Within doWork";
        if( messageCaptured ){
           /// do your process
           emit valueChanged(QString::fromStdString(message);
         messageCaptured = false;
         }            
    }
}

in callback function capture message if capturing proccess is finished before

void ble_evt_gap_scan_response(const struct 
ble_msg_gap_scan_response_evt_t *msg)
    {
        int i;
        std::string buffAsStdStr;
        char buff[100];
        char *name = NULL;
        for(i=0;i<6;i++){
            snprintf(buff, sizeof(buff), "%02x%s",msg->sender.addr[5-i],i<5?":":"");
            buffAsStdStr += buff;
        }


        snprintf(buff, sizeof(buff), "\t%d",msg->rssi);
        buffAsStdStr += buff;

        // if message captured before you can take it
        if( !messageCaptured ){
            message = buffAsStdStr;
            messageCaptured = true;
        }

        free(name);
    }
CMLDMR
  • 334
  • 2
  • 12