At work I make heavy use of the GNU Emacs mode serial-term to interface with various target boards. The boards all run U-Boot with a 5 second autoboot timeout. I often want to power-cycle a group of boards, then stop them all at the U-Boot prompt before they autoboot. It’s a race to C-x b to all the different buffers in time. I used to frequently miss some buffers; the boards would start booting, and I would have to wait to issue a software reset. It became annoying enough that I decided to create an autostop extension.
Luckily, serial-term is written in Emacs Lisp, so I can extend it to do exactly what I want. In this case I want a global “U-Boot autoboot-stop” mode. Here’s what I came up with:
First, a variable to to keep track of whether the mode is enabled or not.
;; Detect U-Boot autoboot prompt and stop it. (defvar u-boot-stop-autoboot-mode nil "Non-nil if term-mode should prevent U-Boot from autobooting. Use the function u-boot-toggle-stop-autoboot-mode to toggle.")
Then the advice itself. It jacks into the term-emulate-terminal process filter to detect the U-Boot autoboot prompt, then sends a newline in response.
(defadvice term-emulate-terminal (before u-boot-maybe-stop-autoboot activate disable) (with-current-buffer (process-buffer proc) (when (string-match "Hit any key to stop autoboot:" str) (message "U-Boot autoboot stopped in buffer %s" (buffer-name (current-buffer))) (term-send-raw-string "\n"))))
And finally a function to toggle the advice on and off.
(defun u-boot-toggle-stop-autoboot-mode () "Toggle whether or not term-mode should interrupt U-Boot autoboot." (interactive) (if u-boot-stop-autoboot-mode (progn (ad-disable-advice 'term-emulate-terminal 'before 'u-boot-maybe-stop-autoboot) (ad-update 'term-emulate-terminal) (setq u-boot-stop-autoboot-mode nil) (message "U-Boot autoboot will not be interrupted")) (progn (ad-enable-advice 'term-emulate-terminal 'before 'u-boot-maybe-stop-autoboot) (ad-activate 'term-emulate-terminal) (setq u-boot-stop-autoboot-mode t) (message "U-Boot autoboot will be interrupted"))))
Now I can enable the mode globally with
and be sure that all the boards will be interrupted in time.
It’s worth noting that developing this feature was relatively straightforward. I never left my Emacs session; I developed the code right in
~/.emacs.d/init.el, tested it quickly in a terminal buffer, and confirmed its operation in my existing serial-term buffers. Most of the development time was spent reading the Info documentation for Advice, to figure out how to enable and disable a specific piece of advice.