mirror of
https://gitlab.com/eql/lqml.git
synced 2025-12-15 14:51:14 -08:00
example 'cl-repl': simple edit mode for uLisp (Arduino) connected to USB
This commit is contained in:
parent
9aba49287c
commit
ff27767747
10 changed files with 186 additions and 12 deletions
|
|
@ -23,5 +23,7 @@
|
|||
(:file "lisp/swank-quicklisp")
|
||||
#+mobile
|
||||
(:file "lisp/upload-download")
|
||||
#+linux
|
||||
(:file "lisp/usb-ulisp")
|
||||
(:file "lisp/main")))
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@
|
|||
#include <QNetworkInterface>
|
||||
#include <QHostAddress>
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#include "usb/usb.h"
|
||||
#endif
|
||||
|
||||
#ifdef PLUGIN
|
||||
#include <ecl_fun_plugin.h>
|
||||
#else
|
||||
|
|
@ -335,4 +339,29 @@ QVariant QT::localIp() {
|
|||
return QVariant();
|
||||
}
|
||||
|
||||
// USB
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
QVariant QT::connectUsb() {
|
||||
if (usb == nullptr) {
|
||||
usb = new USB();
|
||||
if (usb->connect2()) {
|
||||
connect(usb, &USB::receivingDone,
|
||||
[](const QByteArray& data) {
|
||||
ecl_fun("ed:received-from-ulisp", QString::fromUtf8(data));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant QT::sendToUlisp(const QVariant &vData) {
|
||||
if (usb != nullptr) {
|
||||
usb->write2(vData.toByteArray());
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
extern "C" { LIB_EXPORT QObject* ini(); }
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
class USB;
|
||||
#endif
|
||||
|
||||
class SyntaxHighlighter : public QSyntaxHighlighter {
|
||||
Q_OBJECT
|
||||
friend class QT;
|
||||
|
|
@ -104,7 +108,15 @@ public:
|
|||
Q_INVOKABLE QVariant textDocument (const QVariant&);
|
||||
|
||||
// etc
|
||||
Q_INVOKABLE QVariant localIp ();
|
||||
Q_INVOKABLE QVariant localIp();
|
||||
|
||||
// USB
|
||||
#ifdef Q_OS_LINUX
|
||||
Q_INVOKABLE QVariant connectUsb ();
|
||||
Q_INVOKABLE QVariant sendToUlisp (const QVariant&);
|
||||
|
||||
USB* usb = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ HEADERS += qt.h
|
|||
SOURCES += qt.cpp
|
||||
|
||||
linux {
|
||||
QT += serialport
|
||||
HEADERS += usb/usb.h
|
||||
SOURCES += usb/usb.cpp
|
||||
LIBS += -L../../../platforms/linux/lib
|
||||
}
|
||||
|
||||
|
|
|
|||
82
examples/cl-repl/cpp/usb/usb.cpp
Normal file
82
examples/cl-repl/cpp/usb/usb.cpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#include "usb.h"
|
||||
#include <QSerialPortInfo>
|
||||
#include <QTimer>
|
||||
#include <QtDebug>
|
||||
|
||||
USB::USB() {
|
||||
connect(this, &QSerialPort::readyRead, this, &USB::read2);
|
||||
connect(this, &QSerialPort::errorOccurred,
|
||||
[](QSerialPort::SerialPortError error) {
|
||||
if (error != QSerialPort::NoError) {
|
||||
qDebug() << "USB error:" << error;
|
||||
}
|
||||
});
|
||||
setBaudRate(Baud9600);
|
||||
|
||||
timer.setSingleShot(true);
|
||||
connect(&timer, &QTimer::timeout, this, &USB::done);
|
||||
}
|
||||
|
||||
bool USB::connect2() {
|
||||
if (isOpen()) {
|
||||
setReady(portName());
|
||||
qDebug() << "USB already open:" << portName();
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto infos = QSerialPortInfo::availablePorts();
|
||||
const QStringList supported = { "Arduino" }; // set here micro controller name
|
||||
for (auto info : infos) {
|
||||
QString name(info.manufacturer() + " | " + info.description());
|
||||
QString port(info.portName());
|
||||
if (port.startsWith("tty") &&
|
||||
(port.contains("ACM", Qt::CaseInsensitive) || // Linux
|
||||
port.contains("USB", Qt::CaseInsensitive))) { // macOS
|
||||
for (auto s : supported) {
|
||||
if (name.contains(s, Qt::CaseInsensitive)) {
|
||||
setPortName(info.portName());
|
||||
qDebug() << "USB:" << port
|
||||
<< "VID" << info.vendorIdentifier()
|
||||
<< "PID" << info.productIdentifier()
|
||||
<< "name" << name;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (!open(QIODevice::ReadWrite)) {
|
||||
qDebug() << "USB: unable to open port" << portName();
|
||||
return false;
|
||||
} else {
|
||||
ready = true;
|
||||
setReady(portName());
|
||||
qDebug() << "USB open";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void USB::disconnect() {
|
||||
close();
|
||||
qDebug() << "USB closed";
|
||||
}
|
||||
|
||||
void USB::write2(const QByteArray& data) {
|
||||
if (ready) {
|
||||
write(data);
|
||||
} else {
|
||||
qDebug() << "USB not ready: write()";
|
||||
}
|
||||
}
|
||||
|
||||
void USB::read2() {
|
||||
packets << readAll();
|
||||
timer.start(250); // assume receiving done after pause
|
||||
}
|
||||
|
||||
void USB::done() {
|
||||
Q_EMIT receivingDone(packets.join());
|
||||
packets.clear();
|
||||
}
|
||||
|
||||
29
examples/cl-repl/cpp/usb/usb.h
Normal file
29
examples/cl-repl/cpp/usb/usb.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <QSerialPort>
|
||||
#include <QTimer>
|
||||
|
||||
class USB : public QSerialPort {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
USB();
|
||||
|
||||
bool ready = false;
|
||||
QTimer timer;
|
||||
QByteArrayList packets;
|
||||
|
||||
void received(const QByteArray&);
|
||||
|
||||
public Q_SLOTS:
|
||||
bool connect2();
|
||||
void disconnect();
|
||||
void read2();
|
||||
void write2(const QByteArray&);
|
||||
void done();
|
||||
|
||||
Q_SIGNALS:
|
||||
void setReady(const QString&);
|
||||
void receivingDone(const QByteArray&);
|
||||
};
|
||||
|
||||
|
|
@ -655,6 +655,9 @@
|
|||
(defvar *ex-cmd* nil)
|
||||
|
||||
(defun feed-top-level (text)
|
||||
(if #+linux *ulisp-mode* #-linux nil
|
||||
#+linux (send-to-ulisp text) #-linux nil
|
||||
(progn
|
||||
(when eval:*eval-thread*
|
||||
(if (mp:process-active-p eval:*eval-thread*)
|
||||
(progn
|
||||
|
|
@ -662,7 +665,7 @@
|
|||
(eval* ":k"))
|
||||
(setf eval:*eval-thread* nil)))
|
||||
(unless eval:*eval-thread*
|
||||
(eval:feed-top-level text)))
|
||||
(eval:feed-top-level text)))))
|
||||
|
||||
(defun eval* (text)
|
||||
(if (find #\Newline text)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
(:nicknames :ed)
|
||||
(:use :cl :qml)
|
||||
(:export
|
||||
;; editor
|
||||
#:*file*
|
||||
#:*plain-text-search*
|
||||
#:append-output
|
||||
|
|
@ -14,5 +15,9 @@
|
|||
#:reload-qml
|
||||
#:save-changes
|
||||
#:set-font
|
||||
#:start))
|
||||
#:start
|
||||
;; uLisp mode (e.g. Arduino)
|
||||
#+linux #:*ulisp-mode*
|
||||
#+linux #:send-to-ulisp
|
||||
#+linux #:received-from-ulisp))
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,10 @@
|
|||
#:set-format
|
||||
#:set-pattern
|
||||
#:text
|
||||
#:text-document))
|
||||
#:text-document
|
||||
;; ulisp (e.g. Arduino)
|
||||
#+linux #:connect-usb
|
||||
#+linux #:send-to-ulisp))
|
||||
|
||||
(in-package :qt)
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,12 @@
|
|||
(defun option (name)
|
||||
(find name (ext:command-args) :test 'search))
|
||||
|
||||
;;; use app to send code to e.g. Arduino uLisp connected to USB
|
||||
|
||||
#+linux
|
||||
(when (option "-ulisp")
|
||||
(setf ed:*ulisp-mode* t))
|
||||
|
||||
;;; trivial auto reload of all QML files after saving any change
|
||||
|
||||
(when (option "-auto")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue