Raspberry Pi Device Discovery

Before you begin, ensure you have a method of developing on your PI (either remotely or locally). I am doing my development on windows so here is the tutorial I followed to setup a shared drive

http://blogs.arcsoftwareconsultancy.com/pi/2013/03/07/windows-networking/

Now onto the code!

Device discovery is a pretty common way to identify multiple devices within a local network. It is not the best way but definitely a great place to start.

The idea of this code is that a PC will broadcast a UDP message with the datagram “request” and all PI’s listening will response with a UDP packet of their own with a datagram of “PI”.

Below is the C++ code for the PI (Qt GUI Application)

First we need a GUI so layout a GUI similiar to the one below:

 

gui

Its a very simple layout (horizontal layout) with 2 buttons and a treeview.

We need 1 class for this project. Make a class called MyUDP, below is the header file.

In the dialog cpp, insert the following code
#include "maindialog.h"
#include "ui_maindialog.h"

MainDialog::MainDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::MainDialog)
{
    ui->setupUi(this);
    //create a UDP class
    udp = new MyUDP(this);
    /*
     * connect UDP on readRady to onUDPreceived
     * so when a reply comes in, the table with add the IP to the table
     * if the table does not already contain the IP
     */
    connect(udp, SIGNAL(updateList(QString)), this, SLOT(onUDPReceived(QString)));
}

MainDialog::~MainDialog()
{
    delete ui;
}

void MainDialog::on_btnClear_clicked()
{
    //clear table list
    currentIPs.clear();
    ui->tableWidget->setRowCount(0); //clear out the rows

}

void MainDialog::on_btnSearch_clicked()
{
    //send UDP broadcast
    udp->deviceDiscover();
}

void MainDialog::onUDPReceived(QString address)
{
    //update table when new packet is received
    qDebug() << "Updating list";
    if(!currentIPs.contains(address)){
        currentIPs.append(address);
        int row = ui->tableWidget->rowCount();
        ui->tableWidget->insertRow(row);
        ui->tableWidget->setItem(row, 0, new QTableWidgetItem("Pi"));
        ui->tableWidget->setItem(row, 1, new QTableWidgetItem(address));
    }
}

For our classes we need a UDP object that can connect to a socket and send datagrams. Here is the header file:

#ifndef MYUDP_H
#define MYUDP_H

#include <QObject>
#include <QDebug>
#include <QUdpSocket>
#include <QNetworkInterface>

class MyUDP : public QObject
{
    Q_OBJECT
public:
    explicit MyUDP(QObject *parent = 0);
    void deviceDiscover();

signals:
    void updateList(QString IP);

public slots:
    void readyRead();
private:
    QUdpSocket *socket;
    QHostAddress localAddress;
    QHostAddress bcastAddress;

};
#endif // MYUDP_H
#include "myudp.h"

MyUDP::MyUDP(QObject *parent) :
    QObject(parent)
{
    qDebug() << "Binding UDP Socket";
    socket = new QUdpSocket(this);
    socket->bind(QHostAddress::Any, 5000); //bind to 5000
    connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
}

void MyUDP::deviceDiscover(){
    QByteArray data;
    data.append("Request");
    qDebug() << "Sending broadcast";
    socket->writeDatagram(data, QHostAddress::Broadcast, 5000); //broadcast from port 5000
}

void MyUDP::readyRead(){
    QByteArray buffer;
    buffer.resize(socket->pendingDatagramSize());
    //var to store headers from udp
    QHostAddress sender;
    quint16 sender_port;
    socket->readDatagram(buffer.data(),buffer.size(), &sender, &sender_port);
    qDebug() << "Message from " << sender << " port " << sender_port;
    qDebug() << "Msg: " << buffer;
    if(QString(buffer).compare("PI")==0){
        //add to list
        emit(updateList(sender.toString()));
    }

}

The main in a console application is left untouched, the main dialog becomes the main of our program.


On our Pi we need a similar structure but we only need it to respond:


#ifndef MYUDP_H
#define MYUDP_H

#include <QObject>
#include <QUdpSocket>
#include <QDebug>
#include <QNetworkInterface>

/*
 Small packets
 Very fast
 Good for multicast/broadcast
 Pings
 Unreliable, no 3-way handshake
*/
class MyUDP : public QObject
{
 Q_OBJECT
public:
 explicit MyUDP(QObject *parent = 0);
signals:

public slots:
 void readyRead();

private:
 QUdpSocket *socket;
};

#endif // MYUDP_H

And the CPP file:


#include "myudp.h"

MyUDP::MyUDP(QObject *parent) :
 QObject(parent)
{
 qDebug() << "Binding UDP Socket";
 socket = new QUdpSocket(this);
 socket->bind(QHostAddress::Any, 5000); //bind to 5000
 connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
 QByteArray data;
 data.append("PI");
 socket->writeDatagram(data, QHostAddress::Broadcast, 5000); //broadcast from port 5000
}

void MyUDP::readyRead(){
 QByteArray buffer;
 buffer.resize(socket->pendingDatagramSize());
 //var to store headers from udp
 QHostAddress sender;
 quint16 sender_port;
 socket->readDatagram(buffer.data(),buffer.size(), &sender, &sender_port);
 qDebug() << "Message from " << sender << " port " << sender_port;
 qDebug() << "Msg: " << buffer;
 if(QString(buffer).compare("Request")==0){
 QByteArray data;
 data.append("PI");
 socket->writeDatagram(data, sender, 5000); //reply back with a PI
 }
}

And finally the main:


#include <QCoreApplication>
#include "myudp.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyUDP server;
return a.exec();
}

Now set the code to run automatically when Linux starts. I will post a tutorial of my own later but here’s a link for those who do not know how:http://dalank.com/blog/?p=368

Posted on June 19, 2013, in Projects. Bookmark the permalink. Leave a comment.

Leave a comment