Storing all incoming data and button not working

please format code with </> button * homework policy * asking questions

Hi, my code currently stores data whenever I press the button ‘save data in text’. It stores the data at that moment in time and that second. However, I want the button to store all the data that comes in and is inputed up to when I press the button, so in the text file that is produced, a column of data and a column of time elapsed is produced. How can I do this?
Also, my button has a fault. Wherever I press on the display, it presses it as a button. How can I fix this?
Many thanks:

//This program takes ASCII-encoded strings
//from the serial port at 9600 baud and graphs them. It expects values in the
//range 0 to 1023, followed by a newline, or newline and carriage return
import processing.serial.*;

Serial myPort;                           // The serial port - object from serial class
String[] list = new String[3];           // For serial port
boolean newData = false;                 // Sets incoming data to false at the beginning
float inByte;                            // For incoming serial data
int xPos = 0;                            // Horizontal position of the graph (from bottom of screen) 
String inString;                         // Data recieved from serial port
int lastxPos=0;                          // X position from (0,0) of graph 
int lastheight=700;                      // Y position from (0,0) of graph 
                                         // - (Also Y length of graph)
                                         // Note: This number should be the Y value of the size() function in void setup()
int X = 1000;                            // X length of graph                     
                                         // Note: This number should be the X value of the size() function in void setup()
int halflength = X/2;       
String Title = "Signal";                 // Sets Title of Graph 
                                         // Note: Please change this to suit experiment
String Timer = "Time Elapsed:";
int boxLength = 700;
int rectSize = 30;
Button save;
Button cont;
int m;

Grid grid;
float Q = 45.0;
int qSave = 0;
boolean outputOpen = false;
PrintWriter output;


void setup () {
  size(1000, 700);                               // Set the window size:   
  smooth();
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600);    // A serialEvent() is generated when a newline character is received
  myPort.bufferUntil('\n');                     // Sets a specific byte to buffer until before calling serialEvent()
  background(100);                              // Set inital background colour
  
  grid=new Grid(0, 0, 10*Q, 12*Q);
  save=new Button(width-width/12,boxLength/10,"Save data \n in data.txt");
}

void draw () {
  //grid.display();
  stroke(0);
  line(width - width/10,0,width - width/10,boxLength);
  fill(255);
  rect(width-width/10,0,width/10,boxLength);
  fill(255);                                         // These few lines draws on screen text
  textSize(20); 
  textAlign(CENTER);                                 //Centre's Title
  text(Title, halflength, 30);
  stroke(100);
  fill(0);                                  
  textSize(13);                              
  text(Timer,width-width/20,boxLength/3);
  fill(0);  
  m = millis()/1000;
  textSize(13);                              
  text(m,width-width/20,boxLength/2.5);
 
  save.display();
  
  if (newData) {                                        // If there is new input data:
    stroke(255);                                        // Stroke color
    strokeWeight(2);                                    // Stroke wider
    line(lastxPos, lastheight, xPos, height-inByte);    // Draw line
    lastxPos = xPos;                                    // Allows for continuous signals
    lastheight= int(height-inByte);

    if (xPos >= width-width/10) {                       // At the edge of the window, go back to the beginning
      xPos = 0;
      lastxPos= 0;
      background(100);                                  // Clear the screen.
    } 
    else {
      xPos++;                                           // Increment the horizontal position
    }
   newData = false;                                     // Again sets new data to false
  }
}

void serialEvent (Serial myPort) {
  // get the ASCII string:
  inString = myPort.readStringUntil('\n');
  println(inString);
  if (inString != null) {
    inString = trim(inString);                // trim off whitespaces.
    inByte = float(inString);                 // convert to a number.
    inByte = map(inByte, 0, 1023, 0, height); // map to the screen height.
    newData = true; 
  }
}

void mouseClicked(){{
        if (save.click){
          if (outputOpen==false){ // if is not recording then start recording
            String fileName ="dataf"+"_"+nf(year(),4)+"_"+nf(month(),2)+"_"+nf(day(),2)+"_"+nf(hour(),2)+"_"+nf(minute(),2)+"_"+nf(second(),2)+".txt";
            output=createWriter(fileName);
            outputOpen=true;
            save.title="saving";
            output.print("Signal Value: "); output.print(inString);
            output.print("\n");
            output.print("Time Elapsed(s): "); output.print(m);
            output.println();
            qSave=0;
            // when entering each data in the stream write to output.print ()
            // write to the entry routine
          } else { // save is already recording, so stop recording
            //println("outputOpen==true => ",outputOpen);
            output.close();
            outputOpen=false;
            qSave=1;
            if (qSave>10) {qSave=1;}
            save.title="Save data \n in data.txt" + "-"+qSave;
            save.click=false;
          }
        } else {
          String fileName ="data"+"_"+nf(year(),4)+"_"+nf(month(),2)+"_"+nf(day(),2)+"_"+nf(hour(),2)+"_"+nf(minute(),2)+"_"+nf(second(),2)+".txt";
          output=createWriter(fileName);
          output.print("Signal Value: "); output.print(inString);
          output.print("\n");
          output.print("Time Elapsed(s): "); output.print(m);
          // dados
          float f=5000.0/1023.0;          
          output.close();
          qSave+=1;
          if (qSave>10) {qSave=1;}
          save.title="Save data \n in data.txt" + "-"+qSave;
          save.click=false;
        }
  }
}

Button CLass:

class Button{
   color cor_ativo=color(0,255,0);
   color cor_fio=color(0);
   
   float x,y;
   String title;
   boolean mouseClick = false;
   boolean click = false;
   
   Button(float x, float y, String title){
     this.x = x;
     this.y = y;
     this.title = title;
   } 
   
   void display(){
     if (mouseClick){
        fill(0,100,0);
     } else if (click){
         fill(cor_ativo); //fill(0,255,0); 
      } else{
        fill(200);
      }
      stroke(cor_fio); 
      strokeWeight(1);
      fill(100);
      rect(width-width/12, boxLength/10, width/15, rectSize);
      textAlign(CENTER);
      textSize(10);
      fill(255);
      text(title,width-width/20,boxLength/8.5);
   }
   
   void mouseClick(){
     if (mouseButton==LEFT) {
       if (mouseX>(width - width/12) && mouseX<(width - width/12 + width/15) && mouseY>(boxLength/10) && mouseY<(boxLength/10+rectSize)){
          mouseClick=true;
       }
     }
   }
  
   boolean mouseClickd(){ // returns if it is clicked or not
     boolean ret=false;
     if (mouseButton==LEFT){
       if (mouseX>(width - width/12) && mouseX<(width - width/12 + width/15) && mouseY>(boxLength/10) && mouseY<(boxLength/10+rectSize)){
          click=!click;
          ret=true;
          mouseClick=false;
       }
     }
     return ret;
   }
}

Thanks

Hi @saaqib.m, I tried to run your code but it Grid is undefined. Is that another tab? Does the grid fill with rows of data time+value? Then you can use that data to save to file. On click, open the file, write the lines out, close. I can see you have all the pieces for that already.

For the button that responds to the whole window, in your button class you have two routines, that check if the mouse is over the button. I think you just need to call them from the main mouseClicked().


void mouseClicked()
{
  save.mouseClick();
  save.mouseClickd();
}

Please excuse me being picky about this other issue. Your code for calculating the filename is unreliable because there’s a small chance the time will change while you are reading all the different pieces. 09:59 can be read as 09:00 because time has moved to 10:00. Please try this:

import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Calendar;

SimpleDateFormat fmt_file;

Date aDate;
String file_date; 

fmt_file = new SimpleDateFormat("yyyyMMdd_HHmmss");

aDate = new Date();
file_date = fmt_file.format(aDate); 
println("Date in file format " + file_date);
exit();

HI Richard, thank you for your reply. I will try it out but I think i might be leaning towards a table as well. Also, would you have any idea on how I could implement a sampling variable? So this variable would indicate when to store/save the data and print on screen. For example a value of 1Hz would sample the incoming data a certain amount of times etc. Many thanks

Hello,

Here is the simplest example of collecting data into an ArrayList of Integers.

Example Code
//This program takes ASCII-encoded strings

//from the serial port at 9600 baud and graphs them. It expects values in the
//range 0 to 1023, followed by a newline, or newline and carriage return

IntList data;

import processing.serial.*;

Serial myPort;                           // The serial port - object from serial class
//String[] list = new String[3];           // For serial port

int inData;

boolean newData = false;
boolean record = false;
boolean dataReady = false;

int counter;

void setup () 
  {
  size(200, 400);                               // Set the window size:   
  background(0);

  data = new IntList();
  
  // List all the available serial ports
  printArray(Serial.list());
  
  String portName = Serial.list()[2];
  myPort = new Serial(this, portName, 9600);    // A serialEvent() is generated when a newline character is received
  myPort.bufferUntil('\n');                     // Sets a specific byte to buffer until before calling serialEvent()
  delay(1000);
 
  textSize(16);
  //noLoop();
  }

void draw () 
  {
  //background(0);
  if(dataReady)
    {
    println(data);
    for(int i=0; i<16; i++)
      {
      text(data.get(i), 10, i*20+20);
      }
    dataReady = false;
    data.clear();
    }
  }

void serialEvent (Serial myPort) 
  {
  // get the ASCII string:
  String inString = myPort.readStringUntil('\n');
  //println(inString);
  if (inString != null) 
    {
    inString = trim(inString);                // trim off whitespaces.
    
    //inByte = float(inString);                 // convert to a number
    //inByte = map(inByte, 0, 1023, 0, height); // map to the screen height.
    //newData = true; 
    
    if (record)
      {
      data.append(int(inString));
      println(counter++);
      if (data.size() >= 16)
        {
        record = false;
        dataReady = true;
        println("Data ready!");
        counter = 0;
        }
      }
    }
  }

void mousePressed()
  {
  record = true;
  background(0);
  }

The incoming data is a string (integer); I converted the string to an integer.
mousePressed() will store 16 integer values and display to screen.

You can easily adapt these concepts with a timer and store data.

There are plenty of examples of timers in this forum.

:)

1 Like

@saaqib.m (Sorry, distracted.) Re ‘sampling variable’ I think you have a few selections that don’t simply fit on to one variable. I would construct something simple that records at a fixed rate to file. Then add features one-by-one. Remember that the Processing sketch must always be able to keep up with all that arrives from the Arduino. Data at 1 Hz will be fine. You can accumulate n points in a table or intlist (thanks @glv, I’d never used that before). When that is full (e.g. 60 = 1 minute) write to file. Another choice is whether the chart scrolls as the data arrives, or fills from the left overwriting the previous. You’ll probably want both at different times. Then again, you’ll want to show the recorded data from file.

2 Likes

Thank you very much Richard and glv! That has sparked some ideas :slight_smile:

1 Like

By the way, would you know how I could make this a scrolling graph from left to right? At the moment it over writes the data as soon as it reaches the end. Many thanks

Hello,

Is this a homework or academic assignment?

:)

I’ve used scrolling graph from the ControlP5 library. Install the library then see Examples, Contributed Libraries, ControlP5, controllers, ControlP5chart.

Something similar in js I made myself (change mode to p5.js):
image

function graph(_x, _y, _n, _h)
{
  // Params:
  var my_x = _x;            // Location
  var my_y = _y;            // Location
  var max_x = _n;           // nof points
  var graph_data = [max_x]; // width of graph
  var max_y = _h;           // height of graph area
  var my_h  = _h;           // height of graph area
  //
  var ary0_ix = 0; // the point where we add the next data.
  var tix;
  // Init the graph data
  for (tix = 0; tix < max_x; tix++) {graph_data[tix] = 0;}

  this.display = function()
  {
    // The data, and val1 are in units of y pixels.
    var tix;
    var val1;
    var iGX1;
    var iGY1;
    var iGX2;
    var iGY2;
    // rect to cover previous
    noStroke();
    fill(60, 60, 60);
    rect(my_x, my_y - (max_y - 1), max_x, my_h);
    // plot the graph
    for (tix = 0; tix < max_x; tix++)
    {
      iGX2 = my_x + tix;
      // plot new point
      stroke(0, 255, 0);
      val1 = graph_data[(tix + ary0_ix) % max_x];
      if (val1 > max_y - 1) {val1 = max_y - 1;}
      if (val1 < 0)         {val1 = 0;}
      iGY2 = my_y - val1;
      if (tix == 0) {point(iGX2, iGY2);}
      else {line(iGX1, iGY1, iGX2, iGY2);}
      iGX1 = iGX2;
      iGY1 = iGY2;
    }
  }
  // add a value to front of graph
  this.add_data = function(_v)
  {
    graph_data[ary0_ix] = _v;
    ary0_ix++;
    ary0_ix %= max_x;
  }
}

var graphs = [];
var nof_graphs = 2;

function setup()
{
  var iGX;
  var iGY;
  var iGW;
  var iGH;

  createCanvas(windowWidth * 19 /20, windowHeight * 39/40);
  background(0);
  frameRate(20);

  iGY = 120;
  iGH = 37;
  graphs.push(new graph(180, iGY, 206, iGH)); iGY += 40;
  graphs.push(new graph(180, iGY, 206, iGH)); iGY += 40;
}

function draw()
{
  var gix;
    graphs[ 0].add_data(frameCount /5 % 30);
    graphs[ 1].add_data((frameCount/5 + 10) % 30);
    for (gix = 0; gix < nof_graphs; gix++){graphs[gix].display();}
}