Files
Ai/FT991A-Remote/FT991A-Remote/Models/Settings.swift
T
Claude 1e153f2f85 Add FT-991A Remote Control App for macOS
Complete Phase 1 implementation of the Yaesu FT-991A remote control
application with CAT protocol support over USB serial (CP210x).

Features implemented:
- SerialPortManager with auto-detection of CP210x ports
- Full CAT protocol parser and command builder
- RadioState model with all transceiver parameters
- Modern SwiftUI interface with frequency/mode/level controls
- Skeuomorphic front panel view (switchable)
- Debug panel with CAT command console
- QSO log panel with CSV export/import
- Audio routing panel with BlackHole integration
- Settings with connection, UI, keyboard configuration
- Menu bar extra for background operation
- German/English localization
- Logging system for debugging

Supports: Frequency control, VFO A/B, all modes (LSB/USB/CW/FM/AM/
DATA/RTTY/C4FM), level controls, NB/NR/DNF/ATU/Split functions,
S-meter/Power/SWR metering, PTT control via Shift key.

Target: macOS 15.0+ (Sequoia/Tahoe)
2025-12-18 10:59:15 +00:00

124 lines
3.2 KiB
Swift

//
// Settings.swift
// FT991A-Remote
//
// Application settings model
//
import Foundation
// MARK: - App Settings
struct AppSettings: Codable {
// Connection
var serialPort: String = ""
var baudRate: Int = 38400
var autoReconnect: Bool = true
var reconnectInterval: TimeInterval = 5.0
// UI
var uiStyle: UIStyle = .modern
var language: AppLanguage = .german
var showDebugPanel: Bool = false
var showLogPanel: Bool = false
var compactMode: Bool = true
// Frequency
var frequencyStep: FrequencyStep = .khz1
// Logging
var logDirectory: String = "~/Documents/FT991A-Logs/"
var autoSaveLog: Bool = true
// Audio
var audioInputDevice: String = ""
var audioOutputDevice: String = ""
var useBlackHole: Bool = false
// Keyboard
var pttShortcutEnabled: Bool = true
var arrowFrequencyEnabled: Bool = true
var tunerShortcutEnabled: Bool = true
// MARK: - Persistence
static let defaults = AppSettings()
static var settingsURL: URL {
let appSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
let appFolder = appSupport.appendingPathComponent("FT991A-Remote", isDirectory: true)
try? FileManager.default.createDirectory(at: appFolder, withIntermediateDirectories: true)
return appFolder.appendingPathComponent("settings.json")
}
static func load() -> AppSettings {
guard FileManager.default.fileExists(atPath: settingsURL.path) else {
return defaults
}
do {
let data = try Data(contentsOf: settingsURL)
return try JSONDecoder().decode(AppSettings.self, from: data)
} catch {
print("Failed to load settings: \(error)")
return defaults
}
}
func save() {
do {
let data = try JSONEncoder().encode(self)
try data.write(to: AppSettings.settingsURL)
} catch {
print("Failed to save settings: \(error)")
}
}
// MARK: - Log Directory
var expandedLogDirectory: String {
(logDirectory as NSString).expandingTildeInPath
}
mutating func ensureLogDirectoryExists() {
let path = expandedLogDirectory
if !FileManager.default.fileExists(atPath: path) {
try? FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true)
}
}
}
// MARK: - Serial Port Configuration
struct SerialConfig: Codable {
var baudRate: Int = 38400
var dataBits: Int = 8
var stopBits: Int = 1
var parity: Parity = .none
var flowControl: FlowControl = .none
enum Parity: String, Codable, CaseIterable {
case none = "None"
case odd = "Odd"
case even = "Even"
}
enum FlowControl: String, Codable, CaseIterable {
case none = "None"
case hardware = "RTS/CTS"
case software = "XON/XOFF"
}
static let ft991aDefault = SerialConfig(
baudRate: 38400,
dataBits: 8,
stopBits: 1,
parity: .none,
flowControl: .none
)
static let availableBaudRates = [4800, 9600, 19200, 38400, 57600, 115200]
}