You are not logged in.

#1 2016-06-20 18:01:19

daviddavo
Member
Registered: 2015-12-30
Posts: 64

Grub Scripting: Physichal Switch

I read that you can do a bit of scripting with GRUB2, and also it can read Serial. I have a Raspberry Pi Zero and a Arduino Uno, how can i make to add an actual switch to my case, and use it to select a boot option? I'm willing to use a 3 state button to boot the option 1, the option 2 or wait to select one of the three other options.

Edit: The motherboard has an internal COM1 port

Last edited by daviddavo (2016-06-20 18:30:14)

Offline

#2 2016-06-20 18:22:35

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,785

Re: Grub Scripting: Physichal Switch

It is not obvious what you are trying to do.  Are you trying to allow a microcontroller to use the serial port of your Arch Linux box to control what Grub boots?  Yes that is possible, but you won't likely have much luck using the Uno -- It's serial port is really a serial stream over USB that looks like a serial port.  That won;t work until your are booted and the device is enumerated on the USB bus.


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#3 2016-06-20 18:31:09

daviddavo
Member
Registered: 2015-12-30
Posts: 64

Re: Grub Scripting: Physichal Switch

ewaller wrote:

It is not obvious what you are trying to do.  Are you trying to allow a microcontroller to use the serial port of your Arch Linux box to control what Grub boots?  Yes that is possible, but you won't likely have much luck using the Uno -- It's serial port is really a serial stream over USB that looks like a serial port.  That won;t work until your are booted and the device is enumerated on the USB bus.

And using the Raspberry Pi Zero?

Offline

#4 2016-06-20 18:37:05

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,785

Re: Grub Scripting: Physichal Switch

Should be fine.


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#5 2016-06-22 14:39:53

dimich
Member
From: Kharkiv, Ukraine
Registered: 2009-11-03
Posts: 242

Re: Grub Scripting: Physichal Switch

Arduino Uno has native serial port. You just need TTL to RS232 converter to plug it to PC COM port, such as MAX3222.
The issue is can grub take terminal input from serial port and keyboard simultaneously?

Offline

#6 2016-06-22 14:41:22

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,785

Re: Grub Scripting: Physichal Switch

dimich wrote:

Arduino Uno has native serial port.

You are correct.  I was thinking Leonardo.


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#7 2016-06-22 14:52:32

dimich
Member
From: Kharkiv, Ukraine
Registered: 2009-11-03
Posts: 242

Re: Grub Scripting: Physichal Switch

Yes, grub can. You can setup terminal to serial and console both. Grub should write some unique char sequence to console. Controller's program should detect this sequence and answer with proper boot option name or do nothing in third case.

Offline

#8 2016-06-23 11:29:20

daviddavo
Member
Registered: 2015-12-30
Posts: 64

Re: Grub Scripting: Physichal Switch

dimich wrote:

Yes, grub can. You can setup terminal to serial and console both. Grub should write some unique char sequence to console. Controller's program should detect this sequence and answer with proper boot option name or do nothing in third case.

Thanks, now, to do some scripting.

Offline

#9 2016-07-06 13:58:35

dimich
Member
From: Kharkiv, Ukraine
Registered: 2009-11-03
Posts: 242

Re: Grub Scripting: Physichal Switch

Well, i had some free time and implemented something close to your design. For testing i used VirtualBox with host device serial port and ATtiny2313 as hardware.

First of all, setup grub to use serial port as console. This is my grub.conf:

GRUB_DEFAULT=0
GRUB_TIMEOUT=-1
GRUB_DISTRIBUTOR="Arch"
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX=""

# Preload both GPT and MBR modules so that they are not missed
GRUB_PRELOAD_MODULES="part_gpt part_msdos"

# Uncomment to enable Hidden Menu, and optionally hide the timeout count
#GRUB_HIDDEN_TIMEOUT=5
#GRUB_HIDDEN_TIMEOUT_QUIET=true

# Uncomment to use basic console

GRUB_SERIAL_COMMAND="serial --speed=9600 --unit=0 --word=8 --parity=no --stop=1"
GRUB_TERMINAL="console serial"

GRUB_VIDEO_BACKEND=vga

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=auto

# Uncomment to allow the kernel use the same resolution used by grub
#GRUB_GFXPAYLOAD_LINUX=keep

# Uncomment if you want GRUB to pass to the Linux kernel the old parameter 
# format "root=/dev/xxx" instead of "root=/dev/disk/by-uuid/xxx" 
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY=true

# Uncomment and set to the desired menu colors.  Used by normal and wallpaper 
# modes only.  Entries specified as foreground/background.
#GRUB_COLOR_NORMAL="light-blue/black"
#GRUB_COLOR_HIGHLIGHT="light-cyan/blue"

# Uncomment one of them for the gfx desired, a image background or a gfxtheme
#GRUB_BACKGROUND="/path/to/wallpaper"
#GRUB_THEME="/path/to/gfxtheme"

# Uncomment to get a beep at GRUB start
#GRUB_INIT_TUNE="480 440 1"

#GRUB_SAVEDEFAULT="true"

GRUB_DISABLE_SUBMENU=y

Then, here is patch for /etc/grub.d directory to generate sequentional hotkeys for each menu entry:

diff -ru /etc/grub.d/10_linux /home/dimich/vbox/grub/grub.d/10_linux
--- /etc/grub.d/10_linux	2015-12-15 17:36:16.000000000 +0200
+++ /home/dimich/vbox/grub/grub.d/10_linux	2016-06-26 07:27:09.000000000 +0300
@@ -98,9 +98,11 @@
 	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
 	  grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")"
       fi
-      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
+      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {" | sed "s/^/$submenu_indentation/"
   else
-      echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
+      echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {" | sed "s/^/$submenu_indentation/"
   fi      
   if [ x$type != xrecovery ] ; then
       save_default_entry | grub_add_tab
diff -ru /etc/grub.d/20_linux_xen /home/dimich/vbox/grub/grub.d/20_linux_xen
--- /etc/grub.d/20_linux_xen	2015-12-15 17:36:16.000000000 +0200
+++ /home/dimich/vbox/grub/grub.d/20_linux_xen	2016-06-26 07:27:33.000000000 +0300
@@ -98,10 +98,12 @@
          title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
          grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")"
       fi
-      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
+      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-$version-$type-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {" | sed "s/^/$submenu_indentation/"
   else
       title="$(gettext_printf "%s, with Xen hypervisor" "${os}")"
-      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
+      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-simple-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {" | sed "s/^/$submenu_indentation/"
   fi
   if [ x$type != xrecovery ] ; then
       save_default_entry | grub_add_tab | sed "s/^/$submenu_indentation/"
diff -ru /etc/grub.d/30_os-prober /home/dimich/vbox/grub/grub.d/30_os-prober
--- /etc/grub.d/30_os-prober	2015-12-15 17:36:16.000000000 +0200
+++ /home/dimich/vbox/grub/grub.d/30_os-prober	2016-06-26 07:28:29.000000000 +0300
@@ -51,8 +51,9 @@
     fi
     # TRANSLATORS: it refers on the OS residing on device %s
     onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+    MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
         cat << EOF
-menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")'  {
+menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' --hotkey=${MENUENTRY_HOTKEY} {
 EOF
 	save_default_entry | grub_add_tab
 	prepare_grub_to_access_device ${DEVICE} | grub_add_tab
@@ -140,8 +141,9 @@
     chain)
 
 	  onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
       cat << EOF
-menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class windows --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' {
+menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class windows --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' --hotkey=${MENUENTRY_HOTKEY} {
 EOF
       save_default_entry | grub_add_tab
       prepare_grub_to_access_device ${DEVICE} | grub_add_tab
@@ -228,8 +230,9 @@
 	fi
 
 	if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xy ]; then
+	MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
             cat << EOF
-menuentry '$(echo "$OS $onstr" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-simple-$boot_device_id' {
+menuentry '$(echo "$OS $onstr" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-simple-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {
 EOF
 	    save_default_entry | grub_add_tab
 	    printf '%s\n' "${prepare_boot_cache}"
@@ -248,8 +251,9 @@
 	    is_top_level=false
 	fi
 	title="${LLABEL} $onstr"
+	MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
         cat << EOF
-	menuentry '$(echo "$title" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-$LKERNEL-${recovery_params}-$boot_device_id' {
+	menuentry '$(echo "$title" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-$LKERNEL-${recovery_params}-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {
 EOF
 	save_default_entry | sed -e "s/^/$grub_tab$grub_tab/"
 	printf '%s\n' "${prepare_boot_cache}" | grub_add_tab
@@ -283,8 +287,9 @@
     ;;
     hurd)
       onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
       cat << EOF
-menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' {
+menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' --hotkey=${MENUENTRY_HOTKEY} {
 EOF
       save_default_entry | grub_add_tab
       prepare_grub_to_access_device ${DEVICE} | grub_add_tab
@@ -308,8 +313,9 @@
 EOF
     ;;
     minix)
+	  MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
 	  cat << EOF
-menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" {
+menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" --hotkey=${MENUENTRY_HOTKEY} {
 EOF
          save_default_entry | sed -e "s/^/\t/"
          prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/"
diff -ru /etc/grub.d/60_memtest86+ /home/dimich/vbox/grub/grub.d/60_memtest86+
--- /etc/grub.d/60_memtest86+	2015-12-15 17:36:21.000000000 +0200
+++ /home/dimich/vbox/grub/grub.d/60_memtest86+	2016-06-26 07:28:53.000000000 +0300
@@ -21,9 +21,10 @@
     _GRUB_MEMTEST_HINTS_STRING="$(${grub_probe} --target=hints_string ${MEMTEST86_IMAGE})"
     _GRUB_MEMTEST_FS_UUID="$(${grub_probe} --target=fs_uuid ${MEMTEST86_IMAGE})"
     _GRUB_MEMTEST_REL_PATH="$(make_system_path_relative_to_its_root ${MEMTEST86_IMAGE})"
+    MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
     cat << EOF
 if [ "\${grub_platform}" == "pc" ]; then
-    menuentry "Memory Tester (memtest86+)" ${CLASS} {
+    menuentry "Memory Tester (memtest86+)" ${CLASS} --hotkey=${MENUENTRY_HOTKEY} {
         search --fs-uuid --no-floppy --set=root ${_GRUB_MEMTEST_HINTS_STRING} ${_GRUB_MEMTEST_FS_UUID}
         linux16 ${_GRUB_MEMTEST_REL_PATH} ${GRUB_CMDLINE_MEMTEST86}
     }

And the last thing: program for AVR:

#include <avr/io.h>
#include <util/delay.h>

#define BAUDRATE 9600

static char uart_getc(void) {
    while ((UCSRA & (1<<RXC)) == 0);
    return UDR;
}

static void uart_putc(char c) {
    while ((UCSRA & (1<<UDRE)) == 0);
    UDR = c;
}

static void uart_init(void) {
    UBRRH = (F_CPU/(16L*BAUDRATE)-1) >> 8;
    UBRRL = (F_CPU/(16L*BAUDRATE)-1) & 0xFF;
    UCSRC = 3<<UCSZ0;
    UCSRB = (1<<RXEN) | (1<<TXEN);
}

static int get_switch_state(void) {
    return PINB & 0b00000011;
}

static int wait_for_str(const char *s) {
    const char *p = s;
    char c;

    while (*p != '\0') {
        c = uart_getc();

        if (c == *p) {
            ++p;
        } else {
            p = s;
            if (c == *p) {
                ++p;
            }
        }
    }

    return 0;
}

int main(void) {
    PORTB |= 0b00000011;

    uart_init();

    for (;;) {
        wait_for_str("GNU GRUB");

        _delay_ms(2000);

        switch (get_switch_state()) {
            case 2:
                uart_putc('1');
                break;

            case 1:
                uart_putc('2');
                break;

            default:
                break;
        }
    }

    return 0;
}

If PB0 only is connected to ground then grub boots first menu entry, if PB1 only is connected to ground then second menu entry is booted. Grub waits for user input in all other states of PB0/PB1.

Last edited by dimich (2016-07-06 13:59:21)

Offline

#10 2016-07-07 06:22:12

daviddavo
Member
Registered: 2015-12-30
Posts: 64

Re: Grub Scripting: Physichal Switch

dimich wrote:

Well, i had some free time and implemented something close to your design. For testing i used VirtualBox with host device serial port and ATtiny2313 as hardware.

First of all, setup grub to use serial port as console. This is my grub.conf:

GRUB_DEFAULT=0
GRUB_TIMEOUT=-1
GRUB_DISTRIBUTOR="Arch"
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX=""

# Preload both GPT and MBR modules so that they are not missed
GRUB_PRELOAD_MODULES="part_gpt part_msdos"

# Uncomment to enable Hidden Menu, and optionally hide the timeout count
#GRUB_HIDDEN_TIMEOUT=5
#GRUB_HIDDEN_TIMEOUT_QUIET=true

# Uncomment to use basic console

GRUB_SERIAL_COMMAND="serial --speed=9600 --unit=0 --word=8 --parity=no --stop=1"
GRUB_TERMINAL="console serial"

GRUB_VIDEO_BACKEND=vga

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=auto

# Uncomment to allow the kernel use the same resolution used by grub
#GRUB_GFXPAYLOAD_LINUX=keep

# Uncomment if you want GRUB to pass to the Linux kernel the old parameter 
# format "root=/dev/xxx" instead of "root=/dev/disk/by-uuid/xxx" 
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY=true

# Uncomment and set to the desired menu colors.  Used by normal and wallpaper 
# modes only.  Entries specified as foreground/background.
#GRUB_COLOR_NORMAL="light-blue/black"
#GRUB_COLOR_HIGHLIGHT="light-cyan/blue"

# Uncomment one of them for the gfx desired, a image background or a gfxtheme
#GRUB_BACKGROUND="/path/to/wallpaper"
#GRUB_THEME="/path/to/gfxtheme"

# Uncomment to get a beep at GRUB start
#GRUB_INIT_TUNE="480 440 1"

#GRUB_SAVEDEFAULT="true"

GRUB_DISABLE_SUBMENU=y

Then, here is patch for /etc/grub.d directory to generate sequentional hotkeys for each menu entry:

diff -ru /etc/grub.d/10_linux /home/dimich/vbox/grub/grub.d/10_linux
--- /etc/grub.d/10_linux	2015-12-15 17:36:16.000000000 +0200
+++ /home/dimich/vbox/grub/grub.d/10_linux	2016-06-26 07:27:09.000000000 +0300
@@ -98,9 +98,11 @@
 	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
 	  grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")"
       fi
-      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
+      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {" | sed "s/^/$submenu_indentation/"
   else
-      echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
+      echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {" | sed "s/^/$submenu_indentation/"
   fi      
   if [ x$type != xrecovery ] ; then
       save_default_entry | grub_add_tab
diff -ru /etc/grub.d/20_linux_xen /home/dimich/vbox/grub/grub.d/20_linux_xen
--- /etc/grub.d/20_linux_xen	2015-12-15 17:36:16.000000000 +0200
+++ /home/dimich/vbox/grub/grub.d/20_linux_xen	2016-06-26 07:27:33.000000000 +0300
@@ -98,10 +98,12 @@
          title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
          grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")"
       fi
-      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
+      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-$version-$type-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {" | sed "s/^/$submenu_indentation/"
   else
       title="$(gettext_printf "%s, with Xen hypervisor" "${os}")"
-      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
+      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-simple-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {" | sed "s/^/$submenu_indentation/"
   fi
   if [ x$type != xrecovery ] ; then
       save_default_entry | grub_add_tab | sed "s/^/$submenu_indentation/"
diff -ru /etc/grub.d/30_os-prober /home/dimich/vbox/grub/grub.d/30_os-prober
--- /etc/grub.d/30_os-prober	2015-12-15 17:36:16.000000000 +0200
+++ /home/dimich/vbox/grub/grub.d/30_os-prober	2016-06-26 07:28:29.000000000 +0300
@@ -51,8 +51,9 @@
     fi
     # TRANSLATORS: it refers on the OS residing on device %s
     onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+    MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
         cat << EOF
-menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")'  {
+menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' --hotkey=${MENUENTRY_HOTKEY} {
 EOF
 	save_default_entry | grub_add_tab
 	prepare_grub_to_access_device ${DEVICE} | grub_add_tab
@@ -140,8 +141,9 @@
     chain)
 
 	  onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
       cat << EOF
-menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class windows --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' {
+menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class windows --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' --hotkey=${MENUENTRY_HOTKEY} {
 EOF
       save_default_entry | grub_add_tab
       prepare_grub_to_access_device ${DEVICE} | grub_add_tab
@@ -228,8 +230,9 @@
 	fi
 
 	if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xy ]; then
+	MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
             cat << EOF
-menuentry '$(echo "$OS $onstr" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-simple-$boot_device_id' {
+menuentry '$(echo "$OS $onstr" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-simple-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {
 EOF
 	    save_default_entry | grub_add_tab
 	    printf '%s\n' "${prepare_boot_cache}"
@@ -248,8 +251,9 @@
 	    is_top_level=false
 	fi
 	title="${LLABEL} $onstr"
+	MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
         cat << EOF
-	menuentry '$(echo "$title" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-$LKERNEL-${recovery_params}-$boot_device_id' {
+	menuentry '$(echo "$title" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-$LKERNEL-${recovery_params}-$boot_device_id' --hotkey=${MENUENTRY_HOTKEY} {
 EOF
 	save_default_entry | sed -e "s/^/$grub_tab$grub_tab/"
 	printf '%s\n' "${prepare_boot_cache}" | grub_add_tab
@@ -283,8 +287,9 @@
     ;;
     hurd)
       onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+      MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
       cat << EOF
-menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' {
+menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' --hotkey=${MENUENTRY_HOTKEY} {
 EOF
       save_default_entry | grub_add_tab
       prepare_grub_to_access_device ${DEVICE} | grub_add_tab
@@ -308,8 +313,9 @@
 EOF
     ;;
     minix)
+	  MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
 	  cat << EOF
-menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" {
+menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" --hotkey=${MENUENTRY_HOTKEY} {
 EOF
          save_default_entry | sed -e "s/^/\t/"
          prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/"
diff -ru /etc/grub.d/60_memtest86+ /home/dimich/vbox/grub/grub.d/60_memtest86+
--- /etc/grub.d/60_memtest86+	2015-12-15 17:36:21.000000000 +0200
+++ /home/dimich/vbox/grub/grub.d/60_memtest86+	2016-06-26 07:28:53.000000000 +0300
@@ -21,9 +21,10 @@
     _GRUB_MEMTEST_HINTS_STRING="$(${grub_probe} --target=hints_string ${MEMTEST86_IMAGE})"
     _GRUB_MEMTEST_FS_UUID="$(${grub_probe} --target=fs_uuid ${MEMTEST86_IMAGE})"
     _GRUB_MEMTEST_REL_PATH="$(make_system_path_relative_to_its_root ${MEMTEST86_IMAGE})"
+    MENUENTRY_HOTKEY=$(expr ${MENUENTRY_HOTKEY} + 1)
     cat << EOF
 if [ "\${grub_platform}" == "pc" ]; then
-    menuentry "Memory Tester (memtest86+)" ${CLASS} {
+    menuentry "Memory Tester (memtest86+)" ${CLASS} --hotkey=${MENUENTRY_HOTKEY} {
         search --fs-uuid --no-floppy --set=root ${_GRUB_MEMTEST_HINTS_STRING} ${_GRUB_MEMTEST_FS_UUID}
         linux16 ${_GRUB_MEMTEST_REL_PATH} ${GRUB_CMDLINE_MEMTEST86}
     }

And the last thing: program for AVR:

#include <avr/io.h>
#include <util/delay.h>

#define BAUDRATE 9600

static char uart_getc(void) {
    while ((UCSRA & (1<<RXC)) == 0);
    return UDR;
}

static void uart_putc(char c) {
    while ((UCSRA & (1<<UDRE)) == 0);
    UDR = c;
}

static void uart_init(void) {
    UBRRH = (F_CPU/(16L*BAUDRATE)-1) >> 8;
    UBRRL = (F_CPU/(16L*BAUDRATE)-1) & 0xFF;
    UCSRC = 3<<UCSZ0;
    UCSRB = (1<<RXEN) | (1<<TXEN);
}

static int get_switch_state(void) {
    return PINB & 0b00000011;
}

static int wait_for_str(const char *s) {
    const char *p = s;
    char c;

    while (*p != '\0') {
        c = uart_getc();

        if (c == *p) {
            ++p;
        } else {
            p = s;
            if (c == *p) {
                ++p;
            }
        }
    }

    return 0;
}

int main(void) {
    PORTB |= 0b00000011;

    uart_init();

    for (;;) {
        wait_for_str("GNU GRUB");

        _delay_ms(2000);

        switch (get_switch_state()) {
            case 2:
                uart_putc('1');
                break;

            case 1:
                uart_putc('2');
                break;

            default:
                break;
        }
    }

    return 0;
}

If PB0 only is connected to ground then grub boots first menu entry, if PB1 only is connected to ground then second menu entry is booted. Grub waits for user input in all other states of PB0/PB1.

Thanks, I'm not programmer so I was strugglin a bit with the scripting.

Offline

#11 2016-07-13 12:36:11

Purgator
Member
Registered: 2016-03-02
Posts: 102

Re: Grub Scripting: Physichal Switch

I did something but a little bit more tricky and less expert.
I used no programming, no arduino, nothing. Only a physical switch and a usb key.

I have a dual boot, Windows on a ssd, Linux on a hdd. The boot priority is 'USB' > 'SSD' > 'Other'.
On the ssd there is the windows boot.
On the usb key there is grub installed, with first choice on Linux, and timeout set to 0. This usb key is connected to the switch and the motherboard.

Result : If i turn on the switch it boot on Linux, if i turn off the switch it boot Windows.

You could imagine something with an other usb key and a 3 states switch to do exactly what you want.

Offline

#12 2016-07-13 13:32:39

dimich
Member
From: Kharkiv, Ukraine
Registered: 2009-11-03
Posts: 242

Re: Grub Scripting: Physichal Switch

All genius things are simple smile

Offline

Board footer

Powered by FluxBB