2021/04/15

Teclado Hexadecimal USB

A raiz de mi cada vez mayor involucramiento con sistemas embebidos y fpga y un arrastre de hace años de networking, tengo una necesidad: ingresar letras de la "a" a la "f" para cosas como código de máquina, direcciones de memoria y direcciones MAC, o sea, datos en formato hexadecimal.

¿Qué es eso? Pues que las máquinas representan todo con unos y ceros, pero a las personas nos cuesta, rápido, decime cuál número es mayor:

10111110101110101100101011111110

10111110101100001100101011111110



Esos números son

3199912702

3199257342


Que no es el formato nativo de la compu pero si nuestro.

Si esos números los agrupamos:

1011 1110 1011 1010 1100 1010 1111 1110

1011 1110 1011 0000 1100 1010 1111 1110


Vemos que cada grupo va de 0000 a 1111, que son 16 combinaciones y podemos representar con 0 a 9 y seis caracteres más, arbitrariamente elegidos A a F:

 0   0
 1   1
 2   2
 3   3
 4   4
 5   5
 6   6
 7   7
 8   8
 9   9
10   A
11   B
12   C
13   D
14   E
15   F


Podemos reescribir así:

BEBACAFE

BEB0CAFE


No es nuestro formato nativo, es fácil de convertir a y desde binario y es más fácil leerlos y escribirlos sin equivocarse.

No voy a entrar en todos los detalles de este tema que se llama "sistemas numéricos".


Cuando son pocos caracteres, aunque incómodo no es tan terrible, cosa que cambia cuando con una mano estoy sosteniendo un dispositivo y tengo que mover la vista del dispositivo al teclado pues aunque puedo escribir al tacto y con la mano izquierda están cubiertas esas letras, si hay mezcla con números, (10:6) se me complica o cuando son muchos caracteres.

Fijate en este caso, de un aparente exploit que había en una máquina y no podía copiarlo, entonces hice hexdump -C y captura de pantalla. Por supuesto no lo puedo encontrar, así que te muestro algo equivalente, los primeros bytes de /bin/ls:


Hexdump
Hexdump



Mientras reflexionaba sobre estos temas e investigaba para un trabajo práctico como hacer que linux entienda que lo que le paso por serial dentro de USB en realidad es un mouse, recordé que tengo un viejo teclado numérico QTronix, me parece que lo compré hace muchos mucho años en compucanje y algún Teensy 2, que viene a ser una variante de arduino, de hecho se programa con una variante de arduino ide llamada teensyduino y tiene la particularidad de funcionar como teclado USB con extrema sencillez. Hace un tiempo hice la conversión de un touchpad PS/2 a USB.

Habiendo puesto todos los ingredientes en el tazón, revolví y me dije, para qué voy a sufrir con los caracteres hexadecimales si puedo sufrir adaptando el teclado a USB y reprogramando unas teclas.

La reprogramación la hago en el Teensy antes de transmitir por USB, con el agregado de poder cambiar de modo, ya sea volver a las teclas nativas o cambiar de mayúscula a minúscula, apretando rápidas secuencias de una tecla de poco uso como es NumLock, la que controla que se envíen números o flechitas.


Primera etapa: preparativos


Determinar cuál es el modo común entre AP y X




El teclado tiene un switch que dice AP y X, calculo que viene a ser AT y XT, pues creo recordar que los teclados de las XT (8086) no eran compatibles con las AT (80286). Esta operación es muy fácil con un simple adaptador de DIN 5 180 grados a PS/2 lo tenemos:


Adaptador PS/2 a mini din a USB
Adaptador PS/2 a mini din a USB

Bueno, no tan simple, no tengo interfaz PS/2, no importa, si tengo un cajón llenísimo de todo tipo de basura adaptadora, igual que vos. Esto incluye un adaptador PS/2 a USB:

El cajón de adaptadores
El cajón de adaptadores

Te juro que empecé a ordenarlo para que se vea más lindo pero no, si uso mi tiempo en eso no lo uso en esto.



Listo, tal como esperaba es AP.


Medir consumo


Tendría que desarmar un poquito el teclado y medir. Luego agregarle el consumo del teensy, probablemente fabricando un cable USB donde puede poner en serie el tester o conseguir uno de estos:


Usb Tester
Usb Tester

No he hallado manera de que el mother te diga cuánto está consumiendo.

Mejor pensemos de otra manera:

Si el teclado con el adaptador PS/2 USB funciona, ¿qué tan distinto puede ser el consumo del Teensy? Listo, una preocupación menos.



Segunda etapa: implementar el software


Estoy seguro de tener una VM con teensyduino instalado, pero no recuerdo cuál. Si hubiera anotado en la descripción ese detalle podría encontrarlo, veamos...

Con este comando:

find $DIR1 $DIR2 -iname "*.vbox" | \
  while read CONF; do grep -ie teens -ie duino "$CONF";
done



Lo que hace el comando es buscar en las carpetas donde tengo VMs ($DIR1, $DIR2) archivos con extensión vbox y busca menciones a arduino o teensy.


No encontré nada, mala suerte. Ya instalaré una VM con eso. Uso mientras el de mi la máquina real, que no debería tener instaladas esas cosas.


Los requerimientos del programa son:

  • Debe convertir del protocolo del teclado PS/2 a USB Keyboard.
  • Debe reemplazar los keycodes determinados por [a-f] y tab.
  • Si se aprieta NumLock dos veces en rápida secuencia:
    • Debe cambiar ciclar entre [a-f] y [A-F]
  • Si se aprieta NumLock cuatro veces en rápida secuencia:
    • Debe cambiar ciclar entre el reemplazo y las funciones nativas.



+-----------+-----------+-----------+
|   print   |   scroll  |   pause   |
|   screen  |    lock   |           |
|    tab    |           |           |
+-----------+-----------+-----------+



+-----------+-----------+-----------+
|   insert  |    home   |  Page Up  |
|     A     |     B     |     C     |
+-----------+-----------+-----------+
|   delete  |    end    | Page Down |
|     D     |     E     |     F     |
+-----------+-----------+-----------+




El programa es básicamente el ejemplo de Teensy de adaptador de teclado PS/2 a USB, sólo que estoy mandando al Serial para diagnosticar.


include <PS2Keyboard.h>

const int DataPin = 5;
const int IRQpin =  3;

PS2Keyboard keyboard;
 
void setup() {
  delayMicroseconds(1000);
  Serial.begin(9600);
  keyboard.begin(DataPin, IRQpin);
  delay(2000);
  Serial.println("Keyboard Init");
}

void loop() {
 if (keyboard.available()) {
    char c = keyboard.read();

    if (c == PS2_ENTER) {
      Serial.println("[Enter]");
    } else if (c == PS2_TAB) {
      Serial.println("[Tab]");
    } else if (c == PS2_ESC) {
      Serial.println("[ESC]");
    } else if (c == PS2_PAGEDOWN) {
      Serial.
println("[PgDn]");
    } else if (c == PS2_PAGEUP) {
      Serial.
println("[PgUp]");
    } else if (c == PS2_LEFTARROW) {
      Serial.
println("[Left]");
    } else if (c == PS2_RIGHTARROW) {
      Serial.
println("[Right]");
    } else if (c == PS2_UPARROW) {
      Serial.
println("[Up]");
    } else if (c == PS2_DOWNARROW) {
      Serial.
println("[Down]");
    } else if (c == PS2_DELETE) {
      Serial.
println("[Del]");
    } else {
      Serial.println(c);
    }
  }
}


Y anda bastante bien, salvo que parece faltar una inicialización hacia el teclado, pues no prende la luz de KeyLock ni la detecta, asi como a varias otras teclas.


Prototipo, el teensy a la izquierda
Prototipo, el teensy a la izquierda


Tengo que analizar el protocolo, corre riesgo el proyecto, en pocos días regreso...


Debo además el cambio de función y mayúscula/minúscula y el armado físico.

Sigue en la primera versión.


2021/04/12

Orden y scripting para gestionar y preservar webinares

 Venís de leer cómo grabar webinares, pero te falta el antes y el despues.

 

Cómo conseguir webinares

 

Aunque claramente tengo un sesgo hacia algunos temas igual te cuento.

Con el dork "site:PROVEEDOR.com webinar" conseguís donde están los webinares de tus proveedores de preferencia.

Te pego acá algunos, no necesariamente los he explorado pero a ojo,  por los que he asist, ido parecen ser los correctos:

https://www.xilinx.com/about/webinar.html

https://www.nxp.com/design/training:TRAINING-EVENTS#/

https://www.arm.com/company/events/on-demand-webinars

https://neo4j.com/webinars/

etc...

Si te pareció medio raro eso de que nos los exploré, es por que mi fuente principal proviene de recibir por mail los eventos, habiéndome registrado en diversas listas, que corresponden a esos mismos proveedores.

Esto no es buscar oro, en realidad vos sos el producto así que apenas demuestres interés te van a llegar de sobra.

 

Cómo guardar y ordenar webinares


El concepto de ordenamiento es algo muy personal, así que lo que te comparto es sólo como referencia para que lo adaptes a tu gusto. De paso, hace bastante que no explico bash, aprovecho la ocasión así repasamos un poquito.

Todo esto es válido si compartís conmigo la perversa perversión de no confiar en la nube e intentar tener copia de lo que pueda tener valor.

Lo que más útil me ha resultado es distinguir los ya atendidos de los que no. Luego los que tengo de los que no. Ya tenemos cuatro posibilidades. Si a eso se le agrega que a algunos tanto atendidos como no, les estoy esperando el link para verlo y de paso  quizás grabarlo y algunos que... mejor te muestro las categorías que me vienen resultado:


  • attended
  • to_attend
  • to_classify
  • to_download
  • to_download_and_attend
  • to_download_and_attend_waiting_link

Entonces, para cada proveedor, tengo una carpeta con esta estructura adentro.

  • ARM
    • attended
    • to_attend
    • to_classify
    • to_download
    • to_download_and_attend
    • to_download_and_attend_waiting_link
  • XILINX
    • attended
      • webinar 1 
        • video 1.ogv
        • material 1.tgz
    • to_attend
    • to_classify
    • to_download
    • to_download_and_attend
    • to_download_and_attend_waiting_link


Dentro de cada categoría, una carpeta con el nombre del webinar conteniendo el video y opcionalmente:

  • preguntas y respuestas.pdf
  • material adicional.tgz

Parecería que vamos bien, pero teniendo más de tres proveedores se empieza a tornar confuso, ¿cúales ví? ¿cuáles tengo que bajar? Para eso están los scripts.

El primero está implícito y es cómo agregar un nuevo proveedor, por ejemplo, Xilinx:

cp -r template XILINX

El segundo es para explorar:

  1. for CAT in "to_attend" "to_download" \
  2.       "to_download and attend"  \
  3.       "to_download and attend waiting link" \
  4.       "to_download waiting link" "to_classify"; do
  5.    echo "#########################################"
  6.    echo "$CAT"
  7.    find . -path "*/$CAT/*" -type d  \
  8.       | rev \
  9.       | cut -d"/" -f 1 \
  10.       | rev \
  11.    | while read WEBINAR; do
  12.      echo \
  13.      $(find . -iname "$WEBINAR" | cut -d "/" -f 2)\
  14.      " $WEBINAR"
  15.    done
  16.    echo
  17. done


En la línea 1 a la 4 tenemos un for, que es un loop que va ejecutar la sección entre el do de la 4 y el done de la 17, asignando a CAT los strings enumerados.

Podría tomar esas categorías de la carpeta de template descartando to_attend, pero prefiero tener el control sobre el orden de las categorías.

Las líneas 5 y 6 hacen de encabezado de categoría.

En la 7 tenemos que vamos a buscar en la carpeta actual, los paths que coincidan en su nombre con CAT entre "/" y que sean directorios. Es que nos interesa la carpeta contenedora del webinar, no el video ni los materiales adicionales.

El problema es que nos trae algo de la forma:

./PROVEEDOR/CAT/webinar

y sólo nos interesa el webinar. En las líneas 8 a 10 tomo lo que haya a la derecha del último "/"

Primero lo reversamos con rev, luego con cat con delimitador "/" pedimos el primer campo (o sea el último al dercho) y lo volvemos a reversar.

Con el while de la 11, vamos leyendo cada resultado y asignándolo a WEBINAR y ejecutando el bloque do...done. Al WEBINAR lo buscamos en la 13 y con el cut nos quedamos con el primer campo, que es el PROVEEDOR.

Eso se lo damos al echo con $( ) que le agrega el WEBINAR y finalmente nos queda de la forma:

################################################
CAT1
PROVEEDOR1 WEBINAR1
PROVEEDOR1 WEBINAR2
PROVEEDOR2 WEBINAR3

################################################
CAT2

################################################
CAT3
PROVEEDOR1 WEBINAR4
PROVEEDOR3 WEBINAR5
PROVEEDOR4 WEBINAR6



Cuando lo hice no tenía clara la estructura aún, asi que este script puede tener alguna tara debida al legacy, seguro que lo podría mejorar, pero prefiero usar ese tiempo en escribir y compartir el tema

 

Cómo compartir conmigo los webinares

 

El paso final tiene que con que yo suelo ver los webinares en una tablet cuando estoy fuera de casa, poco frecuente con la cuarentena pero ocurre.

Lo primero es generar symbolic links a los videos que hayan en "to_attend" de todos los proveedores en una sola carpeta:

 

  1. find . -path "*/to_attend/*" \
  2.      -iname "*ogv" -o -iname "*mp4" \
  3.    | while read WEBINAR; do
  4.       ln -s "../$WEBINAR" zone4transfer
  5. done

En la línea 1 buscamos en las carpetas "to_attend" archivos ogv o mp4 y para cada uno hallado, generamos en la 3 el symbolic link con ln dentro de la carpeta que luego compartiremos.


Lo segundo, opcional, es cambiarle el nombre a los links, por ejemplo para un orden para verlos prefijando con 01_, 02_, lo que sea


Lo tercero es servirlos vía web, mi tablet tiene un montón de años, ya le cambié el conector USB y se ha roto otra vez y no puedo transferir archivos y me molesta usar una SD card.

  1. find zone4transfer -iname "*.mp4" \
  2.   -o -iname "*.pdf" \
  3.   -o -iname "*.ogv" \
  4.   | sort \
  5.   | while read FILE; do
  6.   FILE=$( basename "$FILE" )
  7.   echo "<a href=\"./$FILE\">$FILE</a><br/>"
  8. done  >zone4transfer/index.html
  9. php -t zone4transfer -S \
  10. $( ip addr show dev enp3s0 \
  11.    | grep "inet " \
  12.    | cut -d " " -f 6 \
  13.    | cut -d "/" -f 1\
  14. ):8080

En las líneas 1 y 2 buscamos en la carpeta donde están los symlinks los archivos mp4, ogv y de paso pdf, sirve para otras transferncias.

En la 3 le damos orden, en la 4 vamos leyendo y asignándola a FILE, pero tenemos que quitarle la ruta completa, en la 5 con basename, que por algún motivo oscuro no lo usé con el mismo propósito en el primer script.

En la 6 generamos una referencia html y en la 7 las concatenamos en un index.html

De la 9 a la 12 obtenemos la dirección IP de la interfaz sobre la que vayas a compartir y le concatenamos en la 13 el puerto.

Finalmente, en la 8 lanzamos un servidor web de php para que sirva en la ip y puerto que definimos antes los archivos de la carpeta donde están los symlinks.

Y más finalmente, si tenés un Android 4.x como el de mi tablet, te bajás VLC y podés ver los videos.

 

Algunas explicaciones pendientes

 

Fijate que "\" indica continuación de la línea en la siguiente, ojo, no puede tener nada a continuación salvo el salto de línea.

El comando find es bastante molesto, necesita que le respetes el orden de lo que le vas dando, es de mucho antes de expresiones como las de búsqueda de mongo, que aunque complicadas terminan siendo intuitivas. El -o significa "o".


El código en https://github.com/cpantel/playground/tree/master/sysadmin/webinar