$ cat /proc/bus/input/devices .... I: Bus=0005 Vendor=057e Product=0306 Version=0600 N: Name="Nintendo Wii Remote Balance Board" P: Phys= S: Sysfs=/devices/platform/soc/3f201000.serial/tty/ttyAMA0/hci0/hci0:11/0005:057E:0306.0002/input/input1 U: Uniq= H: Handlers=event1 js0 B: PROP=0 B: EV=b B: KEY=10000 0 0 0 0 0 0 0 0 0 B: ABS=f0000
enheden er tilgængelig både som input1 og js0 der er den gamle devicetype for joysticks. Al ny kode bør bruge input.
Flowet i en vejning er:
funktionalitet skal være:
Det første man skal gøre er at læse manual-siden, desværre er der ingen for input. Det næste er at læse include filer, og da det er en driver, er det også værd at kigge i kildeteksten til linux-kernen, og så er der google. Her er hvad jeg skimmede igennem:
kildeteksten til selve driveren behøver man sikkert ikke at konsultere, men det godt at vide at der er fuld dokumentation.
Vores Wii Balance Board er tilgængelig via /dev/input/event1, Events får man fat i via read() ind i en structur der indeholder time-stamp, type, code, value, for at se på hvad det er vi har med at gøre, har jeg skrevet dette lille C-program
/*
* read_events.c - Copyright (c) 2017 peter@lorenzen.us
* This program is free software, BSD-licensed
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <linux/input.h>
void usage(char *mess)
{
printf("read_events path\n");
printf("f.ex path=/dev/input/event1\n");
printf("%s\n",mess);
exit(1);
}
int main(int argc, char **argv)
{
int fd;
if ((fd = open(argv[1], O_RDONLY)) < 0) {
usage("cannot open device");
}
char name[80] = "Got nothing expected Nintendo";
int r = ioctl(fd, EVIOCGNAME(sizeof(name)), name);
printf("Events for \"%s\" on device %s\n", name, argv[1]);
int first_sec=0;
struct input_event ev;
while (read(fd, &ev, sizeof(ev)) == sizeof(ev)) {
if (first_sec==0) first_sec = ev.time.tv_sec;
int sec = ev.time.tv_sec - first_sec;
int usec = ev.time.tv_usec; // to avoid warning
printf("sec %d.%06d type=0x%04x code=0x%04x value=0x%08x\n", sec, usec, ev.type, ev.code, ev.value);
}
perror("error reading event");
}
Output af read_events dev/input/event1 ser således ud:
Events for "Nintendo Wii Remote Balance Board" on device /dev/input/event1 sec 0.803470 type=0x0003 code=0x0012 value=0x00000018 sec 0.803470 type=0x0000 code=0x0000 value=0x00000000 sec 0.805909 type=0x0003 code=0x0011 value=0x00000013 sec 0.805909 type=0x0003 code=0x0012 value=0x00000011 sec 0.805909 type=0x0003 code=0x0013 value=0x00000041 sec 0.805909 type=0x0000 code=0x0000 value=0x00000000 sec 0.823412 type=0x0003 code=0x0011 value=0x00000014 sec 0.823412 type=0x0003 code=0x0012 value=0x0000000f sec 0.823412 type=0x0003 code=0x0013 value=0x00000048 sec 0.823412 type=0x0000 code=0x0000 value=0x00000000 ...
Fra /usr/include/linux/input.h finder vi disse definitioner
/* excerpts from <linux/input.h> */
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
/* Event types */
#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_ABS 0x03
/* Absolute axes */
#define ABS_HAT0X 0x11
#define ABS_HAT0Y 0x11
#define ABS_HAT1X 0x12
#define ABS_HAT1Y 0x13
Dermed kan vi vi skrive en første version af vores program wiibb.c
/*
* wiibb.c - Copyright (c) 2017 peter@lorenzen.us
* This program is free software - BSD-licensed
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <linux/input.h>
void usage(char *mes)
{
printf("Usage: wiibb event_device\n");
printf(" print sensor values and total weight\n");
if (mes) printf("%s\n",mes);
exit(1);
}
time_t start_sec;
typedef struct {
int usec; // 12:10:10 seconds:msec:usec
int button;
int sensor[4]; // br tr bl tl bottom/top right/left
int total;
} sample_t;
void handle_sample(sample_t *s)
{
static int prev_usec = 0;
printf("%d.%03d %d %d %d %d %d %d\n",
s->usec>>20, (s->usec & 0xfffff)>>10, (s->usec - prev_usec)>>10,
s->total, s->sensor[0], s->sensor[1], s->sensor[2], s->sensor[3]);
prev_usec = s->usec;
}
int main(int argc, char **argv)
{
if (argc != 2) {
usage(NULL);
}
int fd;
if ((fd = open( argv[argc-1], O_RDONLY)) < 0) {
usage("cannot open device");
}
char name[80] = "Got nothing expected Nintendo";
int r = ioctl(fd, EVIOCGNAME(sizeof(name)), name);
printf("# %s \"%s\" margin=%d, divisor=%d option_d=%d\n",
getenv("DEVNAME"), name, margin, divisor, option_d);
if (r<0) {
usage("ioctl name failed");
}
printf("# t.ms + 10g br tr bl tl\n");
sample_t s = { .usec=-1, .button=0, .sensor={0,0,0,0}};
struct input_event ev;
while (read(fd, &ev, sizeof(ev)) == sizeof(ev)) {
if (start_sec==0) {
start_sec = ev.time.tv_sec;
} else if (ev.time.tv_sec > (60+start_sec)) {
printf("timeout after 60 seconds\n");
exit(0);
}
if (ev.type == EV_SYN) { // end if this time_stamp,
s.usec = (ev.time.tv_sec - start_sec) * 1024*1024; // >> 20 will give seconds
s.usec += ev.time.tv_usec;
s.total = s.sensor[0]+s.sensor[1]+s.sensor[2]+s.sensor[3];
handle_sample( &s);
} else if (ev.type == EV_KEY) {
if (ev.value) {
printf("button pressed\n ");
exit(0);
}
} else if (ev.type == EV_ABS) {
s.sensor[0x3 & ev.code] = ev.value;
} else {
printf("UNKNOWN type=0x%x code=0x%x value=0x%x\n", ev.type, ev.code, ev.value);
}
}
perror("wiibb: error reading");
}
Nu ser output fra programmet således ud
# /dev/input/event16 "Nintendo Wii Remote Balance Board" margin=10, divisor=100 option_d=1 # t.ms + 10g br tr bl tl 0.876 2 256 0 72 56 128 0.903 26 280 33 73 54 120 0.906 3 298 37 80 53 128 0.925 18 297 37 80 52 128 0.926 1 284 33 85 44 122 0.943 17 296 34 84 42 136 0.960 17 284 28 95 33 128 0.966 6 273 29 85 32 127 1.017 74 274 30 92 26 126
Det ser ud som om der er støj på dataene, så lad os kigge nærmere på dem via gnuplot, vi tager en 5 sekunders måling og plotter resultat. For at komme fri af nul-punktet vejer vi 4 styk 500gram Blå cirkel kaffe som jeg har bragt hjem fra Danmark til dette formål, scriptet ser således ud:
#!/bin/sh
# wiibb -a > fil; wiibb_gnuplot.sh < fil
# t.ms + 10g br tr bl tl
sec=1;kg=3;br=4;tr=5;bl=6;tl=7
FILE=$(basename $1 .log)-sensor
# scale total by 1/4 to have equal scales
awk 'NF==7 { $3=$3/4;print $0}' < $1 > $FILE.dat
f=`head -1 $FILE.dat | cut -f1 -d:`
t=`tail -1 $FILE.dat | cut -f1 -d:`
echo gnuplot of $FILE.dat over $t seconds to $FILE.png
gnuplot << EOF
set term png size 1024,512
set output "$FILE.png"
set autoscale
set xlabel "seconds"
set ylabel "sensor"
set y2label "kg"
set y2tics
set link y2 via y/25 inverse y*25
plot ["$f":"$t"] \
'$FILE.dat' using 1:$kg title "kg" with lines lw 3, \
'$FILE.dat' using 1:$br title "bottom right" with lines, \
'$FILE.dat' using 1:$tr title "top right" with lines, \
'$FILE.dat' using 1:$bl title "bottom left" with lines, \
'$FILE.dat' using 1:$tl title "top left" with lines
EOF
Da jeg prøvede nogle af de eksisterende programmer i mit første indlæg, var der meget flicker på de sidste cifre, og som man ser er der periodisk støj af forskellig størrelse på de forskellige sensorer, første indskydelse er at det hidrører fra netstøj og er på en eller anden måde relateret til 60 Hz.
Et simpel lavpas filtrering kan filtrere støjen væk der er 50-60 samples pr sekund. Inden vi laver vores endelige C-program laver vi lige et par test offline i AWK.
Lavpas filteret bidrager med 1% af forskellen til resultatet hver gang, da der er 50-60 samples pr sekund vil det tage et nogle sekunder før resultatet vil stabilisere sig, derfor bruger vi en meget større faktor 20% når forskellen er mere end 5 kg, idet vi antager at støjen er markant mindre end det.
Når resultatet ikke ændrer sig mere end +- 0.1 kg inden for 1 sekund, betragter vi resultatet som stabilt og målingen afsluttes.
Parametrene kan justeres ved at sætte env-variablerne FACTOR=0.01 og MARGIN=10 (0.1kg),
#!/bin/sh
# wiibb /dev/input/event1 > fil; plot_filter.sh < fil
# t.ms + xgram br tr bl tl
sec=1;xgram=3;br=4;tr=5;bl=6;tl=7
FILE=$(basename $1 .log)-filter
awk 'BEGIN {
margin='${MARGIN:-0.1}'
lowpass = 0
last_lp = 0
printf("# t raw lowpass diff sec_settled\n");}
NF==7 {
kg = $3/100.0
diff = lowpass - kg
if ((diff > 5) || (diff < -5)) { # more than 5 kg diff this is not noise
factor = 0.2 # adjust fast
} else {
factor = '${FACTOR:-0.01}'
}
lowpass -= diff * factor
if ((last_lp < (lowpass-margin)) || (last_lp > (lowpass+margin)) || (kg < 5)) {
last_lp = lowpass;
last_time = $1
} else if (($1-last_time) > 1.0) {
printf("# at t = %1.3f settled at %1.3f kg +- %1.3f for %s seconds\n", $1, lowpass, margin, $1-last_time)
printf("at t = %1.3f settled at %1.3f kg +- %1.3f for %s seconds\n", $1, lowpass, margin, $1-last_time) > "/dev/tty"
}
printf("%1.3f %1.2f %1.2f %1.2f %d # last=%1.3f\n", $1, kg, lowpass, diff, 100*($1-last_time), last_time)
}' <$1 >$FILE.dat
if [ $# = 2 ]; then
from=$1
to=$2
else
from=`awk '! /^#/ {print $1;exit}' $FILE.dat`
to=`awk 'END {print $1;exit}' $FILE.dat`
fi
echo gnuplot of $FILE.dat $from - $to seconds to $FILE.png
gnuplot << EOF
set term png size 1024,512
set output "$FILE.png"
set autoscale
set xlabel "seconds"
set ylabel "kg"
set ytics nomirror
set y2label "settled in msec."
set y2tics
set link y2 via y*10 inverse y/10
plot ["$from":"$to"] \
'$FILE.dat' using 1:2 title "raw" with lines, \
'$FILE.dat' using 1:3 title "lowpass factor ${FACTOR:-0.01}" with lines, \
'$FILE.dat' using 1:4 title "diff between two kg samples" with lines, \
'$FILE.dat' using 1:5 title "ms settled within ${MARGIN:-0.1} kg" with lines
EOF
Plottet af min vejning ser således ud
Så er der bare tilbage at kopiere funktionaliteten fra AWK-script over i C-programmet, det mest funktionen handle_sample() der skal rettes til, resultatet er:
/*
* wiibb.c - Copyright (c) 2017 peter@lorenzen.us
* This program is free software - BSD-licensed
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <linux/input.h>
void usage(char *mes)
{
printf("Usage: wiibb [-d] event_device\n");
printf(" filter and determine the weight on the balance board\n");
if (mes) printf("%s\n",mes);
exit(1);
}
int option_d=0;
#define dprint(...) option_d && fprintf(stderr, __VA_ARGS__)
#define ddprint(...) (option_d>1) && fprintf(stderr, __VA_ARGS__)
int margin = 10; // 100 gram
int divisor = 100;
time_t start_sec;
typedef struct {
int usec; // 12:10:10 seconds:msec:usec
int button;
int sensor[4]; // br tr bl tl bottom/top right/left
int total;
} sample_t;
void handle_sample(sample_t *s)
{
static int prev_usec = 0;
static int xgram = 0; // each unit is ten gram
static int last_xgram = 0;
static int last_usec = 0;
int diff = xgram - s->total;
if ((diff > 500) || (diff < -500)) { // more than 5 kg diff this is not noise
xgram -= diff / 5; // adjust fast
} else {
xgram -= diff / divisor;
}
dprint("%d.%03d %d %d %d %d %d %d",
s->usec>>20, (s->usec & 0xfffff)>>10, (s->usec - prev_usec)>>10,
s->total, s->sensor[0], s->sensor[1], s->sensor[2], s->sensor[3]);
ddprint("# last_usec: %d.%03d xgram: %d last_xgram: %d\n",
last_usec>>20, (last_usec & 0xfffff)>>10, xgram, last_xgram );
dprint("\n");
prev_usec = s->usec;
if ((last_xgram < (xgram-margin)) || (last_xgram > (xgram+margin)) || (xgram < 500)) {
last_xgram = xgram; // start a new stable
last_usec = s->usec;
} else if ((s->usec-last_usec) > (1024*1024)) { // stable for a second, we are DONE
char date_time[100];
time_t sec = start_sec + s->usec/(1024*1024);
strftime(date_time, sizeof(date_time), "%Y%m%d-%H%M", localtime(&sec));
printf("#date: %s kg: %1.2f lbs: %1.1f\n", date_time, xgram/100.0, xgram/45.4);
exit(0);
}
}
int main(int argc, char **argv)
{
if (argc==3) {
if (strcmp(argv[1], "-d")==0) {
option_d = 1;
} else if (strcmp(argv[1], "-dd")==0) {
option_d = 2;
}
} else if (argc != 2) {
usage(NULL);
}
char *env;
if ((env = getenv("MARGIN"))) {
margin = atoi(env); // 100 gram
}
if ((env = getenv("DIVISOR"))) {
divisor = atoi(env);
}
int fd;
if ((fd = open( argv[argc-1], O_RDONLY)) < 0) {
usage("cannot open device");
}
char name[80] = "Got nothing expected Nintendo";
int r = ioctl(fd, EVIOCGNAME(sizeof(name)), name);
dprint("# %s \"%s\" margin=%d, divisor=%d option_d=%d\n",
getenv("DEVNAME"), name, margin, divisor, option_d);
if (r<0) {
usage("ioctl name failed");
}
dprint("# t.ms + 10g br tr bl tl\n");
sample_t s = { .usec=-1, .button=0, .sensor={0,0,0,0}};
struct input_event ev;
while (read(fd, &ev, sizeof(ev)) == sizeof(ev)) {
if (start_sec==0) {
start_sec = ev.time.tv_sec;
} else if (ev.time.tv_sec > (60+start_sec)) {
printf("timeout after 60 seconds\n");
exit(0);
}
if (ev.type == EV_SYN) { // end if this time_stamp,
s.usec = (ev.time.tv_sec - start_sec) * 1024*1024; // >> 20 will give seconds
s.usec += ev.time.tv_usec;
s.total = s.sensor[0]+s.sensor[1]+s.sensor[2]+s.sensor[3];
handle_sample( &s);
} else if (ev.type == EV_KEY) {
if (ev.value) {
printf("button pressed\n ");
exit(0);
}
} else if (ev.type == EV_ABS) {
s.sensor[0x3 & ev.code] = ev.value;
} else {
printf("UNKNOWN type=0x%x code=0x%x value=0x%x\n", ev.type, ev.code, ev.value);
}
}
perror("wiibb: error reading");
}
I begyndelse køres scriptet med debug print på så der bliver lidt statistik at kigge på senere, og måske optimere MARGIN og DIVISOR eller hvad der nu måtte vise sig. Filerne ligger under /var/log/wiibb
!/bin/bash
# called via this udev rule:
# SUBSYSTEM=="input", DEVPATH=="*:057E:0306*", ACTION=="add" RUN+="/bin/sh -c '/usr/local/sbin/wiibb.sh >>/tmp/wiibb.log 2>&1'"
# we rely on DEVPATH and DEVNAME, the rest we get from sysfs
#export PATH=/usr/local/bin:/usr/local/sbin:$PATH
set -x
DEVICE=/sys/$DEVPATH/device
LED=$DEVICE/leds/*:057E:0306*:blue:p0/brightness
# sets HID_UNIQ
. $DEVICE/uevent
MAC=$(echo $HID_UNIQ | tr a-f A-F)
DATE_TIME=$(date "+%Y%m%d-%H%M")
set
echo Wii Board $MAC accessed via $DEVNAME $DEVPATH | sudo tee /dev/kmsg >/dev/console
echo 1 > $LED; sleep 1; # when it turns off it indicates device is off
/usr/local/sbin/wiibb -dd $DEVNAME >/tmp/wiibb-$DATE_TIME.log1 2>/tmp/wiibb-$DATE_TIME.log2
if dpkg --compare-versions $(bluetoothctl -v) lt 5.43 ; then
hcitool dc $MAC # use hcitool to disconnect if bluetoothctl is old
else
echo disconnect $MAC | bluetoothctl
fi
KG=$(cut -f4 -d' ' /tmp/wiibb-$DATE_TIME.log1)
mkdir -p /var/log/wiibb
cat /tmp/wiibb-$DATE_TIME.log1 /tmp/wiibb-$DATE_TIME.log2 | xz -z >/var/log/wiibb/$DATE_TIME-$KG.xz
rm -f /tmp/wibb-$DATE_TIME*
echo "WiiBB $MAC $_DATE_TIME $KG kg"| sudo tee /dev/kmsg >/dev/console
# Udev wiibb Call wiibb.sh when ever Wii Balanaceboard is turned on
SUBSYSTEM=="input", ENV{DEVNAME}=="/dev/input/event*", DEVPATH=="*:057E:0306*", ACTION=="add", RUN+="/bin/sh -c '/usr/local/sbin/wiibb.sh $DEVNAME >>/tmp/wiibb.log 2>&1'"
Listen her bliver sikkert mere udførlig engang jeg skal installere det på en ny maskine, men der skal ihverfald installeres disse pakker
sudo apt-get install xz gnuplot # raspbian pre Stretch (før sommer 2017) installer gnuplot5 sudo apt-get install libxwiimote-dev xwiimote libxwiimote2]]>
Plus dem vi så på i mit sidste indlæg Badevægt, problemet med de løsninger var permanent parring. så det skal vi lige have styr på først.
Der er sket meget med bluetooth på Linux siden 2008, da den oprindelige kode blev skrevet, dengang klarede applikationerne stortset det hele selv. Og de løsninger jeg præsenterede sidste gang baserede sig alle på den rå bluetooth adgang.
I dag er abstrakstions niveauet hævet, og mange af de basale operationer klares af Bluez, som bluetooth frame-work hedder under Linux. Dermed kan man parre Wii-Fit direkte fra en GUI Bluetooth manager, eller hvis man er mere til kommando-linien så brug bluetoothctl således:
$ bluetoothctl [NEW] Controller B8:27:EB:C6:64:03 raspberrypi [default] [NEW] Device 34:AF:2C:2D:A8:C2 Nintendo RVL-WBC-01 [CHG] Device 34:AF:2C:2D:A8:C2 Connected: yes [CHG] Device 34:AF:2C:2D:A8:C2 Connected: no [CHG] Device 34:AF:2C:2D:A8:C2 Connected: yes # herover kommer der løbende status # nedenfor en kommando prompt - prøv help [bluetooth]# scan on [bluetooth]# pair 34:AF:2C:2D:A8:C2 [bluetooth]# trusted 34:AF:2C:2D:A8:C2 # når man trykker på knappen bliver enheden tændt og forbundet # for at bruge enheden udfør nedenstående [bluetooth]# connect 34:AF:2C:2D:A8:C2 # og når vi er færdige med at bruge den [bluetooth]# disconnect 34:AF:2C:2D:A8:C2
Der er allerede en driver hid-wiimote installeret under Linux, og når enheden først er parret vil den dukke op når Wii-Fit bliver tændt og fjernet når man disconnecter. Nedenfor er output fra dmesg:
$ dmesg ... wiimote 0005:057E:0306.0004: unknown main item tag 0x0 wiimote 0005:057E:0306.0004: hidraw2: BLUETOOTH HID v6.00 Gamepad [Nintendo RVL-WBC-01] on b8:27:eb:c6:64:03 wiimote 0005:057E:0306.0004: New device registered wiimote 0005:057E:0306.0004: detected device: Nintendo Wii Balance Board wiimote 0005:057E:0306.0004: detected extension: Nintendo Wii Balance Board input: Nintendo Wii Remote Balance Board as /devices/platform/soc/3f201000.uart/tty/ttyAMA0/hci0/hci0:13/0005:057E:0306.0004/input/input3 ... wiimote 0005:057E:0306.0004: Device removed
Så prøver vi: batteri, ud, batteri ind igen og Wii-Fit bliver automatisk detekteret igen når vi trykker på knappen, men ikke med den samme device. Så problemet er allerede løst, der er en hid-driver, så nu kommer vi til det svære LÆS MANUALEN: man xwiimote
Her står bl.a. hvor man kan finde sin wii-fit device i mit tilfælde:
ls -l /sys/module/hid_wiimote/drivers/hid:wiimote/0005:057E:0306.0005 -r--r--r-- 1 root root 4096 Jan 27 02:42 bboard_calib -r--r--r-- 1 root root 4096 Jan 27 02:42 country -r--r--r-- 1 root root 4096 Jan 27 02:42 devtype lrwxrwxrwx 1 root root 0 Jan 27 02:42 driver -> ../../../../../../../../../bus/hid/drivers/wiimote -rw-rw-r-- 1 root root 4096 Jan 27 02:42 extension drwxr-xr-x 3 root root 0 Jan 27 02:31 hidraw drwxr-xr-x 3 root root 0 Jan 27 02:41 input drwxr-xr-x 3 root root 0 Jan 27 02:42 leds -r--r--r-- 1 root root 4096 Jan 27 02:42 modalias drwxr-xr-x 2 root root 0 Jan 27 02:42 power drwxr-xr-x 3 root root 0 Jan 27 02:42 power_supply -r--r--r-- 1 root root 4096 Jan 27 02:42 report_descriptor lrwxrwxrwx 1 root root 0 Jan 27 02:42 subsystem -> ../../../../../../../../../bus/hid -rw-r--r-- 1 root root 4096 Jan 27 02:42 uevent
Og der er jo det hele. HID device med Kalibrerings data, lysdiode, batteri information, osv.
På manualsiden var der også en henvisning til xwiishow, et C-program med kildetekst, der viser status på alle Wii-enheder dynamisk, med fin character grafik. Alle sensor-værdierne kan ses og lysdioden kan tændes og slukkes, knappen er dog ikke med.
HID enheder kan normalt bruges uden at der skal installeres drivere.
I min verden er det første program man laver et der skriver “Hello World”, blot for at få alt det basale på plads og vise at der er hul igennem, så det vil jeg også gøre her. Den eneste output enhed der er på Wii-Fit er den blå lysdiode, så det bliver den.
Jeg vil gerne måle vægten automatisk hver gang der er nogen der bruger den, ikke noget med at man skal starte et program via GUI eller kommando-linie
Under Linux er det udev der holder styr på devices der kommer og går. Vi kan følge med i hvad der sker via:
$ udevadm monitor # only relevant lines shown monitor will print the received events for: UDEV - the event which udev sends out after rule processing KERNEL - the kernel uevent KERNEL[275.636718] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256 (bluetooth) UDEV [275.639448] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256 (bluetooth) KERNEL[275.702511] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid) KERNEL[275.712277] add /module/hid_wiimote (module) KERNEL[275.712913] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/hidraw/hidraw1 (hidraw) KERNEL[275.713030] add /bus/hid/drivers/wiimote (drivers) UDEV [275.713266] add /module/hid_wiimote (module) UDEV [275.713363] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid) UDEV [275.715145] add /bus/hid/drivers/wiimote (drivers) UDEV [275.718351] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/hidraw/hidraw1 (hidraw) KERNEL[275.771624] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/leds/0005:057E:0306.0002:blue:p0 (leds) UDEV [275.776623] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/leds/0005:057E:0306.0002:blue:p0 (leds) KERNEL[275.841784] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18 (input) KERNEL[275.841969] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/event16 (input) KERNEL[275.842166] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/js1 (input) KERNEL[275.842271] change /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid) UDEV [275.847737] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18 (input) KERNEL[275.851425] change /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/power_supply/wiimote_battery_34:af:2c:2d:69:fe (power_supply) UDEV [275.854009] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/js1 (input) ... KERNEL[277.005331] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/event16 (input) KERNEL[277.028347] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/js1 (input) KERNEL[277.060483] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18 (input) KERNEL[277.060543] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/leds/0005:057E:0306.0002:blue:p0 (leds) UDEV [277.070917] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/event16 (input) UDEV [277.075802] change /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid) UDEV [277.079230] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/event16 (input) UDEV [277.079341] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18/js1 (input) UDEV [277.079990] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/leds/0005:057E:0306.0002:blue:p0 (leds) UDEV [277.080135] change /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/power_supply/wiimote_battery_34:af:2c:2d:69:fe (power_supply) UDEV [277.081084] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/input/input18 (input) KERNEL[277.084245] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/power_supply/wiimote_battery_34:af:2c:2d:69:fe (power_supply) KERNEL[277.084431] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/hidraw/hidraw1 (hidraw) KERNEL[277.084509] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid) UDEV [277.086365] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/power_supply/wiimote_battery_34:af:2c:2d:69:fe (power_supply) UDEV [277.088054] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002/hidraw/hidraw1 (hidraw) UDEV [277.089331] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256/0005:057E:0306.0002 (hid) KERNEL[279.064318] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256 (bluetooth) UDEV [279.065836] remove /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.0/bluetooth/hci0/hci0:256 (bluetooth)
Den enkleste måde at få vores program til at starte når Wii-Fit bliver tændt er at lave en en ny regel: /etc/udev/rules.d/99-wiibb.rules
# to see what we have available just print all ENV to file # you could get same information using this command "udevadm monitor -p" DRIVERS=="wiimote", RUN+="/bin/sh -c '(date;set) >>/tmp/wiibb-log'"
FIXME: Virker ikke under Ubuntu-16.10 efter reboot, da / var monteret read-only da systemd-udevd blev startet see discussion here: http://askubuntu.com/questions/883843/udev-rules-scripts-has-only-read-only-access-to-ubuntu16-10
Så tænder vi og slukker et par gange, og kigger på de mange variable vi kan se i /tmp/wiibb-log, Her lægger vi specielt mærke til:
Næste trin er at lade udev kalde et program der morser “hello world” og derefter slukker enheden, og det er præcis hvad dette shell-script gør:
#!/bin/bash
# wiibb.sh Copyright Peter@Lorenzen.us Januar 2017, This is BSD-style free software
# called with DEVPATH and HID_UNIQ set
export PATH=/usr/local/bin:/usr/local/sbin:$PATH
LED=/sys/$DEVPATH/leds/$(basename $DEVPATH):blue:p0/brightness
MAC=$(echo $HID_UNIQ | tr a-f A-F)
h="...."; e="."; l=".-.."; o="---"; w=".--"; r=".-."; d="-.."
led_on() { (echo 1; sleep $1; echo 0) > $LED; }
echo Wii Board $MAC installed at $DEVPATH | sudo tee /dev/kmsg >/dev/console
echo connect $MAC | bluetoothctl
text="hello world"
for word in $text; do
chars=(`echo $word | fold -w1`)
for ch in "${chars[@]}"; do
eval 'morse="${'"$ch"'}"'
c_array=(`echo $morse | fold -w1`)
for cm in "${c_array[@]}"; do
case $cm in
.) led_on 1; sleep 1;;
-) led_on 3; sleep 1;;
esac
done
sleep 2
done
sleep 4
done
echo 1 > $LED; sleep 1; # when it turns off it indicates device is off
echo disconnect $MAC | bluetoothctl
echo Wii Board $MAC done | sudo tee /dev/kmsg >/dev/console
Hmm – Det virkede ikke for mig og ganske rigtigt der er en BUG i bluetoothctl der kun kommer til udtryk når man kører det fra et script, interaktivt virker det fint. Ubuntu-16.10 har bluez-5.41, Raspian har bluez-5.23. Problemet er løst i bluez-5.43. Jeg har beskrevet hvordan man installerer den nyeste version fra Zesty under Ubuntu 16.04 eller 16.10 her http://askubuntu.com/a/884062/655086, Der sker følgende:
#!/bin/bash
sudo apt-get install devscripts debhelper dh-autoreconf flex bison libdbus-glib-1-dev libglib2.0-dev libcap-ng-dev libudev-dev l
ibreadline-dev libical-dev check dh-systemd libebook1.2-dev
wget https://launchpad.net/ubuntu/+archive/primary/+files/bluez_5.43.orig.tar.xz
wget https://launchpad.net/ubuntu/+archive/primary/+files/bluez_5.43-0ubuntu1.debian.tar.xz
wget https://launchpad.net/ubuntu/+archive/primary/+files/bluez_5.43-0ubuntu1.dsc
tar xf bluez_5.43.orig.tar.xz
cd bluez-5.43
tar xf ../bluez_5.43-0ubuntu1.debian.tar.xz
# install patches relevant for rpi-3 bluetooth
. /etc/os-release
if [ $ID = raspbian ]; then
wget https://gist.github.com/pelwell/c8230c48ea24698527cd/archive/3b07a1eb296862da889609a84f8e10b299b7442d.zip
cd debian/patches
unzip ../../3b07a1eb296862da889609a84f8e10b299b7442d.zip
for i in c8230c48ea24698527cd-3b07a1eb296862da889609a84f8e10b299b7442d/*;do
mv $i .
basename $i >> series
done
rmdir c8230c48ea24698527cd-3b07a1eb296862da889609a84f8e10b299b7442d
cd ../..
fi
# end of Raspian related patches
debchange --local=~lorenzen 'Backport to Xenial'
debuild -b -j4
cd ..
sudo dpkg -i *.deb
Ovenstående virker også under Raspian, alternativt se her
http://stackoverflow.com/questions/41707164/connect-ble-devices-with-raspberry-pi-3-b
Man kunne også blot installere bluez fra debian stretch, eller vente et par måneder så er det standard
how-to-use-stretch-testing-packages
Når det så virker installeres shell-scriptet i /usr/local/sbin/wiibb.sh, og en opdateret version af vores udev-rule /etc/udev/rules.d/99-wiibb.rules skal være som nedenfor
# Whenever a Wii Balance Board is turned on wiibb.sh is called
# wiibb.sh reads the weight and turns the device off when done
SUBSYSTEM=="hid", ENV{HID_NAME}=="Nintendo RVL-WBC-01" ACTION=="change", DRIVERS=="wiimote", RUN+="/usr/sbin/wiibb.sh"
Hvis man så er radio-amatør (oz1dmk), kan man forvisse sig om at hele frame-worket virker, der er endda log-entries i dmesg.
Det var sådan set det hele, resten er blot at skrive et program til at læse vægten. Vælg et programmerings-sprog og kom igang.
Næste gang laver vi lige et sådant program i C
]]>
Kurven er altså ikke min, alene af den grund af min jo er pund.
Jakob må have en magisk maskine der overfører dataene fra vægten til WEB-en, Mon ikke det involverer mindst en kugle-pen, en A4-side og Matlab. Jeg har tænkt mig at lave min alene med Bash, “The VI development kit”, og et stykke konsum-elektronik.
På Ama
zon kan man købe masser af bluetooth badevægte, så i stedet for at kigge ned på vægten kan man se hvad man vejer på sin telefon. Det er trods alt lidt for moderne til mig, og havde jeg nu købt en af dem var denne artikel færdig allerede nu.
Typisk er der heller ikke nogen dokumentation på hvordan man får data ud at tingesten.
Det viser sig at der for år tilbage var en masse artikler om hvordan man kunne lave en “IofT badevægt” baseret på en Wii balance board (2007), det er en robust lille plastik sag, hvor der er en vægt bygget ind i de 4 fødder. ideen var at disse værdier overføres til spille-konsolen via bluetooth i reeltid. Min dreng blev meget skuffet da han så den og jeg fortalte ham at vi ikke også fik en Wii. Det ville ellers “også” have være en færdig løsning som man kan se i denne video Wii-Fit
Hvis man googl
er Wii Scale kommer der en masse projekter op, der er færdige lukkede programmer og open-source projekter af varierende kvalitet. Der altså dokumentation tilgængelig og dermed er der ingen vej tilbage.
Jeg købte et par hos b&h photo for $15 stykket, leveret
De kom dagen efter og det første jeg prøvede var at installere http://snosrap.com/wiiscale/ (2013) på min Mac (MacOS 10.12) og inden for et minut kunne jeg se at jeg vejede for meget!.
Applikationen kan sættes op til at gemme resultaterne i en csv-fil, og der kan kaldes en WEB-side, så faktisk er der alt jeg har brug for, MEEEN jeg kunne ikke få den til at gemme vægten, det skyldes sikkert bit-rot, applicationen er skrevet til OSX-10.8.
Kildetekst til at parre Mac-en med Wii-Fit permanent er tilgengængelig https://github.com/snosrap/WiiPair.git men selve applications kildeteksten kan jeg ikke finde.
Der er mange der har leget med Wii-Fit og Linux, der er inspiration her:
De bygger alle sammen videre på hinanden, og de kræver at der er en masse programmel installeret dele som ikke er supporteret på moderne Linux, og der er problemer med permanent parring med Wii-Fit. Men bortset fra det er det muligt at få hul igennem relativt let, man skal blot parre den hver gang.
Den bedste permanente løsning jeg har set er en blyant tapet til undersiden så man nemt kan parre vægten hver eneste gang man bruger den.
Det ville aldrig gå i min husholdning, Så selv om der kommer mere og mere glimmer på så er der ingen der har kunnet/villet fixe fundamentet.
Men kan du leve med blyant løsningen, så kan du godt bestille en Wii-Fit idag, vil du have en noget mere elegant løsning må du vente på mit næste indlæg
]]>