Add runtime BMA456 tap config with NVS persistence and goTool UI.
Expose multitap parameters over UART/ESP-NOW (like deadzone), store per node in NVS, and allow get/set from CLI, REST, and the dashboard without poll-overwrite while editing. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+78
-30
@@ -15,31 +15,45 @@ import (
|
||||
)
|
||||
|
||||
type MasterView struct {
|
||||
Version uint32 `json:"version"`
|
||||
GitHash string `json:"git_hash"`
|
||||
RunningPartition string `json:"running_partition,omitempty"`
|
||||
Deadzone uint32 `json:"deadzone,omitempty"`
|
||||
Lipo1 lipoReadingJSON `json:"lipo1"`
|
||||
Lipo2 lipoReadingJSON `json:"lipo2"`
|
||||
BatteryAgeMs uint32 `json:"battery_age_ms,omitempty"`
|
||||
OK bool `json:"ok"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Version uint32 `json:"version"`
|
||||
GitHash string `json:"git_hash"`
|
||||
RunningPartition string `json:"running_partition,omitempty"`
|
||||
Deadzone uint32 `json:"deadzone,omitempty"`
|
||||
TapConfig *TapConfigView `json:"tap_config,omitempty"`
|
||||
Lipo1 lipoReadingJSON `json:"lipo1"`
|
||||
Lipo2 lipoReadingJSON `json:"lipo2"`
|
||||
BatteryAgeMs uint32 `json:"battery_age_ms,omitempty"`
|
||||
OK bool `json:"ok"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type TapConfigView struct {
|
||||
TapSensThres uint32 `json:"tap_sens_thres"`
|
||||
MaxGestDur uint32 `json:"max_gest_dur"`
|
||||
TapShockDur uint32 `json:"tap_shock_dur"`
|
||||
QuiteTimeAfterGest uint32 `json:"quite_time_after_gest"`
|
||||
WaitForTimeout uint32 `json:"wait_for_timeout"`
|
||||
AxisSel uint32 `json:"axis_sel"`
|
||||
EnableSingle bool `json:"enable_single"`
|
||||
EnableDouble bool `json:"enable_double"`
|
||||
EnableTriple bool `json:"enable_triple"`
|
||||
}
|
||||
|
||||
type ClientView struct {
|
||||
ID uint32 `json:"id"`
|
||||
MAC string `json:"mac"`
|
||||
Version uint32 `json:"version"`
|
||||
Deadzone uint32 `json:"deadzone,omitempty"`
|
||||
Available bool `json:"available"`
|
||||
Used bool `json:"used"`
|
||||
LastPing uint32 `json:"last_ping"`
|
||||
LastSuccessPing uint32 `json:"last_success_ping"`
|
||||
AccelValid bool `json:"accel_valid"`
|
||||
AccelX int32 `json:"accel_x"`
|
||||
AccelY int32 `json:"accel_y"`
|
||||
AccelZ int32 `json:"accel_z"`
|
||||
AccelAgeMs uint32 `json:"accel_age_ms"`
|
||||
ID uint32 `json:"id"`
|
||||
MAC string `json:"mac"`
|
||||
Version uint32 `json:"version"`
|
||||
Deadzone uint32 `json:"deadzone,omitempty"`
|
||||
TapConfig *TapConfigView `json:"tap_config,omitempty"`
|
||||
Available bool `json:"available"`
|
||||
Used bool `json:"used"`
|
||||
LastPing uint32 `json:"last_ping"`
|
||||
LastSuccessPing uint32 `json:"last_success_ping"`
|
||||
AccelValid bool `json:"accel_valid"`
|
||||
AccelX int32 `json:"accel_x"`
|
||||
AccelY int32 `json:"accel_y"`
|
||||
AccelZ int32 `json:"accel_z"`
|
||||
AccelAgeMs uint32 `json:"accel_age_ms"`
|
||||
AccelStream bool `json:"accel_stream"`
|
||||
TapNotifySingle bool `json:"tap_notify_single"`
|
||||
TapNotifyDouble bool `json:"tap_notify_double"`
|
||||
@@ -52,15 +66,15 @@ type ClientView struct {
|
||||
}
|
||||
|
||||
type DashboardState struct {
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
SerialPort string `json:"serial_port"`
|
||||
UARTConnected bool `json:"uart_connected"`
|
||||
SerialOK bool `json:"serial_ok"`
|
||||
SerialError string `json:"serial_error,omitempty"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
SerialPort string `json:"serial_port"`
|
||||
UARTConnected bool `json:"uart_connected"`
|
||||
SerialOK bool `json:"serial_ok"`
|
||||
SerialError string `json:"serial_error,omitempty"`
|
||||
/** Host: fast CACHE_STATUS poll (~16 ms) for accel + tap. */
|
||||
LiveStream bool `json:"live_stream"`
|
||||
Master MasterView `json:"master"`
|
||||
Clients []ClientView `json:"clients"`
|
||||
LiveStream bool `json:"live_stream"`
|
||||
Master MasterView `json:"master"`
|
||||
Clients []ClientView `json:"clients"`
|
||||
}
|
||||
|
||||
type wsHub struct {
|
||||
@@ -540,6 +554,9 @@ func pollDashboard(link *managedSerial, portName string, last *DashboardState, s
|
||||
if dz, err := readDeadzonePoll(link, 0); err == nil {
|
||||
st.Master.Deadzone = dz
|
||||
}
|
||||
if tc, err := readTapConfigPoll(link, 0); err == nil {
|
||||
st.Master.TapConfig = tc
|
||||
}
|
||||
|
||||
clients, err := link.listClientsPoll()
|
||||
if err != nil {
|
||||
@@ -574,6 +591,9 @@ func pollDashboard(link *managedSerial, portName string, last *DashboardState, s
|
||||
if dz, err := readDeadzonePoll(link, c.GetId()); err == nil {
|
||||
st.Clients[i].Deadzone = dz
|
||||
}
|
||||
if tc, err := readTapConfigPoll(link, c.GetId()); err == nil {
|
||||
st.Clients[i].TapConfig = tc
|
||||
}
|
||||
}
|
||||
}
|
||||
if last != nil {
|
||||
@@ -714,6 +734,34 @@ func readDeadzonePoll(link *managedSerial, clientID uint32) (uint32, error) {
|
||||
return r.GetDeadzone(), nil
|
||||
}
|
||||
|
||||
func tapConfigViewFromPB(r *pb.TapConfigResponse) *TapConfigView {
|
||||
return &TapConfigView{
|
||||
TapSensThres: r.GetTapSensThres(),
|
||||
MaxGestDur: r.GetMaxGestDur(),
|
||||
TapShockDur: r.GetTapShockDur(),
|
||||
QuiteTimeAfterGest: r.GetQuiteTimeAfterGest(),
|
||||
WaitForTimeout: r.GetWaitForTimeout(),
|
||||
AxisSel: r.GetAxisSel(),
|
||||
EnableSingle: r.GetEnableSingle(),
|
||||
EnableDouble: r.GetEnableDouble(),
|
||||
EnableTriple: r.GetEnableTriple(),
|
||||
}
|
||||
}
|
||||
|
||||
func readTapConfigPoll(link *managedSerial, clientID uint32) (*TapConfigView, error) {
|
||||
r, err := link.TapConfigPoll(&pb.TapConfigRequest{
|
||||
Write: false,
|
||||
ClientId: clientID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !r.GetSuccess() {
|
||||
return nil, fmt.Errorf("tap config read failed for client %d", clientID)
|
||||
}
|
||||
return tapConfigViewFromPB(r), nil
|
||||
}
|
||||
|
||||
func formatMAC(mac []byte) string {
|
||||
if len(mac) == 0 {
|
||||
return ""
|
||||
|
||||
Reference in New Issue
Block a user