You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Also coming from a previous PR that was about refactoring, I have noticed some code was not completely separated by their concerns. That is okay, I do this all the time too :)
But seeing how this project might grow, it may be worthwhile to reconsider the current architecture. Therefore I've asked gemini and this is what it proposes. Tbh I don't understand every detail, but I figured you would know whether this makes sense and this is something we should pursue.
I have tried to display everything as concise and understandable as possible.
This plan outlines the refactoring of the SimApi project to decouple the Data Provider (the daemon that maps game data) from the Client SDK (the library used by dashboards and HUDs).
1. The Core Benefit: Separation of Concerns
Currently, any application that wants to read telemetry must link against a monolithic library that contains code for every supported racing game.
Why this matters
Maintenance – Adding support for a new game shouldn’t require recompiling every HUD and dashboard.
Dependency hygiene – Clients (HUDs) shouldn’t need libuv or libconfig; only the provider (simd) needs those for process and configuration management.
Ease of use – Switch from manual memory mapping to a clean simapi_connect() function.
2. Architecture Diagrams
Before: The Monolithic Architecture
The simapi library is a leaky abstraction containing both the public interface and the heavy mapping machinery.
The mapping logic is encapsulated. The public SDK is tiny and dependency-free.
graph TD
subgraph ClientSDK [Target: libsimapi - Public SDK]
SDK[simdata.h / simapi.h]
API[simapi_client.c - NEW]
API --> SDK
end
subgraph MappingEngine [Target: libsimmapper - Internal]
Engine[simmapper.c + mapping/]
GHeaders[ac.h, rf2.h, etc.]
Engine --> GHeaders
end
subgraph Daemon [Target: simd - The Service]
Main[simd.c]
Main -- "Links" --> MappingEngine
Main -- "Links" --> ClientSDK
end
subgraph Apps [Client Applications]
HUD[view_telemetry / HUDs]
HUD -- "Links" --> ClientSDK
end
Main -- "Writes" --> SHM[("/dev/shm/SIMAPI.DAT")]
ClientSDK -- "Reads" --> SHM
Loading
3. Comparison Contrast
Feature
Current (Monolith)
New (Layered)
Public API
Manual shm_open + mmap
simapi_connect(), simapi_read()
Client Dependencies
libuv, libconfig, game headers
None (standard C library only)
Namespace Hygiene
ac.h, rf2.h exposed to clients
Game structures hidden in libsimmapper
Build Impact
Adding a game = rebuild everything
Adding a game = rebuild simd only
Library Size
Large (contains translation logic)
Tiny (<20KB SDK)
4. Implementation Checklist: What Changes?
1. Structural Changes
Move simapi/mapping/ and simapi/simmapper.c to a new internal directory (e.g., simapi/internal/ or simd/mapper/).
Move ac.h, rf2.h, pcars2.h, etc., to the internal directory.
2. New Files
simapi/simapi.c: Implements the new client-facing API:
SimData* simapi_connect() — handles shm_open and mmap.
void simapi_disconnect() — handles munmap.
simapi/simapi.h: Cleaned up to only export the two functions above and the SimData struct.
3. Build System (CMakeLists.txt)
Split the simapi target:
simapi: A public SHARED library (the SDK).
simmapper: A private STATIC library (the Engine).
Update simd: Link it against both simmapper and simapi.
Update view_telemetry: Update code to use simapi_connect().
5. Impact on monocoque
This refactoring is highly beneficial for the Monocoque project (and other consumers like simmonitor). Since Monocoque is "sim-agnostic" by design, it currently pays a "tax" for the monolithic architecture that this refactor eliminates.
Here is exactly how it affects Monocoque:
1. Zero Breaking Changes (Data Compatibility)
The most important point: The SimData structure remains 100% identical.
Because the binary layout of the shared memory (SIMAPI.DAT) does not change, existing versions of Monocoque will continue to work without any modifications.
It will still find the data exactly where it expects it in /dev/shm/.
2. Radical Dependency Reduction
Currently, if you want to compile Monocoque, you effectively have to include the logic for every single simulator simapi supports.
Before: Monocoque (a client) has a transitive dependency on libuv, libconfig, and all the simulator-specific mapping code (Assetto Corsa, rFactor 2, etc.).
After: Monocoque only links against the new, tiny libsimapi. It becomes a pure "Consumer" with zero knowledge of the "Provider" complexities.
3. Simplified Integration (The SDK)
Code Cleanup: You can delete the manual shm_open, ftruncate, and mmap boilerplate code in Monocoque.
New API: Instead of managing file descriptors and memory pointers, Monocoque would simply do:
SimData*telemetry=simapi_connect();
// ... use telemetry->speed, etc ...simapi_disconnect();
4. Improved Portability
Because the new libsimapi will have zero external dependencies (only standard C headers), it becomes much easier to port Monocoque to different distributions or environments. You no longer need to ensure that the client environment has all the libraries required by the mapping engine.
Summary of Impact for Monocoque
Aspect
Impact
Binary Compatibility
Perfect. No change required to run.
Source Code
Simplified. Can remove ~50-100 lines of SHM boilerplate.
Build System
Streamlined. No longer needs to link against provider-specific libs.
Maintenance
Better. Monocoque doesn't need a re-build when simapi adds a new game.
In short: Monocoque goes from being "tied to the engine" to "talking to an interface."
Also coming from a previous PR that was about refactoring, I have noticed some code was not completely separated by their concerns. That is okay, I do this all the time too :)
But seeing how this project might grow, it may be worthwhile to reconsider the current architecture. Therefore I've asked gemini and this is what it proposes. Tbh I don't understand every detail, but I figured you would know whether this makes sense and this is something we should pursue.
I have tried to display everything as concise and understandable as possible.
This plan outlines the refactoring of the SimApi project to decouple the Data Provider (the daemon that maps game data) from the Client SDK (the library used by dashboards and HUDs).
1. The Core Benefit: Separation of Concerns
Currently, any application that wants to read telemetry must link against a monolithic library that contains code for every supported racing game.
Why this matters
libuvorlibconfig; only the provider (simd) needs those for process and configuration management.simapi_connect()function.2. Architecture Diagrams
Before: The Monolithic Architecture
The
simapilibrary is a leaky abstraction containing both the public interface and the heavy mapping machinery.graph TD subgraph libsimapi.so [Target: simapi - The Monolith] SDK[Public: simdata.h] Engine[Internal: simmapper.c + mapping/] Games[Game Headers: ac.h, rf2.h, etc.] Engine --> SDK Engine --> Games end subgraph simd_app [Target: simd] Daemon[simd.c] Daemon -- "Links & Includes" --> libsimapi.so end subgraph consumers [Consumers] VT[view_telemetry.c] VT -- "Manual SHM Read" --> SHM[("/dev/shm/SIMAPI.DAT")] VT -- "Includes" --> SDK end Daemon -- "Writes" --> SHMAFTER: The Layered Architecture
The mapping logic is encapsulated. The public SDK is tiny and dependency-free.
graph TD subgraph ClientSDK [Target: libsimapi - Public SDK] SDK[simdata.h / simapi.h] API[simapi_client.c - NEW] API --> SDK end subgraph MappingEngine [Target: libsimmapper - Internal] Engine[simmapper.c + mapping/] GHeaders[ac.h, rf2.h, etc.] Engine --> GHeaders end subgraph Daemon [Target: simd - The Service] Main[simd.c] Main -- "Links" --> MappingEngine Main -- "Links" --> ClientSDK end subgraph Apps [Client Applications] HUD[view_telemetry / HUDs] HUD -- "Links" --> ClientSDK end Main -- "Writes" --> SHM[("/dev/shm/SIMAPI.DAT")] ClientSDK -- "Reads" --> SHM3. Comparison Contrast
shm_open+mmapsimapi_connect(),simapi_read()libuv,libconfig, game headersac.h,rf2.hexposed to clientslibsimmappersimdonly4. Implementation Checklist: What Changes?
1. Structural Changes
simapi/mapping/andsimapi/simmapper.cto a new internal directory (e.g.,simapi/internal/orsimd/mapper/).ac.h,rf2.h,pcars2.h, etc., to the internal directory.2. New Files
simapi/simapi.c: Implements the new client-facing API:SimData* simapi_connect()— handlesshm_openandmmap.void simapi_disconnect()— handlesmunmap.simapi/simapi.h: Cleaned up to only export the two functions above and theSimDatastruct.3. Build System (CMakeLists.txt)
simapi: A public SHARED library (the SDK).simmapper: A private STATIC library (the Engine).simd: Link it against bothsimmapperandsimapi.view_telemetry: Update code to usesimapi_connect().5. Impact on monocoque
This refactoring is highly beneficial for the Monocoque project (and other consumers like simmonitor). Since Monocoque is "sim-agnostic" by design, it currently pays a "tax" for the monolithic architecture that this refactor eliminates.
Here is exactly how it affects Monocoque:
1. Zero Breaking Changes (Data Compatibility)
SimDatastructure remains 100% identical.SIMAPI.DAT) does not change, existing versions of Monocoque will continue to work without any modifications./dev/shm/.2. Radical Dependency Reduction
simapisupports.libuv,libconfig, and all the simulator-specific mapping code (Assetto Corsa, rFactor 2, etc.).libsimapi. It becomes a pure "Consumer" with zero knowledge of the "Provider" complexities.3. Simplified Integration (The SDK)
shm_open,ftruncate, andmmapboilerplate code in Monocoque.4. Improved Portability
Because the new
libsimapiwill have zero external dependencies (only standard C headers), it becomes much easier to port Monocoque to different distributions or environments. You no longer need to ensure that the client environment has all the libraries required by the mapping engine.Summary of Impact for Monocoque
In short: Monocoque goes from being "tied to the engine" to "talking to an interface."