Skip to content

Commit dbae71f

Browse files
authored
Fix errors overlaying on topics in ncurses frontend (#35)
Logs are now directed to a logfile instead of the screen by default. --------- Signed-off-by: Blake McHale <bmchale@nvidia.com>
1 parent 0704069 commit dbae71f

2 files changed

Lines changed: 35 additions & 24 deletions

File tree

‎greenwave_monitor/greenwave_monitor/ncurses_frontend.py‎

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,11 @@ def update_visible_topics(self):
113113

114114
self.visible_topics.sort()
115115

116-
def toggle_topic_monitoring(self, topic_name: str):
116+
def toggle_topic_monitoring(self, topic_name: str) -> tuple[bool, str]:
117117
"""Toggle monitoring for a topic."""
118118
if self.ui_adaptor:
119-
self.ui_adaptor.toggle_topic_monitoring(topic_name)
120-
self.show_status(f'Toggling monitoring for {topic_name}')
121-
else:
122-
self.show_status('UI adaptor not available')
119+
return self.ui_adaptor.toggle_topic_monitoring(topic_name)
120+
return False, 'UI adaptor not available'
123121

124122
def show_status(self, message: str):
125123
"""Show a status message for 3 seconds."""
@@ -141,6 +139,7 @@ def curses_main(stdscr, node):
141139
last_redraw = 0
142140
status_message = ''
143141
status_timeout = 0
142+
status_is_error = False
144143
input_mode = None
145144
input_buffer = ''
146145

@@ -231,12 +230,15 @@ def curses_main(stdscr, node):
231230
success, msg = node.ui_adaptor.set_expected_frequency(
232231
topic_name, hz, tolerance)
233232
status_message = f'Set frequency for {topic_name}: {hz}Hz'
233+
status_is_error = not success
234234
if not success:
235235
status_message = f'Error: {msg}'
236236
else:
237237
status_message = 'Invalid input format'
238+
status_is_error = True
238239
except ValueError:
239240
status_message = 'Invalid frequency values'
241+
status_is_error = True
240242
status_timeout = current_time + 3.0
241243
input_mode = None
242244
input_buffer = ''
@@ -273,19 +275,23 @@ def curses_main(stdscr, node):
273275
elif key == ord('\n') or key == ord(' '):
274276
if 0 <= selected_row < len(node.visible_topics):
275277
topic_name = node.visible_topics[selected_row]
276-
node.toggle_topic_monitoring(topic_name)
277-
status_message = f'Toggled monitoring for {topic_name}'
278+
success, msg = node.toggle_topic_monitoring(topic_name)
279+
status_message = msg if not success else f'Toggled monitoring for {topic_name}'
280+
status_is_error = not success
278281
status_timeout = current_time + 3.0
279282
elif key == ord('f') or key == ord('F'):
280283
if 0 <= selected_row < len(node.visible_topics):
281284
input_mode = 'frequency'
282285
input_buffer = ''
286+
status_timeout = 0
287+
status_is_error = False
283288
elif key == ord('c') or key == ord('C'):
284289
if 0 <= selected_row < len(node.visible_topics):
285290
topic_name = node.visible_topics[selected_row]
286291
success, msg = node.ui_adaptor.set_expected_frequency(
287292
topic_name, clear=True)
288293
status_message = f'Cleared frequency for {topic_name}'
294+
status_is_error = not success
289295
if not success:
290296
status_message = f'Error: {msg}'
291297
status_timeout = current_time + 3.0
@@ -295,6 +301,7 @@ def curses_main(stdscr, node):
295301
node.update_visible_topics()
296302
mode_text = 'monitored only' if node.hide_unmonitored else 'all topics'
297303
status_message = f'Showing {mode_text}'
304+
status_is_error = False
298305
status_timeout = current_time + 3.0
299306

300307
# Get data safely
@@ -400,8 +407,9 @@ def curses_main(stdscr, node):
400407
# Status message
401408
if current_time < status_timeout:
402409
try:
403-
stdscr.addstr(height - 3, 0, status_message[:width-1],
404-
curses.color_pair(COLOR_STATUS_MSG))
410+
color = curses.color_pair(COLOR_ERROR) if status_is_error \
411+
else curses.color_pair(COLOR_STATUS_MSG)
412+
stdscr.addstr(height - 3, 0, status_message[:width-1], color)
405413
except curses.error:
406414
pass
407415

@@ -470,6 +478,7 @@ def parse_args(args=None):
470478
def main(args=None):
471479
"""Entry point for the ncurses frontend application."""
472480
parsed_args, ros_args = parse_args(args)
481+
ros_args.extend(['--ros-args', '--disable-stdout-logs'])
473482
rclpy.init(args=ros_args)
474483
node = GreenwaveNcursesFrontend(hide_unmonitored=parsed_args.hide_unmonitored)
475484
thread = None

‎greenwave_monitor/greenwave_monitor/ui_adaptor.py‎

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -184,45 +184,47 @@ def _on_diagnostics(self, msg: DiagnosticArray):
184184
# Skip updating expected_frequencies if values aren't numeric
185185
self.expected_frequencies.pop(topic_name, None)
186186

187-
def toggle_topic_monitoring(self, topic_name: str):
187+
def toggle_topic_monitoring(self, topic_name: str) -> tuple[bool, str]:
188188
"""Toggle monitoring for a topic."""
189189
if not self.manage_topic_client.wait_for_service(timeout_sec=1.0):
190-
return
190+
return False, 'Could not connect to manage_topic service.'
191191

192192
request = ManageTopic.Request()
193193
request.topic_name = topic_name
194194

195195
with self.data_lock:
196196
request.add_topic = topic_name not in self.ui_diagnostics
197197

198+
action = 'start' if request.add_topic else 'stop'
199+
198200
try:
199-
# Use asynchronous service call to prevent deadlock
200201
future = self.manage_topic_client.call_async(request)
201202
rclpy.spin_until_future_complete(self.node, future, timeout_sec=3.0)
202203

203204
if future.result() is None:
204-
action = 'start' if request.add_topic else 'stop'
205-
self.node.get_logger().error(
206-
f'Failed to {action} monitoring: Service call timed out')
207-
return
205+
error_msg = f'Failed to {action} monitoring: Service call timed out'
206+
self.node.get_logger().error(error_msg)
207+
return False, error_msg
208208

209209
response = future.result()
210210

211-
with self.data_lock:
212-
if not response.success:
213-
action = 'start' if request.add_topic else 'stop'
214-
self.node.get_logger().error(
215-
f'Failed to {action} monitoring: {response.message}')
216-
return
211+
if not response.success:
212+
error_msg = f'Failed to {action} monitoring: {response.message}'
213+
self.node.get_logger().error(error_msg)
214+
return False, error_msg
217215

216+
with self.data_lock:
218217
if not request.add_topic and topic_name in self.ui_diagnostics:
219218
del self.ui_diagnostics[topic_name]
220219
if topic_name in self.expected_frequencies:
221220
del self.expected_frequencies[topic_name]
222221

222+
return True, f'Successfully {"started" if request.add_topic else "stopped"} monitoring'
223+
223224
except Exception as e:
224-
action = 'start' if request.add_topic else 'stop'
225-
self.node.get_logger().error(f'Failed to {action} monitoring: {e}')
225+
error_msg = f'Failed to {action} monitoring: {e}'
226+
self.node.get_logger().error(error_msg)
227+
return False, error_msg
226228

227229
def set_expected_frequency(self,
228230
topic_name: str,

0 commit comments

Comments
 (0)