ShellFish C source

Official repository.

Version 0.0.1 – Stable – Release date: 16 February 2021
Platform Linux / GCC; K8055 series, Ubuntu, Debian, Raspbian.

Excerpt

Shellfish is a micro logic event driver running on Linux that controls the state of the Velleman P8055 or VM110 USB interface boards. These boards belong to the K8055 hardware group using the PIC16C745 micro-controller for USB communication and digital / analog port driving.

The micro logic event driver is able to read and change the state of the hardware by means of a set of commands sent from an event script / program. Whenever the state changes of the hardware, The event driver calls the event script / program for macro logic processing.

The state of the hardware, type of event and identification of the object that caused the event are sent as command line parameters to the event script / program during the call. The event script / program returns a set of commands in a response file that will be read and executed by the event driver.

Optionally, a web-server can be updated with the status of the hardware and may return commands to be processed by the event driver.

Background

While looking for Linux solutions that could provide communication with the K8055 series I found a library that provided core communication with the hardware, libk8055. The library is identical to the Windows library Velleman provided.

The support tool provided with libk8055 was made for getting and setting status once and return to the caller. During the call the device needed to be iterated, initialized, opened, read, set and closed. Also, the caller needed to setup memory to hold a copy of the status for interchangeable actions. All this takes time and eventually missed out on status when signals were fast switching and it became even worse when the Linux system tried to get ownership of the USB device resulting in unacceptable timeouts and ultimately USB blackouts. Nice for demonstrations without a mission critical factor but not for performances on any Linux system.

The cluster of bad performances had to be programmed in a main event loop and that is a different league to modern programmers used to program code for event driven languages. So, I turned it inside out, initialized the hardware outside the main loop, wrote the main loop, designed a mini command parser, setup virtual state memory, called the hardware for getting and setting status, handle errors and most important, call a script when events are happening, polling web services trom time to time, processing return commands from the both with the command parser, added some programmable timers and triggers and finally closing the connection with the hardware when the program exits the main loop, usually when the system shuts down.

This is, in my opinion, a micro logic event driver performing speedy and reliable in manners the modern programmer thinks is acceptable. I named it shellfish because besides micro logic event driving, shelling to events is it’s business.

Donate

If you like the software and found a good use for it please support the project by donating a small fee of your choice. Thanks in advance.

Download

https://sanghalung.com/shellfish_release_0_0_1.tar.gz

This is the core program of the Shellfish suite, the event driver. No tools, no utilities, end-user programs or samples (other than a stub event script) are included. Packages and suites that make use of the event driver, such as a home security system are distributed separately. These packages and suites do not belong to the GNU GPL and usually come fully installed on the hardware of the suite, the commercial end product. Despite the non GPL status of the suites, customers are allowed to modify code whenever they see fit.

You need to compile and link the program. Also, You may need to download libraries, Add the hardware to user-space, Change permissions and more depending on what you’re planning to do with Shellfish.

Substantial knowledge of C and Bash as well as the Linux system is highly recommended. This will not be an easy Sunday afternoon crossing up the progress of driving on the grass. Read this manual at least once.

About the program

Shellfish is written in C by Marcel Ferenc Blokker of Sanghalung Software (ferenc@sanghalung.com) and can be compiled / linked with the GNU Compiler Collection or in short, gcc.

Contributors

Shellfish uses the libk8055 library created by Julien Etelain and Edward Nys. It also uses the libusb library created by Hans de Goede, Xiaofan Chen, Ludovic Rousseau, Nathan Hjelm and Chris Dickens.

Source and libraries

The libk8055 and Shellfish C source files are supplied with the package. libusb and gcc must be downloaded from its respective repositories.

The program and the libraries are released under the GNU General Public License.

Schema of Shellfish

Startup

Shellfish can run as a program in a terminal window or in the background as a service. Before Shellfish can retrieve status, a connection with the USB hardware must be established.

Main loop

Because USB is hot-pluggable, the connection may drop and Shellfish will try to restore the connection with the USB device but will not turn into an non-operative state during the absence of the hardware.

Depending the status of the hardware, Shellfish will fire events. That may be USB connection status change events, Input and output status change events, Button press events, Keyboard events or screen update events.

The events will then be processed by an event script where the macro logic’s of the USB card takes place. An event script must be written in a bash script or any other program supporting a command line for input and exit codes for signaling the existence or absence of a command response file. Because of the event driven nature and constant polling, status loss is limited to a minimum, however, during execution of the event, status polling is halted. Events need to be executed in the fastest way possible.

The scheduler will poll optionally for commands at a web service whilst supplying status update of the USB card to the web service. The web service may act as a remote control whilst Shellfish remains as a service on the system. The scheduler also takes care of an optional heart beat signal, activity signals and timer events.

The commands delivered by the event script and web service will then be interpreted on arrival and translated to hardware commands sent to the USB hardware.

Compiling

Before you can use the program, You need to compile and link the program with gcc. A file named make.sh is included in the archive.

gcc -O2 -c -o libk8055.o libk8055.c
gcc -O2 -c -o shellfish.o shellfish.c
gcc shellfish.o libk8055.o -o shellfish -lusb -L/usr/lib -lm

Permissions

Set permissions for the program and the stub event script.

chmod +x ./shellfish
chmod +x ./shellfish.sh

By default, Shellfish will look for the event script named shellfish.sh. in the current folder, I added a stub event script so it won’t go totally dark at the first baptism of Shellfish on your system.

Connect the interface

Insert the USB connector of the USB cable attached to the Velleman interface in the USB slot of your computer. Give your system as few seconds to connect with the card before you start Shellfish.

Run Shellfish

./shellfish

Test the hardware

Press the test buttons on the board and turn the pot meters. You will see output similar to this.

Event ST.
0 0 0 ST 00000000 00000000 0 0 0 0 0 0 0 0 0
Event RF.
0 0 0 RF 00000000 00000000 0 0 0 0 0 0 0 0 0
Event RF.
0 0 0 RF 00000000 10000000 4 0 0 0 0 0 0 0 0
Input 1 UP.
0 0 1 UP 00000000 10000000 4 0 0 0 0 0 0 0 0
Event RF.
0 0 0 RF 00000000 10000000 5 0 0 0 0 0 0 0 0
Event RF.
0 0 0 RF 00000000 10100000 6 1 1 0 0 0 0 0 0
Input 3 UP.
0 0 3 UP 00000000 10100000 6 1 1 0 0 0 0 0 0
Event C1.
0 0 0 C1 00000000 10100000 7 1 1 0 0 0 0 0 0
Event C2.
0 0 0 C2 00000000 10100000 7 1 1 0 0 0 0 0 0
Event RF.
0 0 0 RF 00000000 10100000 7 1 1 0 0 0 0 0 0

Startup parameters

Startup parameter  Value  Description
-mNumberModule number.  

The module number will be sent to the script as where it can be used to determine what part of the controller script must be executed.
By evaluating this number you will be able to write more than one controller function in a single script. You could for example use “0“ for standard operation and “1“ for debug operation.

Example: -m0
-iNumberInterface number.  

You can connect 4 K8055 type boards to the USB bus and set the interface number per card by changing the jumper on the board.  

Example: -i0  

Shellfish is only able to use one interface per session. For each interface you need to start an new instance of Shellfish if you want more interfaces to be controlled by the program.
-xStringThe path and name of the event script.  

The default value is “./shellfish.sh”.

Example: -x/home/user/shellfish.sh  

Whenever the state changes of the K8055, the script specified by the -x parameter will be executed.

Shellfish will call the script by executing a system() call and supply it with a set of status and event parameters.
-XNumberType of event script.  

0 – Programs or scripts supporting a command line as input.  
 
Currently only type 0 executable’s are supported. In future versions it may be possible to use other types of scripts or programs using socks for (or other forms of) communication.
-dStringEvent script data folder.  

Default value is “.”

The last character should not be a /
 
Example: -m0 -i1 -d/home/user/response

Will use /home/user/response/Shellfish.0.1.ret as a response file.  
-u0 / 1Enables or disables the submission of the hardware-status to a status-collector.  

The status-collector is a script (PHP, CGI, etc.) that is processing the hardware-status and keep the values of the status in session memory of the script mechanism.

Shellfish will feed the commands returned by the status-collector to the event script.  

Default, no status updates will be sent to a web service (-u0).  

Example: -u1           
             
This will enable status updates to a web service. 
-CURLURL of the status collector to navigate for hardware-status updating and fetching commands.  

Example: -Chttps://user:pass@localhost/myscript.php  
-c0 / 1Processing indicator on output 6.
-b0 / 1Web service updating indicator on output 7.
-a0 / 1Shellfish heartbeat indicator on output 8.
-s0 / 1Silenced mode.
-l0 / 1Write log information to the stderr log device.

Commands

CommandMinMaxDescription
O18Raise output.
o18Lower output.
R12Reset counter 1 or 2 to zero.
A0255Set Analog out 1.
B0255Set Analog out 2.
Y0255Simulate Analog in 1.

Set value and turn on simulation mode.
y01Set simulation mode Analog in 1
(0=off, 1=on).
Z0255Simulate Analog in 2.

Set value and turn on simulation mode.
z01Set simulation mode Analog in 2

(0=off, 1=on).
P15Raise + Lower input (pulse). Simulated.
I15Raise input and hold. Simulated.
i15Lower input. Simulated.
F1255Function call.
T1255Set timer.

Parameters:
0 – 999999 Seconds.

A value of zero resets pending timer.

Example: T5=60
 

Event script parameters

ParameterMinMaxDescription
$10999999Module number.
$203Interface number (see jumper setting on the board).
$30999999Event parameter.
$4AZEvent ID.  

CC USB Card connected.
CD USB Card disconnected.
ST Controller start.
EX Controller exit.
RF Refresh.
UP Input raised.
DN Input lowered.
DH Input lowered from hold state.
A1 Analog input 1 changed.
A2 Analog input 2 changed.
C1 Counter 1 changed.
C2 Counter 2 changed.
KB Keyboard input.
TM Timer expired.
FN Function call.  
$50000000011111111Output state.
$60000000011111000Input state.
$70NDelta.

Number of seconds elapsed since start.
$81NCounter 1.
$91NCounter 2.
$101255Analog input 1.
$111255Analog input 2.
$121255Analog output 1.
$131255Analog output 2.
$1401Analog input 1 simulation mode
(0=off, 1=on).
$1501Analog input 2 simulation mode
(0=off, 1=on).

Status collector parameters

FieldMinMaxDescription
F11999999Module number.
F203Interface number.
F30000000011111111Output state.
F40000000011111000Input state.
F50NDelta.

Number of seconds elapsed since start.
F61NCounter 1.
F71NCounter 2.
F81255Analog input 1.
F91255Analog input 2.
F101255Analog output 1.
F111255Analog output 2.
F1201Analog input 1 simulation mode
(0=off 1=on).
F1301Analog input 2 simulation mode
(0=off 1=on).

Example of event handling

#!/bin/bash

# Output path

ShellDataFolder = '/home/username/shellfish'

# Handle keypress 'l'

if [[ $4 == 'KB' && $3 == '108' ]] ; then

	# Change Analog B

	Command="B255"
	echo "$Command" > $ShellDataFolder/shellfish.$1.$2.ret
			
	exit 1
fi

exit 0

In this example variable $4 and $3 are evaluated for event KB and ASCII code 103, Lowercase L. The variable $Command is then set to “B255“ the command to set Dac/Pwm 2 to value 255.

The content of variable $Command is redirected to the return file Shellfish is using to fetch the commands.

Note that the path of the return file is specified by variable $ShellDataFolder and the filename is constructed with variable $1 (module number) and $2 (interface number).

The event is then exiting with the return code 1 indicating a return file is waiting for processing.

It is good practice to keep a shell script as compact as possible. All though it is relatively easy to program events in a shell script it is also the slowest method. Because Shellfish is halting the evaluation of the hardware-status until completion of the event script it might miss out on status change during the waiting for the completion of the script.

All variables of the hardware are maintained by Shellfish, Including virtual input and output states normally not maintained by the hardware. The event script does not need any global variables (i.e. variables stored in a file and retrieved from that file at each start of the event script). It is not forbidden to do so but keep in mind that any time consuming task in the event script will halt status retrieval for the duration of processing.

Returning commands

As you can see at the $Command variable assignment in the previous script example, commands can be returned to Shellfish. You can send more than one command as long as you separate each command with a space. All commands must remain on the same line. The space is a separator and may not be used as part of a command or command expression.

The line must be written to the response file Shellfish.#1.#2.ret (where #1 is the module number and #2 is the interface number). When you returning commands you must exit the event script using exit 1. If there are no commands to process, use exit 0 to exit the event script.

The folder name of the response file must be specified by parameter -d when you start Shellfish. Do not specify this parameter or any other parameter when calling an event script.

Setting up web communication

Shellfish supports a feature that enables you to control the K8055 hardware by means of a web service. In respect to the event scripts, the web calls are not event driven. It works by sending frequently the status of the hardware and feeding the returning commands (if any) to the event script. Therefore, Latency between command submission and execution of commands by the event script must be expected and is a feature by design.

Status collector update parameters

Shellfish is calling the status collector with the shellfishid URL parameter containing the status record shellfishupd. The record has 13 fields representing the status of the hardware.

shellfishid=shellfishupd(F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13)

Returning commands

Commands returned by the status collector are in the same format as the commands that are returned by the event script. The status collector may return more than one command as long as they are separated by a space. All commands must remain on the same returning line. Do not include HTML tags and the like. The space is a separator and may not be used as part of a command or command expression.

Example of returning commands by using the PHP die() function.

<?php
	$cmd=$_GET['cmd'];
	if($cmd=="do"){
		die("P1 P2 O4");
	}
?>

Because Shellfish is polling the status collector using intervals of 1.5 seconds, you may want to queue the commands submitted by the components of your web application in an intermediary file or database table and retrieve it from there when returning commands with the status collector.

It is advisable to use a local web service, A web service running on your Linux system or at least inside the LAN. The longer it takes to process a request the longer Shellfish will halt status-scanning of the hardware and may miss out on any input events.

Terminal output and silenced mode

Shellfish is reporting events by sending messages to the terminal. This is handy when you’re developing an event script controller but when you’re writing an event script that also acts as a terminal application with a fancy window and status printed nice and orderly on the screen or just want to run Shellfish as a service, it’s causing noise either on screen or in the systemctl log.

Managing in user space.

Before Shellfish can iterate the USB subsystem, connect with the board, retrieve status and sending commands, a udev rules file must be created.

Low level support of the board is handled at kernel level. However, the management of events related to the board are managed in user space by udev. This is done by creating a rules file in the /etc/udev/rules.d folder.

Add the following content to a new file and name it velleman.rules and save it (use sudo).

SUBSYSTEMS!="usb", ACTION!="add", GOTO="k8055_rules_end"

ATTRS{idVendor}=="10cf", ATTRS{idProduct}=="5500", GROUP="k8055", MODE="0660"
ATTRS{idVendor}=="10cf", ATTRS{idProduct}=="5501", GROUP="k8055", MODE="0660"
ATTRS{idVendor}=="10cf", ATTRS{idProduct}=="5502", GROUP="k8055", MODE="0660"
ATTRS{idVendor}=="10cf", ATTRS{idProduct}=="5503", GROUP="k8055", MODE="0660"

LABEL="k8055_rules_end"

Because group k8055 is specified, you need to create a group named k8055 and add users to it that are allowed to make use of the board.

The hardware identifies itself as “Velleman USB K8055“ or “Velleman USB VM110” to the USB subsystem and is using the group name k8055. This might be a bit confusing since the printed on board identification states the board is a P8055N-1, P8055N-2 or a PVM110M-1 and we must assume that k8055 is a group of boards all interfacing in the same manner.

Raspberry Pi

The Raspberry Pi appears to work when querying the sysfs tree and the use of symbolic links. If the rules file above did not yield into a successful connection with your board you might want to try the following rules file. Note that the group name is plugdev.

SUBSYSTEM !="usb_device", ACTION !="add", GOTO="velleman_rules_end"

SYSFS{idVendor}=="10cf", SYSFS{idProduct}=="5500", SYMLINK+="k8055_0"
SYSFS{idVendor}=="10cf", SYSFS{idProduct}=="5501", SYMLINK+="k8055_1"
SYSFS{idVendor}=="10cf", SYSFS{idProduct}=="5502", SYMLINK+="k8055_2"
SYSFS{idVendor}=="10cf", SYSFS{idProduct}=="5503", SYMLINK+="k8055_3"

MODE="0660", GROUP="plugdev"

LABEL="velleman_rules_end"

User pi has already been added to the group plugdev but you may want to check this and add user pi and any other user allowed to use the board to the group.

Run as a service

Create a file named shellfish.service (use sudo) in the /etc/systemd/system folder and add the content below. Make sure the path to the Shellfish executable is correct and the desired parameters are specified.

[Unit]
Description=Shellfish K8055 controller service

Wants=network.target
After=syslog.target network-online.target

[Service]
Type=simple
ExecStart=/path/shellfish [type your parameters]
Restart=on-failure
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target

Service commands

Start the servicesudo systemctl start shellfish.service
Get status from the servicesudo systemctl status shellfish.service
Stop the servicesudo systemctl stop shellfish.service
Reload after modifying the filesudo systemctl daemon-reload

What’s next

If you finally grasp the event driver and it is up and running, it’s time to program your event scripts and maybe a few webpages controlling your hardware. That will be a tedious but very rewarding task on it’s own as I can say from my own experiences writing micro and macro logic’s for diverse controller applications.