Comment configurer Bluetooth sur Linux de manière compliquée


En préparation du forum informatique annuel, j'ai eu l'idée de créer un simple manipulateur contrôlé par une manette de jeu sans fil pour démontrer les capacités des microcontrôleurs et des ordinateurs à carte unique. À portée de main se trouvait un contrôleur TRIC, plusieurs servomoteurs, un constructeur de fer, et un mois avant le début du forum.


«Tout se déroule comme prévu», mais pas dans ce cas.


Étape 1. Préparation


TRIC à bord de Linux était un buste pour un tel manipulateur, mais "le point est la banalité d'utilisation et de maintenance" (citation de ClusterM à propos de Linux dans un interphone intelligent ).


Après avoir lu la spécification , il a été découvert qu'il dispose de Bluetooth. Si vous avez travaillé avec ce contrôleur, vous savez que le transfert de programmes se fait via le Wi-Fi et qu'il n'y a pas d'autres moyens pratiques de communiquer avec lui. Il n'y a aucune mention de Bluetooth dans le menu. Mais comment ça?


Armé de SSH, d'un tournevis et de curiosité, j'ai commencé à chercher le Bluetooth. Le système comprenait hcitool, hciconfig et le démon bluetoothd. Tous ont dit qu'il n'était pas là.


root@trik-7dda93:~# hcitool dev Devices: 

 root@trik-7dda93:~# hciconfig hci0 Can't get device info: No such device 

 root@trik-7dda93:~# bluetoothd -n & [1] 5449 root@trik-7dda93:~# bluetoothd[5449]: Bluetooth daemon 4.101 bluetoothd[5449]: Starting SDP server bluetoothd[5449]: Bluetooth Management interface initialized 

Appelant des amis à la recherche d'un module USB externe, j'ai continué à chercher.


Après avoir démonté le contrôleur, le module Jorjin WG7311-0A a été trouvé. La spécification indique qu'il y a vraiment une connexion Wi-Fi, Bluetooth et même une radio FM. L'interface pour communiquer avec Bluetooth est UART, et elle est activée via BT_EN.



Après avoir lu comment le module Bluetooth est connecté via UART via hcitool, j'ai tenté ma chance et rien. Deux des trois ports UART gratuits étaient silencieux.


Mais nous avons contact BT_EN! Il est possible que le module soit simplement éteint et ne réponde pas aux demandes. Après avoir examiné le périphérique du noyau Linux pour les périphériques ARM, un fichier a été trouvé où tous les contacts utilisés par SoC sont enregistrés. En ouvrant arch/arm/mach-davinci/board-da850-trik.c dans le code source du noyau, un contact GPIO pour Bluetooth a été trouvé. Victoire! Pensai-je.


 static const short da850_trik_bluetooth_pins[] __initconst = { DA850_GPIO6_11, /*BT_EN_33 */ DA850_GPIO6_10, /*BT_WU_33*/ -1 }; 

Étape 2. Offensive


Pour activer un contact via GPIO, vous devez trouver son numéro de série de bout en bout. Nous trouvons la ligne suivante dans le code du noyau avec une demande d'initialisation du contact BT_EN_33 dans arch/arm/mach-davinci/board-da850-trik.c :


 ret = gpio_request_one(GPIO_TO_PIN(6, 11), GPIOF_OUT_INIT_LOW, "BT_EN_33"); 

Il utilise la macro GPIO_TO_PIN. Voir la description de la macro dans arch/arm/mach-davinci/include/mach/gpio-davinci.h :


 /* Convert GPIO signal to GPIO pin number */ #define GPIO_TO_PIN(bank, gpio) (16 * (bank) + (gpio)) 

En l'utilisant, vous pouvez trouver le numéro de contact de bout en bout. Nous obtenons que 16 * 6 + 11 = 107. Passons maintenant à l'inclusion du contact.


 echo 1 >> /sys/devices/virtual/gpio/gpio107/value 

0 ou 1 dans la commande echo est l'état du contact.


Exécutez la commande pour vous connecter et ...


 root@trik-7dda93:~# hciattach /dev/ttyS0 texas Found a Texas Instruments' chip! Firmware file : /lib/firmware/TIInit_7.6.15.bts can't open firmware file: No such file or directory Warning: cannot find BTS file: /lib/firmware/TIInit_7.6.15.bts Device setup complete 

incompréhensible pour nous (pour le moment) des messages d'erreur. Nous essayons de configurer l'appareil via hcitool:


 root@trik-7dda93:~# hcitool dev Devices: 

Il n'y a pas d'appareils, bien que l'initialisation soit censément passée. Nous essayons de nous connecter une deuxième fois, mais avec un autre type d'adaptateur:


 root@trik-7dda93:~# hciattach /dev/ttyS0 texasalt Texas module LMP version : 0x06 Texas module LMP sub-version : 0x1f0f internal version freeze: 15 software version: 6 chip: wl1271 (7) Opening firmware file: /etc/firmware/wl1271.bin Could not open firmware file /etc/firmware/wl1271.bin: No such file or directory (2). Device setup complete 

Et encore une fois, rien. Revenons à la première erreur et appliquons la connaissance de l'anglais:


 Warning: cannot find BTS file: /lib/firmware/TIInit_7.6.15.bts 

Nous ouvrons le dossier / lib / firmware avec firmware et ne trouvons pas le fichier dont nous avons besoin. Après une longue recherche sur Internet, nous trouvons le fichier souhaité sur le référentiel TI et le téléchargeons. D'autres versions du même fichier ont refusé de fonctionner.


 curl -k https://git.ti.com/wilink8-bt/ti-bt-firmware/blobs/raw/45897a170bc30afb841b1491642e774f0c89b584/TIInit_7.6.15.bts > TIInit_7.6.15.bts cp TIInit_7.6.15.bts /lib/firmware/TIInit_7.6.15.bts 

Nous redémarrons le contrôleur et nous nous reconnectons:


 root@trik-7dda93:~# echo 1 >> /sys/devices/virtual/gpio/gpio107/value root@trik-7dda93:~# hciattach /dev/ttyS0 texas Found a Texas Instruments' chip! Firmware file : /lib/firmware/TIInit_7.6.15.bts Loaded BTS script version 1 Device setup complete 

Hourra! Le firmware a démarré. Vérification de hciconfig:


 root@trik-7dda93:~# hciconfig hci0: Type: BR/EDR Bus: UART BD Address: 78:**:**:**:**:B3 ACL MTU: 1021:4 SCO MTU: 180:4 DOWN RX bytes:509 acl:0 sco:0 events:21 errors:0 TX bytes:388 acl:0 sco:0 commands:21 errors:0 

Nous démarrons le service bluetoothd, recherchons des appareils et détectons notre module:


 root@trik-7dda93:~# bluetoothd -n & [1] 4689 bluetoothd[4689]: Bluetooth daemon 4.101 bluetoothd[4689]: Starting SDP server bluetoothd[4689]: Bluetooth Management interface initialized bluetoothd[4689]: Parsing /etc/bluetooth/serial.conf failed: No such file or directory bluetoothd[4689]: Could not get the contents of DMI chassis type bluetoothd[4689]: Adapter /org/bluez/4689/hci0 has been enabled root@trik-7dda93:~# hciconfig hci0 piscan 

Une recherche informatique trouve un appareil:



Pour activer Bluetooth, vous pouvez créer un script:


 #!/bin/bash case "$1" in start) echo 1 >> /sys/devices/virtual/gpio/gpio107/value bluetoothd -n & hciattach /dev/ttyS0 texas hciconfig hci0 piscan ;; stop) ;; restart) ;; status) ;; *) ;; 

Et ajoutez-le à l'exécution automatique:


 cp init-bluetooth /etc/init.d/init-bluetooth update-rc.d init-bluetooth enable 99 

Le redémarrage et l'arrêt du module se comportent de façon imprévisible, donc les options d'arrêt et de redémarrage n'ont pas de commandes.


Étape 3. Vérification de la communication


Le moyen le plus simple de vérifier la communication dans les deux sens est le service de port COM. Avec quelques commandes, allumez-le:


 root@trik-7dda93:~# sdptool add --channel=3 SP Serial Port service registered root@trik-7dda93:~# mknod -m 666 /dev/rfcomm0 c 216 0 root@trik-7dda93:~# rfcomm watch /dev/rfcomm0 3 /sbin/getty rfcomm0 115200 linux Waiting for connection on channel 3 

Nous nous connectons depuis le téléphone et voyons une invitation à entrer dans le système:



Aucun des terminaux testés ne permettait d'entrer un mot de passe utilisateur vide, j'ai donc dû envoyer des informations de connexion à l'aide de la redirection de thread dans une session SSH.


Étape 4. ./configure && make


En suivant les instructions pour connecter une manette de jeu à Linux, nous rencontrons les problèmes suivants:


  • BlueZ dans la distribution est obsolète et ne comprend pas les commandes du démon sixad, qui établit une connexion avec la manette de jeu
  • La nouvelle version BlueZ de la source refuse de compiler en raison de nombreuses dépendances
  • La nouvelle BlueZ de Debian nécessite udev et systemd, qui sont absents de la distribution actuelle

La seule dépendance qui a pu satisfaire était le module du noyau uinput.


Pour ce faire:


  • obtenir la configuration du noyau actuel sur l'appareil

 cp /proc/config.gz config.gz gunzip config.gz 

  • télécharger le code du noyau
  • télécharger et installer la chaîne d'outils
  • copiez la configuration du noyau dans le dossier avec le code du noyau
  • ajouter le module uinput à la configuration

 echo "CONFIG_INPUT_UINPUT=m" >> config 

  • démarrer l'assemblage en allumant d'abord la chaîne d'outils

 source /opt/trik-sdk/environment-setup-arm926ejste-oe-linux-gnueabi make 

  • copier les modules du noyau sur la carte mémoire

 make INSTALL_MOD_PATH=/mnt/trik-sd modules_install 

  • construire l'image uBoot et la copier dans / boot

 make uImage cp arch/arm/boot/uImage /mnt/trik-sd/boot/uImage-3.6.7 

Maintenant, le programme ne jure pas sur l'absence d'un module noyau, mais nous ne pouvons rien faire. Les instructions pour la manette de jeu vous seront utiles plus tard.


Étape 5. Cuire la bouillie de la hache


Arriver au plan "tyap-blooper". Puisqu'il n'y a aucun moyen pratique de mettre les programmes nécessaires sur la distribution d'origine, nous mettrons quelque chose de populaire. Le processeur a une architecture ARMv5TE, ce qui signifie qu'il existe des distributions pour lui.


Nous essayons de décompresser et d'exécuter Arch Linux universel pour ARM et lors du chargement dans la console, nous voyons que systemd nécessite une version de noyau plus récente, que nous n'avons pas. Les tentatives de transfert du noyau 4.16 ont échoué et cela a pris trop de temps.


Nous passons à une autre option - Debian. Une image disque avec un système installé pour ARM existe, mais il est préférable de mettre un système propre avec les packages et les paramètres nécessaires pour nous.


Installation dans QEMU


Téléchargez l'image d'installation (lien vers .iso ) et installez QEMU.
Nous avons également besoin du noyau et de l'image initrd pour démarrer l'installation, qui peut être téléchargée ici .


Créez une image d'une carte mémoire avec la taille d'une vraie carte mémoire (dans ce cas 4 Go):


 qemu-img create -f raw debian.img 4G 

Nous commençons l'installation:


 qemu-system-arm -M versatilepb -kernel vmlinuz-3.2.0-4-versatile -initrd initrd.gz -hda debian.img -cdrom debian-7.11.0-armel-CD-1.iso 

Si vous souhaitez créer une disposition de disque d'une distribution d'origine relative non standard, laissez d'abord la partition racine, sinon vous devrez modifier les paramètres de démarrage du noyau dans uBoot. Il y a le numéro de la partition sur laquelle se trouve le système de fichiers racine.


Le balisage standard contient:


  1. Partition EXT4 pour un système de fichiers racine de 1,3 Go
  2. Partition FAT32 pour le stockage des données utilisateur d'une taille de 500 Mo

La sortie fdisk pour l'image de la distribution d'origine:


 Disk: trik-distro.img geometry: 893/64/63 [3604478 sectors] Signature: 0xAA55 Starting Ending #: id cyl hd sec - cyl hd sec [ start - size] ------------------------------------------------------------------------ 1: 83 1023 3 32 - 1023 3 32 [ 1040382 - 2564096] Linux files* 2: 0C 64 0 1 - 1023 3 32 [ 8192 - 1032190] Win95 FAT32L 3: 00 0 0 0 - 0 0 0 [ 0 - 0] unused 4: 00 0 0 0 - 0 0 0 [ 0 - 0] unused 

Après avoir réglé les paramètres, nous partons boire quelques tasses de thé, car l'émulateur n'est pas beaucoup plus rapide qu'un vrai processeur ARM.


Pour démarrer le système installé, vous avez besoin d'une autre image initrd, qui peut être prise à partir d'ici .


Nous démarrons le système:


 qemu-system-arm -M versatilepb -kernel vmlinuz-3.2.0-4-versatile -initrd initrd.img-3.2.0-4-versatile -hda debian.img -append "root=/dev/sda1" 

Configuration du système


Après le démarrage, nous entrons dans le superutilisateur, vérifions la connexion à Internet, mettons à jour les référentiels et le système, mettons le minimum de programmes:


 apt-get update apt-get upgrade apt-get install curl git mc htop joystick 

Terminaux


Nous éditons /etc/inittab , /etc/inittab les terminaux inutiles, activons l'UART dont nous avons besoin pour nous et ajoutons une entrée automatique pour le bon utilisateur (utilisez root uniquement lors du débogage). La saisie automatique est utile si vous prévoyez d'exécuter le shell pour le contrôle sur le contrôleur.


 1:2345:respawn:/sbin/getty 38400 tty1 --autologin root #2:23:respawn:/sbin/getty 38400 tty2 #3:23:respawn:/sbin/getty 38400 tty3 #4:23:respawn:/sbin/getty 38400 tty4 #5:23:respawn:/sbin/getty 38400 tty5 #6:23:respawn:/sbin/getty 38400 tty6 uart:12345:respawn:/sbin/getty -L 115200 ttyS1 

Bluetooth et wifi


Installez bluez-utils et wpasupplicant pour accéder au Wi-Fi et au Bluetooth.


 apt-get install bluez-utils wpasupplicant 

Nous désactivons l'interface eth0 et configurons l'interface wlan1 dans /etc/network/interfaces :


 # /etc/network/interfaces -- configuration file for ifup(8), ifdown(8) # The loopback interface auto lo iface lo inet loopback # Wireless interfaces auto wlan1 iface wlan1 inet dhcp wireless_mode managed wireless_essid any wpa-driver wext wpa-conf /etc/wpa_supplicant.conf 

Ajoutez le réseau à l'avance à /etc/wpa_supplicant.conf , car faire cela sur le contrôleur lui-même n'est pas si pratique:


 wpa_passphrase ssid password >> /etc/wpa_supplicant.conf 

Si vous ne disposez pas d'un accès Wi-Fi, vous pouvez utiliser UART pour une configuration supplémentaire, mais gardez à l'esprit que par défaut, le noyau affiche toutes les erreurs sur ce terminal. Par conséquent, pendant le fonctionnement, un message soudain du noyau ou du service peut vous interrompre.


Ajoutez un script pour activer Bluetooth. Cette fois, modifiez /etc/init.d/bluetooth :


  139: case $1 in start) echo 1 >> /sys/devices/virtual/gpio/gpio107/value  168: hciattach /dev/ttyS0 texas log_end_msg 0 ;; 

Ainsi, tous les services qui nécessitent le service Bluetooth exécuteront les commandes nécessaires pour s'initialiser.


Balayez vers la gauche, balayez vers la droite


Nous supprimons les programmes et services inutiles qui peuvent être affichés à l'aide de htop, car ils occupent une place précieuse dans la RAM:



Dans ce cas, le service ConsoleKit comporte de nombreux processus . Déplacez le fichier de ce service vers le dossier racine en cas de récupération:


 mv /usr/share/dbus-1/system-services/org.freedesktop.ConsoleKit.service /root/ 

Avant d'arrêter le service, la consommation de RAM était de 19 Mo, et après - 16 Mo.


Sections système


Bien que uBoot transfère au noyau le périphérique sur lequel se trouve la partition racine, cela vaut la peine de l'écrire dans /etc/fstab pour plus de fiabilité. Nous changeons la première ligne responsable de la section racine:


 /dev/mmcblk0p1 / auto defaults 1 1 proc /proc proc defaults 0 0 devpts /dev/pts devpts mode=0620,gid=5 0 0 usbdevfs /proc/bus/usb usbdevfs noauto 0 0 tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0 tmpfs /var/volatile tmpfs defaults 0 0 

Si vous n'avez pas créé la partition racine en premier, n'oubliez pas de spécifier le numéro de partition souhaité.


Si vous avez laissé la deuxième partition FAT pour les données utilisateur, vous devez créer un dossier pour y monter la partition


 mkdir /usr/share/trik 

et écrivez la section dans /etc/fstab :


 /dev/mmcblk0p2 /usr/share/trik vfat defaults 0 0 

Étape 6. Nous essayons notre bouillie


Après avoir configuré l'image système, vous devez la monter pour installer les modules du noyau et le noyau lui-même:


 # ,     (start) fdisk -l debian.img mount -o loop,offset=NNNN debian.img /mnt/debian 

où, NNNN = taille du secteur * début de la section. La taille de secteur par défaut est de 512 octets.


Nous montons également la distribution d'origine:


 fdisk -l trik-distro.img mount -o loop,offset=NNNN trik-distro.img /mnt/trik-clean 

Nous supprimons le noyau pour QEMU et ses modules, comme ils ne sont pas destinés à notre plateforme. Nous copions le nouveau noyau et les nouveaux modules, tout comme sur la distribution d'origine.


 rm -rf /mnt/debian/boot/ rm -rf /mnt/debian/lib/modules/3.2.0-4-versatile rm -rf /mnt/debian/lib/modules/3.2.0-5-versatile mkdir /mnt/debian/boot/ cp arch/arm/boot/uImage /mnt/debian/boot/ make INSTALL_MOD_PATH=/mnt/debian modules_install 

Nous aurons besoin d'un firmware pour le module Wi-Fi, qui se trouve dans la distribution d'origine dans le dossier / lib / firmware et le firmware Bluetooth que nous avons trouvé plus tôt.


 cp /mnt/trik-clean/lib/firmware/* /mnt/debian/lib/firmware/ cp TIInit_7.6.15.bts /mnt/debian/lib/firmware/ 

Déconnectez les images de disque:


 umount /mnt/trik-clean umount /mnt/debian 

Et commencez à copier l'image sur la carte mémoire à l'aide de dd:


 #    ( ) lsblk dd if=debian.img of=/dev/sdX bs=4M 

Étape 7. La ligne d'arrivée


Nous compilons les programmes de connexion de la manette de jeu sur le nouveau système et installons le démon sixad.


Nous connectons la manette de jeu via USB au contrôleur et exécutons le programme pour créer une paire:


 root@trik:~/bt# ./sixpair Current Bluetooth master: 78:**:**:**:**:b9 Setting master bd_addr to 78:**:**:**:**:b9 

Lorsque la manette de jeu est connectée, rien ne se passe et le service sixad est silencieux:


 sixad-bin[2675]: started sixad-bin[2675]: sixad started, press the PS button now sixad-bin[2675]: unable to connect to sdp session 

Mais la communauté Raspberry Pi a déjà fait une «béquille» pour réparer la connexion .


Nous reconstruisons le programme et nous nous réjouissons.


 sixad-bin[2833]: started sixad-bin[2833]: sixad started, press the PS button now sixad-bin[2833]: unable to connect to sdp session sixad-sixaxis[2836]: started sixad-sixaxis[2836]: Connected 'PLAYSTATION(R)3 Controller (00:**:**:**:**:09)' [Battery 02] 

Maintenant, la manette de jeu est disponible pour le système en tant que périphérique d'entrée et le programme jstest affichera l'état de tous les boutons et capteurs analogiques:


 root@trik:~# ls /dev/input/ by-path event0 event1 event2 event3 js0 js1 js2 mice root@trik:~# jstest --normal /dev/input/jsX Driver version is 2.1.0. Joystick (PLAYSTATION(R)3 Controller (00:**:**:**:**:09)) has 29 axes (X, Y, Z, Rx, Ry, Rz, Throttle, Rudder, Wheel, Gas, Brake, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, (null), (null), (null), (null), (null), (null), (null), (null)) and 17 buttons (Trigger, ThumbBtn, ThumbBtn2, TopBtn, TopBtn2, PinkieBtn, BaseBtn, BaseBtn2, BaseBtn3, BaseBtn4, BaseBtn5, BaseBtn6, BtnDead, BtnA, BtnB, BtnC, BtnX). Testing ... (interrupt to exit) Axes: 0: 0 1: 0 2: 0 3: 0 4: -7150 5: -7746 6:-32767 7: 0 8: 0 9: 0 10: 0 11: 0 12: 0 13: 0 14: 0 15: 0 16: 0 17: 0 18: 0 19: 0 20: 0 21: 0 22: 0 23: 0 24: 0 25: 0 26: 0 27: 0 28: 0 Buttons: 0:off 1:off 2:off 3:off 4:off 5:off 6:off 7:off 8:off 9:off 10:off 11:off 12:off 13:off 14:off 15:off 16:off 

où X est le numéro de périphérique dans le système, par défaut - 2. Le nombre de boutons et d'axes peut être affiché ici .


Utilisation en pratique


Vidéo montrant la manette de jeu sur YouTube .


Photos de la distribution

Chargement du noyau:

Terminal fonctionnant sur X11:



Et selon la tradition:



Liens utiles


Programmes pour connecter la manette Dualshock 3 - six paires et sixad .


Pour les manettes de jeu et autres périphériques d'entrée, il existe une bibliothèque C légère - libenjoy .


Le code source du programme de contrôle des servomoteurs et des moteurs est le référentiel GitHub .


Tous les fichiers de configuration de l'article pour un kit de distribution de fortune sont le référentiel GitHub .


La source du noyau est le référentiel GitHub .


Faits intéressants sur le contrôleur


  • La spécification indique que la RAM est de 256 Mo. Mais si vous exécutez htop, vous verrez que seulement 128 Mo sont disponibles. Ceci est limité par les options du noyau qui peuvent être affichées dans la console uBoot:

 mem=128M console=ttyS1,115200n8 rw noinitrd rootwait root=/dev/mmcblk0p1 vt.global_cursor_default=0 consoleblank=0 

La puce mémoire est marquée 3PC22 D9MTD fabriquée par Micron. Il n'a pas été possible de trouver des informations sur son volume actuel.


  • uBoot est stocké sur une mémoire flash SPI dans laquelle le noyau est également câblé et n'est pas utilisé. Vous pouvez essayer d'utiliser cet endroit pour vos tâches ou copier un nouveau noyau et reconfigurer uBoot pour qu'il l'utilise.

Adresses d'images de dmesg:


 [ 11.598170] 0x000000000000-0x000000040000 : "uboot" [ 11.642985] 0x000000040000-0x000000080000 : "uboot-env1" [ 11.706256] 0x000000080000-0x0000000c0000 : "uboot-env2" [ 11.761827] 0x0000000c0000-0x000000100000 : "config-periph" [ 11.805129] 0x000000100000-0x000000400000 : "kernel" [ 11.861864] 0x000000400000-0x000001000000 : "RootFS" 

  • L'écran du contrôleur, bien que petit, possède en fait un capteur résistif. On ignore si le capteur lui-même est connecté.
  • Dualshock 3 a des LED sur le connecteur USB qui indiquent le numéro de la manette de jeu / joystick. Il y a un gamepad dans la vidéo, mais son numéro est 3. Ce n'est pas une erreur, car il y a deux autres «joysticks» dans le système: un accéléromètre et un gyroscope.

Problèmes rencontrés lors de l'utilisation


  • Le robot se bloque parfois fermement, sans éteindre les servomoteurs, ce qui leur permet de changer leur position du bruit sur la ligne de données. Cela a été vu même sur une distribution standard .
  • L'inclusion de contrôleurs PWM est différente de ce qui est écrit dans la documentation . Au moins en C pur, cela n'a pas fonctionné.
  • L'USB cesse parfois de fonctionner sur Debian.

Source: https://habr.com/ru/post/fr415007/


All Articles