Thumby API

23/12/2021

# Introducción

Como hemos comentado ya en algunas de las unidades didácticas anteriores y tras haber estudiado el concepto de Firmware y el Thumby IDE, en lo que sigue vamos a utilizar fundamentalmente las herramientas que proporciona esta última plataforma. Además del IDE, una de los elementos que facilita la programación de Raspberry Pi Pico y en concreto de PiConsole y el hardware de que consta, es la API de Thumby.

API significa Application Programming Interface o Interfaz de Programación de Aplicaciones (opens new window) en español. En general se refiere a una librería que ofrece un conjunto de funciones para facilitar el uso de determinado hardware o servicio. Por ejemplo, la pantalla OLED de PiConsole es un dispositivo hardware conectado a Pico por medio de una conexión SPI (opens new window). La forma de trabajar con ella consiste en enviar a través del interfaz SPI los comandos que el fabricante indica en su datasheet (u hoja de especificaciones). Si echamos un vistazo al datasheet de esta pantalla (opens new window) (página 64), vemos que sólo inicializarla sin llegar a dibujar nada en ella, requiere de 12 comandos. Cualquier operación requerirá un número elevado de estos comandos que además en general resultan muy crípticos para el profano. Como será habitual que sólo requiramos realizar unas pocas operaciones habituales en la pantalla (escribir un texto en una determinada posición, dibujar algunas pocas primitivas gráficas como puntos o rectas, o representar gráficos predibujados), resulta muy práctico preparar una librería que se especialice en estas funciones y nos abstraiga de los comandos de bajo nivel que hay que enviar a la pantalla para realizar esas operaciones.

La API de Thumby que vamos a ver recoge funciones para usar no sólo la pantalla sino también de los 6 controles y el buzzer. Los elementos que tiene PiConsole que no existen en Thumby (el potenciómetro, los LEDs y la fotorresistencia) no están contemplados naturalmente en la librería, por lo que tendremos que acceder a ellos de forma más directa. Vamos a ver a continuación las capacidades de la API de Thumby así como el uso directo de los dispositivos adicionales de PiConsole.

# API Thumby

Los amigos de Thumby tienen su propia documentación de la API en este sitio (opens new window). A continuación vamos a repetir más o menos la información que allí hay, con las pequeñas modificaciones que hemos hecho a la API para que sea compatible con PiConsole. El código de la librería se encuentra en el fichero thumby.py que hay dentro del directorio lib que se crea/instala cuando utilizamos el botón FORMAT del Thumby IDE. La versión que se instala desde el Thumby IDE (opens new window) adaptado para PiConsole, ya incluye las modificaciones necesarias para funcionar correctamente con PiConsole. Puede consultarse en la copia que hay en el repositorio de software de PiConsole en este enlace (opens new window).

# Pantalla

  • # Constantes

    • thumby.DISPLAY_W: 128 | Número de píxeles de ancho de la pantalla
    • thumby.DISPLAY_H: 64 | Número de píxeles de alto de la pantalla
  • # Funciones

    • thumby.display.update() | Actualiza la pantalla con el resultado de haber utilizado las funciones de dibujo que se describen después. Llamar a esta función lo menos posible, sólo cuando hayamos terminado de representar la escena completa, no después de cada orden de dibujo (por ejemplo thumby.display.rect(...), thumby.display.drawText(...), etc.).
      • Devuelve None
    • thumby.display.fill(color) | Cambia todos los píxeles de la pantalla al color color.
      • Devuelve: None
      • Argumentos:
        • color | tipo: int; valores: 0 o 1 (predeterminado: 0)
    • thumby.display.setPixel(x, y, color) | Cambia el pixel en la posición x,y al color color.
      • Devuelve: None
      • Argumentos:
        • x | tipo: int; valores: 0 (izquierda) ~ 127 (derecha)
        • y | tipo: int; valores: 0 (arriba) ~ 63 (abajo)
        • color | tipo: int; valores: 0 o 1 (predeterminado: 1)
    • thumby.display.drawLine(x1, y1, x2, y2, color) | Dibuja una línea de 1px de espesor con el color color desde la posición x1,y1 hasta la x2,y2.
      • Devuelve: None
      • Argumentos:
        • x1 | tipo: int; valores: 0 (izquierda) ~ 127 (derecha)
        • y1 | tipo: int; valores: 0 (arriba) ~ 63 (abajo)
        • x2 | tipo: int; valores: 0 (izquierda) ~ 127 (derecha)
        • y2 | tipo: int; valores: 0 (arriba) ~ 63 (abajo)
        • color | tipo: int; valores: 0 o 1 (predeterminado: 1)
    • thumby.display.fillRect(x, y, w, h, color) | Crea un rectángulo relleno del color color con la esquina superior izquierda en la posición x,y y con las dimensiones w (anchura) y h (altura).
      • Devuelve: None
      • Argumentos:
        • x | tipo: int; valores: 0 (izquierda) ~ 127 (derecha)
        • y | tipo: int; valores: 0 (arriba) ~ 63 (abajo)
        • w | tipo: int; valores: 0 ~ 127
        • h | tipo: int; valores: 0 ~ 63
        • color | tipo: int; valores: 0 o 1 (predeterminado: 1)
    • thumby.display.rect(x, y, w, h, color) | Crea un rectángulo de 1px de espesor del color color con la esquina superior izquierda en la posición x,y y con las dimensiones w (anchura) y h (altura).
      • Devuelve: None
      • Argumentos:
        • x | tipo: int; valores: 0 (izquierda) ~ 127 (derecha)
        • y | tipo: int; valores: 0 (arriba) ~ 63 (abajo)
        • w | tipo: int; valores: 0 ~ 127
        • h | tipo: int; valores: 0 ~ 63
        • color | tipo: int; valores: 0 o 1 (predeterminado: 1)
    • thumby.display.drawText(string, x, y, color) | Escribe la cadena string del color color en la posición x,y con el tipo de letra predeterminado de MicroPython en tamaño 8px x 8px.
      • Devuelve: None
      • Argumentos:
        • string | tipo: str; valores: 128 caracteres ASCII
        • x | tipo: int; valores: 0 (izquierda) ~ 127 (derecha)
        • y | tipo: int; valores: 0 (arriba) ~ 63 (abajo)
        • color | tipo: int; valores: 0 o 1 (predeterminado: 1)
    • thumby.display.blit(inspr, x, y, w, h, key) | Dibuja los píxeles definidos en el array inspr en la posición x,y adoptando la anchura y altura indicadas en w y h (lo que se suele llamar un sprite) con cálculos de transparencias indicados en key (-1: Los píxeles negros se dibujan como negros; 0: Los píxeles negros se tratan como transparentes; 1: Se mezclan los píxeles con cierta operación desconocida).
      • Devuelve: None
      • Argumentos:
        • x | tipo: int; valores: 0 (izquierda) ~ 127 (derecha)
        • y | tipo: int; valores: 0 (arriba) ~ 63 (abajo)
        • w | tipo: int; valores: 0 ~ 127
        • h | tipo: int; valores: 0 ~ 63
        • key | tipo: int; valores: -1 o 0 o 1 (predeterminado: -1)
    • thumby.display.drawSprite(inspr, x, y, w, h, mirrorX, mirrorY, key) | Dibuja los píxeles definidos en el array inspr en la posición x,y adoptando la anchura y altura indicadas en w y h (lo que se suele llamar un sprite) con la posibilidad de reflejar alrededor de los ejes x e y indicados en los flags mirrorX y mirrorY y con cálculos de transparencias indicados en key (-1: Los píxeles negros se dibujan como negros; 0: Los píxeles negros se tratan como transparentes; 1: Se mezclan los píxeles con cierta operación desconocida).
      • Devuelve: None
      • Argumentos:
        • x | tipo: int; valores: 0 (izquierda) ~ 127 (derecha)
        • y | tipo: int; valores: 0 (arriba) ~ 63 (abajo)
        • w | tipo: int; valores: 0 ~ 127
        • h | tipo: int; valores: 0 ~ 63
        • mirrorX | tipo: bool; valores: 1/True (reflejar) o 0/False (no reflejar)
        • mirrorY | tipo: bool; valores: 1/True (reflejar) o 0/False (no reflejar)
        • key | tipo: int; valores: -1 o 0 o 1 (predeterminado: -1)

# Teclas

  • # Objetos

    • thumby.buttonA | Para acceder a la tecla A
    • thumby.buttonB | Para acceder a la tecla B
    • thumby.buttonU | Para acceder a la dirección Arriba en la cruceta
    • thumby.buttonD | Para acceder a la dirección Abajo en la cruceta
    • thumby.buttonL | Para acceder a la dirección Izquierda en la cruceta
    • thumby.buttonR | Para acceder a la dirección Derecha en la cruceta
  • # Funciones

    • thumby.buttonX.pressed() | Devuelve True si la tecla thumby.buttonX está pulsado, False en otro caso (sustituir buttonX por cualquiera de los objetos de la lista anterior)
    • thumby.buttonX.justPressed() | Devuelve True si la última tecla pulsada fue thumby.buttonX, False en otro caso (sustituir buttonX por cualquiera de los objetos de la lista anterior)

# Sonido

Nota: El sonido no está implementado en el emulador del Thumby IDE, pero es poco probable que produzca excepciones.

  • # Funciones

    • thumby.audio.play(freq, duration, duty) | Reproduce una nota de frecuencia freq, ancho de pulso duty por una duración de duration en milisegundos sin bloquear la ejecución del resto del código. Por ahora, intenta buscar "tabla notas musicales frecuencia" para relacionar estos parámetros con notas musicales.
      • Devuelve: None
      • Argumentos:
        • freq | tipo: int; valores: 7 ~ 125000000 (Hz)
        • duration | tipo: int; valores: 0 ~ 2147483647 (ms)
        • duty | tipo: uint_16; valores: 0 (0%) ~ 65535 (100%) (predeterminado: 32768 equivalente a 50%)
    • thumby.audio.playBlocking(freq, duration, duty) | Reproduce una nota de frecuencia freq, ancho de pulso duty por una duración de duration en milisegundos bloqueando la ejecución del resto del código. Por ahora, intenta buscar "tabla notas musicales frecuencia" para relacionar estos parámetros con notas musicales.
      • Devuelve: None
      • Argumentos:
        • freq | tipo: int; valores: 7 ~ 125000000 (Hz)
        • duration | tipo: int; valores: 0 ~ 2147483647 (ms)
        • duty | tipo: uint_16; valores: 0 (0%) ~ 65535 (100%) (predeterminado: 32768 equivalente a 50%)
    • thumby.audio.stop() | Detiene la reproducción de cualquier sonido producido por thumby.audio.play(...).
      • Devuelve: None
    • thumby.audio.set_enabled(setting) | Desactiva o activa el buzzer de manera que en estado desactivado las funciones thumby.audio.play() o thumby.audio.playBlocking() no producen sonido. thumby.audio.playBlocking(...) seguirá bloqueando la ejecución del código durante la duración indicada en los parámetros.
      • Devuelve: None
      • Argumentos:
        • setting | tipo: bool; valores: 1/True (activado) o 0/False (desactivado)

# Archivos

Precaución: La creación y escritura en ficheros no funciona en el emulador del Thumby IDE y puede causar excepciones.

  • # Funciones

    • thumby.files.openFile(filename, options) | Abre el fichero de la ruta completa indicada en filename (por ejemplo /Games/MyGame/config.txt) con la opción de apertura de ficheros de Python (opens new window) indicada en options.
      • Devuelve: None
      • Argumentos:
        • filename | tipo: str; valores: Ruta ASCII con directorios separados por /
        • options | tipo: str; valores: 'w', 'r', 'wb', 'rb'
    • thumby.files.closeFile() | Cierra el último fichero abierto con thumby.files.openFile(...).
      • Devuelve: None
    • thumby.files.setFile(f) | Asocia el fichero manejado internamente al objeto Python de tipo fichero f (obtenido por ejemplo con f = open(..., ...)).
      • Devuelve: None
    • thumby.files.readFile(l) | Lee l bytes del fichero abierto con thumby.files.openFile(...).
      • Devuelve: los l bytes leídos del fichero o "" si no se ha abierto fichero todavía
      • Argumentos:
        • l | tipo: int; valores: 0 ~ 2147483647 (default: -1, read whole file)
    • thumby.files.writeFile(data) | Escribe data al fichero abierto con thumby.files.openFile(...).
      • Devuelve: True si ha tenido éxito, False si no, y -1 si no se ha abierto fichero todavía
      • Argumentos:
        • data | tipo: str, bytes(...), bytearray(...), etc.; valores: texto o binario dependiendo de la opción con que fue abierto el fichero
    • thumby.files.changeDirectory(path) | Cambia el directorio a la ruta path (por ejemplo si path vale ""/Games/MyGame" a partir de entonces podremos hacer f = open("config.txt")).
      • Devuelve: None
      • Argumentos:
        • path | tipo: str; valores: Ruta ASCII con directorios separados por /
    • thumby.files.getDirectory() | Devuelve un str con la ruta del directorio actual seleccionado.
    • thumby.files.makeDirectory(path) | Crea el directorio indicado en path.
      • Devuelve: None
      • Argumentos:
        • path | tipo: str; valores: Ruta ASCII con directorios separados por /

Ejemplo rápido

Vamos a mostrar cómo utilizar la API escribiendo un sencillo programa que emplee alguna de las funciones anteriores. Abre el Thumby IDE (opens new window) y teclea en el Editor de código lo siguiente:

import thumby

thumby.display.fill(0)      # Rellena pantalla de negro
thumby.display.update()     # Refresca pantalla

def nota(tecla, freq):
    thumby.display.drawText(tecla, 60, 30, 1)       # Dibuja tecla pulsada
    thumby.display.update()                         # Refresca pantalla
    thumby.audio.playBlocking(freq, 1000, 32768)    # Interpreta nota
    thumby.display.fill(0)                          # Rellena pantalla de negro
    thumby.display.update()                         # Refresca pantalla

while True:
    if thumby.buttonA.justPressed():                # Detecta pulsación 'A'
        nota("A", 440)                              # Interpreta nota 'A' (La)

    if thumby.buttonB.justPressed():                # Detecta pulsación 'B'
        nota("B", 494)                              # Interpreta nota 'B' (Si)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Pulsa FAST EXECUTE para ejecutarlo en PiConsole. Probarlo pulsando las teclas A y B

Última actualización: 21/4/2022, 10:20:07