#!/usr/bin/env python # # esp-idf NVS partition generation tool. Tool helps in generating NVS-compatible # partition binary, with key-value pair entries provided via a CSV file. # # Copyright 2018 Espressif Systems (Shanghai) PTE LTD # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import sys import argparse import binascii import getopt import struct import os import array import csv import zlib from os import path """ Class for standard NVS page structure """ class Page(object): PAGE_PARAMS = { "max_size": 4096, "max_old_blob_size": 1984, "max_new_blob_size": 4000, "max_entries": 126 } # Item type codes U8 = 0x01 I8 = 0x11 U16 = 0x02 I16 = 0x12 U32 = 0x04 I32 = 0x14 SZ = 0x21 BLOB = 0x41 BLOB_DATA = 0x42 BLOB_IDX = 0x48 # Few Page constants HEADER_SIZE = 32 BITMAPARRAY_OFFSET = 32 BITMAPARRAY_SIZE_IN_BYTES = 32 FIRST_ENTRY_OFFSET = 64 SINGLE_ENTRY_SIZE = 32 CHUNK_ANY = 0xFF ACTIVE = 0xFFFFFFFE FULL = 0xFFFFFFFC VERSION1=0xFF VERSION2=0xFE def __init__(self, page_num, is_rsrv_page=False): self.entry_num = 0 self.bitmap_array = array.array('B') self.version = Page.VERSION2 self.page_buf = bytearray(b'\xff')*Page.PAGE_PARAMS["max_size"] if not is_rsrv_page: self.bitmap_array = self.create_bitmap_array() self.set_header(page_num) def set_header(self, page_num): global page_header # set page state to active page_header= bytearray(b'\xff')*32 page_state_active_seq = Page.ACTIVE page_header[0:4] = struct.pack('=0, "Page overflow!!" # Split the binary data into two and store a chunk of available size onto curr page if tailroom < remaining_size: chunk_size = tailroom else: chunk_size = remaining_size remaining_size = remaining_size - chunk_size # Change type of data to BLOB_DATA entry_struct[1] = Page.BLOB_DATA # Calculate no. of entries data chunk will require datachunk_rounded_size = (chunk_size + 31) & ~31 datachunk_entry_count = datachunk_rounded_size / 32 datachunk_total_entry_count = datachunk_entry_count + 1 # +1 for the entry header # Set Span entry_struct[2] = datachunk_total_entry_count # Update the chunkIndex chunk_index = chunk_start + chunk_count entry_struct[3] = chunk_index # Set data chunk data_chunk = data[offset:offset + chunk_size] # Compute CRC of data chunk entry_struct[24:26] = struct.pack(' Page.PAGE_PARAMS["max_old_blob_size"]: raise InputError("%s: Size exceeds max allowed length." % key) if version == Page.VERSION2: if encoding == "string": if datalen > Page.PAGE_PARAMS["max_new_blob_size"]: raise InputError("%s: Size exceeds max allowed length." % key) # Calculate no. of entries data will require rounded_size = (datalen + 31) & ~31 data_entry_count = rounded_size / 32 total_entry_count = data_entry_count + 1 # +1 for the entry header # Check if page is already full and new page is needed to be created right away if encoding == "string": if (self.entry_num + total_entry_count) >= Page.PAGE_PARAMS["max_entries"]: raise PageFullError() # Entry header entry_struct = bytearray('\xff')*32 # Set Namespace Index entry_struct[0] = ns_index # Set Span if version == Page.VERSION2: if encoding == "string": entry_struct[2] = data_entry_count + 1 # Set Chunk Index chunk_index = Page.CHUNK_ANY entry_struct[3] = chunk_index else: entry_struct[2] = data_entry_count + 1 # set key key_array = bytearray('\x00')*16 entry_struct[8:24] = key_array entry_struct[8:8 + len(key)] = key # set Type if encoding == "string": entry_struct[1] = Page.SZ elif encoding in ["hex2bin", "binary", "base64"]: entry_struct[1] = Page.BLOB if version == Page.VERSION2 and encoding == "binary" or encoding == "hex2bin" or encoding == "base64": entry_struct = self.write_varlen_binary_data(entry_struct,ns_index,key,data,\ datalen,total_entry_count, nvs_obj) else: self.write_single_page_entry(entry_struct, data, datalen, data_entry_count) """ Low-level function to write data of primitive type into page buffer. """ def write_primitive_data(self, key, data, encoding, ns_index): # Check if entry exceeds max number of entries allowed per page if self.entry_num >= Page.PAGE_PARAMS["max_entries"]: raise PageFullError() entry_struct = bytearray('\xff')*32 entry_struct[0] = ns_index # namespace index entry_struct[2] = 0x01 # Span chunk_index = Page.CHUNK_ANY entry_struct[3] = chunk_index # write key key_array = bytearray('\x00')*16 entry_struct[8:24] = key_array entry_struct[8:8 + len(key)] = key if encoding == "u8": entry_struct[1] = Page.U8 entry_struct[24] = struct.pack('