Trackballs declutter busy desks and can be more comfortable than mice for precision pointing.
Logitech trackballs also support Linux, paired and configured via
Solaar.
Every few months pop out the trackball and clean the rollers or just blow on them to get the dust out.
Whatever mouse or trackball one buys, be sure to get one that work via Bluetooth Low Energy (BLE) or the Unifying receiver.
The main observed differences of using BLE is slightly shorter battery life and a slight initial lag if the buttons/roller haven’t been used for several seconds.
The advantage of BLE is avoiding damage to the laptop USB port with the dongle while handling the laptop.
The Logitech trackballs below have a user-maintainable trackball with back/forward buttons and clickable roller for programming and web-browsing convenience.
These trackballs support BLE and Unifying receiver.
Logitech MX Ergo: a higher-end trackball with two-position tilt for comfort. The Ergo has a button to switch between two Bluetooth devices e.g. laptop, phone, etc.
Logitech M575: fixed tilt, no device switching button
include(CheckSourceCompiles)set(CMAKE_TRY_COMPILE_TARGET_TYPESTATIC_LIBRARY)# save link time, only compile is needed
check_source_compiles(Fortran"program test
implicit none
intrinsic :: random_init
call random_init(.false., .false.)
end"f18random)
Older versions of gfortran call random_seed() gives a unique seed.
Not every compiler vendor gives a unique seed for random_seed() however.
PyGame,
PyAudio and PySoundDevice are three of the best currently maintained packages for playing audio from Python, including from Numpy arrays or streaming sources.
For these examples, we will use this common sinewave-generating code in a Numpy array.
importnumpyasnpfs = 8000# HzT = 1.# second, arbitrary length of tone# 1 kHz sine wave, 1 second long, sampled at 8 kHzt = np.arange(0, T, 1/fs)
x = 0.5 * np.sin(2*np.pi*1000*t) # 0.5 is arbitrary to avoid clipping sound card DACx = (x*32768).astype(np.int16) # scale to int16 for sound card
PySoundDevice has the simplest syntax for Python audio play/record packages.
importsounddeviceimporttimesounddevice.play(x, fs) # releases GILtime.sleep(1) # NOTE: Since sound playback is async, allow sound playback to finish before Python exits
PyGame is for building games and does much more than audio.
I find PyGame to be very robust across a wide variety of systems (including embedded systems) to play audio from Python.
pip install pygame
uses pre-compiled .whl binary wheel.
importpygamefromtimeimport sleep
pygame.mixer.pre_init(fs, size=-16, channels=1)
pygame.mixer.init()
sound = pygame.sndarray.make_sound(x)
sound.play()
sleep(0.01) # NOTE: Since sound playback is async, allow sound playback to start before Python exits
The PyAudio and PySoundDevice packages are PortAudio based.
PyAudio uses PortAudio to allow easy playback of Numpy arrays.
If you find that you’re not able to install PortAudio, consider using PyGame instead of PyAudio.
importpyaudio# PyAudio doesn't seem to have context managerP = pyaudio.PyAudio()
stream = P.open(rate=fs, format=pyaudio.paInt16, channels=1, output=True)
stream.write(x.tobytes())
stream.close() # this blocks until sound finishes playingP.terminate()
Oct2Py doesn’t work as temporary files are needed.
Example PyGame program: audio_pygame.py.
Advanced PyGame setup.
Python can be used within Windows Subsystem for Linux.
Using Python on WSL can be advantageous because of easier compiler access.
Miniconda
Python works well on WSL.
conda install matplotlib spyder
If Spyder won’t start, look in the error message for missing libraries such as libxcomposite libxss1
X11 prereqs are specified in the error message on starting GUI programs like Spyder.
ModuleNotFoundError: No module named ‘PyQt5.QtWebKitWidgets’
See if libxcomposite or libxss etc. need to be installed via apt install.
Using CMake to
download,
verify the checksum of files and extract compressed files is easy and seamless.
FetchContent downloads the file at configure time.
include(FetchContent)function(download_fileurlhash)FetchContent_Declare(download_${hash}
URL ${url}
URL_HASHSHA256=${hash}
DOWNLOAD_NO_EXTRACTtrue)if(NOTdownload_${hash}_POPULATED)FetchContent_Populate(download_${hash})endif()endfunction(download_file)# === example
download_file(
https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg12794390cce7d0682ffc783c785e4282305684431b30b29ed75c224da24035b4)
CMake also can
extract compressed files
like .zip, .tar.bz2, etc.
This command can also specify output directory, extract a subset of files matching a pattern and more.
This guide assumes there is no Internet, no Wifi, no router, no display, no keyboard.
It assumes you have a Raspberry Pi and laptop with:
Ethernet port (built-in or USB-Ethernet adapter)
plain (or crossover) Ethernet cable–no router/switch is required
Some laptops can also work via USB-C connection and the RNDIS Ethernet driver instead of the Ethernet jack.
However, some laptops, particularly on Windows may not work for RNDIS.
The symptom of this is that the Pi shows up as a serial port instead of an Ethernet connection.
Hence, best to use the Ethernet jack for better reliability.
Before going into the field away from internet, download:
Prepare SD card via the Raspberry Pi Imaging tool to write the desired SD card image.
If the laptop is not on the internet, use the imager tool to write the .img you downloaded previously.
BEFORE writing, use Imager settings to enable SSH, set username, hostname, etc.
“eject” or unmount the SD card before removal, to avoid corrupting the SD card file system.
Boot the headless Pi by inserting the SD card into the Pi and powering up the Pi.
We use link-local networking, where the IP address will be in the 169.254.*.* range, no DHCP server needed.
You may need to manually select this network when you plug the Pi into the laptop.
After about one minute, on your laptop plugged directly to the Pi via Ethernet (username, hostname are those picked for the Pi by the Raspberry Pi Imager program):
ssh username@hostname.local
Just a simple network switch connecting Raspberry Pis, PCs and other devices makes an internet-free, pure link-local “off the grid” network.
Of course, you can also put the Pis on a wired or wireless network connected to the Internet if desired.
The .local address functionality will NOT work over the Internet, but only on the LAN segment your device is on.
Without further configuration, SSH servers listen on all interfaces.
Normally this is fine.
If you want only specific interface(s) to have the SSH server listen, you will need to research ListenAddress of /etc/ssh/sshd_config and/or IPTables.
Ninja normally deletes each
response .rsp file
if the target build is successful.
When debugging a program, we may need to see all the commands run before failure by keeping the .rsp files.
Ninja keeps the .rsp files after compilation by using option:
ninja -d keeprsp
Ninja is a build backend used by Meson build system and CMake as a fast, modern replacement for GNU Make.
.rsp files are simply a plain text file containing the command fragment to be run on the command line.
For example, a build line:
cc -Iinc hello.c -lm
is implemented with an .rsp file by the build system as:
cc hello.rsp
where file foo.rsp contains
-Iinc hello.c -lm
There is currently not a Meson or CMake option to keep the .rsp files.
Instead, manually invoke Ninja as above when Meson or CMake has configured the build.
That is, instead of:
If the CI-detected change is git commit --amend or squash and force push over previous commits, the CI run may fail with a message like:
fatal: reference is not a tree: <commit id>
The command "git checkout -qf <commit id>" failed and exited with 128 during .
Different CI systems have distinct default Git depth.
Checking out all commits takes too much time, while too shallow can falsely fail on force push.
We would suggest not specifying the Git clone depth, thereby using the CI system default, unless the repo is very large and Git clone is taking too long.
If manually specifying Git depth, the depth must be larger than the number of Git commits your team would ever squash and force push (overwriting prior commits).