# 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.