Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/skyeye.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ jobs:
mingw-w64-ucrt-x86_64-go
mingw-w64-ucrt-x86_64-curl
zip
- name: Download Go modules
shell: msys2 {0}
run: GOMODCACHE=$(cygpath -w /ucrt64/pkg/mod) go mod download
- name: Build Skyeye
shell: msys2 {0}
run: make skyeye.exe
Expand Down
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,21 @@ SKYEYE_BIN = skyeye.exe
SKYEYE_SCALER_BIN = skyeye-scaler.exe
# Override Windows Go environment with MSYS2 UCRT64 Go environment
GO = /ucrt64/bin/go
GOBUILDVARS += GOROOT="/ucrt64/lib/go" GOPATH="/ucrt64"
GOMODCACHE_NATIVE := $(shell cygpath -w /ucrt64/pkg/mod)
GOBUILDVARS += GOROOT="/ucrt64/lib/go" GOPATH="/ucrt64" GOMODCACHE="$(GOMODCACHE_NATIVE)"
# On Windows, we statically link opus and soxr so users don't need to install them.
LIBRARIES = opus soxr
CFLAGS = $(shell pkg-config $(LIBRARIES) --cflags --static)
BUILD_VARS += CFLAGS='$(CFLAGS)'
EXTLDFLAGS = -Wl,-Bstatic $(shell pkg-config $(LIBRARIES) --libs --static) -Wl,-Bdynamic
LDFLAGS += -linkmode external -extldflags "$(EXTLDFLAGS)"
# On Windows, we copy the ONNX Runtime DLLs so we can package them with the binary during distribution.
SHERPA_DLL_DIR := $(shell $(GOBUILDVARS) $(GO) list -m -json github.com/k2-fsa/sherpa-onnx-go-windows 2>/dev/null | grep '"Dir"' | cut -d'"' -f4)/lib/x86_64-pc-windows-gnu
# The module version is read directly from go.mod to avoid invoking Go (which would trigger
# toolchain delegation to a Windows-native binary that misinterprets MSYS2 POSIX paths).
SHERPA_VERSION := $(shell grep 'k2-fsa/sherpa-onnx-go-windows' go.mod | awk '{print $$2}')
SHERPA_DLL_DIR := /ucrt64/pkg/mod/github.com/k2-fsa/sherpa-onnx-go-windows@$(SHERPA_VERSION)/lib/x86_64-pc-windows-gnu
SHERPA_DLLS = sherpa-onnx-c-api.dll onnxruntime.dll sherpa-onnx-cxx-api.dll
BUILD_VARS += SHERPA_DLL_DIR="$(SHERPA_DLL_DIR)"
endif

BUILD_VARS += LDFLAGS='$(LDFLAGS)'
Expand Down
2 changes: 1 addition & 1 deletion internal/application/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (a *Application) composeCall(ctx context.Context, call any, out chan<- Mess
response = a.composer.ComposeShoppingResponse(c)
case brevity.SnaplockResponse:
response = a.composer.ComposeSnaplockResponse(c)
case brevity.SpikedResponseV2:
case brevity.SpikedResponse:
response = a.composer.ComposeSpikedResponse(c)
case brevity.StrobeResponse:
response = a.composer.ComposeStrobeResponse(c)
Expand Down
2 changes: 1 addition & 1 deletion internal/application/synthesize.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (a *Application) synthesizeMessage(ctx context.Context, response composer.N
start := time.Now()
synthesisCtx, synthesisCancel := context.WithTimeout(ctx, 30*time.Second)
defer synthesisCancel()
audio, err := a.speaker.SayContext(synthesisCtx, response.Speech)
audio, err := a.speaker.Say(synthesisCtx, response.Speech)
if err != nil {
log.Error().Err(err).Msg("error synthesizing speech")
a.trace(traces.WithRequestError(ctx, err))
Expand Down
26 changes: 0 additions & 26 deletions pkg/brevity/spiked.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"

"github.com/dharmab/skyeye/pkg/bearings"
"github.com/martinlindhe/unit"
)

// SpikedRequest is a request to correlate a radar spike within ±30 degrees.
Expand All @@ -22,32 +21,7 @@ func (r SpikedRequest) String() string {

// SpikedResponse reports any contacts within ±30 degrees of a reported radar spike.
// Reference: ATP 3-52.4 Chapter V section 13.
//
// Deprecated: Use SpikedResponseV2 instead.
type SpikedResponse struct {
// Callsign of the friendly aircraft calling SPIKED.
Callsign string
// True if the spike was correlated to a contact. False otherwise.
Status bool
// Range to the correlated contact. If Status is false, this may be 0.
Range unit.Length
// Altitude of the correlated contact. If Status is false, this may be 0.
Altitude unit.Length
// Aspect of the correlated contact. If Status is false, this may be UnknownAspect.
Aspect Aspect
// Track of the correlated contact. If Status is false, this may be UnknownDirection.
Track Track
// Declaration of the correlated contact. If Status is false, this may be Clean.
Declaration Declaration
// Number of contacts in the correlated group. If Status is false, this may be zero.
Contacts int
// Reported spike bearing. This is used if the response did not correlate to a group.
Bearing bearings.Bearing
}

// SpikedResponseV2 reports any contacts within ±30 degrees of a reported radar spike.
// Reference: ATP 3-52.4 Chapter V section 13.
type SpikedResponseV2 struct {
// Callsign of the friendly aircraft calling SPIKED.
Callsign string
// Reported spike bearing. This is used if the response did not correlate to a group.
Expand Down
2 changes: 1 addition & 1 deletion pkg/composer/spiked.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import (
)

// ComposeSpikedResponse constructs natural language brevity for responding to a SPIKED call.
func (c *Composer) ComposeSpikedResponse(response brevity.SpikedResponseV2) NaturalLanguageResponse {
func (c *Composer) ComposeSpikedResponse(response brevity.SpikedResponse) NaturalLanguageResponse {
return c.composeCorrelation("spike", response.Callsign, response.Status, response.Bearing, response.Group)
}
2 changes: 1 addition & 1 deletion pkg/controller/spiked.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func (c *Controller) HandleSpiked(ctx context.Context, request *brevity.SpikedRe
if correlation.Callsign == "" {
c.calls <- NewCall(ctx, brevity.NegativeRadarContactResponse{Callsign: request.Callsign})
} else {
response := brevity.SpikedResponseV2{
response := brevity.SpikedResponse{
Callsign: correlation.Callsign,
Status: correlation.Group != nil,
Bearing: correlation.Bearing,
Expand Down
8 changes: 0 additions & 8 deletions pkg/encyclopedia/aircraft.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
package encyclopedia

import (
"slices"
"time"

"github.com/dharmab/skyeye/pkg/brevity"
Expand Down Expand Up @@ -89,13 +88,6 @@ func (a Aircraft) HasTag(tag AircraftTag) bool {
return ok && v
}

// HasAnyTag returns true if the aircraft has any of the specified tags.
//
// Deprecated: Use slices.Contains instead.
func (a Aircraft) HasAnyTag(tags ...AircraftTag) bool {
return slices.ContainsFunc(tags, a.HasTag)
}

// ThreatRadius returns the aircraft's threat radius.
func (a Aircraft) ThreatRadius() unit.Length {
if a.threatRadius != 0 || a.HasTag(Unarmed) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/radar/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (g *group) altitudes() []unit.Length {

// circularMean computes the circular mean of all contacts' courses.
// Returns the mean magnetic bearing and a coherence value in range 0-1.
// 0 means no coherence, 1 means all courses are prefectly coherent.
// 0 means no coherence, 1 means all courses are perfectly coherent.
func (g *group) circularMean() (bearings.Bearing, float64) {
var sumOfSines, sumOfCosines float64
for _, tf := range g.contacts {
Expand Down
2 changes: 1 addition & 1 deletion pkg/recognizer/parakeet/generate_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

package parakeet

//go:generate sh -c "SHERPA_LIB=$(go list -m -json github.com/k2-fsa/sherpa-onnx-go-windows 2>/dev/null | grep '\"Dir\"' | cut -d'\"' -f4)/lib/x86_64-pc-windows-gnu && cd \"$SHERPA_LIB\" && gendef sherpa-onnx-c-api.dll && dlltool -d sherpa-onnx-c-api.def -l libsherpa-onnx-c-api.dll.a && gendef onnxruntime.dll && dlltool -d onnxruntime.def -l libonnxruntime.dll.a && gendef sherpa-onnx-cxx-api.dll && dlltool -d sherpa-onnx-cxx-api.def -l libsherpa-onnx-cxx-api.dll.a"
//go:generate sh -c "cd \"$SHERPA_DLL_DIR\" && gendef sherpa-onnx-c-api.dll && dlltool -d sherpa-onnx-c-api.def -l libsherpa-onnx-c-api.dll.a && gendef onnxruntime.dll && dlltool -d onnxruntime.def -l libonnxruntime.dll.a && gendef sherpa-onnx-cxx-api.dll && dlltool -d sherpa-onnx-cxx-api.def -l libsherpa-onnx-cxx-api.dll.a"
17 changes: 10 additions & 7 deletions pkg/simpleradio/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ func (c *Client) newMessage(t types.MessageType) types.Message {
Version: "2.1.0.2", // stubbing fake SRS version, TODO add flag
Type: t,
}
message.Client = c.clientInfo
client := c.clientInfo
message.Client = &client
return message
}

Expand All @@ -51,14 +52,16 @@ func (c *Client) handleMessage(message types.Message) {
logMessageAndIgnore(message)
case types.MessageSync:
c.syncClients(message.Clients)
case types.MessageUpdate:
c.syncClient(message.Client)
case types.MessageRadioUpdate:
c.syncClient(message.Client)
case types.MessageUpdate, types.MessageRadioUpdate:
if message.Client != nil {
c.syncClient(*message.Client)
}
case types.MessageClientDisconnect:
c.removeClient(message.Client)
if message.Client != nil {
c.removeClient(*message.Client)
}
case types.MessageExternalAWACSModePassword:
if message.Client.Coalition == c.clientInfo.Coalition {
if message.Client != nil && message.Client.Coalition == c.clientInfo.Coalition {
log.Debug().Any("remoteClient", message.Client).Msg("received external AWACS mode password message")
// TODO is the update necessary?
if err := c.updateRadios(); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/simpleradio/types/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type Message struct {
// Version is the SRS client version.
Version string `json:"Version"`
// Client is used in messages that reference a single client.
Client ClientInfo `json:"Client"` // TODO v2: Change type to *ClientInfo and set omitempty
Client *ClientInfo `json:"Client,omitempty"`
// Clients is used in messages that reference multiple clients.
Clients []ClientInfo `json:"Clients,omitempty"`
// ServerSettings is a map of server settings and their values. It sometimes appears in Sync messages.
Expand Down
9 changes: 2 additions & 7 deletions pkg/synthesizer/speakers/macos.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ func NewMacOSSpeaker(useSystemVoice bool, playbackSpeed float64) Speaker {
return synth
}

// SayContext implements [Speaker.SayContext].
func (s *macOSSynth) SayContext(ctx context.Context, text string) ([]float32, error) {
// Say implements [Speaker.Say].
func (s *macOSSynth) Say(ctx context.Context, text string) ([]float32, error) {
outFile, err := os.CreateTemp("", "skyeye-*.aiff")
if err != nil {
return nil, fmt.Errorf("failed to create temporary AIFF file: %w", err)
Expand Down Expand Up @@ -86,8 +86,3 @@ func (s *macOSSynth) SayContext(ctx context.Context, text string) ([]float32, er
f32le := pcm.S16LEBytesToF32LE(sample)
return f32le, nil
}

// Say implements [Speaker.Say].
func (s *macOSSynth) Say(text string) ([]float32, error) {
return s.SayContext(context.Background(), text)
}
9 changes: 2 additions & 7 deletions pkg/synthesizer/speakers/piper.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ func NewPiperSpeaker(v voices.Voice, playbackSpeed float64, playbackPause time.D
return &piperSynth{tts: tts, speed: playbackSpeed, pauseLength: playbackPause}, nil
}

// SayContext implements [Speaker.SayContext].
func (s *piperSynth) SayContext(_ context.Context, text string) ([]float32, error) {
// Say implements [Speaker.Say].
func (s *piperSynth) Say(_ context.Context, text string) ([]float32, error) {
synthesized, err := s.tts.Synthesize(text, piper.WithSpeed(float32(s.speed)), piper.WithPause(float32(s.pauseLength.Seconds())))
if err != nil {
return nil, fmt.Errorf("failed to synthesize text: %w", err)
Expand All @@ -50,8 +50,3 @@ func (s *piperSynth) SayContext(_ context.Context, text string) ([]float32, erro
f32le := pcm.S16LEBytesToF32LE(downsampled)
return f32le, nil
}

// Say implements [Speaker.Say].
func (s *piperSynth) Say(text string) ([]float32, error) {
return s.SayContext(context.Background(), text)
}
5 changes: 1 addition & 4 deletions pkg/synthesizer/speakers/speaker.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ import (
// Speaker provides text-to-speech.
type Speaker interface {
// Say returns F32LE PCM audio for the given text.
//
// Deprecated: Use SayContext instead.
Say(string) ([]float32, error)
SayContext(context.Context, string) ([]float32, error)
Say(context.Context, string) ([]float32, error)
}

func downsample(sample []byte, sourceRate unit.Frequency) ([]byte, error) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/trackfiles/trackfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func TestLastKnown(t *testing.T) {
frame := tf.LastKnown()
assert.Equal(t, latest.Time, frame.Time)
assert.Equal(t, latest.Point, frame.Point)
assert.Equal(t, latest.Altitude, frame.Altitude)
assert.InDelta(t, latest.Altitude.Feet(), frame.Altitude.Feet(), 1)
})
}

Expand Down
Loading