Skip to content

Commit c2a4427

Browse files
author
Luca Toniolo
committed
halscope: add configurable sample memory and simplify UI
- Add GUI control for sample count in acquire dialog with config file persistence (SAMPLES command read before scope_rt loads) - Always enable all 16 channels - remove confusing record length radio buttons that forced tradeoff between channels and samples - Initialize sample_len and rec_len in init_horiz() so sampling works immediately without opening acquire dialog - Add bounds checking for num_samples (min 1000, max 1000000) - Increase default window size to 1050x550 for better channel display - Show restart message when sample count changed (requires reload)
1 parent 9c21e1b commit c2a4427

7 files changed

Lines changed: 159 additions & 161 deletions

File tree

src/hal/utils/scope.c

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,28 @@ static void exit_on_signal(int signum) {
9999
exit_from_hal();
100100
exit(1);
101101
}
102+
103+
/* Read just the SAMPLES value from config file before loading scope_rt */
104+
static int read_samples_from_config(const char *filename)
105+
{
106+
FILE *fp;
107+
char buf[100];
108+
int samples = 0;
109+
110+
fp = fopen(filename, "r");
111+
if (fp == NULL) {
112+
return 0; /* file doesn't exist, use default */
113+
}
114+
while (fgets(buf, sizeof(buf), fp) != NULL) {
115+
if (strncasecmp(buf, "SAMPLES ", 8) == 0) {
116+
samples = atoi(buf + 8);
117+
break;
118+
}
119+
}
120+
fclose(fp);
121+
return samples;
122+
}
123+
102124
/***********************************************************************
103125
* MAIN() FUNCTION *
104126
************************************************************************/
@@ -141,9 +163,30 @@ int main(int argc, gchar * argv[])
141163
break;
142164
}
143165
}
144-
if(argc > optind) num_samples = atoi(argv[argc-1]);
166+
/* first try to read samples from config file */
167+
num_samples = read_samples_from_config(ifilename);
168+
/* command line num_samples overrides config file, but only if it's a valid number */
169+
if(argc > optind) {
170+
int cmdline_samples = atoi(argv[optind]);
171+
if(cmdline_samples > 0) {
172+
num_samples = cmdline_samples;
173+
}
174+
}
175+
/* apply defaults and bounds */
145176
if(num_samples <= 0)
146177
num_samples = SCOPE_NUM_SAMPLES_DEFAULT;
178+
if(num_samples < SCOPE_NUM_SAMPLES_MIN) {
179+
rtapi_print_msg(RTAPI_MSG_WARN,
180+
"SCOPE: num_samples %d too small, using %d\n",
181+
num_samples, SCOPE_NUM_SAMPLES_MIN);
182+
num_samples = SCOPE_NUM_SAMPLES_MIN;
183+
}
184+
if(num_samples > SCOPE_NUM_SAMPLES_MAX) {
185+
rtapi_print_msg(RTAPI_MSG_WARN,
186+
"SCOPE: num_samples %d too large, using %d\n",
187+
num_samples, SCOPE_NUM_SAMPLES_MAX);
188+
num_samples = SCOPE_NUM_SAMPLES_MAX;
189+
}
147190

148191
/* connect to the HAL */
149192
comp_id = hal_init("halscope");
@@ -161,6 +204,10 @@ int main(int argc, gchar * argv[])
161204
hal_exit(comp_id);
162205
exit(1);
163206
}
207+
} else {
208+
/* scope_rt already loaded - we'll check if sample count matches later */
209+
rtapi_print_msg(RTAPI_MSG_DBG,
210+
"SCOPE: scope_rt already loaded, requested %d samples\n", num_samples);
164211
}
165212
/* set up a shared memory region for the scope data */
166213
shm_id = rtapi_shmem_new(SCOPE_SHM_KEY, comp_id, sizeof(scope_shm_control_t));
@@ -191,6 +238,16 @@ int main(int argc, gchar * argv[])
191238
ctrl_usr = &ctrl_struct;
192239
init_usr_control_struct(shm_base);
193240

241+
/* check if loaded scope_rt has different sample count than requested */
242+
if (ctrl_shm->buf_len != num_samples) {
243+
rtapi_print_msg(RTAPI_MSG_WARN,
244+
"SCOPE: scope_rt was loaded with %d samples, but config requested %d.\n"
245+
"To change sample count, unload scope_rt first or restart LinuxCNC.\n",
246+
ctrl_shm->buf_len, num_samples);
247+
}
248+
/* store requested samples for saving to config */
249+
ctrl_usr->horiz.requested_samples = num_samples;
250+
194251
/* init watchdog */
195252
ctrl_shm->watchdog = 10;
196253
/* set main window */
@@ -626,9 +683,9 @@ static void define_scope_windows(void)
626683
{
627684
GtkWidget *vbox, *hbox, *vboxtop, *vboxbottom, *vboxleft, *vboxright, *hboxright;
628685

629-
/* create main window, set its minimum size and title */
686+
/* create main window, set its default size and title */
630687
ctrl_usr->main_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
631-
gtk_widget_set_size_request(GTK_WIDGET(ctrl_usr->main_win), 650, 400);
688+
gtk_window_set_default_size(GTK_WINDOW(ctrl_usr->main_win), 1050, 550);
632689
gtk_window_set_title(GTK_WINDOW(ctrl_usr->main_win), _("HAL Oscilloscope"));
633690

634691
/* top level - big vbox, menu above, everything else below */

src/hal/utils/scope_files.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,11 @@ static char *rmode_cmd(void * arg);
144144
* LOCAL VARIABLES *
145145
************************************************************************/
146146

147-
static const cmd_lut_entry_t cmd_lut[25] =
147+
static char *samples_cmd(void * arg);
148+
149+
static const cmd_lut_entry_t cmd_lut[26] =
148150
{
151+
{ "samples", INT, samples_cmd },
149152
{ "thread", STRING, thread_cmd },
150153
{ "maxchan", INT, maxchan_cmd },
151154
{ "hmult", INT, hmult_cmd },
@@ -453,13 +456,19 @@ static char *thread_cmd(void * arg)
453456

454457
static char *maxchan_cmd(void * arg)
455458
{
456-
int *argp, rv;
459+
/* maxchan is now ignored - we always use 16 channels */
460+
/* kept for backwards compatibility with old config files */
461+
(void)arg;
462+
return NULL;
463+
}
457464

465+
static char *samples_cmd(void * arg)
466+
{
467+
int *argp;
468+
/* SAMPLES is handled early in main() before scope_rt is loaded */
469+
/* Here we just store it in requested_samples so it gets saved back */
458470
argp = (int *)(arg);
459-
rv = set_rec_len(*argp);
460-
if ( rv < 0 ) {
461-
return "could not set record length";
462-
}
471+
ctrl_usr->horiz.requested_samples = *argp;
463472
return NULL;
464473
}
465474

src/hal/utils/scope_horiz.c

Lines changed: 66 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ static void deactivate_sample_thread(void);
8686
static void mult_changed(GtkAdjustment * adj, gpointer gdata);
8787
static void zoom_changed(GtkAdjustment * adj, gpointer gdata);
8888
static void pos_changed(GtkAdjustment * adj, gpointer gdata);
89-
static void rec_len_button(GtkWidget * widget, gpointer gdata);
9089

9190
static void calc_horiz_scaling(void);
9291

@@ -113,6 +112,10 @@ void init_horiz(void)
113112
{
114113
/* stop sampling */
115114
ctrl_shm->state = IDLE;
115+
/* always use 16 channels - initialize sample_len and rec_len
116+
so sampling works without opening the acquire dialog */
117+
ctrl_shm->sample_len = 16;
118+
ctrl_shm->rec_len = ctrl_shm->buf_len / 16;
116119
/* init non-zero members of the horizontal structure */
117120
/* set up the window */
118121
init_horiz_window();
@@ -310,10 +313,15 @@ void refresh_state_info(void)
310313
void write_horiz_config(FILE *fp)
311314
{
312315
scope_horiz_t *horiz;
316+
int samples_to_save;
313317

314318
horiz = &(ctrl_usr->horiz);
319+
/* SAMPLES must be first - it's read early before scope_rt loads */
320+
/* save requested_samples if set, otherwise current buf_len */
321+
samples_to_save = (horiz->requested_samples > 0) ?
322+
horiz->requested_samples : ctrl_shm->buf_len;
323+
fprintf(fp, "SAMPLES %d\n", samples_to_save);
315324
fprintf(fp, "THREAD %s\n", horiz->thread_name);
316-
fprintf(fp, "MAXCHAN %d\n", ctrl_shm->sample_len);
317325
fprintf(fp, "HMULT %d\n", ctrl_shm->mult);
318326
fprintf(fp, "HZOOM %d\n", horiz->zoom_setting);
319327
fprintf(fp, "HPOS %e\n", horiz->pos_setting);
@@ -340,33 +348,11 @@ int set_sample_thread(char *name)
340348

341349
int set_rec_len(int setting)
342350
{
343-
int count, n;
344-
345-
switch ( setting ) {
346-
case 1:
347-
case 2:
348-
case 4:
349-
case 8:
350-
case 16:
351-
/* acceptable value */
352-
break;
353-
default:
354-
/* bad value */
355-
return -1;
356-
}
357-
/* count enabled channels */
358-
count = 0;
359-
for (n = 0; n < 16; n++) {
360-
if (ctrl_usr->vert.chan_enabled[n]) {
361-
count++;
362-
}
363-
}
364-
if (count > setting) {
365-
/* too many channels already enabled */
366-
return -1;
367-
}
368-
ctrl_shm->sample_len = setting;
369-
ctrl_shm->rec_len = ctrl_shm->buf_len / ctrl_shm->sample_len;
351+
/* This function is kept for backwards compatibility */
352+
/* We now always use 16 channels, setting is ignored */
353+
(void)setting;
354+
ctrl_shm->sample_len = 16;
355+
ctrl_shm->rec_len = ctrl_shm->buf_len / 16;
370356
calc_horiz_scaling();
371357
refresh_horiz_info();
372358
return 0;
@@ -507,7 +493,6 @@ static void dialog_realtime_not_linked(void)
507493
GtkWidget *hbox, *label;
508494
GtkWidget *content_area;
509495
GtkWidget *dialog;
510-
GtkWidget *buttons[5];
511496
GtkWidget *scrolled_window;
512497
GtkTreeSelection *selection;
513498

@@ -653,65 +638,31 @@ static void dialog_realtime_not_linked(void)
653638
gtk_box_pack_start(GTK_BOX(GTK_CONTAINER(content_area)),
654639
gtk_separator_new(GTK_ORIENTATION_HORIZONTAL), FALSE, FALSE , 0);
655640

656-
/* box for record length buttons */
657-
label = gtk_label_new(_("Record Length"));
658-
gtk_box_pack_start(GTK_BOX(GTK_CONTAINER(content_area)),
659-
label, TRUE, TRUE, 0);
660-
661-
/* now define the radio buttons */
662-
snprintf(buf, BUFLEN, _("%5d samples (1 channel)"), ctrl_shm->buf_len);
663-
buttons[0] = gtk_radio_button_new_with_label(NULL, buf);
664-
snprintf(buf, BUFLEN, _("%5d samples (2 channels)"), ctrl_shm->buf_len / 2);
665-
buttons[1] =
666-
gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(buttons
667-
[0]), buf);
668-
snprintf(buf, BUFLEN, _("%5d samples (4 channels)"), ctrl_shm->buf_len / 4);
669-
buttons[2] =
670-
gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(buttons
671-
[0]), buf);
672-
snprintf(buf, BUFLEN, _("%5d samples (8 channels)"), ctrl_shm->buf_len / 8);
673-
buttons[3] =
674-
gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(buttons
675-
[0]), buf);
676-
snprintf(buf, BUFLEN, _("%5d samples (16 channels)"),
677-
ctrl_shm->buf_len / 16);
678-
buttons[4] =
679-
gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(buttons
680-
[0]), buf);
681-
/* now put them into the box and make visible */
682-
for (n = 0; n < 5; n++) {
683-
gtk_box_pack_start(GTK_BOX(GTK_CONTAINER(content_area)),
684-
buttons[n], FALSE, FALSE, 0);
685-
}
686-
/* determine which button should be pressed by default */
687-
if (ctrl_shm->sample_len == 1) {
688-
n = 0;
689-
} else if (ctrl_shm->sample_len == 2) {
690-
n = 1;
691-
} else if (ctrl_shm->sample_len == 4) {
692-
n = 2;
693-
} else if (ctrl_shm->sample_len == 8) {
694-
n = 3;
695-
} else if (ctrl_shm->sample_len == 16) {
696-
n = 4;
697-
} else {
698-
n = 2;
699-
ctrl_shm->sample_len = 4;
700-
ctrl_shm->rec_len = ctrl_shm->buf_len / ctrl_shm->sample_len;
641+
/* Samples setting - all 16 channels always available */
642+
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
643+
gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
644+
gtk_label_new_in_box(_("Samples (16 channels):"), hbox, FALSE, FALSE, 0);
645+
/* initialize requested_samples from current if not set */
646+
if (horiz->requested_samples <= 0) {
647+
horiz->requested_samples = ctrl_shm->buf_len;
701648
}
702-
/* set the default button */
703-
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(buttons[n]), TRUE);
704-
/* set up callbacks for the buttons */
705-
g_signal_connect(buttons[0], "clicked",
706-
G_CALLBACK(rec_len_button), (gpointer) 1);
707-
g_signal_connect(buttons[1], "clicked",
708-
G_CALLBACK(rec_len_button), (gpointer) 2);
709-
g_signal_connect(buttons[2], "clicked",
710-
G_CALLBACK(rec_len_button), (gpointer) 4);
711-
g_signal_connect(buttons[3], "clicked",
712-
G_CALLBACK(rec_len_button), (gpointer) 8);
713-
g_signal_connect(buttons[4], "clicked",
714-
G_CALLBACK(rec_len_button), (gpointer) 16);
649+
horiz->samples_adj = gtk_adjustment_new(horiz->requested_samples,
650+
SCOPE_NUM_SAMPLES_MIN, SCOPE_NUM_SAMPLES_MAX, 1000, 10000, 0);
651+
horiz->samples_spinbutton =
652+
gtk_spin_button_new(GTK_ADJUSTMENT(horiz->samples_adj), 1000, 0);
653+
gtk_box_pack_start(GTK_BOX(hbox), horiz->samples_spinbutton, FALSE, TRUE, 0);
654+
gtk_box_pack_start(GTK_BOX(GTK_CONTAINER(content_area)),
655+
hbox, FALSE, TRUE, 0);
656+
/* show current record length info */
657+
snprintf(buf, BUFLEN, _("Current: %d samples (%d per channel)"),
658+
ctrl_shm->buf_len, ctrl_shm->buf_len / 16);
659+
label = gtk_label_new(buf);
660+
gtk_box_pack_start(GTK_BOX(GTK_CONTAINER(content_area)),
661+
label, FALSE, TRUE, 0);
662+
663+
/* always use 16 channels */
664+
ctrl_shm->sample_len = 16;
665+
ctrl_shm->rec_len = ctrl_shm->buf_len / 16;
715666

716667
/* was a thread previously used? */
717668
if (sel_row > -1) {
@@ -721,6 +672,31 @@ static void dialog_realtime_not_linked(void)
721672
gtk_widget_show_all(dialog);
722673

723674
retval = gtk_dialog_run(GTK_DIALOG(dialog));
675+
676+
/* save requested samples before destroying dialog */
677+
if (retval == GTK_RESPONSE_OK) {
678+
int new_samples = gtk_spin_button_get_value_as_int(
679+
GTK_SPIN_BUTTON(horiz->samples_spinbutton));
680+
horiz->requested_samples = new_samples;
681+
if (new_samples != ctrl_shm->buf_len) {
682+
/* samples changed, show restart message */
683+
GtkWidget *info_dialog = gtk_message_dialog_new(
684+
GTK_WINDOW(ctrl_usr->main_win),
685+
GTK_DIALOG_MODAL,
686+
GTK_MESSAGE_INFO,
687+
GTK_BUTTONS_OK,
688+
_("Sample count changed"));
689+
gtk_message_dialog_format_secondary_text(
690+
GTK_MESSAGE_DIALOG(info_dialog),
691+
_("The new sample count (%d) will take effect\n"
692+
"the next time halscope is started.\n\n"
693+
"The setting has been saved to the configuration file."),
694+
new_samples);
695+
gtk_dialog_run(GTK_DIALOG(info_dialog));
696+
gtk_widget_destroy(info_dialog);
697+
}
698+
}
699+
724700
gtk_widget_destroy(dialog);
725701

726702
/* these items no longer exist - NULL them */
@@ -730,6 +706,8 @@ static void dialog_realtime_not_linked(void)
730706
horiz->sample_period_label = NULL;
731707
horiz->mult_adj = NULL;
732708
horiz->mult_spinbutton = NULL;
709+
horiz->samples_adj = NULL;
710+
horiz->samples_spinbutton = NULL;
733711

734712
/* we get here when the user hits OK or Quit */
735713
if (retval == GTK_RESPONSE_CLOSE) {
@@ -963,32 +941,6 @@ static void pos_changed(GtkAdjustment * adj, gpointer gdata)
963941
set_horiz_pos(gtk_adjustment_get_value(adj) / 1000.0);
964942
}
965943

966-
static void rec_len_button(GtkWidget * widget, gpointer gdata)
967-
{
968-
int retval;
969-
GtkWidget *dialog;
970-
971-
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) != TRUE) {
972-
/* not pressed, ignore it */
973-
return;
974-
}
975-
retval = set_rec_len((long)gdata);
976-
if (retval < 0) {
977-
/* too many channels already enabled */
978-
dialog = gtk_message_dialog_new(GTK_WINDOW(ctrl_usr->main_win),
979-
GTK_DIALOG_MODAL,
980-
GTK_MESSAGE_INFO,
981-
GTK_BUTTONS_OK,
982-
_("Not enough channels"));
983-
gtk_message_dialog_format_secondary_text(
984-
GTK_MESSAGE_DIALOG(dialog),
985-
_("This record length cannot handle the channels\n"
986-
"that are currently enabled. Pick a shorter\n"
987-
"record length that supports more channels."));
988-
gtk_dialog_run(GTK_DIALOG(dialog));
989-
gtk_widget_destroy(dialog);
990-
}
991-
}
992944

993945
static void calc_horiz_scaling(void)
994946
{

0 commit comments

Comments
 (0)