From c01a99093fa5924d602f545a9a2b8514007a77fd Mon Sep 17 00:00:00 2001 From: Jacquin Antoine Date: Sun, 12 Jul 2026 15:24:11 +0200 Subject: [PATCH] Disable dangerous motor reset command after causing telescope reboot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The motor reset command (cmd 14003, inferred from a gap in the WsCmd enum) caused the telescope to immediately reboot during live testing. The Android app never uses ReqMotorReset — it only uses joystick (14006-14009), run (14000) and stop (14002). Motor homing is handled internally by the firmware during astro calibration or panorama operations. Changes: - MotorReset() now returns an error instead of sending the command - CLI "motor reset" shows the disabled message - Documented the incident and lessons in TEST_RESULTS.md - Confirmed motor position query (cmd 14001) works but returns NEED_RESET - Confirmed slew movements (all directions/speeds) work safely after reboot 💘 Generated with Crush Assisted-by: Crush:glm-5.2 --- dwarfctl/TEST_RESULTS.md | 19 +++++++++++++++++++ dwarfctl/cmd/dwarfctl/main.go | 3 +-- dwarfctl/internal/api/client.go | 19 +++++++++++-------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/dwarfctl/TEST_RESULTS.md b/dwarfctl/TEST_RESULTS.md index 996f28e..edad820 100644 --- a/dwarfctl/TEST_RESULTS.md +++ b/dwarfctl/TEST_RESULTS.md @@ -98,6 +98,25 @@ Le `motor stop` interrompt un slew en cours instantanĂ©ment. `ReqMotorRunTo` : moteur ID, position cible, vitesse. Fire-and-forget (pas de ack type=3). +#### 4.6 Motor get-position (cmd 14001 — infĂ©rĂ©, confirmĂ© fonctionnel) + +| Test | Commande | RĂ©sultat | +|------|----------|----------| +| Position moteur 0 | `motor position 0` | ✅ reply type=3, `code=-14520` (NEED_RESET) | +| Position moteur 1 | `motor position 1` | ✅ reply type=3, `code=-14520` (NEED_RESET) | + +L'ID 14001 n'est pas dans le WsCmd enum de l'APK mais fonctionne — le firmware rĂ©pond avec `ResMotorPosition{id, code, position}`. Le `code=-14520` correspond Ă  `CODE_STEP_MOTOR_NEED_RESET` : les moteurs n'ont pas Ă©tĂ© homed. + +#### 4.7 Motor reset (cmd 14003 — ⚠ DANGEREUX, DÉSACTIVÉ) + +| Test | Commande | RĂ©sultat | +|------|----------|----------| +| Reset moteur 0 | `motor reset 0 0` | ⚠ **A causĂ© le reboot du tĂ©lescope** | + +L'ID 14003 est infĂ©rĂ© (gap entre STOP=14002 et JOYSTICK=14006). L'envoi de `ReqMotorReset{id, direction}` a provoquĂ© un **reboot immĂ©diat du tĂ©lescope**. La commande est dĂ©sormais **dĂ©sactivĂ©e** dans le code et retourne une erreur explicite. + +**Leçon** : ne jamais envoyer de commandes infĂ©rĂ©es (IDs non confirmĂ©s dans le WsCmd enum de l'APK) sans validation prĂ©alable. L'app Android n'utilise que les commandes joystick (14006-14009), run (14000) et stop (14002). Le reset/home des moteurs est probablement gĂ©rĂ© cĂŽtĂ© firmware uniquement, dĂ©clenchĂ© par la calibration astro ou le panorama. + #### 4.6 Observations sur la lecture de position - **`focus_position`** (moteur de mise au point) : visible dans `state` → `focus_position:{pos:593}`, reste stable pendant les mouvements de pointage. diff --git a/dwarfctl/cmd/dwarfctl/main.go b/dwarfctl/cmd/dwarfctl/main.go index dafcf7f..e25a2b3 100644 --- a/dwarfctl/cmd/dwarfctl/main.go +++ b/dwarfctl/cmd/dwarfctl/main.go @@ -265,7 +265,7 @@ func cmdMotor() *cobra.Command { }, &cobra.Command{ Use: "reset [direction]", - Short: "Reset motor to home (0=back, 1=forward)", + Short: "Reset motor to home (DISABLED — causes reboot)", Args: cobra.RangeArgs(1, 2), Run: func(_ *cobra.Command, args []string) { id := parseInt32(args[0]) @@ -276,7 +276,6 @@ func cmdMotor() *cobra.Command { scope, cleanup := dial() defer cleanup() must(scope.MotorReset(id, dir)) - fmt.Printf("motor %d reset (dir=%v)\n", id, dir) }, }, &cobra.Command{ diff --git a/dwarfctl/internal/api/client.go b/dwarfctl/internal/api/client.go index 788489c..9119290 100644 --- a/dwarfctl/internal/api/client.go +++ b/dwarfctl/internal/api/client.go @@ -197,14 +197,10 @@ func (t *Telescope) MotorRunTo(id int32, endPos, speed float64) error { }) } -// MotorReset resets a motor (finds home via limit switch). -// cmd 14003 is inferred (not in WsCmd enum). direction: false=back, true=forward. -func (t *Telescope) MotorReset(id int32, direction bool) error { - return t.sendNotify(CmdMotorReset, &pb.ReqMotorReset{Id: id, Direction: direction}) -} - -// MotorGetPosition queries a motor's current position. -// cmd 14001 is inferred. May timeout if firmware doesn't support it. +// MotorGetPosition queries a motor's current position (cmd 14001). +// Returns code=-14520 (NEED_RESET) if motors haven't been homed. +// Note: this command ID is inferred, not in the APK's WsCmd enum, but +// confirmed working via live testing. func (t *Telescope) MotorGetPosition(id int32) (*pb.ResMotorPosition, error) { pkt, err := t.send(CmdMotorGetPosition, &pb.ReqMotorGetPosition{Id: id}) if err != nil { @@ -214,6 +210,13 @@ func (t *Telescope) MotorGetPosition(id int32) (*pb.ResMotorPosition, error) { return resp, decodeResponse(pkt, resp) } +// WARNING: MotorReset (cmd 14003) is inferred and NOT used by the Android app. +// Live testing showed it causes the telescope to reboot. Use with extreme caution. +// Disabled until properly reverse-engineered from the native .so libraries. +func (t *Telescope) MotorReset(id int32, direction bool) error { + return fmt.Errorf("motor reset (cmd 14003) is disabled: causes telescope reboot, not safe") +} + // GetFocusInfinityPos retrieves the user-defined infinity focus position. func (t *Telescope) GetFocusInfinityPos() (int32, error) { pkt, err := t.sendEmpty(CmdFocusGetUserInfinity)