You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
542 lines
21 KiB
542 lines
21 KiB
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
**vzug-e-hinge Test & Control System** - A PyQt6-based desktop application for testing and controlling e-hinge devices through UART and I2C interfaces. The system provides automated test session execution, real-time data logging, packet detection, and telemetry storage in SQLite.
|
|
|
|
## Running the Application
|
|
|
|
```bash
|
|
# Install dependencies
|
|
pip install -r requirements.txt
|
|
|
|
# Run the application (uses default database path: ./database/ehinge.db)
|
|
python main.py
|
|
|
|
# Run with custom database path
|
|
python main.py /path/to/custom.db
|
|
```
|
|
|
|
## Database Management
|
|
|
|
```bash
|
|
# Initialize/recreate database
|
|
python database/init_database.py
|
|
|
|
# Recreate database (overwrite existing)
|
|
python database/init_database.py --overwrite
|
|
|
|
# Check database health
|
|
python database/init_database.py --check
|
|
```
|
|
|
|
## Architecture
|
|
|
|
### Application Entry Point
|
|
- `main.py` - Main application window with tabbed interface (Session, Configure Session, Configure Interface, UART, I2C, Graph)
|
|
- `MainWindow` class manages all tabs and coordinates database connection
|
|
|
|
### Core Session Execution Flow
|
|
|
|
The application uses a **three-layer execution model**:
|
|
|
|
1. **Session Layer** (`session.py`) - Orchestrates the complete test session
|
|
- Loads interface and session profiles from database
|
|
- Opens/closes hardware ports (UART command, UART logger, I2C)
|
|
- Manages command sequence execution
|
|
- Handles pause/stop requests (queued after current run)
|
|
- Emits PyQt signals for real-time GUI updates
|
|
|
|
2. **Run Layer** (`run.py`) - Executes a single RUN (one command with data collection)
|
|
- Configures packet detection with callback
|
|
- Sends UART command via command port
|
|
- Collects telemetry packets from logger port (if enabled)
|
|
- Triggers I2C reads correlated to UART timestamps
|
|
- Decodes data and saves to database
|
|
|
|
3. **Hardware Layer** (`uart/uart_kit/uart_core.py`, `i2c/i2c_kit/i2c_core.py`) - Low-level interface management
|
|
- UART: Packet detection, circular buffer, reader threads, timestamping
|
|
- I2C: Bus operations, device scanning, continuous logging
|
|
|
|
### Critical Architectural Concepts
|
|
|
|
#### Dual UART Port System
|
|
The application uses **two separate UART ports** for different purposes:
|
|
- **UART Command Port** (TX/RX): Sends commands to device and receives ACK/responses
|
|
- **UART Logger Port** (RX only, optional): Receives telemetry packets from device
|
|
- This separation allows simultaneous command sending and telemetry logging
|
|
- Logger port can be disabled for simple command/response mode
|
|
|
|
#### Packet Detection vs. Raw Mode
|
|
- **Packet Detection Enabled**: UART Logger port detects packets with start/end markers, used for telemetry streams
|
|
- **Packet Detection Disabled**: Raw TX/RX mode for simple command/response (set `print_command_rx=True` in session profile)
|
|
|
|
#### Queued Pause/Stop
|
|
- Pause and Stop requests are **queued** and execute AFTER the current run completes
|
|
- Users can press pause/stop anytime, but it only takes effect during the delay phase between runs
|
|
- This prevents data corruption by ensuring runs complete atomically
|
|
|
|
#### PGKomm2 Protocol (V-ZUG Serial Communication)
|
|
The e-hinge devices use **PGKomm2** protocol (V-ZUG spec A5.5093D-AB) for UART communication:
|
|
|
|
**Frame Format:**
|
|
```
|
|
DD 22 | ADR1 ADR2 | LEN | DATA (0-255 bytes) | BCC
|
|
MAGIC | Address | Len | Payload | Checksum
|
|
```
|
|
|
|
**Key Characteristics:**
|
|
- **MAGIC**: `0xDD` (221), **INVMAGIC**: `0x22` (34)
|
|
- **Length-delimited**: LEN field specifies DATA length (no terminator bytes like `\n`)
|
|
- **Address swap**: Slave response swaps ADR1/ADR2 (if master sends `PH`, slave responds `HP`)
|
|
- **BCC**: Block check character calculated from ADR1 through DATA (XOR checksum) - **VALIDATED on receive**
|
|
- **Timing**: Response time < 15 ms, inter-byte time < 10 ms
|
|
- **Baud rates**: 4800 or 115200 baud, 8N1 with **Even Parity**
|
|
|
|
**Common Addresses:**
|
|
- `PH` (`0x50 0x48`): Command from master → Echo from slave
|
|
- `HP` (`0x48 0x50`): Response from slave
|
|
- `SB` (`0x53 0x42`): Status broadcast
|
|
|
|
**Multiple Frames:**
|
|
Device typically sends multiple frames per command:
|
|
1. **Echo (PH)**: Device echoes received command
|
|
2. **Response (HP)**: Actual response with data
|
|
3. **Status (SB)**: Optional status update
|
|
|
|
Example:
|
|
```
|
|
TX: DD 22 50 48 02 43 4F 16 (Master sends PH command)
|
|
RX: DD 22 50 48 02 43 4F 16 (Echo: PH)
|
|
RX: DD 22 48 50 02 43 4F 16 (Response: HP, addresses swapped)
|
|
RX: DD 22 53 42 01 4E 5E (Status: SB)
|
|
```
|
|
|
|
**Documentation:**
|
|
- Protocol spec: `v_zug_documentation/PGKomm2_Spec_A5.5093D_AB.pdf`
|
|
- Application telegrams: `v_zug_documentation/PgKomm2_ Application Telegrams-v122-20230417_181422.pdf`
|
|
|
|
**Quick Start (Final Working Implementation):**
|
|
1. **GUI defaults** automatically set: Parity=Even, Mode=PGKomm2, Timeout=30ms
|
|
2. **Connect** → waits 100ms settle delay
|
|
3. **First 1-2 commands may timeout** (device synchronization)
|
|
4. **After 3-4 commands** → rock solid reliability
|
|
5. **BCC errors logged to console** if frame corruption detected
|
|
|
|
**Implementation Notes (`uart/uart_kit/uart_core.py::uart_send_and_read_pgkomm2()`):**
|
|
|
|
The implementation uses a **simple single-loop approach** (matches old working code exactly):
|
|
|
|
```python
|
|
# Flush buffer and send
|
|
reset_input_buffer()
|
|
uart_write(tx_data)
|
|
|
|
# Single loop with deadline
|
|
deadline = now + 30ms # Total timeout (spec <15ms + real-world margin)
|
|
while now < deadline:
|
|
if bytes_available:
|
|
rx_buffer += read_all_available() # Read IMMEDIATELY
|
|
|
|
# Extract frames using LEN field
|
|
while True:
|
|
frame = extract_frame(rx_buffer) # Uses LEN to know size
|
|
validate_BCC(frame) # Reject corrupted
|
|
|
|
if frame is None:
|
|
break # Need more bytes
|
|
|
|
collected_frames.append(frame)
|
|
|
|
if frame.address == HP:
|
|
return collected_frames # Stop on HP!
|
|
|
|
# No sleep - just spin
|
|
```
|
|
|
|
**Key Implementation Details:**
|
|
- **Single timeout (30ms)**: Total window for entire operation (spec says < 15ms, +15ms margin for real-world conditions)
|
|
- **Read immediately**: When bytes arrive, read them instantly (no delays)
|
|
- **No sleep**: Pure spinning for minimum latency
|
|
- **Stop on HP**: Exits immediately when HP response detected
|
|
- **BCC validation**: Every frame validated before acceptance - corrupted frames rejected and logged
|
|
- **LEN field**: Uses frame length to know exactly how many bytes to read
|
|
- **Simple**: No phases, no grace periods, just read-parse-detect loop
|
|
- **Debug logging**: TIMEOUT and IO_ERROR cases logged with buffer contents for diagnostics
|
|
|
|
**Default GUI Settings (for PGKomm2):**
|
|
- **Parity**: Even (required by spec)
|
|
- **Mode**: PGKomm2
|
|
- **Timeout**: 30ms (hidden, automatic)
|
|
|
|
**Why 30ms (not 15ms)?**
|
|
- **Spec says < 15ms**: Ideal conditions only
|
|
- **Real world**: Background SB telemetry, device load, USB latency, reader thread stop/restart add overhead
|
|
- **Testing results**: 20ms still showed occasional timeouts, 30ms more reliable
|
|
- **Still fast**: Stops immediately on HP detection (typically 8-12ms actual response time)
|
|
|
|
**Error Handling:**
|
|
- **TIMEOUT**: No data received within 30ms (device not responding) or got frames but no HP response
|
|
- **IO_ERROR**: Unparseable data in buffer (incomplete frame or BCC failure)
|
|
- **BCC ERROR**: Logged to console when checksum validation fails (electrical noise/corruption)
|
|
- Format: `[PGKOMM2] ✗ BCC FAIL: ADR=XX YY, calc=ZZ, recv=WW`
|
|
- Shows calculated vs received BCC and full frame hex dump
|
|
|
|
**Connection Behavior:**
|
|
- **100ms settle delay**: After port opens, waits 100ms for device to stabilize
|
|
- **Reason**: Device may reset on DTR/RTS change, needs boot/initialization time
|
|
- **First commands**: May still timeout if device is sending SB status broadcasts
|
|
- **After 3-4 commands**: Device synchronized, all commands work reliably
|
|
|
|
**Threading Architecture:**
|
|
- **UART Reader Thread**: Always running (except during PGKomm2 operations)
|
|
- Reads serial port → circular buffer continuously
|
|
- Most modes read from circular buffer
|
|
- **PGKomm2**: No worker thread - called directly from GUI thread
|
|
- Blocks GUI for ~30ms (acceptable, keeps threading simple)
|
|
- **Temporarily stops reader thread** for exclusive serial access (prevents race condition)
|
|
- Reads directly from serial port (not circular buffer - lower latency)
|
|
- Restarts reader thread after completion
|
|
- **Why stop reader thread?**: PGKomm2 needs direct serial reads for low latency. Stopping reader prevents both threads competing for same bytes.
|
|
|
|
**Key Design Decisions (Lessons Learned):**
|
|
|
|
1. **Simplicity Over Complexity**
|
|
- Tried: Worker threads, two-phase reading, packet-driven with circular buffer
|
|
- Final: Direct serial reads with reader thread temporarily stopped
|
|
- Lesson: Simple approach that matches old working code is best
|
|
|
|
2. **Timeout Tuning**
|
|
- Spec: < 15ms response time
|
|
- Reality: 30ms needed (background telemetry, thread overhead, USB latency)
|
|
- Testing: 15ms → occasional timeouts, 20ms → still issues, 30ms → reliable
|
|
|
|
3. **Thread Safety**
|
|
- Problem: Reader thread and PGKomm2 competing for serial bytes (race condition)
|
|
- Solution: Stop reader during PGKomm2 operations (exclusive access)
|
|
- Benefit: Simple, predictable, no race conditions
|
|
|
|
4. **BCC Validation Critical**
|
|
- Initially: Not validated (trusted device)
|
|
- Reality: Occasional electrical noise/corruption
|
|
- Solution: Validate BCC, log errors, reject corrupted frames
|
|
- Result: More robust, easier debugging
|
|
|
|
5. **First Commands After Connect**
|
|
- Device needs time to stabilize after DTR/RTS change
|
|
- 100ms settle delay helps but not sufficient
|
|
- Accept first 1-2 timeouts as normal device synchronization
|
|
- After 3-4 commands: rock solid
|
|
|
|
**PGKomm2 Implementation Status: ✅ Production Ready**
|
|
|
|
### Database Schema
|
|
|
|
Located in `database/init_database.py`:
|
|
|
|
**Profiles:**
|
|
- `interface_profiles` - Hardware configuration (UART command/logger ports, I2C bus, packet detection settings)
|
|
- `session_profiles` - Test sequences (JSON command list with delays and repetitions)
|
|
- `gui_profiles` - GUI appearance settings
|
|
|
|
**Execution:**
|
|
- `sessions` - Session records (links to profiles, tracks total runs, status)
|
|
- `uart_commands` - Predefined UART commands (hex strings, categories)
|
|
- `i2c_commands` - Predefined I2C operations (register access)
|
|
|
|
**Telemetry:**
|
|
- `telemetry_raw` - Raw backup data (UART packets and I2C bytes as BLOB)
|
|
- `telemetry_decoded` - Processed data (motor current, encoder values, angles, etc.)
|
|
|
|
Both telemetry tables use nanosecond timestamps (`t_ns`) for precise correlation between UART and I2C data.
|
|
|
|
### Widget Organization
|
|
|
|
**Configuration Widgets:**
|
|
- `configure_interface_widget.py` - Create/edit interface profiles (UART/I2C settings)
|
|
- `configure_session_widget.py` - Create/edit session profiles (command sequences)
|
|
|
|
**Control Widgets:**
|
|
- `session_widget.py` - Main control panel for running sessions (start/pause/stop, profile selection, status display)
|
|
- `uart/uart_integrated_widget.py` - Manual UART testing (command table + direct control)
|
|
- `i2c/i2c_integrated_widget.py` - Manual I2C testing (command table + direct control)
|
|
|
|
**UART Widget Modes (`uart/uart_kit/uart_core_widget.py`):**
|
|
The UART widget supports 4 operational modes:
|
|
|
|
1. **Request-Response**: Send command, wait for response packet (timeout or terminator-based)
|
|
- Uses packet detection with configurable stop condition
|
|
- Best for generic packet-based protocols
|
|
|
|
2. **Polling**: Continuous packet detection with grace period
|
|
- Waits for first byte (grace period), then captures burst
|
|
- Supports packet detection with callbacks
|
|
- Best for streaming telemetry
|
|
|
|
3. **Listening**: Raw stream mode with no stop condition
|
|
- Captures everything continuously
|
|
- Manual buffer reading required
|
|
- Best for debugging and raw data capture
|
|
|
|
4. **PGKomm2**: V-ZUG protocol with DD 22 framing and automatic HP detection
|
|
- **Automatic response detection** - No timing configuration needed
|
|
- Stops immediately when HP response detected (typically 5-10ms)
|
|
- 20ms safety timeout (hardcoded, hidden from user)
|
|
- Automatically parses multiple frames (PH echo + HP response)
|
|
- Identifies frame types by address bytes (PH/HP/SB)
|
|
- **Requires EVEN parity** (115200 8E1 per spec)
|
|
- **Use this mode for e-hinge device communication**
|
|
|
|
**Session Worker:**
|
|
- `session_worker.py` - QThread wrapper for running sessions in background without blocking GUI
|
|
|
|
### Supporting Modules
|
|
|
|
- `decoder.py` - Packet decoding logic (UART telemetry and I2C angle conversion)
|
|
- `global_clock.py` - Shared timestamp source for UART/I2C synchronization
|
|
- `graph_table_query.py` - Database query utilities for graphing
|
|
- `buffer_kit/circular_buffer.py` - Thread-safe circular buffer for data streams
|
|
- `command_table/command_table.py` - Reusable command table widget
|
|
|
|
## Development Workflow
|
|
|
|
### Adding New UART Commands
|
|
1. Insert into `uart_commands` table via database or GUI
|
|
2. Commands are immediately available in session profiles and manual testing
|
|
3. Format: `hex_string` as space-separated hex bytes (e.g., "DD 22 50 48 02 41 52 09")
|
|
|
|
### Creating Test Profiles
|
|
1. Create interface profile with port settings and packet detection config
|
|
2. Create session profile with JSON command sequence:
|
|
```json
|
|
{
|
|
"commands": [
|
|
{
|
|
"command_id": 1,
|
|
"delay_ms": 3000
|
|
},
|
|
{
|
|
"command_id": 5,
|
|
"delay_ms": 5000
|
|
}
|
|
]
|
|
}
|
|
```
|
|
3. Use session widget to execute profile
|
|
|
|
### Database Size Management
|
|
- Max size: 2 GB (configured in `init_database.py`)
|
|
- Monitor via status bar (shows percentage and color-coded warning)
|
|
- Use "Database > Vacuum Database" to reclaim space after deletions
|
|
|
|
## Port Configuration Notes
|
|
|
|
**UART Ports:**
|
|
- Linux: `/dev/ttyUSB0`, `/dev/ttyACM0`, etc.
|
|
- Must have read/write permissions (add user to `dialout` group)
|
|
- Typical baud rates: 9600, 115200
|
|
|
|
**I2C Bus:**
|
|
- Linux: Bus ID corresponds to `/dev/i2c-X` (e.g., bus_id=1 means `/dev/i2c-1`)
|
|
- Requires `smbus2` library
|
|
- Must have read/write permissions (add user to `i2c` group)
|
|
|
|
## Signal/Slot Architecture
|
|
|
|
The Session class emits PyQt signals for GUI updates:
|
|
- `session_started(session_id)` - Session begins
|
|
- `command_started(command_no, command_name)` - Command starts
|
|
- `run_completed(run_no, packet_count)` - Run finishes
|
|
- `delay_countdown(seconds_remaining)` - Countdown during delays
|
|
- `session_paused()` - Session paused
|
|
- `session_finished()` - Session completes
|
|
- `error_occurred(error_message)` - Error encountered
|
|
- `status_changed(status_text)` - General status update
|
|
- `raw_data_received(direction, hex_string)` - TX/RX data for display
|
|
|
|
Connect to these signals in widgets for real-time updates without polling.
|
|
|
|
## Testing
|
|
|
|
Individual modules can be tested directly:
|
|
```bash
|
|
# Test UART core
|
|
python uart/uart_kit/uart_core.py
|
|
|
|
# Test I2C core
|
|
python i2c/i2c_kit/i2c_core.py
|
|
|
|
# Test circular buffer
|
|
python buffer_kit/circular_buffer_test.py
|
|
```
|
|
|
|
## Code Style Notes
|
|
|
|
- Type hints used throughout (Python 3.10+)
|
|
- Dataclasses for configuration structures
|
|
- Enums for status codes and modes
|
|
- Thread-safe operations with locks where needed
|
|
- Extensive docstrings with Args/Returns/Raises sections
|
|
|
|
---
|
|
|
|
## Technical Challenges & Solutions
|
|
|
|
### Challenge 1: GUI Threading & Responsiveness
|
|
**Problem:** Qt requires GUI to never block. Session execution is a long-running loop that would freeze the interface.
|
|
|
|
**Solution:** `session_worker.py` - QThread wrapper that:
|
|
- Runs session in background thread
|
|
- Creates thread-local SQLite connection (SQLite objects cannot cross threads)
|
|
- Uses Qt signals for thread-safe GUI updates
|
|
- Swaps database connections before/after execution
|
|
|
|
**Critical Code:**
|
|
```python
|
|
# session_worker.py
|
|
thread_db_conn = sqlite3.connect(self.db_path) # Thread-local
|
|
self.session.db_conn = thread_db_conn # Temporary swap
|
|
self.session.start_session() # Blocking call runs in background
|
|
```
|
|
|
|
### Challenge 2: Timestamp Correlation (UART ↔ I2C)
|
|
**Problem:** UART packets arrive at unpredictable times. I2C angle readings must be timestamped at the exact moment the UART packet is detected to correlate motor state with door position.
|
|
|
|
**Solution:** Callback-based triggering in `run.py`:
|
|
```python
|
|
def on_uart_packet_detected(timestamp_ns: int):
|
|
"""Called IMMEDIATELY when packet detected"""
|
|
if i2c_port:
|
|
status, i2c_bytes = i2c_read_block(i2c_port, ...)
|
|
store_with_timestamp(timestamp_ns, i2c_bytes) # Same timestamp!
|
|
```
|
|
|
|
**Flow:**
|
|
1. UART reader thread detects packet start → captures `timestamp_ns`
|
|
2. Calls callback immediately with timestamp
|
|
3. Callback reads I2C angle sensor
|
|
4. Both readings share identical timestamp → perfect correlation in database
|
|
|
|
**Hardware Notes:**
|
|
- Two physically separate USB UART interfaces (command + logger)
|
|
- I2C read must complete before next UART packet arrives
|
|
- Blocking I2C read is acceptable if fast enough (<17 byte receive time @ baud rate)
|
|
|
|
### Challenge 3: Circular Buffer Absolute Positioning
|
|
**Problem:** Standard circular buffers wrap around. Need to extract data spans that might cross the wrap boundary using absolute offsets.
|
|
|
|
**Solution:** `buffer_kit/circular_buffer.py` tracks `write_absolute` (total bytes ever written):
|
|
```python
|
|
write_absolute: int # Monotonic counter, never wraps
|
|
position_in_buffer = write_absolute % capacity # Actual index
|
|
|
|
# Extract span handles wrapping automatically
|
|
cb_copy_span(buffer, start_abs=1000, end_abs=1050) # Works even if wrapped
|
|
```
|
|
|
|
**Use Case:** Read UART/I2C ring buffers after run completes, even if data wrapped during acquisition.
|
|
|
|
### Challenge 4: Grace Period vs Stop Timeout
|
|
**Problem:** Device may take time to respond. Need to distinguish:
|
|
- **Grace period**: Wait for FIRST byte after command sent
|
|
- **Stop timeout**: Silence between packets within a burst
|
|
|
|
**Solution in UART config:**
|
|
```python
|
|
polling_mode=True # Enable grace period
|
|
grace_timeout_ms=150 # Wait up to 150ms for first byte
|
|
stop_timeout_ms=150 # Silence between packets
|
|
```
|
|
|
|
**Behavior:**
|
|
1. Send command
|
|
2. Wait up to `grace_timeout_ms` for first byte → If no byte: "Device not responding"
|
|
3. Once first byte arrives, switch to stop condition mode
|
|
4. If `stop_timeout_ms` passes with no data → Packet burst complete
|
|
|
|
**Configured per interface profile** in `interface_profiles` table.
|
|
|
|
### Challenge 5: Buffer Sizing
|
|
**Configuration:** 40MB buffers for both UART and I2C
|
|
|
|
**Rationale:**
|
|
- Buffers cleared per run, not shared across runs
|
|
- Large buffers prevent overflow during long runs
|
|
- System has 8GB RAM + 32GB NVMe → 40MB per port is negligible
|
|
- Prevents data loss if device sends unexpected burst
|
|
|
|
**Locations:**
|
|
- Default: `uart_core.py` line 139, `i2c_core.py` line 72
|
|
- Session overrides: `session.py` _open_ports() method
|
|
|
|
### Challenge 6: Error Reporting
|
|
**Requirement:** Track I2C read failures without failing the entire run.
|
|
|
|
**Solution in `run.py`:**
|
|
```python
|
|
self.i2c_failures = 0 # Counter initialized
|
|
|
|
# In callback:
|
|
if i2c_read_status != OK:
|
|
self.i2c_failures += 1 # Count but continue
|
|
|
|
# At end of run:
|
|
if self.i2c_failures > 0:
|
|
raw_data_callback("ERROR", f"I2C failures: {self.i2c_failures}")
|
|
```
|
|
|
|
**Display:** Errors appear in GUI Data Monitor, not as run failure.
|
|
|
|
### Challenge 7: Queued Pause/Stop
|
|
**Problem:** User presses Stop during run execution. Cannot stop immediately (would corrupt data, leave hardware in bad state).
|
|
|
|
**Solution:** Flag-based queuing:
|
|
```python
|
|
self.stop_queued = False # Flag set by user action
|
|
|
|
# In command loop:
|
|
for cmd in commands:
|
|
if self.stop_queued: # Check BEFORE starting run
|
|
finalize_and_return()
|
|
|
|
execute_run(...) # Runs atomically
|
|
|
|
if self.stop_queued: # Check during delay
|
|
finalize_and_return()
|
|
```
|
|
|
|
**Behavior:** Pause/Stop take effect between runs, not during. Current run always completes.
|
|
|
|
## Configuration Details
|
|
|
|
### Stop Timeout Loading
|
|
**Fixed:** Stop timeout and grace period are now loaded from `interface_profiles` table and passed to `execute_run()`.
|
|
|
|
**Previous Issue:** Hardcoded 5000ms timeout → Now uses configured value (typically 150ms)
|
|
|
|
**Files Modified:**
|
|
- `session.py` line 190: Added `uart_logger_grace_ms` to SQL query
|
|
- `session.py` line 222: Added to `interface_config` dict
|
|
- `session.py` line 742: Changed from hardcoded 5000 to `interface_config['uart_logger_timeout_ms']`
|
|
- `session.py` lines 341-349, 378-388: Full UART config with all parameters
|
|
- `session.py` line 476: I2C config with 40MB buffer
|
|
|
|
### Typical Configuration Values
|
|
```python
|
|
uart_logger_timeout_ms = 150 # Packet silence timeout
|
|
uart_logger_grace_ms = 150 # Wait for first byte
|
|
uart_command_timeout_ms = 1000 # Command response timeout
|
|
buffer_size = 40 * 1024 * 1024 # 40MB per port
|
|
```
|
|
|
|
## Diagrams
|
|
|
|
Block diagrams available in `diagram/` folder:
|
|
- `Block Diagram.xml` - Overall system architecture (3 layers)
|
|
- `run.xml` - Single RUN execution flow
|
|
- `session.xml` - Session configuration and command loop
|
|
|
|
View with draw.io or compatible tool.
|