Пишем плагин для Arduino IDE

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Доброго дня, коллеги!

Я давно хотел написать что-нибудь про нашу IDE. В реальности очень любопытную конструкцию на JAVA.

В настоящей теме я закину "фидер" на леща. В том смысле, что приведу некий скелет плагина для IDE. Посмотрю "придет ли к берегу рыба". То есть вообще интересно это или народ быстро бросает IDE, переходя на более совершенные среды разработки?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Продолжу. Разработчики IDE оставили общий интерфейс создания собственных плагинов к среде. Пример лежит в ./tools/Mangler вместе с устаревшим сценарием Линукс shell  для компиляции и сборки в jar.

При наличии минимальных знаний о JAVA можно поправить сценарий, переделать под Винду, если кому надо, и собрать Манглер - смешную игрушку перемешивающую выделенный фрагмент в открытом скетче.

Я пока нарочно не стану ничего писать о подробностях.

Вот так под свежую среду переписывается make.sh в Линуксе:

#!/bin/sh

PDE=`find ../.. -name pde.jar`

javac -target 1.8 -source 1.8 \
  -cp "../../lib/arduino-core.jar:$PDE" \
  -d bin \
  src/Mangler.java

mkdir tool
cd bin && zip -r ../tool/mangler.jar * && cd ..

Виндоус версия - читателю, если кто заинтересуется.

После отработки мейк файла получается каталог ./tools/Mangler/tool, в котором лежит jar файл с плагином.

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Пара слов о том, как писать плагины. Образец - манглер и плагины для записи файловых систем в ESP6266 и ESP32. Желательно использовать jar библиотеки уже имеющиеся в Arduino IDE. Во избежании глюков и несовместимостей. Наша ИДЕ вообще довольно любительская среда с большим количеством слабо написанного кода, хотя строк в исходнике на джаве - много тысяч.

Но следует признать, что ошибки понемногу удаляют и библиотеки есть почти на всё.

Главное, что нас может интересовать - библиотка работы с COM-портом -JSSC - она есть, конечно!

Ниже приведу не комментированный, совершенно сырой код для демонстрации возможностей плагинов.

Я писал "рыбу" для работы с ком-портом. Например можно придумать графики, стрелочные индикаторы, имитацию семисегментника или 12864. Да что угодно. Вывести два, три, четыре компорта, если нужно и так далее.

Для этого нужно научиться делать три вещи:

1. выбирать порт;

2. принимать данные;

3. Рисовать интерактивно в канве.

В приведенном коде есть все три компоненты. Повторю - нет комментариев. Код запускался на Линуксе и Вин10-64 (ВиртБокс). На Винде не собирал, а просто jar копировал из Линукса. Есть какие-то мелкие глюки в Винде, анализировать которые пока не интересно. Возможно особенности java-swing/awt на винде.

Сейчас меня интересует на вылизывание кода, тут не форум по java, а наличие интереса.

Будет интерес - продолжу. Заодно и виндовые темы разберу, или на форуме виндусятник найдется для помощи. Я все таки совершенно линуксовый человек. Винда для меня чужой и пугающий мир! ;)))

------------------------------------

Фсё! Наболтался, теперь код и мейк фал для сборки. От мейк файла манглера отличается только добавкой поиска jssc библиотеки.

код

package com.wlad.test001;


import jssc.SerialPort;
import jssc.SerialPortException;
import jssc.SerialPortList;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.BevelBorder;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.Arrays;

import static java.awt.Color.RED;
import static java.awt.Color.WHITE;

import static javax.swing.WindowConstants.EXIT_ON_CLOSE;


import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.JOptionPane;

import processing.app.Editor;
import processing.app.tools.Tool;



public class WladTest implements Tool {
  Editor editor;


  public void init(Editor editor) {
    this.editor = editor;
  }


  public String getMenuTitle() {
    return "Wlad Test";
  }


     boolean isRunning = false;
    JFrame a = new JFrame("Влад тест");
    JPanel p0 = new JPanel();
    JPanel p1 = new JPanel();
    DrawArea pg = new DrawArea();
    JTextArea t = new JTextArea(12,60);
    JButton b = new JButton("START");
    JButton b1 = new JButton("Rescan");
    DefaultListModel<String> lm = new DefaultListModel<>();
    JList<String> l = new JList<>(lm);

    SerialPort serialPort;
    boolean serialSet = false;

    public void run() {

        scanSerialPorts();
        b.addActionListener(e -> {
                if (isRunning) {
                    isRunning = false;
                    b.setText("START");
                }
                else {
                    setSerialPort(String.valueOf(l.getSelectedValue()));
                    isRunning = true;
                    b.setText("STOP");
                }
        });

        b1.addActionListener(e -> scanSerialPorts());

        t.setBounds(0,0,380,40);
        l.setBounds(0,0,380,100);
        b.setBounds(0,0,200,50);
        b1.setBounds(0,0,200,50);

        p0.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
        p0.setBounds(0,0,790,190);
        p0.setLayout(new BorderLayout());
        p0.add(new JScrollPane(t),BorderLayout.WEST);
        p0.add(b,BorderLayout.EAST);

        p1.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
        p1.setBounds(0,0,790,190);
        p1.setLayout(new BorderLayout());
        p1.add(b1,BorderLayout.EAST);
        p1.add(l,BorderLayout.WEST);

        pg.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
        pg.setBounds(0,0,400,200);

        a.setSize(800,400);
        a.setLayout(new BorderLayout());
        a.add(p0, BorderLayout.NORTH);
        a.add(p1, BorderLayout.SOUTH);
        a.add(pg, BorderLayout.CENTER);
        a.setVisible(true);

    }
    private static class DrawArea extends JPanel {
        ArrayList<int[]> points = new ArrayList<>();

        public DrawArea () {
            setPreferredSize(new Dimension(400, 400));

        }
        void add (int x, int y) {
            points.add(new int[]{x, y});
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            setBackground(WHITE);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(RED);
            for (int[] p : points) {
                g2d.fill(new Ellipse2D.Double(p[0], p[1], 10, 10));
            }

        }

    }
    public void scanSerialPorts () {
        lm.removeAllElements();
        for (String pn : SerialPortList.getPortNames()) {
            lm.addElement(pn);
        }
        l.setSelectedIndex(lm.getSize()-1);
        l.ensureIndexIsVisible(lm.getSize()-1);

    }
    public void setSerialPort(String portName) {

        if (serialPort != null && serialSet) {
            try {
                serialPort.closePort();
            } catch (SerialPortException ex) {
                ex.printStackTrace();
            }
        }
        serialPort = new SerialPort(portName);
        try {
            serialPort.openPort();
            serialPort.setParams(SerialPort.BAUDRATE_115200,
                    SerialPort.DATABITS_8,
                    SerialPort.STOPBITS_1,
                    SerialPort.PARITY_NONE);
            serialPort.addEventListener(serialPortEvent -> {
                if (isRunning && serialPortEvent.isRXCHAR() && serialPortEvent.getEventValue() > 0) {
                    try {
                        String data = serialPort.readString(serialPortEvent.getEventValue());
//                        t.append(String.format("%s %20x\n", data, new BigInteger(1, data.getBytes(StandardCharsets.UTF_8))) + "\n");
//                        t.append(String.format("%s", data));
                        String[] xy = data.split(" ");
                        int x = 0;
                        int y = 0;
                        try {
                            x = Integer.parseInt(xy[0]);
                            y = Integer.parseInt(xy[1]);
                        } catch (NumberFormatException ex) {
                            ex.printStackTrace();
                        }
                        t.append(Arrays.toString(xy) + "\n");
                        pg.add(x,y);
                    } catch (SerialPortException ex) {
                        ex.printStackTrace();
                    }
                }
            }, SerialPort.MASK_RXCHAR);
            serialSet = true;
        } catch (SerialPortException ex) {
            ex.printStackTrace();
        }
    }
}

Ну и мейк к нему

#!/bin/sh

# The pde.jar file may be buried inside the .app file on Mac OS X.
PDE=`find ../.. -name pde.jar`
JSSC=`find ../.. -name jssc*.jar` 

javac -target 1.8 -source 1.8 \
  -cp "../../lib/arduino-core.jar:$PDE:$JSSC" \
  -d bin \
  src/WladTest.java

mkdir tool
cd bin && zip -r ../tool/WladTest.jar * && cd ..


 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ПОнятно, что для отладки метод run() со-товащи нужно перепаковать в другой класс. Есть еще способы отладки, но это самый простой. У меня есть класс в IntelliJ IDEA в который я просто копирую кусок текста и обратно.

Снова напомню моё мнение о том, что писать на джаве (я всегда говорю "на яве") нужно исключительно в ИДЕЕ, не в Эклипсе и не в  Нетбиинсе. Один раз запустив ИДЕЮ никогда к старому говну не вернешься. Ну как бы ИМХО. Хотя могу и принять пару лопаток на вентилятор! ;)

b707
Offline
Зарегистрирован: 26.05.2017

вопросик, может глупый - нафига работу с компортом и всякую графику к нему писать на яве, если есть процессинг, не говоря уж о более серьезных С++ средах. типа Qt ?

в чем преимущество этих "плагинов"?

Или я ничего не понял

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

b707 пишет:
я ничего не понял

я тоже. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

b707 пишет:
я ничего не понял

я тоже. 

не отлынивай! осталось определиться, а чего еще от IDE надо, я то ничего другого кроме IDE не видел, мнения быть не может )))

Logik
Offline
Зарегистрирован: 05.08.2014

b707 пишет:

в чем преимущество этих "плагинов"?

Или я ничего не понял

Приходит к пластическому хирургу мужик и просит:
- Пришейте мне член ко лбу.
Доктор с крайней степенью удивления:
- Зачем??
- Ну во первых это красиво...

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

DetSimen пишет:

b707 пишет:
я ничего не понял

я тоже. 

По порядку.

1. Куча народа. по моему мнению. может и не так, пользуется ИДЕ. Многие пользуются монитором порта при отладке. хоть он и кривее турецкой сабли.

2. Плагин в ИДЕ дает доступ к скетчу, вот прям к страничке в редакторе, в оранжевым буквам на черном фоне ;)) внизу, под редактором, ко всем настройкам платы. Что удобно, особенно для начинающего.

3. Плагин один раз закинул в папку со скетчами, как и платформы или библиотеки и не нужно пересталять вместе с ИДЕ. Ну по крайней мере пока не будет революционных изменений в ИДЕ ;))) Например перехода с 8 JDK на 11 ;))))) Гы! (это шутка для понимающих в яве)

4.  Работа с портом просто мне интересна была, у меня всякие идеи на разбивку одного порта на виртуальные каналы в  голове крутятся, но плагин это гораздо больше. Например можно написать конвертер картинок в массив для дисплея, который прямо в текст скетча напишет готовый код картинки. Доступ к редактору, напоминаю.

5. Ну и плагин же сам ложится в меню ИДЕ и оттуда вызывается, это удобно вообще.

-------------------

Если кто не понял, то я не призываю новичка учить яву, ява вообще язык ни разу не проще С. И не дает возможности писать без ООП, как на Ардуинке ;)). Мой призыв направлен к программистам, которых есть  много  на форуме! Писать интересные плагины. Для диагностики вместо монитора, для конвертации фонтов и картинок, да хоть для "замены делей на миллис", хоть это уже и иной уровень! ;))

Если для себя, то люди пишут инструменты отладки и проверки на привычном языке.  Конечно на Питоне легче написать приблуду для ком порта. Но и Ява дает много. А главное, что по умолчанию Ява есть везде, а Питон только на Линуксе и Маке. Винда активно свой говноязык C# продвигает. Тот же Питон, только свой, виндовый, Никому нахер не нужный без активного пресса от Микрософт.

--------------------

Ну вот. я снова не удержался от пафоса и говнометания.... сорри. ;)) хотя, если честно, то пофигу.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Забавная тема. Если бы ещё не лень ... было у меня пара идей, что из этого можно сделать, но лениво, хотя и прикольно.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Женя! Ты пиши, может мне что понравится и я сделаю

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Нет, ну там совсем ... скажем так, полезность вызывает вопр... вернее, не вызывает вопросов, но прикольно :-)

Общая идея - корёжить исходник:

1)
сделать более продвинутый препроцессор, тогда "библиотеки" можно разворачивать до констант, ставить только нужные куски кода и т.п.

2)
делать полную замену кода (кросс-компиляцию), чтобы например, можно было писать в IDE сразу на обобщённом брейнфаке, а вызов интерпретатора сам бы подставлялся.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Нет, ну там совсем ... скажем так, полезность вызывает вопр... вернее, не вызывает вопросов, но прикольно :-)

Общая идея - корёжить исходник:

Ну есть ограничения в самой среде. К редактору редакторский доступ ;). В том смысле, что в открытом документе можно что-то поменять. но заставить открыть в среде не ino/cpp/h/c нереально этим способом. Хотя никто не мешает открыть для редактирования своё окно, не штатного эдитора, а обычное, диалоговое. И в нем делать что-то на брейнфаке. создав потом заполнение для ino окна в ИДЕ.

А вот с препроцессором не сильно ясно. Это отдельный код. Можно всегда сделать некое свое ядро, в котором добавить свою обработку исходников и свои platform.txt и boards.txt. Но это немного другая тема выйдет.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Может и другая, я так подробно, как ты не разбирался. Просто идея была по аналогии с "добавить свой шаг в тулчейн вижуалстудии".

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

шаг можно добавить любой, ИДЕ очень гибкая, никто не заставляет использовать их препроцессор, но задача видится мне не в написании своего ИДЕ. а в мелких плагинах, которые не нужно заново ставить при обновлении ИДЕ. Например свой способ сборки, включая препроцессор, можно написать делая свое ядро. ну как всякие мини и микро коры.Инструмент плагинов это про работу с текстом в ОТКРЫТОМ редакторе и с подключенной платой. С брейнфаком весело можно сделать. ino будет генериться автоматом. ;))