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
M-x u-boot-toggle-stop-autoboot-mode
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.