Commit 4183cfa6 authored by vertighel's avatar vertighel
Browse files

Fix route /teccam2|3/gain; robustezza STL driver open; README firmware SBIG



api/guider.py: dynamic_import risolve la resource class dal nome della
classe del device (Guider per tec1/2/3), non dal file dove è scritta —
Gain (aggiunta di recente in api/camera.py) mancava dal re-export che
guider.py già fa per le classi condivise con i teccam, causando
"module 'noctua.api.guider' has no attribute 'Gain'" all'avvio.

stl.py._check_connection(): nessun percorso di fallimento chiudeva
driver/device aperti. Un Open Device fallito (27, camera non trovata)
lasciava il driver aperto; il tentativo successivo nello stesso
processo falliva quindi con Open Driver error 21
(CE_DRIVER_NOT_CLOSED), mascherando l'errore reale finché non si
riavviava tutto il processo. Ora ogni fallimento chiude quanto aperto.

README SbigSTL: causa reale riscontrata su fork — dopo un riavvio,
mancava /usr/lib/firmware/sbiglcam.hex (installato a mano solo
sbigpcam.hex durante il bring-up), la STL restava bloccata in USB
bootloader mode. Comando di copia ora usa un wildcard (*.hex) invece di
elencare i file a mano, più verifica esplicita in "Verifying".

Co-Authored-By: default avatarClaude Sonnet 5 <noreply@anthropic.com>
parent 728ad4db
Loading
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -61,9 +61,17 @@ sudo ldconfig
sudo mkdir -p /usr/include/libsbig
sudo cp sbigudrv.h /usr/include/libsbig/sbigudrv.h

# Firmware
# Firmware — copy ALL of them, not just the one for the camera you're
# testing right now. Incident on fork (2026-07): only sbigpcam.hex had
# been installed (probably a partial manual copy during an earlier
# session); after a reboot the STL-11000M (sbiglcam.hex) stayed stuck in
# USB bootloader mode (idProduct 0d97:0002, 0 endpoints) because udev's
# fxload rule for it silently failed with the .hex missing — surfacing
# as "Open Device failed (error 27)" in stl.py, then "Open Driver failed
# (error 21)" on every retry after (see stl.py's _check_connection()
# docstring for why one causes the other).
sudo mkdir -p /usr/lib/firmware
sudo cp sbigucam.hex sbiglcam.hex sbigfcam.hex sbigpcam.hex /usr/lib/firmware/
sudo cp *.hex /usr/lib/firmware/

# udev rule (remove any old/broken 99-sbig.rules first)
sudo rm -f /etc/udev/rules.d/99-sbig.rules /etc/udev/rules.d/99-sbig.rules.bak
@@ -80,6 +88,9 @@ unplugging the camera.

```bash
ldconfig -p | grep sbig      # should list libsbig.so.4
ls /usr/lib/firmware/sbig*.hex   # all 4 must be present: sbigucam, sbiglcam,
                                  # sbigfcam, sbigpcam — not just the one for
                                  # the camera you happen to be testing today
lsusb                        # SBIG camera should show "(with firmware)"
                              # in its product string after the trigger
```
+1 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ from quart import Blueprint, jsonify, request
from noctua.api.guider_instance import guider
from noctua.utils.logger import log

from .camera import FrameBinning, Loop, SnapshotRaw, SnapshotState  # noqa: F401 — re-exported for dynamic_import (tec1/2/3 class=Guider → module noctua.api.guider)
from .camera import FrameBinning, Gain, Loop, SnapshotRaw, SnapshotState  # noqa: F401 — re-exported for dynamic_import (tec1/2/3 class=Guider → module noctua.api.guider)

guider_api = Blueprint("guider", __name__)

+12 −1
Original line number Diff line number Diff line
@@ -363,7 +363,15 @@ class STL(BaseDevice):
        return self._sbig(command, params, results)

    def _check_connection(self):
        """Open the driver/device and establish a link, once."""
        """Open the driver/device and establish a link, once.

        Every failure path below closes whatever it just opened before
        returning — the driver keeps CC_OPEN_DRIVER's state across calls
        within the process, so leaving it open after a failed
        CC_OPEN_DEVICE/CC_ESTABLISH_LINK makes the *next* retry fail with
        CE_DRIVER_NOT_CLOSED (21) instead of the real, transient error,
        masking it until the whole process is restarted.
        """
        if self._opened or self._lib is None:
            return self._opened

@@ -382,6 +390,7 @@ class STL(BaseDevice):
            if msg not in self.error:
                self.error.append(msg)
            log.error(msg)
            self.put(CC_CLOSE_DRIVER)
            return False

        link_results = EstablishLinkResults()
@@ -391,6 +400,8 @@ class STL(BaseDevice):
            if msg not in self.error:
                self.error.append(msg)
            log.error(msg)
            self.put(CC_CLOSE_DEVICE)
            self.put(CC_CLOSE_DRIVER)
            return False

        self._camera_type = link_results.cameraType