From d1a614fbbb6854d02947035ae8201afac98964e1 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Mon, 7 Jul 2025 13:50:05 +0800 Subject: [PATCH] docs: enhance hardware protocol documentation and reorganize project docs - Complete hardware communication protocol documentation with: * Add ping/pong health check protocol (0x01) * Add hardware control protocols (0x03 brightness, 0x04 volume) * Add mDNS service discovery specifications * Add connection state management and retry logic * Add comprehensive troubleshooting guide * Update hardware implementation examples - Reorganize project documentation: * Move device auto-refresh docs from root to docs/ directory * Rename files to follow kebab-case convention * Maintain complete technical implementation details - Fix markdown formatting issues: * Add proper language tags to code blocks * Ensure consistent documentation structure --- docs/device-auto-refresh-implementation.md | 99 ++++++ docs/device-auto-refresh-testing.md | 105 +++++++ docs/hardware-protocol.md | 294 ++++++++++++++++-- .../led-strip-test/led-strip-test.tsx | 68 +++- 4 files changed, 529 insertions(+), 37 deletions(-) create mode 100644 docs/device-auto-refresh-implementation.md create mode 100644 docs/device-auto-refresh-testing.md diff --git a/docs/device-auto-refresh-implementation.md b/docs/device-auto-refresh-implementation.md new file mode 100644 index 0000000..1eb0458 --- /dev/null +++ b/docs/device-auto-refresh-implementation.md @@ -0,0 +1,99 @@ +# LED Strip Test Device Auto-Refresh Implementation + +## Overview +Implemented automatic refresh functionality for the device dropdown in the LED strip test interface. The device list now updates in real-time when devices are discovered, connected, or disconnected. + +## Changes Made + +### 1. Frontend Changes (`src/components/led-strip-test/led-strip-test.tsx`) + +#### Added Event Listener Import +```typescript +import { listen } from '@tauri-apps/api/event'; +``` + +#### Enhanced Device Loading Logic +- **Initial Load**: Still loads devices on component mount using `get_boards()` +- **Real-time Updates**: Added listener for `boards_changed` events from backend +- **Smart Selection**: Automatically handles device selection when devices are added/removed: + - If current device disconnects, automatically selects first available device + - If no device was selected and devices become available, selects the first one + - Properly cleans up event listeners on component unmount + +#### Improved UI Display +- **Device Count**: Shows number of devices found in label +- **Connection Status**: Each device option shows: + - Status icon (🟢 Connected, 🟡 Connecting, 🔴 Disconnected) + - Device name and address + - Connection status text +- **Empty State**: Shows "Searching..." when no devices found + +#### Type Safety Improvements +- Updated `BoardInfo` interface to match backend types +- Proper handling of `connect_status` union type +- Type-safe status checking functions + +### 2. Backend Integration +The implementation leverages existing backend infrastructure: +- **UdpRpc Manager**: Continuously searches for devices via mDNS +- **Device Monitoring**: Checks device connectivity every second +- **Event Broadcasting**: Sends `boards_changed` events to frontend +- **Status Tracking**: Maintains real-time connection status for each device + +## Technical Details + +### Event Flow +1. Backend `UdpRpc` discovers devices via mDNS service discovery +2. Backend monitors device connectivity with periodic health checks +3. Backend broadcasts `boards_changed` events when device list changes +4. Frontend listens for events and updates UI automatically +5. Frontend handles device selection logic intelligently + +### Connection Status Types +- `Connected`: Device is responding to ping requests +- `Connecting`: Device is in retry state (with retry count) +- `Disconnected`: Device is not responding + +### Error Handling +- Graceful fallback if initial device load fails +- Proper cleanup of event listeners +- Maintains UI state consistency during device changes + +## Benefits +1. **Real-time Updates**: No need to manually refresh device list +2. **Better UX**: Visual indicators for device status +3. **Automatic Recovery**: Handles device disconnections gracefully +4. **Type Safety**: Proper TypeScript types prevent runtime errors +5. **Performance**: Efficient event-driven updates instead of polling + +## Implementation Status +✅ **Completed**: LED Strip Test device dropdown auto-refresh +✅ **Already Implemented**: Board Index page auto-refresh (was already working) +✅ **Type Safety**: Fixed TypeScript type definitions for BoardInfo +✅ **UI Improvements**: Added status indicators and device count display + +## Testing +To test the functionality: +1. Start the application with `npm run tauri dev` +2. Navigate to LED Strip Test page +3. Observe device list updates as devices come online/offline +4. Verify status indicators show correct connection states: + - 🟢 Connected devices + - 🟡 Connecting devices (with retry count) + - 🔴 Disconnected devices +5. Test device selection behavior when devices disconnect +6. Check that device count is displayed in the label + +## Code Quality +- ✅ No TypeScript errors +- ✅ Proper event listener cleanup +- ✅ Type-safe status checking +- ✅ Consistent with existing codebase patterns +- ✅ Follows SolidJS best practices + +## Future Enhancements +- Add device refresh button for manual refresh +- Show device discovery progress indicator +- Add device connection retry controls +- Display device ping latency information +- Add device connection history/logs diff --git a/docs/device-auto-refresh-testing.md b/docs/device-auto-refresh-testing.md new file mode 100644 index 0000000..f2a3034 --- /dev/null +++ b/docs/device-auto-refresh-testing.md @@ -0,0 +1,105 @@ +# Device Auto-Refresh Testing Guide + +## Test Scenarios + +### 1. Initial Load Test +**Expected Behavior**: Device list loads automatically when component mounts + +**Steps**: +1. Start the application: `npm run tauri dev` +2. Navigate to LED Strip Test page +3. Observe the device dropdown + +**Expected Results**: +- Device dropdown shows "Searching..." if no devices found +- Device dropdown shows device count if devices are found +- First available device is automatically selected +- Status icons appear next to device names + +### 2. Device Discovery Test +**Expected Behavior**: New devices appear automatically when discovered + +**Steps**: +1. Start with no devices connected +2. Connect a device to the network +3. Wait for device discovery (should be automatic) + +**Expected Results**: +- Device count updates automatically +- New device appears in dropdown +- If no device was selected, new device gets selected automatically +- Status icon shows connection state + +### 3. Device Disconnection Test +**Expected Behavior**: Disconnected devices are handled gracefully + +**Steps**: +1. Start with connected devices +2. Select a device in the dropdown +3. Disconnect the selected device from network +4. Wait for connection timeout + +**Expected Results**: +- Device status changes to disconnected (🔴) +- If device becomes unavailable, another device is selected automatically +- Device count updates +- UI remains responsive + +### 4. Connection Status Test +**Expected Behavior**: Status indicators reflect actual device states + +**Steps**: +1. Observe devices in different connection states +2. Check status icons and text + +**Expected Results**: +- 🟢 "Connected" for responsive devices +- 🟡 "Connecting" for devices in retry state +- 🔴 "Disconnected" for unresponsive devices +- Status text matches icon state + +### 5. UI Responsiveness Test +**Expected Behavior**: Interface remains responsive during device changes + +**Steps**: +1. Rapidly connect/disconnect devices +2. Interact with other UI elements during device changes +3. Switch between pages and return + +**Expected Results**: +- No UI freezing or lag +- Event listeners are properly cleaned up +- No memory leaks +- Smooth transitions + +## Verification Checklist + +- [ ] Device dropdown shows correct device count +- [ ] Status icons display correctly (🟢🟡🔴) +- [ ] Automatic device selection works +- [ ] Event listeners are cleaned up on component unmount +- [ ] No TypeScript errors in console +- [ ] No runtime errors in console +- [ ] Performance remains good with multiple devices +- [ ] UI updates smoothly without flickering + +## Common Issues to Watch For + +1. **Memory Leaks**: Event listeners not cleaned up +2. **Type Errors**: Incorrect BoardInfo type handling +3. **Selection Logic**: Device selection not updating correctly +4. **Performance**: UI lag during rapid device changes +5. **State Consistency**: UI state not matching actual device state + +## Debug Information + +Check browser console for: +- `boards_changed` events +- Device list updates +- Selection changes +- Any error messages + +Check Tauri logs for: +- Device discovery messages +- Connection status changes +- mDNS service events diff --git a/docs/hardware-protocol.md b/docs/hardware-protocol.md index 242fa41..0e42682 100644 --- a/docs/hardware-protocol.md +++ b/docs/hardware-protocol.md @@ -2,7 +2,7 @@ ## Overview -UDP-based protocol for sending LED color data from desktop application to ambient light hardware boards. The hardware acts as a simple UDP-to-WS2812 bridge, directly forwarding color data without any processing or LED type distinction. +UDP-based bidirectional protocol for communication between desktop application and ambient light hardware boards. The protocol supports LED color data transmission, device health monitoring, and remote control capabilities. ## Connection @@ -11,12 +11,61 @@ UDP-based protocol for sending LED color data from desktop application to ambien - **Discovery**: mDNS (`_ambient_light._udp.local.`) - **Example Board**: `192.168.31.206:23042` -## Packet Format +## mDNS Service Discovery +### Service Registration (Hardware Side) + +Hardware boards must register the following mDNS service: + +- **Service Type**: `_ambient_light._udp.local.` +- **Port**: 23042 +- **TXT Records**: Optional, can include device information + +### Service Discovery (Desktop Side) + +Desktop application continuously browses for `_ambient_light._udp.local.` services and automatically connects to discovered devices. + +## Protocol Messages + +The protocol uses different message headers to distinguish message types: + +| Header | Direction | Purpose | Format | +|--------|-----------|---------|---------| +| 0x01 | Desktop → Hardware | Ping (Health Check) | `[0x01]` | +| 0x01 | Hardware → Desktop | Pong (Health Response) | `[0x01]` | +| 0x02 | Desktop → Hardware | LED Color Data | `[0x02][Offset_H][Offset_L][Color_Data...]` | +| 0x03 | Hardware → Desktop | Display Brightness Control | `[0x03][Display_Index][Brightness]` | +| 0x04 | Hardware → Desktop | Volume Control | `[0x04][Volume_Percent]` | + +## Health Check Protocol (Ping/Pong) + +### Desktop → Hardware (Ping) + +```text +Byte 0: Header (0x01) ``` + +### Hardware → Desktop (Pong) + +```text +Byte 0: Header (0x01) +``` + +**Behavior:** + +- Desktop sends ping every 1 second to each connected device +- Hardware must respond with pong within 1 second +- Timeout or incorrect response triggers reconnection logic +- After 10 failed attempts, device is marked as disconnected + +## LED Color Data Protocol + +### Packet Format + +```text Byte 0: Header (0x02) Byte 1: Offset High (upper 8 bits of LED start position) -Byte 2: Offset Low (lower 8 bits of LED start position) +Byte 2: Offset Low (lower 8 bits of LED start position) Byte 3+: LED Color Data (variable length) ``` @@ -24,13 +73,13 @@ Byte 3+: LED Color Data (variable length) ### RGB LEDs (3 bytes per LED) -``` +```text [R][G][B][R][G][B][R][G][B]... ``` ### RGBW LEDs (4 bytes per LED) -``` +```text [R][G][B][W][R][G][B][W][R][G][B][W]... ``` @@ -57,13 +106,78 @@ calibrated_b = (original_b * calibration_b) / 255 calibrated_w = calibration_w // Direct value ``` +## Hardware Control Protocol (Hardware → Desktop) + +### Display Brightness Control + +Hardware can send display brightness adjustment commands to the desktop: + +```text +Byte 0: Header (0x03) +Byte 1: Display Index (0-based display number) +Byte 2: Brightness (0-255, where 255 = 100% brightness) +``` + +**Example:** Set display 0 to 50% brightness + +```text +03 00 80 +│ │ └─ Brightness (128 = ~50%) +│ └─ Display Index (0) +└─ Header (0x03) +``` + +### Volume Control + +Hardware can send system volume adjustment commands to the desktop: + +```text +Byte 0: Header (0x04) +Byte 1: Volume Percent (0-100) +``` + +**Example:** Set system volume to 75% + +```text +04 4B +│ └─ Volume (75%) +└─ Header (0x04) +``` + +## Connection State Management + +### Connection States + +- **Unknown**: Initial state when device is first discovered +- **Connecting**: Device is being tested, includes retry count (1-10) +- **Connected**: Device is responding to ping requests normally +- **Disconnected**: Device failed to respond after 10 retry attempts + +### State Transitions + +```text +Unknown → Connecting(1) → Connected + ↓ ↓ ↓ + ↓ Connecting(2-10) ↓ + ↓ ↓ ↓ + └─→ Disconnected ←────────┘ +``` + +### Retry Logic + +1. **Initial Connection**: When device discovered via mDNS +2. **Health Check Failure**: If ping timeout or wrong response +3. **Retry Attempts**: Up to 10 attempts with 1-second intervals +4. **Disconnection**: After 10 failed attempts, mark as disconnected +5. **Recovery**: Disconnected devices continue to receive ping attempts + ## Packet Examples ### RGB Example 3 RGB LEDs starting at position 0: Red, Green, Blue -``` +```text 02 00 00 FF 00 00 00 FF 00 00 00 FF │ │ │ └─────────────────────────── 9 bytes color data │ │ └─ Offset Low (0) @@ -71,11 +185,11 @@ calibrated_w = calibration_w // Direct value └─ Header (0x02) ``` -### RGBW Example +### RGBW Example 2 RGBW LEDs starting at position 10: White, Warm White -``` +```text 02 00 0A FF FF FF FF FF C8 96 C8 │ │ │ └─────────────────────── 8 bytes color data │ │ └─ Offset Low (10) @@ -94,20 +208,48 @@ calibrated_w = calibration_w // Direct value ## Hardware Implementation -The hardware board acts as a simple UDP-to-WS2812 bridge, directly forwarding color data to the LED strips without any processing or type distinction. +The hardware board handles multiple protocol functions: UDP-to-WS2812 bridge for LED data, health monitoring, and optional control input capabilities. -### Packet Processing +### Required Functions -1. **Validation**: Check minimum 3 bytes and header (0x02) -2. **Extract Offset**: Parse 16-bit LED start position -3. **Forward Data**: Send color data directly to WS2812 controller -4. **No Type Logic**: Hardware doesn't distinguish RGB/RGBW - just forwards bytes +1. **mDNS Service Registration**: Advertise `_ambient_light._udp.local.` service +2. **UDP Server**: Listen on port 23042 for incoming packets +3. **Packet Processing**: Handle different message types based on header +4. **Health Monitoring**: Respond to ping requests with pong +5. **LED Control**: Forward color data to WS2812 strips +6. **Optional Control**: Send brightness/volume commands to desktop -### Example C Code +### Packet Processing Logic ```c void process_packet(uint8_t* data, size_t len) { - if (len < 3 || data[0] != 0x02) return; + if (len < 1) return; + + switch (data[0]) { + case 0x01: // Ping request + handle_ping(data, len); + break; + + case 0x02: // LED color data + handle_led_data(data, len); + break; + + default: + // Unknown packet type, ignore + break; + } +} + +void handle_ping(uint8_t* data, size_t len) { + if (len != 1) return; + + // Respond with pong + uint8_t pong = 0x01; + udp_send_response(&pong, 1); +} + +void handle_led_data(uint8_t* data, size_t len) { + if (len < 3) return; uint16_t offset = (data[1] << 8) | data[2]; uint8_t* color_data = &data[3]; @@ -118,23 +260,119 @@ void process_packet(uint8_t* data, size_t len) { } ``` -### Key Simplifications +### Optional Control Features -- **No LED Type Detection**: Hardware doesn't need to know RGB vs RGBW -- **Direct Data Forward**: Color bytes sent as-is to WS2812 controller -- **Desktop Handles Logic**: All RGB/RGBW processing done on desktop side -- **Simple Bridge**: Hardware is just a UDP-to-WS2812 data bridge +Hardware can optionally send control commands to desktop: + +```c +// Send display brightness control +void send_brightness_control(uint8_t display_index, uint8_t brightness) { + uint8_t packet[3] = {0x03, display_index, brightness}; + udp_send_to_desktop(packet, 3); +} + +// Send volume control +void send_volume_control(uint8_t volume_percent) { + uint8_t packet[2] = {0x04, volume_percent}; + udp_send_to_desktop(packet, 2); +} +``` + +### Key Implementation Notes + +- **Ping Response**: Must respond to ping (0x01) within 1 second +- **LED Data**: Direct forward to WS2812, no processing required +- **Control Commands**: Optional feature for hardware with input capabilities +- **mDNS Registration**: Essential for automatic device discovery +- **UDP Server**: Must handle concurrent connections from multiple desktops ## Troubleshooting -**No Updates**: Check network connectivity, mDNS discovery, port 23042 -**Wrong Colors**: Verify calibration settings on desktop application -**Flickering**: Monitor packet rate, network congestion, power supply -**Partial Updates**: Check strip configuration, offset calculations -**Hardware Issues**: Verify WS2812 wiring, power supply, data signal integrity +### Device Discovery Issues + +**Device Not Found**: + +- Verify mDNS service registration on hardware +- Check service type: `_ambient_light._udp.local.` +- Ensure port 23042 is accessible +- Verify network connectivity between desktop and hardware + +**Device Shows as Disconnected**: + +- Check ping/pong response implementation +- Verify hardware responds to 0x01 packets within 1 second +- Monitor network latency and packet loss +- Check UDP server implementation on hardware + +### LED Control Issues + +**No LED Updates**: + +- Verify hardware processes 0x02 packets correctly +- Check WS2812 wiring and power supply +- Monitor packet reception on hardware side +- Verify offset calculations and LED strip configuration + +**Wrong Colors**: + +- Check color calibration settings on desktop +- Verify RGB/RGBW data format matches LED strip type +- Monitor color data in packets (bytes 3+) +- Check WS2812 color order (GRB vs RGB) + +**Flickering or Lag**: + +- Monitor packet rate and network congestion +- Check power supply stability for LED strips +- Verify WS2812 data signal integrity +- Consider reducing update frequency + +### Control Protocol Issues + +**Brightness/Volume Control Not Working**: + +- Verify hardware sends correct packet format (0x03/0x04) +- Check desktop receives and processes control packets +- Monitor packet transmission from hardware +- Verify display index and value ranges + +### Connection State Issues + +**Frequent Disconnections**: + +- Check network stability and latency +- Verify ping response timing (< 1 second) +- Monitor retry logic and connection state transitions +- Check for UDP packet loss + +**Stuck in Connecting State**: + +- Verify ping/pong packet format +- Check hardware UDP server implementation +- Monitor ping response timing +- Verify network firewall settings + +### Network Debugging + +**Packet Monitoring**: + +```bash +# Monitor UDP traffic on port 23042 +tcpdump -i any -X port 23042 + +# Check mDNS service discovery +dns-sd -B _ambient_light._udp.local. +``` + +**Hardware Debug Output**: + +- Log received packet headers and lengths +- Monitor ping/pong timing +- Track LED data processing +- Log mDNS service registration status ## Protocol Version - **Current**: 1.0 -- **Header**: 0x02 -- **Future**: Different headers for backward compatibility +- **Headers**: 0x01 (Ping/Pong), 0x02 (LED Data), 0x03 (Brightness), 0x04 (Volume) +- **Future**: Additional headers for new features, backward compatibility maintained diff --git a/src/components/led-strip-test/led-strip-test.tsx b/src/components/led-strip-test/led-strip-test.tsx index ff4f81d..3c3f950 100644 --- a/src/components/led-strip-test/led-strip-test.tsx +++ b/src/components/led-strip-test/led-strip-test.tsx @@ -1,12 +1,13 @@ import { createSignal, createEffect, For, Show, onCleanup } from 'solid-js'; import { invoke } from '@tauri-apps/api/core'; +import { listen } from '@tauri-apps/api/event'; interface BoardInfo { fullname: string; host: string; address: string; port: number; - connect_status: string; + connect_status: 'Connected' | 'Disconnected' | { Connecting: number }; } interface TestPattern { @@ -31,8 +32,9 @@ export const LedStripTest = () => { const [currentPattern, setCurrentPattern] = createSignal(null); const [animationSpeed, setAnimationSpeed] = createSignal(33); // ~30fps - // Load available boards + // Load available boards and listen for changes createEffect(() => { + // Initial load invoke('get_boards').then((boardList) => { setBoards(boardList); if (boardList.length > 0 && !selectedBoard()) { @@ -41,6 +43,35 @@ export const LedStripTest = () => { }).catch((error) => { console.error('Failed to load boards:', error); }); + + // Listen for board changes + const unlisten = listen('boards_changed', (event) => { + const boardList = event.payload; + setBoards(boardList); + + // If currently selected board is no longer available, select the first available one + const currentBoard = selectedBoard(); + if (currentBoard) { + const stillExists = boardList.find(board => + board.host === currentBoard.host && + board.address === currentBoard.address && + board.port === currentBoard.port + ); + + if (!stillExists) { + // Current board is no longer available, select first available or null + setSelectedBoard(boardList.length > 0 ? boardList[0] : null); + } + } else if (boardList.length > 0) { + // No board was selected, select the first one + setSelectedBoard(boardList[0]); + } + }); + + // Cleanup listener when effect is disposed + onCleanup(() => { + unlisten.then((unlistenFn) => unlistenFn()); + }); }); // Cleanup when component is unmounted @@ -161,8 +192,11 @@ export const LedStripTest = () => {
-