diff options
-rw-r--r-- | ob-visa.el | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/ob-visa.el b/ob-visa.el new file mode 100644 index 0000000..584d969 --- /dev/null +++ b/ob-visa.el @@ -0,0 +1,135 @@ +;;; ob-visa.el --- Babel Functions for VISA + +;; Author: Ferdinand Pieper <mail@pie.tf> +;; Keywords: literate programming, reproducible research + +;; Copyright (c) 2022 Ferdinand Pieper + +;; License: GPL v3, or any later version +;; +;; This file is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; This file is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Org-Babel support for communicating with Virtual Instrument +;; Software Architecture (VISA) resources. Currently optimized to +;; run on Windows under WSL. + +;;; Requirements: + +;; - pyvisa-shell + +;;; Code: + +(require 'ob) + +(defcustom org-babel-visa-command "pyvisa-shell.exe" + "Name of the command to pyvisa-shell.") + +(defvar org-babel-visa-delay 0.1) + +(defun org-babel-visa-initiate-session (&optional session _params) + "Initiate a pyvisa-shell sesion." + (let* ((process-connection-type nil) ;; use communication per pipe + (sessionname (if (or (not session) (string= session "none")) + "VISA" session)) + (session (make-comint sessionname org-babel-visa-command))) + session)) + +;; This is a copy of org-babel-comint-with-output only with a small +;; delay added before output is expected. Should find a way to clean +;; this up sometime.. +(defmacro org-babel-visa-comint-with-output (meta &rest body) + "Evaluate BODY in BUFFER and return process output. +Will wait until EOE-INDICATOR appears in the output, then return +all process output. If REMOVE-ECHO and FULL-BODY are present and +non-nil, then strip echo'd body from the returned output. META +should be a list containing the following where the last two +elements are optional. + + (BUFFER EOE-INDICATOR REMOVE-ECHO FULL-BODY) + +This macro ensures that the filter is removed in case of an error +or user `keyboard-quit' during execution of body." + (declare (indent 1) (debug (sexp body))) + (let ((buffer (nth 0 meta)) + (eoe-indicator (nth 1 meta)) + (remove-echo (nth 2 meta)) + (full-body (nth 3 meta))) + `(org-babel-comint-in-buffer ,buffer + (let* ((string-buffer "") + (comint-output-filter-functions + (cons (lambda (text) (setq string-buffer (concat string-buffer text))) + comint-output-filter-functions)) + dangling-text) + ;; got located, and save dangling text + (goto-char (process-mark (get-buffer-process (current-buffer)))) + (let ((start (point)) + (end (point-max))) + (setq dangling-text (buffer-substring start end)) + (delete-region start end)) + ;; pass FULL-BODY to process + ,@body + ;; wait for end-of-evaluation indicator + (sit-for org-babel-visa-delay) + (while (progn + (goto-char comint-last-input-end) + (not (save-excursion + (and (re-search-forward + (regexp-quote ,eoe-indicator) nil t) + (re-search-forward + comint-prompt-regexp nil t))))) + (accept-process-output (get-buffer-process (current-buffer)))) + ;; replace cut dangling text + (goto-char (process-mark (get-buffer-process (current-buffer)))) + (insert dangling-text) + + ;; remove echo'd FULL-BODY from input + (when (and ,remove-echo ,full-body + (string-match + (replace-regexp-in-string + "\n" "[\r\n]+" (regexp-quote (or ,full-body ""))) + string-buffer)) + (setq string-buffer (substring string-buffer (match-end 0)))) + (split-string string-buffer comint-prompt-regexp))))) + + +(defun org-babel-execute:visa (body params) + "Execute a block of VISA code with Babel. +This function is called by `org-babel-execute-src-block'." + (let ((result-params (cdr (assq :result-params params))) + (result-type (cdr (assq :result-type params))) + (session (org-babel-visa-initiate-session + (cdr (assq :session params)))) + (comint-prompt-regexp "^(visa\\|open) ") + (eoe-string "org-babel-eoe") + (mapconcat + #'identity + (butlast + (cdr + (split-string + (mapconcat + #'org-trim + (org-babel-visa-comint-with-output + (session "(visa) *** Unknown syntax: org-babel-eoe" t) + (mapc (lambda (line) + (insert (org-babel-chomp line)) (comint-send-input nil t)) + (list body + eoe-string)) + ) "\n") "[\r\n]+")) 2) + "\n"))) + + +(provide 'ob-visa) +;;; ob-visa.el ends here |