Skip to content

ftkalcevic/hidcomp

Repository files navigation

#hidcomp - EMC/LinuxCNC USB HID interface component

Introduction

hidcomp is an EMC/LinuxCNC user mode component to provide access to USB HID devices. A HID device is a Human Interface Device, things like joysticks, gamepads, multimedia controllers (like the Shuttle Pro), and more exotic devices like barcode scanners, alphanumeric displays, medical instruments and home made USB pendants.

Why another HID interface component when EMC/LinuxCNC already has hal_input and hal_joystick?

  • hidcomp was written to support my home made USB pendant (this is another project, GenericHID)
  • hidcomp uses the low level USB protocols and does its own HID interfacing, so it can, or can be modified to, work with non-standard, or just more complex devices.
  • It supports additional controls on a device...
    • Encoder support, which allows devices like Contour Design's, Shuttle Pro to work
    • Alphanumeric displays, currently only supporting text mode displays
    • Hat switches.
    • Selector switches.
  • Adds scaling and shaping of analogue inputs (e.g. joystick axis)
  • hidconfig makes it easier to find and configure HID devices
  • Correctly finds and handles multiple identical devices, e.g. 2 Logitech gamepads

What doesn't hidcomp do?

  • It still only provides a set of HAL pins that need to be connected up to other HAL components in a .hal file. hidcomp doesn't help you multiplex buttons and switches.
  • Probably many things. I wrote hidcomp to support my USB devices, so it has only had minimal testing. However, USB devices are generally pretty simple, so it should work with most. If it doesn't, because hidcomp was written to interface devices at the lowest level, changes can be made to support them.

Installing hidcomp

hidcomp is only avaiable as this github source project. This was last built against LinuxCNC 2.7.4, and on the Debian Wheezy distribution.

###Building hidcomp

hidcomp/hidconfig are built against Qt4.5.1 using a static library. Get these using apt-get on the command line...

sudo apt-get install qt4-qmake libqt4-dev

The LinuxCNC source is required to build hidcomp. An environment variable, EMCPATH must be set to point to the linuxcnc directory, eg...

export EMCPATH=/home/frankt/emc2.core/emc2-dev

To build, first run...

qmake

then

make

the binaries are in hid/hidcomp/release/hidcomp and hid/hidconfig/release/hidconfig. There is also a debug build.

Changes to emc.nml/linuxcnc.nml

In order to support displaying EMC/LinuxCNC information on an LCD display, hidcomp must hook into the EMC/LinuxCNC messaging system. This is done by adding the following lines to the emc.nml/linuxcnc.nml file. (The file may be called something else - check for the NML_FILE parameter in the EMC section in the ini file)

P hidcomp       emcCommand      LOCAL   localhost       W       0       10.0    0       10
P hidcomp       emcStatus       LOCAL   localhost       R       0       10.0    0       10
P hidcomp       emcError        LOCAL   localhost       R       0       10.0    0       10					

Note - this change is only necessary if an LCD module is used.

Note 2 - The NML file now normally lives in /usr/share/linuxcnc/linuxcnc.nml. To customise your version, copy this file to your config directory and add the hidcomp lines. Don't forget to add the NML_FILE parameter to the EMC section of the ini file to tell EMC/LinuxCNC to use your version.

hidcomp

The hidcomp component provides a hal representation of a USB HID device. The pins exposed by hidcomp are defined using the hidconfig application.

Supported Controls

USB Data Type Common Usage Description
Input Value 1 Bit Button An input value which has a 1 bit data length is interpreted as a button, although it could be any digital input.
Input Value > 1 Bit Axis, Selector switch, jog Wheel, volume control An input value which has a data length greater than 1 bit, has its value exposed as an integer value. This may be an analogue joystick, or a selector switch.
Input Value > 1 Bit, with wrap Encoder When an input value has the wrap bit set in its description, the control is interpreted as an encoder. The wrap bit implies the counter wraps around to 0 when it hits its maximum value (or vice-versa).
Input Value > 1 Bit, usage=HATSWITCH Hat switch The hat switch is a special case of an input value. The devices sets the control's recommended usage to HATSWITCH. The data is then interpreted as a directional key press. If the key isn't pressed, an out of range value is returned.
Output Value 1 Bit LED An output value which has a 1 bit data length is interpreted as an LED, although it could be any digital output.
Output Value > 1 Bit Multi-Colour LED The Generic HID device can support bi-colour and tri-colour LEDs, which is how these devices are set. Only a simple integer output is supported at this time.
USAGE=ALPHA_NUMERIC_DISPLAY LCD

hidcomp supports standard character only alphanumeric displays. It has been tested with 1x8, 2x20 and 4x20 displays, but should be able to cope with any size.

This has only been tested against a home made USB Alphanumeric display, and as such, may need to be tweaked to make work with other displays. The requirements at the moment are...

  • USAGE_ROWS and USAGE_COLUMNS must appear in a feature report.
  • USAGE_ROW, USAGE_COLUMN, USAGE_CLEAR_DISPLAY and USAGE_DISPLAY_DATA must appear the output report to render the screen.
  • USAGE_DISPLAY_DATA must be a whole line long.

Synopsis

hidcomp [-ini inifile] [-d] [-n name] configfile ...

Options

-ini inifile
The ini file that is used to start EMC/LinuxCNC. This defaults to emc.ini. If it is not emc.ini, or in a location that hidcomp can't find it, it must be specified.

-d
Turn on debugging. Debugging sends volumous amounts of data to stderr. In order to catch the debug, start EMC/LinuxCNC on the command line and redirect stderr to a file. For example...
/usr/bin/linuxcnc mill.ini 2> logfile

-n name
Change the name of the component as seen by HAL. The default name is hidcomp.

configfile ...
One or more configuration files. These files are created with the hidconfig application. Each device is accessible in HAL as hidcomp.n, where n is the number of the device, starting at zero, as it appears on the command line.

Usage

hidcomp is a user space component so it must be loaded into EMC/LinuxCNC using loadusr...

loadusr -W hidcomp -ini lathe.ini pendant.hid
hidcomp can take a while to start, so it is recommended to use the -W option of loadusr to wait for the component to start.

If more than one USB device is used, there are two ways to support this.  First, two configuration files can be specified on the command line.  For example...

loadusr -W hidcomp -ini lathe.ini pendant1.hid pendant2.hid

This will make the two devices available as hidcomp.0.* and hidcomp.1.*

The other way to support multiple devices is to load hidcomp multiple times with different names.  For example...

loadusr -Wn joypad -name joypad -ini lathe.ini joypad.hid
loadusr -Wn gamepad -name gamepad -ini lathe.ini gamepad.hid 

The devices in the above example can then be accessed as joypad.0.* and gamepad.0.*

Exported Pins

When run, hidcomp will export a large number of pins based on the definition in the configuration file. These can then be used in the EMC/LinuxCNC HAL file to control parts of the EMC/LinuxCNC machine, usually via halui(1).

The exported pins are defined in the configuration file created by hidconfig. The name of each control (button, axis, encoder, etc) can be changed using hidconfig but the suffix remains the same.

<!-- Hatswitch Switch -->
<tr>
	<td rowspan="2">Hat switch</td>
	<td>*.raw</td>
		<td>s32</td>
		<td>out</td>
		<td>The raw value from hat switch control.  Usually 0 to 7 
	representing the 8 directions, and a number outside this range, 
	e.g. 8, meaning not pressed</td>
</tr>
<tr>		       		
	<td>*.direction</td>
	<td>float</td>
		<td>out</td>
	<td>The direction the switch has been pressed in degrees, 0-315&deg; for an 8 position switch.  -1 represents no press.</td>
</tr>

<!-- Value -->
<tr>
	<td rowspan="3">Value (axis)</td>
	<td>*.raw</td>
		<td>s32</td>
		<td>out</td>
		<td>The raw value from control.  The range varies. </td>
</tr>
<tr>		       		
	<td>*.ivalue</td>
	<td>u32</td>
		<td>out</td>
	<td>The scaled *.raw value as an u32 type.  Scaling is configured using the <b>hidconfig</b> application.</td>
</tr>
<tr>		       		
	<td>*.fvalue</td>
	<td>float</td>
		<td>out</td>
	<td>
		The scaled *.raw value as a float type.  Scaling is configured using the <b>hidconfig</b> application.  
		Scaling is usually configured by user to make this value range from -1.0 to 1.0
	</td>
</tr>

<!-- Encoder -->
<tr>
	<td rowspan="4">Encoder</td>
	<td>*.raw</td>
		<td>s32</td>
		<td>out</td>
		<td>The raw value from control.  The range varies. </td>
</tr>
<tr>		       		
	<td>*.count</td>
	<td>s32</td>
		<td>out</td>
	<td>The accumulated count value as an integer.</td>
</tr>
<tr>		       		
	<td>*.position</td>
	<td>float</td>
		<td>out</td>
	<td>The accumulated count value, scaled to a floating point value.  Scaling is set using the <b>hidconfig</b> application.</td>
</tr>
<tr>		       		
	<td>*.reset</td>
	<td>bit</td>
		<td>io</td>
	<td>When the bit is set, the counter is reset to 0.  The *.reset bit is then set back to 0.</td>
</tr>

<!-- LED -->
<tr>
	<td>LED</td>
	<td>*.out</td>
		<td>bit</td>
		<td>in</td>
		<td>Toggle an LED on and off.  An LED can generically be used as a digital output.</td>
</tr>

<!-- Output Value -->
<tr>
	<td>Output Value</td>
	<td>*.ivalue</td>
		<td>s32</td>
		<td>in</td>
		<td>A generic output of data size > 1 bit.</td>
</tr>

<!-- LCD -->
<tr>
	<td rowspan="7">Alphanumeric Display</td>
	<td>*.page-select</td>
		<td>s32</td>
		<td>in</td>
		<td>Used to select a page of information on the 
	display.  Pages are user defined using <b>hidconfig</b>.</td>
</tr>
<tr>		       		
	<td>*.pages</td>
	<td>s32</td>
		<td>out</td>
	<td>Returns the number of user defined pages.  This is a pin so it can be connected to a page turning component to set the maximum number of pages at run time.</td>
</tr>
<tr>		       		
	<td>*.max-page</td>
	<td>s32</td>
		<td>out</td>
	<td>The same as *.pages - 1.  More useful because pages are number 0 to pages-1.</td>
</tr>
<tr>		       		
	<td>*.in-bit-n</td>
	<td>bit</td>
		<td>in</td>
	<td>User defined input bit.  Used to display items that are not available from <b>hidcomp</b>'s internal database base.  n can be any integer value.</td>
</tr>
<tr>		       		
	<td>*.in-float-n</td>
	<td>float</td>
		<td>in</td>
	<td>User defined input float.  Used to display items that are not available from <b>hidcomp</b>'s internal database base.  n can be any integer value.</td>
</tr>
<tr>		       		
	<td>*.in-s32-n</td>
	<td>s32</td>
		<td>in</td>
	<td>User defined input s32.  Used to display items that are not available from <b>hidcomp</b>'s internal database base.  n can be any integer value.</td>
</tr>
<tr>		       		
	<td>*.in-u32-n</td>
	<td>u32</td>
		<td>in</td>
	<td>User defined input u32.  Used to display items that are not available from <b>hidcomp</b>'s internal database base.  n can be any integer value.</td>
</tr>
Control Type Pin Suffix Data Type Direction Description
Button *.in bit out The button state. 1 when pressed, 0 when not pressed.
*.in-not bit out The inverted button state. 0 when pressed, 1 when not pressed.

The simplest way to list all of the pins is to add the loadusr hidcomp -ini my.ini device.hid line to an EMC/LinuxCNC hal file, run EMC/LinuxCNC, then browse the pins using the configuration browser. This is the "Show Hal Configuration" menu option in the "Machine" menu in Axis.

hidconfig

The hidconfig application is used to create configuration files used by hidcomp. This is a convenient way to find devices, identify controls and adjust the function of the controls.

Main screen

hidconfig is run from the command line...

hidconfig [file.hid]
optionally specifying an existing configuration file to edit. The default extension for the hidcomp configuration files is ".hid".

hidconfig is a graphical application built using Qt, so a graphical Windowing System must be running. The next image shows the start up screen.

To create a new configuration, hit the "New" button on the tool bar, or select "New" from the "File" menu. Alternatively, an existing file can be opened using the "Open" button, or "Open" menu item.

Selecting "New" will prompt with the "Select Device" dialog, shown below.

The "Select Device" dialog box will show a list of USB HID devices that have been recognised by hidconfig. Those devices that hidconfig has permission to access are shown with the full manufacturer name and device name. When hidconfig doesn't have permission to access a USB HID device, only the vendor id (VID) and product id (PID) are shown, with an asterisk (*) next to the name.

If all devices appear with an asterisk, you will not be able to configure any devices. The correct solution is set up the udev permissions correctly. See the section on permissions. A quick and dirty work around is to run hidconfig as root, i.e. use...

sudo hidconfig
But that is only a temporary solution. hidcomp wont work, and any configuration file you create will have root ownership permissions which you need to address.

When a device is loaded, hidconfig will show all the available controls in a functional display. Below is an screen shot of my Logitech dual action game pad.

The window is broken up into two parts: the "Device Search Criteria" frame (top part), and the "HID Device Input/Output items" (the large bottom part).

Device Search Criteria

The "Device Search Criteria" is used to identify the USB device. Most applications only use the VID and PID (Vendor ID and Product ID). This is fine if you only have one device.

If you only have one USB device, mark the PID and VID checkboxes.

This wont work, however, if you have more than one of the same device. You need to specify additional attributes to check when searching for the USB device. These can be the Manufacturer name, the Product name, the Serial Number (S/N), or the system id.

The Manufacturer name, Product name, and Serial Number are self explanatory and generally wont vary across identical devices. The system id, will always be unique. It represents the USB port that the device is plugged into. For two identical devices, this is the only way to distinguish them. As long as the device isn't moved from one USB port to another, it will always locate the same device.

The "Test Criteria" button can be used to check how many devices are found using the current criteria. You will be warned when saving the file if the criteria doesn't match exactly one device. This is important. If hidconfig cannot uniquely identify the device specified in the configuration file it will not be able to reload the file. Similarly, hidcomp will not be able to locate the USB device.

HID Device Input/Output items

The majority of the hidconfig display shows all of the USB device's controls and configuration laid out in a table.

Each row represents one of the device's controls. On the Logitech gamepad shown above, the first 4 rows show the joystick axis, then one row for the hat switch, 12 rows for the buttons and then 23 rows (only the first 3 shown) for some undocumented gamepad magic.

There are 5 columns in the table.

  1. Current Value - this shows the current raw value of the USB Device control. Use this to test and identify which control is which on the device.
  2. USB Name - the shows the USB Device allocated Usage Page and Usage. These are the suggested usages of the control.
  3. Enabled Check Box - unless the check box is ticked, the control will not be available.
  4. Hal Pin name - the unique pin name (prefix) for the control. This can be set to any meaningful name. The name must be unique among enabled pins. The total name length (hidcomp.n.<pin name>.suffixes) must not be more than 40 characters. This is checked before the configuration file is saved.
  5. Configuration button - some controls, value type and LCDs have additional configuration that can be accessed via the button.

Value Config Dialog

The Value Config Dialog is used to customise USB value controls. A screen shot is shown below.

Overrides

The first section of the dialog is the Overrides section. This allows modification of controls that don't behave as expected. Currently, the only control that misbehaves is the Wheel on the Shuttle Pro, which claims a Logical Min/Max of -128/127, but only generates values of -7/7.

The Type combo box doesn't do anything. Yet.

Output

The Output section controls the scaling of output values. Specify a min/max value, and the control's logical min/max will be scaled between them. The output type combo box is not used, as both a floating point scaled value (.fvalue) and a scaled integer value (.ivalue) are output.

The Reverse Axis check box will reverse the direction of the value. This can also be accomplished by swapping the min/max values (although the changes will only be visible when using the device in hidcomp).

Response

Checking the Use Response Curve check box will enable the response curve. This allows the behaviour of an axis to be changed. In the example above, there is a dead zone specified in the middle, and a non-linear behaviour when moved.

The display is broken up into two parts. The response curve plot, which shows the position of the raw input value as a vertical red line, and the control output, displayed as a single bar.

The nodes on the curve can be moved, added and deleted. When the mouse cursor is over a node, the mouse pointer will change to a hand. Click and drag the node.

Nodes are deleted by right clicking on them and selecting delete node from the context menu.

Nodes can be added by right clicking anywhere on the line and selecting add node from the context menu.

If changes are made to the curve, the curve is save as the "Custom" curve. The buttons at the bottom, "1", "2", "3", "4", and "Custom" can be used to cycle through the built-in curves and the custom curve. If a built-in curve is changed, the changes are saved to the custom curve.

The Snap to Grid check box helps align nodes. It only assists when moving nodes. It doesn't automatically move nodes that aren't aligned to the grid.

LCD Config Dialog

The LCD (Alphanumeric Display) interface is implemented as a series of pages containing display fields. Multiple pages can be defined and then selected using the *.page-select hal pin. Each page contains a series of formatted data fields. These fields display values that are present on hal input pins, or via a list of predefined values that hidcomp knows about.

The LCD Configuration dialog is shown below

Pages

On the left side of the dialog is the pages list. The "New Page" and "Delete Page" buttons below the list are used to add and remove pages.

Pages are always numbered consecutively from 0. The "Page Name" in the list is only used in hidconfig for information.

The up and down arrows to the right of the page list is used to change the order of the pages. Moving pages will change the page number.

In the example above, there are 3 pages. The main page, #0, is the default and will be shown at start-up. A button is wired to the hal updown counter component then wired to the .page-select pin to cycle through the pages. The tool change page, #2, is configured to be selected when a tool change is requested.

LCD Display

The top right section of the dialog shows a simulated LCD display. It will show the contents of each page as the page items are edited. The same display will also be shown on the LCD display of the USB Device.

Display Items

The table underneath the LCD display contains a list of all of the fields that will be displayed on a page. The example above shows an overly complex display, but is a good example of what can be done.

The table has 7 columns...

Column Description
Col The column number that data is to appear on. Column numbers start at 0.
Row The row number that data is to appear on. Row numbers start at 0.
Value What is to be displayed. This can be one of the build in data fields, or an external pin. The fields are listed below.
Format How the data is formatted. More on this below.
Scale A multiplier applied to the data before it is displayed. Only used on integer and floating point data fields. Typically used to convert 0-1 to 0-100%, or unit conversions.
Index Some data fields require an additional index. For example, the Actual Position field, requires an index to specify the axis (0=x, 1=y, 2=z, etc). When a format is selected, a tool tip will describe if an index is required.
Test Value Used to populate the LCD display with sample data. Use this field to test all values that may displayed in the LCD. In particular test min/max values to ensure fields don't overflow.

The "Refresh Period (ms)" field specifies how often the display should be updated.

Data Values

The data values displayed on the LCD can be selected from the internal database of known values, or a data value that has been set via an input pin. The list of all data values is listed in the table below...

Operator Error Operator Error Messages
Operator Text Operator Text Messages
Operator Display Operator Display Messages
Operator Message The last Operator Messages
Mode EMC/LinuxCNC Task Mode - 1=Manual, 2=Auto, 3=MDI
State EMC/LinuxCNC Task State - 1=E-Stop, 2=E-Stop/Reset, 3=Off, 4=On
Execution State EMC/LinuxCNC Executing state 1=Error, 2=Done, 3=Waiting for Motion, 4=Waiting for Motion Queue, 5=Waiting for IO, 6=Waiting for Pause, 7=Waiting for Motion and IO, 8=Waiting for Delay, 9=Waiting for System Cmd
Interpreter State EMC/LinuxCNC Interpreter state - 1=Idle, 2=Reading, 3=Paused, 4=Waiting
Motion Line The line in the GCode file that corresponds to the current motion position
Current Line The line in the GCode file that corresponds to the line the interpreter is looking at
Optional Stop State Optional Stop State
Block Delete State Block Delete State
GCode File Path The full path of the current GCode program
GCode File Name The file name of the current GCode program
GCode Command The current GCode command being interpreted
Active GCodes Active GCodes. Index from 0 to 15
Active MCodes Active MCodes. Index from 0 to 9
Active Settings Active settings. Index from 0 to 2
Paused Task Paused
Trajectory Mode Trajectory Mode 1=Free, 2=Coord, 3=Teleop
Trajectory Enabled Trajectory Enabled
In Position Motion in position
Paused Motion paused
Commanded Position[axis] Commanded Position for each axis. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Actual Position[axis] Actual Position for each axis. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
System Velocity System velocity for subsequent moves
System Acceleration System acceleration for subsequent moves
Last Probe Trip Pos[axis] Last probe trip position for each axis. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Probe Tripped Probe tripped since last clear // int EMC_TRAJ_STAT.probe_tripped; // Has the probe been tripped since the last // clear.
Probing We are currently probing
Probe Value Current probe value
Distance to Go Distance to go in current move
Distance to Go[axis] Distance to go for each individual axis. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Current Velocity Velocity of current move
Feedrate Override Enabled Feedrate override enabled
Spindle Override Enabled Spindle override enabled
Adaptive Feed Enabled Adaptive feed enabled
Feed Hold Enabled Feed Hold Enabled
FError[axis] Current following error for this axis. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Command Output Position[axis] Current Command Position for this axis. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Current Input Position[axis] Current Input Position for this axis. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
In Position[axis] The axis is currently at the requested position. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Homing[axis] The axis is currently homing. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Homed[axis] The axis is homed. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Fault[axis] The axis has faulted. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Enabled[axis] The axis is enabled. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Min Soft Limit[axis] The axis has exceeded the min soft limit. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Max Soft Limit[axis] The axis has exceeded the max soft limit. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Min Hard Limit[axis] The axis has exceeded the min hard limit. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Max Hard Limit[axis] The axis has exceeded the max hard limit. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Override Limits[axis] Override the limits. Axis numbers from 0-8 represent axis x,y,z,a,b,c,u,v,w
Spindle Speed Spindle speed in RPM
Spindle Direction Spindle direction. 0=stopped, 1=forward, -1=reverse
Spindle Brake Spindle brake. 0=released, 1=engaged
Spindle Increasing Spindle Speed Increasing. 1=increasing, -1=decreasing, 0=steady
Spindle Enabled Spindle enabled
Tool Prepped Tool ready for loading. 0 is no tool
Tool In Spindle Tool in spindle. 0 is no tool
Coolant-Mist Mist coolant. 0 - off, 1 - on
Coolant-Flood Flood coolant. 0 - off, 1 - on
E-Stop E-Stop - 0 means run, 1 stopped
Lube On Lube on - 0=off, 1=on
Lube Level Lube level - 0=low, 1=okay
User S32[index] Custom User S32 value on pin <device>.lcd-s32-<index>. Any Index values can be used
User U32[index] Custom User U32 value on pin <device>.lcd-u32-<index>. Any Index values can be used
User Float[index] Custom User Float value on pin <device>.lcd-float-<index>. Any Index values can be used
User Bit[index] Custom User Bit value on pin <device>.lcd-bit-<index>. Any Index values can be used

The last four rows show how to set up user defined data sources. By specifying a User data type and an index, hidcomp will provide a hal input pin for custom data. For example, selecting "User U32[index]" and index 17, hidcomp will create an input pin hidcomp.0.LCD.in-u32-17

Format

The LCD data fields are formatted using printf format strings. A format string can contains plain text and optionally an embedded format tag of the form...

%[flags][width][.precision][length]specifier
Note - it only make sense to use the correct format string for the correct data type, i.e. %d,%u for integers, %f,%g,%e for floating point values, etc. Using the incorrect format specifier will produce unpredictable results.

For a detailed description of the format string, see the printf(3) man page or do an internet search on printf.

In addition to all the standard printf format strings, a custom enumeration type, %b is also supported. The syntax of this format is as follows...

%[flags][width][.precision][length]:id,string[:id,string]:b
> As you can see, the format is the same as the printf syntax followed by a colon separated list of (id,string) pairs, followed by the specifier, b. id, is an integer that is matched against input data and the matching string is used as the output.  The id,string pair is used as the default when the data value does not match.  Internally, when the string is formatted, the (id,value):b data is stripped out and replaced with the s specifier, turning the format into a string format.  It only makes sense to use this format for integer data. 

For example, in the screen shot above, line 4 shows how to display an * (asterisk) when an axis has not been homed...

%1:0,*:1, :b
The formatting starts with the % (percent symbol) to indicate the formatting tag, followed by a 1 (one) to specify the field width. So far is a standard printf format. Then comes the : (colon), which indicates the first id,string pair. The first pair is 0,* which means if the data value is 0, display a *. The next pair is 1, (one comma space), which means if the value is one, display a space character. Additionally, because it is the last pair, a space character will be displayed if any other value is present. Internally, the value pairs are stripped from the format string and replaced with the s specifier, in this case leaving "%1s".

When designing a format string for data, make sure the final result is a fixed width string otherwise artefacts may be left on the screen. The example below shows the difference between using %d and %5d for formatting an integer value. The Acc column shows the accumulated result on the LCD after the value has been displayed. The Acc %5d column looks fine (dots are used to represent spaces). Acc %d however does not display the Value of 5 correctly - it has failed to erase the text underneath it. That's why a fixed width string format should be used to erase the previous contents

Value %d Acc %d %5d Acc %5d
1 1 1 ....1 ....1
123 123 123 ..123 ..123
5 5 523 ....5 ....5

When a Data Value is selected in the table, its default format string is selected, if no previous edits have been made to the existing format string.

User Fonts

hiconfig support user font characters.  Each display can have up to 8 user defined characters.  These characters are shared between the pages of the display.

Hit the "User Fonts" button to edit the fonts.  The "User Fonts" button only appears if the LCD display supports user defined fonts.  This shows the Edit Font dialog...

The font above is the degrees symbol.  Left click to set a dot.  Right click to clear a dot.  8 characters can be defined.

LCD External Access Port

The "LCD External Access Port" provides an external interface to the LCD display.  The port is a TCP Socket Port number, in the range 1 to 32767, that provides a simple text based interface to the LCD.  The port number can be any free port; I use 29090.

The External Access Port allows any application to connect to hidcomp and write directly to the LCD display.  It uses a series of simple text commands to access the LCD display.  All commands are terminated by a newline character ('\n' or 0x0A), and respond with "OK\n" if successful, or "?\n" when not.  The following is a list of the commands supported by the external interface. 

hello Connection initialisation command.  This currently doesn't do anything, but can be used to check if the display is present.
cls Clears the screen.  For displays that support different colours, this command will clear the display to to the current background colour.
fg R,G,B Sets the current foreground colour on devices that support colour.  R/G/B are the Red/Green/Blue components of the colour and range from 0-255.  For example, to set the foreground colour to red,

fg 255,0,0

bg R,G,B Sets the current background colour on devices that support colour.  R/G/B are the Red/Green/Blue components of the colour and range from 0-255.  For example, to set the background colour to black,

bg 0,0,0

text x, y, data Displays text on the screen at character position x,y.  data is a quoted string.  For graphic based devices, the current foreground and background colours are used. For example,

text 0,1, "Test string"

textp x, y, data Displays text on the screen at pixel position x,y.  data is a quoted string.  For graphic based devices, the current foreground and background colours are used. This will only work on devices that support pixel positioning.  For example,

textp 92,27, "Test string"

font id Changes the font to 'id'.  This only works on devices that support fonts.  For example,

font 0

backlight intensity Sets the LCD backlight to 'intensity' from 0-100.  0 is off.  Only works with devices that support changing the backlight intensity.  For eaxmple...

backlight 50

rect x,y,w,h Draw a rectangle with its top corner at (x,y), width w, and height h.  The rectangle is drawn with the current foreground colour. Only works with devices that support rectangles.  For example...

rect 0,0,320,240

fill x,y,w,h Draw a filled rectangle with its top corner at (x,y), width w, and height h.  The rectangle is filled with the current foreground colour. Only works with devices that support rectangles.  For example...

fill 0,0,320,240

A simple way to test the display is to use a telnet session...

> telnet localhost 29090
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
OK
cls
OK
text 0,0,"This is text line 1"
OK
^]
telnet> quit
Connection closed.

 

This is an example using python...

import socket

lcd = None host='localhost' port=29090 for i in range(10): try: lcd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) lcd.connect((host, port)) break except: pass

time.sleep(1)

if lcd == None: print "Failed to connect to LCD socket - host:" + host + ", port:" + port exit()

def cls(): lcd.send('cls\n')

def text(x,y,s): lcd.send('text ' + x + ',' + y + ', "' + s + '"\n')

cls() text(0,0,"Test string")

The external interface is useful for interactive displays.  See Lathe Pendant for an example.

Permissions

Note - this information applies to Ubuntu 8.04 and may or may not work for other versions.

When you insert a USB device, by default, the device is owned by root. As mentioned above, a quick and dirty fix is to run hidconfig as root but that will only allow a configuration file to be built, not run hidcomp.

The correct solution is to create a udev rules file. A file is create in /etc/udev/rules.d which tells udev (the dynamic device management system) what to do when the device is inserted. We only need to set permissions.

Here is an example of a udev rules file. In my /etc/udev/rules.d/ folder I have created the file 99-hid.rules. The name of the file is not important, as long as it has the extension .rules.

# Generic HID device
ATTR{idProduct}=="04d9", ATTR{idVendor}=="1c40", MODE="0660", GROUP="plugdev"
# Logitech dual action
ATTR{idProduct}=="c216", ATTR{idVendor}=="046d", MODE="0660", GROUP="plugdev"
# Contour design, shuttle pro
ATTR{idProduct}=="0030", ATTR{idVendor}=="0b33", MODE="0660", GROUP="plugdev"
Note - the rules syntax has changed. Use ATTR instead of SYSFS for newer versions of udev.
# Generic HID device
SYSFS{idProduct}=="04d9", SYSFS{idVendor}=="1c40", MODE="0660", GROUP="plugdev"
# Logitech dual action
SYSFS{idProduct}=="c216", SYSFS{idVendor}=="046d", MODE="0660", GROUP="plugdev"
# Contour design, shuttle pro
SYSFS{idProduct}=="0030", SYSFS{idVendor}=="0b33", MODE="0660", GROUP="plugdev"

In my file, each data line has 4 parts. The first two specify the PID and VID of the USB device that this line applies to. The last 2 parts refer to the commands to run when a device is found. In this case, we set the permissions on the device to 0660 (owner=read/write, group=read/write), and we set the group of the device to plugdev.

The lines beginning with # are comments.

For this file to work, there must also be a group on the system called plugdev, and the user account that runs EMC/LinuxCNC must belong to this group. This can be done with the commands...

sudo addgroup plugdev
sudo addgroup myloginname plugdev

To find the PID and VID of the USB device, run the lsusb command...

frankt@workshoppc:$ lsusb
Bus 004 Device 002: ID 05e3:0606 Genesys Logic, Inc. D-Link DUB-H4 USB 2.0 Hub
Bus 004 Device 001: ID 0000:0000
Bus 003 Device 001: ID 0000:0000
Bus 002 Device 001: ID 0000:0000
Bus 001 Device 017: ID 1c40:04d9
Bus 001 Device 016: ID 046d:c216 Logitech, Inc. Dual Action Gamepad
Bus 001 Device 015: ID 046d:c216 Logitech, Inc. Dual Action Gamepad
Bus 001 Device 014: ID 0b33:0030 Contour Design, Inc.
Bus 001 Device 009: ID 413c:2010 Dell Computer Corp.
Bus 001 Device 008: ID 0409:005a NEC Corp.
Bus 001 Device 007: ID 1532:0101
Bus 001 Device 006: ID 0079:0006
Bus 001 Device 005: ID 413c:1003 Dell Computer Corp.
Bus 001 Device 004: ID 05e3:0606 Genesys Logic, Inc. D-Link DUB-H4 USB 2.0 Hub
Bus 001 Device 003: ID 2001:f103 D-Link Corp. [hex]
Bus 001 Device 002: ID 05e3:0606 Genesys Logic, Inc. D-Link DUB-H4 USB 2.0 Hub
Bus 001 Device 001: ID 0000:0000

The pair of hexadecimal numbers are PID:VID. Use these in the .rules file. If you cannot identify your device, you can run lsusb as root to see if that helps. If it doesn't, run lsusb with the device unplugged, then again with the device plugged in to identify the new device.

The rules file will take effect next time the device is plugged in.

There is more information about the rules file in udev(7) man page. The man page for hal_input(1) also has a good write up of USB permissions.

Problem Devices

  • Griffin Technologies, Powermate - The LED can't be driven because it uses vendor defined messages to program the LED state. The dial sends timed updates as it is rotated. If the device doesn't move, hidcomp outputs the last movement value, making it look like the device is stuck on.

Known Issues

  • When hidconfig is run remotely (using an X terminal), USB devices with high update rates (like the Logitech gamepads which update 100 times per second) the display can lag behind the device motion until it comes to rest.
  • There is a known resizing problem on the LCD setup screen.  Sometimes the virtual LCD display overlaps the data table and uses 100% of the cpu repainting the overlap.  Resizing the window by dragging a corner will stop this.

ToDo List

  • When a long operator message is displayed, make it scroll or something so the whole message can be seen.

Change History

1.8
  • Build for EMC2 2.9(master).
  • Remove libusb source.
1.7
  • Build for EMC2 2.6.7.
  • Fix bug not initialising select timeout value correctly.
  • Stop crash on exit, where USB callbacks active after shutdown.
  • Update udev rules documentation to use new ATTR code instead of SYSFS.
1.6 Build for EMC2 2.5.
1.5 Build for EMC2 2.4.6.  Add checking for version mismatches.
1.4 "Reverse Axis" option on a value axis was not working.  Now it is.
1.3 Add LCD External Access Port to allow external socket interface to LCD display.  Also support advanced displays as used in Lathe Pendant.
1.2 Update LCD handling to bring in line with GenericHID release.  Correctly handle multiple LCDs.  Support user defined characters.  And MRU list.
1.1 Remove need for emc.nml changes if an LCD display isn't being used
1.0 Initial Release

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages