docs: Multi-frequency RF file handling analysis

Comprehensive analysis of how the system handles .sub files with
multiple frequencies.

Key findings:
- Standard Flipper Zero files contain ONE frequency per file
- Multiple .sub files in one upload: WORKS correctly
- Multiple Frequency: lines in one file: Only last used (silent loss)
- Recommended: Add validation warning for multi-frequency edge case

Analysis includes:
- Current parser behavior
- Flipper Zero file format specification
- 4 solution options with pros/cons
- Testing scenarios
- Impact assessment
- Short-term and long-term recommendations
This commit is contained in:
2026-01-14 13:20:08 -08:00
parent a0ccc3d00a
commit 9bd9f4f43b
+456
View File
@@ -0,0 +1,456 @@
# Multi-Frequency RF File Handling - Analysis & Recommendations
**Date:** January 14, 2026
**Status:** Current Limitation Identified
**Priority:** Medium (Future Enhancement)
---
## Current Behavior
### How the System Handles .sub Files Today
**Current Implementation:**
```python
# src/parser/sub_parser.py (line 79)
frequency = int(self.fields.get('Frequency', 0)) # Single frequency only
# src/api/main_simple.py (line 323)
frequency = metadata.frequency # Extracts single frequency
```
**What Happens:**
1. Parser reads the `Frequency:` field from .sub file
2. Extracts **ONE** frequency value (integer)
3. Creates **ONE** capture record per file
4. Stores that single frequency with GPS coordinates
### Flipper Zero .sub File Format
**Standard Single-Frequency File:**
```
Filetype: Flipper SubGhz Key File
Version: 1
Frequency: 433920000
Preset: FuriHalSubGhzPresetOok270Async
Protocol: Princeton
Bit: 24
Key: 00 00 00 00 00 95 D5 D4
```
**Can .sub Files Contain Multiple Frequencies?**
Based on Flipper Zero's firmware and file format specification:
**NO** - Standard Flipper Zero .sub files contain **ONE frequency per file**
Each .sub file represents a **single capture** at a **single frequency**.
### Multi-Frequency Scenarios
However, there are **edge cases** where multiple frequencies might appear:
#### Scenario 1: Multiple .sub Files in One Upload
**SUPPORTED** - System handles this correctly
```python
# User uploads multiple files at once
files = [
"capture_315MHz.sub", # Frequency: 315000000
"capture_433MHz.sub", # Frequency: 433920000
"capture_868MHz.sub" # Frequency: 868000000
]
# System behavior:
for file in files:
metadata = sub_parser.parse(file) # Each file parsed separately
capture = create_capture(metadata) # Each creates separate capture
# Result: 3 separate captures with 3 different frequencies
```
**Result:** ✅ Works correctly - creates 3 separate map markers
#### Scenario 2: Frequency-Hopping Devices (Future)
**NOT SUPPORTED** - Would require new file format
Some devices transmit on multiple frequencies (e.g., Bluetooth frequency hopping, LoRa adaptive data rate):
```
Device transmits: 315 MHz → 433 MHz → 868 MHz
```
**Current behavior:** Flipper Zero would create 3 separate .sub files
**Hypothetical multi-frequency file (NOT STANDARD):**
```
Filetype: Flipper SubGhz Multi File # DOES NOT EXIST
Version: 1
Frequency: 315000000
Frequency: 433920000 # Multiple Frequency fields
Frequency: 868000000
```
**Our parser behavior:** Only reads **first** Frequency field (line 79)
#### Scenario 3: Scanning/Waterfall Captures
**NOT SUPPORTED** - Different file format
Flipper Zero's spectrum analyzer creates different file types:
- `.sub` files = Single frequency capture
- Waterfall scans = Not saved to .sub format
---
## Current System Limitations
### What Happens If Someone Manually Edits a .sub File?
Let's test what happens if a .sub file has multiple `Frequency:` lines:
**Malformed File:**
```
Filetype: Flipper SubGhz Key File
Version: 1
Frequency: 315000000
Frequency: 433920000 # Second frequency line
Protocol: Princeton
```
**Parser Behavior:**
```python
# src/parser/sub_parser.py (lines 54-61)
for line in content.split('\n'):
if ':' in line:
key, value = line.split(':', 1)
self.fields[key.strip()] = value.strip() # OVERWRITES previous value!
```
**Result:**
- First `Frequency: 315000000` is stored
- Second `Frequency: 433920000` **OVERWRITES** it
- Only **433920000** is used
**Silent data loss** - First frequency is discarded without warning
### Upload Endpoint Behavior
```python
# src/api/main_simple.py (lines 305-376)
for file in files:
metadata = sub_parser.parse(temp_path) # Parses single frequency
frequency = metadata.frequency # Gets single frequency
# Creates ONE capture per file
capture_info = {
"id": upload_counter,
"frequency": frequency, # Single frequency stored
# ... other fields
}
```
**Result:** One file = One frequency = One capture = One map marker
---
## Proposed Solutions
### Option 1: Detect and Reject Multi-Frequency Files (Recommended)
**Pros:**
- Maintains data integrity
- Prevents silent data loss
- Simple to implement
**Implementation:**
```python
def parse(self, file_path: str) -> SignalMetadata:
# Count frequency fields
freq_count = content.count('Frequency:')
if freq_count > 1:
raise ValueError(
f"Multi-frequency files not supported. "
f"Found {freq_count} frequency fields. "
f"Please split into separate .sub files."
)
# Rest of parsing...
```
### Option 2: Parse All Frequencies and Create Multiple Captures (Complex)
**Pros:**
- Handles edge cases gracefully
- Future-proof for multi-frequency devices
**Cons:**
- Significant code changes required
- Not aligned with Flipper Zero standard
- GPS coordinates ambiguous (which freq was captured where?)
**Implementation:**
```python
def parse(self, file_path: str) -> List[SignalMetadata]:
"""Returns LIST of metadata objects"""
# Parse all frequency fields
frequencies = []
for line in content.split('\n'):
if line.startswith('Frequency:'):
freq = int(line.split(':', 1)[1].strip())
frequencies.append(freq)
if len(frequencies) == 0:
raise ValueError("No frequency found")
# Create separate metadata for each frequency
results = []
for freq in frequencies:
metadata = SignalMetadata(frequency=freq, ...)
results.append(metadata)
return results
# Upload endpoint changes needed:
for file in files:
metadatas = sub_parser.parse(temp_path) # Returns LIST
for metadata in metadatas: # Create multiple captures
capture = create_capture(metadata)
```
**Database changes:**
- `captures_storage` would need to link related captures
- GPS coordinates: same for all captures from one file
- Map display: Multiple markers at same location?
### Option 3: Store Multiple Frequencies in Single Capture (Database Change)
**Pros:**
- Preserves all frequency data
- Single capture per file (simpler logic)
**Cons:**
- Database schema change required
- Map display complexity (show all frequencies?)
- Matching logic needs update
**Implementation:**
```python
# Database schema:
capture_info = {
"id": 1,
"filename": "multi_freq.sub",
"frequencies": [315000000, 433920000, 868000000], # Array instead of single
"primary_frequency": 315000000, # First or dominant frequency
# ...
}
# Map display:
# Option A: Show primary frequency only
# Option B: Show all frequencies in popup
# Option C: Create multiple semi-transparent markers
```
### Option 4: Do Nothing (Current Behavior)
**Pros:**
- No code changes needed
- Aligns with Flipper Zero standard (one freq per file)
**Cons:**
- Silent data loss if malformed file uploaded
- No user feedback about issue
---
## Recommendations
### Short-Term (Implement Now)
**1. Add Validation Warning**
```python
def parse(self, file_path: str) -> SignalMetadata:
freq_count = content.count('Frequency:')
if freq_count > 1:
logger.warning(
f"File {file_path} contains {freq_count} frequency fields. "
f"Only the last one will be used: {self.fields['Frequency']}"
)
```
**2. Document Behavior**
- Update API docs to clarify: "One frequency per .sub file"
- Add to upload UI: "Multi-frequency files not supported"
**3. Add to Upload Response**
```python
if freq_count > 1:
warnings.append({
"filename": file.filename,
"warning": "Multiple frequencies detected. Only last frequency used.",
"frequencies_found": freq_count
})
```
### Medium-Term (Future Enhancement)
**If multi-frequency support becomes needed:**
1. **Update File Format Spec**
- Define multi-frequency .sub format
- OR: Use separate file per frequency (Flipper standard)
2. **Update Parser**
- Return `List[SignalMetadata]` instead of single
- Parse all frequency fields
3. **Update Upload Endpoint**
- Handle list of metadata objects
- Create multiple captures per file
- Link captures with `parent_file_id`
4. **Update Map Display**
- Show multiple markers at same GPS location
- OR: Single marker with frequency list in popup
5. **Update Database Schema**
```python
# New fields:
"is_multi_frequency": True,
"parent_capture_id": None, # For linked captures
"frequency_index": 0, # Which frequency in multi-freq file
```
---
## Testing
### Test Case 1: Normal Single-Frequency File
```python
# Input: standard_capture.sub
Frequency: 433920000
# Expected:
- Parse succeeds
- frequency = 433920000
- One capture created
```
### Test Case 2: Duplicate Frequency Lines
```python
# Input: duplicate_freq.sub
Frequency: 315000000
Frequency: 315000000 # Same frequency twice
# Current behavior:
- Parse succeeds
- frequency = 315000000 (last value)
- Warning logged
# Recommended:
- Parse succeeds
- Warning returned to user
```
### Test Case 3: Different Frequency Lines
```python
# Input: multi_freq.sub
Frequency: 315000000
Frequency: 433920000 # Different frequency
# Current behavior:
- Parse succeeds
- frequency = 433920000 (last value)
- 315000000 silently discarded
# Recommended:
- Parse fails OR
- Parse succeeds with warning
- User informed of data loss
```
### Test Case 4: Multiple Files Uploaded
```python
# Input: 3 separate .sub files
file1.sub: Frequency: 315000000
file2.sub: Frequency: 433920000
file3.sub: Frequency: 868000000
# Current behavior: ✅ WORKS
- Parse each file separately
- Create 3 captures
- 3 map markers with different frequencies
```
---
## FAQ
**Q: Can a single .sub file contain multiple frequencies?**
A: Not in the standard Flipper Zero format. Each .sub file represents one capture at one frequency.
**Q: What if I scan multiple frequencies?**
A: Flipper Zero creates separate .sub files for each frequency. Upload all files together.
**Q: What happens if I manually add multiple `Frequency:` lines?**
A: Currently, only the **last** frequency is used. Earlier ones are silently discarded.
**Q: Can I upload multiple .sub files with different frequencies?**
A: ✅ Yes! Upload them all at once. Each file creates a separate capture.
**Q: Why not support multi-frequency files?**
A:
1. Not part of Flipper Zero standard
2. GPS coordinates are per-file, not per-frequency
3. Adds significant complexity
4. No known devices that require this
**Q: Will this be supported in the future?**
A: Maybe, if:
1. Users frequently encounter multi-frequency devices
2. A clear use case emerges (frequency-hopping, channel scanning)
3. Standard file format is defined
---
## Impact Assessment
### Current Impact
- **Low** - Flipper Zero doesn't create multi-frequency files
- **Edge case only** - Manually edited/malformed files
### User Impact if Implemented
- **Positive:** Handle more file types
- **Negative:** Increased complexity, potential confusion (multiple markers at same GPS)
### Development Effort
- **Option 1 (Validation):** Low - 1-2 hours
- **Option 2 (Multi-capture):** High - 1-2 days
- **Option 3 (Database change):** Very High - 3-5 days + migration
---
## Conclusion
**Current Status:** System handles **one frequency per .sub file** correctly.
**Recommendation:** Implement **Option 1** (validation warning) in short-term.
**Reasoning:**
1. Aligns with Flipper Zero standard (one freq per file)
2. No known use cases for multi-frequency files
3. Minimal development effort
4. Prevents silent data loss
5. Future-proof: can enhance later if needed
**Action Items:**
- [ ] Add frequency count validation
- [ ] Log warning if multiple frequencies detected
- [ ] Return warning in upload API response
- [ ] Document behavior in API docs
- [ ] Add user-facing note in upload UI
---
**Status:** Analysis complete, awaiting decision on implementation priority.