#!/usr/bin/env python3 import sys import os import time import re from select import select from glob import glob from subprocess import check_output, STDOUT, PIPE, Popen, TimeoutExpired IMAGES_HOST = 'l_samenv@linse-c' IMAGES_DIR = 'boxes/rpi_images' IMAGES_PAT = '*.lz4' extdisks = {} def prt(text): print(time.strftime('%H:%M:%S'), text) def cmd(command, verbose=False): if verbose: print(f'> {command}') return check_output(command.split(), stderr=STDOUT).decode('latin-1') def get_disks(): return [line for line in cmd('lsblk -d').split('\n') if line] def rpiboot(): lines = [] with Popen(['sudo', './rpiboot', '-d', 'mass-storage-gadget64'], stdout=PIPE) as p: tmo = 1 t = 0 while select([p.stdout], [], [], tmo)[0]: rawline = p.stdout.readline() if not rawline: return tmo != 1 line = rawline.decode('latin-1').strip() print(line) if lines is None: pass # print(line) elif 'Waiting' in line: tmo = 10 lines.append(line) t = time.time() elif tmo == 1: lines.append(line) else: print('\n'.join(lines)) print(line) lines = None else: p.terminate() return False def list_external(): print('--- external disks:') for disk, info in extdisks.items(): print(disk, info) rescue = """ Remark: not all cables might work. Example on Markus Mac: - does not work: black USB C to USB C cable - works: white USB A to USB C cable plugged into docking station. Please unpower the box with compute module, start this script again and put power immediately.""" def wait_disks(prevset, delay): for i in range(int(delay)): disks = get_disks() diskset = set(disks) if diskset != prevset: print('\n'.join(disks)) if i: print('') return diskset - prevset print('.', end='') time.sleep(1) return None def find_raspi(kind='emmc'): input('make sure device is not connected [confirm]') prevset = set(get_disks()) input('now connect [confirm]') disks = wait_disks(prevset, 5) if not disks: print('can not yet detect disk, try to run rpiboot') print('if is blocked at "Waiting for BCM...", turn off and on power of target rpi') # cmd('sudo ./rpiboot -d mass-storage-gadget64') rpiboot() disks = wait_disks(prevset, 15) if not disks: raise RuntimeError('raspi disk does not appear') return disks def write_image(kind): proposed = [v.split()[0] for v in find_raspi(kind)] list_external() if len(proposed) == 1: dev = proposed[0] elif len(proposed) > 1: if kind == 'emmc': print('several potential devices:', proposed) return dev = input('select device to write to {" ".join(proposed)}: ') else: print('not found') return images = check_output(['sudo', '-u', 'l_samenv', 'ssh', IMAGES_HOST, f'cd {IMAGES_DIR} ; ls {IMAGES_PAT}']).decode('latin-1').split('\n') for file in sorted(images): print(file) print('') image = input(f'select image to write to {dev} [{file}]: ') or file prt(f'unmount {dev} ...') print('you may be prompted for your account password for sudo') os.system(f'sudo umount /dev/{dev}') print('') prt('get, uncompress and write... (takes about 15 min)') os.system(f'ssh {IMAGES_HOST} "dd if={IMAGES_DIR}/{image} bs=512k" | lz4 -d | sudo dd of=/dev/{dev} bs=512k') prt('unmount bootfs') for _ in range(3): if os.path.exists('/Volumes/bootfs'): prt('unmount bootfs') os.system('sudo umount bootfs') break time.sleep(1.0) prt('done') os.system(f'sudo umount /dev/{dev}') if len(sys.argv) == 2: write_image(sys.argv[1]) else: print(""" Usage: > write_to emmc # write to compute module using PoE board" > write_to sd # write to sd card """)