Added tutorial and fixed issues on debugservice
This commit is contained in:
@@ -158,17 +158,20 @@ bool DebugService::Initialise(StructuredDataI & data) {
|
||||
REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to Listen on port %u", controlPort);
|
||||
return false;
|
||||
}
|
||||
printf("[DebugService] TCP Server listening on port %u\n", controlPort);
|
||||
|
||||
if (!udpSocket.Open()) {
|
||||
REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to open UDP Socket");
|
||||
return false;
|
||||
}
|
||||
printf("[DebugService] UDP Streamer socket opened\n");
|
||||
|
||||
if (!logServer.Open()) {
|
||||
REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to open Log Server Socket");
|
||||
return false;
|
||||
}
|
||||
(void)logServer.Listen(logPort);
|
||||
printf("[DebugService] Log Server listening on port %u\n", logPort);
|
||||
|
||||
if (threadService.Start() != ErrorManagement::NoError) {
|
||||
REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to start Server thread");
|
||||
@@ -182,6 +185,7 @@ bool DebugService::Initialise(StructuredDataI & data) {
|
||||
REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to start LogStreamer thread");
|
||||
return false;
|
||||
}
|
||||
printf("[DebugService] All worker threads started.\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
56
TUTORIAL.md
Normal file
56
TUTORIAL.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Tutorial: High-Speed Observability with MARTe2 Debug GUI
|
||||
|
||||
This guide will walk you through the process of tracing and forcing signals in a real-time MARTe2 application using the native Rust GUI client.
|
||||
|
||||
## 1. Environment Setup
|
||||
|
||||
### Launch the MARTe2 Application
|
||||
First, start your application using the provided debug runner. This script launches the standard `MARTeApp.ex` while injecting the debugging layer:
|
||||
```bash
|
||||
./run_debug_app.sh
|
||||
```
|
||||
*Note: You should see logs indicating the `DebugService` has started on port 8080.*
|
||||
|
||||
### Start the GUI Client
|
||||
In a new terminal window, navigate to the client directory and run the GUI:
|
||||
```bash
|
||||
cd Tools/gui_client
|
||||
cargo run --release
|
||||
```
|
||||
|
||||
## 2. Exploring the Object Tree
|
||||
Once connected, the left panel (**Application Tree**) displays the live hierarchy of your application.
|
||||
|
||||
1. **Navigate to Data:** Expand `Root` -> `App` -> `Data`.
|
||||
2. **Inspect Nodes:** Click the **ℹ Info** button next to any node (like `Timer` or `DDB`).
|
||||
3. **View Metadata:** The bottom-left pane will display the full JSON configuration of that object, including its class, parameters, and signals.
|
||||
|
||||
## 3. Real-Time Signal Tracing (Oscilloscope)
|
||||
Tracing allows you to see signal values exactly as they exist in the real-time memory map.
|
||||
|
||||
1. **Find a Signal:** In the tree, locate `Root.App.Data.Timer.Counter`.
|
||||
2. **Activate Trace:** Click the **📈 Trace** button.
|
||||
3. **Monitor the Scope:** The central **Oscilloscope** panel will begin plotting the signal.
|
||||
4. **Verify Data Flow:** Check the **UDP Packets** counter in the top bar; it should be increasing rapidly, confirming high-speed data reception (Port 8081).
|
||||
5. **Multi-Signal Trace:** You can click **📈 Trace** on other signals (like `Time`) to overlay multiple plots.
|
||||
|
||||
## 4. Signal Forcing (Manual Override)
|
||||
Forcing allows you to bypass the framework logic and manually set a signal's value in memory.
|
||||
|
||||
1. **Locate Target:** Find a signal that is being written by a GAM, such as `Root.App.Data.DDB.Counter`.
|
||||
2. **Open Force Dialog:** Click the **⚡ Force** button next to the signal.
|
||||
3. **Inject Value:** In the popup dialog, enter a new value (e.g., `9999`) and click **Apply Force**.
|
||||
4. **Observe Effect:** If you are tracing the same signal, the oscilloscope plot will immediately jump to and hold at `9999`.
|
||||
5. **Release Control:** To stop forcing, click the **❌** button in the **Active Controls** (Right Panel) under "Forced Signals". The framework will resume writing its own values to that memory location.
|
||||
|
||||
## 5. Advanced Controls
|
||||
|
||||
### Global Pause
|
||||
If you need to "freeze" the entire application to inspect a specific state:
|
||||
- Click **⏸ Pause** in the top bar. The real-time threads will halt at the start of their next cycle.
|
||||
- Click **▶ Resume** to restart the execution.
|
||||
|
||||
### Log Terminal
|
||||
The bottom panel displays every `REPORT_ERROR` event from the C++ framework.
|
||||
- **Regex Filter:** Type a keyword like `Timer` in the filter box to isolate relevant events.
|
||||
- **Pause Logs:** Toggle **⏸ Pause Logs** to stop the scrolling view while data continues to be captured in the background.
|
||||
@@ -1,19 +1,4 @@
|
||||
+DebugService = {
|
||||
Class = DebugService
|
||||
ControlPort = 8080
|
||||
StreamPort = 8081
|
||||
StreamIP = "127.0.0.1"
|
||||
}
|
||||
|
||||
+LoggerService = {
|
||||
Class = LoggerService
|
||||
CPUs = 0x1
|
||||
+DebugConsumer = {
|
||||
Class = DebugService
|
||||
}
|
||||
}
|
||||
|
||||
+App = {
|
||||
$App = {
|
||||
Class = RealTimeApplication
|
||||
+Functions = {
|
||||
Class = ReferenceContainer
|
||||
@@ -23,7 +8,7 @@
|
||||
Counter = {
|
||||
DataSource = Timer
|
||||
Type = uint32
|
||||
Frequency = 10
|
||||
Frequency = 1
|
||||
}
|
||||
Time = {
|
||||
DataSource = Timer
|
||||
@@ -47,7 +32,7 @@
|
||||
DefaultDataSource = DDB
|
||||
+Timer = {
|
||||
Class = LinuxTimer
|
||||
SleepTime = 1000000 // 1 second
|
||||
SleepTime = 1000000 // 1 second cycle to reduce log spam
|
||||
Signals = {
|
||||
Counter = {
|
||||
Type = uint32
|
||||
@@ -99,3 +84,18 @@
|
||||
TimingDataSource = DAMS
|
||||
}
|
||||
}
|
||||
|
||||
+DebugService = {
|
||||
Class = DebugService
|
||||
ControlPort = 8080
|
||||
UdpPort = 8081
|
||||
StreamIP = "127.0.0.1"
|
||||
}
|
||||
|
||||
+LoggerService = {
|
||||
Class = LoggerService
|
||||
CPUs = 0x1
|
||||
+DebugConsumer = {
|
||||
Class = DebugService
|
||||
}
|
||||
}
|
||||
|
||||
40
run_debug_app.sh
Executable file
40
run_debug_app.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
# run_debug_app.sh - Launch the MARTe2 Debugging Environment using standard MARTeApp.ex
|
||||
|
||||
# 1. Environment Setup
|
||||
if [ -f "./env.sh" ]; then
|
||||
source ./env.sh
|
||||
else
|
||||
echo "ERROR: env.sh not found. Ensure you are in the project root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. Paths
|
||||
MARTE_EX="${MARTe2_DIR}/Build/${TARGET}/App/MARTeApp.ex"
|
||||
DEBUG_LIB="$(pwd)/Build/libmarte_dev.so"
|
||||
|
||||
# Component library base search path
|
||||
COMPONENTS_BUILD_DIR="${MARTe2_Components_DIR}/Build/${TARGET}/Components"
|
||||
|
||||
# DYNAMICALLY FIND ALL COMPONENT DIRS
|
||||
# MARTe2 Loader needs the specific directories containing .so files in LD_LIBRARY_PATH
|
||||
ALL_COMPONENT_DIRS=$(find "$COMPONENTS_BUILD_DIR" -type d)
|
||||
for dir in $ALL_COMPONENT_DIRS; do
|
||||
if ls "$dir"/*.so >/dev/null 2>&1; then
|
||||
export LD_LIBRARY_PATH="$dir:$LD_LIBRARY_PATH"
|
||||
fi
|
||||
done
|
||||
|
||||
# Ensure our build dir and core dir are included
|
||||
export LD_LIBRARY_PATH="$(pwd)/Build:${MARTe2_DIR}/Build/${TARGET}/Core:${LD_LIBRARY_PATH}"
|
||||
|
||||
# 3. Cleanup
|
||||
echo "Cleaning up lingering processes..."
|
||||
pkill -9 MARTeApp.ex
|
||||
sleep 1
|
||||
|
||||
# 4. Launch Application
|
||||
echo "Launching standard MARTeApp.ex with debug_test.cfg..."
|
||||
# PRELOAD ensures our DebugService class is available to the registry early
|
||||
export LD_PRELOAD="${DEBUG_LIB}"
|
||||
"$MARTE_EX" -f Test/Configurations/debug_test.cfg -l RealTimeLoader -s State1
|
||||
Reference in New Issue
Block a user