diff --git a/examples/qt_socket/UdpCommunicator.h b/examples/qt_socket/UdpCommunicator.h new file mode 100644 index 0000000..96632eb --- /dev/null +++ b/examples/qt_socket/UdpCommunicator.h @@ -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 +#include + +#include +#include + +#include +#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(), 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(transformerData.humidity) << "\n" + << " Energy consumed: " << transformerData.energyConsumed << "\n" + << " Peak load: " << transformerData.peakLoad << "\n" + << " Status flags: " << static_cast(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(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 m_readBuffer; + bytepack::binary_stream<> m_readStream; +}; + +#endif // QT_UDP_UDPCOMMUNICATOR_H diff --git a/examples/qt_socket/messages.h b/examples/qt_socket/messages.h new file mode 100644 index 0000000..2f80979 --- /dev/null +++ b/examples/qt_socket/messages.h @@ -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 +#include +#include + +#include + +#include + +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 \ No newline at end of file diff --git a/examples/qt_socket/qt_udp_main.cpp b/examples/qt_socket/qt_udp_main.cpp new file mode 100644 index 0000000..8297761 --- /dev/null +++ b/examples/qt_socket/qt_udp_main.cpp @@ -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 + +#include + +#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(); +}