Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Interruptor de Arranque Pico-Powered: Elige tu SO Antes de Encender

Pre-elige el SO para arrancar, incluso antes de encender el ordenador, conmutando un interruptor. Ahora no tienes que esperar a seleccionar el SO (Windows) desde el menú GRUB cada vez que quieres cambiar a Windows.

Historia

Navegando por Hackaday.io, tropecé con este proyecto de Stephen Holdaway. En él, resolvió una tarea frustrante a la que se enfrenta todo usuario de dual boot: sentarse y esperar para elegir el SO (Windows) desde el menú GRUB cada vez que queremos cambiar a Windows. Logró añadir un interruptor hardware para determinar el SO a arrancar cada vez que se enciende el ordenador.

Lo logró configurando un microcontrolador STM32 como dispositivo de almacenamiento masivo USB. Ha documentado todo su viaje a través de la investigación e implementación en su post de Hackaday. Por favor, revisa su post para entender mejor las implementaciones.

En este proyecto, te mostraré cómo logré portar los cambios a Raspberry Pi Pico. Puedes encontrar mi versión en este repositorio de GitHub.

Concepto

GNU GRUB es un programa que se ejecuta antes de que se cargue cualquier Sistema Operativo. A través de este menú, podemos seleccionar qué SO cargar. GRUB ofrece módulos muy limitados para trabajar. Esto significa que no puede leer datos de un microcontrolador conectado vía USB. Pero sí puede leer datos de discos de almacenamiento.

Así que podemos engañar a GRUB para que lea datos del microcontrolador, enumerando nuestro micro como un dispositivo de almacenamiento masivo.

Por tanto, enumeramos nuestra Raspberry Pi Pico como dispositivo de almacenamiento masivo, vía la librería tinyUSB, que tendrá un archivo switch.cfg, al que el Pico escribirá la posición del interruptor: 1 para ON, 0 para OFF.

Tenemos que añadir un script en GRUB, cuyas funciones lean el archivo switch.cfg y establezcan el default a 0 (Ubuntu) / 2 (Windows).

Cuando GRUB carga, ejecuta nuestros scripts personalizados, que a su vez buscan nuestro dispositivo por sus identificadores UUID, y si existe, leen el archivo switch.cfg. Tras obtener la posición del interruptor, establece la selección de SO por defecto respectivamente.

En resumen:

Configurar el Pico como Dispositivo de Almacenamiento Masivo

He usado el ejemplo cdc_msc de tinyUSB para lograr esto. El ejemplo configura el Pico como dispositivo de almacenamiento masivo y crea un sistema de archivos FAT12 y enumera un archivo README.txt.

Cambié el README.txt a switch.cfg y añadí la línea "set os_hw_switch=0\n" al archivo.

#define SWITCH_CFG_CONTENTS \
"set os_hw_switch=0\n"

...
//------------- Block3: Readme Content -------------//
SWITCH_CFG_CONTENTS

Ahora hemos configurado el Pico como dispositivo de almacenamiento masivo. Tras copiar el archivo uf2 al Pico, se enumera como dispositivo de almacenamiento. Necesitaremos el UUID del dispositivo para el script de GRUB, que es UUID="0000-1234".

$ sudo blkid
...
/dev/sda: SEC_TYPE="msdos" LABEL_FATBOOT="TinyUSB MSC" LABEL="TinyUSB MSC" UUID="0000-1234" BLOCK_SIZE="512" TYPE="vfat"

Circuito

Leer Posición del Interruptor y Escribir en Archivo

Ahora necesitamos leer la posición del interruptor y cambiar el contenido del archivo switch.cfg según corresponda:

He usado GPIO_PIN 28 como pin del interruptor, configurado como pull-down.

read_switch_value devuelve la posición del interruptor: '1' es on (pull-up) y '0' es off (pull-down).

//-------------------------main.c---------------------
#define SWITCH_PIN 28

// read switch value
uint8_t read_switch_value()
{
    return gpio_get(SWITCH_PIN) ? '1' : '0';
}

int main(void)
{
    gpio_init(SWITCH_PIN);

    // configure pin as INPUT
    gpio_set_dir(SWITCH_PIN, false);

    // configure pin as PULL_DOWN
    gpio_set_pulls(SWITCH_PIN, false, true);

Para escribir la posición del interruptor en switch.cfg, he usado readGRUBConfig() que llama a la función read_switch_value, y establece el buffer de salida con la posición del interruptor.

Descubrí que al leer el tercer bloque3 lba se establece a 3, por lo que interceptando la llamada y llamando a readGrubConfig y pasando el buffer donde se copiará el contenido del archivo.

//-------------------------msc_disk.c---------------------
static char grubConfigStr[] = "set os_hw_switch=0\n";
static void readGrubConfig(uint8_t* output)
{
    // Modify config string with current switch value
    grubConfigStr[sizeof(grubConfigStr)-3] = read_switch_value();
    memcpy(output, &grubConfigStr, sizeof(grubConfigStr));
}

// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
    (void) lun;
    // when reading the file
    if(lba == 3){
        readGrubConfig(buffer);
        return bufsize;
    }
    ...
    ...
}

Compilar el Código del Pico

Necesitamos añadir stdlib de pico a nuestro código para obtener acceso al pin gpio.

//-------------------------main.c-----------------------------------
#include 
#include 
#include 
#include "bsp/board.h"
#include "tusb.h"
...
#include "pico/stdlib.h"

Para compilar el proyecto:

$ mkdir build
$ cd build
$ cmake ..
$ make

Configurar GRUB para Leer el Contenido del Archivo

He añadido estos cambios en mi Ubuntu 20.10.

$ sudo vim /etc/grub.d/40_custom

....
# Buscar dispositivo de interruptor hardware por su ID de filesystem hardcodeado
search --no-floppy --fs-uuid --set hdswitch 0000-1234

# Si se encuentra, leer archivo de config dinámico y seleccionar entrada apropiada para cada posición
if [ "${hdswitch}" ] ; then
    source ($hdswitch)/switch.cfg

    if [ "${os_hw_switch}" == 0 ] ; then
        # Arrancar Linux
        set default="0"
    elif [ "${os_hw_switch}" == 1 ] ; then
        # Arrancar Windows
        set default="2"
    else
        # Fallback a default
        set default="${GRUB_DEFAULT}"
    fi

else
    set default="${GRUB_DEFAULT}"
fi

Primero, buscamos nuestro filesystem. GRUB tiene un subcomando search justo para esto.

Si se encuentra algún dispositivo, el primer dispositivo encontrado se establece como valor de la variable de entorno.

–set hdswitchhdswitch es nuestra variable de entorno y se establece con el nombre del disco si se encuentra.

Luego, hacemos source del archivo switch.cfg si la variable hdswitch está establecida, lo que crea otra variable de entorno os_hw_switch con la posición del interruptor (0/1).

Leemos el valor de os_hw_switch y establecemos el default a 0 o 2 respectivamente. 0 porque Ubuntu está en posición 0 y Windows en posición 2 en el menú GRUB.

Por último, si hdswitch no se estableció, ponemos el default a GRUB_DEFAULT.

Ahora necesitamos actualizar nuestro grub:

$ sudo update-grub

Fuente: Hardware Boot Select Switch Using Pico

Proceso de manufactura

  1. Guía completa de dispositivos de depilación modernos: Diseño, historia y futuro
  2. Construcción de una estación meteorológica exterior con Raspberry Pi 2 y ADS‑WS1
  3. Sistema de control de temperatura basado en LM35 con microcontrolador AT89S52
  4. Monitorización meteorológica remota con Raspberry Pi 3 y PubNub
  5. Integración de TI SensorTag con Blynk vía Node‑RED en Raspberry Pi Zero
  6. Controle un LED con Sensor PIR de Movimiento en Raspberry Pi
  7. Construye un robot inteligente con Bridge Shield – Integración Raspberry Pi y Arduino
  8. Construye un Robot Raspberry Pi Controlado por Wi‑Fi con Python – Guía Paso a Paso
  9. Hacking de Hardware Embebido para Dispositivos IoT: Herramientas, Técnicas e Implicaciones de Negocio
  10. Dominando la sentencia switch en C#: Sintaxis, ejemplos y mejores prácticas
  11. Dominando las Sentencias Using en C#: Importaciones, Alias y Directivas Estáticas