up
This commit is contained in:
11
cmd/server/web/dist/assets/index-Drom3Zfz.js
vendored
Normal file
11
cmd/server/web/dist/assets/index-Drom3Zfz.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
cmd/server/web/dist/assets/index-pnuRxXpy.css
vendored
Normal file
1
cmd/server/web/dist/assets/index-pnuRxXpy.css
vendored
Normal file
File diff suppressed because one or more lines are too long
5
cmd/server/web/dist/index.html
vendored
5
cmd/server/web/dist/index.html
vendored
@@ -7,11 +7,10 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
|
||||
<script type="module" crossorigin src="/assets/index-BqlArLJ0.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Bl7hatTL.css">
|
||||
<script type="module" crossorigin src="/assets/index-Drom3Zfz.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-pnuRxXpy.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
|
||||
</body>
|
||||
@@ -45,6 +45,10 @@ type Client struct {
|
||||
|
||||
onFrequencyChange func(freqMHz float64)
|
||||
checkTransmitAllowed func() bool
|
||||
|
||||
// Track current slice frequency
|
||||
currentFreq float64
|
||||
currentFreqMu sync.RWMutex
|
||||
}
|
||||
|
||||
func New(host string, port int) *Client {
|
||||
@@ -59,7 +63,11 @@ func New(host string, port int) *Client {
|
||||
lastStatus: &Status{
|
||||
Connected: false,
|
||||
RadioOn: false,
|
||||
Tx: false, // Initialisé à false
|
||||
ActiveSlices: 0,
|
||||
Frequency: 0,
|
||||
},
|
||||
currentFreq: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,21 +326,108 @@ func (c *Client) handleMessage(msg string) {
|
||||
// DEBUG: Log tous les messages reçus
|
||||
log.Printf("FlexRadio RAW: %s", msg)
|
||||
|
||||
// Router selon le premier caractère
|
||||
switch msg[0] {
|
||||
case 'R': // Réponse à une commande
|
||||
// Vérifier le type de message
|
||||
if len(msg) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
// Messages commençant par R (réponses)
|
||||
if msg[0] == 'R' {
|
||||
c.handleCommandResponse(msg)
|
||||
case 'S': // Message de statut
|
||||
c.handleStatusMessage(msg)
|
||||
case 'V': // Version/Handle
|
||||
return
|
||||
}
|
||||
|
||||
// Messages commençant par S (statut)
|
||||
if msg[0] == 'S' {
|
||||
// Enlever le préfixe S
|
||||
msg = msg[1:]
|
||||
|
||||
// Séparer handle et données
|
||||
parts := strings.SplitN(msg, "|", 2)
|
||||
if len(parts) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
handle := parts[0]
|
||||
data := parts[1]
|
||||
|
||||
// Parser les paires clé=valeur
|
||||
statusMap := make(map[string]string)
|
||||
pairs := strings.Fields(data)
|
||||
for _, pair := range pairs {
|
||||
if kv := strings.SplitN(pair, "=", 2); len(kv) == 2 {
|
||||
statusMap[kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
|
||||
// Identifier le type de message
|
||||
if strings.Contains(data, "interlock") {
|
||||
c.handleInterlockStatus(handle, statusMap)
|
||||
} else if strings.Contains(data, "slice") {
|
||||
c.handleSliceStatus(handle, statusMap)
|
||||
} else if strings.Contains(data, "radio") {
|
||||
c.handleRadioStatus(handle, statusMap)
|
||||
} else {
|
||||
// Vérifier si c'est une mise à jour de fréquence
|
||||
if freqStr, ok := statusMap["RF_frequency"]; ok {
|
||||
c.handleFrequencyUpdate(handle, freqStr, statusMap)
|
||||
} else {
|
||||
log.Printf("FlexRadio: Message inconnu (handle=%s): %s", handle, data)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Autres types de messages
|
||||
switch msg[0] {
|
||||
case 'V':
|
||||
log.Printf("FlexRadio: Version/Handle: %s", msg)
|
||||
case 'M': // Message général
|
||||
case 'M':
|
||||
log.Printf("FlexRadio: Message: %s", msg)
|
||||
default:
|
||||
log.Printf("FlexRadio: Unknown message type: %s", msg)
|
||||
log.Printf("FlexRadio: Type de message inconnu: %s", msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleSliceStatus(handle string, statusMap map[string]string) {
|
||||
c.statusMu.Lock()
|
||||
defer c.statusMu.Unlock()
|
||||
|
||||
if c.lastStatus == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Mettre à jour le nombre de slices actives
|
||||
c.lastStatus.ActiveSlices = 1
|
||||
|
||||
// Mettre à jour la fréquence
|
||||
if rfFreq, ok := statusMap["RF_frequency"]; ok {
|
||||
if freq, err := strconv.ParseFloat(rfFreq, 64); err == nil && freq > 0 {
|
||||
oldFreq := c.lastStatus.Frequency
|
||||
c.lastStatus.Frequency = freq
|
||||
c.lastStatus.RadioInfo = fmt.Sprintf("Active on %.3f MHz", freq)
|
||||
|
||||
// Déclencher le callback si la fréquence a changé
|
||||
if oldFreq != freq && c.onFrequencyChange != nil {
|
||||
go c.onFrequencyChange(freq)
|
||||
}
|
||||
} else if freq == 0 {
|
||||
// Fréquence 0 = slice inactive
|
||||
c.lastStatus.Frequency = 0
|
||||
c.lastStatus.RadioInfo = "Slice inactive"
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour le mode
|
||||
if mode, ok := statusMap["mode"]; ok {
|
||||
c.lastStatus.Mode = mode
|
||||
}
|
||||
|
||||
// NE PAS utiliser tx du slice pour l'état TX réel
|
||||
// tx=1 dans le slice signifie seulement "capable de TX", pas "en train de TX"
|
||||
// L'état TX réel vient de l'interlock
|
||||
}
|
||||
|
||||
func (c *Client) handleCommandResponse(msg string) {
|
||||
// Format: R<seq>|<status>|<data>
|
||||
parts := strings.SplitN(msg, "|", 3)
|
||||
@@ -381,39 +476,6 @@ func isSliceListResponse(data string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Client) handleStatusMessage(msg string) {
|
||||
parts := strings.SplitN(msg, "|", 2)
|
||||
if len(parts) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
handle := parts[0][1:]
|
||||
data := parts[1]
|
||||
|
||||
statusMap := make(map[string]string)
|
||||
pairs := strings.Fields(data)
|
||||
|
||||
for _, pair := range pairs {
|
||||
if kv := strings.SplitN(pair, "=", 2); len(kv) == 2 {
|
||||
statusMap[kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.Contains(msg, "interlock"):
|
||||
c.handleInterlockStatus(handle, statusMap)
|
||||
|
||||
case strings.Contains(msg, "slice"):
|
||||
c.handleSliceStatus(handle, statusMap)
|
||||
|
||||
case strings.Contains(msg, "radio"):
|
||||
c.handleRadioStatus(handle, statusMap)
|
||||
|
||||
default:
|
||||
log.Printf("FlexRadio: Unknown status (handle=%s): %s", handle, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleInterlockStatus(handle string, statusMap map[string]string) {
|
||||
c.statusMu.Lock()
|
||||
defer c.statusMu.Unlock()
|
||||
@@ -424,45 +486,57 @@ func (c *Client) handleInterlockStatus(handle string, statusMap map[string]strin
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleSliceStatus(handle string, statusMap map[string]string) {
|
||||
func (c *Client) handleRadioStatus(handle string, statusMap map[string]string) {
|
||||
c.statusMu.Lock()
|
||||
defer c.statusMu.Unlock()
|
||||
|
||||
// Quand on reçoit un message de slice, on a au moins une slice active
|
||||
c.lastStatus.ActiveSlices = 1
|
||||
if c.lastStatus == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if rfFreq, ok := statusMap["RF_frequency"]; ok {
|
||||
if freq, err := strconv.ParseFloat(rfFreq, 64); err == nil && freq > 0 {
|
||||
// Mettre à jour les informations radio
|
||||
c.lastStatus.RadioOn = true
|
||||
c.lastStatus.Connected = true
|
||||
|
||||
// Mettre à jour le nombre de slices
|
||||
if slices, ok := statusMap["slices"]; ok {
|
||||
if num, err := strconv.Atoi(slices); err == nil {
|
||||
c.lastStatus.NumSlices = num
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour le callsign
|
||||
if callsign, ok := statusMap["callsign"]; ok {
|
||||
c.lastStatus.Callsign = callsign
|
||||
}
|
||||
|
||||
// Mettre à jour les autres infos
|
||||
if nickname, ok := statusMap["nickname"]; ok {
|
||||
c.lastStatus.RadioInfo = fmt.Sprintf("Radio: %s", nickname)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleFrequencyUpdate(handle string, freqStr string, statusMap map[string]string) {
|
||||
c.statusMu.Lock()
|
||||
defer c.statusMu.Unlock()
|
||||
|
||||
if c.lastStatus == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Parser la fréquence
|
||||
if freq, err := strconv.ParseFloat(freqStr, 64); err == nil && freq > 0 {
|
||||
oldFreq := c.lastStatus.Frequency
|
||||
c.lastStatus.Frequency = freq
|
||||
c.lastStatus.RadioInfo = fmt.Sprintf("Active on %.3f MHz", freq)
|
||||
|
||||
if c.onFrequencyChange != nil {
|
||||
// Déclencher le callback si la fréquence a changé
|
||||
if oldFreq != freq && c.onFrequencyChange != nil {
|
||||
go c.onFrequencyChange(freq)
|
||||
}
|
||||
} else if freq == 0 {
|
||||
// Fréquence 0 dans le message de slice = slice inactive
|
||||
c.lastStatus.Frequency = 0
|
||||
c.lastStatus.RadioInfo = "Slice inactive"
|
||||
}
|
||||
}
|
||||
|
||||
if mode, ok := statusMap["mode"]; ok {
|
||||
c.lastStatus.Mode = mode
|
||||
}
|
||||
|
||||
if tx, ok := statusMap["tx"]; ok {
|
||||
c.lastStatus.Tx = (tx == "1")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleRadioStatus(handle string, statusMap map[string]string) {
|
||||
if slices, ok := statusMap["slices"]; ok {
|
||||
if num, err := strconv.Atoi(slices); err == nil {
|
||||
c.statusMu.Lock()
|
||||
c.lastStatus.NumSlices = num
|
||||
c.statusMu.Unlock()
|
||||
}
|
||||
}
|
||||
log.Printf("FlexRadio: Frequency update: %s MHz", freqStr)
|
||||
}
|
||||
|
||||
func (c *Client) parseInfoResponse(data string) {
|
||||
@@ -506,11 +580,18 @@ func (c *Client) parseInfoResponse(data string) {
|
||||
|
||||
c.radioInfoMu.Unlock()
|
||||
|
||||
// Mettre à jour le statut
|
||||
c.updateRadioStatus(true, "Radio is on")
|
||||
|
||||
go func() {
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
c.SendSliceList()
|
||||
|
||||
// S'abonner aux mises à jour
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
c.sendCommand("sub slice all")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
c.sendCommand("sub interlock 0")
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -555,7 +636,10 @@ func (c *Client) updateRadioStatus(isOn bool, info string) {
|
||||
c.statusMu.Lock()
|
||||
defer c.statusMu.Unlock()
|
||||
|
||||
if c.lastStatus != nil {
|
||||
if c.lastStatus == nil {
|
||||
return
|
||||
}
|
||||
|
||||
c.lastStatus.RadioOn = isOn
|
||||
c.lastStatus.RadioInfo = info
|
||||
|
||||
@@ -580,7 +664,6 @@ func (c *Client) updateRadioStatus(isOn bool, info string) {
|
||||
c.lastStatus.RadioInfo = "Radio is on without any active slice"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) reconnectionMonitor() {
|
||||
log.Println("FlexRadio: Reconnection monitor started")
|
||||
@@ -716,10 +799,12 @@ func (c *Client) GetStatus() (*Status, error) {
|
||||
return &Status{
|
||||
Connected: false,
|
||||
RadioOn: false,
|
||||
Tx: false,
|
||||
RadioInfo: "Not initialized",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Créer une copie
|
||||
status := *c.lastStatus
|
||||
return &status, nil
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@ package flexradio
|
||||
// Status represents the FlexRadio status
|
||||
type Status struct {
|
||||
Connected bool `json:"connected"`
|
||||
Frequency float64 `json:"frequency"`
|
||||
RadioOn bool `json:"radio_on"`
|
||||
RadioInfo string `json:"radio_info"`
|
||||
Frequency float64 `json:"frequency"` // Primary frequency in MHz
|
||||
Mode string `json:"mode"`
|
||||
Tx bool `json:"tx"`
|
||||
RadioOn bool `json:"radio_on"` // Radio is powered on and responding
|
||||
RadioInfo string `json:"radio_info"` // Additional info about radio state
|
||||
Callsign string `json:"callsign"` // From info command
|
||||
Model string `json:"model"` // From info command
|
||||
SoftwareVer string `json:"software_ver"` // From info command
|
||||
NumSlices int `json:"num_slices"` // From info command
|
||||
ActiveSlices int `json:"active_slices"` // Count of active slices
|
||||
Tx bool `json:"tx"` // Actually transmitting
|
||||
ActiveSlices int `json:"active_slices"`
|
||||
NumSlices int `json:"num_slices"`
|
||||
Callsign string `json:"callsign"`
|
||||
Model string `json:"model"`
|
||||
SoftwareVer string `json:"software_ver"`
|
||||
}
|
||||
|
||||
// InterlockState represents possible interlock states
|
||||
|
||||
Reference in New Issue
Block a user