// references: // 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 // https://docs.gtk.org/gtk4/class.DrawingArea.html // https://www.gtk.org/docs/getting-started/hello-world/ #include #include #include #include // verify_knownhost() #include #include #include // open() // plplot #include #include #include //#include #include #include #include // voltage max format 8 bytes ,xxx.xxx // temp max format 5 bytes ,xx.x // timestamp max 8 bytes 86400000 // 96 voltage, 32 temp // 96*8+32*5+8=936 bytes #define MAX_XFER_BUF_SIZE 936 #define LEN 10 #define VOLTLEN 96 #define TEMPLEN 32 // Variables for holding error return info from PLplot static PLINT pl_errcode; static char errmsg[160]; typedef struct { ssh_session session; sftp_session sftp; PLINT id1; PLFLT t[LEN]; PLFLT volt[LEN][VOLTLEN]; PLFLT temp[LEN][TEMPLEN]; 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; // This is to represent a loop over time // Let's try a random walk process file = sftp_open(data->sftp, "/tmp/mycan", access_type, 0); if (file == NULL) { fprintf(stderr, "Can't open file for reading: %s\n", ssh_get_error(data->session)); //return SSH_ERROR; return G_SOURCE_REMOVE; } for(int i=0;i<(LEN-1);i++) { //data->t[i]=data->t[i+1]; for(int j=0;jvolt[i][j]=data->volt[i+1][j]; for(int j=0;jtemp[i][j]=data->temp[i+1][j]; } 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; return G_SOURCE_REMOVE; } //printf("receive: %s",buffer); //data->buffer[LEN-1]=atof(buffer); // would be better if check strtok return NULL or not strtok(buffer,","); for(int i=0;ivolt[LEN-1][i]=atof(strtok(NULL,",")); for(int i=0;itemp[LEN-1][i]=atof(strtok(NULL,",")); } rc = sftp_close(file); if (rc != SSH_OK) { fprintf(stderr, "Can't close the read file: %s\n", ssh_get_error(data->session)); //return rc; return G_SOURCE_REMOVE; } for(int i=0;it[i]++; //printf("sftp_read_sync end\n"); 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 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; } static void draw_function (GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data) { //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] = "voltage"; // 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", 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;it[i]); //printf("buffer%d %f\n",i,data->buffer[i]); plstripa( data->id1, 0, data->t[i], data->volt[i][0]); } //printf("before pl free\n"); plstripd( data->id1 ); plend(); //printf("draw done\n"); } static void print_data (GtkWidget *widget, gpointer user_data) { DATA *data=user_data; for(int i=0;it[i]); for(int j=0;jvolt[i][j]); for(int j=0;jtemp[i][j]); putchar('\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 ("Print data"); g_signal_connect (button, "clicked", G_CALLBACK (print_data), user_data); 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(500,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