Overview
This blog will show you how to setup snapcraft.yaml to access USB devices connected to ctrlX CORE. In addition to that, it shows an example of a Python snap, which uses the PyUSB module [wrapper for libusb] to read in data from a USB mouse.
You can also download the full project, which includes the providing of the mouse data on the ctrlX Data Layer, by clicking here.
Prerequisites
Setup development environment for ctrlX AUTOMATION
Python USB access module pip install pyusb
Some basic understanding of Snapcraft
The Vendor ID and the Product ID of the connected USB device are needed to be able to access the specific device you want to read in data from. The easiest way to find these is to connect the USB device to your PC and look it up according to your OS.
On Linux: Type in the following command in a terminal window. usb-devices
This will show you the information about all of your connected USB devices. Just look for the corresponding device. For this example:
T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#= 3 Spd=1.5 MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=17ef ProdID=608d Rev=01.00
S: Manufacturer=PixArt
S: Product=Lenovo USB Optical Mouse
C: #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
I: If#=0x0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=usbhid
On Windows: How do I find the USB Vendor ID and Product ID?
Implementation
Here, the setup of the snapcraft.yaml file is done before the implementation of the Python script. But you can do it the other way around as well.
Snapcraft YAML File Setup
Open a terminal window, change the working directory to where you want to build the snap and type in the following command: snapcraft init
This should give a YAML file similiar to this:
name: my-snap-name # you probably want to 'snapcraft register <name>'
base: core20 # the base snap is the execution environment for this snap
version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'
summary: Single-line elevator pitch for your amazing snap # 79 char long summary
description: |
This is my-snap's description. You have a paragraph or two to tell the
most important story about your snap. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the snap
store.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
Change grade and confinement of the snap: grade: stable
confinement: strict
Define the parts from which the snap is built and make sure to include the following packages: parts:
provider:
plugin: python
source: .
build-packages:
- libusb-1.0-0
stage-packages:
- libusb-1.0-0
python-packages:
- pyusb
Define the apps provided by the snap and make sure to include at least these three plugs in order to give this snap the permissions needed to access the USB device: apps:
provider:
command: bin/main.py
plugs:
- network
- raw-usb
- hardware-observe
daemon: simple
passthrough:
restart-condition: always
restart-delay: 10s
In addition to the snapcraft.yaml file, you need to create a setup.py script for the Python plugin to work properly and define in it which Python script is supposed to be used for this project. Simple setup.py for this example: from setuptools import setup
setup(scripts = ['main.py'])
Python Script
Original example
Import the following modules: import usb.core
import usb.util
import usb.backend.libusb1
Reference explicitly the libusb library within the snap to get access to hardware: backend = usb.backend.libusb1.get_backend(
find_library=lambda x: "/snap/my-snap-name/current/lib/aarch64-linux-gnu/libusb-1.0.so.0")
Find the connected USB device using the Vendor ID and the Product ID from above: dev = usb.core.find(idVendor=0x17ef, idProduct=0x608d, backend=backend)
Get the endpoint of the device and make sure to detach the connection to the OS kernel in order to claim it for this app: interface = 0
endpoint = dev[0].interfaces()[0].endpoints()[0]
dev.reset()
if dev.is_kernel_driver_active(interface):
dev.detach_kernel_driver(interface)
usb.util.claim_interface(dev, interface)
Loop to read in data from the USB device more than once: while True:
try:
data = dev.read(endpoint.bEndpointAddress,endpoint.wMaxPacketSize)
print(data)
# put your own code here
# for example datalayer access to present the data
except usb.core.USBError as e:
data = None
if e.args == ('Operation timed out',):
continue
Related Topics
Forum discussion: libusb on ctrlX CORE
... View more