Part 4b

Testing Periodic for Errors

Add a Test Button

  1. Open up gui4.glade and click on the button bar then pick the editor. In the Hierarchy tab add a button. Change the Name: to test_error then press the enter key or it might not take then change Stock Id: to Error then close the Tool Bar Editor.

    Your project should look like this now.

    images/gui-04-02.png
  2. Click on the new button and check that the Name: is correct then on the Signals tab add the on_test_error_clicked handler to the GtkToolButton clicked signal and don’t forget to press enter so it will save.

    Your project should look like this now.

    images/gui-04-03.png

The Python

  1. Open up gui4.py and add this function to our code. We have an intentional typo in the code. If this code is run in the periodic function we would not get any error reported to the terminal and periodic would just quit. This way we can test for errors in our code before adding them to the periodic function.

def on_test_error_clicked(self, widget, data=None):
  self.status.poll()
  data = self.status.actual_position[2]
  text = "% 9.4f"% (data)
  self.builder.get_object("dro_zz").set_text(text)
gui4.py
#!/usr/bin/env python

import gtk
import gobject
import gladevcp.makepins
from gladevcp.gladebuilder import GladeBuilder
import hal
import sys,os

# set up paths to files
BASE = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), ".."))
libdir = os.path.join(BASE, "lib", "python")
sys.path.insert(0, libdir)
datadir = os.path.join(BASE, "share", "linuxcnc")
xmlname = os.path.join(datadir,"gui4.glade")

import linuxcnc

class gui3(object):

  def __init__(self):
    self.emc = linuxcnc
    self.error_channel = self.emc.error_channel()
    self.status = self.emc.stat()
    self.builder = gtk.Builder()
    self.builder.add_from_file(xmlname)
    self.halcomp = hal.component("gui4")
    self.builder.connect_signals(self)
    self.window = self.builder.get_object("window1")
    self.statusbar = self.builder.get_object("statusbar1")
    self.window.show()
    self.panel = gladevcp.makepins.GladePanel(self.halcomp, xmlname, self.builder, None)
    self.halcomp.ready()
    # since the main loop is needed to handle the UI and its events, blocking calls like sleep()
    # will block the UI as well, so everything goes through event handlers (aka callbacks)
    # The gobject.timeout_add() function sets a function to be called at regular intervals
    # the time between calls to the function, in milliseconds
    gobject.timeout_add(100, self.periodic) # time between calls to the function, in milliseconds
    self.machine_status = 0

  def periodic(self): # fetch status items and update screen

    # poll the error channel
    self.error_status = self.error_channel.poll()
    if self.error_status:
      self.error_kind, self.error_text = self.error_status
      if self.error_kind in (linuxcnc.NML_ERROR, linuxcnc.OPERATOR_ERROR):
        self.error_type = "Error "
      else:
        self.error_type = "Info "
      self.message_id = self.statusbar.push(0, self.error_type + self.error_text)

    # poll the status channel
    self.status.poll()
    data = self.status.actual_position[0]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_x").set_text(text)

    data = self.status.actual_position[1]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_y").set_text(text)

    data = self.status.actual_position[2]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_z").set_text(text)

    return True # must return True to keep running

  def on_hal_stat1_mode_mdi(self, widget, data=None):
    self.mode_mdi = 1

  def on_test_error_clicked(self, widget, data=None):
    self.status.poll()
    data = self.status.actual_position[2]
    text = "% 9.4f"% (data)
    self.builder.get_object("dro_zz").set_text(text)

  def on_window1_destroy(self, widget, data=None):
    print "quit with cancel"
    gtk.main_quit()

  def on_gtk_quit_activate(self, menuitem, data=None):
    print "quit from menu"
    gtk.main_quit()

if __name__ == "__main__":
  app = gui3()
  gtk.main()

Testing the Code

  1. Copy the changed files like before with:

    sudo cp gui4 /usr/bin
    sudo cp gui4.glade /usr/share/linuxcnc
  2. Now run the GUI using the desktop launcher and your project should look like this now.

images/gui-04-04.png

Now when you press the error button you should see the error in the terminal. Because the builder could not find the object named dro_zz it could not set the text so you get the cryptic message about NoneType.

images/gui-04-05.png

To see the results of having an error in the periodic function change an object name, copy the changed python file to the installed location then run the configuration again and run a file and notice that nothing gets updated in the DRO tab because the periodic function had an error and has quit cycling.

Using the above process of editing and copying the files to the installed location as you build your GUI will be about the easiest way to test it as you build it.