«Зачем?», «Что за бред?», «Извращение!», «Фу-фу-фу» — вот некоторые из многих высказываний, которые мы услышали, когда выпустили плату Iskra JS на ядре Espruino.
Зачем
Когда правильный электронщик слышит, что что-то сделано на Arduino, температура его тела поднимается примерно на полградуса: «взяли годный микроконтроллер и вместо того, чтобы фигак-фигак и регистрами выжать из него все соки, опошлили всё на свете… нет слов, одна ненависть».
Но ведь можно пойти ещё дальше. Взять микроконтроллер Cortex M4, который в десятки раз богаче того, что стоит на той же Arduino Uno, запихнуть туда интерпретатор JavaScript и делать проекты на JavaScript!
Думаю, что на этом моменте те, кто не готов к такому надругательству над святыми микросхемами, уже лопнули. Я продолжу для остальных.
В хобби-электронике для подавляющего большинства проектов Arduino Uno хватает за глаза. И даже не важно будет она работать на штатных 16 МГц или на 4 МГц: включится ли подсветка кровати или насос на даче за 1 мс или за 10 мс не имеет значения.
Что имеет значение, так это то, что C++ — сложный и деревянный. Да, он близок к железу, но именно поэтому требует глубокого понимания этого железа и информатики. Добавим к этому синтаксис с кучей нюансов, который является суммой ошибок 30-летнего развития языка. Затем лишим то, что получилось адекватных массивов, строк, словарей, а ещё лучше — вообще лишим динамической памяти. Вот, наконец мы получили Arduino.
Наблюдая за вопросами на нашем форуме я вижу, что люди тратят время на долбание с языком, а не на сути своих проектов. Так почему бы не снизить пропасть между железом и людьми? Железо — дешёвое и постоянно развивается, время людей — дорогое и ниоткуда не берётся.
Похожий процесс я наблюдал много лет пока работал в разработке игр. В 2003-м году представить было нельзя, что игру можно писать на чём-то кроме C/C++. Потом в движках появились встроенные скрипт машины. А затем и создание полноценного продукта стало возможным без единой строки на Си. Только Java, C#, Ruby, Python, JavaScript. Это логично, потому что железо стало тянуть «медленные языки», а засчёт в разы более быстрой разработки и большего количества доступных программистов, стало возможным больше ресурсов тратить на интересность игры, а не на поиск утечек памяти.
На что похоже программирование микроконтроллеров на JavaScript
Программирование похоже на… JavaScript. На разработку для браузера или Node.js. Вот пример:
// SMS
var sim = require('@amperka/Sim900r').connect();
sim.powerOn();
sim.on('sms', function(sms) {
var rgb = sms.text.split(' ');
var r = +rgb[0];
var g = +rgb[1];
var b = +rgb[2];
if (isNaN(r + g + b)) return;
fadeTo(r, g, b);
});
// Лента
SPI2.setup({baud:3200000, mosi:B15});
var LED_COUNT = 150;
var colors = new Uint8ClampedArray(LED_COUNT * 3);
function fadeTo(r, g, b) {
var n = 0;
var ivalID = setInterval(function() {
colors[n*3 + 0] = b;
colors[n*3 + 1] = r;
colors[n*3 + 2] = g;
SPI2.send4bit(colors, 0b0001, 0b0011);
if (n++ >= LED_COUNT) {
clearInterval(ivalID);
}
}, 50);
}
Эта программа занимается тем, что принимает SMS’ки и в зависимости от их текста бегущим огоньком меняет цвет подключённой RGB-ленты. Мы делали такой проект для нашей новогодней ёлки, но на классической Arduino. Кода было в 4 раза больше.
Ядро Espruino
Итак, у компьютера есть движки V8 и SpiderMonkey для JavaScript. А у микроконтроллеров есть движок Espruino.
Если говорить грубо, движок Espruino — это прошивка (скетч, скетчище) для микроконтроллеров, который в свою очередь может исполнять JavaScript-код, который вы передаёте на плату через serial-соединение, например по USB.
Espruino — это open source проект, фаундером которого является Gordon Williams. Человек, который в одиночку реализовал большую часть всей экосистемы и успешно сходил с ней на KickStarter.
Эта экосистема состоит из нескольких основных частей:
- Espruino Web IDE — среда программирования;
- Espruino Firmware — JavaScript-машина, которая крутится на микроконтроллере;
- Железо — сами платы, которые совместимы с Espruino;
- Стандартная библиотека и внешние библиотеки;
- Документация.
Обо всём по порядку.
Среда программирования
Написание JavaScript-кода, загрузка его в плату и наблюдение за выводом происходит в Espruino Web IDE. Это приложение для Google Chrome, поэтому оно ставится в 1 клик и работает под всеми настольными операционками.
Для пользователя эта среда заменяет Arduino IDE.
По функционалу Espruino IDE, конечно, много проще полновесных Eclipse или Visual Studio, но она более продвинута, чем Arduino IDE.
Если окинуть окно среды одним взглядом, увидите редактор кода (справа), панель консоли (слева) и кнопку для загрузки кода в плату.
Консоль — это как Serial Monitor в Arduino IDE, но в отличии от него он не только выводит, но и принимает: можно прямо налету, без ресета и загрузки новой программы, вызвать функцию, посмотреть значение переменной, прервать цикл и т.п.
Поработав плотнее, вы столкнётесь с отладчиком (ага, step-by-step исполнение, breakpoint’ы), подсказками редактора, подсвечиванием ошибок налету и прочими приятными фишечками.
Кроме того, прямо из IDE можно обновить версию самой Espruino Firmware до последней. Среда сама сама скачает последний доступный релиз и зальёт его через USB.
Firmware
Сердце системы — прошивка, которая крутится на микроконтроллере. Она написана на чистом Си, загружается единожды в отдельное место флеш-памяти микроконтроллера и занимается тем, что исполняет пользовательский JS-код, который приходит через последовательное соединение или находится в пользовательской области флеш-памяти.
Если схематично изобразить расклад флеш-памяти для Iskra JS, получим такую картину:
Загрузчик
Сначала идёт загрузчик, которы не обновляется (условно) никогда. Это маленькая программа, с исполнения которой абсолютно всегда начинается жизнь микроконтроллера после включения или сброса.
Загрузчик делает довольно простую вещь:
- Если не нажата пользовательская кнопка BTN1, тут же передаёт управление интерпретатору.
- Если кнопка была нажата при старте, он зацикливается на себе и ждёт либо пока кнопку нажмут ещё раз, чтобы таки выйти в интерпретатор, либо ждёт пока через USB загрузят новую версию интерпретатора. В этом случае bootloader перепишет область флеш-памяти с Espruino Firmware, а мы получим на плате свежую версию интерпретатора.
Интерпретатор
Итак за загрузчиком следует интерпретатор, который и делает основную работу.
Когда он стартует, проверяет с помощью проверки волшебного байта, есть ли в пользовательской флеш-памяти сохранённый код JavaScript. Если есть, принимается его исполнять.
Если кода нет или же, если мы вручную с помощью BTN1 вышли из загрузчика, ничего слёту исполнено не будет, мы просто получим готовую к работе JS-машину.
Свободная память
После интерпретатора есть ничейная область памяти, которую вы можете использовать для энергонезависимого хранения своих данных. Это своеобразная замена EEPROM на Arduino, но со своей спецификой, а ещё её в десятки-сотни раз больше.
Пользовательский код
Здесь хранится та JS-программа, которую выполняет интерпретатор. Программа лежит там в обычном текстовом виде, одним брикетом, как есть.
За то, чтобы множество подключённых библиотек с их зависимостями и ваша собственная программа превратились в один литой и минифицированный брикетик следит при загрузке IDE.
Вернее, всю работу делает не IDE, а её GUI-независимая составная часть EspruinoTools, у которой есть интерфейс коммандной строки и точка входа для использования в качестве Node.js-модуля. Поэтому при желании вы можете использовать Vim, Atom, Eclipse или чего вам удобнее для разработки.
На месте кода вместо текстового брикета может лежать сохранённый бинарный слепок оперативной памяти, который полностью отражает состояние интерпретатора на момент сохранения. Но это уже технические детали не для беглого обзора.
Библиотеки
Библиотеки можно разделить на 3 вида: стандартная, встроенные и внешние.
Стандартная библиотека
Стандартная библиотека — это функции и объекты, которые можно слёту использовать. Среди них, как привычные и прописанные в стандарте языка `Date`, `JSON`, `Math`, `Object`, `setInterval`, `setTimeout` и прочие-прочие, так и специфичные для Espruino функции для работы с пинами, интерфейсами, памятью.
Среди функций вы найдёте привычные ардуинщику `pinMode`, `digitalRead`, `digitalWrite`, `analogRead`, `analogWrite`, а ещё не столь привычные `setWatch` для наблюдения за входными пинами, `digitalPulse` для точной генерации последовательности цифровых импульсов и ещё много разных штук для работы с периферией.
Кстати, несмотря на то, что функция `pinMode` на платформе есть, по умолчанию она работаем сама, за кадром, поэтому в большинстве сценариев можете о ней не вспоминать (на этом месте громко лопнул последний электронщик).
Чего вы не найдёте в стандартной библиотеке, так это `delay`. Mamma Mia, как я благодарен за это! Достаточно немного перестроить мышление и становится ясно, что всё решается через `setInterval`, `setTimeout` без всякого `delay`.
В благодарность вы получаете асинхронность исполнения: можете мигать двадцатью светодиодами независимо, каждым со своей частотой. А ещё вы получаете энергоэффективность: `delay` — это прожигание процессорного сремени, а без `delay` процессор может мирно спать пока нечего делать. В Espruino пока нет работы процессор засыпает и потребляет в десятки раз меньший ток.
Встроенные библиотеки
Встроенные библиотеки — это такая же часть стандартной библиотеки в том смысле, что они жёстко вшиты в Espruino Firmware, но для доступа к их функционалу требуется синтаксически их подключить с помощью знакомой JavaScript-программистам функции `require`.
Среди таких библиотек вы найдёте, например, `fs` для работы с файловыми системами SD-карт, `http` для создания web-интерфейса к своему устройству, `Waveform` для записи/воспроизведения аудиосигналов и другие.
Стандартная и встроенные библиотеки реализованы на чистом Си, а пользователю выведен лишь JavaScript-интерфейс в виде набора объектов, функций и модулей. Это позволяет достичь максимальной эффективности для реализации сложных алгоритмов, оставляя при этом возможность обращения к ним из высокоуровнего кода.
Вы и сами можете реализовать на Си что-то, на что JavaScript сказал бы «нет, спасибо», а наружу вывести только несколько необходимых для запуска хвостов.
Внешние библиотеки
Внешние библиотеки — это то, что формирует богатство экосистемы. Их пишут на JavaScript авторы Espruino, мы пишем, пишут пользователи Espruino.
Храниться они могут на локальном диске, в песочнице текущего проекта, могут быть в интернет-репозитории, могут быть на GitHub’е, могут лежать на NPM’е.
Подключаются библиотеки, традиционно, с помощью `require`.
Когда среда видит `require`, она рекурсивно загружает их из удалённого источника и при загрузке скетча приклеивает их содержимое к началу вашей программы. Таким образом для микроконтроллера формируется цельный брикетик с кодом, о котором я говорил выше.
Такой подход означает также, что в отличии от Arduino пользователю не нужно спотыкаться о то, что библиотеку для начала нужно найти, скачать, положить куда нужно. Достаточно просто слямзить откуда-нибудь понравившийся скетч и среда сама разберётся с зависимостями от библиотек.
Железо
Вот мы и подошли к самому осязаемому компоненту экосистемы Espruino. Это платы, которые могут исполнить Espruino Firmware.
К ним относятся оригинальные Espruino Board, Espruino Pico, а также выпущенная Амперкой Iskra JS. На перечисленных платах всё уже установлено на заводе, они сразу готовы к работе.
Вы можете несколько раз стукнуть в бубен и самостоятельно поставить Espruino-ядро на STM32 Discovery, Nucleo и, внезапно, на ESP8266.
Документация
Нет ничего грустнее, чем что-то очень крутое и мощное, но без документации.
У Espruino — неплохая документация. На www.espruino.com/Reference вы найдёте много справочных и обучающих статей.
Мы хотим сделать ещё больше и лучше. Поэтому создали отдельный раздел: js.amperka.ru, снимаем видеоуроки. Работа пока в процессе, но многое уже освещено.
И традиционно для тех, кто любит коробочные решения, мы создали набор «Йодо». В нём Iskra JS, модули и цветная книга.
Вот такая петрушка. Загадкой остаётся лишь то, смог ли хоть один правильный электронщик дочитать до этой строки?