Panelui

1. Introduction

Panelui is a userspace component to interface buttons to linuxcnc or HAL.
It decodes MESA 7I73 style key-scan codes and calls the appropriate routine.
It gets input from a realtime component - sampler.
Sampler gets it’s input from either the MESA 7i73 or sim_matrix_kb component.
Panelui is configurable using an INI style text file to define button types, HAL pin types, and/or commands.

It can be extended using a Python based handler file to add functions.
While actual input buttons are required to be momentary, Panelui will use this input to make toggle, radio, or momentary button output.

2. Loading Commands

The command used to load panelui (with optional -d debug switch):

loadusr -W panelui -d

This will initialize panelui, which will look for the INI file panelui.ini in the config folder or user folder.

One can validate the INI file with this command:

loadusr pyui

This will read, try to correct, then save the panelui.ini file. It will print errors to the terminal if found.

A typical HAL file will have these commands added:

# commands needed for panelui loading
#
# sampler is needed for panelui
# cfg= must always be u for panelui. depth sets the available buffer
loadrt sampler cfg=u depth=1025

#uncomment to validate the panelui INI file
#loadusr pyui

# -d = debug, -v = verbose debug
# -d will show you keypress identification and commands called
# -v is for develeper info
loadusr -W panelui -d

# using simulated buttons instead of the MESA 7I73 card
# so we load the sim_matrix_kb component to convert HAL pins to keyscan codes
loadrt sim_matrix_kb

# connect the components together.
# sampler talks to panelui internally
net key-scan    sim-matrix-kb.0.out
net key-scan    sampler.0.pin.0

# add panelui components to a thread

addf sim-matrix-kb.0    servo-thread
addf sampler.0          servo-thread

3. panelui.ini file reference

Key words
  • KEY= This is used to designate the key that the button responds to. It can be NONE or ROW number and column number eg R1C2. A row and column can only be used once.

  • OUTPUT= This sets the Button’s output type, eg S32, U32, FLOAT, BIT, NONE, COMMAND

  • DEFAULT= This sets the starting output of the group or button.

  • GROUP= In radiobuttons, designates the group the button interacts with.

  • GROUP_OUTPUT= sets the output the group pin will be, if this button is active.

  • STATUS_PIN= If TRUE, a HAL pin will be added that reflects the current state of button.

  • TRUE_STATE= sets the output the HAL pin will be, if button is TRUE

  • FALSE_STATE= sets the OUTPUT the HAL pin will be, if the button is FALSE

  • TRUE_COMMAND= sets the command and arguments to be called when the button is TRUE

  • FALSE_COMMAND= sets the command and arguments to be called when the button is FALSE.

HAL Prefix
[HAL_PREFIX]
    NAME= Yourname

This allows one to change the prefix of the HAL pins from panelui to an arbitrary name.

Radio Buttons

Radiobutons allow only one button in the group to be active at a time.
Each group has its own output pin, separate from each button in the group.
Radio button definitions start with the text RADIO_BUTTON inside single brackets.

[RADIO_BUTTONS]
        # The double bracket section(s) define the group(s) of radio buttons.
        # The group name must be unique and is case sensitive.
        # Groups output is controlled by what button is active not directly by keycode.
        # DEFAULT references a button in the group by name and is case sensitive.
        [[group1_name]]
            KEY = NONE
            OUTPUT = FLOAT
            DEFAULT = small
            # The triple bracket sections define the buttons in this group.
            # button names must be unique and are case sensitive.
            # There must be at least two buttons in a group.
            #
            # This button, named 'small'is controller by the row 0 column 1 key.
            # It will cause the group output to be .0001 when it is pressed.
            # It has no output of it's own, but has a status
            # pin which will follow it's current state.
            # since this button is in a group, DEFAULT has no bearing.
            # since OUTPUT in not 'COMMAND' _COMMAND entries are ignored.
            [[[small]]]
                KEY = R0C1
                GROUP = group1_name
                GROUP_OUTPUT = .0001
                OUTPUT = NONE
                STATUS_PIN = True
                TRUE_STATE = TRUE
                FALSE_STATE = FALSE
                TRUE_COMMAND = NONE, NONE
                FALSE_COMMAND = NONE, NONE
                DEFAULT = false
            # This button, named 'large' is controller by the row 0 column 2 key.
            # It will cause the group output to be 1000 when it is pressed.
            # It has a S32 output of it's own, will be 20 on true and 0 on false.
            # It also has a status pin which will follow it's current state.
            # since this button is in a group, DEFAULT has no bearing.
            # since OUTPUT in not 'COMMAND' _COMMAND entries are ignored.
            [[[large]]]
                KEY = R0C2
                GROUP = group1_name
                GROUP_OUTPUT = 1000
                OUTPUT = S32
                STATUS_PIN = True
                TRUE_STATE = 20
                TRUE_COMMAND = NONE, NONE
                FALSE_COMMAND = NONE, NONE
                FALSE_STATE = 0
                DEFAULT = false
Toggle Buttons

Togglebuttons only change state on each press of the button. Toggle button definitions start with the text TOGGLE_BUTTON inside single brackets.

[TOGGLE_BUTTONS]
    # Each button name inside double brackets, must be unique and is case sensitive.
    # This button, named 'tool_change'is controller by the row 2 column 5 key.
    # It has a BIT output, will output 1 on true state and 0 on false state.
    # It also has a status pin which will follow it's current state.
    # DEFAULT sets this to true when first initialized.
    # The _COMMAND are not used since OUTPUT is not set to COMMAND but validation will
    # add the lines regardless
    [[tool_change]]
        KEY = R2C5
        OUTPUT = BIT
        TRUE_COMMAND = NONE, NONE
        FALSE_COMMAND = NONE, NONE
        STATUS_PIN = True
        DEFAULT = TRUE
        TRUE_STATE = 1
        FALSE_STATE = 0
Momentary Buttons

Momentary buttons are true when pressed and false when released. Momentary button definitions start with the text MOMENTARY_BUTTON inside single brackets.

[MOMENTARY_BUTTONS]
    # Each button name inside double brackets, must be unique and is case sensitive.
    # This button, named 'spindle_rev'is controller by the row 2 column 3 key.
    # It has a COMMAND output, so will use TRUE_COMMAND and FALSE_COMMAND.
    # It also has a status pin which will follow it's current state.
    # COMMANDs will have a command name and then any required arguments
    # This TRUE_COMMAND calls an internal command to start the spindle in reverse at 200 rpm
    # If the spindle is already started, it will increase the rpm.
    # DEFAULT is not used with Momentary buttons.
    # The _STATE are not used since OUTPUT is set to COMMAND but validation will
    # add the lines regardless
    [[spindle_rev]]
        KEY = R2C3
        OUTPUT = COMMAND
        TRUE_COMMAND = SPINDLE_REVERSE_INCREASE, 200
        FALSE_COMMAND = None, NONE
        STATUS_PIN = True
        DEFAULT = FALSE
        TRUE_STATE = 1
        FALSE_STATE = 0

4. Internal Command reference

There are a number of internal commands you may use.

mist_on

mist_off

flood_on

flood_off

estop

estop_reset

machine_off

machine_on

home_all

unhome_all

home_selected
  • required argument: axis number (int)

unhome_selected
  • required argument: axis number (int)

spindle_forward_adjust
  • optional argument: starting RPM (int) - default 100

  • Description: If the spindle is stopped it will start in the forward direction. If it is already running it will increase or decrease the rpm depending on what direction the spindle is running in.

spindle_forward
  • optional argument: starting RPM (int) - default 100

spindle_stop

spindle_reverse
  • optional argument: starting RPM (int) - default 100

spindle_reverse_adjust
  • optional argument: starting RPM (int) - default 100

  • Description: If the spindle is stopped it will start in the reverse direction. If it is already running it will increase or decrease the rpm depending on what direction the spindle is running in.

spindle_faster
  • Description: increases spindle speed by 100 RPM

spindle_slower
  • Description: decreases spindle speed by 100 RPM, until RPM is 100

set_linear_jog_velocity
  • required argument: velocity in inches per minute (float)

  • description: sets the jog velocity on axis 0,1,2,6,7,8 (X,Y,Z,U,V,W)

set_angular_jog_velocity
  • required argument: velocity in degrees per minute (float)

  • description: sets the jog velocity on axis 3,4,5 (A.B.C)

continuous_jog
  • required arguments: axis number (int), direction (int)

incremental_jog
  • required arguments: axis number (int), direction (int), distance (float)

quill_up
  • optional arguments: machine Z axis absolute position (float)

  • Description: Move Z axis to the given machine position

feed_hold
  • required argument: state (bool 0 or 1)

feed_override
  • required argument: rate (float)

rapid_override
  • required argument: rate (float 0-1)

spindle_override
  • required argument: rate (float)

max_velocity
  • required argument: rate (float)

reload_tooltable

optional_stop
  • required argument: state (bool 0 or 1)

block_delete
  • required argument: state (bool 0 or 1)

abort

pause

resume

single_block
  • required argument: state (bool 0 or 1)

smart_cycle_start
  • Description: If idle, starts gcode program, if paused runs one line.

re_start line
  • required argument: line number (int)

mdi_and_return
  • required argument: Gcode command(s)

  • Description: records the current mode, calls commands and then returns to mode.

mdi
  • required argument: Gcode command(s)

  • Description: sets mode to MDI, calls commands.

5. Handler File Extension

A special file can be used to add custom python code that will be available as commands. panelui_handler.py must be written in python and be placed in the configuration folder. If panelui finds a file there it will add it’s function calls to the available commands. Here is an example of a handler file that adds two functions - hello_world and cycle_mode:

# standard handler call - This will always be required
def get_handlers(linuxcnc_stat, linucnc_cmd, commands, master):
     return [HandlerClass(linuxcnc_stat, linucnc_cmd, commands, master)]

# Also required - handler class
class HandlerClass:

    # This will be pretty standard to gain access to everything
    # linuxcnc_stat: is the python status instance of linuxcnc
    # linuxcnc_cmd: is the python command instance of linuxcnc
    # commands: is the command instance so one can call the internal routines
    # master: give access to the master functions/data

    def __init__(self, linuxcnc_stat, linuxcnc_cmd, commands, master):
        self.parent = commands
        self.current_mode = 0

    # command functions are expected to have this layout:
    # def some_name(self, widget_instance, arguments from widget):
    # widget_instance gives access to the calling widget's function/data
    # arguments can be a list of arguments, a single argument, or None
    # depending on what was given in panelui's INI file.
    def hello_world(self, wname, m):
        # print to terminal so we know it worked
        print '\nHello world\n'
        print m     # print the argument(s)
        print wname.metadata    # Print the calling widgets internal metadata (from config file)

        # call a mdi command to print a msg in linuxcnc
        # This requires linuxcnc to be homed, but does not check for that.
        # parent commands expect a widget_instance - None is substituted
        self.parent.mdi(None,'(MSG, Hello Linuxcnc World!)')

    # Each call to this function will cycle the mode of linuxcnc
    def cycle_mode(self, wname, m):
        if self.current_mode == 0:
            self.current_mode = 1
            self.parent.set_mdi_mode()
        elif self.current_mode == 1:
            self.current_mode = 2
            self.parent.set_auto_mode()
        else:
            self.current_mode = 0
            self.parent.set_manual_mode()
        print self.current_mode

    # Boiler code, often required
    def __getitem__(self, item):
        return getattr(self, item)
    def __setitem__(self, item, value):
        return setattr(self, item, value)