File System

Most connected applications require the ability to store configuration information or cache local data. ZentriOS provides a reliable read/write filesystem and access to extended and bulk flash storage to satisfy application storage requirements.

Zentri Wi-Fi modules contain a microprocessor with internal flash and an extended (on module) serial flash. An additional (optional) bulk serial flash is also supported. See Flash Storage. For third-party devices running ZentriOS, an extended serial flash must be provided to store temporary files and to enable wireless OTA updates.

Commands are available to create, delete and open files, and file contents can be easily accessed using one or more stream commands.

Here's a quick example showing how to create, manipulate then delete a file:

ZentriOS Commands Description

> file_create     hello.txt 12
Hello World!

> file_open       hello.txt
> stream_read     0 3
> stream_read     0 50
lo World!
> file_delete     hello.txt

<- Create file, length 12 bytes
<- Enter file contents
  (echoed if system.cmd.echo = 1)

<- Open file for reading
(ZentriOS returns file stream handle = 0)
<- Read no more than 3 bytes

<- Read no more than 50 bytes
  (close file if EOF reached)
<- Delete file

When a file is open, ZentriOS creates a file stream and returns a file stream handle to be used as an argument of the stream_read command. See Network Connections and Streams. The stream type is FILE.

File System Limits

Minimum File Size

Files are created 4KByte aligned; that is, no file can occupy less flash space than 4K.

Maximum File Size

There is no limit to the size of an individual file other than the size of the extended or bulk serial flash connected to the ZentriOS hardware. However the method of creating the file may impose a limit.

When creating files via the file_create command, or via the Web App, which uses file_create in the background, file size is limited by available RAM at file creation.

Maximum File Count

The minimum flash space occupied by files is <number of files> * 4K. For example, in 20K of flash you can create no more than 5 files .

Listing Files

To list files, use the ls command.

To obtain a verbose listing of all files on the MCU-internal flash, bulk and extended serial flash, use the ls command with the -v option. Users are only permitted to write files to serial flash.

> ls -v
!  # Type  Flags  Hnd    Size    Version  Filename
#  0 e-FE   0001   73    1853  /favicon.ico.gz
#  1 e-FE   0001   68   18067  webapp/images.png
#  2 e-FE   0001   52   10525  webapp/index.css.gz
#  3 e-FE   0001   65   10155  webapp/index.html
#  4 e-FE   0001   55   39247  webapp/index.js.gz
#  5 e-FB   0001   74   36511  command_help.csv
#  6 e-FD   0001   51     135  default_setup.script
#  7 e-03   0001   50    1236  geotrust_ca.pem
#  8 e-FE   0021   84    2074  my_ca.pem
#  9 i-00   001B    0  212736  sys/kernel.bin
# 10 i-81   001B   52  178252  sys/services.bin
# 11 e-01   0009    0  203261  sys/wifi_fw.bin
# 12 b-FE   0021   25 1995261  DSC20564.JPEG

File Types

In the ls file listing, Type column, a prefix indicates the location of the file in internal, bulk or extended flash:

See Flash Storage below.

For example, e-FE indicates a file in extended serial flash with a file type of 0xFE.

File types are used internally by ZentriOS for file management.

ZentriOS file types are enumerated in the following table.

File typeID (hex)ID (dec)
Custom type0x96 - 0xC7150 - 199

Custom User Types

The type range from 0x96 (decimal 150) to 0xC7 (decimal 199) is set aside for custom types. Use types in this range for file management specific to your application.

File Flags

Flags are displayed in the file listing in hex format, without a 0x prefix.

The flags correspond to bits as follows:

Encrypted2Encrypted with either the system.security_key or the device's internal AES key. See -y option for file_create, http_download
Essential6This flag can be explicitly set with the -e flag for file_create, http_download
Unprotected8This flag can be explicitly set with the -u flag for file_create, http_download
User Encrypted10Encrypted with the system.security_key. See -s option for file_create, http_download. See also File System, Encrypting ZentriOS Files.

Only the Essential and the Unprotected flags can be explicitly set using a command.

The file_create and http_download commands provide -e and -u options to set the Essential and Unprotected flags.


Flags columnFlags Set
001BValid Executable Internal Bootable
0021Valid User
0061Valid User Essential
0121Valid User Unprotected
0161Valid User Essential Unprotected

File Version

For files that form part of the ZentriOS system, such as services.bin and kernel.bin, the file version follows the scheme:


When creating a user file, the user can choose the versioning scheme. The file_create and http_download commands provide a version option to set the version.

File Checksum

The checksum used on individual files is calculated using a CCITT CRC-16 algorithm with polynomial 0x1021. The full set of CRC parameters is as follows:

CRC Order16
CRC Polynomial0x1021
Initial ValueFFFF (direct)
Final XOR0x0
Reverse data bytesYes
Reverse CRCNo

See the python script and the crccitt_test.c C source for demonstrations of calculating the CRC.

The file_create and http_download commands provide an option to set the CRC.

You can view a file CRC with the file_stat command. The CRC is the second item in the comma-separated list.

See also the File System application note.

File Names

File names are case sensitive, and can contain a maximum of 95 characters from the set:


That is, a file name can contain any character except for the double quote character. A double quote results in a parse error when creating a file with the file_create command.

It may be possible to create a file with a double quote character using other means, then download the file to the device flash.

The ZentriOS file system does not treat the . character or the / character differently to any other. These can be used to create pseudo extensions and pseudo folders. The web app recognizes the / character for folder emulation, which makes some file manipulations more convenient. See ZentriOS Web App, Folder Emulation.

Web app folder emulation creates some restrictions on where you can place a / character in a file name. These apply only to files manipulated in the Web App Files tab.

Special Files

Some files with special functions are listed in the following table:

File NameDescriptionNotes
default_setup.scriptRuns on issuing setup cmdSee Configuration and Setup, Setup Configuration Script
default_config.csvVariable configuration, loaded after a successful OTASee Configuration and Setup, Variable Configuration Script
gpio_config_init.csvBootup GPIO configurationSee Configuration and Setup, Using a GPIO Configuration File

Writing Files

There are two ZentriOS commands that can write to the file system:

There are several ways to invoke these commands:

Writing with the Web App File Browser

When you open the ZentriOS Web App in a web browser and select the Files tab, you can load files to the device file system using click and browse, or drag and drop.

In the background, the ZentriOS Web App uses the file_create command to write files to the device file system, using the HTTP Server RESTful API.

There are several ways to activate the ZentriOS Web App. See ZentriOS Web App.

Writing with the Terminal

In the ZentriOS terminal or remote terminal, use the file_create command to create the file. Immediately after issuing the command, type the file contents, or alternatively copy and paste the file contents into the terminal after issuing the fcr command. The length of the file must be supplied. The character count includes any line termination characters.

In the example below we create a script that can be run using the command setup cmd -v test.script. In this case the character count is 35.

> fcr test.script 35
help,setup,\r\n#This is a comment

File created

Writing File Contents in Chunks

You can write the file in chunks by leaving the file open after issuing the file_create with the -o option. Write the file chunks to the stream returned by the file_create command. You must know the total size of the file to be created in advance.

When you open the file, ZentriOS returns a stream handle, to be used as an argument of the stream_write command. See Network Connections and Streams.

In the example below a small file is created in two chunks:

Commands and ResponsesDescription

> file_create -o hello.txt 11
[Opened: 0]
> stream_write 0 6
> stream_write 0 5
File created
[Closed: 0]
> file_open hello.txt
[Opened: 0]
> stream_read 0 1000
Hello World
[Closed: 0]

Create file; leave stream open; specify total length

Response: open stream and return stream handle
Write first chunk; specify chunk length
Send chunk content (includes trailing space)

Write second chunk; specify chunk length
Send chunk content

Stream closed

Open new file

Response: open stream and return stream handle
Read contents

Stream closed

HTTP Download

You can also provide the file for download from a web server accessible to the device, and use the http_download command. For example:

> http_download test1.png
Downloading: test1.png to flash file system
Request GET /images/srpr/logo11w.png
Connecting (http):
HTTP response: 200
> ls
!  #   Size   Version  Filename
#  4  14022     1.0.0  test1.png


OTA wireless updates allow you to update the ZentriOS system files automatically from Zentri OTA update servers online. Please contact Zentri if you need custom hosting services for your application firmware or files.

Reading Files

The following ZentriOS commands can read from the file system:

There are several ways to invoke these commands:

Reading with the Web App File Browser

When you open the ZentriOS Web App in a web browser and select the Files tab, you can download a file from the device file system by clicking the file name.

In the background, the ZentriOS Web App uses the file_open command to read the files from the device file system, using the HTTP Server RESTful API.

There are several ways to activate the ZentriOS Web App. See ZentriOS Web App.

Reading from a Terminal

You can read text files directly from the ZentriOS Terminal or remote terminal. Read the file, using a file_open followed by a stream_read command, specifying the stream index returned from the file open, e.g.:

> fop default_setup.script
[Opened: 0]
> read 0 1000
network_up,-s    ,Configuration network credentials
set wlan.auto_join.enabled,true,Enable network auto-join
save,-,Saving settings

[Closed: 0]

HTTP Upload

You can upload the file to an available web server with file upload capability with the http_upload command.

Flash Storage

A ZentriOS device contains internal flash inside the microprocessor and an extended flash chip for user storage.

Extended flash is serial flash. Internal flash cannot be manipulated by ZentriOS commands.

Flash Wear Leveling

The flash wear leveling feature ensures that all sectors on the extended/bulk flash are evenly used. This allows for maximum file writes to the extended/bulk flash. This system works seamlessly in the background, and requires no user activity.

The file sys/wl_table.bin is used by the flash wear leveling feature.

Bulk Flash

In addition, an external serial flash can be connected to the device using the existing sflash GPIOs. This is referred to as bulk flash. To enable access to bulk flash, configure the chip select GPIO with the system.bflash.cs_gpio variable.

By default ZentriOS can support up to 128MB bulk flash.

All OTA files and config files (created by the save command) are always stored on extended flash regardless of whether the bulk flash is enabled.

The following commands operate on bulk flash if available, otherwise on extended flash:

Extended and bulk flash can be formatted with the format_flash command.

Supported Bulk Flash Chips

Serial flash chips currently supported by ZentriOS are as follows:

Model IDStorage Capacity

If you require support for a serial flash chip not listed in the table above, please contact Zentri.

Connecting Bulk Serial Flash to the Device

The ZentriOS device is the SPI master. The bulk sflash is the SPI slave.

Connecting bulk sflash to the device requires 4 signals. The GPIO numbers vary depending on the device, as follows:

CLK177Serial Clock
MOSI188Master Out, Slave In
MISO196Master In, Slave Out
CSXXChip Select. Configurable based on system.bflash.cs_gpio variable

Use the format_flash bulk command to erase the contents of the sflash.

The bulk sflash uses the same SPI bus as the extended serial flash on-board the module. Thus the SPI parameters (clock speed, polarity, etc) are not configurable.

Encrypting ZentriOS Files

The python script demonstrates encrypting and decrypting files which can be used by ZentriOS.

An example zap also demonstrates encrypting/decrypting:


Encrypted File Format

A ZentriOS encrypted file has the following format:

So an encrypted file is always 32 bytes longer than a file with same contents unencrypted.

Encryption Sequence

The sequence for encrypting a file is as follows:

  1. Generate Initialization Vector (IV)
  2. Initialize AES-128 context with the user AES key
  3. Calculate the Cipher Block Chaining (CBC) of the entire file, IV=0, and pad with 0s to 16 bytes if necessary, the last 16 bytes of the encrypted output is used as the HMAC
  4. Write the initial IV (the IV from step 1) to the output file/buffer
  5. Using the IV from step 1 and AES-128 context from step 2, using CTR mode encrypt HMAC and write to output file/buffer
  6. Using IV from step 5 and AES-128 context from step 2, using CTR mode encrypt file contents and write to output file/buffer

Decryption Sequence

The sequence for decrypting a file is as follows:

  1. Initialize AES-128 context with the user AES key
  2. Read the 16 byte IV from the beginning of the encrypted file
  3. Read the 16 bytes encrypted HMAC from the file
  4. Using the AES context from Step 1 and the IV from Step 2, decrypt the HMAC using AES CTR mode
  5. Using the AES context and IV from step 4, decrypt the rest of the file using AES CTR mode
  6. Calculate the Cipher Block Chaining (CBC) of the decrypted file data from step 5, IV=0, and pad with 0s to 16 bytes if necessary
  7. The final block from step 6 should match the HMAC from step 4. If the two 16 byte values don't match then either the given user key is invalid or the encrypted file is corrupted.

Preventing File Corruption

The ZentriOS file system is designed to be resistant to file corruption. A file does not appear in the file system until it is marked as valid. See File Flags. A file is marked as valid only after all file data is written and validated. When a file is not valid, it cannot be listed with the ls command or opened with the file_open command. A valid file may not be modified. That is, file size and contents cannot be modified after the file is created.

This ensures the file system does not become populated with corrupt files due to sudden power loss, reset, or interruption of the file stream during writing.

Although normal files cannot be modified, you can add contents to a log file after it is created.

The steps in file creation are as follows:

If the module is reset or power cycled, or the file stream is manually closed before the valid flag is set, the created file and any written contents are lost.

Once the valid flag is set, the file may not be modified.

Log Files

There is no command API interface to this feature. Log files are available only through the Native API File System API:

Log files are used when the file contents are not known in advance, and when small amounts of data are to be written to the file in future.

For example, an application that wakes, writes sensor readings, then goes to sleep or shuts down, can use a log file to accumulate sensor data over a period of time.

If all the data is immediately available, normal files are more appropriate than log files.

A log file is created with a specified total size. The contents of the file are left blank. Logs may then be written to the file at any point thereafter.

Each log has its own header which indicates the log's size and has a valid flag. When a log is appended, a header is created and the log data is written. Once all the log data is written, the log's valid flag is set.

Log File Format

When a log file is generated, its entire contents is erased (i.e. the contents is set to 0xFF).

When you call zn_log_file_append(), ZentriOS appends an individual log entry to the first blank (i.e. first 0xFFFF) in the file.

The log entry starts with a 16bit header. The first 15bits contain the log's length in bytes (little-endian). The MSb is the log entry valid flag. When the MSb of the log's header is cleared (i.e. 0) the log entry is valid. After the 16bit header is the log's contents with length specified in the header.

After the log entry data is written, the MSb of the header is cleared to indicate that the log is valid.

The general format of a log file is:

<header><log data><header><log data>....<header><log data>0xFFFF...

where <header> is:

<1bit valid flag><15bit log data length, little-endian>

For example, see the following log file, listed as a string of hex bytes: 0x06,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x06,0x00,0xFF,0xFF,0xFF,...

The first two bytes are the little endian 16 bit header: 0x06, 0x00 = 0x0006. In the header, the MSb of the high order byte is the valid bit. It is cleared (0) meaning the log is valid. The length of the log, expressed in the remaining 15 bits, is 6 bytes.

A 6 byte log entry follows. All values are 0xFF. Then another log entry begins. In this case it has the same header, 0x06, 0x00.

Cloud System Files

There is no command API interface to this feature. Cloud System files are available only through the Native API Cloud file system API.

Cloud files are managed by the Zentri Device Management Server (DMS).

There are two types of cloud system file:

You can read data directly from a cloud system file. You can download device-specific or product-specific data to your local device file system, for use by your app.

You can create a cloud system file and write to it directly. You can store data in a local normal or log file, then upload it to a cloud system device file when cloud processing is required.

Local Files Versus Cloud System Files

The device's local file system should be used:

The device's cloud file system should be used: