todbot / blink1-tool

Command-line tools and C library for blink(1) USB RGB LED
https://blink1.thingm.com/
Other
84 stars 15 forks source link

blink1-tool not working on raspberry pi 3B / 3B+, works on Zero W #44

Closed nestukh closed 9 months ago

nestukh commented 3 years ago

Standard instructions for installing blink1-tool do not work on raspberry pi 3B / 3B+, but it does on a zero w. Both with standard updated Raspberry Pi OS with current 5.10.17 kernel.

Looking around the web, apparently there is some problem with udev or modern HIDAPI. On the 3Bs, blink1-tool --fwversion -v returns cannot open blink(1), bad id or serial number, while it's present via lsusb: Bus 001 Device 004: ID 27b8:01ed ThingM blink(1)

I've tested on a couple of devices in both armv6l and armv7l architecture, same results with official installation.

Anyway mixing info from the python setup I've got it working, so I'm providing a working installation procedure that covers all mentioned cases (and even resetting the usb connection without physical disconnection).

sudo apt-get install -y git coreutils usbutils build-essential pkg-config libudev-dev udev libusb-1.0-0-dev <&-

mkdir -p "$HOME/Blink1_USBLED/usbreset"
cd "$HOME/Blink1_USBLED/usbreset"

# https://askubuntu.com/questions/645/how-do-you-reset-a-usb-device-from-the-command-line
echo -e "/* usbreset -- send a USB port reset to a USB device */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>

int main(int argc, char **argv)
{
    const char *filename;
    int fd;
    int rc;

    if (argc != 2) {
        fprintf(stderr, \"Usage: usbreset device-filename\\\n\");
        return 1;
    }
    filename = argv[1];

    fd = open(filename, O_WRONLY);
    if (fd < 0) {
        perror(\"Error opening output file\");
        return 1;
    }

    printf(\"Resetting USB device %s\\\n\", filename);
    rc = ioctl(fd, USBDEVFS_RESET, 0);
    if (rc < 0) {
        perror(\"Error in ioctl\");
        return 1;
    }
    printf(\"Reset successful\\\n\");

    close(fd);
    return 0;
}" > usbreset.c
cc usbreset.c -o usbreset
chmod +x usbreset

cd "$HOME/Blink1_USBLED"
git clone https://github.com/todbot/blink1.git
git clone https://github.com/todbot/blink1-tool.git
cd blink1-tool
make clean
if [[ "$(uname -m)" == "armv6l" ]]; then 
  # raspberry pi zero w
  make
  # https://github.com/todbot/blink1/blob/master/linux/51-blink1.rules
  sudo cp ../blink1/linux/51-blink1.rules /etc/udev/rules.d/
else
  HIDAPI_TYPE=LIBUSB make
  echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="27b8", ATTRS{idProduct}=="01ed", MODE:="666", GROUP="plugdev"' | sudo tee /etc/udev/rules.d/51-blink1.rules
fi
sudo udevadm control --reload
sudo udevadm trigger

if [[ "$(lsusb | grep blink)" != "" ]]; then
  sudo "$HOME/Blink1_USBLED/usbreset/usbreset" "/dev/bus/usb/$(lsusb | grep blink | awk '{print $2}' | sed "s/://g")/$(lsusb | grep blink | awk '{print $4}' | sed "s/://g")"
fi 
sudo cp -f "$HOME/Blink1_USBLED/blink1-tool/blink1-tool" /usr/bin/
sudo chmod a+rx /usr/bin/blink*

# test
cd
which blink1-tool
blink1-tool --version
blink1-tool --list
blink1-tool --fwversion -v
todbot commented 2 years ago

I think this is no longer an issue. Just tested this on a RaspberryPi 2B, both with the current release binary and recompiling from source. Both work as expected without any tricks.

The usbreset code is neat! Very concise. In the past I've used usbhubctl (available via apt too) for USB port power cycling and thus triggering a USB re-enumeration, but usbreset is (I think) doing a protocol reset instead. Another useful tool.

I'm leaving this issue open for now as a reminder to make a "USB tricks for blink(1)" page.