diff --git a/simulation/VirtualLedBoard/.gitignore b/simulation/VirtualLedBoard/.gitignore
new file mode 100644
index 0000000..fab7372
--- /dev/null
+++ b/simulation/VirtualLedBoard/.gitignore
@@ -0,0 +1,73 @@
+# This file is used to ignore files which are generated
+# ----------------------------------------------------------------------------
+
+*~
+*.autosave
+*.a
+*.core
+*.moc
+*.o
+*.obj
+*.orig
+*.rej
+*.so
+*.so.*
+*_pch.h.cpp
+*_resource.rc
+*.qm
+.#*
+*.*#
+core
+!core/
+tags
+.DS_Store
+.directory
+*.debug
+Makefile*
+*.prl
+*.app
+moc_*.cpp
+ui_*.h
+qrc_*.cpp
+Thumbs.db
+*.res
+*.rc
+/.qmake.cache
+/.qmake.stash
+
+# qtcreator generated files
+*.pro.user*
+
+# xemacs temporary files
+*.flc
+
+# Vim temporary files
+.*.swp
+
+# Visual Studio generated files
+*.ib_pdb_index
+*.idb
+*.ilk
+*.pdb
+*.sln
+*.suo
+*.vcproj
+*vcproj.*.*.user
+*.ncb
+*.sdf
+*.opensdf
+*.vcxproj
+*vcxproj.*
+
+# MinGW generated files
+*.Debug
+*.Release
+
+# Python byte code
+*.pyc
+
+# Binaries
+# --------
+*.dll
+*.exe
+
diff --git a/simulation/VirtualLedBoard/VirtualLedBoard.pro b/simulation/VirtualLedBoard/VirtualLedBoard.pro
new file mode 100644
index 0000000..208ce2e
--- /dev/null
+++ b/simulation/VirtualLedBoard/VirtualLedBoard.pro
@@ -0,0 +1,31 @@
+QT += core gui
+QT += network
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+CONFIG += c++11
+
+# You can make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp \
+ udpserver.cpp
+
+HEADERS += \
+ mainwindow.h \
+ settings.h \
+ udpserver.h
+
+FORMS += \
+ mainwindow.ui
+
+TRANSLATIONS += \
+ VirtualLedBoard_en_150.ts
+
+# Default rules for deployment.
+qnx: target.path = /tmp/$${TARGET}/bin
+else: unix:!android: target.path = /opt/$${TARGET}/bin
+!isEmpty(target.path): INSTALLS += target
diff --git a/simulation/VirtualLedBoard/VirtualLedBoard_en_150.ts b/simulation/VirtualLedBoard/VirtualLedBoard_en_150.ts
new file mode 100644
index 0000000..eb9feca
--- /dev/null
+++ b/simulation/VirtualLedBoard/VirtualLedBoard_en_150.ts
@@ -0,0 +1,3 @@
+
+
+
diff --git a/simulation/VirtualLedBoard/main.cpp b/simulation/VirtualLedBoard/main.cpp
new file mode 100644
index 0000000..fd3e533
--- /dev/null
+++ b/simulation/VirtualLedBoard/main.cpp
@@ -0,0 +1,11 @@
+#include "mainwindow.h"
+
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/simulation/VirtualLedBoard/mainwindow.cpp b/simulation/VirtualLedBoard/mainwindow.cpp
new file mode 100644
index 0000000..b99fbab
--- /dev/null
+++ b/simulation/VirtualLedBoard/mainwindow.cpp
@@ -0,0 +1,53 @@
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+#include
+#include
+#include
+#include
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+ this->mOffscreenPanel = new QImage(DEFAULT_WIDTH + LED_DISTANCE, DEFAULT_HEIGHT + LED_DISTANCE, QImage::Format_RGB32);
+ this->drawImage(this->mOffscreenPanel);
+ this->server = new UdpLedServer (NULL, this);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
+void MainWindow::drawImage(QImage *target) {
+ this->mScene=new QGraphicsScene() ;
+ QGraphicsView *graphicsView = new QGraphicsView();
+ graphicsView->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ graphicsView->setScene(this->mScene);
+ graphicsView->show();
+ this->ui->ledPanel->addWidget(graphicsView);
+}
+
+
+void MainWindow::setLED(uint8_t x, uint8_t y) {
+ /* draw inital screen */
+ QPainter painter(this->mOffscreenPanel);
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.setPen(QPen(COLOR_FOREGROUND, 1));
+ painter.setBrush(COLOR_FOREGROUND);
+ painter.drawEllipse(LED_DIAMETER/2 + (x* LED_DISTANCE), LED_DIAMETER/2 + (y * LED_DISTANCE), LED_DIAMETER, LED_DIAMETER);
+}
+
+void MainWindow::updatePanel(void) {
+
+ QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(*(this->mOffscreenPanel)));
+ this->mScene->clear();
+ mScene->addItem(item);
+ this->renderPanel();
+}
+
+void MainWindow::renderPanel(void) {
+ this->mOffscreenPanel->fill(COLOR_BACKGROUND);
+}
diff --git a/simulation/VirtualLedBoard/mainwindow.h b/simulation/VirtualLedBoard/mainwindow.h
new file mode 100644
index 0000000..d32b5f4
--- /dev/null
+++ b/simulation/VirtualLedBoard/mainwindow.h
@@ -0,0 +1,41 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include
+#include
+#include "udpserver.h"
+
+#include "settings.h"
+
+#define COLOR_BACKGROUND Qt::black
+#define COLOR_FOREGROUND QColor(255, 127, 0, 255)
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class MainWindow; }
+QT_END_NAMESPACE
+
+/* dummy */
+class UdpLedServer;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+public slots:
+ void setLED(uint8_t x, uint8_t y);
+ void updatePanel(void);
+
+private:
+ Ui::MainWindow *ui;
+ UdpLedServer *server = nullptr;
+ QImage *mOffscreenPanel = nullptr;
+ QGraphicsScene* mScene = nullptr;
+ void drawImage(QImage *image);
+ void renderPanel(void);
+};
+#endif // MAINWINDOW_H
diff --git a/simulation/VirtualLedBoard/mainwindow.ui b/simulation/VirtualLedBoard/mainwindow.ui
new file mode 100644
index 0000000..a181b2b
--- /dev/null
+++ b/simulation/VirtualLedBoard/mainwindow.ui
@@ -0,0 +1,48 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 800
+ 600
+
+
+
+ MainWindow
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+ 10
+ 0
+ 781
+ 441
+
+
+
+
+
+
+
+
+
+
diff --git a/simulation/VirtualLedBoard/settings.h b/simulation/VirtualLedBoard/settings.h
new file mode 100644
index 0000000..c1b23ef
--- /dev/null
+++ b/simulation/VirtualLedBoard/settings.h
@@ -0,0 +1,14 @@
+
+#define PACKET_LENGTH 801
+#define PACKET_INDEX_BRIGHTNESS 0
+#define PACKET_INDEX_PANEL0 1
+
+#define MAXIMUM_PANELSIZE 5
+#define PANEL_WIDTH 32
+#define PANEL_HEIGHT 40
+
+#define LED_DIAMETER 8
+#define LED_DISTANCE (LED_DIAMETER + 3)
+
+#define DEFAULT_WIDTH (LED_DISTANCE * MAXIMUM_PANELSIZE * PANEL_WIDTH)
+#define DEFAULT_HEIGHT (LED_DISTANCE * PANEL_HEIGHT)
diff --git a/simulation/VirtualLedBoard/udpserver.cpp b/simulation/VirtualLedBoard/udpserver.cpp
new file mode 100644
index 0000000..0acdf06
--- /dev/null
+++ b/simulation/VirtualLedBoard/udpserver.cpp
@@ -0,0 +1,74 @@
+#include "udpserver.h"
+#include "settings.h"
+#include
+#include
+#include "mainwindow.h"
+
+#define UDP_IMAGE_PORT 4242
+
+UdpLedServer::UdpLedServer (QObject *parent, MainWindow *window)
+ : QObject(parent)
+{
+ initSocket();
+ connect(this,
+ &UdpLedServer::changeLEDstate,
+ window,
+ &MainWindow::setLED);
+ connect(this,
+ &UdpLedServer::updatePanelContent,
+ window,
+ &MainWindow::updatePanel);
+
+
+ for(int x=0; x < (PANEL_WIDTH * MAXIMUM_PANELSIZE); x++) {
+ for(int y=0; y < PANEL_HEIGHT; y++) {
+ changeLEDstate(x, y);
+ }
+ }
+ updatePanelContent();
+
+}
+
+void UdpLedServer ::initSocket()
+{
+ this->mUdpSocket = new QUdpSocket(this);
+ this->mUdpSocket->bind(QHostAddress::LocalHost, UDP_IMAGE_PORT);
+
+ connect(this->mUdpSocket, &QUdpSocket::readyRead,
+ this, &UdpLedServer ::readPendingDatagrams);
+}
+
+
+void UdpLedServer ::readPendingDatagrams()
+{
+ while (this->mUdpSocket->hasPendingDatagrams()) {
+ QNetworkDatagram datagram = this->mUdpSocket->receiveDatagram();
+ processTheDatagram(datagram);
+ }
+}
+
+void UdpLedServer::processTheDatagram(QNetworkDatagram datagram) {
+ if (datagram.isValid() && datagram.data().length() == PACKET_LENGTH) {
+ uint8_t brightness = datagram.data().at(PACKET_INDEX_BRIGHTNESS);
+ int currentIndex = PACKET_INDEX_PANEL0;
+
+ uint16_t mask = 1;
+ for(int y=0; y < PANEL_HEIGHT; y++) {
+ for(int x=0; x < (PANEL_WIDTH * MAXIMUM_PANELSIZE); x++) {
+ if (datagram.data().at(currentIndex) & mask) {
+ this->changeLEDstate(x, y);
+ qDebug() << x << "x" << y << " set";
+ }
+ mask = (mask << 1);
+ if (mask >= 256) {
+ mask = 1;
+ currentIndex++;
+ }
+ }
+ }
+ this->updatePanelContent();
+
+ qDebug() << "Received datagram:" << brightness;
+
+ }
+}
diff --git a/simulation/VirtualLedBoard/udpserver.h b/simulation/VirtualLedBoard/udpserver.h
new file mode 100644
index 0000000..023370b
--- /dev/null
+++ b/simulation/VirtualLedBoard/udpserver.h
@@ -0,0 +1,29 @@
+#ifndef UDPSERVER_H
+#define UDPSERVER_H
+
+#include
+#include
+#include "mainwindow.h"
+
+class MainWindow;
+
+class UdpLedServer : public QObject
+{
+ Q_OBJECT
+
+public:
+ /*UdpLedServer (QObject *parent = nullptr); */
+ UdpLedServer (QObject *parent = nullptr, MainWindow *window = nullptr);
+
+private:
+ void initSocket();
+ void readPendingDatagrams();
+ QUdpSocket *mUdpSocket;
+ void processTheDatagram(QNetworkDatagram datagram);
+
+signals:
+ void changeLEDstate(uint8_t x, uint8_t y);
+ void updatePanelContent(void);
+};
+
+#endif // UDPSERVER_H