Skip to content

Commit

Permalink
add Qt UDP sender and receiver example for the library usage
Browse files Browse the repository at this point in the history
  • Loading branch information
farukeryilmaz committed Jan 9, 2024
1 parent 039ef89 commit b20fa25
Show file tree
Hide file tree
Showing 3 changed files with 308 additions and 0 deletions.
127 changes: 127 additions & 0 deletions examples/qt_socket/UdpCommunicator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* BytePack Example Codes
*
* The example codes provided in this file are for demonstration purposes only.
* These examples are not covered under the BytePack library's main license.
* Users are free to use, modify, and distribute these example codes as they wish.
*/

#ifndef QT_UDP_UDPCOMMUNICATOR_H
#define QT_UDP_UDPCOMMUNICATOR_H

#include <iostream>
#include <array>

#include <QUdpSocket>
#include <QByteArray>

#include <bytepack/bytepack.hpp>
#include "messages.h"

class UdpCommunicator : public QObject
{
Q_OBJECT

public:
explicit UdpCommunicator(quint16 port, QObject* parent = nullptr)
: QObject(parent), m_socket(new QUdpSocket(this)), m_readBuffer{}, m_readStream(bytepack::buffer_view(m_readBuffer))
{
// Bind the socket to listen for incoming messages
m_socket->bind(QHostAddress::Any, port);
connect(m_socket, &QUdpSocket::readyRead, this, &UdpCommunicator::onReadyRead);
}

void sendMessage(const QHostAddress& address, quint16 port, const CircuitBreakerControl& circuitBreakerControl)
{
m_writeStream.reset();
circuitBreakerControl.serialize(m_writeStream);

auto serializedData = m_writeStream.data();
m_socket->writeDatagram(serializedData.as<const char>(), serializedData.ssize(), address, port);
}

private slots:
void onReadyRead()
{
while (m_socket->hasPendingDatagrams()) {
// m_socket->pendingDatagramSize();
QHostAddress sender;
quint16 senderPort;

m_socket->readDatagram(m_readBuffer.data(), std::ssize(m_readBuffer), &sender, &senderPort);

processMessages(sender, senderPort);
}
}

private:
void processMessages(const QHostAddress& sender, quint16 senderPort)
{
m_readStream.reset();

MessageType messageType{};
m_readStream.read(messageType);

switch (messageType) {
case MessageType::TransformerData:
{
TransformerData transformerData{};
const bool isValid = transformerData.deserialize(m_readStream);
if (isValid) {
std::cout << "Transformer data:\n"
<< " Timestamp: " << transformerData.timestamp << "\n"
<< " Identifier: " << transformerData.identifier << "\n"
<< " Serial number: " << transformerData.serial_number << "\n"
<< " Voltage: (" << transformerData.voltage[0] << ", " << transformerData.voltage[1] << ", "
<< transformerData.voltage[2] << ")\n"
<< " Current: (" << transformerData.current[0] << ", " << transformerData.current[1] << ", "
<< transformerData.current[2] << ")\n"
<< " Power factor: " << transformerData.power_factor << "\n"
<< " Temperature: " << transformerData.temperature << "\n"
<< " Humidity: " << static_cast<int>(transformerData.humidity) << "\n"
<< " Energy consumed: " << transformerData.energyConsumed << "\n"
<< " Peak load: " << transformerData.peakLoad << "\n"
<< " Status flags: " << static_cast<int>(transformerData.status_flags) << "\n"
<< " Alarm codes: " << transformerData.alarm_codes << "\n"
<< " Reserved: (" << transformerData.reserved[0] << ", " << transformerData.reserved[1] << ", "
<< transformerData.reserved[2] << ")\n";

} else {
std::cout << "Corrupted transformer data message!\n";
}
break;
}
case MessageType::CircuitBreakerStatus:
{
CircuitBreakerStatus circuitBreakerStatus{};
const bool isValid = circuitBreakerStatus.deserialize(m_readStream);
if (isValid) {
std::cout << "Circuit breaker status:\n"
<< " Timestamp: " << circuitBreakerStatus.timestamp << "\n"
<< " Circuit ID: " << circuitBreakerStatus.circuit_id << "\n"
<< " Is open: " << std::boolalpha << circuitBreakerStatus.is_open << "\n"
<< " Trip count: " << static_cast<int>(circuitBreakerStatus.trip_count) << "\n"
<< " Last trip time: " << circuitBreakerStatus.last_trip_time << "\n"
<< " Fault description: " << circuitBreakerStatus.fault_description << "\n"
<< " Reserved: (" << circuitBreakerStatus.reserved[0] << ", " << circuitBreakerStatus.reserved[1]
<< ", " << circuitBreakerStatus.reserved[2] << ")\n";

} else {
std::cout << "Corrupted circuit breaker status message!\n";
}
break;
}
default:
std::cout << "Invalid or corrupted message!\n";
}
}

private:
QUdpSocket* m_socket;
bytepack::binary_stream<> m_writeStream{ 1024 * 10 }; // Adjust buffer size as needed

std::array<char, 1024 * 10> m_readBuffer;
bytepack::binary_stream<> m_readStream;
};

#endif // QT_UDP_UDPCOMMUNICATOR_H
148 changes: 148 additions & 0 deletions examples/qt_socket/messages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* BytePack Example Codes
*
* The example codes provided in this file are for demonstration purposes only.
* These examples are not covered under the BytePack library's main license.
* Users are free to use, modify, and distribute these example codes as they wish.
*/

#ifndef QT_UDP_MESSAGES_H
#define QT_UDP_MESSAGES_H

#include <cstdint>
#include <array>
#include <string>

#include <boost/crc.hpp>

#include <bytepack/bytepack.hpp>

enum class MessageType : uint8_t { TransformerData = 10, CircuitBreakerStatus = 11 };

struct TransformerData
{
int64_t timestamp;
uint32_t identifier;
char serial_number[20];
float voltage[3]; // Voltage levels for three phases
float current[3]; // Current levels for three phases
float power_factor;
float temperature;
uint8_t humidity;
uint32_t energyConsumed; // Total energy consumed
uint32_t peakLoad; // Peak load recorded
uint8_t status_flags;
uint16_t alarm_codes;
uint32_t reserved[3]; // Reserved for future use
uint32_t crc32;

void serialize(bytepack::binary_stream<>& stream) const
{
stream.write(timestamp, identifier, serial_number, voltage, current, power_factor, temperature, humidity,
energyConsumed, peakLoad, status_flags, alarm_codes, reserved);
stream.write(computeCRC32());
}

bool deserialize(bytepack::binary_stream<>& stream)
{
stream.read(timestamp, identifier, serial_number, voltage, current, power_factor, temperature, humidity,
energyConsumed, peakLoad, status_flags, alarm_codes, reserved, crc32);
return verifyCRC32();
}

private:
[[nodiscard]] uint32_t computeCRC32() const
{
boost::crc_32_type crcComputer;
crcComputer.process_bytes(&timestamp, sizeof(timestamp));
crcComputer.process_bytes(&identifier, sizeof(identifier));
crcComputer.process_bytes(serial_number, sizeof(serial_number));
crcComputer.process_bytes(voltage, sizeof(voltage));
crcComputer.process_bytes(current, sizeof(current));
crcComputer.process_bytes(&power_factor, sizeof(power_factor));
crcComputer.process_bytes(&temperature, sizeof(temperature));
crcComputer.process_bytes(&humidity, sizeof(humidity));
crcComputer.process_bytes(&energyConsumed, sizeof(energyConsumed));
crcComputer.process_bytes(&peakLoad, sizeof(peakLoad));
crcComputer.process_bytes(&status_flags, sizeof(status_flags));
crcComputer.process_bytes(&alarm_codes, sizeof(alarm_codes));
crcComputer.process_bytes(reserved, sizeof(reserved));
return crcComputer.checksum();
}

[[nodiscard]] bool verifyCRC32() const { return crc32 == computeCRC32(); }
};

struct CircuitBreakerStatus
{
int64_t timestamp;
uint32_t circuit_id;
bool is_open;
uint8_t trip_count;
uint32_t last_trip_time;
char fault_description[80];
int32_t reserved[3]; // Reserved for future use
uint32_t crc32;

void serialize(bytepack::binary_stream<>& stream) const
{
stream.write(timestamp, circuit_id, is_open, trip_count, last_trip_time, fault_description, reserved);
stream.write(computeCRC32());
}

[[nodiscard]] bool deserialize(bytepack::binary_stream<>& stream)
{
stream.read(timestamp, circuit_id, is_open, trip_count, last_trip_time, fault_description, reserved, crc32);
return verifyCRC32();
}

private:
[[nodiscard]] uint32_t computeCRC32() const
{
boost::crc_32_type crcComputer;
crcComputer.process_bytes(&timestamp, sizeof(timestamp));
crcComputer.process_bytes(&circuit_id, sizeof(circuit_id));
crcComputer.process_bytes(&is_open, sizeof(is_open));
crcComputer.process_bytes(&trip_count, sizeof(trip_count));
crcComputer.process_bytes(&last_trip_time, sizeof(last_trip_time));
crcComputer.process_bytes(fault_description, sizeof(fault_description));
crcComputer.process_bytes(reserved, sizeof(reserved));
return crcComputer.checksum();
}

[[nodiscard]] bool verifyCRC32() const { return crc32 == computeCRC32(); }
};

struct CircuitBreakerControl
{
int64_t timestamp;
uint32_t circuit_id;
bool reset; // Command to reset the circuit breaker
uint32_t crc32;

void serialize(bytepack::binary_stream<>& stream) const
{
stream.write(timestamp, circuit_id, reset);
stream.write(computeCRC32());
}

bool deserialize(bytepack::binary_stream<>& stream)
{
stream.read(timestamp, circuit_id, reset, crc32);
return verifyCRC32();
}

private:
[[nodiscard]] uint32_t computeCRC32() const
{
boost::crc_32_type crcComputer;
crcComputer.process_bytes(&timestamp, sizeof(timestamp));
crcComputer.process_bytes(&circuit_id, sizeof(circuit_id));
crcComputer.process_bytes(&reset, sizeof(reset));
return crcComputer.checksum();
}

[[nodiscard]] bool verifyCRC32() const { return crc32 == computeCRC32(); }
};

#endif // QT_UDP_MESSAGES_H
33 changes: 33 additions & 0 deletions examples/qt_socket/qt_udp_main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* BytePack Example Codes
*
* The example codes provided in this file are for demonstration purposes only.
* These examples are not covered under the BytePack library's main license.
* Users are free to use, modify, and distribute these example codes as they wish.
*/

#include <iostream>

#include <QCoreApplication>

#include "UdpCommunicator.h"

int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);

std::cout << "Server started!" << std::endl;

quint16 localPort = 1234;
UdpCommunicator communicator(localPort);

QHostAddress destAddress("10.0.0.2");
quint16 destPort = 55555;

CircuitBreakerControl circuitBreakerControl{ 123456789, 12345, true };
communicator.sendMessage(destAddress, destPort, circuitBreakerControl);

std::cout << "Data sent!" << std::endl;

return app.exec();
}

0 comments on commit b20fa25

Please sign in to comment.