Skip to content

Give RAW captures their own output stream and gate reads on RAWENABLE - #29

Open
mikelangmayr wants to merge 8 commits into
mainfrom
mike/raw-stream-output
Open

mikelangmayr wants to merge 8 commits into
mainfrom
mike/raw-stream-output

Conversation

@mikelangmayr

@mikelangmayr mikelangmayr commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor
  • Frames carry a stream name, so a pre-CDS RAW capture gets its own FITS file (<base>_<frame>_raw.fits) and its own shared-memory segment (<segment>_raw) instead of colliding with the image or resizing its stream
  • FITS datacubes are tracked per stream, so a RAW capture no longer appends into the image's cube
  • raw read refuses while RAWENABLE is 0, since the Archon captures raw alongside the frame and a controller with capture off is indistinguishable from one reporting nothing
  • raw_geometry() decides in one place whether it fell back to the config keys, and raw read warns off that
  • RAW frames carry provenance headers: RAWSEL verbatim, the MODn_TYPE of every slot it could address, and the four geometry keys
  • No slot is derived from RAWSEL: the manual documents four channels per slot over slots 5-8, the Archon GUI offers 72 selections which is eighteen per slot, and the two resolve differently on a mixed chassis
  • Documents raw retrieval in the controller commands chapter, including the module type table from the GUI source where the manual stops at 16+: Unknown
  • Verified on the emulator: the gate refuses while disabled, then enabling and exposing yields the image and RAW pair with the expected keywords
  • Emulator CI asserts the separate RAW file and segment and that the image stream geometry survives a raw read

Comment thread camerad/archon_controller.cpp Outdated

// Raw is captured with the frame, so a buffer filled before RAWENABLE was set
// reports zero and raw_geometry() falls back to inferring from the config keys
if (this->frameinfo.bufrawblocks[index] == 0 ||

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this check in raw_geometry()?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it was. raw_geometry() now sets a from_config flag in the one place that makes the decision, and read_raw warns off that instead of re-testing the buffer fields.

constexpr int MODTYPE_ADM = 17;

// First backplane slot an AD or ADM module may occupy, which RAWSEL indexes from
constexpr int AD_SLOT_FIRST = 5;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does every AD module start at slot 5?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All ADCs are slots 5-8 only

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slots 5-8 only, so the constant holds. Comment now states the full range rather than just the first slot.

Comment thread camerad/archon_controller.cpp Outdated
std::shared_ptr<const Common::FitsKeys> ArchonController::raw_frame_keys() const {
// RAWSEL indexes four channels per slot, starting at the first AD slot
const int channel = this->rawinfo.adchan;
const int slot = AD_SLOT_FIRST + channel / MAXNADCHAN;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be an inherited problem, but MAXNADCHAN=4 but there's also a MAXADCCHAN and MAXADMCHAN. Either way, this arithmetic won't work for either ADC or ADM, and certainly not for both.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and I have not changed it yet because I do not want to guess the mapping. The manual documents RAWSEL only for AD modules: 0 to 15, four per slot, "0 for channel 1 of the ADC module in slot 5 through 15 for channel 4 of the ADC module in slot 8". It says nothing about reaching an ADM channel, and an ADM has 18 per slot. This chassis is mixed, slot 5 reports type 17 and slot 6 type 2, so RAWSEL=4 is genuinely ambiguous between them.

Does RAWSEL address ADM channels at 18 per slot, or is it fixed at 4 per slot regardless of the installed module?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pulled the full SYSTEM report off the controller. It locates the boards but does not settle the mapping:

  • slot 6 is MOD6_TYPE=2, a documented AD, rev 10
  • slot 5 is MOD5_TYPE=17, rev 1, undocumented (the manual stops at 16+: Unknown)
  • slots 1-3 are MOD1..3_TYPE=16, all rev 0

STATUS reports only MODn/TEMP for both slots 5 and 6, so it cannot confirm 17 is an ADM by channel count. That equation stays an assumption already baked into the header as MODTYPE_ADM = 17.

What does settle the slot arithmetic is the documented RAWSEL range of 0 to 15, which is exactly four slots times four channels and so cannot address an 18-channel ADM at all. So dividing by four identifies the slot correctly; what it cannot identify is which of an ADM channel set you received.

Given that, does recording the derived slot plus its MODn_TYPE read right to you, with the divisor named for the documented four-per-slot RAWSEL range instead of borrowing MAXNADCHAN?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Withdrawing what I said above. The Archon GUI source settles it and contradicts the manual.

archon.h carries the full type table, so 16 and 17 are not unknown at all:

#define MOD_TYPE_ATLAS 6
#define MOD_TYPE_DRIVERX 16
#define MOD_TYPE_ADM 17
#define MOD_TYPE_UNKNOWN 18

More to the point, the GUI builds its Raw Channel Select from for (i = 1; i <= 72; i++) and stores RAWSEL = currentIndex(), so RAWSEL spans 0 to 71, not 0 to 15. 72 is 4 slots times 18 channels, which is the ADM layout. The manual range is stale.

That leaves two incompatible strides, 4 per slot from the manual and 18 per slot from the GUI, and no way for the host to tell which the firmware uses on a mixed chassis. This one has DriverX in 1-3, ADM in 5 and AD in 6, so RAWSEL=4 is slot 6 under one reading and slot 5 under the other.

So you were right and the derivation is coming out. Recording RAWSEL verbatim plus the MODn_TYPE of each of slots 5-8 claims nothing the hardware has not told us.

Separately, MODTYPE_UNKNOWN = 16 in our header is wrong, since 16 is DriverX and 18 is the sentinel. It is currently unused so nothing misbehaves, and I will keep it out of this PR.

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://CaltechOpticalObservatories.github.io/camera-interface/previews/pr-29/

Built to branch gh-pages at 2026-09-24 18:41 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants