1e153f2f85
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)
124 lines
3.2 KiB
Swift
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]
|
|
}
|