diff options
author | Xiao Pan <xyz@flylightning.xyz> | 2025-04-06 17:27:44 -0700 |
---|---|---|
committer | Xiao Pan <xyz@flylightning.xyz> | 2025-04-06 17:27:44 -0700 |
commit | a4ec4b272b2eae527f68cbd40488a7805dc5367b (patch) | |
tree | 8c11a53a80b559c5d7941d1ed3d32d2179442dcb | |
parent | 9e28e186b4877efa70d2a78b6d7ff7134debdc53 (diff) |
Integrate with gtk
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | remote_plot.c | 385 | ||||
-rw-r--r-- | remote_plot_no_gtk.c | 329 |
3 files changed, 574 insertions, 142 deletions
@@ -2,5 +2,5 @@ work in progress build ``` -cc -Wall $(pkg-config --cflags --libs libssh --libs plplot) -lm -o remote_plot remote_plot.c +cc -Wall $(pkg-config --cflags --libs libssh plplot gtk4) -lm -o remote_plot remote_plot.c ``` diff --git a/remote_plot.c b/remote_plot.c index b1cb2a6..8f89e62 100644 --- a/remote_plot.c +++ b/remote_plot.c @@ -2,6 +2,7 @@ // https://api.libssh.org/stable/libssh_tutorial.html // https://api.libssh.org/stable/libssh_tutor_guided_tour.html // plplot example 17 +// plplot example ext-cairo-test.c #include <libssh/libssh.h> #include <stdlib.h> @@ -22,6 +23,8 @@ #include <time.h> #include <unistd.h> +#include <gtk/gtk.h> + // very small also works, just transfter delays, I test accelerometer data is // like 15782 which is 7 bytes consider newline and \0? #define MAX_XFER_BUF_SIZE 7 @@ -30,143 +33,78 @@ static PLINT pl_errcode; static char errmsg[160]; -int sftp_read_sync(ssh_session session, sftp_session sftp) +typedef struct { + ssh_session session; + sftp_session sftp; + PLINT id1; + PLFLT t[10]; + PLFLT buffer[10]; + GtkWidget *area; +}DATA; + +static gboolean sftp_read_sync(gpointer user_data) + //int sftp_read_sync(ssh_session session, sftp_session sftp) { + //printf("sftp_read_sync begin\n"); + DATA *data=user_data; + int access_type; sftp_file file; char buffer[MAX_XFER_BUF_SIZE]; int nbytes, rc; access_type = O_RDONLY; - PLINT id1, autoy, acc; - PLFLT ymin, ymax, xlab, ylab; - PLFLT t, tmin, tmax, tjump; - PLINT colbox, collab, colline[4], styline[4]; - PLCHAR_VECTOR legline[4]; - - // If db is used the plot is much more smooth. However, because of the - // async X behaviour, one does not have a real-time scripcharter. - // This is now disabled since it does not significantly improve the - // performance on new machines and makes it difficult to use this - // example non-interactively since it requires an extra pleop call after - // each call to plstripa. - // - //plsetopt("db", ""); - //plsetopt("np", ""); - - // User sets up plot completely except for window and data - // Eventually settings in place when strip chart is created will be - // remembered so that multiple strip charts can be used simultaneously. - // - - // Specify some reasonable defaults for ymin and ymax - // The plot will grow automatically if needed (but not shrink) - - ymin = -0.1; - ymax = 0.1; - - // Specify initial tmin and tmax -- this determines length of window. - // Also specify maximum jump in t - // This can accomodate adaptive timesteps - - tmin = 0.; - tmax = 10.; - tjump = 0.3; // percentage of plot to jump - - // Axes options same as plbox. - // Only automatic tick generation and label placement allowed - // Eventually I'll make this fancier - - colbox = 1; - collab = 3; - styline[0] = colline[0] = 2; // pens color and line style - styline[1] = colline[1] = 3; - styline[2] = colline[2] = 4; - styline[3] = colline[3] = 5; - - legline[0] = "in_accel_z_raw"; // pens legend - legline[1] = "not_used"; - legline[2] = "not_used"; - legline[3] = "not_used"; - - xlab = 0.; ylab = 0.25; // legend position - - autoy = 1; // autoscale y - acc = 1; // don't scrip, accumulate - - // Initialize plplot - - plinit(); - - pladv( 0 ); - plvsta(); - - // Register our error variables with PLplot - // From here on, we're handling all errors here - - plsError( &pl_errcode, errmsg ); - - plstripc( &id1, "bcnst", "bcnstv", - tmin, tmax, tjump, ymin, ymax, - xlab, ylab, - autoy, acc, - colbox, collab, - colline, styline, legline, - "t", "", "Strip chart demo" ); - - if ( pl_errcode ) - { - fprintf( stderr, "%s\n", errmsg ); - exit( 1 ); - } - - // Let plplot handle errors from here on - - plsError( NULL, NULL ); - - autoy = 0; // autoscale y - acc = 1; // accumulate - // This is to represent a loop over time // Let's try a random walk process - for (t=0;;t++) { - file = sftp_open(sftp, "/sys/bus/iio/devices/iio:device2/in_accel_z_raw", - access_type, 0); - if (file == NULL) { - fprintf(stderr, "Can't open file for reading: %s\n", - ssh_get_error(session)); + file = sftp_open(data->sftp, "/sys/bus/iio/devices/iio:device2/in_accel_z_raw", + access_type, 0); + if (file == NULL) { + fprintf(stderr, "Can't open file for reading: %s\n", + ssh_get_error(data->session)); + return SSH_ERROR; + } + + for(int i=0;i<9;i++) + data->buffer[i]=data->buffer[i+1]; + + for (;;) { + nbytes = sftp_read(file, buffer, sizeof(buffer)); + if (nbytes == 0) { + break; // EOF + } else if (nbytes < 0) { + fprintf(stderr, "Error while reading file: %s\n", + ssh_get_error(data->session)); + sftp_close(file); return SSH_ERROR; } - for (;;) { - nbytes = sftp_read(file, buffer, sizeof(buffer)); - if (nbytes == 0) { - break; // EOF - } else if (nbytes < 0) { - fprintf(stderr, "Error while reading file: %s\n", - ssh_get_error(session)); - sftp_close(file); - return SSH_ERROR; - } - - //printf("%s",buffer); - //printf("%d\n",atoi(buffer)); - plstripa( id1, 0, t, atof(buffer)); - } + //printf("buffer %s",buffer); + //printf("buffer int %d\n",atoi(buffer)); + //printf("id1 %d\n",data->id1); + //printf("t %f\n",data->t[9]); + //printf("before sftp_read_sync plstripa\n"); + data->buffer[9]=atof(buffer); + //printf("after sftp_read_sync plstripa\n"); } rc = sftp_close(file); if (rc != SSH_OK) { fprintf(stderr, "Can't close the read file: %s\n", - ssh_get_error(session)); + ssh_get_error(data->session)); return rc; } - plstripd( id1 ); - plend(); + for(int i=0;i<10;i++) + data->t[i]++; + //printf("sftp_read_sync end\n"); - return SSH_OK; + gtk_widget_queue_draw(data->area); + + //return SSH_OK; + // must return G_SOURCE_CONTINUE to keep polling + // return G_SOURCE_REMOVE to stop + return G_SOURCE_CONTINUE; } // https://api.libssh.org/stable/libssh_tutor_guided_tour.html @@ -257,73 +195,238 @@ int verify_knownhost(ssh_session session) return 0; } -int main(void) +static void draw_function (GtkDrawingArea *area, + cairo_t *cr, + int width, + int height, + gpointer user_data) { - ssh_session my_ssh_session; - sftp_session sftp; + //printf("draw begin\n"); + DATA *data=user_data; + + PLINT autoy, acc; + PLFLT ymin, ymax, xlab, ylab; + PLFLT tmin, tmax, tjump; + PLINT colbox, collab, colline[4], styline[4]; + PLCHAR_VECTOR legline[4]; + + // If db is used the plot is much more smooth. However, because of the + // async X behaviour, one does not have a real-time scripcharter. + // This is now disabled since it does not significantly improve the + // performance on new machines and makes it difficult to use this + // example non-interactively since it requires an extra pleop call after + // each call to plstripa. + // + //plsetopt("db", ""); + //plsetopt("np", ""); + + // User sets up plot completely except for window and data + // Eventually settings in place when strip chart is created will be + // remembered so that multiple strip charts can be used simultaneously. + // + + // Specify some reasonable defaults for ymin and ymax + // The plot will grow automatically if needed (but not shrink) + + ymin = -0.1; + ymax = 0.1; + + // Specify initial tmin and tmax -- this determines length of window. + // Also specify maximum jump in t + // This can accomodate adaptive timesteps + + tmin = 0.; + tmax = 10.; + tjump = 0.3; // percentage of plot to jump + + // Axes options same as plbox. + // Only automatic tick generation and label placement allowed + // Eventually I'll make this fancier + + colbox = 1; + collab = 3; + styline[0] = colline[0] = 2; // pens color and line style + styline[1] = colline[1] = 3; + styline[2] = colline[2] = 4; + styline[3] = colline[3] = 5; + + legline[0] = "in_accel_z_raw"; // pens legend + legline[1] = "not_used"; + legline[2] = "not_used"; + legline[3] = "not_used"; + + xlab = 0.; ylab = 0.25; // legend position + + autoy = 1; // autoscale y + acc = 1; // don't scrip, accumulate + + // Initialize plplot + + plsdev( "extcairo" ); + plinit(); + pl_cmd( PLESC_DEVINIT, cr ); + + pladv( 0 ); + plvsta(); + + // Register our error variables with PLplot + // From here on, we're handling all errors here + + plsError( &pl_errcode, errmsg ); + + //plstripc( &(data->id1), "bcnst", "bcnstv", + plstripc( &(data->id1), "bcnst", "bcnstv", + tmin, tmax, tjump, ymin, ymax, + xlab, ylab, + autoy, acc, + colbox, collab, + colline, styline, legline, + "t", "", "Strip chart demo" ); + + if ( pl_errcode ) + { + fprintf( stderr, "%s\n", errmsg ); + exit( 1 ); + } + + // Let plplot handle errors from here on + + plsError( NULL, NULL ); + + autoy = 0; // autoscale y + acc = 1; // accumulate + + for(int i=0;i<10;i++) + { + //printf("t%d %f\n",i,data->t[i]); + //printf("buffer%d %f\n",i,data->buffer[i]); + plstripa( data->id1, 0, data->t[i], data->buffer[i]); + } + + //printf("before pl free\n"); + plstripd( data->id1 ); + plend(); + //printf("draw done\n"); +} + +static void print_hello (GtkWidget *widget, gpointer user_data) +{ + g_print ("Hello World\n"); +} + +static void activate (GtkApplication *app, gpointer user_data) +{ + DATA *data=user_data; + GtkWidget *window; + data->area = gtk_drawing_area_new (); + GtkWidget *button; + GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL,1); + + window = gtk_application_window_new (app); + gtk_window_set_title (GTK_WINDOW (window), "remote_plot"); + gtk_window_set_default_size (GTK_WINDOW (window), 1000, 1000); + + gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (data->area), 600); + gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (data->area), 600); + gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (data->area), + draw_function, + user_data, NULL); + + button = gtk_button_new_with_label ("Hello World"); + g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL); + + gtk_box_append(GTK_BOX(box), button); + gtk_box_append(GTK_BOX(box), data->area); + gtk_window_set_child (GTK_WINDOW (window), box); + + gtk_window_present (GTK_WINDOW (window)); + + g_timeout_add(50,sftp_read_sync,user_data); + //printf("after g_timeout_add\n"); +} + +int main (int argc, char **argv) +{ + DATA data; + //ssh_session session; + //sftp_session sftp; int rc; + GtkApplication *app; + int status; + + for(int i=0;i<10;i++) + { + data.t[i]=i; + data.buffer[i]=0; + } + // Open session and set options - my_ssh_session = ssh_new(); - if (my_ssh_session == NULL) + data.session = ssh_new(); + if (data.session == NULL) exit(-1); - ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "10.0.0.7"); + ssh_options_set(data.session, SSH_OPTIONS_HOST, "10.0.0.7"); // Connect to server - rc = ssh_connect(my_ssh_session); + rc = ssh_connect(data.session); if (rc != SSH_OK) { fprintf(stderr, "Error connecting to 10.0.0.7: %s\n", - ssh_get_error(my_ssh_session)); - ssh_free(my_ssh_session); + ssh_get_error(data.session)); + ssh_free(data.session); exit(-1); } // Verify the server's identity // For the source code of verify_knownhost(), check previous example - if (verify_knownhost(my_ssh_session) < 0) + if (verify_knownhost(data.session) < 0) { - ssh_disconnect(my_ssh_session); - ssh_free(my_ssh_session); + ssh_disconnect(data.session); + ssh_free(data.session); exit(-1); } // Authenticate ourselves // https://api.libssh.org/stable/libssh_tutor_authentication.html - rc = ssh_userauth_publickey_auto(my_ssh_session, NULL, NULL); + rc = ssh_userauth_publickey_auto(data.session, NULL, NULL); if (rc != SSH_AUTH_SUCCESS) { fprintf(stderr, "Error authenticating with key: %s\n", - ssh_get_error(my_ssh_session)); - ssh_disconnect(my_ssh_session); - ssh_free(my_ssh_session); + ssh_get_error(data.session)); + ssh_disconnect(data.session); + ssh_free(data.session); exit(-1); } - sftp = sftp_new(my_ssh_session); - if (sftp == NULL) + data.sftp = sftp_new(data.session); + if (data.sftp == NULL) { fprintf(stderr, "Error allocating SFTP session: %s\n", - ssh_get_error(my_ssh_session)); + ssh_get_error(data.session)); return SSH_ERROR; } - rc = sftp_init(sftp); + rc = sftp_init(data.sftp); if (rc != SSH_OK) { fprintf(stderr, "Error initializing SFTP session: code %d.\n", - sftp_get_error(sftp)); - sftp_free(sftp); + sftp_get_error(data.sftp)); + sftp_free(data.sftp); return rc; } - sftp_read_sync(my_ssh_session,sftp); + app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); + g_signal_connect (app, "activate", G_CALLBACK (activate), &data); + status = g_application_run (G_APPLICATION (app), argc, argv); + g_object_unref (app); + + //printf("before ssh free\n"); - ssh_disconnect(my_ssh_session); - ssh_free(my_ssh_session); + ssh_disconnect(data.session); + ssh_free(data.session); // Segmentation fault (core dumped) error, why? maybe double free? so no free is ok? //sftp_free(sftp); - return 0; + return status; } diff --git a/remote_plot_no_gtk.c b/remote_plot_no_gtk.c new file mode 100644 index 0000000..b1cb2a6 --- /dev/null +++ b/remote_plot_no_gtk.c @@ -0,0 +1,329 @@ +// references: +// https://api.libssh.org/stable/libssh_tutorial.html +// https://api.libssh.org/stable/libssh_tutor_guided_tour.html +// plplot example 17 + +#include <libssh/libssh.h> +#include <stdlib.h> +#include <stdio.h> +#include <libssh/sftp.h> + +// verify_knownhost() +#include <errno.h> +#include <string.h> + +#include <fcntl.h> // open() + +// plplot +#include <plplot/plConfig.h> +#include <plplot/plplot.h> +#include <math.h> +//#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +// very small also works, just transfter delays, I test accelerometer data is +// like 15782 which is 7 bytes consider newline and \0? +#define MAX_XFER_BUF_SIZE 7 + +// Variables for holding error return info from PLplot +static PLINT pl_errcode; +static char errmsg[160]; + +int sftp_read_sync(ssh_session session, sftp_session sftp) +{ + int access_type; + sftp_file file; + char buffer[MAX_XFER_BUF_SIZE]; + int nbytes, rc; + access_type = O_RDONLY; + + PLINT id1, autoy, acc; + PLFLT ymin, ymax, xlab, ylab; + PLFLT t, tmin, tmax, tjump; + PLINT colbox, collab, colline[4], styline[4]; + PLCHAR_VECTOR legline[4]; + + // If db is used the plot is much more smooth. However, because of the + // async X behaviour, one does not have a real-time scripcharter. + // This is now disabled since it does not significantly improve the + // performance on new machines and makes it difficult to use this + // example non-interactively since it requires an extra pleop call after + // each call to plstripa. + // + //plsetopt("db", ""); + //plsetopt("np", ""); + + // User sets up plot completely except for window and data + // Eventually settings in place when strip chart is created will be + // remembered so that multiple strip charts can be used simultaneously. + // + + // Specify some reasonable defaults for ymin and ymax + // The plot will grow automatically if needed (but not shrink) + + ymin = -0.1; + ymax = 0.1; + + // Specify initial tmin and tmax -- this determines length of window. + // Also specify maximum jump in t + // This can accomodate adaptive timesteps + + tmin = 0.; + tmax = 10.; + tjump = 0.3; // percentage of plot to jump + + // Axes options same as plbox. + // Only automatic tick generation and label placement allowed + // Eventually I'll make this fancier + + colbox = 1; + collab = 3; + styline[0] = colline[0] = 2; // pens color and line style + styline[1] = colline[1] = 3; + styline[2] = colline[2] = 4; + styline[3] = colline[3] = 5; + + legline[0] = "in_accel_z_raw"; // pens legend + legline[1] = "not_used"; + legline[2] = "not_used"; + legline[3] = "not_used"; + + xlab = 0.; ylab = 0.25; // legend position + + autoy = 1; // autoscale y + acc = 1; // don't scrip, accumulate + + // Initialize plplot + + plinit(); + + pladv( 0 ); + plvsta(); + + // Register our error variables with PLplot + // From here on, we're handling all errors here + + plsError( &pl_errcode, errmsg ); + + plstripc( &id1, "bcnst", "bcnstv", + tmin, tmax, tjump, ymin, ymax, + xlab, ylab, + autoy, acc, + colbox, collab, + colline, styline, legline, + "t", "", "Strip chart demo" ); + + if ( pl_errcode ) + { + fprintf( stderr, "%s\n", errmsg ); + exit( 1 ); + } + + // Let plplot handle errors from here on + + plsError( NULL, NULL ); + + autoy = 0; // autoscale y + acc = 1; // accumulate + + // This is to represent a loop over time + // Let's try a random walk process + + for (t=0;;t++) { + file = sftp_open(sftp, "/sys/bus/iio/devices/iio:device2/in_accel_z_raw", + access_type, 0); + if (file == NULL) { + fprintf(stderr, "Can't open file for reading: %s\n", + ssh_get_error(session)); + return SSH_ERROR; + } + + for (;;) { + nbytes = sftp_read(file, buffer, sizeof(buffer)); + if (nbytes == 0) { + break; // EOF + } else if (nbytes < 0) { + fprintf(stderr, "Error while reading file: %s\n", + ssh_get_error(session)); + sftp_close(file); + return SSH_ERROR; + } + + //printf("%s",buffer); + //printf("%d\n",atoi(buffer)); + plstripa( id1, 0, t, atof(buffer)); + } + } + + rc = sftp_close(file); + if (rc != SSH_OK) { + fprintf(stderr, "Can't close the read file: %s\n", + ssh_get_error(session)); + return rc; + } + + plstripd( id1 ); + plend(); + + return SSH_OK; +} + +// https://api.libssh.org/stable/libssh_tutor_guided_tour.html +int verify_knownhost(ssh_session session) +{ + enum ssh_known_hosts_e state; + unsigned char *hash = NULL; + ssh_key srv_pubkey = NULL; + size_t hlen; + char buf[10]; + char *hexa; + char *p; + int cmp; + int rc; + + rc = ssh_get_server_publickey(session, &srv_pubkey); + if (rc < 0) { + return -1; + } + + rc = ssh_get_publickey_hash(srv_pubkey, + SSH_PUBLICKEY_HASH_SHA1, + &hash, + &hlen); + ssh_key_free(srv_pubkey); + if (rc < 0) { + return -1; + } + + state = ssh_session_is_known_server(session); + switch (state) { + case SSH_KNOWN_HOSTS_OK: + /* OK */ + + break; + case SSH_KNOWN_HOSTS_CHANGED: + fprintf(stderr, "Host key for server changed: it is now:\n"); + ssh_print_hexa("Public key hash", hash, hlen); + fprintf(stderr, "For security reasons, connection will be stopped\n"); + ssh_clean_pubkey_hash(&hash); + + return -1; + case SSH_KNOWN_HOSTS_OTHER: + fprintf(stderr, "The host key for this server was not found but an other" + "type of key exists.\n"); + fprintf(stderr, "An attacker might change the default server key to" + "confuse your client into thinking the key does not exist\n"); + ssh_clean_pubkey_hash(&hash); + + return -1; + case SSH_KNOWN_HOSTS_NOT_FOUND: + fprintf(stderr, "Could not find known host file.\n"); + fprintf(stderr, "If you accept the host key here, the file will be" + "automatically created.\n"); + + /* FALL THROUGH to SSH_SERVER_NOT_KNOWN behavior */ + + case SSH_KNOWN_HOSTS_UNKNOWN: + hexa = ssh_get_hexa(hash, hlen); + fprintf(stderr,"The server is unknown. Do you trust the host key?\n"); + fprintf(stderr, "Public key hash: %s\n", hexa); + ssh_string_free_char(hexa); + ssh_clean_pubkey_hash(&hash); + p = fgets(buf, sizeof(buf), stdin); + if (p == NULL) { + return -1; + } + + cmp = strncasecmp(buf, "yes", 3); + if (cmp != 0) { + return -1; + } + + rc = ssh_session_update_known_hosts(session); + if (rc < 0) { + fprintf(stderr, "Error %s\n", strerror(errno)); + return -1; + } + + break; + case SSH_KNOWN_HOSTS_ERROR: + fprintf(stderr, "Error %s", ssh_get_error(session)); + ssh_clean_pubkey_hash(&hash); + return -1; + } + + ssh_clean_pubkey_hash(&hash); + return 0; +} + +int main(void) +{ + ssh_session my_ssh_session; + sftp_session sftp; + int rc; + + // Open session and set options + my_ssh_session = ssh_new(); + if (my_ssh_session == NULL) + exit(-1); + ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "10.0.0.7"); + + // Connect to server + rc = ssh_connect(my_ssh_session); + if (rc != SSH_OK) + { + fprintf(stderr, "Error connecting to 10.0.0.7: %s\n", + ssh_get_error(my_ssh_session)); + ssh_free(my_ssh_session); + exit(-1); + } + + // Verify the server's identity + // For the source code of verify_knownhost(), check previous example + if (verify_knownhost(my_ssh_session) < 0) + { + ssh_disconnect(my_ssh_session); + ssh_free(my_ssh_session); + exit(-1); + } + + // Authenticate ourselves + // https://api.libssh.org/stable/libssh_tutor_authentication.html + rc = ssh_userauth_publickey_auto(my_ssh_session, NULL, NULL); + if (rc != SSH_AUTH_SUCCESS) + { + fprintf(stderr, "Error authenticating with key: %s\n", + ssh_get_error(my_ssh_session)); + ssh_disconnect(my_ssh_session); + ssh_free(my_ssh_session); + exit(-1); + } + + + sftp = sftp_new(my_ssh_session); + if (sftp == NULL) + { + fprintf(stderr, "Error allocating SFTP session: %s\n", + ssh_get_error(my_ssh_session)); + return SSH_ERROR; + } + + rc = sftp_init(sftp); + if (rc != SSH_OK) + { + fprintf(stderr, "Error initializing SFTP session: code %d.\n", + sftp_get_error(sftp)); + sftp_free(sftp); + return rc; + } + + sftp_read_sync(my_ssh_session,sftp); + + ssh_disconnect(my_ssh_session); + ssh_free(my_ssh_session); + // Segmentation fault (core dumped) error, why? maybe double free? so no free is ok? + //sftp_free(sftp); + + return 0; +} |