Files
2026-08-27 19:41:00 +03:00

148 lines
3.3 KiB
Go

package service
import (
"context"
"fmt"
"log"
"regexp"
"strconv"
"sync"
pb "spektr/internal/grpc/pb"
"spektr/internal/uart"
)
type Service struct {
mu sync.Mutex
uart *uart.UART
lastFreq uint32
}
var (
versionRe = regexp.MustCompile(`(?i)HW[:=]\s*([^\s]+).*?(?:FW|SW)[:=]\s*([^\s]+)`)
freqRe = regexp.MustCompile(`(?i)\bf\d{7,9}\b`)
)
func New(u *uart.UART) *Service {
return &Service{uart: u}
}
func (s *Service) Handle(ctx context.Context, msg *pb.ClientMessage) *pb.ServerMessage {
_ = ctx
switch payload := msg.GetPayload().(type) {
case *pb.ClientMessage_Av:
return s.handleAV(msg.GetRequestId())
case *pb.ClientMessage_SetFrequency:
return s.handleSetFrequency(msg.GetRequestId(), payload.SetFrequency.GetFrequency())
case *pb.ClientMessage_GetFrequency:
return s.handleGetFrequency(msg.GetRequestId())
default:
return errorMessage(msg.GetRequestId(), "unknown command")
}
}
func (s *Service) handleAV(requestID string) *pb.ServerMessage {
s.mu.Lock()
defer s.mu.Unlock()
line, err := s.uart.Exec("av")
if err != nil {
log.Printf("uart av error: %v", err)
return errorMessage(requestID, err.Error())
}
log.Printf("uart av raw: %q", line)
hw, sw := parseVersion(line)
if hw == "" && sw == "" {
hw = line
}
return &pb.ServerMessage{
RequestId: requestID,
Payload: &pb.ServerMessage_Av{
Av: &pb.AvResponse{Ok: true, Hw: hw, Sw: sw},
},
}
}
func (s *Service) handleSetFrequency(requestID string, frequency uint32) *pb.ServerMessage {
s.mu.Lock()
defer s.mu.Unlock()
cmd := encodeFrequencyCommand(frequency)
if err := s.uart.Write(cmd); err != nil {
log.Printf("uart af write error: %v", err)
return errorMessage(requestID, err.Error())
}
log.Printf("uart af sent: %q", cmd)
s.lastFreq = frequency
return &pb.ServerMessage{
RequestId: requestID,
Payload: &pb.ServerMessage_SetFrequency{
SetFrequency: &pb.SetFrequencyResponse{Ok: true},
},
}
}
func (s *Service) handleGetFrequency(requestID string) *pb.ServerMessage {
s.mu.Lock()
defer s.mu.Unlock()
line, err := s.uart.Exec("ar")
if err != nil {
log.Printf("uart ar error: %v", err)
return errorMessage(requestID, err.Error())
}
log.Printf("uart ar raw: %q", line)
frequency, err := decodeFrequencyResponse(line)
if err != nil {
return errorMessage(requestID, err.Error())
}
s.lastFreq = frequency
return &pb.ServerMessage{
RequestId: requestID,
Payload: &pb.ServerMessage_GetFrequency{
GetFrequency: &pb.GetFrequencyResponse{Frequency: frequency},
},
}
}
func errorMessage(requestID, message string) *pb.ServerMessage {
return &pb.ServerMessage{
RequestId: requestID,
Payload: &pb.ServerMessage_Error{
Error: &pb.Error{Message: message},
},
}
}
func parseVersion(line string) (string, string) {
match := versionRe.FindStringSubmatch(line)
if len(match) == 3 {
return match[1], match[2]
}
return "", ""
}
func encodeFrequencyCommand(frequency uint32) string {
return fmt.Sprintf("af%07d", frequency*100)
}
func decodeFrequencyResponse(line string) (uint32, error) {
match := freqRe.FindString(line)
if match == "" {
return 0, fmt.Errorf("invalid frequency response %q", line)
}
value, err := strconv.ParseUint(match[1:], 10, 32)
if err != nil {
return 0, fmt.Errorf("invalid frequency response %q: %w", line, err)
}
return uint32(value / 100), nil
}