Skip to content

Commit

Permalink
Added cmake script for generating partitions at build time
Browse files Browse the repository at this point in the history
  • Loading branch information
shripad621git committed Jan 7, 2024
1 parent 7381d76 commit a6b515d
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 8 deletions.
6 changes: 6 additions & 0 deletions config/esp32/components/chip/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ if(NOT CHIP_ROOT)
endif()

include(${CMAKE_CURRENT_LIST_DIR}/ota-image.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/factory.cmake)

set(CHIP_REQUIRE_COMPONENTS esp_eth freertos lwip bt mbedtls fatfs app_update console openthread nvs_flash spi_flash)

Expand Down Expand Up @@ -521,6 +522,11 @@ if(CONFIG_ENABLE_PW_RPC)
endforeach()
endif()

if(CONFIG_ENABLE_BUILD_TIME_PARTITION_SCRIPT)
generate_build_time_partition(fctry esp_secure_cert ${CHIP_ROOT} FLASH_IN_PROJECT)
add_dependencies(build_time_partition app)
endif()

# Build Matter OTA image
if (CONFIG_CHIP_OTA_IMAGE_BUILD)
chip_ota_image(chip-ota-image
Expand Down
13 changes: 11 additions & 2 deletions config/esp32/components/chip/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ menu "CHIP Device Layer"
NVS namespace. If this option is enabled, the application can use an API to set a CD,
the configured CD will be used for subsequent CD reads.

config ENABLE_ESP_INSIGHTS_TRACE
config ENABLE_ESP_INSIGHTS_TRACE
bool "Enable Matter ESP Insights"
depends on ESP_INSIGHTS_ENABLED
default y
Expand All @@ -892,12 +892,21 @@ menu "CHIP Device Layer"
Enabling the above option will enable the esp32 specific tracing functionality and report the
diagnostic information to the insights cloud.

config ENABLE_ESP_INSIGHTS_SYSTEM_STATS
config ENABLE_ESP_INSIGHTS_SYSTEM_STATS
bool "Enable System Stats for insights"
depends on ESP_INSIGHTS_ENABLED
default n
help
This option enables the system statistics to be sent to the insights cloud.

config ENABLE_BUILD_TIME_PARTITION_SCRIPT
bool "Enable script to build fctry and esp_secure_cert partition in during build time."
default n
help
Enables the cmake script to generate and map the factory parition bin and esp-secure-cert
partition bin to their corresponding addresses specified in partitions.csv and flash the partitons
in a single idf.py flash command.

endmenu


Expand Down
122 changes: 122 additions & 0 deletions config/esp32/components/chip/factory.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#
# Copyright (c) 2023 Project CHIP Authors
#
# 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.
#

function(generate_build_time_partition fctry_partition esp_secure_cert_partition chip_root)
set(options FLASH_IN_PROJECT)
set(multi DEPENDS)
cmake_parse_arguments(arg "${options}" "" "${multi}" "${ARGN}")
get_filename_component(chip_root_abs_path ${chip_root} ABSOLUTE)

set(generate_esp32_chip_factory_bin.py ${PYTHON} ${chip_root}/scripts/tools/generate_esp32_chip_factory_bin.py)

partition_table_get_partition_info(fctry_partition_size "--partition-name ${fctry_partition}" "size")
partition_table_get_partition_info(fctry_partition_offset "--partition-name ${fctry_partition}" "offset")

partition_table_get_partition_info(secure_cert_partition_size "--partition-name ${esp_secure_cert_partition}" "size")
partition_table_get_partition_info(secure_cert_partition_offset "--partition-name ${esp_secure_cert_partition}" "offset")

message(STATUS "fctry_partition_size : ${fctry_partition_size}")
message(STATUS "fctry_partition_offset : ${fctry_partition_offset}")
message(STATUS "secure_cert_partition_size : ${secure_cert_partition_size}")
message(STATUS "secure_cert_partition_offset : ${secure_cert_partition_offset}")

if("${fctry_partition_size}" AND "${fctry_partition_offset}")
set(DEFAULT_DEVICE_NAME "My bulb")
set(DEFAULT_VENDOR_NAME "Test-vendor")
set(DEFAULT_HARDWARE_VERSION 1)
set(DEFAULT_HARDWARE_VERSION_STR "Devkit")
set(DEFAULT_VENDOR_ID 0xFFF2)
set(DEFAULT_PRODUCT_ID 0x8001)
set(DEFAULT_DAC_CERT "${chip_root_abs_path}/credentials/test/attestation/Chip-Test-DAC-FFF2-8001-0008-Cert.der")
set(DEFAULT_DAC_KEY "${chip_root_abs_path}/credentials/test/attestation/Chip-Test-DAC-FFF2-8001-0008-Key.der")
set(DEFAULT_PAI_CERT "${chip_root_abs_path}/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.der")
set(DEFAULT_CERT_DCLRN "${chip_root_abs_path}/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der")
set(DEFAULT_PASSCODE 20202020)
set(DEFAULT_DISCRIMINATOR 3841)

set(DEVICE_NAME ${DEFAULT_DEVICE_NAME} CACHE STRING "My bulb")
set(VENDOR_NAME ${DEFAULT_VENDOR_NAME} CACHE STRING "Test-vendor")
set(HARDWARE_VERSION ${DEFAULT_HARDWARE_VERSION} CACHE STRING 1)
set(HARDWARE_VERSION_STR ${DEFAULT_HARDWARE_VERSION_STR} CACHE STRING "Devkit")
set(VENDOR_ID ${DEFAULT_VENDOR_ID} CACHE STRING 0xFFF2)
set(PRODUCT_ID ${DEFAULT_PRODUCT_ID} CACHE STRING 0x8001)
set(DAC_CERT ${DEFAULT_DAC_CERT} CACHE STRING "${chip_root_abs_path}/credentials/test/attestation/Chip-Test-DAC-FFF2-8001-0008-Cert.der")
set(DAC_KEY ${DEFAULT_DAC_KEY} CACHE STRING "${chip_root_abs_path}/credentials/test/attestation/Chip-Test-DAC-FFF2-8001-0008-Key.der")
set(PAI_CERT ${DEFAULT_PAI_CERT} CACHE STRING "${chip_root_abs_path}/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.der")
set(CERT_DCLRN ${DEFAULT_CERT_DCLRN} CACHE STRING "${chip_root_abs_path}/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der")
set(PASSCODE ${DEFAULT_PASSCODE} CACHE STRING 20202020)
set(DISCRIMINATOR ${DEFAULT_DISCRIMINATOR} CACHE STRING 3841)

message(STATUS "Bulb Name: ${DEVICE_NAME}")
message(STATUS "Vendor Name: ${VENDOR_NAME}")
message(STATUS "Hardware Version: ${HARDWARE_VERSION}")
message(STATUS "Hardware Version String: ${HARDWARE_VERSION_STR}")
message(STATUS "Vendor ID: ${VENDOR_ID}")
message(STATUS "Product ID: ${PRODUCT_ID}")
message(STATUS "DAC Cert: ${DAC_CERT}")
message(STATUS "DAC Key: ${DAC_KEY}")
message(STATUS "PAI Cert: ${PAI_CERT}")
message(STATUS "Certification Declaration: ${CERT_DCLRN}")
message(STATUS "Passcode: ${PASSCODE}")
message(STATUS "Discriminator: ${DISCRIMINATOR}")


# Execute Factory partition image generation; this always executes as there is no way to specify for CMake to watch for
# contents of the base dir changing.
add_custom_target(build_time_partition ALL
COMMAND ${generate_esp32_chip_factory_bin.py} -d ${DISCRIMINATOR}
-p ${PASSCODE}
--product-name "${DEVICE_NAME}"
--vendor-name "${VENDOR_NAME}"
--vendor-id ${VENDOR_ID}
--product-id ${PRODUCT_ID}
--hw-ver ${HARDWARE_VERSION}
--hw-ver-str "${HARDWARE_VERSION_STR}"
--dac-cert ${DAC_CERT}
--dac-key ${DAC_KEY}
--pai-cert ${PAI_CERT}
--cd ${CERT_DCLRN}
--dac-in-secure-cert
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)


set(factory_partition_bin ${CMAKE_BINARY_DIR}/bin/factory_partition.bin)
set(esp_secure_cert_partition_bin ${CMAKE_BINARY_DIR}/bin/esp_secure_cert_partititon.bin)
idf_component_get_property(main_args esptool_py FLASH_ARGS)
idf_component_get_property(sub_args esptool_py FLASH_SUB_ARGS)

esptool_py_flash_target(${fctry_partition}-flash "${main_args}" "${sub_args}" ALWAYS_PLAINTEXT)
esptool_py_flash_to_partition(${fctry_partition}-flash "${fctry_partition}" "${factory_partition_bin}")

esptool_py_flash_target(${esp_secure_cert_partition}-flash "${main_args}" "${sub_args}" ALWAYS_PLAINTEXT)
esptool_py_flash_to_partition(${esp_secure_cert_partition}-flash "${esp_secure_cert_partition}" "${esp_secure_cert_partition_bin}")

add_dependencies(${fctry_partition}-flash build_time_partition)
add_dependencies(${esp_secure_cert_partition}-flash build_time_partition)

if(arg_FLASH_IN_PROJECT)
esptool_py_flash_to_partition(flash "${fctry_partition}" "${factory_partition_bin}")
esptool_py_flash_to_partition(flash "${esp_secure_cert_partition}" "${esp_secure_cert_partition_bin}")
add_dependencies(flash build_time_partition)
endif()
else()
set(message "Failed to create Factory partition image for partition '${partition}'. "
"Check project configuration if using the correct partition table file.")
fail_at_build_time(factory_${partition}_bin "${message}")

endif()
endfunction()
2 changes: 2 additions & 0 deletions scripts/setup/requirements.esp32.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ reedsolo>=1.5.3,<=1.5.4
bitstring>=3.1.6,<4
ecdsa>=0.16.0
construct==2.10.54
pypng==0.0.21
PyQRCode==1.2.1
python-socketio<5
itsdangerous<2.1 ; python_version < "3.11"
esp_idf_monitor==1.1.1
Expand Down
74 changes: 68 additions & 6 deletions scripts/tools/generate_esp32_chip_factory_bin.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@

import argparse
import base64
import csv
import enum
import hashlib
import json
import logging
import os
import pyqrcode
import sys
from types import SimpleNamespace

from types import SimpleNamespace
import cryptography.x509
from bitarray import bitarray
from bitarray.util import ba2int
Expand All @@ -32,6 +36,8 @@
CHIP_TOPDIR = os.path.dirname(os.path.realpath(__file__))[:-len(os.path.join('scripts', 'tools'))]
sys.path.insert(0, os.path.join(CHIP_TOPDIR, 'scripts', 'tools', 'spake2p'))
from spake2p import generate_verifier # noqa: E402 isort:skip
sys.path.insert(0,os.path.join(CHIP_TOPDIR, 'src', 'setup_payload','python'))
from generate_setup_payload import SetupPayload, CommissioningFlow

if os.getenv('IDF_PATH'):
sys.path.insert(0, os.path.join(os.getenv('IDF_PATH'),
Expand All @@ -48,11 +54,13 @@

TOOLS = {}


FACTORY_PARTITION_CSV = 'nvs_partition.csv'
FACTORY_PARTITION_BIN = 'factory_partition.bin'
NVS_KEY_PARTITION_BIN = 'nvs_key_partition.bin'
ESP_SECURE_CERT_PARTITION_BIN = 'esp_secure_cert_partititon.bin'
CONFIG_FILE = 'config.json'
ONBOARDING_DATA_FILE = 'onboarding_codes.csv'
QROCDE_FILE = 'qrcode.png'

FACTORY_DATA = {
# CommissionableDataProvider
Expand Down Expand Up @@ -167,6 +175,25 @@
}


def save_config(args):
with open(CONFIG_FILE, 'w') as config_file:
json.dump(vars(args), config_file)

def load_config():
try:
with open(CONFIG_FILE, 'r') as config_file:
return json.load(config_file)
except FileNotFoundError:
return None

def calculate_hash(data):
return hashlib.sha256(data.encode('utf-8')).hexdigest()


def args_changed(current_args, saved_args):
return calculate_hash(json.dumps(vars(current_args))) != calculate_hash(json.dumps(saved_args))


class CalendarTypes(enum.Enum):
Buddhist = 0
Chinese = 1
Expand Down Expand Up @@ -602,6 +629,12 @@ def any_base_int(s): return int(s, 0)
help='Do not generate the factory partition binary')
parser.add_argument('--output_dir', type=str, default='bin', help='Created image output file path')

parser.add_argument('-cf', '--commissioning-flow', type=any_base_int, default=0,
help='Device commissioning flow, 0:Standard, 1:User-Intent, 2:Custom. \
Default is 0.', choices=[0, 1, 2])
parser.add_argument('-dm', '--discovery-mode', type=any_base_int, default=1,
help='Commissionable device discovery networking technology. \
0:WiFi-SoftAP, 1:BLE, 2:On-network. Default is BLE.', choices=[0, 1, 2])
parser.set_defaults(generate_bin=True)

return parser.parse_args()
Expand Down Expand Up @@ -632,13 +665,42 @@ def generate_factory_partiton_binary(args):
def set_up_out_dirs(args):
os.makedirs(args.output_dir, exist_ok=True)

def generate_onboarding_data(args):
payloads = SetupPayload(args.discriminator, args.passcode, args.discovery_mode, CommissioningFlow(args.commissioning_flow),
args.vendor_id, args.product_id)
logging.info('Discovery mode' + str(args.discovery_mode))
chip_qrcode = payloads.generate_qrcode()
chip_manualcode = payloads.generate_manualcode()
# ToDo: remove this if qrcode tool can handle the standard manual code format
if args.commissioning_flow == CommissioningFlow.Standard:
chip_manualcode = chip_manualcode[:4] + '-' + chip_manualcode[4:7] + '-' + chip_manualcode[7:]
else:
chip_manualcode = '"' + chip_manualcode[:4] + '-' + chip_manualcode[4:7] + '-' + chip_manualcode[7:11] + '\n' + chip_manualcode[11:15] + '-' + chip_manualcode[15:18] + '-' + chip_manualcode[18:20] + '-' + chip_manualcode[20:21] + '"'

logging.info('Generated QR code: ' + chip_qrcode)
logging.info('Generated manual code: ' + chip_manualcode)

csv_data = 'qrcode,manualcode,discriminator,passcode\n'
csv_data += chip_qrcode + ',' + chip_manualcode + ',' + str(args.discriminator) + ',' + str(args.passcode) + '\n'

with open(os.path.join(args.output_dir,ONBOARDING_DATA_FILE), 'w') as f:
f.write(csv_data)

chip_qr = pyqrcode.create(chip_qrcode, version=2, error='M')
chip_qr.png(os.path.join(args.output_dir,QROCDE_FILE), scale=6)


def main():
saved_args = load_config()
args = get_args()
set_up_out_dirs(args)
set_up_factory_data(args)
generate_factory_partiton_binary(args)

if saved_args is None or args_changed(args, saved_args):
set_up_out_dirs(args)
set_up_factory_data(args)
generate_factory_partiton_binary(args)
generate_onboarding_data(args)
save_config(args)
else:
logging.info("No changes in arguments. Skipping partition generation.")

if __name__ == "__main__":
logging.basicConfig(format='[%(asctime)s] [%(levelname)7s] - %(message)s', level=logging.INFO)
Expand Down

0 comments on commit a6b515d

Please sign in to comment.