push exceeding 32 use limit

edited April 2016 in Arduino

I am writing a dashboard UI for an arduino and am running into the error "pushmatrix cannot use push more than 32 times" this appears to be caused when a pushmatrix is used too many times without popmatrix. I am not totally sure what is causing it as all my pushes have pops. Additionally I tried putting all my different draw sections in try statements so I could see what was causing the problem, but this did not stop the error from happening. This makes me think I am not catching it in a try because there is really no drawing going on outside a try at this point. Finally, I am using the graphica library to plot the data in real time from the arduino. All graphing is in seperate try statements, so its the same thing.

Does anybody know what exception I should use for this error? Right now I am using runtime.

Thanks!

Answers

  • this appears to be caused when a pushmatrix is used too many times without popmatrix

    yes this is the problem. There is no easy solution, except to step through your code one line at a time. You cannot catch this exception because you cannot 'recover' from it, in other words the program crashes because OpenGL does cannot continue after this error.

    Things to watch out for are

    1) recursive functions where the push-pop-pair statements straddle the recursive call.

    2) the push-pop-pair statements are not at the same level. For instance the push is inside a for loop but the pop statement is after the for loop ends.

    3) the push-pop-pair are not in the same function. Although the syntax is OK it is very difficult to ensure that pop is called for every push or even if they are called in the right order.

  • Just an extra addendum:

    4) Using push/pop (or anything related to the canvas) outside the "Animation" Thread.

  • Thanks a ton for both your speedy answers! So by running the code with no pushMatrix commands used on my side I think I have narrowed down that it is happening inside the grafica library. Which stinks because it is not my code. Alas.

    Digging through the source for that library I found all kinds of push pop violations on this list.

    Here is one function that has a push, then it enters a for loop with a push and a pop, then a pop. Theoretically this seems ok to me as it would accumulate 2 pushes before the pop. But it still seems off to me.

    protected void drawAsTopAxis() {
        parent.pushStyle();
        parent.textMode(MODEL);
        parent.textFont(font);
        parent.textSize(fontSize);
        parent.fill(fontColor);
        parent.stroke(lineColor);
        parent.strokeWeight(lineWidth);
        parent.strokeCap(SQUARE);
    
        parent.pushMatrix();
        parent.translate(0, -dim[1]);
    
        // Draw the ticks
        parent.line(0, -offset, dim[0], -offset);
    
        for (int i = 0; i < plotTicks.size(); i++) {
            if (ticksInside.get(i)) {
                if (log && tickLabels.get(i).equals("")) {
                    parent.line(plotTicks.get(i), -offset, plotTicks.get(i), -offset - smallTickLength);
                } else {
                    parent.line(plotTicks.get(i), -offset, plotTicks.get(i), -offset - tickLength);
                }
            }
        }
    
        // Draw the tick labels
        if (drawTickLabels) {
            if (rotateTickLabels) {
                parent.textAlign(LEFT, CENTER);
    
                for (int i = 0; i < plotTicks.size(); i++) {
                    if (ticksInside.get(i) && !tickLabels.get(i).equals("")) {
                        parent.pushMatrix();
                        parent.translate(plotTicks.get(i), -offset - tickLabelOffset);
                        parent.rotate(-HALF_PI);
                        parent.text(tickLabels.get(i), 0, 0);
                        parent.popMatrix();
                    }
                }
            } else {
                parent.textAlign(CENTER, BOTTOM);
    
                for (int i = 0; i < plotTicks.size(); i++) {
                    if (ticksInside.get(i) && !tickLabels.get(i).equals("")) {
                        parent.text(tickLabels.get(i), plotTicks.get(i), -offset - tickLabelOffset);
                    }
                }
            }
        }
    
        parent.popMatrix();
        parent.popStyle();
    }
    

    Here is another example. Here we have a popMatrix and a pushMatrix used in different functions.

    public void beginDraw() {
        parent.pushStyle();
        parent.pushMatrix();
        parent.translate(pos[0] + mar[1], pos[1] + mar[2] + dim[1]);
    }
    
    /**
     * Returns the sketch to the state that it had before calling beginDraw()
     */
    public void endDraw() {
        parent.popMatrix();
        parent.popStyle();
    }
    

    Im at a bit of a loss how to proceed here. Should I just start re-writing the grafica library? Is there anyway to catch when there is a problem? I am thinking now to run the code with a print at each line to see where it fails. The problem is sometimes the code needs to run for 2 days because it will crash. This is my burden I suppose.

    Thoughts?

  • edited April 2016
    • I don't see any obvious problems w/ those 3 grafica's methods. :-?
    • In drawAsTopAxis(), there's 1 push/popStyle() pair and 2 push/popMatrix() pairs.
    • And at its beginDraw() & endDraw() paired up methods, just 1 pair for style & matrix.
    • Unless your sketch is already near the threshold for pushes, there's no other reason for blaming grafica for the crash iMO. :-\"
  • I like many others have used graphica and no one has reported a similar problem.

    I agree with GoToLoop's statements and add that the beginDraw and endDraw methods are a pair and your code should make sure that one method is not called more often than the other.

  • I ran a test last night commenting out all push and pop calls in my code. It crashed after only a few hours. The grafica library is the only possible source of the push and pop calls. Do either of you have ideas about how I might test to see how grafica is getting into this situation? I have tried to track down the creator of grafica via github with no success. I'm a bit at a loss.

  • There's still the possibility that you're misusing the grafica library...

  • It crashed after only a few hours.

    I assume it crashed with the same error i.e. exceeded push limit. Normally this would happen almost immediately the program started the fact that it is happening much later is puzzling.

    The fact that you have commented out all the push/popMatrix calls in your code does not prove the problem is with graphica.

    For instance the beginDraw() method calls pushMatrix and the endDraw() method calls popMatrix so if you call beginDraw() more often than endDraw() you will eventually exceed the push limit. In this case it is NOT a problem caused by graphica but by incorrect use of the library.

    I assume that you are using the serial communication with your arduino device. Are you calling graphica library methods from the serial event handler because that would be wrong. Graphica methods should only be called from the main event thread e.g. draw() method.

    Difficult to help further without seeing the code.

  • edited April 2016

    @Koogs: Helpful...

    @quark: actually helpful!! There is no doubt that it could be me using the library incorrectly. The documentation on the library is "light" and I am absolutely not an expert java-er. I assembled the calls based on the examples that are out there.

    I can't upload the full code because it is too long but here are the two important sections:

    In the serial event I do call Grafica methods. I use this event to add points to the array using the plot.addpoint function. I could move this to the draw method, but I don't see why this is wrong.

    void serialEvent(Serial p)
    {
      arduinoPacket = arduinoPort.readStringUntil(LF); // read serial data
      try {
        //print(arduinoPacket);
        for (int i=0; i <= n_SPs - 2; i++) {
           //read temperature
          read_srt = arduinoPacket.indexOf("T"+str(i)+":") + str(i).length()+2;
          read_end = arduinoPacket.indexOf("F"+str(i)+":");
          T[i] = arduinoPacket.substring(read_srt, read_end);
          //read pressure
          read_srt = arduinoPacket.indexOf("P"+str(i)+":") + str(i).length()+2;
          read_end = arduinoPacket.indexOf("T"+str(i+1)+":");
          P[i] = arduinoPacket.substring(read_srt, read_end);
      //read flow rate
          read_srt = arduinoPacket.indexOf("F"+str(i)+":") + str(i).length()+2;
          read_end = arduinoPacket.indexOf("P"+str(i)+":");
          F[i] = arduinoPacket.substring(read_srt, read_end);
      if (float(T[i])>100) {
        state=29;
      }
      if (float(P[i])>1) {
        state=30;
      }
    }
    
    //read last entry at final statepoint
    //read temperature
    read_srt = arduinoPacket.indexOf("T"+str(n_SPs-1)+":") + str(n_SPs-1).length()+2;
    read_end = arduinoPacket.indexOf("F"+str(n_SPs-1)+":");
    T[n_SPs-1] = arduinoPacket.substring(read_srt, read_end);
    //read pressure
    read_srt = arduinoPacket.indexOf("P"+str(n_SPs-1)+":") + str(n_SPs-1).length()+2;
    read_end = arduinoPacket.indexOf("L1:");
    P[n_SPs-1] = arduinoPacket.substring(read_srt, read_end);
    //read flow rate
    read_srt = arduinoPacket.indexOf("F"+str(n_SPs-1)+":") + str(n_SPs-1).length()+2;
    read_end = arduinoPacket.indexOf("P"+str(n_SPs-1)+":");
    F[n_SPs-1] = arduinoPacket.substring(read_srt, read_end);
    //read level 1 - water level
    read_srt = arduinoPacket.indexOf("L1:") + 3;
    read_end = arduinoPacket.indexOf("L2:");
    Lev_water = int(arduinoPacket.substring(read_srt, read_end));
    //read level 2 - column extration water level
    read_srt = arduinoPacket.indexOf("L2:") + 3;
    read_end = arduinoPacket.indexOf("L3:");
    Lev_col = int(arduinoPacket.substring(read_srt, read_end));
    //read level 3 - FPS level
    read_srt = arduinoPacket.indexOf("L3:") + 3;
    read_end = arduinoPacket.indexOf("state");
    Lev_FPS = int(arduinoPacket.substring(read_srt, read_end));
    //read state, but protect current error state
    read_srt = arduinoPacket.indexOf("state:") + 6;
    read_end = arduinoPacket.indexOf("end");
        if (state<28) {
          state = int(arduinoPacket.substring(read_srt, read_end));
        }
      }
      catch (RuntimeException  e) {
        println("Waiting For Clean Serial Packet");
        nSerialError++;
      }
      if (t_plot<(millis()-time_plotwrite))
      {
         try {
          draw_plot = 1;
          t_plot_max = hour()+minute()/60.+second()/3600.;
          plot.addPoint(float(plot_index), float(T[0]));
          plot.getLayer("SP6").addPoint(float(plot_index), float(T[5]));
          plot.getLayer("SP7").addPoint(float(plot_index), float(T[6]));
          plot.getLayer("SP9").addPoint(float(plot_index), float(T[8]));
          plot.getLayer("SP10").addPoint(float(plot_index), float(T[9]));
          plot.getLayer("SP14").addPoint(float(plot_index), float(T[13]));
    
          if (plot_index>n_plotpoints) {
            plot.removePoint(0);
            t_plot_min = hour()+minute()/60.+second()/3600. -     n_plotpoints*t_plot/3600000.;
           if( t_plot_min<0){
              t_plot_min = t_plot_min+24.;
            }
          }
          plot_index = plot_index+1;
            }
        catch (RuntimeException  e) {
          println("Waiting For Clean Serial Packet");
          nSerialError++;
        }
        time_plotwrite = millis();
     }
    }
    

    Below is the section of draw() where I run all the other grafica methods.

    if (tab_cur=="TS") {
    try {
    //draw legend
    fill(250, 250, 250);
    textFont(text_PFD);
    textAlign(LEFT);
    text(N[0], 1100, 161);
    text(N[5], 1100, 196);
    text(N[6], 1100, 229);
    text(N[8], 1100, 264);
    text(N[9], 1100, 298);
    text(N[13], 1100, 332);
    
    if (plot_index>1) {
      plot.setLineColor(color(174, 202, 23));
      plot.getLayer("SP6").setLineColor(color(246, 195, 0));
      plot.getLayer("SP7").setLineColor(color(0, 189, 155));
      plot.getLayer("SP9").setLineColor(color(22, 157, 228));
      plot.getLayer("SP10").setLineColor(color(254, 140, 24));
      plot.getLayer("SP14").setLineColor(color(210, 82, 65));
      plot.setPointColor(color(174, 202, 23));
      plot.getLayer("SP6").setPointColor(color(246, 195, 0));
      plot.getLayer("SP7").setPointColor(color(0, 189, 155));
      plot.getLayer("SP9").setPointColor(color(22, 157, 228));
      plot.getLayer("SP10").setPointColor(color(254, 140, 24));
      plot.getLayer("SP14").setPointColor(color(210, 82, 65));
      plot.setPointSize(3);
      plot.getLayer("SP6").setPointSize(3);
      plot.getLayer("SP7").setPointSize(3);
      plot.getLayer("SP9").setPointSize(3);
      plot.getLayer("SP10").setPointSize(3);
      plot.getLayer("SP14").setPointSize(3);
      plot.setLineWidth(3);
      plot.getLayer("SP6").setLineWidth(3);
      plot.getLayer("SP7").setLineWidth(3);
      plot.getLayer("SP9").setLineWidth(3);
      plot.getLayer("SP10").setLineWidth(3);
      plot.getLayer("SP14").setLineWidth(3);
    }
    
    
    
          if (plot_index>n_plotpoints) {
            plot.setXLim((per_plot_min/100.)*n_plotpoints+(plot_index-n_plotpoints),       plot_index-1-(100-per_plot_max)/100.*n_plotpoints);
          } else {
            plot.setXLim(max(1, per_plot_min/100.*plot_index), max(1,     plot_index*per_plot_max/100.-1));
          }
          plot.beginDraw();
          plot.drawBackground();
          plot.drawBox();
      plot.drawXAxis();
      plot.drawYAxis();
      plot.drawTitle();
      plot.drawGridLines(GPlot.HORIZONTAL);
      plot.drawLines();
      plot.drawPoints();
      plot.drawLabels();
      plot.drawLegend(new String[] {"SP1", "SP6", "SP7", "SP9", "SP10", "SP14"}, 
        new float[] {1.1, 1.1, 1.1, 1.1, 1.1, 1.1}, 
        new float[] {0.9375, 0.875, 0.8125, 0.75, 0.6875, 0.625});
      plot.endDraw();
    
        //draw slider
        noStroke();
        fill(83, 83, 83);
        rect(320, 736-5, 700, 10);
        ellipse(320, 736, 10, 10);
        ellipse(1020, 736, 10, 10);
        fill(191, 191, 191); 
        low_bar_x = min(320.+per_plot_min/100.*700., high_bar_x);
        high_bar_x = max(1020.-(1-per_plot_max/100.)*700., low_bar_x);
        rect(low_bar_x, 736-5, high_bar_x-low_bar_x, 10);
        fill(255, 255, 255); 
        ellipse(low_bar_x, 736, 20, 20);
        ellipse(high_bar_x, 736, 20, 20);
    
         //overwrite x axis
        fill(38, 38, 38);
        rect(300, 675, 750, 35);
        rect(307, 105, 10, 600);
        fill(255, 255, 255);
        if (plot_index>1) {
          t_plot_min_adj = t_plot_min+per_plot_min/100.*(min(n_plotpoints, plot_index)-1)*t_plot/3600000.;
          t_step = (min(n_plotpoints, plot_index)-1)*t_plot/3600000.*(per_plot_max/100.- per_plot_min/100.)/(n_labels-1.);
          for (int i=0; i <= n_labels-1; i++) {
            t_plot_print = t_plot_min_adj+t_step*i;
            if (t_plot_print>24.) {
              t_plot_print=t_plot_print-24.;
            }
            text(nfc(t_plot_print, 2), 310+i*680./(n_labels-1.), 690);
          }
        }
        }
        catch (RuntimeException  e) {
          println("Plotting Error");
          nPlotError++;
        }  
    }
    

    will try moving the grafica methods to draw and keep you posted. If you see anything let me know.

  • edited April 2016 Answer ✓

    In the serialEvent() I do call grafica methods.

    Like I've warned about before as an extra 4th rule:

    4) Using push/pop (or anything related to the canvas) outside the "Animation" Thread.

    You're calling methods from a library which manipulates the canvas outside the "Animation" Thread!!! [-X

  • A Processing sketch is a single Java application but it has multiple threads. The most important thread is the event despatch thread. This thread is used to process all mouse and keyboard events and to update the user interface i.e. the display.

    Catching and processing serial events is done in a separate thread which is not synchronised with the event despatch thread. Attempting to access the UI (display) from the serial thread in any way is problematic, sometimes you might get away with it, in the sense you don't notice the problem, other times your program crashes. This might explain why it took so long for the program to crash.

    The moral of the story is that updating the UI must ONLY be done in the event despatch thread. This thread executes the draw() method.

  • edited April 2016

    The moral of the story is that updating the UI must ONLY be done in the event dispatch thread. This thread executes the draw() method.

    • Hmmm... All Processing's callbacks are executed by the "Animation" Thread aFaIK. :-\"
    • Those include setup(), draw(), keyPressed(), MouseMoved(), etc. Except settings(). $-)
    • However, if we activate noLoop(), the event callbacks are run by the "AWT-EventQueue-0" Thread instead. :-$

    void settings() {
      //noLoop(); // AWT-EventQueue-0
      println("settings()", Thread.currentThread());
    }
    
    void setup() {
      println("setup()", Thread.currentThread());
    }
    
    void draw() {
      if (frameCount == 1)  println("draw()", Thread.currentThread());
    }
    
    void keyPressed() {
      println("keyPressed()", Thread.currentThread());
    }
    
    void mousePressed() {
      println("mousePressed()", Thread.currentThread());
    }
    
    void mouseDragged() {
      println("mouseDragged()", Thread.currentThread());
    }
    

    The most important Thread is the event dispatch Thread.

    • It is very important indeed. But in Processing it's responsible only for enqueueing the events.
    • The dequeueing part is still done by the "Animation" Thread.
    • Except when noLoop() is active. In which case "AWT-EventQueue-0" Thread dequeues as well. :-B
    • More about Processing's threads: https://forum.Processing.org/two/discussions/tagged?Tag=currentthread()
  • Thanks a ton to you both. I have made the edits and am currently running a test.

    Clearly I have little to no idea what I am doing. I will report what happens.

  • edited April 2016

    If you are interested in seeing what threads exist in a running sketch you can add the code from this discussion. Might prove interesting.

  • Bad news over here. Grafica still crashes in the same way with pushMatrix being called too many times.

    Here is the new serial section:

    void serialEvent(Serial p)
    {
     arduinoPacket = arduinoPort.readStringUntil(LF); // read serial data
     try {
      //print(arduinoPacket);
       for (int i=0; i <= n_SPs - 2; i++) {
         //read temperature
         read_srt = arduinoPacket.indexOf("T"+str(i)+":") + str(i).length()+2;
         read_end = arduinoPacket.indexOf("F"+str(i)+":");
         T[i] = arduinoPacket.substring(read_srt, read_end);
         //read pressure
         read_srt = arduinoPacket.indexOf("P"+str(i)+":") + str(i).length()+2;
         read_end = arduinoPacket.indexOf("T"+str(i+1)+":");
         P[i] = arduinoPacket.substring(read_srt, read_end);
         //read flow rate
         read_srt = arduinoPacket.indexOf("F"+str(i)+":") + str(i).length()+2;
         read_end = arduinoPacket.indexOf("P"+str(i)+":");
         F[i] = arduinoPacket.substring(read_srt, read_end);
         if (float(T[i])>100) {
           state=29;
         }
         if (float(P[i])>1) {
         state=30;
       }
     }
    
     //read last entry at final statepoint
     //read temperature
     read_srt = arduinoPacket.indexOf("T"+str(n_SPs-1)+":") + str(n_SPs-1).length()+2;
     read_end = arduinoPacket.indexOf("F"+str(n_SPs-1)+":");
     T[n_SPs-1] = arduinoPacket.substring(read_srt, read_end);
     //read pressure
     read_srt = arduinoPacket.indexOf("P"+str(n_SPs-1)+":") + str(n_SPs-1).length()+2;
     read_end = arduinoPacket.indexOf("L1:");
     P[n_SPs-1] = arduinoPacket.substring(read_srt, read_end);
     //read flow rate
     read_srt = arduinoPacket.indexOf("F"+str(n_SPs-1)+":") + str(n_SPs-1).length()+2;
     read_end = arduinoPacket.indexOf("P"+str(n_SPs-1)+":");
     F[n_SPs-1] = arduinoPacket.substring(read_srt, read_end);
     //read level 1 - water level
     read_srt = arduinoPacket.indexOf("L1:") + 3;
     read_end = arduinoPacket.indexOf("L2:");
     Lev_water = int(arduinoPacket.substring(read_srt, read_end));
     //read level 2 - column extration water level
     read_srt = arduinoPacket.indexOf("L2:") + 3;
     read_end = arduinoPacket.indexOf("L3:");
     Lev_col = int(arduinoPacket.substring(read_srt, read_end));
     //read level 3 - FPS level
     read_srt = arduinoPacket.indexOf("L3:") + 3;
     read_end = arduinoPacket.indexOf("state");
     Lev_FPS = int(arduinoPacket.substring(read_srt, read_end));
     //read state, but protect current error state
     read_srt = arduinoPacket.indexOf("state:") + 6;
     read_end = arduinoPacket.indexOf("end");
     if (state<28) {
       state = int(arduinoPacket.substring(read_srt, read_end));
         }
      }
     catch (RuntimeException  e) {
       println("Waiting For Clean Serial Packet");
       nSerialError++;
     }
       }
    

    And here is the new draw section:

    void draw()
    {
    //Draw background
    background(38, 38, 38);
    fill(21, 21, 21);
    rect(0, 0, 196, 800);
    
    //Select current state image
    tabselect(); 
    
    //Draw tab and buttons
    image(tab_img, 0, 0, 1280, 800);
    image(mode_img, 39, 158);
    
    //Propogate side bar text
    textFont(text_status);
    statusselect();
    textAlign(CENTER);
    text(status, 99.334, 515);
    fill(0, 189, 155);
    textFont(text_cooling);
    text(Q_cool, 99.334, 670);
    
     if (tWrite<(millis()-timeDataWrite) && plot_index>3)
     {
       //Setup data write
       //runAppendRowChoreo();
       timeDataWrite = millis();
     }
    
      // PFD TAB DRAWING ----------------------------------------------------------------
    //Draw pump heads
    if (tab_cur=="PFD") {
      fill(191, 191, 191);
      noStroke();
      rotation();
     try {
      //circulation pump
    
      //pushMatrix();
      //translate((456+3.465/2), (639+14.571/2));
      //rotate(rot_circ);
      //rect(-3.465/2, -14.571/2, 3.465, 14.571);
      //popMatrix();
    
      ////coolant pump
      //pushMatrix();
      //translate((449.441+3.465/2), (362.833+14.571/2));
      //rotate(rot_cool);
      //rect(-3.465/2, -14.571/2, 3.465, 14.571);
      //popMatrix();
    
      ////thermal recovery pump
      //pushMatrix();
      //translate((595.862+3.465/2), (301.785+14.571/2));
      //rotate(rot_tr);
      //rect(-3.465/2, -14.571/2, 3.465, 14.571);
      //popMatrix();
    
      ////FPS extraction pump
      //pushMatrix();
      //translate((911+14.571/2), (659.5+3.465/2));
      //rotate(-rot_FPS);
      //rect(-14.571/2, -3.465/2, 14.571, 3.465);
      //popMatrix();
    
      ////water extraction pump
      //pushMatrix();
      //translate((1178+3.465/2), (672.775+14.571/2));
      //rotate(rot_water);
      //rect(-3.465/2, -14.571/2, 3.465, 14.571);
      //popMatrix();
    }
    catch (RuntimeException  e) {
      println("Push Called Too Many Times");
      nPushError++;
    }
    
    //Propogate temperatures, flow rates, levels, and pressures
    textFont(text_PFD);
    fill(255, 255, 255);
    try {
      for (int i=0; i <= n_SPs - 1; i++) {
        if (float(T[i])>100) {
          fill(254, 104, 24);
          state=29;
        }
        text(T[i]+"C", x_T[i], y_T[i]);
        fill(255, 255, 255);
        if (float(P[i])>1) {
          fill(254, 104, 24);
          state=30;
        }
        text(P[i]+"bar", x_P[i], y_P[i]);
        fill(255, 255, 255);
        if (float(F[i])>10) {
          fill(254, 104, 24);
        }
        text(F[i]+"LPM", x_F[i], y_F[i]);
      }
      //Propogate tank levels
      //water tank
      translate(296.71, 268);
      fill(22, 157, 228);
      rect(0, 0, 81.3, -57*(float(Lev_water)-1)/2);
      translate(-296.71, -268);
      //FPS Column tank
      translate(899.52, 575);
      fill(0, 189, 155);
      rect(0, 0, 37.45, -38.815*(float(Lev_FPS)-1)/2);
      translate(-899.52, -575);
      //water Column tank
      translate(1089.9, 633);
      fill(22, 157, 228);
      rect(0, 0, 58.3, -26.15*(float(Lev_col)-1)/2);
      translate(-1089.9, -633);
     }
     catch (RuntimeException  e) {
      println("Waiting For State Point Read");
      nSerialError++;
    }
    }
    
      // TIME SERIES TAB DRAWING ----------------------------------------------------------------
    if (tab_cur=="TS") {
     if (t_plot<(millis()-time_plotwrite))
      {
        try {
         draw_plot = 1;
          t_plot_max = hour()+minute()/60.+second()/3600.;
          plot.addPoint(float(plot_index), float(T[0]));
          plot.getLayer("SP6").addPoint(float(plot_index), float(T[5]));
          plot.getLayer("SP7").addPoint(float(plot_index), float(T[6]));
          plot.getLayer("SP9").addPoint(float(plot_index), float(T[8]));
          plot.getLayer("SP10").addPoint(float(plot_index), float(T[9]));
         plot.getLayer("SP14").addPoint(float(plot_index), float(T[13]));
    
         if (plot_index>n_plotpoints) {
           plot.removePoint(0);
           t_plot_min = hour()+minute()/60.+second()/3600. - n_plotpoints*t_plot/3600000.;
           if ( t_plot_min<0) {
             t_plot_min = t_plot_min+24.;
          }
        }
        plot_index = plot_index+1;
      }
      catch (RuntimeException  e) {
        println("Waiting For Clean Serial Packet");
        nSerialError++;
      }
       time_plotwrite = millis();
     }
    
    
     try {
      //draw legend
      fill(250, 250, 250);
      textFont(text_PFD);
      textAlign(LEFT);
      text(N[0], 1100, 161);
      text(N[5], 1100, 196);
      text(N[6], 1100, 229);
      text(N[8], 1100, 264);
      text(N[9], 1100, 298);
      text(N[13], 1100, 332);
    
      if (plot_index>1) {
        plot.setLineColor(color(174, 202, 23));
        plot.getLayer("SP6").setLineColor(color(246, 195, 0));
        plot.getLayer("SP7").setLineColor(color(0, 189, 155));
        plot.getLayer("SP9").setLineColor(color(22, 157, 228));
        plot.getLayer("SP10").setLineColor(color(254, 140, 24));
        plot.getLayer("SP14").setLineColor(color(210, 82, 65));
        plot.setPointColor(color(174, 202, 23));
        plot.getLayer("SP6").setPointColor(color(246, 195, 0));
        plot.getLayer("SP7").setPointColor(color(0, 189, 155));
        plot.getLayer("SP9").setPointColor(color(22, 157, 228));
        plot.getLayer("SP10").setPointColor(color(254, 140, 24));
        plot.getLayer("SP14").setPointColor(color(210, 82, 65));
        plot.setPointSize(3);
        plot.getLayer("SP6").setPointSize(3);
        plot.getLayer("SP7").setPointSize(3);
        plot.getLayer("SP9").setPointSize(3);
        plot.getLayer("SP10").setPointSize(3);
        plot.getLayer("SP14").setPointSize(3);
        plot.setLineWidth(3);
        plot.getLayer("SP6").setLineWidth(3);
        plot.getLayer("SP7").setLineWidth(3);
        plot.getLayer("SP9").setLineWidth(3);
        plot.getLayer("SP10").setLineWidth(3);
        plot.getLayer("SP14").setLineWidth(3);
      }
    
      if (plot_index>n_plotpoints) {
        plot.setXLim((per_plot_min/100.)*n_plotpoints+(plot_index-n_plotpoints), plot_index-1-(100-per_plot_max)/100.*n_plotpoints);
      } else {
        plot.setXLim(max(1, per_plot_min/100.*plot_index), max(1, plot_index*per_plot_max/100.-1));
      }
      plot.beginDraw();
      plot.drawBackground();
      plot.drawBox();
      plot.drawXAxis();
      plot.drawYAxis();
      plot.drawTitle();
      plot.drawGridLines(GPlot.HORIZONTAL);
      plot.drawLines();
      plot.drawPoints();
      plot.drawLabels();
      plot.drawLegend(new String[] {"SP1", "SP6", "SP7", "SP9", "SP10", "SP14"}, 
        new float[] {1.1, 1.1, 1.1, 1.1, 1.1, 1.1}, 
        new float[] {0.9375, 0.875, 0.8125, 0.75, 0.6875, 0.625});
      plot.endDraw();
    
      //draw slider
      noStroke();
      fill(83, 83, 83);
      rect(320, 736-5, 700, 10);
      ellipse(320, 736, 10, 10);
      ellipse(1020, 736, 10, 10);
      fill(191, 191, 191); 
      low_bar_x = min(320.+per_plot_min/100.*700., high_bar_x);
      high_bar_x = max(1020.-(1-per_plot_max/100.)*700., low_bar_x);
      rect(low_bar_x, 736-5, high_bar_x-low_bar_x, 10);
      fill(255, 255, 255); 
      ellipse(low_bar_x, 736, 20, 20);
      ellipse(high_bar_x, 736, 20, 20);
    
      //overwrite x axis
      fill(38, 38, 38);
      rect(300, 675, 750, 35);
      rect(307, 105, 10, 600);
      fill(255, 255, 255);
      if (plot_index>1) {
        t_plot_min_adj = t_plot_min+per_plot_min/100.*(min(n_plotpoints, plot_index)-1)*t_plot/3600000.;
        t_step = (min(n_plotpoints, plot_index)-1)*t_plot/3600000.*(per_plot_max/100.- per_plot_min/100.)/(n_labels-1.);
        for (int i=0; i <= n_labels-1; i++) {
          t_plot_print = t_plot_min_adj+t_step*i;
          if (t_plot_print>24.) {
            t_plot_print=t_plot_print-24.;
          }
           text(nfc(t_plot_print, 2), 310+i*680./(n_labels-1.), 690);
         }
       }
     }
      catch (RuntimeException  e) {
      println("Plotting Error");
      nPlotError++;
       }
      }
      // DIRECT OUTPUT TAB DRAWING ----------------------------------------------------------------
      if (tab_cur=="DO") {
    
    
    //report temps, flows, and pressures
    textFont(text_PFD);
    int x_table = 450;
    int y_table = 150;
    int text_space = 24;
    int x_space = 125;
    fill(38, 38, 38);
    stroke(255, 255, 255);
    //rect(x_table-50,y_table-50,625,650);
    line(x_table-25, y_table+text_space+6, x_table-25+575, y_table+text_space+6);
    noStroke();
    fill(255, 255, 255);
    textAlign(CENTER);
    text("SP", x_table, y_table+text_space);
    text("Name", x_table+x_space, y_table+text_space);
    text("Temperature", x_table+x_space*2, y_table);
    text("[C]", x_table+x_space*2, y_table+text_space);
    text("Pressure", x_table+x_space*3, y_table);
    text("[bar]", x_table+x_space*3, y_table+text_space);
    text("Flow", x_table+x_space*4, y_table);
    text("[LPM]", x_table+x_space*4, y_table+text_space);
    int k=0;
    try {
      for (int i=0; i <= n_SPs - 1; i++) {
        if (is_not_dup[i]) {
          if ((k+2)%2==0) {
            fill(18, 18, 18);
            rect(x_table-25, y_table+text_space*(k+1)+7, 576, text_space);
            fill(255, 255, 255);
          }
          text(str(i+1), x_table, y_table+text_space*(k+2));
          text(N[i], x_table+x_space, y_table+text_space*(k+2));
          if (float(T[i])>100) {
            fill(254, 104, 24);
            state=29;
          }
          text(T[i], x_table+x_space*2, y_table+text_space*(k+2));
          fill(255, 255, 255);
          if (float(P[i])>1) {
            fill(254, 104, 24);
            state=30;
          }
          text(P[i], x_table+x_space*3, y_table+text_space*(k+2));
          fill(255, 255, 255);
          if (float(F[i])>10) {
            fill(254, 104, 24);
          }
          text(F[i], x_table+x_space*4, y_table+text_space*(k+2));
          k++;
        }
      }
      textAlign(LEFT);
      text("Water Level:"+Lev_water, x_table-10, y_table+text_space*(k+3));
      text("Column Level:"+Lev_col, x_table-10, y_table+text_space*(k+4));
      text("FPS Level:"+Lev_FPS, x_table-10, y_table+text_space*(k+5));
      text("State:"+state, x_table-10, y_table+text_space*(k+6));
    
      text("Serial Catch:"+str(nSerialError), x_table-10, y_table+text_space*(k+7));
      text("Plot Catch:"+str(nPlotError), x_table-10, y_table+text_space*(k+8));
      text("Push Catch:"+str(nPushError), x_table-10, y_table+text_space*(k+9));
    }
    catch (RuntimeException  e) {
      println("Waiting For State Point Read");
      nSerialError++;
      }
     }
      }
    

    There are no calls that effect any kind of draw outside the draw thread. I added you thread tracking code and its working, but I am having trouble learning much. I am starting a new test now, but will it report the tread that was active when the crash occurs?

    As usual, thanks for the help!

  • Update: On crash, no thread info is generated. Which makes sense. I was just hoping it would happen.

  • Add the following method

    void keyPressed() {
      if(key == 't')
        ThreadInfo.printAllThreadInfo();
    }
    

    You aren't creating any additional threads yourself so pressing and releasing the 't' key will display the current threads. It should show whether the serial port is being accessed in another thread.

Sign In or Register to comment.