close to finishing claude.md file
This commit is contained in:
254
CLAUDE.md
254
CLAUDE.md
@@ -105,9 +105,10 @@ Also not that when the radar exhibit starts, the very first option will
|
||||
be on the screen. Then the screen will advance through the scopes by two means;
|
||||
the pressing of the s key by the user, or automatically at every 120 seconds. You will
|
||||
need to emphasize in the first desciption that you can advance without waiting
|
||||
for the automatic advancing by pressing the s key. This should be articulated for the
|
||||
for the automatic advancing by pressing the s key. You can reverse by hitting the S key
|
||||
(upper case s) This should be articulated for the
|
||||
discrition window for each scope. When the main exhibit descriptor screen comes up, it's
|
||||
important to highlight the feature that the user can press the s key any time to 'hurry up'
|
||||
important to highlight the feature that the user can press the s key or the S key any time to 'hurry up'
|
||||
the scope advancement.
|
||||
|
||||
Also ensure that the timeout clock will reset when the user changes to a new scope, or presses
|
||||
@@ -143,6 +144,20 @@ should be articulated in the descriptive text
|
||||
In addition to the blips for targets, there would be a floor of noise (signal received by
|
||||
rain and waves. This needs to be shown.
|
||||
|
||||
Graticule swap simulation: In the period, changing maximum range required the operator
|
||||
to physically slide the glass graticule panel upward and out from in front of the CRT,
|
||||
then slide the replacement graticule (calibrated for the new range) downward into position.
|
||||
This must be simulated when the operator presses u or d to change range.
|
||||
|
||||
The graticule swap animation uses four states:
|
||||
NORMAL - graticule in place, scope operating normally
|
||||
SLIDING_OUT - old graticule translates upward off screen (~0.5 seconds)
|
||||
BARE_CRT - no graticule visible; CRT trace and noise floor still running
|
||||
SLIDING_IN - new graticule (correct lines for new range) slides down into position (~0.5 seconds)
|
||||
After SLIDING_IN completes, state returns to NORMAL with the new range active.
|
||||
The u and d keys are ignored during the swap animation (operator's hands are busy).
|
||||
The graticule remains incandescent color throughout — it is edge-lit glass.
|
||||
|
||||
3. Chain Home A Scope There is a second use of the a-scope.
|
||||
That is for the early world war 2 chain home
|
||||
radar. This operated very differently. You have a large array of high power transmitters
|
||||
@@ -158,7 +173,7 @@ should be articulated in the descriptive text
|
||||
as this is a bit advanced. I need your advise to how to do this for children and those
|
||||
who never heard of chain home.
|
||||
|
||||
The goniometer vert and h switch could be keys [ and ] and the gonometer tuning
|
||||
The goniometer vertical and horizontal switch could be key [ for toggling. The gonometer tuning
|
||||
would be 9 and 0 to avoid using the shift key. The tuning keys should have one unit
|
||||
for single press, but a slow build of of speed if key is held down. This has to stay
|
||||
slow due to the sudden appearance of the null.
|
||||
@@ -325,8 +340,96 @@ should be articulated in the descriptive text
|
||||
Sweep rate: approximately 30 Hz alternating between azimuth and
|
||||
elevation planes so that each will scan 1/15 th of a second.
|
||||
|
||||
THREADS
|
||||
|
||||
[remove modularity and threads; will work this out later before implementation]
|
||||
These are the threads of processes:
|
||||
|
||||
1. Display initiation and operation (anything that 'touches' the display and the shaders) Thread 1
|
||||
2. Software that receives data for targets. Thread 2 (this is the traffic cop that polls the
|
||||
raspberry pis. and the Simulator. This needs mutex access to shared data with thread 1. It will
|
||||
also need mutex access to shared data with thread 4 (the simulator)
|
||||
3. Knob panel - thread 3 - uses a mutex to write shared state variables that thread 1 reads
|
||||
to send to the shaders.
|
||||
4. Simulator, thread 4. It is polled by the traffic cop
|
||||
|
||||
Threads 2,3, need mutex access to shared data that is read by thread 1.
|
||||
Thread 2 needs mutex access for shared data with thread 4, the simulator
|
||||
|
||||
SUMMARY OF Controls:
|
||||
● ┌─────┬─────────────────────────────────────┬───────┬──────────┬──────────────┬────────────┬─────────┬─────┐
|
||||
│ Key │ Function │ Intro │ Marine A │ Chain Home A │ Marine PPI │ ATC PPI │ PAR │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ s │ Advance to next scope │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ S │ back to previous scope │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ c │ Bearing clockwise │ │ ✓ │ │ │ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ v │ Bearing counterclockwise │ │ ✓ │ │ │ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ u │ Max range up │ │ ✓ │ │ ✓ │ ✓ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ d │ Max range down │ │ ✓ │ │ ✓ │ ✓ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ r │ Cursor bearing right │ │ │ │ ✓ │ ✓ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ l │ Cursor bearing left │ │ │ │ ✓ │ ✓ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ t │ Cursor range increase │ │ │ │ ✓ │ ✓ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ y │ Cursor range decrease │ │ │ │ ✓ │ ✓ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ k │ Antenna bearing offset right (boat) │ │ │ │ ✓ │ ✓ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ j │ Antenna bearing offset left (boat) │ │ │ │ ✓ │ ✓ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ [ │ Goniometer H/V switch │ │ │ ✓ │ │ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ 9 │ Goniometer tune left │ │ │ ✓ │ │ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ 0 │ Goniometer tune right │ │ │ ✓ │ │ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ . │ Toggle PRF (25/12.5 Hz) │ │ │ ✓ │ │ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ n │ Calibrator shrink │ │ │ ✓ │ │ │ │
|
||||
├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼─────────┼─────┤
|
||||
│ m │ Calibrator stretch │ │ │ ✓ │ │ │ │
|
||||
└─────┴─────────────────────────────────────┴───────┴──────────┴──────────────┴────────────┴─────────┴─────┘
|
||||
|
||||
SUMMARY of target handling:
|
||||
|
||||
The traffic cop handles anything that is coming from the simulator as well as the raspberry pi's
|
||||
It will use pollnig to find if anything is available from the raspberry pis and the simulator. It will
|
||||
poll each source once per beam update
|
||||
|
||||
The raspberry pi receiver pulls the data from each raspberry pi. If nothing, it does nothing else
|
||||
for this sweep. If there is data, it will provide data to the traffic cop upon poll.
|
||||
|
||||
Each raspberry pi, after boot-up, will respond to poles from the raspberry pi receiver (thread 2)
|
||||
|
||||
The Simulator will run all fake targets. It will provide data to the traffic cop upon traffic cop poll.
|
||||
It can run as a separate thread. It will not write data to anywhere except when polled by the traffic cop.
|
||||
|
||||
|
||||
CONTROLS
|
||||
|
||||
Things to note about the keyboard type controls.
|
||||
The letter on the keyboard are temporary. When I get around to making
|
||||
the operators panel, this all will go away.
|
||||
|
||||
Implementation of controls:
|
||||
|
||||
1. For keyboard controls. Those are run as thread one where The keyboard callback
|
||||
belongs to GLFW (glfwSetKeyCallback)
|
||||
They will manipulate the shaders only.
|
||||
|
||||
2. The control desk controls will have to mutex to access the state variables that
|
||||
thread 1 sends to the shaders.
|
||||
|
||||
3. If the control does not yet exist, we still want stubs for receiving control
|
||||
data for that control. It's just that nothing will call it.
|
||||
|
||||
Scope and left window arrangement.
|
||||
|
||||
For each scope, put the scope itself on the right hand of the window.
|
||||
On the left hand of the window will be a text description of that scope.
|
||||
@@ -351,6 +454,145 @@ different radars. Range and bearing for the precision aproach radar will be diff
|
||||
than any other radar as that radar is located at the end of the runway and scan both
|
||||
horizontal and vertical.
|
||||
|
||||
[other scopes to be defined later]
|
||||
|
||||
Please analyze and comment. Please do not generate any code file nor shader files.
|
||||
|
||||
==================================================================
|
||||
|
||||
CLASS DESIGN AND FILE LAYOUT
|
||||
|
||||
==================================================================
|
||||
|
||||
Class Hierarchy:
|
||||
|
||||
Scope (abstract base)
|
||||
├── ExhibitIntro
|
||||
├── AScope (abstract)
|
||||
│ ├── MarineAScope
|
||||
│ └── ChainHomeAScope
|
||||
├── PPIScope (abstract)
|
||||
│ ├── MarinePPIScope
|
||||
│ └── ATCPPIScope
|
||||
└── PARScope
|
||||
|
||||
Scope (abstract base) — everything all scopes share:
|
||||
- Left panel text rendering
|
||||
- s / S key handling (scope advance / reverse)
|
||||
- Auto-advance timer reset on any key or control input
|
||||
- Pure virtual: render(), handleKey(), getDescription()
|
||||
|
||||
ExhibitIntro : public Scope
|
||||
- Text-only rendering, no radar display
|
||||
- Header: "WELCOME TO MUSEUM VINTAGE RADAR EXHIBIT" (all caps)
|
||||
|
||||
AScope : public Scope (abstract) — shared A-scope behavior:
|
||||
- Horizontal range axis, vertical amplitude axis
|
||||
- Noise floor rendering (rain/wave clutter)
|
||||
- Incandescent graticule (three horizontal amplitude lines + vertical range lines)
|
||||
- Bearing control with key-hold acceleration
|
||||
- Phosphor type as parameter (P1 or P7)
|
||||
|
||||
MarineAScope : public AScope
|
||||
- P1 phosphor (green)
|
||||
- Range settings: 2, 4, 6 miles
|
||||
- Graticule swap animation state machine (NORMAL/SLIDING_OUT/BARE_CRT/SLIDING_IN)
|
||||
when operator changes max range — see Marine A-Scope section above for full detail
|
||||
- Keys: c (bearing CW), v (bearing CCW), u (range up), d (range down)
|
||||
u and d ignored during graticule swap animation
|
||||
|
||||
ChainHomeAScope : public AScope
|
||||
- P7 phosphor (early implementation)
|
||||
- Goniometer state: H/V mode toggle, azimuth angle, elevation angle
|
||||
- PRF toggle: 25 Hz / 12.5 Hz
|
||||
- Calibrator stretch/shrink scale factor
|
||||
- Fixed 100-mile range
|
||||
- Keys: [ (goniometer H/V toggle), 9/0 (tune), . (PRF), n/m (calibrator)
|
||||
|
||||
PPIScope : public Scope (abstract) — shared PPI behavior:
|
||||
- Clockwise sweep with P7 phosphor persistence (blue strike, green/yellow decay)
|
||||
- Incandescent bearing graticule (1-degree ticks, 15-degree labels, inner/outer rings)
|
||||
- Yellow cursor: 10-degree arc + bearing crossline
|
||||
- Cursor range/bearing readout under scope (white text)
|
||||
- Bearing offset for boat mode (k/j)
|
||||
- Cursor range clamped to max range
|
||||
|
||||
MarinePPIScope : public PPIScope
|
||||
- Sweep time: 4 seconds
|
||||
- Max range: 2, 4, 6 miles with correct ring sets
|
||||
- Keys: u (range up), d (range down) — this scope only
|
||||
|
||||
ATCPPIScope : public PPIScope
|
||||
- Sweep time: 5 seconds
|
||||
- Max range: 5, 10, 15, 20 miles with correct ring sets
|
||||
- Keys: u (range up), d (range down) — this scope only
|
||||
|
||||
PARScope : public Scope
|
||||
- Two stacked sub-scopes: azimuth (top, ~1/3 larger) and elevation (bottom)
|
||||
- 30 Hz alternating scan between planes (~15 Hz each)
|
||||
- Fixed 10-mile range, non-linear scale (inner 5 miles = 70% width)
|
||||
- P7 phosphor; incandescent etched glass graticules
|
||||
- All targets simulated; no cursor or bearing controls
|
||||
|
||||
Supporting classes:
|
||||
ScopeManager Thread 1 — owns scope list, s/S switching, 120s auto-advance timer
|
||||
PhosphorRenderer Thread 1 — P1 and P7 decay/persistence; shared dependency
|
||||
Graticule Thread 1 — incandescent graticule lines/text; parameterized per scope
|
||||
LeftPanel Thread 1 — scope description text panel (left side of window)
|
||||
SharedRenderState Threads 1,2,3 — Mutex A; state vars Thread 1 reads each frame for shader uniforms
|
||||
TargetBuffer Threads 2,4 — Mutex B; target data handoff between TrafficCop and Simulator
|
||||
TrafficCop Thread 2 — polls Simulator and RPi receivers; writes to SharedRenderState
|
||||
Simulator Thread 4 — runs fake targets; returns data to TrafficCop when polled
|
||||
KnobPanel Thread 3 — future hardware stub; writes to SharedRenderState under Mutex A
|
||||
RPiReceiver Thread 2 — stub; one per Raspberry Pi; called by TrafficCop
|
||||
|
||||
File layout:
|
||||
|
||||
src/
|
||||
main.cpp
|
||||
scope_manager.h / scope_manager.cpp
|
||||
scope.h / scope.cpp — abstract Scope base
|
||||
scope_intro.h / scope_intro.cpp
|
||||
scope_ascope.h / scope_ascope.cpp — abstract AScope
|
||||
scope_marine_a.h / scope_marine_a.cpp
|
||||
scope_chain_home.h / scope_chain_home.cpp
|
||||
scope_ppi.h / scope_ppi.cpp — abstract PPIScope
|
||||
scope_marine_ppi.h / scope_marine_ppi.cpp
|
||||
scope_atc_ppi.h / scope_atc_ppi.cpp
|
||||
scope_par.h / scope_par.cpp
|
||||
phosphor.h / phosphor.cpp
|
||||
graticule.h / graticule.cpp
|
||||
left_panel.h / left_panel.cpp
|
||||
shared_render_state.h / shared_render_state.cpp
|
||||
target_buffer.h / target_buffer.cpp
|
||||
traffic_cop.h / traffic_cop.cpp
|
||||
simulator.h / simulator.cpp
|
||||
knob_panel.h / knob_panel.cpp
|
||||
rpi_receiver.h / rpi_receiver.cpp
|
||||
|
||||
settings.h — all tunable constants; no .cpp needed
|
||||
|
||||
shaders/
|
||||
phosphor.vert / phosphor.frag — parameterized for P1 and P7 via uniforms
|
||||
graticule.vert / graticule.frag
|
||||
text.vert / text.frag
|
||||
sweep.vert / sweep.frag
|
||||
|
||||
settings.h — tunable constants:
|
||||
All magic numbers live here. Every source file that needs a tunable value
|
||||
includes settings.h. No values are hardcoded elsewhere.
|
||||
Categories planned:
|
||||
- Phosphor P1 color
|
||||
- Phosphor P7 strike color, persistence color, decay times (PPI and Chain Home)
|
||||
- Sweep line width, brightness, fade trail, periods per scope
|
||||
- PAR scan rate; Chain Home PRF high and low
|
||||
- Graticule incandescent color, line widths
|
||||
- PPI bearing ring tick lengths, label interval, font size
|
||||
- PPI range ring line width, label size, label color
|
||||
- Cursor color, line width, arc span
|
||||
- Noise floor amplitude and variation (Marine A-Scope)
|
||||
- Graticule swap animation durations (slide out, bare CRT, slide in)
|
||||
- Key-hold acceleration (initial step, rate, max) — separate for goniometer
|
||||
- Auto-advance timer interval (120 seconds)
|
||||
- Window size and panel layout fractions
|
||||
- PAR azimuth/elevation height fractions
|
||||
- UI text color and size; cursor readout text size
|
||||
- Graticule label color (incandescent)
|
||||
|
||||
245
DESIGN.md
Normal file
245
DESIGN.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# Radar Simulation — Class Design and File Layout
|
||||
Author: Mark Allyn
|
||||
|
||||
---
|
||||
|
||||
## Class Hierarchy
|
||||
|
||||
```
|
||||
Scope (abstract base)
|
||||
├── ExhibitIntro
|
||||
├── AScope (abstract)
|
||||
│ ├── MarineAScope
|
||||
│ └── ChainHomeAScope
|
||||
├── PPIScope (abstract)
|
||||
│ ├── MarinePPIScope
|
||||
│ └── ATCPPIScope
|
||||
└── PARScope
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Class Descriptions
|
||||
|
||||
### Scope (abstract base)
|
||||
Everything all scopes share:
|
||||
- Left panel text rendering
|
||||
- `s` / `S` key handling (scope advance / reverse)
|
||||
- Auto-advance timer reset on any key or control input
|
||||
- Pure virtual methods: `render()`, `handleKey()`, `getDescription()`
|
||||
|
||||
### ExhibitIntro : public Scope
|
||||
- Text-only rendering, no radar display
|
||||
- Header: "WELCOME TO MUSEUM VINTAGE RADAR EXHIBIT" (all caps)
|
||||
- Emphasizes s/S keys and 120-second auto-advance
|
||||
|
||||
### AScope : public Scope (abstract)
|
||||
Shared A-scope behavior:
|
||||
- Horizontal range axis, vertical amplitude axis
|
||||
- Noise floor rendering (rain/wave clutter)
|
||||
- Incandescent graticule (three horizontal amplitude lines + vertical range lines)
|
||||
- Bearing control with key-hold acceleration
|
||||
- Phosphor type as parameter (P1 or P7)
|
||||
|
||||
### MarineAScope : public AScope
|
||||
- P1 phosphor (green)
|
||||
- Range settings: 2, 4, 6 miles
|
||||
- Max 2: one interim range at 1
|
||||
- Max 4: one interim range at 2
|
||||
- Max 6: one interim range at 4
|
||||
- Keys: c (bearing CW), v (bearing CCW), u (range up), d (range down)
|
||||
- u and d are ignored during graticule swap animation
|
||||
|
||||
**Graticule swap animation:**
|
||||
In the period, changing max range required the operator to physically slide the glass
|
||||
graticule panel upward and out from in front of the CRT, then slide the replacement
|
||||
graticule (calibrated for the new range) downward into position. This is simulated.
|
||||
|
||||
State machine triggered by u or d key:
|
||||
|
||||
NORMAL graticule in place, scope operating normally
|
||||
|
|
||||
| u or d pressed
|
||||
v
|
||||
SLIDING_OUT old graticule translates upward off screen (~0.5 seconds)
|
||||
|
|
||||
v
|
||||
BARE_CRT no graticule rendered; CRT trace and noise floor still running
|
||||
|
|
||||
v
|
||||
SLIDING_IN new graticule slides down into position (~0.5 seconds)
|
||||
|
|
||||
v
|
||||
NORMAL new range now active
|
||||
|
||||
- u and d keys ignored while state != NORMAL
|
||||
- Graticule remains incandescent color throughout (edge-lit glass, not CRT-dependent)
|
||||
|
||||
### ChainHomeAScope : public AScope
|
||||
- P7 phosphor (early implementation, slow decay for slow PRF)
|
||||
- Goniometer state: H/V mode toggle, azimuth angle, elevation angle
|
||||
- PRF toggle: 25 Hz / 12.5 Hz
|
||||
- Calibrator stretch/shrink scale factor
|
||||
- Fixed 100-mile range (no range change)
|
||||
- Keys: [ (goniometer H/V toggle), 9 (tune left), 0 (tune right),
|
||||
. (PRF toggle), n (calibrator shrink), m (calibrator stretch)
|
||||
|
||||
### PPIScope : public Scope (abstract)
|
||||
Shared PPI behavior:
|
||||
- Clockwise sweep with P7 phosphor persistence
|
||||
- Immediate beam strike: blue
|
||||
- Persistence: green/yellow, faded by next sweep pass
|
||||
- Incandescent bearing graticule:
|
||||
- Inner ring with 1-degree tick marks (0–359, True North = 0)
|
||||
- Text labels every 15 degrees
|
||||
- Outer ring
|
||||
- Yellow cursor: 10-degree arc section + bearing crossline
|
||||
- Cursor range/bearing readout displayed under scope (white text)
|
||||
- Bearing offset for boat mode (k = right, j = left)
|
||||
- Keys: r (cursor bearing right), l (cursor bearing left),
|
||||
t (cursor range increase), y (cursor range decrease),
|
||||
k (antenna bearing offset right), j (antenna bearing offset left)
|
||||
- Cursor range clamped to max range if exceeded
|
||||
|
||||
### MarinePPIScope : public PPIScope
|
||||
- Sweep time: 4 seconds
|
||||
- Max range settings: 2, 4, 6 miles
|
||||
- Max 2: rings at 1, 2
|
||||
- Max 4: rings at 2, 4
|
||||
- Max 6: rings at 4, 6
|
||||
- Keys: u (range up), d (range down) — affects only this scope
|
||||
|
||||
### ATCPPIScope : public PPIScope
|
||||
- Sweep time: 5 seconds
|
||||
- Max range settings: 5, 10, 15, 20 miles
|
||||
- Max 5: rings at 2.5, 5
|
||||
- Max 10: rings at 2, 4, 6, 8, 10
|
||||
- Max 15: rings at 4, 8, 12, 15
|
||||
- Max 20: rings at 5, 10, 15, 20
|
||||
- Keys: u (range up), d (range down) — affects only this scope
|
||||
|
||||
### PARScope : public Scope
|
||||
- Two vertically stacked sub-scopes (right panel):
|
||||
- Top: azimuth (lateral deviation vs. range) — ~1/3 larger
|
||||
- Bottom: elevation (vertical deviation vs. range)
|
||||
- P7 phosphor; graticules are incandescent etched glass
|
||||
- 30 Hz alternating scan between azimuth and elevation planes
|
||||
(each plane scans at ~15 Hz, i.e., 1/15 second per plane)
|
||||
- Fixed 10-mile range — no range change control
|
||||
- Non-linear horizontal scale: inner 5 miles occupies 70% of width
|
||||
- All targets simulated; no cursor or bearing controls
|
||||
- Located at south end of Runway 16/34, BLI — active runway 34 (northbound)
|
||||
|
||||
---
|
||||
|
||||
## Supporting Classes
|
||||
|
||||
| Class | Thread | Purpose |
|
||||
|---|---|---|
|
||||
| `ScopeManager` | 1 | Owns scope list; handles s/S switching and 120s auto-advance timer |
|
||||
| `PhosphorRenderer` | 1 | P1 and P7 decay/persistence simulation; shared dependency |
|
||||
| `Graticule` | 1 | Draws incandescent graticule lines and text; parameterized per scope |
|
||||
| `LeftPanel` | 1 | Renders scope description text panel (left side of window) |
|
||||
| `SharedRenderState` | 1,2,3 | Mutex A — state variables Thread 1 reads each frame to push as shader uniforms |
|
||||
| `TargetBuffer` | 2,4 | Mutex B — target data handoff between Thread 2 (traffic cop) and Thread 4 (simulator) |
|
||||
| `TrafficCop` | 2 | Polls Simulator and RPi receivers each beam update; writes targets to SharedRenderState |
|
||||
| `Simulator` | 4 | Runs fake targets independently; returns data to TrafficCop when polled |
|
||||
| `KnobPanel` | 3 | Future hardware stub — writes to SharedRenderState under Mutex A |
|
||||
| `RPiReceiver` | 2 | Stub — one instance per Raspberry Pi; called by TrafficCop |
|
||||
|
||||
---
|
||||
|
||||
## Thread Summary
|
||||
|
||||
| Thread | Class(es) | Mutex Access |
|
||||
|---|---|---|
|
||||
| Thread 1 | ScopeManager, all Scope subclasses, PhosphorRenderer, Graticule, LeftPanel | Reads SharedRenderState under Mutex A |
|
||||
| Thread 2 | TrafficCop, RPiReceiver | Writes SharedRenderState under Mutex A; reads TargetBuffer under Mutex B |
|
||||
| Thread 3 | KnobPanel | Writes SharedRenderState under Mutex A |
|
||||
| Thread 4 | Simulator | Writes TargetBuffer under Mutex B |
|
||||
|
||||
Keyboard input arrives via GLFW callback (glfwSetKeyCallback) in Thread 1.
|
||||
Thread 1 dispatches s/S to ScopeManager and all other keys to the active Scope.
|
||||
|
||||
---
|
||||
|
||||
## Proposed File Layout
|
||||
|
||||
```
|
||||
src/
|
||||
main.cpp — GLFW init, thread launch, main loop
|
||||
scope_manager.h / scope_manager.cpp
|
||||
scope.h / scope.cpp — abstract Scope base class
|
||||
scope_intro.h / scope_intro.cpp — ExhibitIntro
|
||||
scope_ascope.h / scope_ascope.cpp — abstract AScope
|
||||
scope_marine_a.h / scope_marine_a.cpp
|
||||
scope_chain_home.h / scope_chain_home.cpp
|
||||
scope_ppi.h / scope_ppi.cpp — abstract PPIScope
|
||||
scope_marine_ppi.h / scope_marine_ppi.cpp
|
||||
scope_atc_ppi.h / scope_atc_ppi.cpp
|
||||
scope_par.h / scope_par.cpp
|
||||
phosphor.h / phosphor.cpp
|
||||
graticule.h / graticule.cpp
|
||||
left_panel.h / left_panel.cpp
|
||||
shared_render_state.h / shared_render_state.cpp
|
||||
target_buffer.h / target_buffer.cpp
|
||||
traffic_cop.h / traffic_cop.cpp
|
||||
simulator.h / simulator.cpp
|
||||
knob_panel.h / knob_panel.cpp
|
||||
rpi_receiver.h / rpi_receiver.cpp
|
||||
settings.h — all tunable constants (no .cpp needed)
|
||||
|
||||
shaders/
|
||||
phosphor.vert / phosphor.frag — parameterized for P1 and P7 via uniforms
|
||||
graticule.vert / graticule.frag
|
||||
text.vert / text.frag
|
||||
sweep.vert / sweep.frag
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Design Notes
|
||||
|
||||
1. **ScopeManager** sits in Thread 1 and holds the active scope pointer. The GLFW
|
||||
key callback calls ScopeManager::handleKey(), which dispatches s/S to itself
|
||||
and all other keys to the active scope. The auto-advance timer resets on any
|
||||
key event or control input.
|
||||
|
||||
2. **SharedRenderState** holds two categories: control state (bearing, range,
|
||||
cursor — written by Thread 1 keyboard callbacks and Thread 3 knob panel) and
|
||||
target state (written by Thread 2). Thread 1 reads the whole struct once per
|
||||
frame under Mutex A to push uniforms to the shaders.
|
||||
|
||||
3. **TargetBuffer** is separate from SharedRenderState — it is the handoff point
|
||||
between Thread 2 (traffic cop) and Thread 4 (simulator) under Mutex B.
|
||||
|
||||
4. **PhosphorRenderer** is a shared utility. AScope and PPIScope subclasses
|
||||
receive it as a constructor dependency rather than each reimplementing decay
|
||||
logic. Pass phosphor type (P1/P7) and decay constant as parameters.
|
||||
|
||||
5. **Shaders** are parameterized via uniforms rather than duplicated. A single
|
||||
phosphor shader pair handles both P1 (green, no persistence) and P7 (blue
|
||||
strike, yellow-green decay) by passing color and decay time as uniforms.
|
||||
|
||||
6. **Shoreline and terrain geometry** is loaded once at Thread 1 startup as a
|
||||
static VBO. It is read-only after load — no mutex needed.
|
||||
|
||||
7. **Each scope's max range and cursor state are independent.** Changing range
|
||||
on the Marine PPI does not affect the ATC PPI, and vice versa. State is
|
||||
owned by each scope instance.
|
||||
|
||||
8. **PAR sub-scopes** (azimuth and elevation) can be implemented as private
|
||||
member objects within PARScope rather than as separate Scope subclasses,
|
||||
since they are never displayed independently.
|
||||
|
||||
9. **settings.h** is a header-only file (no .cpp). It will contain only
|
||||
`constexpr` constants organized into named sections. Every other source
|
||||
file that needs a tunable value includes this file. No magic numbers
|
||||
anywhere else in the codebase. Add candidate variables here before
|
||||
coding begins; values can be refined during debugging and appearance work.
|
||||
|
||||
10. **MarineAScope graticule swap** is a state machine with four states:
|
||||
NORMAL → SLIDING_OUT → BARE_CRT → SLIDING_IN → NORMAL. The u and d keys
|
||||
are blocked during the animation. The new range value is latched when the
|
||||
key is pressed but not applied to the scope state until SLIDING_IN completes.
|
||||
Animation duration is approximately 0.5 seconds per slide (out and in).
|
||||
181
src/settings.h
Normal file
181
src/settings.h
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* MIT License
|
||||
* Author: Mark Allyn
|
||||
*
|
||||
* settings.h
|
||||
*
|
||||
* Central location for all tunable constants and appearance variables.
|
||||
* Edit values here to adjust rendering, timing, and behavior without
|
||||
* touching any other source file.
|
||||
*
|
||||
* NOTE: This file is a planning document. C++ declarations will be
|
||||
* added once all variables have been identified and agreed upon.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* PHOSPHOR — P1 (Marine A-Scope)
|
||||
* ================================================================
|
||||
*
|
||||
* P1_COLOR_R Red component of P1 phosphor green
|
||||
* P1_COLOR_G Green component of P1 phosphor green
|
||||
* P1_COLOR_B Blue component of P1 phosphor green
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* PHOSPHOR — P7 (Marine PPI, ATC PPI, PAR, Chain Home A-Scope)
|
||||
* ================================================================
|
||||
*
|
||||
* P7_STRIKE_R Red component of initial beam strike (blue)
|
||||
* P7_STRIKE_G Green component of initial beam strike (blue)
|
||||
* P7_STRIKE_B Blue component of initial beam strike (blue)
|
||||
*
|
||||
* P7_PERSIST_R Red component of persistence color (yellow-green)
|
||||
* P7_PERSIST_G Green component of persistence color (yellow-green)
|
||||
* P7_PERSIST_B Blue component of persistence color (yellow-green)
|
||||
*
|
||||
* P7_DECAY_TIME Decay time constant in seconds (PPI scopes and PAR)
|
||||
* P7_DECAY_TIME_CH Decay time constant for Chain Home — longer, must
|
||||
* survive between slow PRF pulses (25 Hz / 12.5 Hz)
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* SWEEP
|
||||
* ================================================================
|
||||
*
|
||||
* SWEEP_LINE_WIDTH Width of the rotating sweep line in pixels
|
||||
* SWEEP_LINE_BRIGHTNESS Brightness multiplier for the sweep line (0.0–1.0)
|
||||
* SWEEP_FADE_TRAIL_DEGREES How many degrees behind the sweep line the bright
|
||||
* afterglow trails before transitioning to P7 decay
|
||||
*
|
||||
* MARINE_PPI_SWEEP_PERIOD Full rotation period in seconds (4.0)
|
||||
* ATC_PPI_SWEEP_PERIOD Full rotation period in seconds (5.0)
|
||||
*
|
||||
* PAR_SCAN_RATE_HZ PAR alternating scan rate in Hz (30)
|
||||
*
|
||||
* CHAIN_HOME_PRF_HIGH_HZ Chain Home high PRF in Hz (25)
|
||||
* CHAIN_HOME_PRF_LOW_HZ Chain Home low PRF in Hz (12.5)
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* GRATICULE — General
|
||||
* ================================================================
|
||||
*
|
||||
* GRATICULE_COLOR_R Red component of incandescent graticule color
|
||||
* GRATICULE_COLOR_G Green component of incandescent graticule color
|
||||
* GRATICULE_COLOR_B Blue component of incandescent graticule color
|
||||
* GRATICULE_LINE_WIDTH Width of graticule lines in pixels
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* GRATICULE — PPI Bearing Ring
|
||||
* ================================================================
|
||||
*
|
||||
* PPI_TICK_MAJOR_LENGTH Length of major tick marks (every 10 degrees)
|
||||
* PPI_TICK_MINOR_LENGTH Length of minor tick marks (every 1 degree)
|
||||
* PPI_TICK_LINE_WIDTH Width of tick mark lines
|
||||
* PPI_LABEL_INTERVAL_DEG Degrees between text labels (15)
|
||||
* PPI_LABEL_FONT_SIZE Font size for bearing labels
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* GRATICULE — PPI Range Rings
|
||||
* ================================================================
|
||||
*
|
||||
* RANGE_RING_LINE_WIDTH Width of range ring lines in pixels
|
||||
* RANGE_RING_LABEL_SIZE Font size for range ring distance labels
|
||||
* RANGE_RING_LABEL_R Red component (P7 color — blue fading to yellow-green)
|
||||
* RANGE_RING_LABEL_G Green component
|
||||
* RANGE_RING_LABEL_B Blue component
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* CURSOR (PPI scopes)
|
||||
* ================================================================
|
||||
*
|
||||
* CURSOR_COLOR_R Red component of cursor color (yellow)
|
||||
* CURSOR_COLOR_G Green component of cursor color (yellow)
|
||||
* CURSOR_COLOR_B Blue component of cursor color (yellow)
|
||||
* CURSOR_LINE_WIDTH Width of cursor arc and bearing line in pixels
|
||||
* CURSOR_ARC_SPAN_DEG Angular span of the cursor arc in degrees (10)
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* NOISE FLOOR (Marine A-Scope)
|
||||
* ================================================================
|
||||
*
|
||||
* NOISE_FLOOR_AMPLITUDE Baseline amplitude of the noise floor (0.0–1.0)
|
||||
* NOISE_FLOOR_VARIATION Random variation range added to baseline
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* GRATICULE SWAP ANIMATION (Marine A-Scope)
|
||||
* ================================================================
|
||||
*
|
||||
* GRATICULE_SLIDE_OUT_TIME Duration of old graticule sliding out in seconds
|
||||
* GRATICULE_BARE_CRT_TIME Duration of bare CRT pause between slides in seconds
|
||||
* GRATICULE_SLIDE_IN_TIME Duration of new graticule sliding in in seconds
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* KEY-HOLD ACCELERATION
|
||||
* ================================================================
|
||||
*
|
||||
* KEY_INITIAL_STEP Step size for a single key press (degrees or miles)
|
||||
* KEY_ACCEL_RATE Rate at which step size grows while key is held
|
||||
* KEY_MAX_STEP Maximum step size regardless of hold duration
|
||||
*
|
||||
* KEY_GONIO_INITIAL_STEP Initial step for goniometer tuning (must stay slow
|
||||
* to allow precise null finding)
|
||||
* KEY_GONIO_ACCEL_RATE Acceleration rate for goniometer (slow build)
|
||||
* KEY_GONIO_MAX_STEP Maximum goniometer step size
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* AUTO-ADVANCE TIMER
|
||||
* ================================================================
|
||||
*
|
||||
* SCOPE_AUTO_ADVANCE_SEC Seconds before auto-advancing to next scope (120)
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* WINDOW AND LAYOUT GEOMETRY
|
||||
* ================================================================
|
||||
*
|
||||
* WINDOW_WIDTH Initial window width in pixels
|
||||
* WINDOW_HEIGHT Initial window height in pixels
|
||||
* LEFT_PANEL_WIDTH_FRAC Left description panel as fraction of window width
|
||||
* RIGHT_PANEL_WIDTH_FRAC Right scope panel as fraction of window width
|
||||
*
|
||||
* PAR_AZIMUTH_HEIGHT_FRAC Azimuth scope height as fraction of right panel height
|
||||
* PAR_ELEVATION_HEIGHT_FRAC Elevation scope height as fraction of right panel height
|
||||
*/
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* TEXT
|
||||
* ================================================================
|
||||
*
|
||||
* UI_TEXT_COLOR_R Red component of general UI text (white)
|
||||
* UI_TEXT_COLOR_G Green component of general UI text (white)
|
||||
* UI_TEXT_COLOR_B Blue component of general UI text (white)
|
||||
* UI_TEXT_SIZE Font size for general UI / description text
|
||||
*
|
||||
* CURSOR_READOUT_TEXT_SIZE Font size for cursor range/bearing readout
|
||||
* displayed under PPI scope
|
||||
*
|
||||
* GRATICULE_LABEL_COLOR_R Red component of graticule text (incandescent)
|
||||
* GRATICULE_LABEL_COLOR_G Green component
|
||||
* GRATICULE_LABEL_COLOR_B Blue component
|
||||
*/
|
||||
Reference in New Issue
Block a user