ESPShell для Ардуино :: Энергонезависимая память

[ На русском ] ↔ [ English ]

NVS в ESP32

Хотя ESP-IDF (а так же Arduino Core) содержат функции для работы с NVS (библиотеки EEPROM и Preferences в Arduino), как таковой EEPROM в SoC от Espressif не предусмотрено: вместо этого EEPROM эмулируется на FLASH памяти и для этого на флеше есть специальный раздел, который по умолчанию называется "nvs".

NVS в ESP устроена в виде линейной базы данных, с одним уровнем иерархии: помимо обычных "ключ=значение" в NVS так же сохраняется т.н. namespace. Ключи могут иметь одинаковые имена если он относятся к разым неймспейсам. Здесь и далее по тексту: термины пространство имен, неймспейс, namespace и каталог означают одно и то же.

ESPShell позволяет перемещаться по NVS образом, похожим на работу с фаловой системой: есть знакомые ls, cd, rm. Для создания новых и изменения существующих значений есть команды new и set, а для экспорта и импорта есть команды import и export, сохраняющие NVS в виде текстового файла, что позволяет переносить NVS между разными устройствами и версиями NVS. Текстовый файл содержит команды ESPShell которые можно выполнить командой "exec" или "import" (на самом деле коанда "import" - это алиас команды "exec")

Для запуска NVS редактора нужно выполнить команду nvs:

  esp32#>nvs
  esp32-nvs(/)>
Появившееся приглашение говорит нам о том, что редактор запустился и мы находимся в корневом каталоге. В этом каталоге находятся пространства имен или namespaces, которые можно пролистать командой "ls" или активировать командой "cd": лучше всего думать о пространствах имен как о каталогах в фаловой системе. Чтобы выйти из режима редактирования NVS нужно выполнить команду "exit" или нажать Ctrl+z

Отображение информации: команды cd, ls и dump

NVS commands
Рис. 1: Пример работы и вывод команд cd и ls

Для просмотра информации из NVS используется три команды: cd, ls и dump. Последняя используется лишь в тех случаях, когда команды "ls" недостаточно: например, если данные это текстовая строка, то команда ls покажет лишь первые 42 символа, а если тип данных - бинарный blob, то ls покажет лишь длину блока данных и первые 16 байт. Команда ls имеет один необязательный параметр: пространство имен. Если параметр опущен, то используется то значение, которое было установлено командой cd. Команда ls, будучи выполненной в корневом каталоге пространства имен выведет список пространства имен:

 esp32-nvs(/)>ls
 % NVS has 3 namespaces:
 %  Namespace "espshell" : 2 keys
 %  Namespace "phy" : 4 keys
 %  Namespace "nvs.net80211" : 25 keys
 esp32-nvs(/)>
Если же зайти, скажем, в пространство имен phy (это WiFi драйвер) командой "cd /phy", то выполнив там команду ls без параметров, получим табличку-список ключей и их значений:
  esp32-nvs(/)>cd phy
  esp32-nvs(/phy)ls
  % # |     Key name     |  Type  | Value (strings may be truncated. use "dump")
  % --+------------------+--------+-----------------------------------------------
  %  1| cal_address      | char[] | <A binary blob, not displayed>, 1 bytes
  %  2| cal_data         | char[] | <A binary blob, not displayed>, 1904 bytes
  %  3| cal_mac          | char[] | <A binary blob, not displayed>, 6 bytes
  %  4| cal_version      | uint32 | 701
  % --+------------------+--------+-----------------------------------------------
  % Total: 4 records
А можно - указать пространство имен непосредственно команде, ее первым аргументом:
esp32-nvs(/phy)>ls ../espshell
% # |     Key name     |  Type  | Value (strings may be truncated. use "dump")
% --+------------------+--------+-----------------------------------------------
%  1| tz               | char*  | UTC-07:00
%  2| hostid           | char*  | <empty>
% --+------------------+--------+-----------------------------------------------
% Total: 2 records
esp32-nvs(/phy)>
ПРИМЕЧАНИЕ: Для команды "cd" существование пространства имен не обязательно: если выполнить "cd sdfgsdfg" то никакой ошибки не произойдет и namespace будет установлено именно таким. При создании первого ключа в данном пространстве имен, оно появится в списке команды "ls /". Если же namespace будет пустым, то после выхода из него (например, командой cd /) пространство имен будет удалено.

Как уже было указано, команда ls выводит содержимое NVS в виде таблицы: в ней указаны названия и типы ключей, а так же их значения, если эти значения являются числами. Строки отображаются целиком,только если они короче 42 символов, а бинарные данные (blob) не отображаются вовсе. Для отображения строк целиком, а так же бинарных данных существует команда dump KEY.

esp32-nvs(/phy)>dump cal_address
10 11 22 33 44 55
esp32-nvs(/phy)>
Для данных небольшого размера (т.е. до 16 байт. лимит можно изменить с помощью команды "var tbl_min_len") отображение осуществляется в виде строчки. Для данных больщего размера включается форматированный табличный вывод:

NVS commands
Рис. 2: Пример работы и вывод команды dump sta.apinfo

Команда "dump" так же позволяет выводить длинные строчки, которые могут быть обрезаны командой "ls", целиком. Фомат вывода, впрочем, отличается от формата вывода бинарных данных:

  mars@esp32-nvs(/espshell)>dump hostid
  % "hostid" = "mars"

  mars@esp32-nvs(/espshell)>
Команда cd позволяет заходить в пространства имен. Выбранное пространство имен будет отображаться в строке-приглашении:
esp32-nvs(/)>cd espshell
esp32-nvs(/espshell)>
Как и при работе с файловой системой, команда "cd" редактора NVS может работать с относительными путями:
esp32-nvs(/espshell)>cd ../phy
Каталог / (корневой каталог NVS) не содержит ни ключей ни их значений - в корневом каталоге расположены пространства имен. Как уже было сказано выше, NVS имеет лишь один уровень иерархии, поэтому "каталог в каталоге" создать нельзя.
КомандаОписание и примеры
ls [PATH]

Получить листинг каталога (пространства имен) или список пространств имен

esp32-nvs(/)>ls
%% NVS namespaces:
%  Namespace "espshell" : 2 keys
%  Namespace "phy" : 4 keys
esp32-nvs(/)>
esp32-nvs(/)>ls espshell
% # |     Key name     |  Type  | Value (strings may be truncated. use "dump")
% --+------------------+--------+-----------------------------------------------
%  1| hostid           | char*  | 
%  2| tz               | char*  | UTC-07:00
% --+------------------+--------+-----------------------------------------------
% Total: 2 records
esp32-nvs(/)>
Если PATH не указан, то использется путь, который был задан до этого командой "cd"

cd PATH

Сменить текущий каталог (пространство имен) на PATH. В качестве PATH может быть указано существующее ролстранство имен (и тогда команда "ls" что-то покажет) а может - несуществующее. В случае, когда PATH не существует, он будет создан. Это поведение используется для создания новых записей: если вам захотелось создать неймспейс "my_prefs" а в нем - записи, то нужно сменить каталог командой cd а затем создать записи командой new. Если никаких записей не создать и выйти, то такой пустой неймспейс будет тут же удален.

  esp32-nvs(/)>cd my_prefs
  esp32-nvs(/my_prefs)>ls
  % Namespace "my_prefs" (partition: "nvs") is empty or does not exist

  esp32-nvs(/my_prefs)>new TestKey char
  % Key created. Use "set TestKey ..." to set its value
  esp32-nvs(/my_prefs)>

cd PATH

Сменить текущий каталог (пространство имен) на PATH. В качестве PATH может быть указано существующее ролстранство имен (и тогда команда "ls" что-то покажет) а может - несуществующее. В случае, когда PATH не существует, он будет создан. Это поведение используется для создания новых записей: если вам захотелось создать неймспейс "my_prefs" а в нем - записи, то нужно сменить каталог командой cd а затем создать записи командой new. Если никаких записей не создать и выйти, то такой пустой неймспейс будет тут же удален.

  esp32-nvs(/)>cd my_prefs
  esp32-nvs(/my_prefs)>ls
  % Namespace "my_prefs" (partition: "nvs") is empty or does not exist

  esp32-nvs(/my_prefs)>new TestKey char
  % Key created. Use "set TestKey ..." to set its value
  esp32-nvs(/my_prefs)>

dump KEY_NAME Выводит на экран значение ключа KEY_NAME в текущем пространстве имен. Эта команда работает только со строками и бинарными данными.
  esp32-nvs(/)>cd phy
  esp32-nvs(/phy)>dump cal_address
  % f0 9e 9e 22 7b 2c

Создание, удаление и редактирование значений: new, rm и set

Чтобы создать новый элемент в NVS (т.е. создать новый ключ) следует выполнить команду "new", которая создаст новую запись и установит ее значение в 0 (для скалярных типов) или в однобайтовый буфер, внутри которого, опять же ноль.

  esp32-nvs(/)>cd phy
  esp32-nvs(/phy)>new Key unsigned char
  % Key created. Use "set Key ..." to set its value
  esp32-nvs(/phy)>
В данном примере мы создали запись с именем "Key", в пространстве имен "phy". Тип данных, который будет хранится в этой записи - unsigned char, т.е. беззнаковый байт. Для указания типа данных используется синтаксис принятый в Си\Си++; поддерживаются следующие типы: А так же их комбинации вроде "unsigned short int". Все типы "указатель" будут восприняты как "char *": т.е. можно написать "unsigned int *", но воспринято это будет именно как указатель на строку (т.е. char*). Аналогично в случае массивов, тип будет жестко преобразован к "char". Размер массива можно задавать, а можно и не задавать: "char [10]" или "char[]" сделают одно и тоже - массив переменной длины. Длина массива, как и длина строки будет определяться в момент установки нового значения командой "set"

Для удаления записей из NVS используется команда rm: она имеет один обязательный параметр. То, как работает эта команда станет понятнее из примеров. Предположим, что мы находимся в каталоге (namespace) "espshell":

esp32-nvs(/)>cd espshell
esp32-nvs(/espshell)>
Если мы выполним команду rm tz, то ключ tz из пространства имен espshell будет удален. Чтобы удалить ВСЕ ключи в данном пространстве имен, вместо имени ключа следует указать звездочку ("*")
esp32-nvs(/)>cd espshell
esp32-nvs(/espshell)>
esp32-nvs(/espshell)>rm *
% All keys in the namespace "espshell" were removed
esp32-nvs(/espshell)>
Для удаления пространства имен целиком так же можно задать его первым аргументом команды rm:
esp32-nvs(/phy)>rm ../espshell
Для удаления всех записей вообще, следует выполнить команду rm * непосредственно в корневом каталоге (в "/") или выполнить команду "rm /" в любом каталоге. Удаление записей NVS происходит без подтверждения (espshell не будет спрашивать у вас, уверены ли вы в том, что хотите удалить то или это)

Для установки значения существующего ключа (существующего или созданного командой "new") можно воспользоваться командой "set". У команды всего два параметра: название ключа и новое значение. Например, установим ключ "tz" в пространстве имен "espshell" в значение "Hello World!":

 esp32-nvs(/espshell)>set tz Hello World!
 esp32-nvs(/espshell)>ls
 % # |     Key name     |  Type  | Value (strings may be truncated. use "dump")
 % --+------------------+--------+-----------------------------------------------
 %  1| hostid           | char*  | 
 %  2| tz               | char*  | Hello World!
 % --+------------------+--------+-----------------------------------------------
 % Total: 2 records
 esp32-nvs(/espshell)>
Для установки бинарных данных (char[]) используется Си-подобный синтаксис: символы, за исключением специальных (начинающихся с "\", например "\n" или "\22") сохраняются "как есть". Символы \r\n\t\v преобразуются в соответствии с правилами Си\Си++, символы вида \AB (где A и B - шеснадцатиричные цифры) преобразуются в байт со значением 0xAB. Пример: установить значение cal_data равным 0x10, 0x20, Hello, 0x20, 0x10
  esp32->nvs(/phy)set cal_data \10\20Hello\20\10
КомандаОписание и примеры
new KEY_NAME KEY_TYPE

Создать ключ типа KEY_TYPE с именем KEY_NAME. В качестве KEY_TYPE может быть указан один из скалярных типов языка Си (т.е. char, short, int, long, unsigned/signed, long long, char *, char []) Пример: создать запись cal_address, задать значение cal_address таким - 0011:2233:4455

  esp32-nvs(/)>cd phy
  esp32-nvs(/phy)>new cal_address char[]
  % Key created. Use "set cal_address ..." to set its value
Если ключ уже существует, то он будет обнулен (строки превратятся в строчки нулевой длины а массивы - в массивы состоящие из одного байта, нуля)

set KEY_NAME KEY_VALUE

Задать новое значение для ключа KEY_NAME. Аргумент KEY_VALUE это либо число (в случае со скалярными типами) либо строка\массив. Массив и строка задаются одним и тем же способом. Пример: Изменить запись cal_address, задать значение 0011:2233:4455

  esp32-nvs(/phy)>set cal_address \00\11\22\33\44\55

rm PATH

Удалить ключи\пространства имен. В качестве аргумента указывается или название ключа или пространство имен. Если в качестве PATH указать "/" (корневой каталог) до будут удалены вообще все данные NVS Если в качестве PATH указать название пространства имен, то будут удалены все ключи в данном пространстве имен. Ну а если команде передать название ключа, то команда удалит только указанный ключ.

Экспорт и импорт: import, export

Для того, чтобы сохранить содержимое NVS в файл существует команда "export":

esp32-nvs(/nvs.net80211)>export nvs_backup.txt
% Exporting namespace "nvs.net80211"..
esp32-nvs(/nvs.net80211)>
Команда может использоваться для экспорта отдельных каталогов (пространств имен) а может - для экспорта всего содержиого NVS целиком. Последний аргумент команды это всегда имя файла, в который требуется сохранить данные из NVS. Пространство имен можно указать, а можно - не указывать. В таком случае в качестве пространства имен для экспорта будет использовано текущее пространство имен. Синтаксис команды станет понятнее из примеров:
esp32-nvs(/phy)#>export /ffat/data.txt  ← экспортировать текущее пространство имен (т.е. "phy")
esp32-nvs(/phy)#>export ../espshell /ffat/data.txt  ← экспортировать настройки espshell
esp32-nvs(/phy)#>export  / /ffat/data.txt  ← экспортировать все содержимое NVS
esp32#>

Сохраненный файл с данными NVS можно будет загрузить командой "import":

esp32-nvs(/phy)#>import /ffat/data.txt  ← импортировать данные из файла в NVS.
При импорте совершенно не важно, в каком каталоге вы находитесь - можно выполнять импорт находясь в корневом каталоге или в каталоге, скажем, "phy", на результат это не повлияет никак. При экспорте то, в каком каталоге вы находитесь имеет значение лишь в случае, когда команда "export" запускается с одним аргументом - именем файла.
КомандаОписание и примеры
export [NVS_PATH] FILE_PATH

Экспорт содержимого NVS в текстовый файл (файловая система должна быть смонтирована, см. "mount") Если в качестве NVS_PATH указать "/" (корневой каталог) до будут экспортированы все данные NVS (все пространства имен).

       esp32-nvs(/espshell)>export / file.txt ← экспортировать все содержимое NVS в файл
      
Если в качестве NVS_PATH указать название пространства имен, то будет экспортировано указанное пространство имен.
       esp32-nvs(/espshell)>export /phy file.txt ← экспортировать содержимое пространства имен "phy"
      
Если же параметр NVS_PATH опустить, то будет экспортировано текущее пространство имен:
       esp32-nvs(/espshell)>export file.txt ← экспортировать пространство имен "espshell"
      

import FILE_PATH

Импорт содержимого текстового файла (файловая система должна быть смонтирована, см. "mount")

       esp32-nvs(/espshell)>import file.txt