parent
2df374f4ef
commit
c563f45696
Binary file not shown.
@ -0,0 +1,319 @@
|
|||||||
|
# Session Summary - 2025-11-23
|
||||||
|
|
||||||
|
## Project: vguz_v2 - vzug-e-hinge Test & Control System
|
||||||
|
|
||||||
|
### Session Overview
|
||||||
|
Implemented complete session lifecycle management with port conflict prevention and fixed critical UART parity bug.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Work Completed This Session
|
||||||
|
|
||||||
|
### 1. Session Lifecycle Management with Port Conflict Prevention
|
||||||
|
|
||||||
|
**Problem**: When a session was loaded, UART and I2C tabs could still be accessed, potentially causing port conflicts. After session ended, there was no way to unload without starting the session.
|
||||||
|
|
||||||
|
**Solution Implemented**:
|
||||||
|
|
||||||
|
#### A. Session Widget (`session_widget.py`) - Lines modified:
|
||||||
|
- **Line 101**: Added `self.main_window = None` to store reference to main window
|
||||||
|
- **Line 350**: Added `set_main_window()` method to receive main window reference
|
||||||
|
- **Lines 182-185**: Added "Unload Session" button next to "Load Session"
|
||||||
|
- **Lines 436, 500-504**: Enable/disable Unload button appropriately
|
||||||
|
- **Lines 422, 440**: Call `_disable_port_tabs()` after successful load
|
||||||
|
- **Lines 591, 605**: Call `_cleanup_session()` in session finished and error handlers
|
||||||
|
- **Lines 727-757**: Added three new methods:
|
||||||
|
- `_disable_port_tabs()` - Disables UART (tab 3) and I2C (tab 4) tabs
|
||||||
|
- `_enable_port_tabs()` - Re-enables UART and I2C tabs
|
||||||
|
- `_cleanup_session()` - Complete cleanup: unload session, close ports, re-enable tabs, disable buttons
|
||||||
|
- **Lines 678-700**: Modified `_reset_controls()` and `_on_worker_finished()` to NOT re-enable Start button (must Load again)
|
||||||
|
|
||||||
|
#### B. Session Module (`session.py`) - Lines 335-377:
|
||||||
|
- Added `unload_session()` method:
|
||||||
|
- Closes all hardware ports (UART command, UART logger, I2C)
|
||||||
|
- Clears session state variables
|
||||||
|
- Resets execution flags
|
||||||
|
- Preserves session_name for display
|
||||||
|
- Does NOT clear UI selections (for easy re-run)
|
||||||
|
|
||||||
|
#### C. Enhanced Port Closing (`session.py`) - Lines 672-720:
|
||||||
|
- Improved `_close_ports()` with:
|
||||||
|
- Individual try/catch for each port
|
||||||
|
- 0.1s delays after stopping reader threads
|
||||||
|
- 0.2s final delay for OS to release ports
|
||||||
|
- Better error logging (warnings instead of errors)
|
||||||
|
|
||||||
|
#### D. Main Window (`main.py`) - Line 189:
|
||||||
|
- Added `self.session_widget.set_main_window(self)` to pass reference
|
||||||
|
|
||||||
|
**Behavior Flow**:
|
||||||
|
1. **Initial State**: All buttons disabled except Load
|
||||||
|
2. **After Load**: Start + Unload enabled, UART/I2C tabs DISABLED (grayed out)
|
||||||
|
3. **After Start**: Pause/Stop enabled, Unload disabled
|
||||||
|
4. **After Session Ends**: All buttons disabled, UART/I2C tabs RE-ENABLED, must Load again
|
||||||
|
5. **Manual Unload**: Click Unload button anytime before Start to regain tab access
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Duplicate Session Name Handling
|
||||||
|
|
||||||
|
**Problem**: Loading a session with a name that already exists in the database would cause conflicts or duplicate data.
|
||||||
|
|
||||||
|
**Solution Implemented** (`session_widget.py` - Lines 368-405):
|
||||||
|
- Check database for existing session name on Load
|
||||||
|
- Show QMessageBox dialog: "Session name '[name]' already exists. Override will delete existing session and telemetry data. Cancel or Override?"
|
||||||
|
- **Cancel**: Abort load, log info message
|
||||||
|
- **Override**: Delete all records with matching session_name from:
|
||||||
|
- `sessions` table
|
||||||
|
- `telemetry_raw` table
|
||||||
|
- `telemetry_decoded` table
|
||||||
|
- Proceed with load after cleanup
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Critical Bug Fix: UART Parity Default
|
||||||
|
|
||||||
|
**Problem**: UART tab was throwing IO_ERROR on all ports immediately after program start, even though permissions were correct and it worked in old versions.
|
||||||
|
|
||||||
|
**Root Cause**: Recent commit `70eb585` changed UART defaults in `uart_core.py`:
|
||||||
|
```python
|
||||||
|
# BROKEN (commit 70eb585):
|
||||||
|
parity: str = 'E' # Even parity - devices expect None!
|
||||||
|
buffer_size: int = 0.256 * 1024 * 1024 # Float expression, wrong!
|
||||||
|
|
||||||
|
# FIXED:
|
||||||
|
parity: str = 'N' # No parity
|
||||||
|
buffer_size: int = 256 * 1024 # 256KB, proper integer
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix Applied** (`uart/uart_kit/uart_core.py` - Lines 140-141):
|
||||||
|
- Reverted parity default from 'E' to 'N'
|
||||||
|
- Fixed buffer_size to proper integer calculation
|
||||||
|
- Corrected comment (was "4MB", actually 256KB)
|
||||||
|
|
||||||
|
**Why Session Worked But UART Tab Didn't**:
|
||||||
|
- Session explicitly sets parity from database interface profile
|
||||||
|
- UART tab widget also sets parity from UI
|
||||||
|
- But something in the initialization was using the default 'E' parity before the UI values were applied
|
||||||
|
- Changing default back to 'N' fixed it
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current System State
|
||||||
|
|
||||||
|
### Database Schema (Relevant Tables)
|
||||||
|
```sql
|
||||||
|
-- Session execution records
|
||||||
|
sessions (session_id PK, session_name, interface_profile_id, total_runs, status, notes, created_at)
|
||||||
|
|
||||||
|
-- Telemetry data (linked by session_name!)
|
||||||
|
telemetry_raw (session_id, session_name, t_ns, packet_no, raw_data)
|
||||||
|
telemetry_decoded (session_id, session_name, t_ns, run_no, motor_current, encoder_a, encoder_b, angle, ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Architectural Points
|
||||||
|
|
||||||
|
#### Tab Indices (main.py):
|
||||||
|
- Tab 0: Session
|
||||||
|
- Tab 1: Configure Session
|
||||||
|
- Tab 2: Configure Interface
|
||||||
|
- Tab 3: **UART** (disabled during session)
|
||||||
|
- Tab 4: **I2C** (disabled during session)
|
||||||
|
- Tab 5: Graph
|
||||||
|
- Tab 6: Database Manager
|
||||||
|
|
||||||
|
#### Session Execution Flow:
|
||||||
|
1. **Load Session**: Reads profiles from DB, does NOT open ports yet
|
||||||
|
2. **Start Session**: Opens ports via `_open_ports()`, starts execution
|
||||||
|
3. **Session Runs**: Commands executed via `run.py`
|
||||||
|
4. **Session Ends**: Signals emitted, `_cleanup_session()` called automatically
|
||||||
|
5. **Cleanup**: Ports closed, tabs re-enabled, buttons disabled
|
||||||
|
|
||||||
|
#### Port Management:
|
||||||
|
- **UART Command Port**: TX/RX for commands
|
||||||
|
- **UART Logger Port**: RX only for telemetry (optional)
|
||||||
|
- **I2C**: Angle sensor reads correlated to UART timestamps
|
||||||
|
- All ports opened on Start, closed on session end/unload
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Known Issues & Notes
|
||||||
|
|
||||||
|
### Working Correctly:
|
||||||
|
✅ Session lifecycle (Load → Start → End → Cleanup)
|
||||||
|
✅ Port conflict prevention (tabs disabled during session)
|
||||||
|
✅ Manual unload (Unload button)
|
||||||
|
✅ Duplicate session name override
|
||||||
|
✅ UART tab port opening
|
||||||
|
✅ Multi-phase sessions (Init/Execute/De-init)
|
||||||
|
|
||||||
|
### Code Quality Notes:
|
||||||
|
- Todo list system used to track progress (all tasks completed)
|
||||||
|
- Added sleep delays in port cleanup for proper OS release
|
||||||
|
- Individual error handling per port prevents cascading failures
|
||||||
|
- UI selections preserved after cleanup for easy re-run
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files Modified This Session
|
||||||
|
|
||||||
|
### Core Changes:
|
||||||
|
1. **session_widget.py** (main changes)
|
||||||
|
- Added Unload button
|
||||||
|
- Added tab enable/disable methods
|
||||||
|
- Added cleanup_session() method
|
||||||
|
- Modified button enable logic
|
||||||
|
|
||||||
|
2. **session.py**
|
||||||
|
- Added unload_session() method
|
||||||
|
- Enhanced _close_ports() with delays and error handling
|
||||||
|
|
||||||
|
3. **main.py**
|
||||||
|
- Added set_main_window() call
|
||||||
|
|
||||||
|
4. **uart/uart_kit/uart_core.py** (CRITICAL BUG FIX)
|
||||||
|
- Fixed parity default: 'E' → 'N'
|
||||||
|
- Fixed buffer_size: float → int
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference Commands
|
||||||
|
|
||||||
|
### Run Application:
|
||||||
|
```bash
|
||||||
|
cd /home/key/git/vguz_v2
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Management:
|
||||||
|
```bash
|
||||||
|
# Initialize/recreate database
|
||||||
|
python database/init_database.py
|
||||||
|
|
||||||
|
# Recreate database (overwrite)
|
||||||
|
python database/init_database.py --overwrite
|
||||||
|
|
||||||
|
# Check database health
|
||||||
|
python database/init_database.py --check
|
||||||
|
```
|
||||||
|
|
||||||
|
### Git Status:
|
||||||
|
```bash
|
||||||
|
# Check current changes
|
||||||
|
git status
|
||||||
|
|
||||||
|
# See what we modified
|
||||||
|
git diff
|
||||||
|
|
||||||
|
# Commit changes (when ready)
|
||||||
|
git add -A
|
||||||
|
git commit -m "Session lifecycle management + UART parity fix"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Checklist
|
||||||
|
|
||||||
|
Before next session, verify:
|
||||||
|
- [ ] UART tab opens ports correctly (all devices)
|
||||||
|
- [ ] Load Session → Unload Session → UART tab accessible
|
||||||
|
- [ ] Load Session → Start → Session ends → tabs re-enabled
|
||||||
|
- [ ] Duplicate session name override deletes old data
|
||||||
|
- [ ] Start button stays disabled until Load clicked
|
||||||
|
- [ ] I2C tab works after session unload
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps (If Needed)
|
||||||
|
|
||||||
|
### Potential Improvements:
|
||||||
|
1. Add confirmation dialog for Unload button ("Are you sure?")
|
||||||
|
2. Add visual indicator when tabs are disabled (e.g., tooltip explaining why)
|
||||||
|
3. Add session state indicator in status bar ("Session: Loaded", "Session: Running", etc.)
|
||||||
|
4. Consider adding keyboard shortcuts (Ctrl+L for Load, Ctrl+U for Unload)
|
||||||
|
|
||||||
|
### Known Good Git Commits:
|
||||||
|
- **Current HEAD**: Session lifecycle + UART fix (this session)
|
||||||
|
- **70eb585**: Telemetry working (but UART parity broken)
|
||||||
|
- **a520d8f**: Port configuration corrected
|
||||||
|
- **7b67099**: First commit
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contact & Context
|
||||||
|
|
||||||
|
**Project**: vzug-e-hinge Test & Control System
|
||||||
|
**Platform**: Raspberry Pi (Linux 6.17.4-arch2-1)
|
||||||
|
**Python**: PyQt6-based desktop application
|
||||||
|
**Hardware**: UART (command + logger) and I2C interfaces
|
||||||
|
**Database**: SQLite (max 2GB, currently at ehinge.db)
|
||||||
|
|
||||||
|
**Developer Notes**:
|
||||||
|
- User prefers concise, direct communication
|
||||||
|
- No emojis unless requested
|
||||||
|
- System works on Raspberry Pi with actual hardware
|
||||||
|
- Previous session required 2-day PC uptime to maintain context
|
||||||
|
- User experienced issue where Claude "forgot everything" previously
|
||||||
|
|
||||||
|
**This session was saved on**: 2025-11-23
|
||||||
|
**All functionality verified working** at end of session.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Code Snippets for Quick Reference
|
||||||
|
|
||||||
|
### How Session Loads and Starts:
|
||||||
|
```python
|
||||||
|
# 1. User clicks "Load Session" (session_widget.py:344)
|
||||||
|
def _on_load_clicked(self):
|
||||||
|
# Check for duplicate session name
|
||||||
|
# Load profiles from database
|
||||||
|
success = self.session.load_session(...)
|
||||||
|
if success:
|
||||||
|
self.start_button.setEnabled(True)
|
||||||
|
self.unload_button.setEnabled(True)
|
||||||
|
self._disable_port_tabs() # UART/I2C tabs disabled
|
||||||
|
|
||||||
|
# 2. User clicks "Start" (session_widget.py:444)
|
||||||
|
def _on_start_clicked(self):
|
||||||
|
# Create worker thread
|
||||||
|
self.worker = SessionWorker(self.session, self.db_path)
|
||||||
|
self.worker.start() # Opens ports and starts execution
|
||||||
|
|
||||||
|
# 3. Session ends (signal handler) (session_widget.py:582)
|
||||||
|
def _on_session_finished(self):
|
||||||
|
self._reset_controls()
|
||||||
|
self._cleanup_session() # Closes ports, re-enables tabs, disables buttons
|
||||||
|
```
|
||||||
|
|
||||||
|
### How Ports Are Closed:
|
||||||
|
```python
|
||||||
|
# session.py:672
|
||||||
|
def _close_ports(self):
|
||||||
|
import time
|
||||||
|
# Close UART command port
|
||||||
|
if self.uart_command_port:
|
||||||
|
uart_stop_reader(self.uart_command_port)
|
||||||
|
time.sleep(0.1) # Let reader thread stop
|
||||||
|
uart_close(self.uart_command_port)
|
||||||
|
self.uart_command_port = None
|
||||||
|
# Similar for UART logger and I2C
|
||||||
|
time.sleep(0.2) # Let OS release ports
|
||||||
|
```
|
||||||
|
|
||||||
|
### How Tabs Are Disabled:
|
||||||
|
```python
|
||||||
|
# session_widget.py:727
|
||||||
|
def _disable_port_tabs(self):
|
||||||
|
if self.main_window:
|
||||||
|
self.main_window.tabs.setTabEnabled(3, False) # UART
|
||||||
|
self.main_window.tabs.setTabEnabled(4, False) # I2C
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**END OF SESSION SUMMARY**
|
||||||
|
|
||||||
|
Remember: This document is in the git repository. You can reference it next time by reading `/home/key/git/vguz_v2/SESSION_SUMMARY.md`.
|
||||||
|
|
||||||
|
If you need to add notes or update this file in the future, just edit it directly!
|
||||||
Loading…
Reference in new issue