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:
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_HAnd 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
Comments 0