148 lines
3.3 KiB
Go
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
|
|
}
|