Espruino:Примеры/Сохранение кода на Espruino: различия между версиями
Myagkij (обсуждение | вклад) Нет описания правки |
Myagkij (обсуждение | вклад) Нет описания правки |
||
Строка 5: | Строка 5: | ||
=Сохранение кода на Espruino<ref>[https://www.espruino.com/Saving www.espruino.com - Saving code on Espruino]</ref>= | =Сохранение кода на Espruino<ref>[https://www.espruino.com/Saving www.espruino.com - Saving code on Espruino]</ref>= | ||
Когда вы загружаете код на Espruino обычным способом, он сохраняется в RAM-память Espruino. В таком случае, если вы выполните сброс платы или если у платы отключится питание, этот код будет потерян. | Когда вы загружаете код на [[Espruino]] обычным способом, он сохраняется в [[RAM-память]] [[Espruino]]. В таком случае, если вы выполните сброс платы или если у платы отключится питание, этот код будет потерян. | ||
Впрочем, вы всегда можете легко сохранить код в долговременную flash-память, чтобы избежать таких неприятных ситуаций. | Впрочем, вы всегда можете легко сохранить код в долговременную [[flash-память]], чтобы избежать таких неприятных ситуаций. | ||
== Итого == | == Итого == | ||
Просто напишите save() в левой стороне IDE и текущее состояние Espruino, включая весь сохранённый код, будет записано на flash-память, а потом снова загружено в момент запуска. | Просто напишите save() в левой стороне [[IDE]] и текущее состояние [[Espruino]], включая весь сохранённый код, будет записано на [[flash-память]], а потом снова загружено в момент запуска. | ||
Но есть и другие – более эффективные – методы сохранения кода, а также методы, включая, например, методы для сохранения констант. | Но есть и другие – более эффективные – методы сохранения кода, а также методы, включая, например, методы для сохранения констант. | ||
Выбрать нужный метод можно двумя способами: | Выбрать нужный метод можно двумя способами: | ||
* Нажмите на кнопку с треугольником под кнопкой загрузки кода в IDE Espruino и выберите нужный вариант. | * Нажмите на кнопку с треугольником под кнопкой загрузки кода в [[IDE Espruino]] и выберите нужный вариант. | ||
* Кликните на иконку с шестерёнкой справа вверху (Settings), затем на Communications, найдите пункт Save on Send и выберите нужный вариант. | * Кликните на иконку с шестерёнкой справа вверху ('''Settings'''), затем на '''Communications''', найдите пункт '''Save on Send''' и выберите нужный вариант. | ||
Более подробно читайте ниже. | Более подробно читайте ниже. | ||
Строка 23: | Строка 23: | ||
== Процесс загрузки == | == Процесс загрузки == | ||
Чтобы понять, как лучше сохранять данные, нужно знать, как Espruino загружает сохранённый код. | Чтобы понять, как лучше сохранять данные, нужно знать, как [[Espruino]] загружает сохранённый код. | ||
Во время запуска Espruino делает следующее: | Во время запуска [[Espruino]] делает следующее: | ||
* При нажатии на кнопку BTN1 или при выполнении сброса с помощью функции reset() задаёт в настройке hasBeenReset значение true. | * При нажатии на кнопку '''BTN1''' или при выполнении сброса с помощью функции reset() задаёт в настройке '''hasBeenReset''' значение '''true'''. | ||
* Если в | * Если в '''hasBeenReset''' не было задано значение '''true''', ищет сжатый образ ('''.varimg''' в хранилище '''Storage''') состояния интерпретатора, сохранённый при помощи save(). Если он есть, [[Espruino]] распаковывает его в [[RAM-память]]. | ||
* (для версии 2.0 и новее) Ищет в Storage файлы с названиями .boot0, .boot1, .boot2 и .boot3 и по очереди их выполняет. Если зажать кнопку BTN1 на Bangle.js, эти файлы выполнены не будут, но все прочие устройства всегда их выполняют. | * (для версии 2.0 и новее) Ищет в '''Storage''' файлы с названиями '''.boot0, .boot1, .boot2 и .boot3''' и по очереди их выполняет. Если зажать кнопку '''BTN1''' на [[Bangle.js]], эти файлы выполнены не будут, но все прочие устройства всегда их выполняют. | ||
* Ищет в Storage файл под названием .bootrst, и если он существует, выполняет его (см. раздел «Save on Send» ниже). | * Ищет в '''Storage''' файл под названием '''.bootrst''', и если он существует, выполняет его (см. раздел [http://wikihandbk.com/wiki/Espruino:%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B/%D0%A1%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BA%D0%BE%D0%B4%D0%B0_%D0%BD%D0%B0_Espruino#Save_on_Send_.28to_Flash.29 «Save on Send»] ниже). | ||
* Если в | * Если в '''hasBeenReset''' не было задано значение '''true''', а в шаге выше не был найден файл '''.bootrst''', ищет в '''Storage''' файл под названием '''.bootcde''' и выполняет его (см. раздел [http://wikihandbk.com/wiki/Espruino:%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B/%D0%A1%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BA%D0%BE%D0%B4%D0%B0_%D0%BD%D0%B0_Espruino#Save_on_Send_.28to_Flash.29 «Save on Send»] ниже). | ||
* Инициализирует все заранее инициализированные периферийные устройства. | * Инициализирует все заранее инициализированные периферийные устройства. | ||
* Запускает все обработчики, зарегистрированные с помощью E.on('init', function() { ... });. | * Запускает все обработчики, зарегистрированные с помощью '''E.on('init', function() { ... });'''. | ||
* Запускает функцию onInit(), если она существует. | * Запускает функцию onInit(), если она существует. | ||
Если сброс Espruino был выполнен с помощью load(), этапы загрузки будут точно такими же, как описано выше, но в настройке hasBeenReset будет задано значение false. В Espruino v2.05 и новее за этими этапами также последует вызов функции load(имя_файла), которая загрузит заданный файл вместо .bootcde/.bootrst. | Если сброс [[Espruino]] был выполнен с помощью load(), этапы загрузки будут точно такими же, как описано выше, но в настройке '''hasBeenReset''' будет задано значение '''false'''. В [[Espruino]] v2.05 и новее за этими этапами также последует вызов функции load(имя_файла), которая загрузит заданный файл вместо '''.bootcde/.bootrst.''' | ||
Есть два главных способа сохранения кода на Espruino: | Есть два главных способа сохранения кода на [[Espruino]]: | ||
== С помощью функции save() == | == С помощью функции save() == | ||
Если после загрузки кода написать save() в левой части IDE Espruino, текущее содержимое RAM-памяти Espruino будет сжато и записано на flash-память. | Если после загрузки кода написать save() в левой части [[IDE Espruino]], текущее содержимое RAM-памяти [[Espruino]] будет сжато и записано на [[flash-память]]. | ||
Это содержимое включает в себя: | Это содержимое включает в себя: | ||
Строка 49: | Строка 49: | ||
* Состояния всех контактов. | * Состояния всех контактов. | ||
Далее, когда на Espruino-устройство будет вновь подано питание, оно загрузит из flash-памяти сохранённую туда информацию и начнёт работать с того момента, где было сделано сохранение. Это что-то вроде режима гибернации на ПК. | Далее, когда на [[Espruino-устройство]] будет вновь подано питание, оно загрузит из flash-памяти сохранённую туда информацию и начнёт работать с того момента, где было сделано сохранение. Это что-то вроде режима гибернации на [[ПК]]. | ||
Это стандартный способ сохранения кода на обычных Espruino- | Это стандартный способ сохранения кода на обычных [[Espruino-устройства]]х (для [[Bangle.js]] он не подходит), и это значит, что вы можете взаимодействовать со своим кодом в левой части [[IDE]], меняя переменные и функции и даже что угодно сохраняя – даже свои изменения. | ||
Например, если вы загрузите код var t = E.getTemperature() и напишите save(), в переменной t будет температура устройства в момент загрузки кода или даже в момент написания save(), а не в момент запуска устройства. | Например, если вы загрузите код '''var t = E.getTemperature()''' и напишите save(), в переменной '''t''' будет температура устройства в момент загрузки кода или даже в момент написания save(), а не в момент запуска устройства. | ||
Однако это значит, что весь код, который был выполнен во время загрузки, повторно выполнен не будет. Например, к вашей Espruino может быть подключено внешнее устройство вроде LCD-дисплея, и после подачи питания этот LCD-дисплей нужно будет инициализировать (т.к. он не умеет запоминать своё состояние). В этом случае мы можем создать функцию onInit() (или добавить прослушиватель E.on('init', function() { ... })), которая будет автоматически вызываться интерпретатором при его инициализации. | Однако это значит, что весь код, который был выполнен во время загрузки, повторно выполнен не будет. Например, к вашей [[Espruino]] может быть подключено внешнее устройство вроде LCD-дисплея, и после подачи питания этот [[LCD-дисплей]] нужно будет инициализировать (т.к. он не умеет запоминать своё состояние). В этом случае мы можем создать функцию onInit() (или добавить прослушиватель E.on('init', function() { ... })), которая будет автоматически вызываться интерпретатором при его инициализации. | ||
Когда код будет сохранён, вы можете вернуть интерпретатор к «нулевому» состоянию при помощи функции reset(). Это не удалит все данные, сохранённые в flash-памяти, поэтому если вы перезагрузите устройство (или вызовите load()), это снова загрузит сохранённое ранее состояние. Чтобы полностью удалить сохранённый код, выполните reset(), а следом save(), чтобы сохранить в flash-память это очищенное «нулевое» состояние. | Когда код будет сохранён, вы можете вернуть интерпретатор к «нулевому» состоянию при помощи функции reset(). Это не удалит все данные, сохранённые в flash-памяти, поэтому если вы перезагрузите устройство (или вызовите load()), это снова загрузит сохранённое ранее состояние. Чтобы полностью удалить сохранённый код, выполните reset(), а следом save(), чтобы сохранить в flash-память это очищенное «нулевое» состояние. | ||
Строка 64: | Строка 64: | ||
* Вы можете изменять код, сохранённый с помощью save(), а затем снова вызвать save(), чтобы сохранить свои изменения. | * Вы можете изменять код, сохранённый с помощью save(), а затем снова вызвать save(), чтобы сохранить свои изменения. | ||
* JS-код не сохраняется в flash-память в виде обычного текста, так что злоумышленнику будет труднее его извлечь. | * JS-код не сохраняется в flash-память в виде обычного текста, так что злоумышленнику будет труднее его извлечь. | ||
* Чтобы JavaScript-код в RAM-памяти быстрее выполнялся и был очень компактным, можно воспользоваться E.setFlags({pretokenise:1}). | * Чтобы JavaScript-код в RAM-памяти быстрее выполнялся и был очень компактным, можно воспользоваться '''E.setFlags({pretokenise:1}).''' | ||
=== Минусы === | === Минусы === | ||
Строка 70: | Строка 70: | ||
* Не эффективен с точки зрения расходования памяти, так как всё хранится в RAM-памяти. | * Не эффективен с точки зрения расходования памяти, так как всё хранится в RAM-памяти. | ||
* Может сбиться форматирование кода внутри функций. Кроме того, не сохранятся комментарии, находящиеся за пределами функций. | * Может сбиться форматирование кода внутри функций. Кроме того, не сохранятся комментарии, находящиеся за пределами функций. | ||
* Любой код, выполняемый при запуске Espruino, нужно поместить в функцию onInit() или в обработчик событий E.on('init', function() { ... }). | * Любой код, выполняемый при запуске [[Espruino]], нужно поместить в функцию onInit() или в обработчик событий '''E.on('init', function() { ... })'''. | ||
=== Подводные камни === | === Подводные камни === | ||
* Если не воспользоваться функцией onInit() | * Если не воспользоваться функцией onInit() или '''E.on('init', ...)''', код во время загрузки выполняться не будет. | ||
* Поскольку данные функций setWatch() и setInterval() запоминаются, если вызвать их в onInit(), а затем несколько раз вызвать save(), в результате у вас получится много копий этой информации. Чтобы избежать этого, в onInit() можно вызвать clearInterval() и clearWatch(). | * Поскольку данные функций setWatch() и setInterval() запоминаются, если вызвать их в onInit(), а затем несколько раз вызвать save(), в результате у вас получится много копий этой информации. Чтобы избежать этого, в onInit() можно вызвать clearInterval() и clearWatch(). | ||
* Если вы загрузили какой-то код с помощью функции onInit() или E.on('init', ...), то помните, что в момент загрузки этот код выполнен не будет. Поэтому, чтобы протестировать его, вам надо будет либо вызвать save(), либо вручную выполнить onInit(). | * Если вы загрузили какой-то код с помощью функции onInit() или '''E.on('init', ...)''', то помните, что в момент загрузки этот код выполнен не будет. Поэтому, чтобы протестировать его, вам надо будет либо вызвать save(), либо вручную выполнить onInit(). | ||
== Save on Send (to Flash) == | == Save on Send (to Flash) == | ||
Save on Send – это настройка в IDE Espruino. Внутри неё неявно используется функция E.setBootCode() для сохранения JS-кода напрямую в flash-память Espruino. Этот сохранённый JavaScript-код будет выполнен при запуске Espruino. | '''Save on Send''' – это настройка в [[IDE Espruino]]. Внутри неё неявно используется функция E.setBootCode() для сохранения JS-кода напрямую в [[flash-память]] [[Espruino]]. Этот сохранённый JavaScript-код будет выполнен при запуске [[Espruino]]. | ||
Этот метод похож на программирование «обычного» | Этот метод похож на программирование ''«обычного»'' [[микроконтроллер]]а. | ||
Например, если при включенной настройке Save on Send загрузить код var t = E.getTemperature(), в результате при каждом включении устройства в переменную t будет записываться новая температура, тогда как при использовании save() температура записывается в момент загрузки кода. | Например, если при включенной настройке '''Save on Send''' загрузить код '''var t = E.getTemperature()''', в результате при каждом включении устройства в переменную '''t''' будет записываться новая температура, тогда как при использовании save() температура записывается в момент загрузки кода. | ||
В настройке Save on Send (чтобы найти её, кликните на иконку с шестерёнкой справа вверху, затем на Communication, и далее ищите внизу пункт Save on Send) можно задать три режима: | В настройке '''Save on Send''' (чтобы найти её, кликните на иконку с шестерёнкой справа вверху, затем на '''Communication''', и далее ищите внизу пункт '''Save on Send''') можно задать три режима: | ||
* No – код будет загружен в RAM-память, но может быть сохранён с помощью save() (см. выше). Под иконкой загрузки будет надпись «RAM». | * '''No''' – код будет загружен в [[RAM-память]], но может быть сохранён с помощью save() (см. выше). Под иконкой загрузки будет надпись '''«RAM»'''. | ||
* Yes – JavaScript-код будет сохранён в flash-память и выполнен во время загрузки Espruino. Под иконкой загрузки будет надпись «Flash». Если вызвать функцию reset(), Espruino удалит из RAM-памяти весь код и не выполнит сохранённый JS-код. Это сохранит ваш JS-код в файл .bootcde, находящийся в Storage. | * '''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. | * '''(устарел) Yes, execute even after reset()''' – JavaScript-код будет сохранён в [[flash-память]] и выполнен даже после загрузки [[Espruino]]. Под иконкой загрузки будет надпись '''«Flash»''' с треугольником '''«Внимание!»'''. Если вызвать reset(), [[Espruino]] удалит из RAM-памяти весь код, сохранённый с помощью save(), но всё равно выполнит сохранённый JS-код. См. раздел [http://wikihandbk.com/wiki/Espruino:%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B/%D0%A1%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BA%D0%BE%D0%B4%D0%B0_%D0%BD%D0%B0_Espruino#.D0.9E.D0.B1.D0.B0_.D0.B2.D0.B0.D1.80.D0.B8.D0.B0.D0.BD.D1.82.D0.B0 «Оба способа»] ниже. Это сохранит ваш код в '''Storage''' в файл '''.bootrst'''. | ||
Сейчас эта опция удалена из онлайн-IDE Espruino, так как опасна и в 99% случаев просто не нужна. Впрочем, если вам надо воспользоваться этим вариантом, вы можете сохранить код в Storage в файл .bootrst. | Сейчас эта опция удалена из онлайн-IDE [[Espruino]], так как опасна и в ''99%'' случаев просто не нужна. Впрочем, если вам надо воспользоваться этим вариантом, вы можете сохранить код в '''Storage''' в файл '''.bootrst'''. | ||
Чтобы удалить любой код, сохранённый с помощью Save on Send, просто вызовите E.setBootCode() без аргументов. | |||
Чтобы удалить любой код, сохранённый с помощью '''Save on Send''', просто вызовите E.setBootCode() без аргументов. | |||
=== Плюсы === | === Плюсы === | ||
* Запускает весь код во время загрузки, избавляя от необходимости вызывать onInit(). | * Запускает весь код во время загрузки, избавляя от необходимости вызывать onInit(). | ||
* Код внутри каждой функции хранится в flash-памяти, так что RAM-память расходуется в экономном режиме. То же самое касается и модулей, если в IDE поставлена галочка в настройке Modules uploaded as functions. | * Код внутри каждой функции хранится в flash-памяти, так что [[RAM-память]] расходуется в экономном режиме. То же самое касается и модулей, если в IDE поставлена галочка в настройке '''Modules uploaded as functions.''' | ||
=== Минусы === | === Минусы === | ||
* Ваш JavaScript-код сохраняется в flash-память как обычный текст, из-за чего его можно легко прочесть. | * Ваш [[JavaScript]]-код сохраняется в [[flash-память]] как обычный текст, из-за чего его можно легко прочесть. | ||
* Если вы внесёте какие-нибудь изменения в левую часть IDE, сохранить их не получится. | * Если вы внесёте какие-нибудь изменения в левую часть IDE, сохранить их не получится. | ||
* Использование E.setFlags({pretokenise:1}) не даст никакого эффекта, поскольку код функции будет сохранён в flash-память. Впрочем, вы можете задать "ram" в первом аргументе функции, чтобы принудительно загрузить её в RAM-память и токенизировать (это процесс, при котором сохраняемые слова разбиваются на байты, а пробельные символы удаляются). | * Использование '''E.setFlags({pretokenise:1})''' не даст никакого эффекта, поскольку код функции будет сохранён в [[flash-память]]. Впрочем, вы можете задать '''"ram"''' в первом аргументе функции, чтобы принудительно загрузить её в [[RAM-память]] и токенизировать (это процесс, при котором сохраняемые слова разбиваются на байты, а пробельные символы удаляются). | ||
* В момент загрузки кода выполнить его нельзя – это можно сделать только при включении устройства. | * В момент загрузки кода выполнить его нельзя – это можно сделать только при включении устройства. | ||
=== Подводные камни === | === Подводные камни === | ||
* Если включить настройку Save on Send, загрузить код, а затем выключить её, на Espruino одновременно могут остаться оба фрагмента кода (см. раздел «Оба способа» ниже). | * Если включить настройку '''Save on Send''', загрузить код, а затем выключить её, на Espruino одновременно могут остаться оба фрагмента кода (см. раздел [http://wikihandbk.com/wiki/Espruino:%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B/%D0%A1%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BA%D0%BE%D0%B4%D0%B0_%D0%BD%D0%B0_Espruino#.D0.9E.D0.B1.D0.B0_.D0.B2.D0.B0.D1.80.D0.B8.D0.B0.D0.BD.D1.82.D0.B0 «Оба способа»] ниже). | ||
* Если вызвать save() после сохранения кода в flash-память при помощи метода ниже, можно получить ошибку Got EOF expected ... или [ERASED]. Причина в том, что в RAM-память были сохранены функции, чьи элементы ссылаются на код, которого в flash-памяти больше нет. | * Если вызвать save() после сохранения кода в [[flash-память]] при помощи метода ниже, можно получить ошибку '''Got EOF expected ... или [ERASED]'''. Причина в том, что в [[RAM-память]] были сохранены функции, чьи элементы ссылаются на код, которого в flash-памяти больше нет. | ||
== Сохранение в Storage == | == Сохранение в Storage == | ||
Этот вариант аналогичен Save on Send (to Flash), но на Espruino 2v05 и новее вы можете вызвать load(имя_файла) – это выполнит сброс Espruino и загрузит JavaScript-код из именованного файла, хранящегося в памяти Espruino. | Этот вариант аналогичен '''Save on Send (to Flash)''', но на [[Espruino]] 2v05 и новее вы можете вызвать '''load(имя_файла)''' – это выполнит сброс Espruino и загрузит [[JavaScript]]-код из именованного файла, хранящегося в памяти [[Espruino]]. | ||
== Оба варианта == | == Оба варианта == | ||
Способы Save on Send и save() можно использовать вместе – более подробно читайте выше, в разделе «Процесс загрузки». | Способы '''Save on Send''' и '''save()''' можно использовать вместе – более подробно читайте выше, в разделе [http://wikihandbk.com/wiki/Espruino:%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B/%D0%A1%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BA%D0%BE%D0%B4%D0%B0_%D0%BD%D0%B0_Espruino#.D0.9F.D1.80.D0.BE.D1.86.D0.B5.D1.81.D1.81_.D0.B7.D0.B0.D0.B3.D1.80.D1.83.D0.B7.D0.BA.D0.B8 «Процесс загрузки»]. | ||
Этот метод позволяет при помощи Save on Send сохранять код, который будет гарантированно выполнять некоторые действия независимо от кода, сохранённого с помощью save(). | Этот метод позволяет при помощи '''Save on Send''' сохранять код, который будет гарантированно выполнять некоторые действия независимо от кода, сохранённого с помощью save(). | ||
Вы также можете воспользоваться файлами .boot0, .boot1, .boot2 и .boot3 – с их помощью можно сохранить дополнительный код, который никак не будет пересекаться с кодом, сохранённым другими способами. Например, можно добавить вот такой код: | Вы также можете воспользоваться файлами '''.boot0''', '''.boot1''', '''.boot2''' и '''.boot3''' – с их помощью можно сохранить дополнительный код, который никак не будет пересекаться с кодом, сохранённым другими способами. Например, можно добавить вот такой код: | ||
<syntaxhighlight lang="javascript" enclose="div"> | <syntaxhighlight lang="javascript" enclose="div"> | ||
Строка 130: | Строка 131: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Благодаря этому коду у вас всегда будут заданы переменные WIFI_NAME и WIFI_PASS – независимо от другого загруженного кода. | Благодаря этому коду у вас всегда будут заданы переменные '''WIFI_NAME''' и '''WIFI_PASS''' – независимо от другого загруженного кода. | ||
Например, если вы создаёте устройство вроде [https://www.espruino.com/Espruino+Home+Computer домашнего Espruino-компьютера], то для сохранения кода инициализации дисплея и клавиатуры можно воспользоваться Save on Send или .boot0. Это позволит вам безопасно программировать сам компьютер, сохраняя его состояние при помощи save() – то есть, независимо от того, что вы сохранили на устройство, вы всегда сможете положиться на то, что дисплей и клавиатура настроены правильно. | Например, если вы создаёте устройство вроде [https://www.espruino.com/Espruino+Home+Computer домашнего Espruino-компьютера], то для сохранения кода инициализации дисплея и клавиатуры можно воспользоваться '''Save on Send''' или '''.boot0'''. Это позволит вам безопасно программировать сам компьютер, сохраняя его состояние при помощи save() – то есть, независимо от того, что вы сохранили на устройство, вы всегда сможете положиться на то, что дисплей и клавиатура настроены правильно. | ||
== Примечания == | == Примечания == | ||
Вы можете загрузить на Espruino такой код, который введёт её в состояние, при котором её нельзя будет перепрограммировать. На большинстве плат, если зажать кнопку в момент подачи питания, это принудительно запустит устройство без загрузки какого-либо сохранённого кода. Более подробно читайте на информационной страничке, посвящённой вашей плате. | Вы можете загрузить на [[Espruino]] такой код, который введёт её в состояние, при котором её нельзя будет перепрограммировать. На большинстве плат, если зажать кнопку в момент подачи питания, это принудительно запустит устройство без загрузки какого-либо сохранённого кода. Более подробно читайте на информационной страничке, посвящённой вашей плате. | ||
=См.также= | =См.также= |
Версия от 21:10, 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 такой код, который введёт её в состояние, при котором её нельзя будет перепрограммировать. На большинстве плат, если зажать кнопку в момент подачи питания, это принудительно запустит устройство без загрузки какого-либо сохранённого кода. Более подробно читайте на информационной страничке, посвящённой вашей плате.
См.также
Внешние ссылки