217 lines
5.2 KiB
Go
217 lines
5.2 KiB
Go
// Package driver implementiert herstellerunabhängige Hardware-Treiber.
|
|
// Diese Datei enthält die Dummy-Implementierungen zur Simulation von Hardware ohne physische Geräte.
|
|
package driver
|
|
|
|
import (
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// DummyRig simuliert ein Funkgerät im Arbeitsspeicher.
|
|
type DummyRig struct {
|
|
mu sync.Mutex
|
|
connected bool
|
|
freq int64
|
|
mode string
|
|
ptt bool
|
|
}
|
|
|
|
// NewDummyRig erstellt eine neue Instanz eines simulierten Funkgeräts mit Standardwerten.
|
|
func NewDummyRig() *DummyRig {
|
|
return &DummyRig{
|
|
freq: 14250000, // 20m Band Standardfrequenz (14.250 MHz)
|
|
mode: "USB",
|
|
}
|
|
}
|
|
|
|
func (d *DummyRig) Connect(port string, baud int) error {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
d.connected = true
|
|
log.Printf("[Dummy-Rig] Erfolgreich verbunden via %s (%d Baud)", port, baud)
|
|
return nil
|
|
}
|
|
|
|
func (d *DummyRig) Disconnect() error {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
d.connected = false
|
|
log.Println("[Dummy-Rig] Verbindung sauber getrennt.")
|
|
return nil
|
|
}
|
|
|
|
func (d *DummyRig) SetFrequency(hz int64) error {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
d.freq = hz
|
|
log.Printf("[Dummy-Rig] Frequenz geändert auf: %d Hz", hz)
|
|
return nil
|
|
}
|
|
|
|
func (d *DummyRig) GetFrequency() (int64, error) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
return d.freq, nil
|
|
}
|
|
|
|
func (d *DummyRig) SetMode(mode string) error {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
d.mode = mode
|
|
log.Printf("[Dummy-Rig] Betriebsart geändert auf: %s", mode)
|
|
return nil
|
|
}
|
|
|
|
func (d *DummyRig) GetMode() (string, error) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
return d.mode, nil
|
|
}
|
|
|
|
func (d *DummyRig) SetPTT(active bool) error {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
d.ptt = active
|
|
log.Printf("[Dummy-Rig] PTT Status geändert: %t (TX = %t)", active, active)
|
|
return nil
|
|
}
|
|
|
|
func (d *DummyRig) GetSMeter() (int, error) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
// Simuliert ein leichtes Rauschen um S3, wenn kein TX aktiv ist
|
|
if d.ptt {
|
|
return 0, nil
|
|
}
|
|
return 3, nil
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// DummyRotor simuliert einen Antennenrotor mit einer Trägheits-Animation.
|
|
type DummyRotor struct {
|
|
mu sync.Mutex
|
|
azTarget float64
|
|
elTarget float64
|
|
azCurrent float64
|
|
elCurrent float64
|
|
}
|
|
|
|
// NewDummyRotor erstellt einen simulierten Rotor und startet die Hintergrund-Bewegung.
|
|
func NewDummyRotor() *DummyRotor {
|
|
r := &DummyRotor{
|
|
azCurrent: 180.0, // Startet im Süden
|
|
elCurrent: 0.0, // Flach am Horizont
|
|
}
|
|
r.azTarget = r.azCurrent
|
|
r.elTarget = r.elCurrent
|
|
|
|
// Startet die flüssige Bewegungssimulation im Hintergrund
|
|
go r.startMovementSimulation()
|
|
return r
|
|
}
|
|
|
|
func (d *DummyRotor) Connect(port string, baud int) error {
|
|
log.Printf("[Dummy-Rotor] Erfolgreich verbunden via %s (%d Baud)", port, baud)
|
|
return nil
|
|
}
|
|
|
|
func (d *DummyRotor) Disconnect() error {
|
|
log.Println("[Dummy-Rotor] Verbindung getrennt.")
|
|
return nil
|
|
}
|
|
|
|
func (d *DummyRotor) SetPosition(azimuth, elevation float64) error {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
d.azTarget = azimuth
|
|
d.elTarget = elevation
|
|
log.Printf("[Dummy-Rotor] Fahre auf Soll-Position -> Az: %.1f°, El: %.1f°", azimuth, elevation)
|
|
return nil
|
|
}
|
|
|
|
func (d *DummyRotor) GetPosition() (az, el float64, err error) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
return d.azCurrent, d.elCurrent, nil
|
|
}
|
|
|
|
// startMovementSimulation nähert die Ist-Werte alle 100ms Schritt für Schritt an die Soll-Werte an.
|
|
func (d *DummyRotor) startMovementSimulation() {
|
|
ticker := time.NewTicker(100 * time.Millisecond)
|
|
for range ticker.C {
|
|
d.mu.Lock()
|
|
// Azimut bewegen (Simuliert 4 Grad pro Sekunde -> 0.4 Grad pro 100ms)
|
|
if d.azCurrent < d.azTarget {
|
|
d.azCurrent += 0.4
|
|
if d.azCurrent > d.azTarget {
|
|
d.azCurrent = d.azTarget
|
|
}
|
|
} else if d.azCurrent > d.azTarget {
|
|
d.azCurrent -= 0.4
|
|
if d.azCurrent < d.azTarget {
|
|
d.azCurrent = d.azTarget
|
|
}
|
|
}
|
|
|
|
// Elevation bewegen (Simuliert 2 Grad pro Sekunde -> 0.2 Grad pro 100ms)
|
|
if d.elCurrent < d.elTarget {
|
|
d.elCurrent += 0.2
|
|
if d.elCurrent > d.elTarget {
|
|
d.elCurrent = d.elTarget
|
|
}
|
|
} else if d.elCurrent > d.elTarget {
|
|
d.elCurrent -= 0.2
|
|
if d.elCurrent < d.elTarget {
|
|
d.elCurrent = d.elTarget
|
|
}
|
|
}
|
|
d.mu.Unlock()
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// DummyRelais simuliert ein Relais-Board im Arbeitsspeicher.
|
|
type DummyRelais struct {
|
|
mu sync.Mutex
|
|
pins map[int]bool
|
|
}
|
|
|
|
// NewDummyRelais erstellt eine neue Instanz einer simulierten Relaiskarte.
|
|
func NewDummyRelais() *DummyRelais {
|
|
return &DummyRelais{
|
|
pins: make(map[int]bool),
|
|
}
|
|
}
|
|
|
|
func (d *DummyRelais) Connect(address string) error {
|
|
log.Printf("[Dummy-Relais] Board an Adresse %s initialisiert.", address)
|
|
return nil
|
|
}
|
|
|
|
func (d *DummyRelais) SetPin(pin int, state bool) error {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
d.pins[pin] = state
|
|
log.Printf("[Dummy-Relais] Pin %d geschaltet auf: %t", pin, state)
|
|
return nil
|
|
}
|
|
|
|
func (d *DummyRelais) GetPin(pin int) (bool, error) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
return d.pins[pin], nil
|
|
}
|
|
|
|
func (d *DummyRelais) GetAllPins() (map[int]bool, error) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
// Kopie der Map zurückgeben, um Race-Conditions außerhalb zu verhindern
|
|
copyMap := make(map[int]bool)
|
|
for k, v := range d.pins {
|
|
copyMap[k] = v
|
|
}
|
|
return copyMap, nil
|
|
}
|