Skip to content

Commit

Permalink
Merge pull request #183 from RobertGawron/feature/storage_implementation
Browse files Browse the repository at this point in the history
Feature/storage implementation
  • Loading branch information
RobertGawron authored Dec 19, 2024
2 parents 4dd73a0 + c8c1616 commit 52acd36
Show file tree
Hide file tree
Showing 84 changed files with 1,359 additions and 465 deletions.
2 changes: 1 addition & 1 deletion DevOps/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ make test

## Run static analysis

make static
cd /workspace/build && cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_STANDARD=17 .. && make static

# Run code coverage

Expand Down
75 changes: 75 additions & 0 deletions Documentation/Diagrams/PCSimulationComponentDiagram.plantuml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
@startuml
!pragma layout smetana

package "Simulation (located in Simulation/FirmwarePCSimulator)" {
[GUI] --> [Simulation Engine (simulation.py)]
[Simulation Engine (simulation.py)] --> [Python Wrapper (device_under_test.py)]
[Python Wrapper (device_under_test.py)] --> ["DLL (libFirmwarePCSimulator.so)"]
[Simulation Engine (simulation.py)] --> [Mocks]
[Mocks] -up-> ["DLL (libFirmwarePCSimulator.so)"]
}

package "Firmware (located in Software/STM32F103RBTx)" {
component "Application" {
package "Business Logic" as BL {
folder "Headers" as BusinessLogic_Headers
folder "Interfaces" as BusinessLogic_Interfaces
folder "Sources" as BusinessLogic_Sources
}

package "Device" as Dev {
folder "Headers" as Device_Headers
folder "Interfaces" as Device_Interfaces
folder "Sources" as Device_Sources
}
' Dummy relation to group blocks vertically
package "Driver" as Drv {
folder "Headers" as Driver_Headers
folder "Interfaces" as Driver_Interfaces
folder "Sources" as Driver_Sources
}

BL -[hidden]down--- Dev
Dev -[hidden]down--- Drv
}

component "Libraries \n(located in Middlewares/Third_Party)" {
package "STM32-ST7735" {
folder "Headers (*.h)" as STM32_ST7735_Headers
}
}

component "Core (located in Core)" {
folder "Headers (*.h)" as Core_Headers
}

"Application" -[hidden]down-------- "Libraries \n(located in Middlewares/Third_Party)"
"Application" -[hidden]down-------- "Core (located in Core)"
}


' Connections between DLL and Firmware components
["DLL (libFirmwarePCSimulator.so)"] -down--> BL
["DLL (libFirmwarePCSimulator.so)"] -down--> Dev
[Mocks] -down----> Driver_Interfaces
[Mocks] -down----> Core_Headers
[Mocks] -down---> STM32_ST7735_Headers

' Add a note for Mocks
note left of [GUI]
Uses PyQt6. Only this component uses it
to avoid tightly coupling with the framework.
end note


' Add a note for Mocks
note top of [Mocks]
These replace the hardware-specific code
from the firmware directory because
the source code from:
* Application/Driver
* Middlewares/Third_Party
* Core
is not included in the compilation.
end note
@enduml
1 change: 1 addition & 0 deletions Documentation/Diagrams/PCSimulationComponentDiagram.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions Documentation/Diagrams/RemoteHostMeasurementDataFlow.plantuml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@startuml
title Deploy Diagram

actor "Measurement Devices"

box "HardwareDataLogger" #LightYellow
participant "STM32F103RBTx chip"
participant "ESP8266MOD chip"
end box

box "Docker Image" #LightBlue
database "InfluxDB"
participant "Grafana"
end box

note over "InfluxDB", "Grafana"
"Either run locally (for debug) on PC or remotely on RaspberryPi"
end note

actor "End User"

"Measurement Devices" -> "STM32F103RBTx chip" : Sends Raw Data
"STM32F103RBTx chip" -> "ESP8266MOD chip" : Processes and Transfers Data
"ESP8266MOD chip" --> "InfluxDB" : Stores Data\n(via MQTT or HTTP)
"InfluxDB" -> "Grafana" : Fetches and Serves Data
"End User" -> "Grafana" : Accesses Data Visualization
@enduml
1 change: 1 addition & 0 deletions Documentation/Diagrams/RemoteHostMeasurementDataFlow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,3 @@ While this simulation handles the firmware, speed of execution isn't a concern s

* Toolchain: pyqt6, cmake.
* [More info.](./Simulation/FirmwarePCSimulator/README.md)

## Documentation

TBD UML diagrams.
13 changes: 12 additions & 1 deletion Simulation/FirmwarePCSimulator/LibWrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
#include "LibWrapper.hpp"
#include <stdint.h>

#include "PlatformFactoryStm32.hpp"
#include "MyApplication.hpp"

#include "KeyboardDriverStub.hpp"
#include "Driver/Inc/KeyboardKeyState.hpp"
#include "PulseCounterDriverStub.hpp"

#include "St7735DisplayDriverStub.hpp"
#include "DisplayPixelColor.hpp"

#include <stdint.h>
#include <array>

extern Driver::St7735DisplayDriverStub st7735DisplayDriverStub;
extern Driver::KeyboardDriverStub keyboardDriverStub;

Expand Down Expand Up @@ -57,3 +60,11 @@ std::uint16_t LibWrapper_GetPixelValue(std::uint8_t x, std::uint8_t y)
{
return st7735DisplayDriverStub.getPixelValue(x, y);
}

void LibWrapper_UpdatePulseCounters(const std::array<std::uint16_t, PULSE_COUNTER_COUNT> &pulseCounters)
{
for (std::size_t i = 0; i < PULSE_COUNTER_COUNT; i++)
{
setPulseCounter(i, pulseCounters.at(i));
}
}
13 changes: 13 additions & 0 deletions Simulation/FirmwarePCSimulator/LibWrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
#define LibWrapper_h

#include <cstdint>
#include <array>
#include "MyApplication.hpp"

constexpr std::size_t PULSE_COUNTER_COUNT = 4;

#ifdef __cplusplus
extern "C"
{
Expand Down Expand Up @@ -67,6 +70,16 @@ extern "C"

void LibWrapper_KeyReleased(KeyboardKeyIdentifier keyId);

/**
* @brief Updates the values of the pulse counters.
*
* This function takes an std::array containing the pulse counter values and updates
* the internal state accordingly.
*
* @param pulseCounters An array of pulse counter values.
*/
void LibWrapper_UpdatePulseCounters(const std::array<std::uint16_t, PULSE_COUNTER_COUNT> &pulseCounters);

#ifdef __cplusplus
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
extern "C"
{
void incrementPulseCounter(std::uint8_t counterId);
void setPulseCounter(std::uint8_t counterId, std::uint32_t value);
}

namespace Driver
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ extern "C"
pulseCounters[counterId]++;
}
}

void setPulseCounter(std::uint8_t counterId, std::uint32_t value)
{
pulseCounters[counterId] = value;
}
}

namespace Driver
Expand Down Expand Up @@ -51,7 +56,7 @@ namespace Driver
IPulseCounterDriver::CounterSizeType PulseCounterDriverStub::getMeasurement()
{
// printf("PulseCounterDriverStub::getMeasurement()\n");
return 5;
return pulseCounters[0];
}

void PulseCounterDriverStub::clearMeasurement()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ namespace Driver

for (std::size_t i = 0u; i < size; i++)
{
printf("TX %d ", data[i]);
// printf("TX %d ", data[i]);
}
printf("\n");
// printf("\n");

return UartExchangeStatus::Ok;
}
Expand Down
2 changes: 1 addition & 1 deletion Simulation/FirmwarePCSimulator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

The reasons for using a simulator are explained in the [main README](../../README.md).

![PC Simulation Screenshot](../../Documentation/Pictures/PCSimulation_17_11_2024.png)
![PC Simulation Screenshot](../../Documentation/Pictures/PCSimulation_18_12_2024.png)

## Architecture

Expand Down
57 changes: 57 additions & 0 deletions Simulation/FirmwarePCSimulator/data_visualization_widget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from PyQt6.QtWidgets import QWidget, QVBoxLayout
from PyQt6.QtCore import Qt
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas

class DataVisualizationWidget(QWidget):
def __init__(self):
super().__init__()

# Main layout for the Data Visualization Widget
self.layout = QVBoxLayout()
self.layout.setAlignment(Qt.AlignmentFlag.AlignTop)

# Create a Matplotlib figure and canvas
self.figure, self.ax = plt.subplots()
self.canvas = FigureCanvas(self.figure)

# Add the canvas to the layout
self.layout.addWidget(self.canvas)

# Initialize data storage for pulse counters
self.time_stamps = []
self.pulse_counters = {i: [] for i in range(4)} # 4 pulse counters

self.setLayout(self.layout)

def update_pulse_counters(self, timestamp, values):
"""
Update the graph with new pulse counter values.
:param timestamp: The timestamp of the update.
:param values: A list of pulse counter values.
"""
# Append new data to the storage
self.time_stamps.append(timestamp)
for i, value in enumerate(values):
self.pulse_counters[i].append(value)

# Ensure the time series does not grow indefinitely (optional)
MAX_POINTS = 100
if len(self.time_stamps) > MAX_POINTS:
self.time_stamps.pop(0)
for key in self.pulse_counters:
self.pulse_counters[key].pop(0)

# Clear and plot new data
self.ax.clear()
for i, values in self.pulse_counters.items():
self.ax.plot(self.time_stamps, values, label=f"Pulse Counter {i + 1}")

self.ax.set_title("Pulse Counter Values Over Time")
self.ax.set_xlabel("Time")
self.ax.set_ylabel("Value")
self.ax.legend()

# Redraw the canvas
self.canvas.draw()
17 changes: 17 additions & 0 deletions Simulation/FirmwarePCSimulator/device_under_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import ctypes
import os.path
from enum import Enum
from typing import List

class SimulationKey(Enum):
UP = 0
Expand Down Expand Up @@ -77,3 +78,19 @@ def key_released(self, key: SimulationKey):
self.dut.LibWrapper_KeyReleased.argtypes = [ctypes.c_uint8] # Accepts an integer (enum value)
self.dut.LibWrapper_KeyReleased(key.value)

def update_pulse_counters(self, pulse_counters: List[int]):
"""
Updates the pulse counters in the shared library.
:param pulse_counters: A list of pulse counter values to update.
"""
PULSE_COUNTER_COUNT = 4
if len(pulse_counters) != PULSE_COUNTER_COUNT:
raise ValueError(f"Expected {PULSE_COUNTER_COUNT} pulse counters, got {len(pulse_counters)}")

PulseCountersArrayType = ctypes.c_uint16 * PULSE_COUNTER_COUNT
pulse_counters_array = PulseCountersArrayType(*pulse_counters)

self.dut.LibWrapper_UpdatePulseCounters.restype = None
self.dut.LibWrapper_UpdatePulseCounters.argtypes = [PulseCountersArrayType]
self.dut.LibWrapper_UpdatePulseCounters(pulse_counters_array)
Loading

0 comments on commit 52acd36

Please sign in to comment.