Search code examples
pythonpyserialu-bootimx6

Cannot interrupt uboot "Hit any key to stop autoboot:" with pySerial


I have a python script that is supposed to run a Linux update on an iMX6 device. I can reboot Linux via serial connection. I can see the device rebooting (console output is transferred). However, when I encounter the line "Hit any key to stop autoboot:" in the serial output, a write command seems to get ignored.

import time
import serial


def reboot_and_update(port, baudrate=115200):
    # Open the serial connection
    ser = serial.Serial(port, baudrate, timeout=1,
                        bytesize=serial.EIGHTBITS, xonxoff=True,
                        parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE)
    print(f"Connected to {port} at {baudrate} baud. Output:")
    ser.write(b"reboot\r")  # Send the command
    try:
        while True:
            # Read a line from the serial port
            line = ser.readline().decode('utf-8').strip()
            if line:
                # Print the received line to the console
                print(f"{line}")

                # Check for the specific line to trigger actions
                if "Hit any key to stop autoboot:" in line:
                    print("Interrupt autoboot...")
                    time.sleep(0.1)
                    ser.write(b"345ju\r")
                    time.sleep(1)
                    ser.write(b"run install_linux_fw_sd\r")  # Send the command

                # Check for the login prompt and wait 3 seconds
                elif "ccimx6ulsbc login:" in line:
                    print("Login prompt detected. Waiting for 3 seconds.")
                    time.sleep(3)

                    # If nothing else happens, close the connection
                    additional_line = ser.readline().decode('utf-8').strip()
                    if not additional_line:
                        break
                    else:
                        # Print any additional lines received during the wait period
                        print(f"Received after login prompt: {additional_line}")
            else:
                time.sleep(0.1)  # Small delay to prevent busy waiting

    finally:
        ser.close()
        print("Finished")

The output I receive:

  (py312) C:\...>python serialconn.py
Connected to COM5 at 115200 baud. Output:
reboot
Broadcast message from root@ccimx6ulsbc (ttymxc4) (Fri Mar  9 14:41:36 2018):
The system is going down for reboot NOW!
INIT: Switching to runlevel: 6
INIT: Sending processes configured via /etc/inittab the TERM signal
root@ccimx6ulsbc:~# Stopping syslogd/klogd: stopped syslogd (pid 639)
stopped klogd (pid 642)
done
Stopping Dropbear SSH server: stopped /usr/sbin/dropbear (pid 661)
dropbear.
Stopping bluetooth: bluetoothd.
Stopping Busybox ACPI daemon: done
stopping Busybox HTTP Daemon: httpd... no httpd found; none killed
Stopping Busybox NTP client/server: done
Stopping system message bus: dbus.
ModemManager[739]: <warn>  could not acquire the 'org.freedesktop.ModemManager1' service name
ModemManager[739]: <info>  ModemManager is shut down
Stopping HOSTAP Daemon: hostapd.
Stopping tcf-agent: OK
ALSA: Storing mixer settings...
Unmounting remote filesystems...
Deconfiguring network interfaces... done.
Stopping NetworkManager: done
Stopping vsftpd server: done
Sending all processes the TERM signal...
Sending all processes the KILL signal...
Deactivating swap...
Unmounting local filesystems...
Rebooting...
U-Boot dub-2020.04-r7.1+gaf77921f51 (Jan 30 2024 - 12:53:20 +0000)
CPU:   i.MX6UL rev1.2 528 MHz (running at 396 MHz)
CPU:   Industrial temperature grade (-40C to 105C) at 68C
Reset cause: POR
DRAM:  1 GiB
MCA:   HW_VER=1  FW_VER=1.14
PMIC:  PFUZE3000 DEV_ID=0x30 REV_ID=0x11
NAND:  1024 MiB
MMC:   FSL_SDHC: 0
In:    serial
Out:   serial
Err:   serial
Model: Digi International ConnectCore 6UL SBC.
ConnectCore 6UL SOM variant 0x04: Industrial Ultralite 528MHz, 1GB NAND, 1GB DDR3, -40/+85C, Wireless, Bluetooth
Board version undefined, ID undefined
Boot device:  NAND
Net:   FEC0 [PRIME]
Fastboot: Normal
Normal Boot
Hit any key to stop autoboot:  0
Interrupt autoboot...
ubi0: attaching mtd4
ubi0: scanning is finished
ubi0: attached mtd4 (name "linux", size 24 MiB)
ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
ubi0: VID header offset: 2048 (aligned 2048), data offset: 4096
ubi0: good PEBs: 192, bad PEBs: 0, corrupted PEBs: 0
ubi0: user volume: 1, internal volumes: 1, max. volumes count: 128
ubi0: max/mean erase counter: 15/11, WL threshold: 4096, image sequence number: 0
ubi0: available PEBs: 0, total reserved PEBs: 192, PEBs reserved for bad PEB handling: 8
Loading file 'boot.scr' to addr 0x80800000...
Done
## Executing script at 80800000
## Loading kernel: zImage-ccimx6ulsbc.bin

...

So, seems like any input during the boot is somehow ignored.

I have tried to do the same thing with PuTTY, here it works. I have copied all the connection settings to my python script (but even with xonxoff disabled, it didn't work).

Can anybody help me here?


Solution

    • U-Boot does not support the Xon/Xoff protocol. Please, use xonxoff=False.
    • As user Risto mentioned you should not use readline() but read single bytes.
    • You should use the U-Boot command line prompt to know when to write the U-Boot command.
        line = b''
        uboot = 0
        prompt = b'=>'
        try:
            while True:
                # Read a line from the serial port
                char = ser.read()
                if char == b'':
                    continue
                if char[0] == 13:
                    # Print the received line to the console
                    print(f"{line.decode('utf-8').strip()}")
                    line = b''
                line += char
                # Check for the specific line to trigger actions
                if uboot == 0 and b'Hit any key to stop autoboot:' in line:
                    print("Interrupt autoboot...")
                    ser.write(b'\r')
                    uboot = 1
                elif uboot == 1 and prompt in line:
                    ser.write(b"run install_linux_fw_sd\r")  # Send the command
                    uboot = 2
                # Check for the login prompt and wait 3 seconds
                elif uboot == 2 and b'ccimx6ulsbc login:' in line:
                    print("Login prompt detected. Waiting for 3 seconds.")