Espruino:Примеры/Сохранение кода на Espruino: различия между версиями
Myagkij (обсуждение | вклад) (Новая страница: «{{Espruino/Панель перехода}} {{Перевод от Сubewriter}} {{Myagkij-редактор}} =<ref>[ www.espruino.com - ]</ref>= <syntaxhighligh...») |
Myagkij (обсуждение | вклад) Нет описания правки |
||
Строка 3: | Строка 3: | ||
{{Myagkij-редактор}} | {{Myagkij-редактор}} | ||
=<ref>[ www.espruino.com - ]</ref>= | =Сохранение кода на Espruino<ref>[https://www.espruino.com/Saving www.espruino.com - Saving code on Espruino]</ref>= | ||
Когда вы загружаете код на Espruino обычным способом, он сохраняется в RAM-память Espruino. В таком случае, если вы выполните сброс платы или если у платы отключится питание, этот код будет потерян. | |||
Впрочем, вы всегда можете легко сохранить код в долговременную flash-память, чтобы избежать таких неприятных ситуаций. | |||
== Итого == | |||
Просто напишите save() в левой стороне IDE и текущее состояние Espruino, включая весь сохранённый код, будет записано на flash-память, а потом снова загружено в момент запуска. | |||
Но есть и другие – более эффективные – методы сохранения кода, а также методы, включая, например, методы для сохранения констант. | |||
Выбрать нужный метод можно двумя способами: | |||
* Нажмите на кнопку с треугольником под кнопкой загрузки кода в IDE Espruino и выберите нужный вариант. | |||
* Кликните на иконку с шестерёнкой справа вверху (Settings), затем на Communications, найдите пункт Save on Send и выберите нужный вариант. | |||
Более подробно читайте ниже. | |||
== Процесс загрузки == | |||
Чтобы понять, как лучше сохранять данные, нужно знать, как Espruino загружает сохранённый код. | |||
Во время запуска Espruino делает следующее: | |||
* При нажатии на кнопку BTN1 или при выполнении сброса с помощью функции reset() задаёт в настройке hasBeenReset значение true. | |||
* Если в hasBeenReset не было задано значение true, ищет сжатый образ (.varimg в хранилище Storage) состояния интерпретатора, сохранённый при помощи save(). Если он есть, Espruino распаковывает его в RAM-память. | |||
* (для версии 2.0 и новее) Ищет в Storage файлы с названиями .boot0, .boot1, .boot2 и .boot3 и по очереди их выполняет. Если зажать кнопку BTN1 на Bangle.js, эти файлы выполнены не будут, но все прочие устройства всегда их выполняют. | |||
* Ищет в Storage файл под названием .bootrst, и если он существует, выполняет его (см. раздел «Save on Send» ниже). | |||
* Если в hasBeenReset не было задано значение true, а в шаге выше не был найден файл .bootrst, ищет в Storage файл под названием .bootcde и выполняет его (см. раздел «Save on Send» ниже). | |||
* Инициализирует все заранее инициализированные периферийные устройства. | |||
* Запускает все обработчики, зарегистрированные с помощью E.on('init', function() { ... });. | |||
* Запускает функцию onInit(), если она существует. | |||
Если сброс Espruino был выполнен с помощью load(), этапы загрузки будут точно такими же, как описано выше, но в настройке hasBeenReset будет задано значение false. В Espruino v2.05 и новее за этими этапами также последует вызов функции load(имя_файла), которая загрузит заданный файл вместо .bootcde/.bootrst. | |||
Есть два главных способа сохранения кода на Espruino: | |||
== С помощью функции save() == | |||
Если после загрузки кода написать save() в левой части IDE Espruino, текущее содержимое RAM-памяти Espruino будет сжато и записано на flash-память. | |||
Это содержимое включает в себя: | |||
* Все переменные и функции. | |||
* Все прерывания, созданные с помощью setWatch(). | |||
* Таймауты и интервалы, созданные с помощью setTimeout() и setInterval(). | |||
* Состояния всех контактов. | |||
Далее, когда на Espruino-устройство будет вновь подано питание, оно загрузит из flash-памяти сохранённую туда информацию и начнёт работать с того момента, где было сделано сохранение. Это что-то вроде режима гибернации на ПК. | |||
Это стандартный способ сохранения кода на обычных Espruino-устройствах (для Bangle.js он не подходит), и это значит, что вы можете взаимодействовать со своим кодом в левой части IDE, меняя переменные и функции и даже что угодно сохраняя – даже свои изменения. | |||
Например, если вы загрузите код var t = E.getTemperature() и напишите save(), в переменной t будет температура устройства в момент загрузки кода или даже в момент написания save(), а не в момент запуска устройства. | |||
Однако это значит, что весь код, который был выполнен во время загрузки, повторно выполнен не будет. Например, к вашей Espruino может быть подключено внешнее устройство вроде LCD-дисплея, и после подачи питания этот LCD-дисплей нужно будет инициализировать (т.к. он не умеет запоминать своё состояние). В этом случае мы можем создать функцию onInit() (или добавить прослушиватель E.on('init', function() { ... })), которая будет автоматически вызываться интерпретатором при его инициализации. | |||
Когда код будет сохранён, вы можете вернуть интерпретатор к «нулевому» состоянию при помощи функции reset(). Это не удалит все данные, сохранённые в flash-памяти, поэтому если вы перезагрузите устройство (или вызовите load()), это снова загрузит сохранённое ранее состояние. Чтобы полностью удалить сохранённый код, выполните reset(), а следом save(), чтобы сохранить в flash-память это очищенное «нулевое» состояние. | |||
=== Плюсы === | |||
* Когда код обретёт рабочее состояние, вы можете просто вызвать save(), и код продолжит работать. | |||
* Вы можете изменять код, сохранённый с помощью save(), а затем снова вызвать save(), чтобы сохранить свои изменения. | |||
* JS-код не сохраняется в flash-память в виде обычного текста, так что злоумышленнику будет труднее его извлечь. | |||
* Чтобы JavaScript-код в RAM-памяти быстрее выполнялся и был очень компактным, можно воспользоваться E.setFlags({pretokenise:1}). | |||
=== Минусы === | |||
* Не эффективен с точки зрения расходования памяти, так как всё хранится в RAM-памяти. | |||
* Может сбиться форматирование кода внутри функций. Кроме того, не сохранятся комментарии, находящиеся за пределами функций. | |||
* Любой код, выполняемый при запуске Espruino, нужно поместить в функцию onInit() или в обработчик событий E.on('init', function() { ... }). | |||
=== Подводные камни === | |||
* Если не воспользоваться функцией onInit() или E.on('init', ...), код во время загрузки выполняться не будет. | |||
* Поскольку данные функций setWatch() и setInterval() запоминаются, если вызвать их в onInit(), а затем несколько раз вызвать save(), в результате у вас получится много копий этой информации. Чтобы избежать этого, в onInit() можно вызвать clearInterval() и clearWatch(). | |||
* Если вы загрузили какой-то код с помощью функции onInit() или E.on('init', ...), то помните, что в момент загрузки этот код выполнен не будет. Поэтому, чтобы протестировать его, вам надо будет либо вызвать save(), либо вручную выполнить onInit(). | |||
== Save on Send (to Flash) == | |||
Save on Send – это настройка в IDE Espruino. Внутри неё неявно используется функция E.setBootCode() для сохранения JS-кода напрямую в flash-память Espruino. Этот сохранённый JavaScript-код будет выполнен при запуске Espruino. | |||
Этот метод похож на программирование «обычного» микроконтроллера. | |||
Например, если при включенной настройке Save on Send загрузить код var t = E.getTemperature(), в результате при каждом включении устройства в переменную t будет записываться новая температура, тогда как при использовании save() температура записывается в момент загрузки кода. | |||
В настройке Save on Send (чтобы найти её, кликните на иконку с шестерёнкой справа вверху, затем на Communication, и далее ищите внизу пункт Save on Send) можно задать три режима: | |||
* No – код будет загружен в RAM-память, но может быть сохранён с помощью save() (см. выше). Под иконкой загрузки будет надпись «RAM». | |||
* Yes – JavaScript-код будет сохранён в flash-память и выполнен во время загрузки Espruino. Под иконкой загрузки будет надпись «Flash». Если вызвать функцию reset(), Espruino удалит из RAM-памяти весь код и не выполнит сохранённый JS-код. Это сохранит ваш JS-код в файл .bootcde, находящийся в Storage. | |||
* (устарел) Yes, execute even after reset() – JavaScript-код будет сохранён в flash-память и выполнен даже после загрузки Espruino. Под иконкой загрузки будет надпись «Flash» с треугольником «Внимание!». Если вызвать reset(), Espruino удалит из RAM-памяти весь код, сохранённый с помощью save(), но всё равно выполнит сохранённый JS-код. См. раздел «Оба способа» ниже. Это сохранит ваш код в Storage в файл .bootrst. | |||
Сейчас эта опция удалена из онлайн-IDE Espruino, так как опасна и в 99% случаев просто не нужна. Впрочем, если вам надо воспользоваться этим вариантом, вы можете сохранить код в Storage в файл .bootrst. | |||
Чтобы удалить любой код, сохранённый с помощью Save on Send, просто вызовите E.setBootCode() без аргументов. | |||
=== Плюсы === | |||
* Запускает весь код во время загрузки, избавляя от необходимости вызывать onInit(). | |||
* Код внутри каждой функции хранится в flash-памяти, так что RAM-память расходуется в экономном режиме. То же самое касается и модулей, если в IDE поставлена галочка в настройке Modules uploaded as functions. | |||
=== Минусы === | |||
* Ваш JavaScript-код сохраняется в flash-память как обычный текст, из-за чего его можно легко прочесть. | |||
* Если вы внесёте какие-нибудь изменения в левую часть IDE, сохранить их не получится. | |||
* Использование E.setFlags({pretokenise:1}) не даст никакого эффекта, поскольку код функции будет сохранён в flash-память. Впрочем, вы можете задать "ram" в первом аргументе функции, чтобы принудительно загрузить её в RAM-память и токенизировать (это процесс, при котором сохраняемые слова разбиваются на байты, а пробельные символы удаляются). | |||
* В момент загрузки кода выполнить его нельзя – это можно сделать только при включении устройства. | |||
=== Подводные камни === | |||
* Если включить настройку Save on Send, загрузить код, а затем выключить её, на Espruino одновременно могут остаться оба фрагмента кода (см. раздел «Оба способа» ниже). | |||
* Если вызвать save() после сохранения кода в flash-память при помощи метода ниже, можно получить ошибку Got EOF expected ... или [ERASED]. Причина в том, что в RAM-память были сохранены функции, чьи элементы ссылаются на код, которого в flash-памяти больше нет. | |||
== Сохранение в Storage == | |||
Этот вариант аналогичен Save on Send (to Flash), но на Espruino 2v05 и новее вы можете вызвать load(имя_файла) – это выполнит сброс Espruino и загрузит JavaScript-код из именованного файла, хранящегося в памяти Espruino. | |||
== Оба варианта == | |||
Способы Save on Send и save() можно использовать вместе – более подробно читайте выше, в разделе «Процесс загрузки». | |||
Этот метод позволяет при помощи Save on Send сохранять код, который будет гарантированно выполнять некоторые действия независимо от кода, сохранённого с помощью save(). | |||
Вы также можете воспользоваться файлами .boot0, .boot1, .boot2 и .boot3 – с их помощью можно сохранить дополнительный код, который никак не будет пересекаться с кодом, сохранённым другими способами. Например, можно добавить вот такой код: | |||
<syntaxhighlight lang="javascript" enclose="div"> | <syntaxhighlight lang="javascript" enclose="div"> | ||
require("Storage").write(".boot0", ` | |||
WIFI_NAME = "MyWiFi"; | |||
WIFI_PASS = "HelloWorld123"; | |||
`); | |||
</syntaxhighlight> | |||
Благодаря этому коду у вас всегда будут заданы переменные WIFI_NAME и WIFI_PASS – независимо от другого загруженного кода. | |||
Например, если вы создаёте устройство вроде [https://www.espruino.com/Espruino+Home+Computer домашнего Espruino-компьютера], то для сохранения кода инициализации дисплея и клавиатуры можно воспользоваться Save on Send или .boot0. Это позволит вам безопасно программировать сам компьютер, сохраняя его состояние при помощи save() – то есть, независимо от того, что вы сохранили на устройство, вы всегда сможете положиться на то, что дисплей и клавиатура настроены правильно. | |||
== Примечания == | |||
Вы можете загрузить на Espruino такой код, который введёт её в состояние, при котором её нельзя будет перепрограммировать. На большинстве плат, если зажать кнопку в момент подачи питания, это принудительно запустит устройство без загрузки какого-либо сохранённого кода. Более подробно читайте на информационной страничке, посвящённой вашей плате. | |||
=См.также= | =См.также= |
Версия от 21:00, 2 марта 2021
Сохранение кода на Espruino[1]
Когда вы загружаете код на Espruino обычным способом, он сохраняется в RAM-память Espruino. В таком случае, если вы выполните сброс платы или если у платы отключится питание, этот код будет потерян.
Впрочем, вы всегда можете легко сохранить код в долговременную flash-память, чтобы избежать таких неприятных ситуаций.
Итого
Просто напишите save() в левой стороне IDE и текущее состояние Espruino, включая весь сохранённый код, будет записано на flash-память, а потом снова загружено в момент запуска.
Но есть и другие – более эффективные – методы сохранения кода, а также методы, включая, например, методы для сохранения констант.
Выбрать нужный метод можно двумя способами:
- Нажмите на кнопку с треугольником под кнопкой загрузки кода в IDE Espruino и выберите нужный вариант.
- Кликните на иконку с шестерёнкой справа вверху (Settings), затем на Communications, найдите пункт Save on Send и выберите нужный вариант.
Более подробно читайте ниже.
Процесс загрузки
Чтобы понять, как лучше сохранять данные, нужно знать, как Espruino загружает сохранённый код.
Во время запуска Espruino делает следующее:
- При нажатии на кнопку BTN1 или при выполнении сброса с помощью функции reset() задаёт в настройке hasBeenReset значение true.
- Если в hasBeenReset не было задано значение true, ищет сжатый образ (.varimg в хранилище Storage) состояния интерпретатора, сохранённый при помощи save(). Если он есть, Espruino распаковывает его в RAM-память.
- (для версии 2.0 и новее) Ищет в Storage файлы с названиями .boot0, .boot1, .boot2 и .boot3 и по очереди их выполняет. Если зажать кнопку BTN1 на Bangle.js, эти файлы выполнены не будут, но все прочие устройства всегда их выполняют.
- Ищет в Storage файл под названием .bootrst, и если он существует, выполняет его (см. раздел «Save on Send» ниже).
- Если в hasBeenReset не было задано значение true, а в шаге выше не был найден файл .bootrst, ищет в Storage файл под названием .bootcde и выполняет его (см. раздел «Save on Send» ниже).
- Инициализирует все заранее инициализированные периферийные устройства.
- Запускает все обработчики, зарегистрированные с помощью E.on('init', function() { ... });.
- Запускает функцию onInit(), если она существует.
Если сброс Espruino был выполнен с помощью load(), этапы загрузки будут точно такими же, как описано выше, но в настройке hasBeenReset будет задано значение false. В Espruino v2.05 и новее за этими этапами также последует вызов функции load(имя_файла), которая загрузит заданный файл вместо .bootcde/.bootrst.
Есть два главных способа сохранения кода на Espruino:
С помощью функции save()
Если после загрузки кода написать save() в левой части IDE Espruino, текущее содержимое RAM-памяти Espruino будет сжато и записано на flash-память.
Это содержимое включает в себя:
- Все переменные и функции.
- Все прерывания, созданные с помощью setWatch().
- Таймауты и интервалы, созданные с помощью setTimeout() и setInterval().
- Состояния всех контактов.
Далее, когда на Espruino-устройство будет вновь подано питание, оно загрузит из flash-памяти сохранённую туда информацию и начнёт работать с того момента, где было сделано сохранение. Это что-то вроде режима гибернации на ПК.
Это стандартный способ сохранения кода на обычных Espruino-устройствах (для Bangle.js он не подходит), и это значит, что вы можете взаимодействовать со своим кодом в левой части IDE, меняя переменные и функции и даже что угодно сохраняя – даже свои изменения.
Например, если вы загрузите код var t = E.getTemperature() и напишите save(), в переменной t будет температура устройства в момент загрузки кода или даже в момент написания save(), а не в момент запуска устройства.
Однако это значит, что весь код, который был выполнен во время загрузки, повторно выполнен не будет. Например, к вашей Espruino может быть подключено внешнее устройство вроде LCD-дисплея, и после подачи питания этот LCD-дисплей нужно будет инициализировать (т.к. он не умеет запоминать своё состояние). В этом случае мы можем создать функцию onInit() (или добавить прослушиватель E.on('init', function() { ... })), которая будет автоматически вызываться интерпретатором при его инициализации.
Когда код будет сохранён, вы можете вернуть интерпретатор к «нулевому» состоянию при помощи функции reset(). Это не удалит все данные, сохранённые в flash-памяти, поэтому если вы перезагрузите устройство (или вызовите load()), это снова загрузит сохранённое ранее состояние. Чтобы полностью удалить сохранённый код, выполните reset(), а следом save(), чтобы сохранить в flash-память это очищенное «нулевое» состояние.
Плюсы
- Когда код обретёт рабочее состояние, вы можете просто вызвать save(), и код продолжит работать.
- Вы можете изменять код, сохранённый с помощью save(), а затем снова вызвать save(), чтобы сохранить свои изменения.
- JS-код не сохраняется в flash-память в виде обычного текста, так что злоумышленнику будет труднее его извлечь.
- Чтобы JavaScript-код в RAM-памяти быстрее выполнялся и был очень компактным, можно воспользоваться E.setFlags({pretokenise:1}).
Минусы
- Не эффективен с точки зрения расходования памяти, так как всё хранится в RAM-памяти.
- Может сбиться форматирование кода внутри функций. Кроме того, не сохранятся комментарии, находящиеся за пределами функций.
- Любой код, выполняемый при запуске Espruino, нужно поместить в функцию onInit() или в обработчик событий E.on('init', function() { ... }).
Подводные камни
- Если не воспользоваться функцией onInit() или E.on('init', ...), код во время загрузки выполняться не будет.
- Поскольку данные функций setWatch() и setInterval() запоминаются, если вызвать их в onInit(), а затем несколько раз вызвать save(), в результате у вас получится много копий этой информации. Чтобы избежать этого, в onInit() можно вызвать clearInterval() и clearWatch().
- Если вы загрузили какой-то код с помощью функции onInit() или E.on('init', ...), то помните, что в момент загрузки этот код выполнен не будет. Поэтому, чтобы протестировать его, вам надо будет либо вызвать save(), либо вручную выполнить onInit().
Save on Send (to Flash)
Save on Send – это настройка в IDE Espruino. Внутри неё неявно используется функция E.setBootCode() для сохранения JS-кода напрямую в flash-память Espruino. Этот сохранённый JavaScript-код будет выполнен при запуске Espruino.
Этот метод похож на программирование «обычного» микроконтроллера.
Например, если при включенной настройке Save on Send загрузить код var t = E.getTemperature(), в результате при каждом включении устройства в переменную t будет записываться новая температура, тогда как при использовании save() температура записывается в момент загрузки кода.
В настройке Save on Send (чтобы найти её, кликните на иконку с шестерёнкой справа вверху, затем на Communication, и далее ищите внизу пункт Save on Send) можно задать три режима:
- No – код будет загружен в RAM-память, но может быть сохранён с помощью save() (см. выше). Под иконкой загрузки будет надпись «RAM».
- Yes – JavaScript-код будет сохранён в flash-память и выполнен во время загрузки Espruino. Под иконкой загрузки будет надпись «Flash». Если вызвать функцию reset(), Espruino удалит из RAM-памяти весь код и не выполнит сохранённый JS-код. Это сохранит ваш JS-код в файл .bootcde, находящийся в Storage.
- (устарел) Yes, execute even after reset() – JavaScript-код будет сохранён в flash-память и выполнен даже после загрузки Espruino. Под иконкой загрузки будет надпись «Flash» с треугольником «Внимание!». Если вызвать reset(), Espruino удалит из RAM-памяти весь код, сохранённый с помощью save(), но всё равно выполнит сохранённый JS-код. См. раздел «Оба способа» ниже. Это сохранит ваш код в Storage в файл .bootrst.
Сейчас эта опция удалена из онлайн-IDE Espruino, так как опасна и в 99% случаев просто не нужна. Впрочем, если вам надо воспользоваться этим вариантом, вы можете сохранить код в Storage в файл .bootrst. Чтобы удалить любой код, сохранённый с помощью Save on Send, просто вызовите E.setBootCode() без аргументов.
Плюсы
- Запускает весь код во время загрузки, избавляя от необходимости вызывать onInit().
- Код внутри каждой функции хранится в flash-памяти, так что RAM-память расходуется в экономном режиме. То же самое касается и модулей, если в IDE поставлена галочка в настройке Modules uploaded as functions.
Минусы
- Ваш JavaScript-код сохраняется в flash-память как обычный текст, из-за чего его можно легко прочесть.
- Если вы внесёте какие-нибудь изменения в левую часть IDE, сохранить их не получится.
- Использование E.setFlags({pretokenise:1}) не даст никакого эффекта, поскольку код функции будет сохранён в flash-память. Впрочем, вы можете задать "ram" в первом аргументе функции, чтобы принудительно загрузить её в RAM-память и токенизировать (это процесс, при котором сохраняемые слова разбиваются на байты, а пробельные символы удаляются).
- В момент загрузки кода выполнить его нельзя – это можно сделать только при включении устройства.
Подводные камни
- Если включить настройку Save on Send, загрузить код, а затем выключить её, на Espruino одновременно могут остаться оба фрагмента кода (см. раздел «Оба способа» ниже).
- Если вызвать save() после сохранения кода в flash-память при помощи метода ниже, можно получить ошибку Got EOF expected ... или [ERASED]. Причина в том, что в RAM-память были сохранены функции, чьи элементы ссылаются на код, которого в flash-памяти больше нет.
Сохранение в Storage
Этот вариант аналогичен Save on Send (to Flash), но на Espruino 2v05 и новее вы можете вызвать load(имя_файла) – это выполнит сброс Espruino и загрузит JavaScript-код из именованного файла, хранящегося в памяти Espruino.
Оба варианта
Способы Save on Send и save() можно использовать вместе – более подробно читайте выше, в разделе «Процесс загрузки».
Этот метод позволяет при помощи Save on Send сохранять код, который будет гарантированно выполнять некоторые действия независимо от кода, сохранённого с помощью save().
Вы также можете воспользоваться файлами .boot0, .boot1, .boot2 и .boot3 – с их помощью можно сохранить дополнительный код, который никак не будет пересекаться с кодом, сохранённым другими способами. Например, можно добавить вот такой код:
require("Storage").write(".boot0", `
WIFI_NAME = "MyWiFi";
WIFI_PASS = "HelloWorld123";
`);
Благодаря этому коду у вас всегда будут заданы переменные WIFI_NAME и WIFI_PASS – независимо от другого загруженного кода.
Например, если вы создаёте устройство вроде домашнего Espruino-компьютера, то для сохранения кода инициализации дисплея и клавиатуры можно воспользоваться Save on Send или .boot0. Это позволит вам безопасно программировать сам компьютер, сохраняя его состояние при помощи save() – то есть, независимо от того, что вы сохранили на устройство, вы всегда сможете положиться на то, что дисплей и клавиатура настроены правильно.
Примечания
Вы можете загрузить на Espruino такой код, который введёт её в состояние, при котором её нельзя будет перепрограммировать. На большинстве плат, если зажать кнопку в момент подачи питания, это принудительно запустит устройство без загрузки какого-либо сохранённого кода. Более подробно читайте на информационной страничке, посвящённой вашей плате.
См.также
Внешние ссылки