lunes, 12 de septiembre de 2016

Script para detectar modelos de Raspberry Pi dentro de rpimonitor

  Aunque es bastante útil el paquete RPi-Monitor para ver el estado de cada computador, si se tienen varios modelos del Raspberry Pi como es mi caso, empieza pasar que ya no se cuál es qué modelo. Para eso quería agregar en mi panel de control algún comando para identificar el modelo y poder diferenciarlos.



  Buscando en internet, encontré un script que podía identificar esto basado en los datos de /proc/cpuinfo, aunque le faltaban casos. Así que expandí el script según la referencia de los modelos del Raspberry que está en eLinux: Which Pi have I got - elinux.org.

Script para identificar el modelo RPi

  El script original de Greg Stephens, al cual contribuí con estos cambios, está en su repositorio github: pivers.sh - rgstephens/pisetup Github.

  Aquí copio el script, que permite identificar el modelo. Actualizado a modelos disponibles al Q4 2018.

#!/bin/bash
CPU=`cat /proc/cpuinfo | grep Serial | cut -d ':' -f 2 | sed -e "s/ //g"`
HW=`cat /proc/cpuinfo | grep Hardware | cut -d ':' -f 2 | sed -e "s/ //g"`
REV=`cat /proc/cpuinfo | grep Revision | cut -d ':' -f 2 | sed -e "s/ //g"`
#values from http://elinux.org/RPi_HardwareHistory
case ${REV} in
  a020d3)
    echo 'Pi 3 Model B+, 1024MB RAM'
    ;;
  9020e0)
    echo 'Pi 3 Model A+, 512MB RAM'
    ;;
  a02082|a22082|a32082)
    echo 'Pi 3 Model B, 1024MB RAM'
    ;;
  a01040|a01041|a21041|a22042)
    echo 'Pi 2 Model B, 1024MB RAM'
    ;;
  900092|900093|920093)
    echo 'Pi Zero, 512MB RAM'
    ;;
  9000c1)
    echo 'Pi Zero W, 512MB RAM'
    ;;
  0015|900021)
    echo 'Pi Model A+, 512MB RAM'
    ;;
  0012)
    echo 'Pi Model A+, 256MB RAM'
    ;;
  0010|0013|900032)
    echo 'Pi, Model B+, 512MB RAM'
    ;;
  0011|0014)
    echo 'Compute Module 1, 512MB RAM'
    ;;
  a020a0)
 echo 'Compute Module 3, 1024MB RAM'
 ;;
  0002|0004|0005|0006)
    echo 'Pi Model B, 256MB RAM'
    ;;
  000d|000e|000f)
    echo 'Pi Model B, 512MB RAM'
    ;;
  0003)
    echo 'Pi Model B (ECN0001), 256MB RAM'
    ;;
  Beta)
    echo 'Pi, Model B (Beta), 256MB RAM'
    ;;
  0007|0008|0009)
    echo 'Pi, Model A, 256MB RAM'
    ;;
  *)
    echo '${REV} (unknown)'
    ;;
esac

 

 Grabar el contenido en nuevo archivo pivers.sh

cd ~/
sudo nano pivers.sh

 Aquí hay que copiar el contenido del script dentro del archivo y grabar con CTRL + O y luego CTRL + X.

Para que funcione en forma fácil, hay que mover el archivo al directorio /bin/, con permisos de usuario root:

sudo mv pivers.sh /bin/pivers.sh

Configurar RPi-Monitor para mostrar el modelo

   Hay que editar el archivo que muestra la versión, agregando el comando para llamar al script. Por seguridad haremos también un respaldo del archivo original:
cd /etc/rpimonitor/template
sudo cp version.conf version-bak.conf
sudo nano version.conf

   Las líneas que edité son las marcadas en color:
########################################################################
# Extract System information
#  Page: 1
#  Information               Status     Statistics
#  - computer model          - yes      - no
#  - distribution name       - yes      - no
#  - kernel version          - yes      - no
#  - firmware version        - yes      - no
#  - processor model         - yes      - no
#  - num of pkg upgradable   - yes      - no
#  - list of pkg upgradable  - yes      - no
########################################################################
static.1.name=distribution
static.1.source=/etc/os-release
static.1.regexp=PRETTY_NAME.\"(.*)\"
static.1.postprocess=

static.2.name=kernel_version
static.2.source=uname -msr
static.2.regexp=(.*)
static.2.postprocess=

static.3.name=firmware
static.3.source=/proc/version
static.3.regexp=(#\d+)
static.3.postprocess=

static.4.name=processor
static.4.source=/proc/cpuinfo
static.4.regexp=(?:Processor|model name)\s+: (.*)
static.4.postprocess=

static.5.name=model
static.5.source=/bin/pivers
static.5.regexp=(.*)
static.5.postprocess=

dynamic.1.name=upgrade
dynamic.1.source=/var/lib/rpimonitor/updatestatus.txt
dynamic.1.regexp=(\d+ upgradable\(s\)|.* .*)
dynamic.1.postprocess=
dynamic.1.rrd=

dynamic.2.name=packages
dynamic.2.source=/var/lib/rpimonitor/updatestatus.txt
dynamic.2.regexp=^\s+(.*)\s+\d+ upgradable
dynamic.2.postprocess=
dynamic.2.rrd=

web.status.1.content.1.name=Version
web.status.1.content.1.icon=version.png
web.status.1.content.1.line.1='Model: <b>' + data.model + '</b>'
web.status.1.content.1.line.2='Processor: <b>' + data.processor + '</b>'
web.status.1.content.1.line.3='Distribution: <b>'+ data.distribution + '</b>'
web.status.1.content.1.line.4='Kernel version: <b>' + data.kernel_version + '</b>'
web.status.1.content.1.line.5='Firmware: <b>' + data.firmware + '</b>'
web.status.1.content.1.line.6='Package(s): <b>' + data.upgrade + '</b>' + ShowInfo('packages','Package(s) upgradable(s)',data.packages)

   Las líneas siguientes a la ultima marcada, solo tienen modificadas el número de línea sumándole 1 (donde decía 1 puse 2, donde decía 2 puse 3, y así).  Cuando termine los cambios, grabar con CTRL + X.

   Finalmente se debe reiniciar el servicio con el comando siguiente, y al visitar la página del RPi se debe ver la imagen mostrada al principio del post.

$ sudo service rpimonitor restart


viernes, 15 de julio de 2016

Conectar Raspberry Pi Zero con Raspbian en modo Host OTG desde Linux Mint

Después de experimentar un rato con el Raspberry Pi Zero, logré encontrar la manera de configurarlo de manera consistente para poder conectarlo con un cable normal micro USB al computador, de modo que el otro lo vea como una conexión de red a través del mismo USB.

La misión: energía y datos con un solo cable USB.

Así se puede conectar en forma remota al Raspi Zero (ejemplo con SSH) y controlarlo desde el notebook por ejemplo, sin tener que usar un host usb externo, teclado, mouse y pantalla HDMI. El truco es habilitar el modo OTG (modo host en que el computador percibe al RPi como un periférico), que esta puerta USB la detecte como un dispositivo de red, que obtenga dirección IP válida para conectarse, e incluso que se pueda compartir el acceso a internet al Rpi. ¿Poca cosa, jaja?
;-)
RPi Zero conectado a notebook por USB (alimentación y datos) y con acceso a internet.

Algo de historia y contexto

   Aunque se estaba experimentando desde que se puso a la venta el Zero en noviembre de 2015, el soporte OTG para Raspbian estaba algo complejo al principio de habilitar, pues requería usar un kernel especial o compilarlo uno mismo, levantar unos módulos del kernel en forma manual y configurar y configurar... como se puede ver en este blog.
   Sin embargo, todo el avance de estos pioneros permitió habilitar los drivers e incluso configurarlos apropiadamente usando overlays, de modo que luego de integrarlo en la entrega del 10/05/2016 del sistema operativo Raspbian, es muy fácil utilizarlo... aunque bastante difícil de encontrarlo explicado de una manera fácil, y menos en español.
   Me basé harto en el post Raspberry Pi Zero – Programming over USB! (Part 2) de Andrew Mulholland (¡admirable!), pero los comentarios de otros usuarios aportaron también mucho a resolver problemas que explico más abajo. En ese post base las instrucciones son mas sencillas, pero con la experiencia adquirida podemos configurar cosas en ambos extremos para que el Zero consiga IP automáticamente, que el Linux Mint lo reconozca siempre bajo la misma interfaz de red y que por lo tanto siempre le comparta internet al Zero.

Breve explicación técnica

   El Raspberry Pi Zero y el Compute Module son diferentes al resto de los Rpi, en el sentido de exponer una sola puerta USB desde la CPU. Los modelos con más de una puerta USB como los B, B+, 2 y 3 lo que hacen es usar un chip (LAN9512 o LAN9514) que provee una puerta LAN y varias  puertas USB vía un hub USB, compartiendo todos el mismo ancho de banda. La única puerta USB directa desde la CPU se configura por defecto en modo "periférico" ("peripheral" en la documentación del overlay para dwc2) para que un dispositivo USB al conectarse al Rpi sea tratado de ese modo. Como esa conexión intermedia entre el SOC y hub USb no es accesible, tampoco se puede utilizar para habilitar el modo "anfitrión" ("host" según la misma documentación) o "otg" que abarca ambas opciones.
  Sin embargo, el Rpi Zero sí tiene expuesto este puerto directo, por lo que podemos habilitar el modo mixto OTG, cuyo nombre indica que se selecciona el modo de operación sobre la marcha, habilitando que se comporte como un puerto normal si enchufamos un pendrive, teclado o mouse, en que el RPi manda, o como un dispositivo periférico de un computador, en que éste manda.

Paso a paso

   Se requiere tener la tarjeta SD ya cargada con Raspbian (mínimo con la versión Jessie 2016-05-10), lo que se puede encontrar en otras guías en internet (ejemplo "instalar raspbian en sd").
Con eso listo, utilizando el mismo Zero o desde el computador corriendo Linux Mint (en mi caso aún con la versión 17.3 Cinnamon) podemos cambiar unas opciones para que reinicie con ese soporte habilitado.

Alternativa sin usar el Raspberry Zero:

   Lo anterior supone que se tiene iniciar el Zero al menos una primera vez para preparar todo, necesitando conectar teclado, monitor, red y pantalla. Sin embargo se tiene la opción de reutilizar otro Raspberry Pi que ya esté conectado para hacer los cambios de los pasos 1 al 4, aunque sea de otro modelo, pues con el sistema ya prendido con esta nueva tarjeta SD se pueden dejar grabados los cambios que harán efecto en el modelo Zero.


1) Instalar Avahi soporte (zeroconf) 

   Se necesita instalar tanto en el Rpi como en el notebook el soporte para autodescubrimiento de dispositivos Zeroconf también conocido Bounjour. Esto aporta a que luego de configurado podamos conectarnos desde el notebook solo utilizando el nombre del Rpi, no teniendo que conocer la ip de éste.
   Lo mínimo para que funcione es instalar avahi-daemon que permite interconectarse por este protocolo. Adicionalmente instalamos avahi-discover que presenta herramientas y e interfaz gráfica para ayudar a dilucidar la dirección IP del aparato.

$ sudo apt-get update && sudo apt-get upgrade
$ sudo apt-get install avahi-daemon avahi-discover

   En mi caso el mismo comando me sirve en ambos ambientes, pues tanto Raspbian como Linux Mint estan basados en la distribución Debian.

2) Anotar o ajustar el nombre de host del RPi Zero

Este paso es para evitarse problemas después, pues en este momento al estar conectado en la consola del Zero es fácil buscar el nombre de host del aparato, para no tener que adivinarlo después. Se puede usar este comando:

$ sudo cat /etc/hostname 
rp04
  Si la tarjeta está recién creada lo más probable es que se llame raspberrypi (cual es el nombre por defecto de una nueva imagen), pero si está clonada desde otro RPi (por ejemplo utilizando la nueva utilidad para clonar la tarjeta SD incorporado en versiones recientes de Raspbian), es probable que tenga otro nombre, como en mi caso es rpi04.  En cualquiera de los casos hay que anotar este nombre para usarlo posteriormente.

Si se desea cambiarlo, también es un buen momento, aunque hay que hacerlo en dos archivos: /etc/hostname y /etc/hosts.

En el primero simplemente es llegar y escribir otro:
$ sudo nano /etc/hostname
 En este otro hay que buscar la línea que comience con 127.0.1.1 y cambiar el nombre por el de su gusto, siempre que entre ambos archivos mantengan el mismo nombre.
$ sudo nano /etc/hosts
en mi caso quise llamar a mi RPi Zero como rpi04, por lo que la línea me quedó así:
127.0.1.1                rpi04

3) Habilitar el modo OTG en el Zero

   Este es el paso crítico en el que hay tener cuidado con las instrucciones y respaldar la configuración anterior para que pueda iniciar bien el Zero y no tener que hacer cosas complicadas para recuperación.

3a) Editar config.txt

   Se tiene que editar dos archivos de la partición /boot que son los importantes al iniciar éste. El primero es config.txt, que define los parámetros que usa el videocore, que es el coprocesador que bootea primero y carga luego el kernel de linux en el ARM.

$ cd /boot
$ cp config.txt config.txt.bak
$ sudo nano config.txt
  En este último archivo tenemos que agregar al final la linea siguiente, grabando el archivo y cerrándolo:
dtoverlay=dwc2
   Esto le indica que se tiene que cargar el archivo de overlay correspondiente que prepara los módulos a cargar en el kernel.

3b) Editar cmdline.txt

   Luego del mismo directorio /boot hay que editar el archivo cmdline.txt, con las siguientes precauciones: tener harto cuidado de mantener un solo carácter de espacio entre palabras y no usar el enter, pues todo debe quedar en una sola línea. Por si sale algo mal, partimos haciendo un respaldo del archivo actual y luego editamos el archivo.

$ sudo cp cmdline.txt cmdline.txt.bak
$ sudo nano cmdline.txt
   Dentro de este archivo tenemos que buscar donde aparece el comando rootwait y a continuación de ello agregar modules-load=dwc2,g_ether, teniendo cuidado si había más instrucciones luego de rootwait, no borrarlas.

   En mi caso el archivo antes de la inserción tenía lo siguiente:
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p7
rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
   Y así quedó luego de insertar el comando para la carga del módulo del kernel:

dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p7
rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2,g_ether
   Este parámetro indica que se debe cargar el módulo del kernel dwc2, exponiendo la interfaz ethernet hacia afuera.

En el caso que la tarjeta SD estuviera recién generada, lo mas probable es que el contenido sea algo como esto:
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p7 
rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait 
quiet init=/usr/lib/raspi-config/init_resize.sh
por lo que debemos insertar el texto entre medio (con las precauciones de mantener un solo espacio y sin enter) dejándolo como:
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p7 
rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2,g_ether 
quiet init=/usr/lib/raspi-config/init_resize.sh
Todavía no hay que cerrar el archivo, pues es necesario aún...

3c) Agregar definición de direcciones de hardware y host

   Si guardáramos y cerráramos el documento tal como está, igual funcionaría la conexión, pero cada vez que se volviera a reconectar al notebook se produciría un efecto no deseado: el Zero aparece cada vez con una dirección de red diferente en IP6, y sin dirección IP4.
   Esto ocurre por una cadena de hechos, partiendo por como funciona el driver DWC2 por defecto: si no le indican una dirección de hardware (conocida por MAC address antiguamente) ni la que debe asumir la interfaz de red USB visible para ambas partes, ocurre que el drivers genera ambas al azar cada vez que se prende el Zero. Así no se puede predeterminar una asignación de IP (que podría hacerse en el archivo /etc/network/interfaces) o que el notebook le comparta internet al Zero. No es tan loca la situación, considerando que se no hay un dispositivo físico de red que venga de fábrica con las direcciones físicas ya predeterminadas

  Por ello al menos necesitamos asignar los parámetros host_addr y dev_addr en este mismo archivo con el siguiente téxto, teniendo el cuidado de mantener un solo espacio y sin enter al final:

g_ether.dev_addr=be:eb:df:c0:95:6e g_ether.host_addr=1A:B8:86:9D:80:61

   Las direcciones be:eb:df:c0:95:6e y 1A:B8:86:9D:80:61 son de ejemplo, aunque si se les pone esas, igual funcionaría. En mi caso yo utilicé las direcciones que me generó el Zero la primera vez que lo prendí sin esos parámetros, detectándolas y anotándolas, usando el camino difícil, tal como en la guía de Andrew Mulholland (pues la falta de estos fue detectada y reportada por las personas en los comentarios al post). Para que a usted no lo pase, lo agregué como un punto más. Así, el texto quedaría como:

dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p7 
rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2,g_ether
g_ether.dev_addr=be:eb:df:c0:95:6e g_ether.host_addr=1A:B8:86:9D:80:61
Para el caso de una tarjeta SD recién generada el texto quedaría como:
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p7 
rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2,g_ether
g_ether.dev_addr=be:eb:df:c0:95:6e g_ether.host_addr=1A:B8:86:9D:80:61 
quiet init=/usr/lib/raspi-config/init_resize.sh
  En cualquiera de los casos no hay que olvidar guardar los cambios y cerrar el archivo.

4) Apagar el RPi Zero, y conectar al notebook

 Ahora toca apagar el aparatito:
$ sudo shutdown now
Como el RPi Zero tiene un solo led, esta luz funciona diferente a los otros modelos, estando prendida al estar funcionando éste en idle y parpadeando al tener actividad, por lo que el indicio de estar realmente apagado es que el led se apague. Lógico, ¿no? ;-)

  Ahí se puede desconectar el Zero de todas sus ataduras (jaja) y podemos conectarlo minimalistamente con un cable normal USB a micro USB al PC.

Alternativa sin usar el Raspberry Zero:

   Como mencioné al comienzo, si se está usando otro modelo de Raspberry para preparar la tarjeta SD con los cambios, luego de terminado este paso se debe sacar la tarjeta del RPi anfitrión y ponerla en el RPi Zero, pues ya le llegó su hora de entrar en acción.

Conectar el RPi Zero al notebook

   Al conectarse en ambos extremos el cable USB, se prenderá el led del RPi Zero comenzando a parpadear, mostrando el avance en el proceso de inicialización. Sólo cuando termine completamente el parpadeo (hasta 90 segundos después en la primera inicialización) podemos estar seguros de que terminó y que podemos comenzar el paso siguiente, pues se requiere que el RPi haya levantado la interfaz OTG y detectado al notebook.
   Si la tarjeta estaba recién creada, incluso es posible que el RPi se rebootee solo (por la tarea de que agranda el espacio de una tarjeta SD si esta es mas grande de 4GB que mostraba el segundo caso del punto anterior) y comience otra vez el proceso de inicializarse. En mi caso me dí cuenta por el notebook que la interfaz de red que se ve en el paso siguiente se conectó, desconecto y luego se volvió a conectar otra vez.

5) Detectar la conexión de red por USB 

   Luego de prenderse e inicializarse el Zero, en mi notebook se detectó una nueva conexión de red. Al ver el detalle, me aparece que el Notebook tiene una red llamada "Conexión Cableada 1" con MAC Address 1A:B8:86:9D:80:61.

   Esto me pareció raro, pues esperaba que apareciera el contenido del parámetro dev_addr y no el del host_addr. Sin embargo, entendí que lo entregado a dev_addr nombra a la interfaz de red virtual del RPi Zero, y lo entregado a host_addr nombra a la interfaz de red virtual en el Notebook.

Intento de conexión al RPi Zero por nombre


   En fin, viendo que ya aparece la conexión de red intenté conectarme al RPi Zero conociendo su nombre desde lo anotado del paso 2), con el comando SSH, pero no funcionaba:
$ ssh pi@rpi04.local
ssh: Could not resolve hostname rpi04.local: Name or service not known

   Luego utilizando una de las utilidades de Avahi en el notebook, se pueden ver las IP y dispositivos detectados, con el comando siguiente:

$ avahi-browse -art
+  wlan0 IPv6 lingatunoNtb [a0:a8:cf:98:ac:48]   Workstation            local
+  wlan0 IPv4 lingatunoNtb [a0:a8:cf:98:ac:48]   Workstation            local

+   usb0 IPv6 rpi04 [be:eb:df:c0:95:6e]          Workstation            local

+   usb0 IPv6 lingatunoNtb [1a:b8:86:9d:80:61]   Workstation            local
+  wlan0 IPv6 lingatunoNtb                       Remote Disk Management local
+  wlan0 IPv4 lingatunoNtb                       Remote Disk Management local

+   usb0 IPv6 rpi04                              Remote Disk Management local
+   usb0 IPv6 lingatunoNtb                       Remote Disk Management local
=   usb0 IPv6 rpi04 [be:eb:df:c0:95:6e]          Workstation            local
   hostname = [rpi04.local]
   address = [fe80::34ba:41aa:bcac:a620]
   port = [9]
   txt = []

=   usb0 IPv6 lingatunoNtb [1a:b8:86:9d:80:61]   Workstation            local
   hostname = [lingatunoNtb.local]
   address = [fe80::18b8:86ff:fe9d:8061]
   port = [9]
   txt = []

=   usb0 IPv6 rpi04                              Remote Disk Management local
   hostname = [rpi04.local]
   address = [fe80::34ba:41aa:bcac:a620]
   port = [22]
   txt = []


   Se pueden reconocer los siguientes grupos:
  • Lo marcado en amarillo se corresponde a la interfaz virtual como la ve el RPi Zero, puesto que se comunica a través de la interfaz usb0 que es la que activamos en las configuraciones del punto 3). Como se ve, solamente presenta dirección IPv6 (fe80::18b8:86ff:fe9d:8061).
  • Lo marcado en cyan corresponde a la interfaz virtual como la expone el notebook, comunicada por el otro extremo de la interfaz usb0, con una dirección IPv6 diferente (fe80::34ba:41aa:bcac:a620). 
  • Por último, lo marcado en blanco es la interfaz Wifi del notebook, que tiene tanto dirección IPv4 como IP6.

Conexión al RPi Zero usando IP6

Considerando lo anterior, el notebook no puede llegar al RPi, primero por que sólo tiene dirección IP6 y no tiene IPv4, y el comando ssh utiliza por defecto esta última dirección. Si utilizo ssh -6 para especificar que use IPv6, sí si se llega, pues sí hay visibilidad usando esta dirección, pero se debe especificar esta en forma completa (se pone bastante feo el comando):
$ ssh pi@fe80::34ba:41aa:bcac:a620%usb0
The authenticity of host 'fe80::34ba:41aa:bcac:a620%usb0 (fe80::34ba:41aa:bcac:a620%usb0)' 
can't be established.
ECDSA key fingerprint is 03:a8:c4:0a:c0:ed:de:ab:7d:63:e4:da:21:b1:16:d5.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'fe80::34ba:41aa:bcac:a620%usb0' (ECDSA) to the list of known hosts.
pi@fe80::34ba:41aa:bcac:a620%usb0's password:

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed May 25 01:17:17 2016
pi@rpi04:~ 

   Donde pi@ especifica que se conecte usando el login de usuario pi, fe80::34ba:41aa:bcac:a620 es la dirección IPv6 y %usb0 es la interfaz de red que se utiliza.
   Funciona pero no es para nada cómodo, al tener que buscarse la dirección IPv6 cada vez, la que podría variar mas encima.

Confirmación: Detalles de interfaz usb0 en el RPi Zero

Estando al fin conectado a la consola del RPi Zero desde el notebook, podemos ver los detalles de la interfaz usb0 desde la perspectiva del RPi, lo que reafirma el que no tiene dirección IPv4 definida:
$ ifconfig usb0
usb0      Link encap:Ethernet  direcciónHW be:eb:df:c0:95:6e 
          Dirección inet6: fe80::34ba:41aa:bcac:a620/64 Alcance:Enlace
          ACTIVO DIFUSIÓN FUNCIONANDO MULTICAST  MTU:1500  Métrica:1
          Paquetes RX:325 errores:0 perdidos:0 overruns:0 frame:0
          Paquetes TX:1009 errores:0 perdidos:0 overruns:0 carrier:0
          colisiones:0 long.colaTX:1000
          Bytes RX:62812 (62.8 KB)  TX bytes:221885 (221.8 KB)

Confirmación: Información desde log del kernel del módulo DWC2

 Podemos aprovechar de revisar en el Zero el log del módulo DWC2, viendo que los parámetros host_addr y dev_addr fueron considerados, mirando el resultado del comando DMESG (copié aquí sólo las partes relevantes al módulo):

 $ dmesg -H
...
[  +0,245730] dwc2 20980000.usb: DWC OTG Controller
[  +0,007742] dwc2 20980000.usb: new USB bus registered, assigned bus number 1
[  +0,032035] dwc2 20980000.usb: irq 33, io mem 0x00000000
[  +0,026420] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
[  +0,009900] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[  +0,010223] usb usb1: Product: DWC OTG Controller
[  +0,007660] usb usb1: Manufacturer: Linux 4.4.9+ dwc2_hsotg
[  +0,008527] usb usb1: SerialNumber: 20980000.usb
[  +0,022201] systemd-udevd[108]: starting version 215
[  +0,185440] hub 1-0:1.0: USB hub found
[  +0,000112] hub 1-0:1.0: 1 port detected
[  +0,172219] using random self ethernet address
[  +0,007306] using random host ethernet address
[  +0,006995] using host ethernet address: 1A:B8:86:9D:80:61
[  +0,005494] using self ethernet address: be:eb:df:c0:95:6e
[  +0,091771] usb0: HOST MAC 1a:b8:86:9d:80:61
[  +0,045861] usb0: MAC be:eb:df:c0:95:6e

[  +0,006638] using random self ethernet address
[  +0,007178] using random host ethernet address
[  +0,076208] g_ether gadget: Ethernet Gadget, version: Memorial Day 2008
[  +0,009344] g_ether gadget: g_ether ready
[  +0,006707] dwc2 20980000.usb: dwc2_hsotg_enqueue_setup: failed queue (-11)
[  +0,012686] dwc2 20980000.usb: bound driver g_ether
...
[jul13 01:22] Adding 102396k swap on /var/swap.  Priority:-1 extents:1 across:102396k SSFS
[  +0,050907] IPv6: ADDRCONF(NETDEV_UP): usb0: link is not ready
[  +2,060551] dwc2 20980000.usb: new device is high-speed
[  +0,184062] dwc2 20980000.usb: new device is high-speed
[  +0,112111] dwc2 20980000.usb: new device is high-speed
[  +0,056973] dwc2 20980000.usb: new address 16
[  +0,017481] g_ether gadget: high-speed config #1: CDC Ethernet (ECM)
[  +0,000744] IPv6: ADDRCONF(NETDEV_CHANGE): usb0: link becomes ready


 Lo marcado en cyan muestra primero el mensaje que se usarán valores al azar para los parámetros, sin embargo como le especificamos valores definidos, lo que está en verde demuestra que sí fueron considerados.

6) Activar asignación de IPv4

   Para mejorar esto, la idea es hacer que el notebook siempre le asocie la misma.   Así hay que cambiar el seteo en el notebook para que se le asigne una dirección de red a la dirección MAC del la red virtual usb0. Para ello en linux mint hay que abrir "Conexiones de Red":

Allí en la pestaña "Ajustes de IPv4", hay que cambiar el valor para el campo Método, en vez de "Manual" a "Solo enlace local".

   Luego hay que apretar el botón Guardar.


7) Compartir acceso a internet al RPi desde el notebook con Linux Mint

  El verdadero truco es cambiar en ese mismo cuadro de diálogo por el valor "Compartida con otros equipos", que aparte le comparte el acceso a Internet que tenga el notebook al RPi Zero.

   Ahora podemos probar conectarse directamente al RPi Zero usando el nombre:

$ sudo ssh pi@rpi04.local
pi@rpi04.local's password:

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed May 25 01:17:17 2016
pi@rpi04:~ $ 

Y así finalmente tener el acceso a Internet compartido desde el notebook. En el ejemplo, actualizando los paquetes instalados:


viernes, 6 de mayo de 2016

Instalar y configurar reloj RTC DS3231 en Raspberry Pi con Raspbian Jessie

El módulo RTC DS3231 es un reloj en tiempo real bastante preciso, que puede ser usado con el Raspberry Pi para mantener la hora en forma independiente de no estar el computador prendido o de contar con acceso a internet al momento de prenderse.

El módulo que compré es un SoundFounder, pero se parece mucho a este en dx.com, que básicamente contiene el chip Maxim y un par de resistencias para el I2C.

Según las especificaciones del chip Maxim DS3231, este tiene una exactitud de ±2 minutos por año,  que es mejor que el típico DS1307 (dependiendo del cristal utilizado puede ser ±1 minuto por mes). La precisión la obtiene al incorporar dentro del chip un cristal con baja dispersión (±2ppm entre 0°C y 40°C y ±3,5ppm entre 40°C y 85°C), junto con tener compensación según la temperatura. Utiliza interfaz I2C, con posibilidad de usar velocidad rápida (400khz).

Configuración del módulo en Raspbian Jessie

Esta sección es una mezcla de información de varios sitios, pues con Raspbian Jessie al usar overlays las instrucciones antiguas quedan algo desactualizadas.

1) Uso de Overlays

Lo primero es editar el archivo /boot/config.txt:
$ sudo nano /boot/config.txt
añadiendo las líneas siguientes al final del archivo:
dtparam=i2c_arm=on
dtoverlay=i2c-rtc,ds3231
La primera línea habilita el canal i2c en los pines GPIO2 y GPIO3.
La segunda línea es la declaración para cargar el módulo RTC, especificando el uso del DS3231.

Lo siguiente es revisar que no esté restringido el driver, revisando el archivo /etc/modprobe.d/raspi-blacklist.conf:
$ sudo nano /etc/modprobe.d/raspi-blacklist.conf
El archivo debería estar en blanco, o tener comentado el driver, en una línea como:
#blacklist i2c-bcm2708 

 Finalmente se debe resetear el Raspi, con el comando:
$ sudo shutdown -r now

Opcional: uso de bus más rápido para i2c

Como este dispositivo se puede utilizar con una velocidad mayor de bus (400kHz), esto también se puede habilitar con los overlays, agregando otro parámetro al archivo /boot/config.txt:
dtparam=i2c_arm=on
dtparam=i2c_arm_baudrate=400000
dtoverlay=i2c-rtc,ds3231

El parámetro i2c_arm_baudrate especifica la velocidad del bus, siendo las comunes 100kHz, 400kHz y 1.2MHz, aunque hay que ver según las posibles para cada dispositivo.

2) Instalación del módulo

Teniendo la precaución de tener el Raspi apagado, el módulo se instala en los pines correspondientes a +3.3V, SDA1 (GPIO2), SCL1 (GPIO3) y GND.
Fuente: http://elinux.org/RPi_Low-level_peripherals

3) Verificación de funcionamiento

 Luego de reiniciado el Raspi, probar los siguientes comandos para revisar que todo funcione:
$ dmesg | grep i2c
[    5.523637] i2c /dev entries driver
[   14.631118] bcm2708_i2c 20804000.i2c: BSC1 Controller at 0x20804000 (irq 79) (baudrate 100000)

Esto muestra que se cargó el driver del i2c con velocidad 100kHz (baudrate).

$ dmesg | grep rtc
[   14.733399] rtc-ds1307 1-0068: rtc core: registered ds3231 as rtc0

Esto muestra que el driver del RTC se cargó exitosamente, como DS3231 y se registró como dispositivo rtc0 en uso por el kernel como reloj en tiempo real. Lo curioso es que el módulo del kernel se llama rtc-ds1307, aunque soporta ese modelo y el del DS3231.

$ lsmod | grep rtc
rtc_ds1307             10459  0

 Aquí también se ve que el módulo del kernel está cargado, y que se llama rtc_ds1307. En fin, hay mucha historia en linux...

$ ls /dev/rtc?
/dev/rtc0

Esto muestra que el dispositivo está en uso por el kernel y está disponible para ser usado desde los programas usuario.

4) Opcional: Uso herramienta i2cdetect

Opcionalmente se puede usar la herramienta i2cdetect para reconocer el dispositivo al conectarlo. Para ello se debe instalar el paquete i2c-tools, luego de la consabida actualización del sistema
$ sudo apt-get update && sudo apt-get upgrade
$ sudo apt-get install i2c-tools


Si por ejemplo no hubieramos hecho la configuración del punto 1, al usar el utilitario, se mostraría lo siguiente (usando el canal 1 para Raspi modelos B+/ 2 / 3)
$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Aquí se ve que el único dispositivo conectado por i2c tiene dirección 0x68, correspondiendo al RTC según el datasheet (0b1101000).

Sin embargo, cuando el kernel cargó el módulo y por lo tanto administra el RTC, el comando entrega:
$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Las letras UU indica que esa dirección está siendo usada por un driver del kernel.

5) Establecer y leer la hora desde el dispositivo rtc0

Aunque el reloj ya está reconocido por el kernel, aún no se está utilizando para establecer la hora en el Raspi. Partamos con los comandos básicos para leer y escribir la hora hacia el RTC:


$ sudo hwclock -r
jue 28 abr 2016 08:30:09 CLST  -0.867263 seconds

Con esto se lee la hora desde el RTC (parámetro -r). En este caso el reloj del RTC estaba bastante atrasado.

La hora del sistema se puede ver con:
$ date
jue may  5 23:02:46 CLST 2016


En mi caso el reloj igual estaba unos minutos atrasado, posiblemente porque tenía el Raspi muchos días funcionando.

Para setear la hora del sistema, se usa este comando:
$ sudo date -s "may 5 2016 23:09:40 CLST"
jue may  5 23:09:40 CLST 2016


Ahora como el reloj del sistema está bien, se puede establecer la hora en el RTC como:
$ sudo hwclock -w

Con esto se escribe la hora hacia el RTC (parámetro -w).

6) Utilización de RTC para establecimiento de la hora del sistema

Todavía falta algo, pues aunque tengamos seteada la hora correcta en el RTC, el sistema al reiniciarse aún sigue utilizando el dispositivo fake-hwclock (rtc en software), que usa el servicio ntp para obtener la fecha y hora actuales desde la red. Por ello, se debe habilitar el servicio hwclock.
Así, para raspbian Jessie se ajustan ambos servicios:
$ sudo update-rc.d hwclock.sh enable
$ sudo update-rc.d fake-hwclock disable


 Finalmente se debe resetear el Raspi, con el comando:
$ sudo shutdown -r now


En todo caso siempre se puede llamar manualmente al servicio ntp para sincronizar la hora del RTC:
$ sudo ntpd -gq; sudo hwclock -w
ntpd: time set -6.827372s


sábado, 9 de enero de 2016

Guía visual de armado de Pantalla oficial 7 pulgadas para Raspberry Pi

Bueno, me dominó la tentación y compré la pantalla de 7" para el Raspberry Pi: ¡tenía que armarla! Aproveché de documentar los pasos que encontré difíciles; aquí estan para ayudar a otros que pueden buscarla en nuestro idioma.

Esta es la pantalla:

La pantalla viene con una placa base que se atornilla en la parte posterior del display, y con unos extensores que permiten fijar también la placa madre del Raspberry Pi, como se ve una imagen del blog de Raspberry Pi:
fuente: https://www.raspberrypi.org/blog/the-eagerly-awaited-raspberry-pi-display/

Lo que muestro es cómo hacer las conexiones de la placa base con el display, partiendo con el cable ancho primero en esta animación GIF:
Armado del primer cable plano.

Teniendo el cable y la placa paralelos, se debe soltar el sujetador del conector (pequeña pieza plástica de color negro) para poder insertar luego el cable por debajo. Yo usé mis uñas, pero alguien más precavido podría usar un destornillador plano pequeño.

Al colocar el cable plano, se debe tener cuidado que quede bien insertado y de forma paralela, para que todos los terminales hagan bien contacto en el conector (no como en mi primera foto que partí poniendo chuequísimo el cable).

Así no!! Así sí, y ... :-) presionar hasta que toque fondo.
Presionar por un lado Presionar por el otro ¡Lista esta conexión!
Armado del segundo cable plano.

Luego pasamos al otro conector, que es bastante mas pequeño y viene con un chip en un circuito flexible. Igual me dió nervio romper algo, así que tuve cuidado de no tocar los terminales metálicos o el chip. Luego el objetivo es girar la placa, posandola en la parte posterior de la plantalla.
Tomar la placa suavemente, rotarla hacia la pantalla, hasta posarla sobre ella.
Soltar suavemente el sujetador de un lado, luego del otro, hasta que esté suelto en ambos lados.

Sujetar con cuidado el segundo ensamble, insertar el cable plano en el conector, presionar para cerrar y ¡listo!
Del resto del ensamblaje no saqué fotos (pues lo hice otro día y no tenía la cámara a mano), pero se trata de 1) montar los tornillos separadores entre la placa base y el soporte de la pantalla, 2) interconectar la placa base del Raspi, tanto en el conector CSI como en los cables de energìa y 3) atornillar la placa base a los separadores. Espero que aunque poco, esta guía visual igual le sirva a alguien.

Sobre el software, no hay mucho que hacer, salvo que antes de conectarlos asegurarse que se esté con el kernel actualizado para que funcione auto-magicamente, con los usuales:

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get dist-upgrade

jueves, 17 de diciembre de 2015

Uso de Librería u8glib para Raspberry Pi con OLED SSD1306

Como parece que me gustan los retos (¿para qué hacerlo fácil, si puedo investigar un poco?), investigué la forma de utilizar la biblioteca u8glib en el Raspberry Pi, para utilizar el OLED que compré en dx.com:
Esta biblioteca permite utilizar directamente una gran variedad de pantallas LCD monocromáticas sin usar X u otras bibliotecas como SDL, pudiendo usar fonts distintos y dibujar líneas, rectángulos, círculos, etc. Tiene un repositorio en Github para el código fuente y manejo de versiones y wiki para la documentación.
Logo U8glib
Aunque en sus orígenes estaba orientada a Arduino, requiriendo poca memoria en esos sistemas, actualmente funciona también en otras plataformas como AVR y ARM.
Esto último es interesante, pues los Raspberry Pi tienen CPU ARM aunque funcionando sobre Linux. Supuestamente no está soportando oficialmente el Raspberry Pi (esto está marcado como mejora en futuras versiones), pero no hay una incompatibilidad en realidad. Al investigar encontré que se le han estado haciendo cambios para soportar al Raspi, ¡y sí funciona!

El módulo OLED en cuestión tiene una resolución de 128 x 64 pixeles, y aunque supuestamente es monocromático, en realidad es bicolor: 16 pixeles (1/4 de pantalla) son amarillos y el resto de color celeste. Aquí va una foto para ilustrar esto:
El módulo permite conexiones SPI (4 y 3 pines) e I2C, cambiando soldando o desoldando pines en su placa, lo que aunque no es difícil, no es como llegar y cambiar.

La biblioteca tiene bastante soporte para este módulo SSD1306, permitendo variedades de OLED con resoluciones 128x64 (como la mía), 128x32 y 64x48, conectándose por SPI e I2C, tanto emuladas por software como usando el soporte de hardware nativo del Raspi. Aunque en la wiki no está muy claro, también permite el uso de doble buffer para ambos tipos de conexiones, lo que en teoría permitiría mostrar animaciones en forma fluida (sin "tearing effect").
Hasta ahora lo he probado solo con SPI por hardware con buffer simple usando 5 pines de datos (más 2 de energía), y no he visto que consuma mucha CPU, que era lo que quería.

Conexiones al Módulo SSD1306

Este es el esquema de conecciones que he usado, mostrando las distintas notaciones para los pines que utiliza la biblioteca.

Pin Módulo OLED Función RPi / Número notación BCM Pin en conector RPi Pin notación WiringPi Función en biblioteca u8gli (Arduino)
1-VCC
+3.3V
pin 17
-
-
2-GND
GND
pin 20
-
-
3-NC
no conectado
-
-
-
4-DIN (data input)
MOSI / GPIO10
pin 19
12
MOSI
5-CLK (clock)
SCLK / GPIO11
pin 23
14
SCK
6-CS (select)
CE0# / GPIO8
pin 24
10
CS
7-D/C (data/command)
GPIO24
pin 18
5
A0
8-RES (reset)
GPIO25
pin 22
6
RESET

La biblioteca 8glib en su sabor Arduino, que es la que probé en su versión del 2/nov/2015, obviamente utiliza notación Arduino. Las personas que están haciendo la implementación para el Raspi utilizaron la biblioteca WiringPi, que tiene orientación similar, pero hay que hacer traducciones entre las distintas notaciones. No me gustó mucho la complicación, pero se puede vivir con eso, especialmente mirando las notaciones de WiringPi y las de Raspberry Pi.

Compilación de biblioteca u8glib en Raspi

Conseguí compilar la biblioteca en el Raspi, usando el siquiente procedimiento:
  • Instalar prerequisitos de compilación en Raspi:
    Me costó al principio la compilación pues yo no detectaba que me faltaban tener instalados los paquetes autoconf y libtool.
    $ sudo apt-get install build-essential autoconf libtool libsdl1.2-dev
  • Clonar el código fuente desde el repositorio:
    En este caso estoy usando la más reciente desde la versión 1.18.1.
    $ sudo git clone https://github.com/olikraus/u8glib.git
    $ cd u8glib/
  • Modificar los programas de ejemplo para que compilen considerando mis conecciones:
    Cambié los siguientes archivos:
    $ sudo nano sys/arduino/Chess/Chess.cpp
    $ sudo nano sys/arduino/U8gLogo/U8gLogo.cpp
    $ sudo nano sys/arduino/GraphicsTest/GraphicsTest.cpp
    buscando la línea que contenía la inicialización del SSD1306 que usara el wardware de SPI :
    //U8GLIB_SSD1306_128X64 u8g(10, 9); 
    // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are  SCK = 13 and MOSI = 11)
    para cambiarla a utilizar mis conexiones:
    U8GLIB_SSD1306_128X64 u8g(10, 5, 6); 
    // HW SPI Com: CS = 10 @wiringpi (8 @BCM_GPIO), A0 = 5 @wiringpi (24 @BCM_GPIO), RESET = 6 @wiringpi (25 @BCM_GPIO) (Hardware Pins are SCK = 14 @wiringpi (11 @BCM_GPIO) and MOSI = 12 @wiringpi (10 @BCM_GPIO))
  • Configurar la biblioteca y compilar:
    $ sudo ./autogen.sh
    $ sudo ./configure
    $ sudo make
    $ sudo make install
  •  Ejecutar el programa de ejemplo:
    $ sudo ./u8gwpi_logo


Cosas por explorar

  • Cambiar la velocidad de conexión SPI, pues como viene el código fuente invocando a la librería WiringPi, la velocidad es de 100kHz. Esto se cambia en el archivo csrc/u8g_com_raspberrypi_hw_spi.c, dentro de la función u8g_com_raspberrypi_hw_spi_fn, en la línea 77:
    case U8G_COM_MSG_INIT:
    ...
      if (wiringPiSPISetup (0, 100000) < 0)
      {
          printf ("Unable to open SPI device 0: %s\n", strerror (errno)) ;
          exit (1) ;
      }

    Según lo mostrado en la documentación del RPI, en la tabla de velocidades, existen velocidades más altas a las que debería funcionar como 3.2MHz o 7.8MHz. Según la documentación del SSD1306, el límite de velocidad sería 10MHz (parametro mínimo de tSCLK de 100ns. de la tabla 13-4 de características de conexión SPI-4 de esa documentación).
    Sin embargo, en los últimos kernels RPI sobre 3.18, ya está implementado un parche que permite funcionar a velocidades intermedias, mientras sean múltiplos de 2 (post de foro RPI "SPI has more speeds"). ¿Cómo andará a 10Mhz?
  • Medir rendimiento y ver si las animaciones corren en forma fluída usando la invocación con doble buffer.

jueves, 28 de mayo de 2015

Esperanzas para Sintonizador ISDB-T (SMS1140): ¿corre en Android?

Esperanzas para Sintonizador ISDB-T (SMS1140): ¿corre en Android?

Mirando una noticia en Fayerwayer (Cómo ver los partidos de la Copa América desde tu celular), encontré sintonizadores compatibles con Android para ISDB-T, DVB-T y ATSC (Geniatech PT275 y otros), y encontré allí que también tienen un sintonizador basado en el chip SMS1140: S936 ISDB-T.
No estaba muy seguro de que era el mismo chip, hasta que bajé el driver para linux dentro de la sección de soporte al S936 y vi dentro del ZIP: el directorio principal se llamaba "siano1140linuxdriver" y dentro de este estaba el mismo archivo de firmware "dvb_nova_12mhz_b0.inp", junto con que las instrucciones para compilar el driver para Linux, indica que se debe agregar el mismo identificador "SMS1XXX_BOARD_SIANO_NOVA_B" que se utiliza en el driver que ya está en LinuxTV (ver artículo anterior Configuración de Sintonizador ISDB-T en Linux Mint).
@@ -301,6 +299,9 @@
     case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
     case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
     case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+    case SMS1XXX_BOARD_SIANO_NOVA_B:


Lo otra cosa interesante es que en la página del producto en Geniatech indican que se puede utilizar en Android! Habrá que investigar esto también...

Lo que sí ocurre es que en DX.COM tienen a la venta uno que se parece mucho:  Micro USB DVB-T ISDB-T Digital Mobile Phone TV Tuner Receiver Stick for Android Tablet/ Mobile Phone.

En la noticia de Faywerwayer mostraban ese y por lo que indican en el foro de dx.com, se podría usar en Android la app PadTV o PadTV HD. De hecho en Geniatech tienen los APK para bajar versiones para ellos. Habrá que probar...