simulator v1
This commit is contained in:
161
internal/device/logic.go
Normal file
161
internal/device/logic.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package device
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ProcessCommand handles incoming BLE commands and returns the response
|
||||
func (s *DeviceState) ProcessCommand(cmd string) string {
|
||||
cmd = strings.TrimSpace(cmd)
|
||||
|
||||
// Handle global commands
|
||||
switch cmd {
|
||||
case "PROG_ON":
|
||||
s.SetProgMode(true)
|
||||
return "PROG_MODE: ON"
|
||||
|
||||
case "PROG_OFF":
|
||||
s.SetProgMode(false)
|
||||
return "PROG_MODE: OFF"
|
||||
|
||||
case "RESET":
|
||||
s.ResetAlarm()
|
||||
return "INFO: Uscita allarme resettata (BT)."
|
||||
|
||||
case "CALI":
|
||||
active := s.ToggleCaliMode()
|
||||
if active {
|
||||
return "--- MODALITA CALIBRAZIONE ATTIVA ---"
|
||||
}
|
||||
return "--- MODALITA CALIBRAZIONE DISATTIVA ---"
|
||||
|
||||
case "FACTORY":
|
||||
s.ResetToDefaults()
|
||||
return "FACTORY RESET DONE"
|
||||
}
|
||||
|
||||
// Handle write commands (W1, W2, etc.)
|
||||
if strings.HasPrefix(cmd, "W") {
|
||||
return s.handleWriteCommand(cmd)
|
||||
}
|
||||
|
||||
// Handle read commands (R1, R2, etc.)
|
||||
if strings.HasPrefix(cmd, "R") {
|
||||
return s.handleReadCommand(cmd)
|
||||
}
|
||||
|
||||
return "ERRORE: Formato comando non valido"
|
||||
}
|
||||
|
||||
// handleWriteCommand processes Wxx <value> commands
|
||||
func (s *DeviceState) handleWriteCommand(cmd string) string {
|
||||
// Check if in programming mode
|
||||
if !s.GetProgMode() {
|
||||
return "ERRORE: I comandi 'W' sono accettati solo in modalità programmazione."
|
||||
}
|
||||
|
||||
// Parse command format: "W<id> <value>"
|
||||
parts := strings.Fields(cmd)
|
||||
if len(parts) != 2 {
|
||||
return "ERRORE: Formato comando non valido"
|
||||
}
|
||||
|
||||
// Extract parameter ID
|
||||
idStr := strings.TrimPrefix(parts[0], "W")
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
return "ERRORE: Formato comando non valido"
|
||||
}
|
||||
|
||||
// Check if parameter ID is valid
|
||||
if !isValidParamID(id) {
|
||||
return "ERRORE: ID Sconosciuto"
|
||||
}
|
||||
|
||||
// Parse value
|
||||
value, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return "ERRORE: Formato comando non valido"
|
||||
}
|
||||
|
||||
// Validate range based on parameter ID
|
||||
if !validateParamRange(id, value) {
|
||||
return fmt.Sprintf("ERRORE: Valore fuori range per W%d", id)
|
||||
}
|
||||
|
||||
// Set the parameter
|
||||
s.SetParam(id, value)
|
||||
return fmt.Sprintf("PARAM: W%d=%d", id, value)
|
||||
}
|
||||
|
||||
// handleReadCommand processes Rxx commands
|
||||
func (s *DeviceState) handleReadCommand(cmd string) string {
|
||||
// Check if in programming mode
|
||||
if !s.GetProgMode() {
|
||||
return "ERRORE: I comandi 'W' sono accettati solo in modalità programmazione."
|
||||
}
|
||||
|
||||
// Extract parameter ID
|
||||
idStr := strings.TrimPrefix(cmd, "R")
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
return "ERRORE: Formato comando non valido"
|
||||
}
|
||||
|
||||
// Check if parameter ID is valid for reading
|
||||
if !isReadableParamID(id) {
|
||||
return "ERRORE: ID Sconosciuto"
|
||||
}
|
||||
|
||||
// Get the parameter value
|
||||
value, ok := s.GetParam(id)
|
||||
if !ok {
|
||||
return "ERRORE: ID Sconosciuto"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("PARAM: W%d=%d", id, value)
|
||||
}
|
||||
|
||||
// isValidParamID checks if the parameter ID is writable
|
||||
func isValidParamID(id int) bool {
|
||||
validIDs := []int{1, 2, 3, 4, 11, 12, 20}
|
||||
for _, v := range validIDs {
|
||||
if id == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isReadableParamID checks if the parameter ID is readable
|
||||
func isReadableParamID(id int) bool {
|
||||
// According to docs.toon, only R1, R2, R20 are documented
|
||||
readableIDs := []int{1, 2, 20}
|
||||
for _, v := range readableIDs {
|
||||
if id == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// validateParamRange checks if value is within acceptable range for parameter
|
||||
func validateParamRange(id, value int) bool {
|
||||
ranges := map[int][2]int{
|
||||
1: {0, 2000}, // W1 - Min Threshold
|
||||
2: {0, 4095}, // W2 - Max Threshold
|
||||
3: {1, 50}, // W3 - Pulse Count
|
||||
4: {10, 1000}, // W4 - Time Window
|
||||
11: {0, 1000}, // W11 - Min Pulse Duration
|
||||
12: {0, 1000}, // W12 - Max Pulse Duration
|
||||
20: {0, 255}, // W20 - Gain (Wiper)
|
||||
}
|
||||
|
||||
r, ok := ranges[id]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return value >= r[0] && value <= r[1]
|
||||
}
|
||||
122
internal/device/state.go
Normal file
122
internal/device/state.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package device
|
||||
|
||||
import "sync"
|
||||
|
||||
// DeviceState holds the simulated device state with thread-safe access
|
||||
type DeviceState struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
progMode bool
|
||||
caliMode bool
|
||||
alarmActive bool
|
||||
|
||||
// Parameters from docs.toon
|
||||
// W1=1200 (Min Threshold), W2=4000 (Max Threshold), W3=2 (Pulse Count),
|
||||
// W4=40 (Time Window), W20=128 (Gain)
|
||||
params map[int]int
|
||||
|
||||
sensorValue int // Default 2067 (ideal rest value)
|
||||
}
|
||||
|
||||
// NewDeviceState creates a new DeviceState with default values
|
||||
func NewDeviceState() *DeviceState {
|
||||
return &DeviceState{
|
||||
progMode: false,
|
||||
caliMode: false,
|
||||
alarmActive: false,
|
||||
params: map[int]int{
|
||||
1: 1200, // W1 - Min Threshold
|
||||
2: 4000, // W2 - Max Threshold
|
||||
3: 2, // W3 - Pulse Count
|
||||
4: 40, // W4 - Time Window
|
||||
11: 0, // W11 - Min Pulse Duration (reserved)
|
||||
12: 0, // W12 - Max Pulse Duration (reserved)
|
||||
20: 128, // W20 - Gain (Wiper)
|
||||
},
|
||||
sensorValue: 2067,
|
||||
}
|
||||
}
|
||||
|
||||
// GetProgMode returns whether programming mode is active
|
||||
func (s *DeviceState) GetProgMode() bool {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return s.progMode
|
||||
}
|
||||
|
||||
// SetProgMode sets the programming mode
|
||||
func (s *DeviceState) SetProgMode(enabled bool) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.progMode = enabled
|
||||
}
|
||||
|
||||
// GetCaliMode returns whether calibration mode is active
|
||||
func (s *DeviceState) GetCaliMode() bool {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return s.caliMode
|
||||
}
|
||||
|
||||
// ToggleCaliMode toggles the calibration mode
|
||||
func (s *DeviceState) ToggleCaliMode() bool {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.caliMode = !s.caliMode
|
||||
return s.caliMode
|
||||
}
|
||||
|
||||
// GetAlarmActive returns whether the alarm is active
|
||||
func (s *DeviceState) GetAlarmActive() bool {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return s.alarmActive
|
||||
}
|
||||
|
||||
// ResetAlarm resets the alarm state
|
||||
func (s *DeviceState) ResetAlarm() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.alarmActive = false
|
||||
}
|
||||
|
||||
// GetParam returns a parameter value by ID
|
||||
func (s *DeviceState) GetParam(id int) (int, bool) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
val, ok := s.params[id]
|
||||
return val, ok
|
||||
}
|
||||
|
||||
// SetParam sets a parameter value by ID
|
||||
func (s *DeviceState) SetParam(id, value int) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.params[id] = value
|
||||
}
|
||||
|
||||
// GetSensorValue returns the current sensor value
|
||||
func (s *DeviceState) GetSensorValue() int {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return s.sensorValue
|
||||
}
|
||||
|
||||
// ResetToDefaults resets all parameters to factory defaults
|
||||
func (s *DeviceState) ResetToDefaults() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.progMode = false
|
||||
s.caliMode = false
|
||||
s.alarmActive = false
|
||||
s.params = map[int]int{
|
||||
1: 1200,
|
||||
2: 4000,
|
||||
3: 2,
|
||||
4: 40,
|
||||
11: 0,
|
||||
12: 0,
|
||||
20: 128,
|
||||
}
|
||||
s.sensorValue = 2067
|
||||
}
|
||||
Reference in New Issue
Block a user