first
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user