-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add Qt UDP sender and receiver example for the library usage
- Loading branch information
1 parent
039ef89
commit b20fa25
Showing
3 changed files
with
308 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(×tamp, 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(×tamp, 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(×tamp, 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |