OpenHantek on FreeBSD for USB oscilloscope

02 Oct 2019 - tsp

This is a really short writeup on what was necessary of bringing OpenHantek6022, a great alternative software used with some USB digital oscilloscopes like the Hantek 6022BE or Hantek 6022BL, (note: The last links are Amazon affilate links, this pages author profits from qualified purchases) to FreeBSD. And also a short story about how everyone can improve open source software with minimal effort. Since development for OpenHantek is done mainly on Linux it turned out to be really easy to port it to FreeBSD (a matter of a few hours including some debugging and mainly writing this story and the files for the port).

Example of OpenHantek running on FreeBSD

I’ve also already generated files for a port at science/openhantek - but havent’s submitted them upstream since the upstream repository for OpenHantek currently has no release tag including the patches. As soon as there is a release present the setup will be a simple matter of

cd /usr/ports/science/openhantek6022
make install clean

or a package install like

pkg install openhantek6022

Until then - or to build manually one can use the following steps:

The short story of porting openhantek to FreeBSD

So this was one of the easiest ports I’ve ever done. First I’ve just tried to clone the GitHub repository of OpenHanek

git clone https://github.com/OpenHantek/OpenHantek6022.git

Then I tried a simple build

mkdir -p OpenHantek6022/build
cd OpenHantek6022/build
cmake ../
make -j2

As expected that failed. It turned out there was a single thing preventing the program to compile - the libusb includes are included in a libusb-1.0 subdirectory on Linux but contained directly in the /usr/include directory on FreeBSD. So as a first try I checked if exchanging would help.

find ../openhantek -name "*.cpp" -exec sed -i '.bak' 's#libusb-1.0/libusb.h#libusb.h#g' {} \;
find ../openhantek -name "*.h" -exec sed -i '.bak' 's#libusb-1.0/libusb.h#libusb.h#g' {} \;
find ./ -name "*.bak" -exec rm {} \;

Another build run

make -j2

produced a runable binary. So I simply modified all sourcefiles (to keep them buildable on existing platforms). I moved from

#include <libusb-1.0/libusb.h>

to

#ifdef __FreeBSD__
	#include <libusb.h>
#else
	#include <libusb-1.0/libusb.h>
#endif

which allows the build system to build the binary at least on Linux, MacOS X and also on FreeBSD.

After that I tried to run the application:

./openhantek/OpenHantek

No USB devices had been discovered. This was caused by the inability of the application to access the USB devices by default (a good thing) so I first added a new group usbscope to the system

pw groupadd usbscope

To use it with my default user I’ve added the user to the group:

pw group mod usbscope -m MYUSERNAME

After that one has to reload identity information (logging out and re-logging in for example). Now I’ve added a simple devd rule file to change group ownership of the usb device file on attachment so all members of the usbscope group would be able to access the device file. This file has been added to the /usr/local/etc/devd/openhantek.rules file:

# Hantek 6022BE (20 MHz, 48 MS/s)

notify 110 {
    match "system" "USB";
    match "subsystem" "DEVICE";
    match "type" "ATTACH";
    match "vendor" "0x04b4";
    match "product" "0x6022";
    action "chgrp usbscope /dev/$ugen; chmod g+rw /dev/$ugen; chgrp -h usbscope /dev/$ugen; chmod -h g+rw /dev/$ugen";
};

notify 110 {
    match "system" "USB";
    match "subsystem" "DEVICE";
    match "type" "ATTACH";
    match "vendor" "0x04b5";
    match "product" "0x6022";
    action "chgrp usbscope /dev/$ugen; chmod g+rw /dev/$ugen; chgrp -h usbscope /dev/$ugen; chmod -h g+rw /dev/$ugen";
};

attach 110 {
    match "vendor" "0x04B4";
    match "product" "0x6022";
    action "chgrp usbscope /dev/$ugen; chmod g+rw /dev/$ugen; chgrp -h usbscope /dev/$ugen; chmod -h g+rw /dev/$ugen";
};

attach 110 {
    match "vendor" "0x04B5";
    match "product" "0x6022";
    action "chgrp usbscope /dev/$ugen; chmod g+rw /dev/$ugen; chgrp -h usbscope /dev/$ugen; chmod -h g+rw /dev/$ugen";
};

After a restart of devd via /etc/rc.d/devd the device was assigned to the correct group after reattachment.

Finally the launch of the application succeeded, the device was listet. And the application. Crashed.

Some hours of debugging later it seemed that the release of the usb device list caused the crash - as if the application would keep a reference into undefined memory locations despite it incrementing the descriptor reference count. Since this seemed to be a bug in the systems libusb library I’ve simply decided to remove the release of the device descriptor since this runs exactly once during application startup and memory will be released during shutdown anyways. Since on other platforms everything works correctly I’ve guarded that with an preprocessor statement:

#if !defined(__FreeBSD__)
	/*
		ToDo: This introduces a potential resource leak if not executed
		on FreeBSD. It seems there is a reference counting problem when
		using libusb on FreeBSD.
	*/
	libusb_free_device_list(deviceList, true);
#endif

Now everything compiled and ran fine. The scope is working.

To prepare everything for the pull request into the upstream repository:

Then for every piece of distinguishable work staged all required parts (in case of changes at the same file that belong to different commits use git add -p FILENAME to stage only parts of the changes, to stage everything git add FILENAME). After that a Commit including signoff message is created (git commit -S -s). The -S switch is included since I also sign my commits using OpenPGP.

After all commits have been made one can create a pull request using GitHub. Simply select source (never master) and destination branches, wirte a short title and description. And everything is ready. After the pull request has been created projects run some automated tests most of the time - which is also the case for OpenHantek.

Creating a FreeBSD port

Now - since FreeBSD has an excellent ports and package system that allows users to install software simply by executing a makefile in /usr/ports or using pkg to install their packages I’ve decided to create a small and fast FreeBSD port for openhantek. I’ve tested everything against my own private copy of the ports tree (and my own github repository).

First one creates a directory at the desired location into a current portstree. Update with portsnap fetch update or if there is no portstree install via portsnap fetch extract. After that one simply created the required files at the desired locations:

mkdir -p /usr/ports/science/openhantek6022

Now one creates the Makefile at /usr/ports/science/openhantek6022/Makefile

# $FreeBSD$

PORTNAME=               openhantek6022
DISTVERSIONPREFIX=      v
DISTVERSION=            2.16
CATEGORIES=             science

MAINTAINER=             tspfbsdport@tspi.at
COMMENT=                DSO software for Hantek USB digital signal oscilloscopes 6022BE/BL

LICENSE=                GPLv3

LIB_DEPENDS=            libfftw3.so:math/fftw3
BUILD_DEPENDS=          cmake:devel/cmake qmake:devel/qmake

USES=                   qt:5 gl cmake

USE_QT=                 printsupport opengl widgets gui core
USE_GL=                 gl glu

USE_GITHUB=             yes
GH_ACCOUNT=             OpenHantek
GH_PROJECT=             OpenHantek6022

do-install:
        ${INSTALL_PROGRAM} ${BUILD_WRKSRC}/openhantek/OpenHantek ${STAGEDIR}${PREFIX}/bin
        ${INSTALL_DATA} ${WRKSRC}/devd_rules_freebsd/openhantek.conf ${STAGEDIR}${PREFIX}/etc/devd

post-install:
        ${STRIP_CMD} ${STAGEDIR}${PREFIX}/bin/OpenHantek

.include <bsd.port.mk>

Basically this is a simple ports Makefile. Let’s look at it step by step. The value of PORTNAME simply identifies the name of the port. This is required during the provisioning and building process of the real FreeBSD ports tree since additions are done via PRs - not via an SCM system. The DISTVERSION identifies the name of the github branch that will be downloaded. If one just starts on can try with master but should use a unmodifyable tag afterwards since the archive will be checksummed.

The fields CATEGORIES and COMMENT provide some metadata about the port, the required field LICENSE identifies the software license and of course the MAINTAINER field allows to contact the port maintainer. This is also done automatically in case of build failures.

With the USE_GITHUB property it’s easy to let the FreeBSD ports system do all of the other stuff, one just has to specify the GH_ACCOUNT and GH_PROJECT that should be used as fetch source.

As we have created a group it will be listed at GROUPS. Note that each of this groups has to be listed also at /usr/ports/GIDs. For testing one can use the value assigned by pw during creation.

At the end there is a bunch of options that list dependencies of this port. Since OpenHantek uses qt5 (some modules out of it), opengl and the fftw library these are listed with USES, LIB_DEPENDS as well as USE_QT and USE_GL.

Now there are several make targets:

All that magic is possible since the default ports Makefile bsd.ports.mk is included at the end.

Two other metadata files are required:

bin/OpenHantek
etc/devd/openhantek.conf

The last missing part for the port is the distinfo file that contains checksums. This is not created manually but using make makesum inside the ports directory. These checksums are also the root cause why the branch is not allowed to change anymore. Any further changes would modify the checksums and prevent the installation or build process to run.

Now one can test the port (after deleting anything that’s already present using make clean && make distclean). The build process should run using make, installation using make install.

If everything worked out the program should be available an runable with OpenHantek as every user who’s member of the usbscope group.

As a last step - before submitting the port upstream - one should run portlint to verify everything works as expected:

cd /usr/ports/science/openhantek6022
portlint

If portlint tells us looks fine. the port is finished successfully we can simply create either the patch or the shar to submit to the portstree maintainers. If one wants to push the port upstream one first has to wipe out everything using make clean && make distclean. After that one can simply create the shar file via:

cd /usr/ports/science
shar `find openhantek6022` > openhantek6022.shar

The generated shar file can then be uploaded to the FreeBSD bug submission form. Make sure to submit as Ports and Packages, Individual Port, add a short decription (like for example New port: science/openhantek6022 DSO software for Hantek USB digital signal oscilloscopes 6022BE/BL of the program as well as the previously generated shar file. And then be patient (days, weeks, months).

Update to version 3.0.2

I’ve continued development of the port Makefile for OpenHantek - to cope with some problems with the older version. Since I’m using xf86-video-intel as graphics driver with the i915kms module and there has been a bug when using OpenGL I had to launch OpenHantek using

env LIBGL_ALWAYS_SOFTWARE=1 OpenHantek

The new Makefile for the port in it’s current state:

# $FreeBSD$

PORTNAME=               openhantek6022
DISTVERSIONPREFIX=
DISTVERSION=            3.0.2
CATEGORIES=             science

MAINTAINER=             tspfbsdport@tspi.at
COMMENT=                DSO software for Hantek USB digital signal oscilloscopes 6022BE/BL

LICENSE=                GPLv3

LIB_DEPENDS=            libfftw3.so:math/fftw3
BUILD_DEPENDS=          cmake:devel/cmake qmake:devel/qmake

USES=                   qt:5 gl cmake

USE_QT=                 printsupport opengl widgets gui core
USE_GL=                 gl glu

USE_GITHUB=             yes
GH_ACCOUNT=             OpenHantek
GH_PROJECT=             OpenHantek6022

pre-build:
        ${MKDIR} ${WRKSRC}/build

do-build:
        cmake -B${WRKSRC}/build ${WRKSRC}
        ${GMAKE} -C ${WRKSRC}/build

post-install:
        ${STRIP_CMD} ${STAGEDIR}${PREFIX}/bin/OpenHantek
        ${MKDIR} ${STAGEDIR}${PREFIX}/etc/devd
        ${INSTALL_DATA} ${WRKSRC}/utils/devd_rules_freebsd/openhantek.conf ${STAGEDIR}${PREFIX}/etc/devd

.include <bsd.port.mk>

This article is tagged: DIY, Computer, FreeBSD, Electronics, Programming, Tutorial


Dipl.-Ing. Thomas Spielauer, Wien (webcomplains389t48957@tspi.at)

This webpage is also available via TOR at http://jugujbrirx3irwyx.onion/

Valid HTML 4.01 Strict Powered by FreeBSD IPv6 support