O NVOL é um registro flash persistente, geralmente chamado de emulação de EEPROM. Oferece uma API básica para leitura e escrita pares de chave/valor indexados de e para uma memória flash, semelhante a um registro. É importante mencionar que a chave e o valor são armazenadas no Flash, permitindo a modificação do registro durante o tempo de execução. Alguns dos recursos do NVOL incluem:
A biblioteca fornece duas opções para gerenciar o armazenamento de dados: Opção 1: Salve imediatamente as entradas na memória flash sempre que alterado. Opção 2: Armazene as entradas na RAM e salve para a memória flash sob demanda.
A desvantagem de uma memória flash é que ela não pode ser apagada ou escrita em bytes únicos. A memória flash só pode ser apagada e escrita em grandes blocos. Um tamanho típico do bloco de apagamento pode ser bytes de 4K ou 8K. Para o NVOL, as implementações do flash devem suportar gravações parciais, onde um bloco apagado pode ser escrito várias vezes enquanto os bits foram alterados apenas de "1" (estado apagado) para "0" (estado programado).
Para o flash, a página é considerada o menor tamanho de bloco que pode ser apagado. Cada setor pode ser composto por uma ou mais dessas páginas.
O primeiro setor é inicialmente apagado. Novas entradas de registro são adicionadas sequencialmente ao flash. Quando uma entrada é atualizada, a entrada antiga é marcada como inválida e uma nova entrada é gravada no próximo endereço flash disponível. Quando o primeiro setor atinge a capacidade, todas as entradas válidas são copiadas para o segundo setor e o primeiro setor é apagado. Este processo se repete.
O NVOL lida com eficiência e acompanha as entradas válidas e seus locais no Flash. Os setores são gerenciados dinamicamente.
As macros estão disponíveis para criar instâncias estáticas de NVOL, que podem ser usadas com a API. Um exemplo de declaração seria:
#define NVOL3_REGISTRY_START 0
#define NVOL3_REGISTRY_SECTOR_SIZE STORAGE_32K
#define NVOL3_REGISTRY_SECTOR_COUNT 2
#define REGISTRY_KEY_LENGTH 24
#define REGISTRY_VALUE_LENGT_MAX 224
NVOL3_INSTANCE_DECL(_regdef_nvol3_entry,
ramdrv_read, ramdrv_write, ramdrv_erase,
NVOL3_REGISTRY_START,
NVOL3_REGISTRY_START + NVOL3_REGISTRY_SECTOR_SIZE,
NVOL3_REGISTRY_SECTOR_SIZE,
REGISTRY_KEY_LENGTH, /*key_size*/
DICTIONARY_KEYSPEC_BINARY(6), /*dictionary key_type (24 char string)*/
53, /*hashsize*/
REGISTRY_VALUE_LENGT_MAX, /*data_size*/
0, /*local_size (no cache in RAM)*/
0, /*tallie*/
NVOL3_SECTOR_VERSION /*version*/
) ;
Isso cria um NVOL com dois setores de 32k no início do flash. O tamanho total da chave, incluindo o cabeçalho de entrada, é de 256 bytes. Isso não é um requisito, mas o alinhamento deve ser levado em consideração. O dicionário de pesquisa possui um tamanho de hash de 53. Além disso, esta instância não armazenará nenhum valores em RAM ( local_size = 0 ), então sempre os lerá no flash quando necessário.
Na demonstração, o driver NVRAMDRV é usado que emulação é uma memória flash em RAM, as funções de acesso é ramdrv_read, ramdrv_write e ramdrv_erase configuradas para esta instância.
Agora _regdef_nvol3_entry pode ser usado com a API NVOL. A API NVOL é ligeiramente invocada para que um exemplo de registro simples seja fornecido.
O exemplo de teste fornecido pode ser compilado e executado em um espaço do codubub. Basta abrir um espaço de codificina para este repostor e tipo de make no terminal que abre (se o terminal não estiver aberto, use ctrl + ` para abrir o terminal). Agora você pode iniciar o exemplo do NVOL digitando ./build/nvol no terminal. Todos os comandos podem ser executados no terminal do espaço de codificina.
Quando o programa de exemplo for lançado, um shell de comando será aberto e exibirá o seguinte:
@navaro /workspaces/nvol (main) $ ./build/nvol
REG : : resetting _regdef_nvol3_entry
NVOL3 : : '_regdef_nvol3_entry' 0 / 255 records loaded
Navaro corshell Demo v 'Jan 16 2023'
use 'help' or '?' for help.
# >
Primeiro, executaremos um script simples para preencher nosso registro com valores. No tipo de prompt:
source ./test/reg.sh
Isso deve preencher o registro com valores. Para listar todos os comandos para testar o tipo de registro ? reg , ele deve exibir a seguinte lista:
# >? reg
reg [key] [value]
regadd <key> <value>
regdel <key>
regerase
regstats
regtest [repeat]
# >
Agora podemos usar o comando reg para visualizar e atualizar o registro:
# >reg
player.age: Ancient
player.gender: Otherworldly
player.level: legendary
player.location: Mount Olympus
player.name: cool_cat
player.points: 9000
player.power: invisibility
player.species: Dragon
player.status: awakened
player.weapon: lightning bolt
test: 123
user.address: 123 Main St.
user.age: 30
user.children: 0
user.email: [email protected]
user.favorite_color: blue
user.gender: male
user.marital_status: single
user.name: John Smith
user.occupation: contributor
user.phone_number: 555-555-5555
21 entries found.
# >reg user.favorite_color yellow
OK
# >reg user.favorite_color
user.favorite_color: yellow
# >regdel user.gender
OK
# >reg player
player.age: Ancient
player.gender: Otherworldly
player.level: legendary
player.location: Mount Olympus
player.name: cool_cat
player.points: 9000
player.power: invisibility
player.species: Dragon
player.status: awakened
player.weapon: lightning bolt
10 entries found.
# >regstats
NVOL3 : : '_regdef_nvol3_entry' 20 / 255 records loaded
record : 256 recordsize
: 0x000000 1st sector version 0x0155 flags 0xaaaaffff
: 0x010000 2nd sector version 0x0000 flags 0xffffffff
: 0x010000 sector size
: 20 loaded
: 20 inuse
: 2 invalid
: 0 error
: 640 lookup table bytes
: 53 dict hash size
: dict hash - max 2, empty 34, used 19
Todos esses comandos são implementados no src/registry/registrycmd.c . A implementação é intuitiva e auto-explicativa e não deve exigir mais explicações.
O shell é um projeto por si só, mas só é incluído neste exemplo para fins de demonstração. É fácil de estender. Usar ? Para ver a lista completa de comandos implementados para este exemplo.
Onde o registro faz uso de strings para indexar as entradas, a tabela de string usa valores inteiros. Essa abordagem requer menos recursos de RAM.
Para este exemplo, também há um script para preencher a tabela de string com valores. No tipo de prompt:
source ./test/strtab.sh
Novamente, agora podemos listar a tabela de string com um comando simples:
# >strtab
0000 ENGLISH
0001 The end of the world is our playground.
0002 The company is family. The family is the company.
0003 Escape the mundane. Embrace the extraordinary.
0004 Work hard, live easy.
0005 The future is now. Join us.
0006 There is no I in team. But there is in severance.
0007 We're not just a company. We're a movement.
0008 Success is a journey, not a destination.
0009 Innovation starts with you.
0010 Welcome to the beginning of something great.
0100 DUTCH
0101 Het einde van de wereld is onze speeltuin.
0102 Het bedrijf is familie. De familie is het bedrijf.
0103 Ontsnap aan het alledaagse. Omarm het buitengewone.
0104 Hard werken, makkelijk leven.
0105 De toekomst is nu. Doe met ons mee.
0106 Er is geen ik in team. Maar wel in ontslagvergoeding.
0107 We zijn niet alleen een bedrijf. We zijn een beweging.
0108 Succes is een reis, geen bestemming.
0109 Innovatie begint bij jou.
0110 Welkom bij het begin van iets groots.
0999 test
23 entries found.
# >
Como o registro, o exemplo da tabela de string se registra na biblioteca de substituição de string para substituir os valores do índice delimitados por <> pela string na tabela String. Por exemplo:
# >echo "<1>"
The end of the world is our playground.
# >
A demonstração usa um driver de emulação para flash na RAM. Isso é implementado em "CRC/drivers/ramdrv.h/c".
No mesmo diretório, um driver de amostra para um chip flash real é provido nos arquivos "spiflash.h/c". Isso foi implementado usando o driver Chibios/HAL SPI e deve ser um bom ponto de partida para portar o NVOL para sua própria plataforma.