Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c1ce7f3
updates sequencerd published messages for fineacquire
astronomerdave Apr 25, 2026
2c57e98
adds updated message_keys.h missing from last commit
astronomerdave Apr 25, 2026
1e6c496
replaces more async UDP broadcasts with new broadcast call (zmq-pub)
astronomerdave Apr 25, 2026
c5d0c8f
* fixes state-change prob in sequencer
Apr 26, 2026
9be38d5
slitd publishes on change, tcsd publishes at 1 Hz
Apr 27, 2026
51b0a10
bug fix tcsd
Apr 27, 2026
a768cb0
fixes issue with acamd tcs subscriber
Apr 27, 2026
d968c27
fixes bug in acam_interface.cpp
Apr 27, 2026
2de13fe
updates seqmon to limit scroll area
astronomerdave Apr 27, 2026
a32bd94
adds new Common::Broadcaster and replacecs async in sequencerd
astronomerdave Apr 27, 2026
52e0f19
fixes typo
astronomerdave Apr 27, 2026
daa60a0
adds a few async calls I forgot to remove from sequencer
astronomerdave Apr 27, 2026
6bbc031
Update common/CMakeLists.txt and make common link ZMQ/zmqpp as PUBLIC so
astronomerdave Apr 28, 2026
3b9803e
fixes bug: catch exception calling Sequence::power_init
astronomerdave Apr 29, 2026
9f381ab
sequencer subscribes to SLITD, TCSD, removes need for get_external_te…
astronomerdave Apr 30, 2026
56dadf0
adds `fineacquire` command to enable|disable automatic fine acquisiti…
astronomerdave May 1, 2026
38b64fa
fixes longstanding copy-paste bug
astronomerdave May 5, 2026
f3f9f2b
fixes race condition where sequencer could start fineacquire
astronomerdave May 5, 2026
b48f483
addresses race condition in slicecamd
astronomerdave May 5, 2026
fc6781e
a more complete fix
astronomerdave May 5, 2026
e677932
fix: accept bare fineacquire start and use config-backed defaults
astronomerdave May 6, 2026
878c91d
fix: fineaquire fail/success cases were reversed
astronomerdave May 7, 2026
4546010
disable guiding before moving telescope
astronomerdave May 7, 2026
d0fe153
fixes bug where stuck in loop when failing to find centroid
astronomerdave May 7, 2026
2a1a4a9
fix: abort didn't cancel acquisition in progress
astronomerdave May 7, 2026
a6ab13b
fixes bug introduced last night using wrong state manager
astronomerdave May 7, 2026
c604718
.
astronomerdave May 7, 2026
b61140a
.
astronomerdave May 7, 2026
0374774
fix: camerad was missing topic handler for SNAPSHOT
astronomerdave May 7, 2026
2c8b09b
.
astronomerdave May 7, 2026
22e3e80
adds gain scheduling and configurable parameters
astronomerdave May 8, 2026
2e03ab3
* fixes SLITO,SLITW telemkeys indexing error
astronomerdave May 8, 2026
55879e3
cleans up sequencer broadcast messages
astronomerdave May 11, 2026
1cfae3e
sequencer publishes SHOULD_FINEACQUIRE along with SEQSTATE
astronomerdave May 11, 2026
ec200e4
fix: not all sequencer threads were awoken on abort
astronomerdave May 11, 2026
400b036
missing message key for prev commit
astronomerdave May 11, 2026
839f0c1
fixes timing overlap between SEQ_READY and SEQUENCE_START during abort
astronomerdave May 11, 2026
1f24aa3
sequencerd: better detection of acam/slicecam failures
astronomerdave May 11, 2026
4c86f29
Update SEQ status flow
prkrtg Apr 20, 2026
5b2a254
Add Seq wait states
prkrtg Apr 23, 2026
acfe20d
import
prkrtg Apr 23, 2026
8084a09
Added zmq debugger
prkrtg May 2, 2026
ce208d4
Add fine acquire button
prkrtg May 14, 2026
ab1fda8
connect to seq state
prkrtg May 14, 2026
af6abbf
Merge branch 'main' into pgupta/gui_auto_acq_update
prkrtg May 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions camerad/astrocam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ namespace AstroCam {
/***** AstroCam::Interface::handletopic_snapshot ****************************/


/***** AstroCam::Interface::handletopic_snapshot ****************************/
/**
* @brief what to do when the topic is Topic::SNAPSHOT
* @details This publishes a JSON message containing a snapshot of my
* telemetry info when the subscriber receives the Topic::SNAPSHOT
* topic and the payload contains my name.
* @param[in] jmessage_in subscribed-received JSON message
*
*/
void Interface::handletopic_snapshot( const nlohmann::json &jmessage_in ) {
if ( jmessage_in.contains( Topic::CAMERAD ) ) this->publish_snapshot();
}
/***** AstroCam::Interface::handletopic_snapshot ****************************/


long NewAstroCam::new_expose( std::string nseq_in ) {
logwrite( "NewAstroCam::new_expose", nseq_in );
return( NO_ERROR );
Expand Down
98 changes: 87 additions & 11 deletions pygui/layout_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from control_tab import ControlTab
from instrument_status_tab import InstrumentStatusTab
import re
import subprocess

class LayoutService:
def __init__(self, parent):
Expand Down Expand Up @@ -193,15 +194,31 @@ def create_system_status_group(self):

# Create a mapping for status colors
status_map = {
"stopped": QColor(169, 169, 169), # Grey
"idle": QColor(255, 255, 0), # Yellow
"paused": QColor(255, 165, 0), # Orange
"exposing": QColor(0, 255, 0), # Green
"readout": QColor(0, 255, 0), # Green
"acquire": QColor(255, 255, 0), # Yellow
"focus": QColor(255, 255, 0), # Yellow
"calib": QColor(255, 255, 0), # Yellow
"user": QColor(255, 255, 0), # Yellow
"stopped": QColor(169, 169, 169),
"not_ready": QColor(255, 0, 0),
"idle": QColor(255, 255, 0),
"paused": QColor(255, 165, 0),
"exposing": QColor(0, 255, 0),
"readout": QColor(0, 255, 0),

"moveto": QColor(255, 255, 0),
"acam_acquire": QColor(255, 255, 0),
"slicecam_fineacquire": QColor(255, 255, 0),

"focus": QColor(255, 255, 0),
"calib": QColor(255, 255, 0),
"camera": QColor(255, 255, 0),
"flexure": QColor(255, 255, 0),
"power": QColor(255, 255, 0),
"slit": QColor(255, 255, 0),
"tcs": QColor(255, 255, 0),
"tcsop": QColor(255, 255, 0),
"user": QColor(255, 255, 0),

# transitional / backward compatibility
"acam": QColor(255, 255, 0),
"slicecam": QColor(255, 255, 0),
"acquire": QColor(255, 255, 0),
}

# Create a dictionary to hold the status widgets, which we will enable/disable
Expand All @@ -223,7 +240,7 @@ def create_system_status_group(self):
status_color_rect.setStyleSheet(f"background-color: {color.name()};")

# Label showing the status
status_label = QLabel(status.capitalize())
status_label = QLabel(status.replace("_", " ").title())
status_label.setMargin(0) # Remove extra margin around the label

# Layout for each status (color + label)
Expand Down Expand Up @@ -359,14 +376,73 @@ def create_sequencer_mode_group(self):
sequencer_mode_layout.addWidget(self.parent.sequencer_mode_single)
sequencer_mode_layout.addWidget(self.parent.sequencer_mode_all)

# Fine acquire toggle
self.parent.fine_acquire_toggle = QPushButton("Fine Acquire: Disabled")
self.parent.fine_acquire_toggle.setCheckable(True)
self.parent.fine_acquire_toggle.setToolTip("Enable or disable sequencer fine acquire")
self.parent.fine_acquire_toggle.setMaximumWidth(200)
self.parent.fine_acquire_toggle.setStyleSheet("""
QPushButton {
background-color: #D3D3D3;
color: black;
font-weight: bold;
border-radius: 6px;
padding: 6px;
}
QPushButton:checked {
background-color: #4CAF50;
color: white;
}
""")
self.parent.fine_acquire_toggle.toggled.connect(self.on_fine_acquire_toggled)
sequencer_mode_layout.addWidget(self.parent.fine_acquire_toggle)

sequencer_mode_group.setLayout(sequencer_mode_layout)

# Set maximum width and height for the sequencer mode group
sequencer_mode_group.setMaximumWidth(300) # Maximum width
sequencer_mode_group.setMaximumHeight(100) # Maximum height
sequencer_mode_group.setMaximumHeight(145) # Maximum height

return sequencer_mode_group

def on_fine_acquire_toggled(self, checked):
"""Enable/disable the sequencer fine-acquire step."""
action = "enable" if checked else "disable"
command = ["seq", "fineacquire", action]
button = getattr(self.parent, "fine_acquire_toggle", None)

if button is not None:
button.setText(f"Fine Acquire: {'Enabled' if checked else 'Disabled'}")

try:
result = subprocess.run(
command,
check=True,
capture_output=True,
text=True,
)

if hasattr(self.parent, "message_log") and self.parent.message_log:
self.update_message_log(f"Ran command: {' '.join(command)}")
if result.stdout.strip():
self.update_message_log(result.stdout.strip())

except Exception as exc:
# Revert the UI if the command failed.
if button is not None:
with QSignalBlocker(button):
button.setChecked(not checked)
button.setText(f"Fine Acquire: {'Disabled' if checked else 'Enabled'}")

QMessageBox.warning(
self.parent,
"Fine Acquire Command Failed",
f"Could not run: {' '.join(command)}\n\n{exc}",
)

if hasattr(self.parent, "message_log") and self.parent.message_log:
self.update_message_log(f"Fine acquire command failed: {' '.join(command)} — {exc}")

def create_progress_and_image_group(self):
progress_and_image_group = QGroupBox("Progress and Image Info")
progress_and_image_layout = QVBoxLayout()
Expand Down
17 changes: 16 additions & 1 deletion pygui/ngps_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def __init__(self):
self.current_owner = None
self.current_target_list_name = None
self.zmq_status_service = None
self.zmq_debug_messages = False

# Login status flag
self.logged_in = False
Expand Down Expand Up @@ -178,7 +179,10 @@ def initialize_services(self):
self.status_service.shutter_status_signal.connect(self.layout_service.update_shutter_status)

# Initialize the ZMQStatusService
self.zmq_status_service = ZmqStatusService(self)
self.zmq_status_service = ZmqStatusService(
self,
emit_debug_messages=self.zmq_debug_messages,
)
self.zmq_status_service.connect()

# # Start the ZMQStatusService in a separate thread
Expand All @@ -189,6 +193,7 @@ def initialize_services(self):
self.zmq_status_service.subscribe_to_topic("tcsd")
self.zmq_status_service.subscribe_to_topic("acamd")
self.zmq_status_service.subscribe_to_topic("seq_waitstate")
self.zmq_status_service.subscribe_to_topic("seq_seqstate")

# Connect the message_received signal from ZMQStatusService to the update_message_log slot
self.zmq_status_service.new_message_signal.connect(self.layout_service.update_message_log)
Expand Down Expand Up @@ -490,6 +495,16 @@ def update_etc_target(self, target_data):

self.etc_popup.set_target_info(name, ra, dec)

def set_zmq_debug_messages(self, enabled: bool):
"""Enable or disable raw ZMQ messages in the GUI message log."""
self.zmq_debug_messages = bool(enabled)

if self.zmq_status_service is not None:
self.zmq_status_service.set_debug_messages(enabled)

state = "enabled" if enabled else "disabled"
self.layout_service.update_message_log(f"ZMQ debug messages {state}.")


if __name__ == '__main__':
app = QApplication(sys.argv)
Expand Down
Loading
Loading