aboutsummaryrefslogtreecommitdiff
path: root/remote_plot.c
diff options
context:
space:
mode:
authorXiao Pan <xyz@flylightning.xyz>2025-04-29 23:41:06 -0700
committerXiao Pan <xyz@flylightning.xyz>2025-04-29 23:41:06 -0700
commit7c86c3921d26788e7a01f4215b098d7e8f31579e (patch)
tree850fff2f39cd35f0867366d30c76d2c9aa9273aa /remote_plot.c
parent15854b83aeed2ca9dab055d68b02f487ce39f765 (diff)
feat: save to local, cli option to read only from local
Diffstat (limited to 'remote_plot.c')
-rw-r--r--remote_plot.c329
1 files changed, 213 insertions, 116 deletions
diff --git a/remote_plot.c b/remote_plot.c
index 443747a..bd0c503 100644
--- a/remote_plot.c
+++ b/remote_plot.c
@@ -195,90 +195,158 @@ typedef struct {
uint32_t from_time;
uint32_t to_time;
bool from_time_entered;
+ // local file name
+ char *filename;
+ // only read from local .csv file or not
+ bool local;
}DATA;
-static gboolean sftp_read_sync(gpointer user_data)
- //int sftp_read_sync(ssh_session session, sftp_session sftp)
+static gboolean read_data(gpointer user_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");
+ //printf("read_data begin\n");
DATA *data=user_data;
+ bool new_entry=false;
- 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, sftp_expand_path(data->sftp,"~/.local/share/mycan.csv"), 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;
- }
+ if(data->local)
+ {
+ //printf("read_data check local pass\n");
+ FILE *fp;
+ if((fp=fopen(data->filename,"r"))!=NULL)
+ {
+ //printf("offset before fseek %d\n",data->offset);
+ fseek(fp, data->offset, SEEK_SET);
+ //printf("before read_data local for loop\n");
+ for(;;)
+ {
+ //printf("start read_data local for loop\n");
+ Item temp;
+ int ct=fscanf(fp,"%u,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",&(temp.t),&(temp.volt[0]),&(temp.volt[1]),&(temp.volt[2]),&(temp.volt[3]),&(temp.volt[4]),&(temp.volt[5]),&(temp.volt[6]),&(temp.volt[7]),&(temp.volt[8]),&(temp.volt[9]),&(temp.volt[10]),&(temp.volt[11]),&(temp.volt[12]),&(temp.volt[13]),&(temp.volt[14]),&(temp.volt[15]),&(temp.volt[16]),&(temp.volt[17]),&(temp.volt[18]),&(temp.volt[19]),&(temp.volt[20]),&(temp.volt[21]),&(temp.volt[22]),&(temp.volt[23]),&(temp.volt[24]),&(temp.volt[25]),&(temp.volt[26]),&(temp.volt[27]),&(temp.volt[28]),&(temp.volt[29]),&(temp.volt[30]),&(temp.volt[31]),&(temp.volt[32]),&(temp.volt[33]),&(temp.volt[34]),&(temp.volt[35]),&(temp.volt[36]),&(temp.volt[37]),&(temp.volt[38]),&(temp.volt[39]),&(temp.volt[40]),&(temp.volt[41]),&(temp.volt[42]),&(temp.volt[43]),&(temp.volt[44]),&(temp.volt[45]),&(temp.volt[46]),&(temp.volt[47]),&(temp.volt[48]),&(temp.volt[49]),&(temp.volt[50]),&(temp.volt[51]),&(temp.volt[52]),&(temp.volt[53]),&(temp.volt[54]),&(temp.volt[55]),&(temp.volt[56]),&(temp.volt[57]),&(temp.volt[58]),&(temp.volt[59]),&(temp.volt[60]),&(temp.volt[61]),&(temp.volt[62]),&(temp.volt[63]),&(temp.volt[64]),&(temp.volt[65]),&(temp.volt[66]),&(temp.volt[67]),&(temp.volt[68]),&(temp.volt[69]),&(temp.volt[70]),&(temp.volt[71]),&(temp.volt[72]),&(temp.volt[73]),&(temp.volt[74]),&(temp.volt[75]),&(temp.volt[76]),&(temp.volt[77]),&(temp.volt[78]),&(temp.volt[79]),&(temp.volt[80]),&(temp.volt[81]),&(temp.volt[82]),&(temp.volt[83]),&(temp.volt[84]),&(temp.volt[85]),&(temp.volt[86]),&(temp.volt[87]),&(temp.volt[88]),&(temp.volt[89]),&(temp.volt[90]),&(temp.volt[91]),&(temp.volt[92]),&(temp.volt[93]),&(temp.volt[94]),&(temp.volt[95]),&(temp.temp[0]),&(temp.temp[1]),&(temp.temp[2]),&(temp.temp[3]),&(temp.temp[4]),&(temp.temp[5]),&(temp.temp[6]),&(temp.temp[7]),&(temp.temp[8]),&(temp.temp[9]),&(temp.temp[10]),&(temp.temp[11]),&(temp.temp[12]),&(temp.temp[13]),&(temp.temp[14]),&(temp.temp[15]),&(temp.temp[16]),&(temp.temp[17]),&(temp.temp[18]),&(temp.temp[19]),&(temp.temp[20]),&(temp.temp[21]),&(temp.temp[22]),&(temp.temp[23]),&(temp.temp[24]),&(temp.temp[25]),&(temp.temp[26]),&(temp.temp[27]),&(temp.temp[28]),&(temp.temp[29]),&(temp.temp[30]),&(temp.temp[31]));
+ if(ct == EOF)
+ break;
+ else if(ct<(VOLTLEN+TEMPLEN+1))
+ {
+ fprintf(stderr,"Read less items (%d) than expected from local file\n",ct);
+ //exit(1);
+ return G_SOURCE_REMOVE;
+ }
+
+ if(AddItem(temp,&(data->cans))==false)
+ {
+ fprintf(stderr,"Problem allocating memory\n");
+ //exit(1);
+ return G_SOURCE_REMOVE;
+ }
- if(data->offset != 0)
- sftp_seek(file,data->offset);
- for(;;)
+ if(!new_entry)
+ new_entry=true;
+ //printf("end read_data local for loop\n");
+ }
+ //printf("after read_data local for loop\n");
+ //printf("offset before ftell %d\n",data->offset);
+ data->offset=ftell(fp);
+ //printf("offset after ftell %d\n",data->offset);
+ fclose(fp);
+ }
+ }
+ else
{
- nbytes = sftp_read(file, buffer, sizeof(buffer));
- //printf("nbytes: %d\n",nbytes);
- //printf("%d\n",MAX_XFER_BUF_SIZE);
- if (nbytes == 0) {
- break; // EOF
- } else if (nbytes < 0) {
- fprintf(stderr, "Error while reading file: %s\n",
+ 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, sftp_expand_path(data->sftp,"~/.local/share/mycan.csv"), access_type, 0);
+ if (file == NULL) {
+ fprintf(stderr, "Can't open file for reading: %s\n",
ssh_get_error(data->session));
- sftp_close(file);
- //return SSH_ERROR;
- return G_SOURCE_REMOVE;
- } else if ((nbytes%ENTRY_SIZE) != 0) {
- fprintf(stderr, "sftp read nbytes not a multiple of %d\n",ENTRY_SIZE);
- sftp_close(file);
//return SSH_ERROR;
return G_SOURCE_REMOVE;
}
- // TODO: check strtok return NULL or not
- //printf("before strtok\n");
- for(int i=0;i<(nbytes/ENTRY_SIZE);i++)
+ if(data->offset != 0)
+ sftp_seek(file,data->offset);
+ for(;;)
{
- Item temp;
- // TODO: pass endptr and check it and other things to be safe, see https://stackoverflow.com/questions/34206446
- if(i)
- temp.t=strtoul(strtok(NULL,","),NULL,10);
- else
- temp.t=strtoul(strtok(buffer,","),NULL,10);
- for(int j=0;j<VOLTLEN;j++)
- temp.volt[j]=atof(strtok(NULL,","));
- for(int j=0;j<(TEMPLEN-1);j++)
- temp.temp[j]=atof(strtok(NULL,","));
- temp.temp[TEMPLEN-1]=atof(strtok(NULL,"\n"));
- //printf("before AddItem\n");
- if(AddItem(temp,&(data->cans))==false)
- {
- fprintf(stderr,"Problem allocating memory\n");
+ nbytes = sftp_read(file, buffer, sizeof(buffer));
+ //printf("nbytes: %d\n",nbytes);
+ //printf("%d\n",MAX_XFER_BUF_SIZE);
+ 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;
+ } else if ((nbytes%ENTRY_SIZE) != 0) {
+ fprintf(stderr, "sftp read nbytes not a multiple of %d\n",ENTRY_SIZE);
+ sftp_close(file);
+ //return SSH_ERROR;
return G_SOURCE_REMOVE;
}
- //printf("after AddItem\n");
+
+ // TODO: check strtok return NULL or not
+ //printf("before strtok\n");
+ for(int i=0;i<(nbytes/ENTRY_SIZE);i++)
+ {
+ Item temp;
+ FILE *fp;
+ // TODO: pass endptr and check it and other things to be safe, see https://stackoverflow.com/questions/34206446
+ if(i)
+ temp.t=strtoul(strtok(NULL,","),NULL,10);
+ else
+ temp.t=strtoul(strtok(buffer,","),NULL,10);
+ for(int j=0;j<VOLTLEN;j++)
+ temp.volt[j]=atof(strtok(NULL,","));
+ for(int j=0;j<(TEMPLEN-1);j++)
+ temp.temp[j]=atof(strtok(NULL,","));
+ temp.temp[TEMPLEN-1]=atof(strtok(NULL,"\n"));
+ //printf("before AddItem\n");
+ if(AddItem(temp,&(data->cans))==false)
+ {
+ fprintf(stderr,"Problem allocating memory\n");
+ return G_SOURCE_REMOVE;
+ }
+ if(!new_entry)
+ new_entry=true;
+ //printf("after AddItem\n");
+
+ if((fp=fopen(data->filename,"a"))==NULL)
+ {
+ fprintf(stderr,"Can't open file \"%s\".\n",data->filename);
+ //exit(1);
+ return G_SOURCE_REMOVE;
+ }
+ fprintf(fp,"%u",temp.t);
+ for(int j=0;j<VOLTLEN;j++)
+ fprintf(fp,",%5.3f",temp.volt[j]);
+ for(int j=0;j<TEMPLEN;j++)
+ fprintf(fp,",%5.1f",temp.temp[j]);
+ fprintf(fp,"\n");
+ fclose(fp);
+ }
+ //printf("after strtok\n");
+ data->offset+=nbytes;
}
- //printf("after strtok\n");
- data->offset+=nbytes;
- }
- 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;
+ 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;
+ }
}
- //printf("sftp_read_sync end\n");
+ //printf("after read_data check local if else\n");
+ if(new_entry)
{
double sum,avg;
// max 28 char + 1 \0: Average temperature: 6553.5 C
@@ -296,9 +364,11 @@ static gboolean sftp_read_sync(gpointer user_data)
avg=sum/TEMPLEN;
sprintf(str,"Average temperature: %.1f C",avg);
gtk_label_set_text(GTK_LABEL(data->temp_label),str);
+ new_entry=false;
+ gtk_widget_queue_draw(data->area);
}
- gtk_widget_queue_draw(data->area);
+ //printf("after check new_entry if\n");
//return SSH_OK;
// must return G_SOURCE_CONTINUE to keep polling
@@ -622,7 +692,7 @@ static void activate (GtkApplication *app, gpointer user_data)
gtk_window_present (GTK_WINDOW (window));
//printf("before g_timeout_add\n");
- g_timeout_add(1000,sftp_read_sync,user_data);
+ g_timeout_add(1000,read_data,user_data);
//printf("after g_timeout_add\n");
}
@@ -637,61 +707,66 @@ static int command_line (GApplication *app, GApplicationCommandLine *cmdline, gp
// https://docs.gtk.org/glib/gvariant-format-strings.html#pointers
// &s copy the pointer
g_variant_dict_lookup (options, "destination", "&s", &dest);
+ g_variant_dict_lookup (options, "local", "b", &(data->local));
- // Open session and set options
- data->session = ssh_new();
- if (data->session == NULL)
- exit(-1);
- ssh_options_set(data->session, SSH_OPTIONS_HOST, dest);
-
- // Connect to server
- rc = ssh_connect(data->session);
- if (rc != SSH_OK)
+ if(!(data->local))
{
- fprintf(stderr, "Error connecting to %s: %s\n",
- dest, ssh_get_error(data->session));
- ssh_free(data->session);
- exit(-1);
- }
+ // Open session and set options
+ data->session = ssh_new();
+ if (data->session == NULL)
+ exit(-1);
+ ssh_options_set(data->session, SSH_OPTIONS_HOST, dest);
+
+ // Connect to server
+ rc = ssh_connect(data->session);
+ if (rc != SSH_OK)
+ {
+ fprintf(stderr, "Error connecting to %s: %s\n",
+ dest, 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(data->session) < 0)
- {
- ssh_disconnect(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(data->session) < 0)
+ {
+ 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(data->session, NULL, NULL);
- if (rc != SSH_AUTH_SUCCESS)
- {
- fprintf(stderr, "Error authenticating with key: %s\n",
- ssh_get_error(data->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(data->session, NULL, NULL);
+ if (rc != SSH_AUTH_SUCCESS)
+ {
+ fprintf(stderr, "Error authenticating with key: %s\n",
+ ssh_get_error(data->session));
+ ssh_disconnect(data->session);
+ ssh_free(data->session);
+ exit(-1);
+ }
- data->sftp = sftp_new(data->session);
- if (data->sftp == NULL)
- {
- fprintf(stderr, "Error allocating SFTP session: %s\n",
- ssh_get_error(data->session));
- return SSH_ERROR;
- }
+ data->sftp = sftp_new(data->session);
+ if (data->sftp == NULL)
+ {
+ fprintf(stderr, "Error allocating SFTP session: %s\n",
+ ssh_get_error(data->session));
+ return SSH_ERROR;
+ }
- rc = sftp_init(data->sftp);
- if (rc != SSH_OK)
- {
- fprintf(stderr, "Error initializing SFTP session: code %d.\n",
- sftp_get_error(data->sftp));
- sftp_free(data->sftp);
- return rc;
+ rc = sftp_init(data->sftp);
+ if (rc != SSH_OK)
+ {
+ fprintf(stderr, "Error initializing SFTP session: code %d.\n",
+ sftp_get_error(data->sftp));
+ sftp_free(data->sftp);
+ return rc;
+ }
}
+
// https://discourse.gnome.org/t/gio-application-commandline-does-trigger-activate-signal/2988/22
// > If you pass G_APPLICATION_HANDLES_COMMAND_LINE in the flags, the
// > command-line args are passed to the primary instance and ::activate is
@@ -711,14 +786,30 @@ int main (int argc, char **argv)
GtkApplication *app;
int status;
+ {
+ // usually ~/.local/share
+ const char *dir=getenv("XDG_DATA_HOME");
+ const char *str;
+ if(dir != NULL)
+ str="/mycan.csv";
+ else
+ {
+ str="/.local/share/mycan.csv";
+ dir=getenv("HOME");
+ }
+ data.filename=malloc((strlen(dir)+strlen(str)+1)*sizeof(char));
+ sprintf(data.filename,"%s%s",dir,str);
+ }
+
InitializeList(&(data.cans));
if(ListIsFull(&(data.cans)))
{
fprintf(stderr,"No memory available! Bye!\n");
exit(1);
}
- data.offset=0;
data.from_time_entered=false;
+ data.offset=0;
+ data.local=false;
//printf("after init\n");
@@ -728,6 +819,7 @@ int main (int argc, char **argv)
app = gtk_application_new ("org.gtk.example", G_APPLICATION_HANDLES_COMMAND_LINE);
g_application_add_main_option(G_APPLICATION(app),"destination",'d',0,G_OPTION_ARG_STRING,"ssh destination","Spartan_Racing_Charger@10.0.0.9");
+ g_application_add_main_option(G_APPLICATION(app),"local",'l',0,G_OPTION_ARG_NONE,"Only read from local .csv file",NULL);
g_signal_connect (app, "activate", G_CALLBACK (activate), &data);
g_signal_connect (app, "command-line", G_CALLBACK (command_line), &data);
@@ -737,12 +829,17 @@ int main (int argc, char **argv)
//printf("before ssh free\n");
- ssh_disconnect(data.session);
- ssh_free(data.session);
+ if(data.local==false)
+ {
+ 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);
EmptyTheList(&(data.cans));
+ free(data.filename);
+
return status;
}