#include "config.h"
#include <locale.h>
#include <libintl.h>
#define _(x) gettext(x)
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "rtapi.h"
#include <rtapi_mutex.h>
#include "hal.h"
#include "../hal_priv.h"
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "miscgtk.h"
#include "scope_usr.h"
#define BUFLEN 80
#define VERT_POS_RESOLUTION 100.0
static int ignore_click = 0;
struct offset_data {
char buf[BUFLEN];
int ac_coupled;
};
static void init_chan_sel_window(void);
static void init_chan_info_window(void);
static void init_vert_info_window(void);
static gboolean dialog_select_source(int chan_num);
static void selection_made(GtkWidget * clist, gint row, gint column,
GdkEventButton * event, dialog_generic_t * dptr);
static void change_source_button(GtkWidget * widget, gpointer gdata);
static void channel_off_button(GtkWidget * widget, gpointer gdata);
static void offset_button(GtkWidget * widget, gpointer gdata);
static gboolean dialog_set_offset(int chan_num);
static void scale_changed(GtkAdjustment * adj, gpointer gdata);
static void offset_changed(GtkEditable * editable, struct offset_data *);
static void offset_activated(GtkEditable * editable, gchar * button);
static void pos_changed(GtkAdjustment * adj, gpointer gdata);
static void chan_sel_button(GtkWidget * widget, gpointer gdata);
static void write_chan_config(FILE *fp, scope_chan_t *chan);
void init_vert(void)
{
scope_chan_t *chan;
int n;
ctrl_shm->state = IDLE;
invalidate_all_channels();
for (n = 1; n <= 16; n++) {
chan = &(ctrl_usr->chan[n - 1]);
chan->position = 0.5;
}
init_chan_sel_window();
init_chan_info_window();
init_vert_info_window();
}
int set_active_channel(int chan_num)
{
int n, count;
scope_vert_t *vert;
scope_chan_t *chan;
if (( chan_num < 1 ) || ( chan_num > 16 )) {
return -1;
}
vert = &(ctrl_usr->vert);
chan = &(ctrl_usr->chan[chan_num - 1]);
if (vert->chan_enabled[chan_num - 1] == 0 ) {
if (ctrl_shm->state != IDLE) {
prepare_scope_restart();
}
count = 0;
for (n = 0; n < 16; n++) {
if (vert->chan_enabled[n]) {
count++;
}
}
if (count >= ctrl_shm->sample_len) {
return -2;
}
if (chan->name == NULL) {
return -3;
}
ignore_click = 1;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(vert->chan_sel_buttons[chan_num-1]), TRUE);
vert->chan_enabled[chan_num - 1] = 1;
}
if (vert->selected != chan_num) {
vert->selected = chan_num;
channel_changed();
}
return 0;
}
int set_channel_off(int chan_num)
{
scope_vert_t *vert;
int n;
if ((chan_num < 1) || (chan_num > 16)) {
return -1;
}
vert = &(ctrl_usr->vert);
if ( vert->chan_enabled[chan_num - 1] == 0 ) {
return -1;
}
vert->chan_enabled[chan_num - 1] = 0;
ignore_click = 1;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(vert->
chan_sel_buttons[chan_num - 1]), FALSE);
if ( chan_num == vert->selected ) {
n = 0;
vert->selected = 0;
do {
chan_num++;
if (chan_num > 16) {
chan_num = 1;
}
if (vert->chan_enabled[chan_num - 1] != 0) {
vert->selected = chan_num;
}
} while ((++n < 16) && (vert->selected == 0));
}
channel_changed();
return 0;
}
int set_channel_source(int chan_num, int type, char *name)
{
scope_vert_t *vert;
scope_chan_t *chan;
hal_pin_t *pin;
hal_sig_t *sig;
hal_param_t *param;
vert = &(ctrl_usr->vert);
chan = &(ctrl_usr->chan[chan_num - 1]);
if (type == 0) {
pin = halpr_find_pin_by_name(name);
if (pin == NULL) {
return -1;
}
chan->data_source_type = 0;
chan->data_source = SHMOFF(pin);
chan->data_type = pin->type;
chan->name = pin->name;
} else if (type == 1) {
sig = halpr_find_sig_by_name(name);
if (sig == NULL) {
return -1;
}
chan->data_source_type = 1;
chan->data_source = SHMOFF(sig);
chan->data_type = sig->type;
chan->name = sig->name;
} else if (type == 2) {
param = halpr_find_param_by_name(name);
if (param == NULL) {
return -1;
}
chan->data_source_type = 2;
chan->data_source = SHMOFF(param);
chan->data_type = param->type;
chan->name = param->name;
}
switch (chan->data_type) {
case HAL_BIT:
chan->data_len = sizeof(hal_bit_t);
chan->min_index = -2;
chan->max_index = 2;
break;
case HAL_FLOAT:
chan->data_len = sizeof(hal_float_t);
chan->min_index = -36;
chan->max_index = 36;
break;
case HAL_S32:
chan->data_len = sizeof(hal_s32_t);
chan->min_index = -2;
chan->max_index = 30;
break;
case HAL_U32:
chan->data_len = sizeof(hal_u32_t);
chan->min_index = -2;
chan->max_index = 30;
break;
default:
chan->data_len = 0;
chan->min_index = -1;
chan->max_index = 1;
}
vert->data_offset[chan_num - 1] = -1;
chan->vert_offset = 0.0;
chan->scale_index = 0;
return 0;
}
int set_vert_scale(int setting)
{
scope_vert_t *vert;
scope_chan_t *chan;
GtkAdjustment *adj;
int chan_num, index;
double scale;
gchar buf[BUFLEN];
vert = &(ctrl_usr->vert);
chan_num = vert->selected;
if ((chan_num < 1) || (chan_num > 16)) {
return -1;
}
chan = &(ctrl_usr->chan[chan_num - 1]);
if ((setting > chan->max_index) || (setting < chan->min_index)) {
return -1;
}
chan->scale_index = setting;
adj = GTK_ADJUSTMENT(vert->scale_adj);
gtk_adjustment_set_value(adj, setting);
scale = 1.0;
index = chan->scale_index;
while (index >= 3) {
scale *= 10.0;
index -= 3;
}
while (index <= -3) {
scale *= 0.1;
index += 3;
}
switch (index) {
case 2:
scale *= 5.0;
break;
case 1:
scale *= 2.0;
break;
case -1:
scale *= 0.5;
break;
case -2:
scale *= 0.2;
break;
default:
break;
}
chan->scale = scale;
format_scale_value(buf, BUFLEN - 1, scale);
gtk_label_set_text_if(vert->scale_label, buf);
if (chan_num == ctrl_shm->trig_chan) {
refresh_trigger();
}
request_display_refresh(1);
return 0;
}
int set_vert_pos(double setting)
{
scope_vert_t *vert;
scope_chan_t *chan;
int chan_num;
GtkAdjustment *adj;
if (( setting < 0.0 ) || ( setting > 1.0 )) {
return -1;
}
vert = &(ctrl_usr->vert);
chan_num = vert->selected;
if ((chan_num < 1) || (chan_num > 16)) {
return -1;
}
chan = &(ctrl_usr->chan[chan_num - 1]);
chan->position = setting;
adj = GTK_ADJUSTMENT(vert->pos_adj);
gtk_adjustment_set_value(adj, chan->position * VERT_POS_RESOLUTION);
if (chan_num == ctrl_shm->trig_chan) {
refresh_trigger();
}
request_display_refresh(1);
return 0;
}
int set_vert_offset(double setting, int ac_coupled)
{
scope_vert_t *vert;
scope_chan_t *chan;
int chan_num;
gchar buf1[BUFLEN + 1], buf2[BUFLEN + 1];
vert = &(ctrl_usr->vert);
chan_num = vert->selected;
if ((chan_num < 1) || (chan_num > 16)) {
return -1;
}
chan = &(ctrl_usr->chan[chan_num - 1]);
chan->vert_offset = setting;
chan->ac_offset = ac_coupled;
if (chan->data_type == HAL_BIT) {
snprintf(buf1, BUFLEN, "----");
} else {
if(chan->ac_offset) {
snprintf(buf1, BUFLEN, "(AC)");
} else {
format_signal_value(buf1, BUFLEN, chan->vert_offset);
}
}
snprintf(buf2, BUFLEN, _("Offset\n%s"), buf1);
gtk_label_set_text_if(vert->offset_label, buf2);
if (chan_num == ctrl_shm->trig_chan) {
refresh_trigger();
}
request_display_refresh(1);
return 0;
}
void format_signal_value(char *buf, int buflen, double value)
{
char *units;
int decimals;
char sign, symbols[] = "pnum KMGT";
if (value < 0) {
value = -value;
sign = '-';
} else {
sign = '+';
}
if (value <= 1.0e-24) {
snprintf(buf, buflen, "0.000");
return;
}
if (value <= 1.0e-12) {
snprintf(buf, buflen, "%c%10.3e", sign, value);
return;
}
if (value >= 1.0e+12) {
snprintf(buf, buflen, "%c%10.3e", sign, value);
return;
}
units = &(symbols[4]);
while (value < 1.0) {
value *= 1000.0;
units--;
}
while (value >= 1000.0) {
value /= 1000.0;
units++;
}
decimals = 3;
if (value >= 9.999) {
decimals--;
}
if (value >= 99.99) {
decimals--;
}
snprintf(buf, buflen, "%c%0.*f%c", sign, decimals, value, *units);
}
void write_vert_config(FILE *fp)
{
int n;
scope_vert_t *vert;
scope_chan_t *chan;
vert = &(ctrl_usr->vert);
for ( n = 1 ; n <= 16 ; n++ ) {
if ( vert->chan_enabled[n-1] != 0 ) {
continue;
}
chan = &(ctrl_usr->chan[n-1]);
if ( chan->name == NULL ) {
continue;
}
fprintf(fp, "CHAN %d\n", n);
write_chan_config(fp, chan);
fprintf(fp, "CHOFF\n");
}
for ( n = 1 ; n <= 16 ; n++ ) {
if ( vert->chan_enabled[n-1] == 0 ) {
continue;
}
if ( vert->selected == n ) {
continue;
}
chan = &(ctrl_usr->chan[n-1]);
if ( chan->name == NULL ) {
continue;
}
fprintf(fp, "CHAN %d\n", n);
write_chan_config(fp, chan);
}
if ((vert->selected < 1) || (vert->selected > 16)) {
return;
}
chan = &(ctrl_usr->chan[vert->selected-1]);
fprintf(fp, "CHAN %d\n", vert->selected);
write_chan_config(fp, chan);
}
void set_color(GdkColor *color, unsigned char red,
unsigned char green, unsigned char blue) {
color->red = ((unsigned long) red) << 8;
color->green = ((unsigned long) green) << 8;
color->blue = ((unsigned long) blue) << 8;
color->pixel =
((unsigned long) red) << 16 | ((unsigned long) green) << 8 |
((unsigned long) blue);
}
extern int normal_colors[16][3], selected_colors[16][3];
static void init_chan_sel_window(void)
{
scope_vert_t *vert;
GtkWidget *button;
long n;
gchar buf[5];
GdkColor c;
vert = &(ctrl_usr->vert);
for (n = 0; n < 16; n++) {
snprintf(buf, 4, "%ld", n + 1);
button = gtk_toggle_button_new_with_label(buf);
set_color(&c, normal_colors[n][0],
normal_colors[n][1], normal_colors[n][2]);
gtk_widget_modify_bg(button, GTK_STATE_ACTIVE, &c);
gtk_widget_modify_bg(button, GTK_STATE_SELECTED, &c);
set_color(&c, selected_colors[n][0],
selected_colors[n][1], selected_colors[n][2]);
gtk_widget_modify_bg(button, GTK_STATE_PRELIGHT, &c);
set_color(&c, 0, 0, 0);
gtk_widget_modify_fg(button, GTK_STATE_ACTIVE, &c);
gtk_widget_modify_fg(button, GTK_STATE_SELECTED, &c);
gtk_widget_modify_fg(button, GTK_STATE_PRELIGHT, &c);
gtk_box_pack_start(GTK_BOX(ctrl_usr->chan_sel_win), button, TRUE,
TRUE, 0);
gtk_widget_show(button);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
GTK_SIGNAL_FUNC(chan_sel_button), (gpointer) n + 1);
vert->chan_sel_buttons[n] = button;
}
}
static void init_chan_info_window(void)
{
scope_vert_t *vert;
char dummyname[HAL_NAME_LEN+1];
int n;
vert = &(ctrl_usr->vert);
vert->chan_num_label =
gtk_label_new_in_box("--", ctrl_usr->chan_info_win, FALSE, FALSE, 5);
gtk_label_size_to_fit(GTK_LABEL(vert->chan_num_label), "99");
gtk_vseparator_new_in_box(ctrl_usr->chan_info_win, 3);
vert->source_name_button = gtk_button_new_with_label("------");
gtk_box_pack_start(GTK_BOX(ctrl_usr->chan_info_win),
vert->source_name_button, FALSE, FALSE, 3);
vert->source_name_label = (GTK_BIN(vert->source_name_button))->child;
gtk_label_set_justify(GTK_LABEL(vert->source_name_label),
GTK_JUSTIFY_LEFT);
for ( n = 0 ; n < HAL_NAME_LEN ; n++) dummyname[n] = 'x';
dummyname[n] = '\0';
gtk_label_size_to_fit(GTK_LABEL(vert->source_name_label), dummyname);
gtk_signal_connect(GTK_OBJECT(vert->source_name_button), "clicked",
GTK_SIGNAL_FUNC(change_source_button), NULL);
gtk_widget_show(vert->source_name_button);
vert->readout_label = gtk_label_new_in_box("",
ctrl_usr->chan_info_win, FALSE, FALSE, 0);
gtk_misc_set_alignment(GTK_MISC(vert->readout_label), 0, 0);
gtk_label_set_justify(GTK_LABEL(vert->readout_label), GTK_JUSTIFY_LEFT);
gtk_label_size_to_fit(GTK_LABEL(vert->readout_label),
"f(99999.9999) = 99999.9999 (ddt 99999.9999)");
}
static void init_vert_info_window(void)
{
scope_vert_t *vert;
GtkWidget *hbox, *vbox;
GtkWidget *button;
vert = &(ctrl_usr->vert);
hbox =
gtk_hbox_new_in_box(TRUE, 0, 0, ctrl_usr->vert_info_win, TRUE, TRUE,
0);
vbox = gtk_vbox_new_in_box(FALSE, 0, 0, hbox, TRUE, TRUE, 0);
gtk_label_new_in_box(_("Gain"), vbox, FALSE, FALSE, 0);
vert->scale_adj = gtk_adjustment_new(0, -5, 5, 1, 1, 0);
vert->scale_slider = gtk_vscale_new(GTK_ADJUSTMENT(vert->scale_adj));
gtk_scale_set_digits(GTK_SCALE(vert->scale_slider), 0);
gtk_scale_set_draw_value(GTK_SCALE(vert->scale_slider), FALSE);
gtk_box_pack_start(GTK_BOX(vbox), vert->scale_slider, TRUE, TRUE, 0);
gtk_signal_connect(GTK_OBJECT(vert->scale_adj), "value_changed",
GTK_SIGNAL_FUNC(scale_changed), NULL);
gtk_widget_show(vert->scale_slider);
vbox = gtk_vbox_new_in_box(FALSE, 0, 0, hbox, TRUE, TRUE, 0);
gtk_label_new_in_box(_("Pos"), vbox, FALSE, FALSE, 0);
vert->pos_adj =
gtk_adjustment_new(VERT_POS_RESOLUTION / 2, 0, VERT_POS_RESOLUTION, 1,
1, 0);
vert->pos_slider = gtk_vscale_new(GTK_ADJUSTMENT(vert->pos_adj));
gtk_scale_set_digits(GTK_SCALE(vert->pos_slider), 0);
gtk_scale_set_draw_value(GTK_SCALE(vert->pos_slider), FALSE);
gtk_box_pack_start(GTK_BOX(vbox), vert->pos_slider, TRUE, TRUE, 0);
gtk_signal_connect(GTK_OBJECT(vert->pos_adj), "value_changed",
GTK_SIGNAL_FUNC(pos_changed), NULL);
gtk_widget_show(vert->pos_slider);
gtk_hseparator_new_in_box(ctrl_usr->vert_info_win, 3);
gtk_label_new_in_box(_("Scale"), ctrl_usr->vert_info_win, FALSE, FALSE, 0);
vert->scale_label =
gtk_label_new_in_box(" ---- ", ctrl_usr->vert_info_win, FALSE, FALSE,
0);
vert->offset_button = gtk_button_new_with_label(_("Offset\n----"));
vert->offset_label = (GTK_BIN(vert->offset_button))->child;
gtk_box_pack_start(GTK_BOX(ctrl_usr->vert_info_win),
vert->offset_button, FALSE, FALSE, 0);
gtk_signal_connect(GTK_OBJECT(vert->offset_button), "clicked",
GTK_SIGNAL_FUNC(offset_button), NULL);
gtk_widget_show(vert->offset_button);
button = gtk_button_new_with_label(_("Chan Off"));
gtk_box_pack_start(GTK_BOX(ctrl_usr->vert_info_win), button, FALSE, FALSE,
0);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
GTK_SIGNAL_FUNC(channel_off_button), NULL);
gtk_widget_show(button);
}
static void scale_changed(GtkAdjustment * adj, gpointer gdata)
{
set_vert_scale(adj->value);
}
static void pos_changed(GtkAdjustment * adj, gpointer gdata)
{
set_vert_pos(adj->value / VERT_POS_RESOLUTION);
}
static void offset_button(GtkWidget * widget, gpointer gdata)
{
scope_vert_t *vert;
scope_chan_t *chan;
int chan_num;
vert = &(ctrl_usr->vert);
chan_num = vert->selected;
if ((chan_num < 1) || (chan_num > 16)) {
return;
}
chan = &(ctrl_usr->chan[chan_num - 1]);
if (chan->data_type == HAL_BIT) {
return;
}
if (dialog_set_offset(chan_num)) {
if (chan_num == ctrl_shm->trig_chan) {
refresh_trigger();
}
channel_changed();
request_display_refresh(1);
}
}
static gboolean dialog_set_offset(int chan_num)
{
scope_vert_t *vert;
scope_chan_t *chan;
dialog_generic_t dialog;
gchar *title, msg[BUFLEN], *cptr;
struct offset_data data;
GtkWidget *label, *button;
double tmp;
vert = &(ctrl_usr->vert);
chan = &(ctrl_usr->chan[chan_num - 1]);
title = _("Set Offset");
snprintf(msg, BUFLEN - 1, _("Set the vertical offset\n"
"for channel %d."), chan_num);
dialog.retval = 0;
dialog.window = gtk_dialog_new();
dialog.app_data = &data;
gtk_window_set_policy(GTK_WINDOW(dialog.window), FALSE, TRUE, FALSE);
gtk_window_set_position(GTK_WINDOW(dialog.window), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(dialog.window), title);
label = gtk_label_new(msg);
gtk_misc_set_padding(GTK_MISC(label), 15, 5);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog.window)->vbox), label, FALSE,
TRUE, 0);
gtk_hseparator_new_in_box(GTK_DIALOG(dialog.window)->vbox, 0);
vert->offset_ac = gtk_check_button_new_with_label(_("AC Coupled"));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog.window)->vbox),
vert->offset_ac, FALSE, TRUE, 0);
gtk_signal_connect(GTK_OBJECT(vert->offset_ac), "toggled",
GTK_SIGNAL_FUNC(offset_changed), &data);
vert->offset_entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog.window)->vbox),
vert->offset_entry, FALSE, TRUE, 0);
snprintf(data.buf, BUFLEN, "%f", chan->vert_offset);
gtk_entry_set_text(GTK_ENTRY(vert->offset_entry), data.buf);
gtk_entry_set_max_length(GTK_ENTRY(vert->offset_entry), BUFLEN-1);
gtk_entry_set_position(GTK_ENTRY(vert->offset_entry), 0);
gtk_entry_select_region(GTK_ENTRY(vert->offset_entry), 0, strlen(data.buf));
gtk_widget_grab_focus(GTK_WIDGET(vert->offset_entry));
gtk_widget_show(vert->offset_entry);
gtk_signal_connect(GTK_OBJECT(vert->offset_entry), "changed",
GTK_SIGNAL_FUNC(offset_changed), data.buf);
gtk_signal_connect(GTK_OBJECT(dialog.window), "destroy",
GTK_SIGNAL_FUNC(dialog_generic_destroyed), &dialog);
button = gtk_button_new_with_label(_("OK"));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog.window)->action_area),
button, TRUE, TRUE, 4);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
GTK_SIGNAL_FUNC(dialog_generic_button1), &dialog);
gtk_signal_connect(GTK_OBJECT(vert->offset_entry), "activate",
GTK_SIGNAL_FUNC(offset_activated), button);
button = gtk_button_new_with_label(_("Cancel"));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog.window)->action_area),
button, TRUE, TRUE, 4);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
GTK_SIGNAL_FUNC(dialog_generic_button2), &dialog);
gtk_window_set_transient_for(GTK_WINDOW(dialog.window),
GTK_WINDOW(ctrl_usr->main_win));
gtk_window_set_modal(GTK_WINDOW(dialog.window), TRUE);
gtk_widget_show_all(dialog.window);
gtk_main();
if ((dialog.retval == 0) || (dialog.retval == 2)) {
return FALSE;
}
tmp = strtod(data.buf, &cptr);
if (cptr == data.buf) {
return FALSE;
}
set_vert_offset(tmp, data.ac_coupled);
return TRUE;
}
static void offset_changed(GtkEditable * editable, struct offset_data *data)
{
const char *text;
data->ac_coupled =
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ctrl_usr->vert.offset_ac));
gtk_entry_set_editable(GTK_ENTRY(ctrl_usr->vert.offset_entry),
!data->ac_coupled);
text = gtk_entry_get_text(GTK_ENTRY(ctrl_usr->vert.offset_entry));
strncpy(data->buf, text, BUFLEN);
}
static void offset_activated(GtkEditable * editable, gchar * button)
{
gtk_button_clicked(GTK_BUTTON(button));
}
static void chan_sel_button(GtkWidget * widget, gpointer gdata)
{
long chan_num;
int n, count;
scope_vert_t *vert;
scope_chan_t *chan;
char *title, *msg;
vert = &(ctrl_usr->vert);
chan_num = (long) gdata;
chan = &(ctrl_usr->chan[chan_num - 1]);
if (ignore_click != 0) {
ignore_click = 0;
return;
}
if (vert->chan_enabled[chan_num - 1] == 0 ) {
if (ctrl_shm->state != IDLE) {
prepare_scope_restart();
}
count = 0;
for (n = 0; n < 16; n++) {
if (vert->chan_enabled[n]) {
count++;
}
}
if (count >= ctrl_shm->sample_len) {
ignore_click = 1;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE);
title = _("Too many channels");
msg = _("You cannot add another channel.\n\n"
"Either turn off one or more channels, or shorten\n"
"the record length to allow for more channels");
dialog_generic_msg(ctrl_usr->main_win, title, msg, _("OK"), NULL,
NULL, NULL);
return;
}
if (chan->name == NULL) {
if (dialog_select_source(chan_num) != TRUE) {
ignore_click = 1;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
FALSE);
return;
}
}
vert->chan_enabled[chan_num - 1] = 1;
} else {
ignore_click = 1;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
}
if (vert->selected != chan_num) {
vert->selected = chan_num;
channel_changed();
}
}
static void channel_off_button(GtkWidget * widget, gpointer gdata)
{
scope_vert_t *vert;
int chan_num;
vert = &(ctrl_usr->vert);
chan_num = vert->selected;
set_channel_off(chan_num);
}
static void change_source_button(GtkWidget * widget, gpointer gdata)
{
int chan_num;
chan_num = ctrl_usr->vert.selected;
if ((chan_num < 1) || (chan_num > 16)) {
return;
}
if (ctrl_shm->state != IDLE) {
prepare_scope_restart();
}
invalidate_channel(chan_num);
dialog_select_source(chan_num);
channel_changed();
}
static char search_target[HAL_NAME_LEN+1];
static guint32 search_time = 0;
static int search_row = -1;
#define SEARCH_RESET_TIME 1000
static void selection_made_common(GtkWidget *clist, gint row, dialog_generic_t *dptr) {
gint n, listnum;
gchar *name;
int rv, chan_num;
scope_vert_t *vert;
vert = &(ctrl_usr->vert);
chan_num = *((int *)(dptr->app_data));
listnum = -1;
for (n = 0; n < 3; n++) {
if (clist == vert->lists[n]) {
listnum = n;
}
}
gtk_clist_get_text(GTK_CLIST(clist), row, 0, &name);
rv = set_channel_source(chan_num, listnum, name);
if ( rv == 0 ) {
dptr->retval = 1;
} else {
dptr->retval = 2;
}
gtk_widget_destroy(dptr->window);
return;
}
static gboolean search_for_entry(GtkWidget *widget, GdkEventKey *event, dialog_generic_t *dptr)
{
GtkCList *clist = GTK_CLIST(widget);
int z, wrapped;
if(event->keyval == GDK_Return) {
selection_made_common(widget, clist->focus_row, dptr);
}
if(!isprint(event->string[0])) {
strcpy(search_target, "");
search_row = clist->focus_row;
return 0;
}
if(event->time - search_time > SEARCH_RESET_TIME) {
strcpy(search_target, "");
search_row = clist->focus_row;
}
search_time = event->time;
if(strcmp(event->string, " ") == 0) {
char *text;
search_row = search_row + 1;
if(!gtk_clist_get_text(clist, search_row, 0, &text))
search_row = 0;
printf(_("next search: %d\n"), search_row);
} else {
strcat(search_target, event->string);
}
for(z = search_row, wrapped=0; z != search_row || !wrapped; z ++) {
char *text;
printf(_("search: %d (wrapped=%d)\n"), z, wrapped);
if(!gtk_clist_get_text(clist, z, 0, &text)) {
if(wrapped) break; z = 0;
wrapped = 1;
}
if(strstr(text, search_target)) {
double pos = (z+.5) / (clist->rows-1);
if(pos > 1) pos = 1;
GTK_CLIST_GET_CLASS(clist)->scroll_vertical(clist, GTK_SCROLL_JUMP, pos);
gtk_clist_select_row(clist, z, 0);
search_row = z;
return 1;
}
}
return 0;
}
static gboolean change_page(GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer user_data) {
scope_vert_t *vert;
vert = &(ctrl_usr->vert);
if(page_num < 3)
gtk_widget_grab_focus(GTK_WIDGET(vert->lists[page_num]));
return 0;
}
static gboolean dialog_select_source(int chan_num)
{
scope_vert_t *vert;
scope_chan_t *chan;
dialog_generic_t dialog;
gchar *title, msg[BUFLEN];
int next, n, initial_page, row, initial_row, max_row;
gchar *tab_label_text[3], *name;
GtkWidget *hbox, *label, *notebk, *button;
GtkAdjustment *adj;
hal_pin_t *pin;
hal_sig_t *sig;
hal_param_t *param;
vert = &(ctrl_usr->vert);
chan = &(ctrl_usr->chan[chan_num - 1]);
title = _("Select Channel Source");
snprintf(msg, BUFLEN - 1, _("Select a pin, signal, or parameter\n"
"as the source for channel %d."), chan_num);
dialog.retval = 0;
dialog.window = gtk_dialog_new();
dialog.app_data = &chan_num;
gtk_widget_set_usize(GTK_WIDGET(dialog.window), -2, 300);
gtk_window_set_policy(GTK_WINDOW(dialog.window), FALSE, TRUE, FALSE);
gtk_window_set_position(GTK_WINDOW(dialog.window), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(dialog.window), title);
label = gtk_label_new(msg);
gtk_misc_set_padding(GTK_MISC(label), 15, 5);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog.window)->vbox), label, FALSE,
TRUE, 0);
gtk_hseparator_new_in_box(GTK_DIALOG(dialog.window)->vbox, 0);
notebk = gtk_notebook_new();
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog.window)->vbox), notebk, TRUE,
TRUE, 0);
gtk_notebook_set_homogeneous_tabs(GTK_NOTEBOOK(notebk), TRUE);
gtk_signal_connect(GTK_OBJECT(notebk), "switch-page", GTK_SIGNAL_FUNC(change_page), &dialog);
tab_label_text[0] = _("Pins");
tab_label_text[1] = _("Signals");
tab_label_text[2] = _("Parameters");
for (n = 0; n < 3; n++) {
vert->windows[n] = gtk_scrolled_window_new(NULL, NULL);
vert->adjs[n] = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(vert->windows[n]));
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vert->windows[n]),
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
gtk_widget_show(vert->windows[n]);
vert->lists[n] = gtk_clist_new(1);
gtk_signal_connect(GTK_OBJECT(vert->lists[n]), "select_row",
GTK_SIGNAL_FUNC(selection_made), &dialog);
gtk_signal_connect(GTK_OBJECT(vert->lists[n]), "key-press-event",
GTK_SIGNAL_FUNC(search_for_entry), &dialog);
gtk_clist_set_shadow_type(GTK_CLIST(vert->lists[n]), GTK_SHADOW_OUT);
gtk_clist_set_selection_mode(GTK_CLIST(vert->lists[n]),
GTK_SELECTION_BROWSE);
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW
(vert->windows[n]), vert->lists[n]);
gtk_widget_show(vert->lists[n]);
hbox = gtk_hbox_new(TRUE, 0);
gtk_label_new_in_box(tab_label_text[n], hbox, TRUE, TRUE, 0);
gtk_widget_show(hbox);
gtk_notebook_append_page(GTK_NOTEBOOK(notebk), vert->windows[n], hbox);
gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(notebk), hbox,
TRUE, TRUE, GTK_PACK_START);
}
if (( chan->data_source_type >= 0 ) && ( chan->data_source_type <= 2 )) {
initial_page = chan->data_source_type;
gtk_notebook_set_page(GTK_NOTEBOOK(notebk), initial_page);
} else {
initial_page = -1;
gtk_notebook_set_page(GTK_NOTEBOOK(notebk), 0);
}
gtk_widget_show(notebk);
gtk_clist_clear(GTK_CLIST(vert->lists[0]));
gtk_clist_clear(GTK_CLIST(vert->lists[1]));
gtk_clist_clear(GTK_CLIST(vert->lists[2]));
rtapi_mutex_get(&(hal_data->mutex));
next = hal_data->pin_list_ptr;
initial_row = -1;
max_row = -1;
while (next != 0) {
pin = SHMPTR(next);
name = pin->name;
row = gtk_clist_append(GTK_CLIST(vert->lists[0]), &name);
if ( initial_page == 0 ) {
if ( strcmp(name, chan->name) == 0 ) {
initial_row = row;
}
max_row = row;
}
next = pin->next_ptr;
}
next = hal_data->sig_list_ptr;
while (next != 0) {
sig = SHMPTR(next);
name = sig->name;
row = gtk_clist_append(GTK_CLIST(vert->lists[1]), &name);
if ( initial_page == 1 ) {
if ( strcmp(name, chan->name) == 0 ) {
initial_row = row;
}
max_row = row;
}
next = sig->next_ptr;
}
next = hal_data->param_list_ptr;
while (next != 0) {
param = SHMPTR(next);
name = param->name;
row = gtk_clist_append(GTK_CLIST(vert->lists[2]), &name);
if ( initial_page == 2 ) {
if ( strcmp(name, chan->name) == 0 ) {
initial_row = row;
}
max_row = row;
}
next = param->next_ptr;
}
rtapi_mutex_give(&(hal_data->mutex));
if ( initial_row >= 0 ) {
gtk_clist_select_row(GTK_CLIST(vert->lists[initial_page]), initial_row, -1);
adj = vert->adjs[initial_page];
adj->value = adj->lower + (adj->upper - adj->lower)*((double)(initial_row)/(double)(max_row+1));
gtk_adjustment_value_changed(vert->adjs[initial_page]);
}
gtk_signal_connect(GTK_OBJECT(dialog.window), "destroy",
GTK_SIGNAL_FUNC(dialog_generic_destroyed), &dialog);
button = gtk_button_new_with_label(_("Cancel"));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog.window)->action_area),
button, TRUE, TRUE, 4);
gtk_signal_connect(GTK_OBJECT(button), "clicked",
GTK_SIGNAL_FUNC(dialog_generic_button2), &dialog);
gtk_window_set_transient_for(GTK_WINDOW(dialog.window),
GTK_WINDOW(ctrl_usr->main_win));
gtk_window_set_modal(GTK_WINDOW(dialog.window), TRUE);
gtk_widget_show_all(dialog.window);
gtk_main();
vert->lists[0] = NULL;
vert->lists[1] = NULL;
vert->lists[2] = NULL;
if ((dialog.retval == 0) || (dialog.retval == 2)) {
return FALSE;
}
channel_changed();
return TRUE;
}
static void selection_made(GtkWidget * clist, gint row, gint column,
GdkEventButton * event, dialog_generic_t * dptr)
{
GdkEventType type;
if ((event == NULL) || (clist == NULL)) {
return;
}
type = event->type;
if (type != 4) {
return;
}
selection_made_common(clist, row, dptr);
}
void channel_changed(void)
{
scope_vert_t *vert;
scope_chan_t *chan;
GtkAdjustment *adj;
gchar *name;
gchar buf1[BUFLEN + 1], buf2[BUFLEN + 1];
vert = &(ctrl_usr->vert);
if ((vert->selected < 1) || (vert->selected > 16)) {
gtk_label_set_text_if(vert->scale_label, "----");
gtk_label_set_text_if(vert->chan_num_label, "--");
gtk_label_set_text_if(vert->source_name_label, "------");
request_display_refresh(1);
return;
}
chan = &(ctrl_usr->chan[vert->selected - 1]);
gtk_adjustment_set_value(GTK_ADJUSTMENT(vert->pos_adj),
chan->position * VERT_POS_RESOLUTION);
adj = GTK_ADJUSTMENT(vert->scale_adj);
adj->lower = chan->min_index;
adj->upper = chan->max_index;
adj->value = chan->scale_index;
gtk_adjustment_changed(adj);
gtk_adjustment_value_changed(adj);
snprintf(buf1, BUFLEN, "%2d", vert->selected);
name = chan->name;
gtk_label_set_text_if(vert->chan_num_label, buf1);
gtk_label_set_text_if(vert->source_name_label, name);
if (chan->data_type == HAL_BIT) {
snprintf(buf1, BUFLEN, "----");
} else {
if(chan->ac_offset) {
snprintf(buf1, BUFLEN, "(AC)");
} else {
format_signal_value(buf1, BUFLEN, chan->vert_offset);
}
}
snprintf(buf2, BUFLEN, _("Offset\n%s"), buf1);
gtk_label_set_text_if(vert->offset_label, buf2);
request_display_refresh(1);
}
void format_scale_value(char *buf, int buflen, double value)
{
char *units;
char symbols[] = "pnum KMGT";
if (value < 0.9e-12) {
snprintf(buf, buflen, "tiny");
return;
}
if (value > 1.1e+12) {
snprintf(buf, buflen, "huge");
return;
}
units = &(symbols[4]);
while (value < 1.0) {
value *= 1000.0;
units--;
}
while (value >= 999.99) {
value *= 0.001;
units++;
}
snprintf(buf, buflen, "%0.0f%c/div", value, *units);
}
static void write_chan_config(FILE *fp, scope_chan_t *chan)
{
if ( chan->data_source_type == 0 ) {
fprintf(fp, "PIN %s\n", chan->name);
} else if ( chan->data_source_type == 1 ) {
fprintf(fp, "SIG %s\n", chan->name);
} else if ( chan->data_source_type == 2 ) {
fprintf(fp, "PARAM %s\n", chan->name);
} else {
return;
}
fprintf(fp, "VSCALE %d\n", chan->scale_index);
fprintf(fp, "VPOS %f\n", chan->position);
if(chan->ac_offset) {
fprintf(fp, "VAC %e\n", chan->vert_offset);
} else {
fprintf(fp, "VOFF %e\n", chan->vert_offset);
}
}