Loading dev/refactor/PLAN.md +26 −0 Original line number Diff line number Diff line Loading @@ -227,6 +227,32 @@ during the devices phase (no hardware needed); CCD-TEMP is still open. just the `_looping` flag) would be the next step, since a single non-looping exposure could plausibly leave the camera briefly downloading/flushing (states 4/5) too. - **New, more fundamental finding while testing the fix above with `test_atik.py` (standalone, no `noctua-api` running): the camera reports `ArtemisCameraState == -1` (`CAMERA_ERROR`) immediately after a fresh `ArtemisConnect`, before any command is issued.** Confirmed reproducible across a genuine USB power cycle in between (one run in the middle showed `ArtemisDeviceCount() == 0`, proving the device really dropped off and came back, not just a stale software handle). Ruled out: a competing process (`noctua-api` confirmed not running), a leftover software connection (ruled out by the real power cycle). Oddly, `ArtemisSubframe`/`ArtemisStartExposure` both still return `ARTEMIS_OK` (0) in this state, but `ArtemisImageReady` never becomes true — nothing actually happens on the sensor. This is a different symptom from the `code 1` failures seen through the `noctua.devices atik.py` wrapper (which happened with `self._looping` presumably true) — here, single-threaded, no loop, state is `-1` from the start and stays that way. `test_atik.py` was extended with a `wait_idle()` poll (up to 3s) to rule out a simple post-connect settle-time race before concluding it's a persistent error — not yet re-tested after this change. If it's still `-1` even after the poll, this points to a real hardware/driver/USB fault on this specific camera or its connection on `fork`, independent of and possibly underlying several other open Atik items above (the `CCD-TEMP` sentinel corruption, and perhaps the subframe/cooling behavior too) — needs `dmesg`/`lsusb` around the connect, and checking the SDK's Linux driver/udev installation (see the SDK guide's Section 4.2) hasn't drifted, not a code fix. ## Regressions found on `fork` post-refactor (2026-07-22) Loading test_atik.py +26 −3 Original line number Diff line number Diff line Loading @@ -55,12 +55,35 @@ class AtikTest: self.lib.ArtemisDisconnect(self.handle) print("Disconnesso") def set_subframe(self, xstart, ystart, width, height): """Imposta la sub-frame e stampa stato macchina + read-back SDK.""" def wait_idle(self, timeout_s=3.0): """Poll ArtemisCameraState fino a 0 (idle) o timeout. Distingue un -1 transitorio (la camera non si e' ancora stabilizzata subito dopo ArtemisConnect) da un -1 persistente (errore vero). Stampa ogni transizione di stato osservata. """ deadline = time.time() + timeout_s last = None while time.time() < deadline: state = self.lib.ArtemisCameraState(self.handle) print(f"Stato camera prima della subframe: {state} " if state != last: print(f"Stato camera: {state} " f"(0=idle, 1=waiting, 2=exposing, 4=downloading, 5=flushing, -1=error)") last = state if state == 0: return state time.sleep(0.1) return last def set_subframe(self, xstart, ystart, width, height): """Imposta la sub-frame e stampa stato macchina + read-back SDK.""" state = self.wait_idle() if state != 0: print(f"ATTENZIONE: la camera non e' mai diventata idle entro il timeout " f"(ultimo stato osservato: {state}) — procedo comunque per vedere " f"cosa fa ArtemisSubframe.") ret = self.lib.ArtemisSubframe(self.handle, xstart, ystart, width, height) print(f"ArtemisSubframe({xstart}, {ystart}, {width}, {height}) -> {ret} " Loading Loading
dev/refactor/PLAN.md +26 −0 Original line number Diff line number Diff line Loading @@ -227,6 +227,32 @@ during the devices phase (no hardware needed); CCD-TEMP is still open. just the `_looping` flag) would be the next step, since a single non-looping exposure could plausibly leave the camera briefly downloading/flushing (states 4/5) too. - **New, more fundamental finding while testing the fix above with `test_atik.py` (standalone, no `noctua-api` running): the camera reports `ArtemisCameraState == -1` (`CAMERA_ERROR`) immediately after a fresh `ArtemisConnect`, before any command is issued.** Confirmed reproducible across a genuine USB power cycle in between (one run in the middle showed `ArtemisDeviceCount() == 0`, proving the device really dropped off and came back, not just a stale software handle). Ruled out: a competing process (`noctua-api` confirmed not running), a leftover software connection (ruled out by the real power cycle). Oddly, `ArtemisSubframe`/`ArtemisStartExposure` both still return `ARTEMIS_OK` (0) in this state, but `ArtemisImageReady` never becomes true — nothing actually happens on the sensor. This is a different symptom from the `code 1` failures seen through the `noctua.devices atik.py` wrapper (which happened with `self._looping` presumably true) — here, single-threaded, no loop, state is `-1` from the start and stays that way. `test_atik.py` was extended with a `wait_idle()` poll (up to 3s) to rule out a simple post-connect settle-time race before concluding it's a persistent error — not yet re-tested after this change. If it's still `-1` even after the poll, this points to a real hardware/driver/USB fault on this specific camera or its connection on `fork`, independent of and possibly underlying several other open Atik items above (the `CCD-TEMP` sentinel corruption, and perhaps the subframe/cooling behavior too) — needs `dmesg`/`lsusb` around the connect, and checking the SDK's Linux driver/udev installation (see the SDK guide's Section 4.2) hasn't drifted, not a code fix. ## Regressions found on `fork` post-refactor (2026-07-22) Loading
test_atik.py +26 −3 Original line number Diff line number Diff line Loading @@ -55,12 +55,35 @@ class AtikTest: self.lib.ArtemisDisconnect(self.handle) print("Disconnesso") def set_subframe(self, xstart, ystart, width, height): """Imposta la sub-frame e stampa stato macchina + read-back SDK.""" def wait_idle(self, timeout_s=3.0): """Poll ArtemisCameraState fino a 0 (idle) o timeout. Distingue un -1 transitorio (la camera non si e' ancora stabilizzata subito dopo ArtemisConnect) da un -1 persistente (errore vero). Stampa ogni transizione di stato osservata. """ deadline = time.time() + timeout_s last = None while time.time() < deadline: state = self.lib.ArtemisCameraState(self.handle) print(f"Stato camera prima della subframe: {state} " if state != last: print(f"Stato camera: {state} " f"(0=idle, 1=waiting, 2=exposing, 4=downloading, 5=flushing, -1=error)") last = state if state == 0: return state time.sleep(0.1) return last def set_subframe(self, xstart, ystart, width, height): """Imposta la sub-frame e stampa stato macchina + read-back SDK.""" state = self.wait_idle() if state != 0: print(f"ATTENZIONE: la camera non e' mai diventata idle entro il timeout " f"(ultimo stato osservato: {state}) — procedo comunque per vedere " f"cosa fa ArtemisSubframe.") ret = self.lib.ArtemisSubframe(self.handle, xstart, ystart, width, height) print(f"ArtemisSubframe({xstart}, {ystart}, {width}, {height}) -> {ret} " Loading