Merge branch 'feature-tui-monolith' into dev

This commit is contained in:
Dmitry Akimov 2026-07-06 18:11:26 +03:00
commit 6d23069103
944 changed files with 1283289 additions and 637 deletions

View file

@ -58,6 +58,84 @@
- Следить за развитием BSP: MQS, RGB, bootloader или `tft_app`. - Следить за развитием BSP: MQS, RGB, bootloader или `tft_app`.
- Отслеживать локальные патчи поверх vendor SDK, которые нужно вести отдельным patch log. - Отслеживать локальные патчи поверх vendor SDK, которые нужно вести отдельным patch log.
## [Не выпущено] — service-tui: кастомная прошивка нестандартной памяти (после слияния `feature-tui-python`)
Диапазон: `<заполнить после merge>..<текущий HEAD>`
Сравнение: `<заполнить после merge>`
> Изменения внесены **поверх** слияния `feature-tui-python → dev` — базовая
> архитектура `service-tui` (экраны, USB/M5-клиенты, оркестратор) приходит
> самим merge-коммитом; здесь только то, что было доработано отдельно после.
### Кратко
- `service-tui` теперь умеет прошивать сторонние/легаси бинарники (платы
с W25Q256/512 вместо штатного W25Q128) через USB SDP, с явной записью
FCB вместо ненадёжного для таких чипов auto-config Flashloader.
- Выбор оператора на `FlashScreen` (файл/память/DCD) запоминается на весь
запуск TUI — ускоряет прошивку партии одинаковых плат.
- Документация (`tools/production/README.md`, `tools/production/DEV_ARCH.md`,
`tools/host/README.md`, `docs/HOW_TO_FLASH.md`, `docs/DEV_ARCH.md`)
синхронизирована с фактическим состоянием кода.
### Добавлено
- `tools/host/flash_usb.py``write_fcb_explicit()` + флаг `--fcb-path`:
буквальная запись 512-байтного FCB-блоба (`write-memory 0x60000000`)
вместо magic option word `0xF000000F`. Штатный `--firmware`-путь
(`firmware_test`/`bootloader`/`app`) не тронут — работает как раньше.
- `tools/production/app/models.py``FcbVariant` (`W25Q128` покрывает и
W25Q64, `W25Q512` — и W25Q256) и `FlashPreset` (липкий выбор оператора).
- `tools/production/app/flasher.py``_build_custom_hab()`: сборка
HAB-образа на лету через `nxpimage hab export` из «сырого» бинарника
(без FCB/IVT/DCD) в `custom_binaries/`, с опциональным `DCDFilePath`;
стриминг вывода `nxpimage` в UI-лог, а не только в `logger.debug`.
`list_custom_binaries()` + `SERVICE_CUSTOM_BINARIES_DIR` — резолв
директории кастомных бинарей (внешняя, не пакуется в PyInstaller).
- `tools/production/app/screens/flash.py``Select` по `custom_binaries/`,
`Select` по `FcbVariant`, `Switch` DCD вместо свободного текстового
`Input`; предзаполнение из `FlashPreset` при создании экрана.
- `tools/production/app/app.py``ServiceApp._last_flash_preset`,
прокидывается в новый `FlashScreen` при каждом `DeviceDetected(FLASHING)`.
### Изменено
- `tools/host/flash_usb.py`, `erase_chip()` — таймаут `blhost`
`flash-erase-all` увеличен до `-t 200000` (W25Q512 стирается заметно
дольше W25Q128, дефолтного таймаута не хватало). `flash-erase-region`
(обычная прошивка) не тронут — там стирается пара секторов, масштаб иной.
- `tools/production/app/app.tcss``#flash-target-group` ограничен по
высоте (`max-height: 18`, свой скролл), `#flash-log` защищён
`min-height: 6` — разросшаяся custom-группа больше не сжимает лог
прошивки до нечитаемого состояния.
### Документация
- `tools/production/README.md` — мокап `FlashScreen` под факт (Select/Select/
Switch), новый workflow «Прошивка стороннего бинарника», `SERVICE_CUSTOM_BINARIES_DIR`
в примере `.env`.
- `tools/production/DEV_ARCH.md` — новый §8 (конвейер кастомной прошивки,
`FlashPreset`, явная запись FCB, обоснование отказа от auto-config для
W25Q256/512 и от полноценного авто-батч-режима прошивки).
- `docs/HOW_TO_FLASH.md` — §1.5, сноска в сравнительной таблице способов
прошивки (FCB «не нужен» верно только для W25Q128).
- `docs/DEV_ARCH.md``tools/production/` добавлен в дерево структуры
репозитория (отсутствовал ранее).
- `tools/host/README.md` — актуализирован статус `dcd/*.bin` (`w25q512_fdcb.bin`
теперь используется), указатель на `service-tui` как способ прошивки
нестандартной памяти.
### Известные ограничения
- Auto-config Flashloader для W25Q256/512 не проверялся напрямую — решение
писать FCB явно снимает вопрос архитектурно, но не подтверждает и не
опровергает надёжность auto-config как таковую.
- Полноценный режим массового программирования (авто-прошивка по факту
детекта USB, без подтверждения оператора) рассмотрен и отклонён — в
SDP/Flashloader-режиме нет способа прочитать UID платы для идентификации.
- Standalone-упаковка (`PyInstaller`) для этого функционала ещё не
реализована — см. `tools/production/RELEASE_PLAN.md`.
## [2026-06-29] — Этапы 6г7: MQS, HIL pytest firmware_test, Provisioning ## [2026-06-29] — Этапы 6г7: MQS, HIL pytest firmware_test, Provisioning
### Кратко ### Кратко

View file

@ -3,7 +3,7 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
project( project(
firmware_test firmware_test
VERSION 0.1.1 VERSION 0.1.2
LANGUAGES C ASM) LANGUAGES C ASM)
set(TARGET_NAME firmware_test) set(TARGET_NAME firmware_test)

View file

@ -254,10 +254,10 @@ static void handle_cmd_run(const char *p_line)
*/ */
static void handle_cmd_run_selected(const char *p_line) static void handle_cmd_run_selected(const char *p_line)
{ {
/* Максимальный размер реестра — не более 16 тестов */ /* Общий "потолок системы" — TEST_REGISTRY_MAX_SIZE (test_module.h),
const size_t MAX_SELECTED = 16U; * тот же, что ограничивает test_runner.c::g_s_selected[]. */
char id_bufs[16][TEST_ID_MAX_SIZE]; char id_bufs[TEST_REGISTRY_MAX_SIZE][TEST_ID_MAX_SIZE];
const char *id_ptrs[16]; const char *id_ptrs[TEST_REGISTRY_MAX_SIZE];
const char *tests_key = strstr(p_line, K_FIELD_TESTS); const char *tests_key = strstr(p_line, K_FIELD_TESTS);
if (tests_key == NULL) if (tests_key == NULL)
@ -267,7 +267,7 @@ static void handle_cmd_run_selected(const char *p_line)
} }
size_t count = size_t count =
parse_string_array(tests_key + sizeof(K_FIELD_TESTS) - 1U, id_bufs, MAX_SELECTED); parse_string_array(tests_key + sizeof(K_FIELD_TESTS) - 1U, id_bufs, TEST_REGISTRY_MAX_SIZE);
if (count == 0U) if (count == 0U)
{ {

View file

@ -21,6 +21,23 @@
/** @brief Максимальная длина идентификатора теста (включая NUL). */ /** @brief Максимальная длина идентификатора теста (включая NUL). */
#define TEST_ID_MAX_SIZE 24U #define TEST_ID_MAX_SIZE 24U
/**
* @brief Верхняя граница числа тест-модулей в системе.
*
* Общий "потолок" для двух независимых мест:
* - test_runner.c: compile-time ёмкость g_s_selected[] (маска выбора
* для RUNNER_MODE_SELECTED). REGISTRY_SIZE в UNIT_TEST-сборке
* runtime-значение (g_unit_test_registry_size), не может быть
* границей массива со static storage duration.
* - cli.c: максимальный размер входящего массива "tests" в команде
* run_selected (handle_cmd_run_selected()).
*
* Реальный реестр (non-UNIT_TEST, k_registry) 8 модулей, запас есть.
* При добавлении нового теста, если REGISTRY_SIZE превысит эту границу,
* сборка упадёт на _Static_assert в test_runner.c увеличивать здесь.
*/
#define TEST_REGISTRY_MAX_SIZE 16U
/* ── Типы результата ───────────────────────────────────────────────────── */ /* ── Типы результата ───────────────────────────────────────────────────── */
/** /**

View file

@ -58,6 +58,12 @@ extern size_t g_unit_test_registry_size;
#define RUNNER_CONFIRM_ID_SIZE 32U #define RUNNER_CONFIRM_ID_SIZE 32U
#ifndef UNIT_TEST
_Static_assert(
REGISTRY_SIZE <= TEST_REGISTRY_MAX_SIZE,
"k_registry вырос за пределы TEST_REGISTRY_MAX_SIZE (test_module.h) — увеличь константу");
#endif
/* ── Типы ──────────────────────────────────────────────────────────────── */ /* ── Типы ──────────────────────────────────────────────────────────────── */
typedef enum runner_state_e typedef enum runner_state_e
@ -92,12 +98,10 @@ static uint8_t g_s_skipped;
static bool g_s_critical_failed; static bool g_s_critical_failed;
/* Маска выбранных тестов для RUNNER_MODE_SELECTED */ /* Маска выбранных тестов для RUNNER_MODE_SELECTED */
static bool g_s_selected[REGISTRY_SIZE]; static bool g_s_selected[TEST_REGISTRY_MAX_SIZE];
/* ── Forward declaration ───────────────────────────────────────────────── */ /* ── Forward declaration ───────────────────────────────────────────────── */
static void start_test_at(size_t idx); static void start_test_at(size_t idx);
/* ── Внутренние вспомогательные функции ────────────────────────────────── */ /* ── Внутренние вспомогательные функции ────────────────────────────────── */
/** /**

View file

@ -566,3 +566,53 @@ service-build:
--add-data "../shared:shared" \ --add-data "../shared:shared" \
main.py main.py
echo " ✅ dist/service_tui ready" echo " ✅ dist/service_tui ready"
# =============================================================================
# ГРУППА: package — сборка service-tui в исполняемый бандл (PyInstaller)
# =============================================================================
_prod_dir := justfile_directory() / 'tools/production'
_prod_build_dir := env('BUILD_DIR', justfile_directory() / 'build')
[doc('Собрать service-tui в PyInstaller-бандл + скопировать firmware/*_hab.bin')]
[group('package')]
package-tui:
#!/usr/bin/env bash
set -euo pipefail
cd "{{ _prod_dir }}"
echo " 📦 Running PyInstaller..."
uv run pyinstaller service_tui.spec --noconfirm
DIST="dist/service_tui"
echo " 📦 Copying firmware HAB images (build/<Type>/*_hab.bin)..."
found=0
for type_dir in "{{ _prod_build_dir }}"/Debug "{{ _prod_build_dir }}"/Release; do
[[ -d "$type_dir" ]] || continue
type_name=$(basename "$type_dir")
for hab in "$type_dir"/*_hab.bin; do
[[ -f "$hab" ]] || continue
mkdir -p "$DIST/firmware/$type_name"
cp "$hab" "$DIST/firmware/$type_name/"
found=1
done
done
if [[ "$found" -eq 0 ]]; then
echo " ⚠️ Ни один *_hab.bin не найден в {{ _prod_build_dir }} — соберите"
echo " прошивки заранее (just build::hab-all-release / hab-all-debug)."
fi
VERSION=$(grep -m1 '^version' pyproject.toml | sed -E 's/.*"(.+)".*/\1/')
case "$(uname -s)" in
Linux*) OS_TAG="linux" ;;
Darwin*) OS_TAG="macos" ;;
MINGW*|MSYS*|CYGWIN*) OS_TAG="windows" ;;
*) OS_TAG="unknown" ;;
esac
RELEASE_NAME="service-tui-v${VERSION}-${OS_TAG}"
rm -rf "dist/${RELEASE_NAME}"
mkdir -p "dist/${RELEASE_NAME}/custom_binaries"
mv "$DIST" "dist/${RELEASE_NAME}"
echo " ✅ dist/${RELEASE_NAME}"

View file

@ -171,6 +171,7 @@ add_host_test(
INCLUDES INCLUDES
${CMAKE_SOURCE_DIR}/firmware/test/src/ ${CMAKE_SOURCE_DIR}/firmware/test/src/
${CMAKE_SOURCE_DIR}/bsp/common/include ${CMAKE_SOURCE_DIR}/bsp/common/include
${CMAKE_SOURCE_DIR}/bsp/provisioning/include
MOCKS MOCKS
${BSP_MOCKS_DIR}) ${BSP_MOCKS_DIR})

View file

@ -18,8 +18,8 @@
DEFINE_FFF_GLOBALS; DEFINE_FFF_GLOBALS;
#include "clock_config.h" #include "clock_config.h"
#include "fsl_clock.h"
#include "fsl_flexcan.h" #include "fsl_flexcan.h"
/* ══════════════════════════════════════════════════════════════════════ /* ══════════════════════════════════════════════════════════════════════
* fff-фейки SDK-функций * fff-фейки SDK-функций
* */ * */
@ -47,6 +47,9 @@ FAKE_VOID_FUNC(FLEXCAN_ClearMbStatusFlags, CAN_Type *, uint64_t);
/* bsp_tick — управляемый «таймер» для тестов таймаутов */ /* bsp_tick — управляемый «таймер» для тестов таймаутов */
FAKE_VALUE_FUNC(uint32_t, bsp_tick_get_ms); FAKE_VALUE_FUNC(uint32_t, bsp_tick_get_ms);
/* ERRATA 50235 workaround (см. bsp_can_init()) */
FAKE_VOID_FUNC(CLOCK_EnableClock, clock_ip_name_t);
/* ══════════════════════════════════════════════════════════════════════ /* ══════════════════════════════════════════════════════════════════════
* Тестируемый модуль (после всех фейков!) * Тестируемый модуль (после всех фейков!)
* */ * */
@ -132,6 +135,7 @@ void setUp(void)
RESET_FAKE(FLEXCAN_GetMbStatusFlags); RESET_FAKE(FLEXCAN_GetMbStatusFlags);
RESET_FAKE(FLEXCAN_ClearMbStatusFlags); RESET_FAKE(FLEXCAN_ClearMbStatusFlags);
RESET_FAKE(bsp_tick_get_ms); RESET_FAKE(bsp_tick_get_ms);
RESET_FAKE(CLOCK_EnableClock);
FFF_RESET_HISTORY(); FFF_RESET_HISTORY();
s_mb_flags_call_count = 0U; s_mb_flags_call_count = 0U;
@ -162,6 +166,8 @@ void test_init_success(void)
TEST_ASSERT_EQUAL(1, FLEXCAN_Init_fake.call_count); TEST_ASSERT_EQUAL(1, FLEXCAN_Init_fake.call_count);
/* MB0 = reserved (ERR005829), MB1 = TX */ /* MB0 = reserved (ERR005829), MB1 = TX */
TEST_ASSERT_EQUAL(1, FLEXCAN_SetTxMbConfig_fake.call_count); TEST_ASSERT_EQUAL(1, FLEXCAN_SetTxMbConfig_fake.call_count);
TEST_ASSERT_EQUAL(1, CLOCK_EnableClock_fake.call_count);
TEST_ASSERT_EQUAL(kCLOCK_Lpuart1, CLOCK_EnableClock_fake.arg0_val);
} }
void test_init_null_config(void) void test_init_null_config(void)

View file

@ -11,7 +11,10 @@
* пока стек ещё жив (аргументы указатели на локальные буферы cli.c). * пока стек ещё жив (аргументы указатели на локальные буферы cli.c).
*/ */
#include "bsp/provisioning.h"
#include "bsp/status.h"
#include "fff.h" #include "fff.h"
#include "test_module.h"
#include "unity.h" #include "unity.h"
#include <stdbool.h> #include <stdbool.h>
@ -28,7 +31,11 @@ FAKE_VOID_FUNC(protocol_send_error, const char *);
FAKE_VOID_FUNC(test_runner_run_all); FAKE_VOID_FUNC(test_runner_run_all);
FAKE_VOID_FUNC(test_runner_run_single, const char *); FAKE_VOID_FUNC(test_runner_run_single, const char *);
FAKE_VOID_FUNC(test_runner_on_confirm, const char *, bool); FAKE_VOID_FUNC(test_runner_on_confirm, const char *, bool);
FAKE_VOID_FUNC(protocol_send_uid_response, const uint8_t *);
FAKE_VOID_FUNC(protocol_send_version_response);
FAKE_VOID_FUNC(test_runner_run_selected, const char *const *, size_t);
FAKE_VOID_FUNC(test_runner_send_list);
FAKE_VALUE_FUNC(bsp_status_t, bsp_prov_read_uid, uint8_t *, size_t);
/* ── Модуль под тестом ─────────────────────────────────────────────────── */ /* ── Модуль под тестом ─────────────────────────────────────────────────── */
#include "cli.h" #include "cli.h"
@ -72,6 +79,16 @@ static char s_run_single_id[32U];
static char s_confirm_id[32U]; static char s_confirm_id[32U];
static bool s_confirm_value; static bool s_confirm_value;
/* get_uid: cli.c передаёт указатель на СВОЙ стековый буфер — копируем
* по значению внутри custom_fake, иначе после возврата cli_process()
* указатель уже dangling (см. "Ловушка" в HOST_CREATE_TEST.md). */
static uint8_t s_captured_uid[BSP_PROV_UID_LEN];
/* run_selected: id_ptrs[] в cli.c указывает на локальный id_bufs[][] —
* та же ловушка, копируем строки, а не указатели. */
static size_t s_run_selected_count;
static char s_run_selected_ids[TEST_REGISTRY_MAX_SIZE][TEST_ID_MAX_SIZE];
static void capture_run_single(const char *p_id) static void capture_run_single(const char *p_id)
{ {
(void) snprintf(s_run_single_id, sizeof(s_run_single_id), "%s", p_id); (void) snprintf(s_run_single_id, sizeof(s_run_single_id), "%s", p_id);
@ -83,6 +100,31 @@ static void capture_on_confirm(const char *p_id, bool confirmed)
s_confirm_value = confirmed; s_confirm_value = confirmed;
} }
static void capture_uid_response(const uint8_t *p_uid)
{
memcpy(s_captured_uid, p_uid, BSP_PROV_UID_LEN);
}
static void capture_run_selected(const char *const *pp_ids, size_t count)
{
s_run_selected_count = count;
for (size_t i = 0U; i < count && i < TEST_REGISTRY_MAX_SIZE; i++)
{
(void) snprintf(s_run_selected_ids[i], sizeof(s_run_selected_ids[i]), "%s", pp_ids[i]);
}
}
/* Фиксированный UID, который "читает" bsp_prov_read_uid в тестах успеха. */
static const uint8_t K_TEST_UID[BSP_PROV_UID_LEN] = {
0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22
};
static bsp_status_t prov_read_uid_success(uint8_t *p_uid, size_t len)
{
(void) len;
memcpy(p_uid, K_TEST_UID, BSP_PROV_UID_LEN);
return BSP_OK;
}
/* ── setUp / tearDown ──────────────────────────────────────────────────── */ /* ── setUp / tearDown ──────────────────────────────────────────────────── */
void setUp(void) void setUp(void)
@ -94,16 +136,27 @@ void setUp(void)
RESET_FAKE(test_runner_run_all); RESET_FAKE(test_runner_run_all);
RESET_FAKE(test_runner_run_single); RESET_FAKE(test_runner_run_single);
RESET_FAKE(test_runner_on_confirm); RESET_FAKE(test_runner_on_confirm);
RESET_FAKE(protocol_send_uid_response);
RESET_FAKE(protocol_send_version_response);
RESET_FAKE(bsp_prov_read_uid);
RESET_FAKE(protocol_send_version_response);
RESET_FAKE(bsp_prov_read_uid);
RESET_FAKE(test_runner_run_selected);
RESET_FAKE(test_runner_send_list);
FFF_RESET_HISTORY(); FFF_RESET_HISTORY();
bsp_usb_cdc_read_fake.custom_fake = fake_usb_read; bsp_usb_cdc_read_fake.custom_fake = fake_usb_read;
test_runner_run_single_fake.custom_fake = capture_run_single; test_runner_run_single_fake.custom_fake = capture_run_single;
test_runner_on_confirm_fake.custom_fake = capture_on_confirm; test_runner_on_confirm_fake.custom_fake = capture_on_confirm;
protocol_send_uid_response_fake.custom_fake = capture_uid_response;
test_runner_run_selected_fake.custom_fake = capture_run_selected;
s_inject_len = 0U; s_inject_len = 0U;
s_run_single_id[0] = '\0'; s_run_single_id[0] = '\0';
s_confirm_id[0] = '\0'; s_confirm_id[0] = '\0';
s_confirm_value = false; s_confirm_value = false;
s_run_selected_count = 0U;
(void) memset(s_captured_uid, 0, sizeof(s_captured_uid));
cli_init(); cli_init();
} }
@ -138,6 +191,62 @@ void test_run_single_dispatches_with_id(void)
TEST_ASSERT_EQUAL_STRING("sdram", s_run_single_id); TEST_ASSERT_EQUAL_STRING("sdram", s_run_single_id);
} }
void test_get_uid_success(void)
{
bsp_prov_read_uid_fake.custom_fake = prov_read_uid_success;
inject("{\"type\":\"cmd\",\"cmd\":\"get_uid\"}\n");
TEST_ASSERT_EQUAL_INT(1, bsp_prov_read_uid_fake.call_count);
TEST_ASSERT_EQUAL_INT(1, protocol_send_uid_response_fake.call_count);
TEST_ASSERT_EQUAL_INT(0, protocol_send_error_fake.call_count);
TEST_ASSERT_EQUAL_UINT8_ARRAY(K_TEST_UID, s_captured_uid, BSP_PROV_UID_LEN);
}
void test_get_uid_read_failure_sends_error(void)
{
bsp_prov_read_uid_fake.return_val = BSP_ERR_PARAM;
inject("{\"type\":\"cmd\",\"cmd\":\"get_uid\"}\n");
TEST_ASSERT_EQUAL_INT(0, protocol_send_uid_response_fake.call_count);
TEST_ASSERT_EQUAL_INT(1, protocol_send_error_fake.call_count);
TEST_ASSERT_EQUAL_STRING("UID_READ_ERR", protocol_send_error_fake.arg0_val);
}
void test_get_version_dispatches(void)
{
inject("{\"type\":\"cmd\",\"cmd\":\"get_version\"}\n");
TEST_ASSERT_EQUAL_INT(1, protocol_send_version_response_fake.call_count);
TEST_ASSERT_EQUAL_INT(0, protocol_send_error_fake.call_count);
}
void test_list_tests_dispatches(void)
{
inject("{\"type\":\"cmd\",\"cmd\":\"list_tests\"}\n");
TEST_ASSERT_EQUAL_INT(1, test_runner_send_list_fake.call_count);
}
void test_run_selected_dispatches_with_ids(void)
{
inject("{\"type\":\"cmd\",\"cmd\":\"run_selected\",\"tests\":[\"sdram\",\"opto\"]}\n");
TEST_ASSERT_EQUAL_INT(1, test_runner_run_selected_fake.call_count);
TEST_ASSERT_EQUAL(2, s_run_selected_count);
TEST_ASSERT_EQUAL_STRING("sdram", s_run_selected_ids[0]);
TEST_ASSERT_EQUAL_STRING("opto", s_run_selected_ids[1]);
}
void test_run_selected_missing_tests_field_sends_parse_err(void)
{
inject("{\"type\":\"cmd\",\"cmd\":\"run_selected\"}\n");
TEST_ASSERT_EQUAL_INT(1, protocol_send_error_fake.call_count);
TEST_ASSERT_EQUAL_STRING("PARSE_ERR", protocol_send_error_fake.arg0_val);
}
void test_unknown_cmd_sends_unknown_cmd_error(void) void test_unknown_cmd_sends_unknown_cmd_error(void)
{ {
inject("{\"type\":\"cmd\",\"cmd\":\"reboot\"}\n"); inject("{\"type\":\"cmd\",\"cmd\":\"reboot\"}\n");
@ -262,5 +371,12 @@ int main(void)
RUN_TEST(test_crlf_handled_same_as_lf); RUN_TEST(test_crlf_handled_same_as_lf);
RUN_TEST(test_two_lines_in_one_chunk_both_dispatched); RUN_TEST(test_two_lines_in_one_chunk_both_dispatched);
RUN_TEST(test_get_uid_success);
RUN_TEST(test_get_uid_read_failure_sends_error);
RUN_TEST(test_get_version_dispatches);
RUN_TEST(test_list_tests_dispatches);
RUN_TEST(test_run_selected_dispatches_with_ids);
RUN_TEST(test_run_selected_missing_tests_field_sends_parse_err);
return UNITY_END(); return UNITY_END();
} }

View file

@ -0,0 +1,24 @@
#pragma once
/**
* @file fsl_clock.h
* @brief Stub fsl_clock.h для host-тестов.
*
* Содержит только то, что реально используется в:
* bsp/can/src/can.c ERRATA 50235 workaround, CLOCK_EnableClock(kCLOCK_Lpuart1)
*
* fff предоставляет реализацию через FAKE_VOID_FUNC в тестовом файле.
*
* Оригинал: sdk/devices/MIMXRT1052/drivers/fsl_clock.h
*/
/* ── clock_ip_name_t — только используемый член ──────────────────────────── */
typedef enum _clock_ip_name
{
kCLOCK_Lpuart1 = 0,
} clock_ip_name_t;
/* ── Function signature — реализуется через fff ──────────────────────────── */
void CLOCK_EnableClock(clock_ip_name_t name);

View file

@ -0,0 +1,19 @@
#pragma once
/**
* @file version.h
* @brief Stub version.h для host-тестов.
*
* Реальный version.h генерируется CMake (configure_file) из
* firmware/test/src/version.h.in только при конфигурации ARM-таргета
* firmware_test (BUILD_TESTS_TARGET=ON). В host-debug/host-release
* firmware/test/CMakeLists.txt не подключается generated/version.h
* не существует. Значения ниже фиксированные, участвуют только
* в сериализации протокола (session_start/version_response), не в логике.
*/
#define FIRMWARE_TEST_VERSION_MAJOR 0
#define FIRMWARE_TEST_VERSION_MINOR 0
#define FIRMWARE_TEST_VERSION_PATCH 0
#define FIRMWARE_TEST_VERSION_STR "0.0.0-host-test"

View file

@ -36,7 +36,7 @@ FAKE_VOID_FUNC(protocol_send_confirm_request, const confirm_params_t *);
FAKE_VOID_FUNC(protocol_send_error, const char *); FAKE_VOID_FUNC(protocol_send_error, const char *);
FAKE_VOID_FUNC(protocol_send_pong); FAKE_VOID_FUNC(protocol_send_pong);
FAKE_VOID_FUNC(protocol_send_session_start); FAKE_VOID_FUNC(protocol_send_session_start);
FAKE_VOID_FUNC(protocol_send_test_list, const test_module_t *const *, size_t);
/* ── Модуль под тестом ─────────────────────────────────────────────────── */ /* ── Модуль под тестом ─────────────────────────────────────────────────── */
#include "test_runner.h" #include "test_runner.h"
@ -131,6 +131,7 @@ void setUp(void)
RESET_FAKE(protocol_send_summary); RESET_FAKE(protocol_send_summary);
RESET_FAKE(protocol_send_confirm_request); RESET_FAKE(protocol_send_confirm_request);
RESET_FAKE(protocol_send_error); RESET_FAKE(protocol_send_error);
RESET_FAKE(protocol_send_test_list);
FFF_RESET_HISTORY(); FFF_RESET_HISTORY();
protocol_send_test_result_fake.custom_fake = capture_test_result; protocol_send_test_result_fake.custom_fake = capture_test_result;

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View file

@ -64,16 +64,24 @@ class ServiceApp(App):
""" """
После прошивки: После прошивки:
- firmware_test + успех PostFlashScreen (промпт смены BootMode) - firmware_test + успех PostFlashScreen (промпт смены BootMode)
- всё остальное (production/custom, либо ошибка) WaitingScreen - production/custom + успех WaitingScreen
- target=None маркер потери соединения (см. ConnectionWatcherMixin) - target=None обрыв USB (watcher в простое ИЛИ backend во время
WaitingScreen с явной причиной возврата активной операции, см. models.FlashResult, Фаза 4a вариант 2)
WaitingScreen с причиной (конкретный текст, если есть, иначе
общий fallback)
Логическая ошибка (плата на месте) сюда не долетает вовсе
FlashScreen в этом случае не покидает себя (см. _do_flash/_do_erase).
""" """
if event.preset is not None: if event.preset is not None:
self._last_flash_preset = event.preset self._last_flash_preset = event.preset
if event.target is None and not event.success: if event.target is None and not event.success:
self.switch_screen( self.switch_screen(
WaitingScreen(disconnect_reason="Соединение с платой потеряно") WaitingScreen(
disconnect_reason=event.error_message
or "Соединение с платой потеряно"
)
) )
return return

View file

@ -0,0 +1,536 @@
"""
flash_backend.py синхронное ядро прошивки MIMXRT1052 на spsdk Python API.
Прямой порт tools/host/flash_usb.py (subprocess sdphost/blhost) на прямые
вызовы spsdk (SDP/McuBoot/HabImage), провалидированные в Фазе 0
(spike_hab.py, spike_flash.py байт-в-байт и на живом железе, macOS+Windows).
Zero Textual/asyncio импортов модуль полностью синхронный и тестируемый
без event loop (см. test_flash_backend.py). Async-обвязка (asyncio.to_thread
+ run_coroutine_threadsafe) забота Flasher (Фаза 2), не этого модуля.
Открытые вопросы/допущения:
- Одна сессия McuBoot на весь flash()/erase_chip(), а не переоткрытие
на каждую операцию, как в CLI flash_usb.py.
- Имена FlashProgress.phase свои (не парсинг stdout blhost).
Фаза 4: SPSDKConnectionError оборачивается в ConnectionLostError на всех
трёх точках отказа (SDP write, McuBoot handshake+команды, McuBoot chip erase),
что позволяет Flasher/TUI отличить обрыв USB от логической ошибки через
поле connection_lost. USB-интерфейс, полученный из load_flashloader(),
закрывается в finally на любом исходе (защита от утечки HID-хэндла в
редком окне «wait_for_flashloader вернул интерфейс USB выдернут
McuBoot.__enter__ упал»).
"""
from __future__ import annotations
import hashlib
import logging
import os
import sys
import tempfile
import time
from pathlib import Path
from typing import Callable, Optional
from spsdk.exceptions import SPSDKConnectionError
from spsdk.image.hab.hab_image import HabImage
from spsdk.mboot import McuBoot, MbootUSBInterface
from spsdk.sdp import SDP, SdpUSBInterface
from spsdk.utils.config import Config
from spsdk.utils.exceptions import SPSDKTimeoutError
from .models import FlashProgress
from .usb_ports import UsbId, resolve_serial_port
logger = logging.getLogger(__name__)
ProgressCallback = Callable[[FlashProgress], None]
# ─── Пути ────────────────────────────────────────────────────────────────
# tools/production/app/flash_backend.py → корень репозитория
REPO_ROOT = Path(__file__).resolve().parents[3]
def _host_dcd_dir() -> Path:
"""Каталог с data-блобами (dcd.bin, ivt_flashloader.bin, *_fdcb.bin) —
двухрежимный резолв (Р6), симметричный firmware_hab_path() (Фаза 5).
Dev: tools/host/dcd/ (единый источник, использует и flash_usb.py).
Frozen: sys._MEIPASS/data см. service_tui.spec, который кладёт эти
же файлы в 'data/' внутри бандла (для onedir _MEIPASS == _internal/).
"""
if getattr(sys, "frozen", False):
return Path(sys._MEIPASS) / "data"
return REPO_ROOT / "tools" / "host" / "dcd"
def flashloader_bin_path() -> Path:
"""Путь к ivt_flashloader.bin (двухрежимный резолв, см. _host_dcd_dir)."""
return _host_dcd_dir() / "ivt_flashloader.bin"
def real_dcd_bin_path() -> Path:
"""Путь к dcd.bin (двухрежимный резолв, см. _host_dcd_dir)."""
return _host_dcd_dir() / "dcd.bin"
def fcb_blob_path(fcb_filename: str) -> Path:
"""Путь к готовому FCB-блобу (tools/host/dcd/w25q128_fdcb.bin и т.п.)."""
return _host_dcd_dir() / fcb_filename
def firmware_hab_path(firmware: str, build_type: str) -> Path:
"""Путь к готовому HAB-образу штатной прошивки (Р6, двухрежимный резолв)."""
if getattr(sys, "frozen", False):
base = Path(sys.executable).resolve().parent / "firmware"
else:
base = Path(os.environ.get("BUILD_DIR", str(REPO_ROOT / "build")))
return base / build_type / f"{firmware}_hab.bin"
# ─── USB VID:PID (те же переменные окружения, что уже приняты в проекте) ──
_BOOTROM_VID = int(os.environ.get("BOOTROM_VID", "0x1fc9"), 16)
_BOOTROM_PID = int(os.environ.get("BOOTROM_PID", "0x0130"), 16)
_FLASHLOADER_VID = int(os.environ.get("FLASHLOADER_VID", "0x15a2"), 16)
_FLASHLOADER_PID = int(os.environ.get("FLASHLOADER_PID", "0x0073"), 16)
_CDC_VID = int(os.environ.get("SERVICE_CDC_VID", "0x1996"), 16)
_CDC_PID = int(os.environ.get("SERVICE_CDC_PID", "0x00ad"), 16)
_SDP_DEVICE_ID = f"0x{_BOOTROM_VID:04x}:0x{_BOOTROM_PID:04x}"
_FLASHLOADER_DEVICE_ID = f"0x{_FLASHLOADER_VID:04x}:0x{_FLASHLOADER_PID:04x}"
# ─── Аппаратные константы (см. flash_usb.py — значения не менялись) ──────
FLASH_BASE = 0x60000000
HAB_OFFSET = 0x1000
FLASHLOADER_LOAD_ADDR = 0x20001C00
FLEXSPI_OPTION_ADDR = 0x2000
FLEXSPI_OPTION_VALUE = 0xC0000007
FLEXSPI_FCB_VALUE = 0xF000000F # tag=0xF → Write FCB command (auto-config)
FLEXSPI_MEMORY_ID = 9
ERASE_ALL_TIMEOUT_MS = 200_000 # эквивалент blhost -t 200000 (см. Фазу 0, ⚠В2)
FLASHLOADER_WAIT_TIMEOUT_S = 10.0
_HAB_OPTIONS_TEMPLATE = [
"options:",
" flags: 0x00",
" startAddress: 0x60000000",
" ivtOffset: 0x1000",
" initialLoadSize: 0x2000",
" family: mimxrt1050",
]
# ─── Исключения ────────────────────────────────────────────────────────────
class FlashBackendError(Exception):
"""Базовая ошибка flash_backend.
:cvar connection_lost: True если ошибка связана с потерей физического
соединения (USB выдернут, устройство пропало с шины). Позволяет
Flasher/TUI отличить обрыв от логической ошибки без парсинга
текста сообщения. По умолчанию False; подкласс ConnectionLostError
переопределяет на True.
"""
connection_lost: bool = False
def __init__(self, message: str, *, connection_lost: bool = False) -> None:
super().__init__(message)
# instance-level override — на случай, если базовый класс поднимается
# напрямую с connection_lost=True без использования ConnectionLostError
if connection_lost:
self.connection_lost = True
class ConnectionLostError(FlashBackendError):
"""Потеря USB-соединения посреди операции (обёртка над SPSDKConnectionError).
Обёртка над spsdk.exceptions.SPSDKConnectionError, поднимается при
исчезновении устройства с шины во время выполнения SDP/McuBoot команд.
Отличается от DeviceNotFoundError, который возникает ДО начала операции
(устройство никогда не было подключено).
"""
connection_lost: bool = True
def __init__(self, message: str) -> None:
super().__init__(message, connection_lost=True)
class DeviceNotFoundError(FlashBackendError):
"""SDP-устройство не найдено при попытке загрузить Flashloader."""
class FlashLoaderTimeoutError(FlashBackendError):
"""Flashloader не ответил за FLASHLOADER_WAIT_TIMEOUT_S после jump_and_run."""
class HabBuildError(FlashBackendError):
"""Ошибка сборки HAB-образа через HabImage (см. build_custom_hab)."""
# SPSDKTimeoutError НЕ наследует SPSDKConnectionError (оба — потомки SPSDKError,
# проверено по исходникам spsdk 3.7.0), поэтому один `except SPSDKConnectionError`
# его пропускал → safety net в Flasher показывал «Непредвиденная ошибка» вместо
# «Соединение потеряно» (Фаза 4a). Ловим оба явным кортежем в SDP/McuBoot-обёртках:
# read-фаза после write может отдать голый таймаут. Именованная константа вместо
# 4× инлайн-дублей.
_CONNECTION_LOST_EXCEPTIONS = (SPSDKConnectionError, SPSDKTimeoutError)
# ─── Detection (Р7 — spsdk API вместо pyusb) ───────────────────────────────
def detect_sdp() -> bool:
"""True если виден BootROM SDP (см. _SDP_DEVICE_ID)."""
return len(SdpUSBInterface.scan(device_id=_SDP_DEVICE_ID)) > 0
def detect_cdc() -> bool:
"""True если виден CDC firmware_test (список портов, см. usb_ports.py)."""
return resolve_serial_port(UsbId(_CDC_VID, _CDC_PID)) is not None
def _sdp_still_present() -> bool:
"""Быстрая проверка «плата ещё на шине» для error-путей (вариант B, Р10).
Любая ошибка самой проверки трактуется как «устройства нет»: проверка
выполняется только ПОСЛЕ уже случившегося сбоя команды, шина в этот
момент нестабильна, и «не смог проверить» практически всегда означает
«плату выдернули» (согласовано, RELEASE_ROADMAP.md §B).
"""
try:
return detect_sdp()
except Exception: # noqa: BLE001 — см. docstring: любой сбой ⇒ считаем обрывом
return False
def _fail_command(message: str) -> None:
"""Живая команда spsdk вернула False — переклассификация по варианту B (Р10).
Если устройство пропало с шины обрыв (ConnectionLostError), иначе
честная ошибка операции (FlashBackendError с прежним текстом). detect_sdp()
выполняется ТОЛЬКО здесь, в error-пути; happy path не затрагивается.
:raises ConnectionLostError: устройство исчезло с шины после сбоя команды.
:raises FlashBackendError: устройство на месте ошибка самой операции.
"""
if not _sdp_still_present():
raise ConnectionLostError(f"{message} (устройство пропало с шины)")
raise FlashBackendError(message)
def _emit(
progress_cb: Optional[ProgressCallback], phase: str, percent: int, message: str
) -> None:
if progress_cb is not None:
progress_cb(FlashProgress(phase=phase, percent=percent, message=message))
def _close_iface_quiet(iface: MbootUSBInterface) -> None:
"""Закрыть интерфейс в finally, глотая любые ошибки.
Внутри McuBoot() как context-manager закрытие уже происходит, поэтому
повторное close() на закрытом интерфейсе может выкинуть исключение
из libusbsio нам это не важно, мы просто хотим гарантию, что если
McuBoot.__enter__ упал (окно между load_flashloader и with McuBoot()),
интерфейс не остался висеть с открытым HID-хэндлом.
"""
try:
iface.close()
except Exception:
pass
# ─── Flashloader bring-up ───────────────────────────────────────────────────
def wait_for_flashloader(
timeout_s: float = FLASHLOADER_WAIT_TIMEOUT_S,
) -> MbootUSBInterface:
"""Опрашивает MbootUSBInterface.scan() пока Flashloader не поднимется.
:raises FlashLoaderTimeoutError: если не ответил за timeout_s.
"""
deadline = time.monotonic() + timeout_s
while time.monotonic() < deadline:
found = MbootUSBInterface.scan(device_id=_FLASHLOADER_DEVICE_ID)
if found:
return found[0]
time.sleep(0.5)
raise FlashLoaderTimeoutError(
f"Flashloader не ответил за {timeout_s:.0f}с. Проверь BOOT_MOD пины и подключение."
)
def load_flashloader(
progress_cb: Optional[ProgressCallback] = None,
) -> MbootUSBInterface:
"""Загружает Flashloader через SDP, если ещё не запущен.
:raises DeviceNotFoundError: SDP-устройство не найдено (и Flashloader тоже не поднят).
:raises FlashLoaderTimeoutError: см. wait_for_flashloader().
:raises ConnectionLostError: USB-соединение потеряно во время SDP-обмена.
"""
already = MbootUSBInterface.scan(device_id=_FLASHLOADER_DEVICE_ID)
if already:
logger.info("Flashloader уже запущен — пропускаем загрузку")
return already[0]
sdp_devices = SdpUSBInterface.scan(device_id=_SDP_DEVICE_ID)
if not sdp_devices:
raise DeviceNotFoundError(
f"SDP-устройство не найдено ({_SDP_DEVICE_ID}). Плата в BootROM-режиме?"
)
flashloader_bin = flashloader_bin_path()
if not flashloader_bin.exists():
raise FlashBackendError(f"Не найден: {flashloader_bin}")
_emit(
progress_cb,
"load_flashloader",
0,
f"Загрузка Flashloader через SDP ({_SDP_DEVICE_ID})",
)
data = flashloader_bin.read_bytes()
try:
with SDP(sdp_devices[0]) as sdp:
sdp.write_file(FLASHLOADER_LOAD_ADDR, data)
sdp.jump_and_run(FLASHLOADER_LOAD_ADDR)
except _CONNECTION_LOST_EXCEPTIONS as exc:
raise ConnectionLostError(
f"USB-соединение потеряно при загрузке Flashloader: {exc}"
) from exc
iface = wait_for_flashloader()
_emit(progress_cb, "load_flashloader", 100, "Flashloader готов")
return iface
# ─── FlexSPI / FCB ───────────────────────────────────────────────────────
def configure_flexspi(mboot: McuBoot) -> None:
"""Инициализирует FlexSPI NOR контроллер (см. flash_usb.py::configure_flexspi)."""
mboot.fill_memory(FLEXSPI_OPTION_ADDR, 4, FLEXSPI_OPTION_VALUE)
ok = mboot.configure_memory(FLEXSPI_OPTION_ADDR, FLEXSPI_MEMORY_ID)
if not ok:
_fail_command("configure_memory (FlexSPI init) вернул False")
def write_fcb_auto(mboot: McuBoot) -> None:
"""Auto-config FCB через magic option word (см. flash_usb.py::write_fcb).
Надёжно проверен только для W25Q128 см. docstring оригинала.
"""
mboot.fill_memory(FLEXSPI_OPTION_ADDR, 4, FLEXSPI_FCB_VALUE)
ok = mboot.configure_memory(FLEXSPI_OPTION_ADDR, FLEXSPI_MEMORY_ID)
if not ok:
_fail_command("configure_memory (FCB write) вернул False")
def write_fcb_explicit(mboot: McuBoot, fcb_path: Path) -> None:
"""Пишет буквальный FCB-блоб (512 байт) в Flash[FLASH_BASE] (custom-бинари).
См. flash_usb.py::write_fcb_explicit nxpimage не кладёт FCB в HAB-образ,
поэтому для произвольных чипов нужен явный блоб под конкретный memory chip.
"""
if not fcb_path.exists():
raise FlashBackendError(f"FCB-файл не найден: {fcb_path}")
data = fcb_path.read_bytes()
ok = mboot.write_memory(FLASH_BASE, data, mem_id=0)
if not ok:
_fail_command(f"write_memory(FCB {fcb_path.name}) вернул False")
# ─── Прошивка / RAM-load / erase ────────────────────────────────────────────
def flash(
hab_bin: Path,
*,
ram_only: bool = False,
fcb_path: Optional[Path] = None,
progress_cb: Optional[ProgressCallback] = None,
) -> None:
"""Прошить HAB-образ в Flash либо загрузить в RAM (см. flash_usb.py::flash).
:param hab_bin: Готовый HAB-образ (.bin). Для custom-бинарей см.
build_custom_hab().
:param ram_only: Загрузить в RAM через SDP, во Flash не писать.
:param fcb_path: Явный FCB-блоб (custom-бинари). None auto-config
(write_fcb_auto, только для штатных firmware_test/production).
:raises FlashBackendError: и подклассы на любой ошибке.
:raises ConnectionLostError: обрыв USB посреди операции.
"""
if not hab_bin.exists():
raise FlashBackendError(f"Файл не найден: {hab_bin}")
if ram_only:
_emit(progress_cb, "load_flashloader", 0, f"Загрузка в RAM: {hab_bin.name}")
sdp_devices = SdpUSBInterface.scan(device_id=_SDP_DEVICE_ID)
if not sdp_devices:
raise DeviceNotFoundError(f"SDP-устройство не найдено ({_SDP_DEVICE_ID})")
addr = FLASH_BASE + HAB_OFFSET
try:
with SDP(sdp_devices[0]) as sdp:
sdp.write_file(addr, hab_bin.read_bytes())
sdp.jump_and_run(addr)
except _CONNECTION_LOST_EXCEPTIONS as exc:
raise ConnectionLostError(
f"USB-соединение потеряно при RAM-загрузке: {exc}"
) from exc
_emit(progress_cb, "done", 100, "Загружено в RAM")
return
iface = load_flashloader(progress_cb)
write_addr = FLASH_BASE + HAB_OFFSET
hab_size = hab_bin.stat().st_size
erase_size = ((HAB_OFFSET + hab_size + 0xFFF) // 0x1000) * 0x1000
# try/finally гарантирует закрытие iface даже если McuBoot.__enter__ падает
# ДО того, как SDP context-manager отработает (тонкое окно, но реальное:
# wait_for_flashloader вернул интерфейс, USB выдернут до McuBoot handshake).
try:
with McuBoot(iface) as mboot:
_emit(progress_cb, "configure", 0, "Конфигурация FlexSPI NOR")
configure_flexspi(mboot)
_emit(
progress_cb,
"erase",
0,
f"Стирание 0x{FLASH_BASE:08X} + {erase_size} байт",
)
ok = mboot.flash_erase_region(FLASH_BASE, erase_size, mem_id=0)
if not ok:
_fail_command("flash_erase_region вернул False")
_emit(progress_cb, "fcb", 0, "Запись FCB")
if fcb_path is not None:
write_fcb_explicit(mboot, fcb_path)
else:
write_fcb_auto(mboot)
_emit(progress_cb, "write", 0, f"Запись {hab_bin.name} ({hab_size} байт)")
def _on_progress(current: int, total: int) -> None:
percent = int(current * 100 / total) if total else 0
_emit(progress_cb, "write", percent, f"{current}/{total} байт")
data = hab_bin.read_bytes()
ok = mboot.write_memory(
write_addr, data, mem_id=0, progress_callback=_on_progress
)
if not ok:
_fail_command("write_memory (HAB-образ) вернул False")
_emit(progress_cb, "reset", 0, "Reset")
mboot.reset(reopen=False)
except _CONNECTION_LOST_EXCEPTIONS as exc:
raise ConnectionLostError(
f"USB-соединение потеряно во время прошивки: {exc}"
) from exc
finally:
_close_iface_quiet(iface)
_emit(progress_cb, "done", 100, "Прошивка завершена успешно")
def erase_chip(progress_cb: Optional[ProgressCallback] = None) -> None:
"""Полная очистка Flash (см. flash_usb.py::erase_chip). После erase FCB
тоже стёрт плата не загрузится до следующей прошивки.
:raises ConnectionLostError: обрыв USB посреди chip erase.
"""
iface = load_flashloader(progress_cb)
try:
with McuBoot(iface) as mboot:
_emit(progress_cb, "configure", 0, "Конфигурация FlexSPI NOR")
configure_flexspi(mboot)
_emit(progress_cb, "erase", 0, "Полная очистка Flash (~30с)")
iface.device.timeout = ERASE_ALL_TIMEOUT_MS # см. Фазу 0, ⚠В2
ok = mboot.flash_erase_all(mem_id=FLEXSPI_MEMORY_ID)
if not ok:
_fail_command("flash_erase_all вернул False")
_emit(progress_cb, "reset", 0, "Reset")
mboot.reset(reopen=False)
except _CONNECTION_LOST_EXCEPTIONS as exc:
raise ConnectionLostError(
f"USB-соединение потеряно во время chip erase: {exc}"
) from exc
finally:
_close_iface_quiet(iface)
_emit(progress_cb, "done", 100, "Chip erase завершён")
# ─── HAB-сборка для custom-бинарей (Фаза 0, ⚠В1 — HabImage вместо nxpimage) ─
def _make_hab_config(input_bin: Path, dcd_bin: Optional[Path], work_dir: Path) -> Path:
"""YAML-конфиг nxpimage hab с АБСОЛЮТНЫМИ путями (Р6 — временный файл
может лежать где угодно, не обязательно рядом с реальными hab/*.yaml)."""
lines = list(_HAB_OPTIONS_TEMPLATE)
if dcd_bin is not None:
lines.append(f" DCDFilePath: {dcd_bin.resolve().as_posix()}")
lines.append(f'inputImageFile: "{input_bin.resolve().as_posix()}"')
lines.append("sections: []")
yaml_path = (
work_dir / f"hab_{hashlib.sha1(input_bin.name.encode()).hexdigest()[:8]}.yaml"
)
yaml_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
return yaml_path
def build_custom_hab(
raw_bin: Path,
use_dcd: bool,
progress_cb: Optional[ProgressCallback] = None,
) -> Path:
"""Собрать HAB-образ из сырого бинарника через HabImage (spsdk API).
Заменяет flasher.py::_build_custom_hab (subprocess nxpimage). Логика
сборки байт-в-байт идентична nxpimage CLI см. Фазу 0 (golden-тест).
:return: путь к собранному *.hab.bin во временной директории
(tempfile.gettempdir(), Р6). Вызывающий код отвечает за unlink
после использования так же, как сейчас делает Flasher.
:raises HabBuildError: при ошибке валидации/сборки.
"""
_emit(progress_cb, "hab_build", 0, "Сборка HAB-образа (HabImage)")
dcd_bin = real_dcd_bin_path() if use_dcd else None
if use_dcd and not dcd_bin.exists():
raise HabBuildError(f"DCD запрошен, но файл не найден: {dcd_bin}")
work_dir = Path(tempfile.mkdtemp(prefix="tui_hab_"))
try:
yaml_path = _make_hab_config(raw_bin, dcd_bin, work_dir)
cfg = Config.create_from_file(str(yaml_path))
schemas = HabImage.get_validation_schemas_from_cfg(cfg)
cfg.check(schemas, check_unknown_props=True)
hab = HabImage.load_from_config(cfg)
hab.post_export(cfg.config_dir)
data = hab.export()
except HabBuildError:
raise
except Exception as exc: # noqa: BLE001 — оборачиваем весь spsdk-зоопарк исключений
raise HabBuildError(f"Сборка HAB не удалась: {exc}") from exc
out_path = work_dir / f"{raw_bin.stem}_hab.bin"
out_path.write_bytes(data)
_emit(progress_cb, "hab_build", 100, f"HAB-образ собран: {len(data)} байт")
return out_path

View file

@ -1,10 +1,26 @@
""" """
flasher.py обёртка над tools/host/flash_usb.py для TUI. flasher.py async-обёртка над app/flash_backend.py для TUI.
Запускает flash_usb.py как subprocess, парсит stdout для прогресса, Фаза 2: внутренности переведены с subprocess (flash_usb.py) на прямые
пробрасывает события через asyncio.Queue в TUI. вызовы синхронного app/flash_backend.py через asyncio.to_thread. Публичный
API класса Flasher не менялся с Фазы 0 сигнатуры те же, что в исходной
subprocess-версии.
Не дублирует spsdk-окружение переиспользует tools/host/ uv-проект. Мост sync async для прогресса: flash_backend отдаёт события через
синхронный callback (вызывается из worker-потока asyncio.to_thread), здесь
он оборачивается в asyncio.run_coroutine_threadsafe(...).result()
согласовано с автором проекта (Фаза 2, вопрос 1): блокирующий .result()
внутри worker-потока гарантирует, что события прогресса приходят в TUI
строго по порядку.
Отмена прошивки посреди операции НЕ поддерживается и не должна
поддерживаться (согласовано, Фаза 2, вопрос 2) если стирание/запись уже
начались, они обязаны докрутиться до конца (успешно или с ошибкой).
Специального кода для этого не потребовалось: Python-поток, запущенный
через asyncio.to_thread, нельзя прервать снаружи если ожидающая
корутина в TUI получит CancelledError, сам поток всё равно продолжит
работу в фоне до естественного завершения flash_backend.flash()/
erase_chip(). Это и есть требуемое поведение, а не обходной путь.
Публичный API: Публичный API:
Flasher.flash(target, bin_path, progress_cb) async, прогресс через callback Flasher.flash(target, bin_path, progress_cb) async, прогресс через callback
@ -18,31 +34,24 @@ from __future__ import annotations
import asyncio import asyncio
import logging import logging
import os import os
import re import shutil
import sys import sys
import tempfile
from pathlib import Path from pathlib import Path
from typing import Awaitable, Callable, Optional from typing import Awaitable, Callable, Optional
from .models import FcbVariant, FlashProgress, FlashTarget from . import flash_backend
from .models import FcbVariant, FlashProgress, FlashResult, FlashTarget
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# VID/PID констант — читаются из env, fallback на известные значения
_BOOTROM_VID = int(os.environ.get("BOOTROM_VID", "0x1fc9"), 16)
_BOOTROM_PID = int(os.environ.get("BOOTROM_PID", "0x0130"), 16)
_CDC_VID = int(os.environ.get("SERVICE_CDC_VID", "0x1996"), 16)
_CDC_PID = int(os.environ.get("SERVICE_CDC_PID", "0x00ad"), 16)
# Тип сборки firmware_test для прошивки (Debug | Release). # Тип сборки firmware_test для прошивки (Debug | Release).
# Release временно нестабилен (см. отчёт о тестировании) — по умолчанию Debug. # Release временно нестабилен (см. отчёт о тестировании) — по умолчанию Debug.
_FIRMWARE_BUILD_TYPE = os.environ.get("FIRMWARE_BUILD_TYPE", "Debug") _FIRMWARE_BUILD_TYPE = os.environ.get("FIRMWARE_BUILD_TYPE", "Debug")
# Путь до flash_usb.py относительно корня репозитория
_FLASH_USB_SCRIPT = Path(__file__).parents[3] / "tools" / "host" / "flash_usb.py" def _firmware_hab_path(firmware: str) -> Path:
_HOST_TOOLS_DIR = _FLASH_USB_SCRIPT.parent """Делегирование в backend (Р6): dev/frozen резолв живёт там."""
_HAB_DIR = _HOST_TOOLS_DIR / "hab" return flash_backend.firmware_hab_path(firmware, _FIRMWARE_BUILD_TYPE)
_DCD_DIR = _HOST_TOOLS_DIR / "dcd"
def _resolve_custom_binaries_dir() -> Path: def _resolve_custom_binaries_dir() -> Path:
@ -67,103 +76,152 @@ def _resolve_custom_binaries_dir() -> Path:
CUSTOM_BINARIES_DIR = _resolve_custom_binaries_dir() CUSTOM_BINARIES_DIR = _resolve_custom_binaries_dir()
# Паттерны stdout flash_usb.py для извлечения прогресса
_RE_PERCENT = re.compile(r"(\d{1,3})\s*%")
_RE_PHASE = re.compile(r"(sdphost|blhost|Writing|Erasing|Verifying)", re.IGNORECASE)
ProgressCallback = Callable[[FlashProgress], Awaitable[None]] ProgressCallback = Callable[[FlashProgress], Awaitable[None]]
def _detect_usb(vid: int, pid: int) -> bool: def _make_sync_progress_cb(
progress_cb: Optional[ProgressCallback],
loop: asyncio.AbstractEventLoop,
) -> Optional[flash_backend.ProgressCallback]:
"""Мост sync (flash_backend, вызывается из worker-потока) → async (TUI).
.result() намеренно блокирующий вызов внутри worker-потока: гарантирует
доставку событий прогресса в порядке их возникновения (см. docstring
модуля). Исключения из progress_cb (например, если экран уже закрыт)
логируются и не прерывают саму операцию прошивки см. договорённость
по отмене (Фаза 2, вопрос 2): прошивка должна докрутиться до конца
независимо от состояния UI.
""" """
Проверить наличие USB-устройства по VID/PID (синхронно). if progress_cb is None:
return None
Два метода детекта: def _sync_cb(progress: FlashProgress) -> None:
1. pyusb (usb.core) видит все USB-устройства включая SDP bulk/HID. future = asyncio.run_coroutine_threadsafe(progress_cb(progress), loop)
На macOS SDP-устройство (1FC9:0130) не создаёт serial-порт try:
и невидимо через serial.tools.list_ports. future.result()
2. serial.tools.list_ports fallback для CDC ACM устройств. except Exception:
logger.exception("progress_cb выбросил исключение из TUI-потока")
return _sync_cb
def _format_error_message(exc: BaseException) -> str:
"""Человекочитаемое сообщение для FlashProgress(phase="error").
Для ConnectionLostError (и любого FlashBackendError с connection_lost=True)
добавляет явный префикс вариант А (согласовано): специального перехода
экрана нет, но в #flash-log причина должна читаться однозначно, без
необходимости лезть в общий лог-файл за трейсбеком.
""" """
# Метод 1: pyusb — работает для SDP и CDC connection_lost = getattr(exc, "connection_lost", False)
try: if connection_lost:
import usb.core return f"Соединение с платой потеряно: {exc}"
return str(exc)
dev = usb.core.find(idVendor=vid, idProduct=pid)
if dev is not None:
return True
except Exception:
pass
# Метод 2: serial list_ports — fallback для CDC ACM
try:
import serial.tools.list_ports
for info in serial.tools.list_ports.comports():
if info.vid == vid and info.pid == pid:
return True
except Exception:
pass
return False
class Flasher: class Flasher:
""" """
Async-обёртка над flash_usb.py. Async-обёртка над app/flash_backend.py.
Пример:: Пример::
flasher = Flasher() flasher = Flasher()
await flasher.flash(
target=FlashTarget.FIRMWARE_TEST, async def on_progress(p: FlashProgress) -> None:
progress_cb=lambda p: print(p.message), print(p.message)
)
await flasher.flash(target=FlashTarget.FIRMWARE_TEST, progress_cb=on_progress)
""" """
def __init__(self) -> None: # ── Detection (делегируется в flash_backend, см. Р7) ──────────────────
self._proc: Optional[asyncio.subprocess.Process] = None
# ── Detection ───────────────────────────────────────────────────────────
@staticmethod @staticmethod
def detect_sdp() -> bool: def detect_sdp() -> bool:
"""True если виден BootROM SDP (1FC9:0130).""" """True если виден BootROM SDP."""
return _detect_usb(_BOOTROM_VID, _BOOTROM_PID) return flash_backend.detect_sdp()
@staticmethod @staticmethod
def detect_cdc() -> bool: def detect_cdc() -> bool:
"""True если виден CDC firmware_test (1996:00AD).""" """True если виден CDC firmware_test."""
return _detect_usb(_CDC_VID, _CDC_PID) return flash_backend.detect_cdc()
@staticmethod @staticmethod
def list_custom_binaries() -> list[Path]: def list_custom_binaries() -> list[Path]:
"""Отсканировать custom_binaries/ на *.bin, отсортировано по имени.""" """Отсканировать custom_binaries/ на *.bin, отсортировано по имени."""
return sorted(CUSTOM_BINARIES_DIR.glob("*.bin")) return sorted(CUSTOM_BINARIES_DIR.glob("*.bin"))
# ── Erase ──────────────────────────────────────────────────────────────── # ── Общий раннер: flash_backend-операция в потоке + перевод ошибок ────
async def _run_flash_op(
self,
func: Callable[..., None],
*args: object,
async_progress_cb: Optional[ProgressCallback],
sync_progress_cb: Optional[flash_backend.ProgressCallback],
**kwargs: object,
) -> FlashResult:
"""Выполнить flash_backend.flash()/erase_chip() в потоке.
flash_backend поднимает FlashBackendError (включая ConnectionLostError,
см. Фазу 4) вместо возврата False здесь это конвертируется обратно
в контракт Flasher (FlashResult + событие phase="error"). connection_lost
транслируется из exc.connection_lost (Фаза 4a, вариант 2) экран
различает физический обрыв от логической ошибки без парсинга текста.
Отдельный except Exception safety net (Фаза 4, согласовано):
любое непредвиденное исключение из worker-потока (не только
FlashBackendError) обязано вернуть управление в TUI с ok=False,
а не оставить кнопки заблокированными навсегда. KeyboardInterrupt/
SystemExit/CancelledError не перехватываются это BaseException,
не Exception, пробрасываются как есть
"""
try:
await asyncio.to_thread(func, *args, progress_cb=sync_progress_cb, **kwargs)
return FlashResult(ok=True)
except flash_backend.FlashBackendError as exc:
logger.error("%s: %s", getattr(func, "__name__", func), exc)
if async_progress_cb is not None:
await async_progress_cb(
FlashProgress(
phase="error", percent=0, message=_format_error_message(exc)
)
)
return FlashResult(ok=False, connection_lost=exc.connection_lost)
except Exception as exc: # noqa: BLE001 — safety net, см. docstring
logger.exception(
"%s: непредвиденная ошибка", getattr(func, "__name__", func)
)
if async_progress_cb is not None:
await async_progress_cb(
FlashProgress(
phase="error",
percent=0,
message=f"Непредвиденная ошибка: {exc}",
)
)
return FlashResult(ok=False, connection_lost=False)
# ── Erase ────────────────────────────────────────────────────────────
async def erase_chip( async def erase_chip(
self, self,
progress_cb: Optional[ProgressCallback] = None, progress_cb: Optional[ProgressCallback] = None,
) -> bool: ) -> FlashResult:
""" """
Chip erase Flash через USB SDP (flash_usb.py --erase-chip). Chip erase Flash через USB SDP (flash_backend.erase_chip).
Занимает ~30 с для W25Q128. FCB будет стёрт. Занимает ~30 с для W25Q128. FCB будет стёрт.
:return: True при успехе. :return: FlashResult(ok, connection_lost) см. models.FlashResult.
""" """
cmd = [ loop = asyncio.get_running_loop()
"uv", sync_cb = _make_sync_progress_cb(progress_cb, loop)
"run", return await self._run_flash_op(
"--directory", flash_backend.erase_chip,
str(_HOST_TOOLS_DIR), async_progress_cb=progress_cb,
"python", sync_progress_cb=sync_cb,
str(_FLASH_USB_SCRIPT), )
"--erase-chip",
]
return await self._run_cmd(cmd, "erase", progress_cb)
# ── Flash ──────────────────────────────────────────────────────────────── # ── Flash ────────────────────────────────────────────────────────────
async def flash( async def flash(
self, self,
@ -172,259 +230,141 @@ class Flasher:
bin_path: Optional[Path] = None, bin_path: Optional[Path] = None,
use_dcd: bool = False, use_dcd: bool = False,
fcb_variant: FcbVariant = FcbVariant.W25Q128, fcb_variant: FcbVariant = FcbVariant.W25Q128,
) -> bool: ) -> FlashResult:
""" """
Запустить прошивку через flash_usb.py. Запустить прошивку через flash_backend.
:param target: Что прошиваем (firmware_test, production или custom). :param target: Что прошиваем (firmware_test, production или custom).
:param progress_cb: Async callback с FlashProgress (может быть None). :param progress_cb: Async callback с FlashProgress (может быть None).
:param bin_path: Путь к бинарю (обязателен для CUSTOM). :param bin_path: Путь к бинарю (обязателен для CUSTOM; для
FIRMWARE_TEST опционален, уже готовый HAB-образ
вместо штатной сборки из BUILD_DIR).
:param use_dcd: Только для CUSTOM включить DCDFilePath (SDRAM-init) :param use_dcd: Только для CUSTOM включить DCDFilePath (SDRAM-init)
при сборке HAB-образа через nxpimage. при сборке HAB-образа через HabImage.
:param fcb_variant: Только для CUSTOM какой явный FCB-блоб (dcd/*_fdcb.bin) :param fcb_variant: Только для CUSTOM какой явный FCB-блоб (dcd/*_fdcb.bin)
записать в Flash[0x60000000] вместо auto-config. записать в Flash[0x60000000] вместо auto-config.
:return: True при успехе. :return: FlashResult(ok, connection_lost) см. models.FlashResult.
""" """
loop = asyncio.get_running_loop()
sync_cb = _make_sync_progress_cb(progress_cb, loop)
if target == FlashTarget.FIRMWARE_TEST: if target == FlashTarget.FIRMWARE_TEST:
if bin_path is not None: hab_bin = (
return await self._run_flash_bin(bin_path, progress_cb) bin_path.resolve()
return await self._run_flash("firmware_test", progress_cb) if bin_path is not None
else _firmware_hab_path("firmware_test")
)
return await self._run_flash_op(
flash_backend.flash,
hab_bin,
async_progress_cb=progress_cb,
sync_progress_cb=sync_cb,
)
elif target == FlashTarget.PRODUCTION: elif target == FlashTarget.PRODUCTION:
ok = await self._run_flash("bootloader", progress_cb) result = await self._run_flash_op(
if ok: flash_backend.flash,
ok = await self._run_flash("app", progress_cb) _firmware_hab_path("bootloader"),
return ok async_progress_cb=progress_cb,
sync_progress_cb=sync_cb,
)
if result.ok:
result = await self._run_flash_op(
flash_backend.flash,
_firmware_hab_path("app"),
async_progress_cb=progress_cb,
sync_progress_cb=sync_cb,
)
return result
elif target == FlashTarget.CUSTOM: elif target == FlashTarget.CUSTOM:
if bin_path is None: if bin_path is None:
raise ValueError("FlashTarget.CUSTOM требует bin_path") raise ValueError("FlashTarget.CUSTOM требует bin_path")
return await self._run_flash_custom( return await self._flash_custom(
bin_path, use_dcd, fcb_variant, progress_cb bin_path, use_dcd, fcb_variant, progress_cb, sync_cb
) )
return False
async def _run_flash_custom( return FlashResult(ok=False)
async def _flash_custom(
self, self,
raw_bin_path: Path, raw_bin_path: Path,
use_dcd: bool, use_dcd: bool,
fcb_variant: FcbVariant, fcb_variant: FcbVariant,
progress_cb: Optional[ProgressCallback], progress_cb: Optional[ProgressCallback],
) -> bool: sync_cb: Optional[flash_backend.ProgressCallback],
) -> FlashResult:
""" """
Прошить «сырой» (не-HAB) кастомный бинарник из custom_binaries/. Прошить «сырой» (не-HAB) кастомный бинарник из custom_binaries/.
Два шага: Два шага:
1. Собрать HAB-образ (IVT + опционально DCD, БЕЗ FCB) через 1. Собрать HAB-образ (IVT + опционально DCD, БЕЗ FCB) через
nxpimage так же, как just build::hab-* собирает штатные flash_backend.build_custom_hab() (HabImage, см. Фазу 0) сам
прошивки, только конфиг генерируется на лету под выбранный файл. эмитит phase="hab_build" 0%/100% через sync_cb, отдельно
2. Прошить получившийся HAB-образ через flash_usb.py --bin-path, дублировать здесь не нужно.
подставив явный FCB-блоб (--fcb-path) под выбранный тип памяти 2. Прошить получившийся HAB-образ через flash_backend.flash(),
см. FcbVariant. подставив явный FCB-блоб под выбранный тип памяти (FcbVariant).
"""
if progress_cb is not None:
await progress_cb(
FlashProgress(
phase="nxpimage", percent=0, message="Сборка HAB-образа..."
)
)
hab_bin = await self._build_custom_hab(raw_bin_path, use_dcd, progress_cb) Временная директория build_custom_hab() (tempfile.mkdtemp) целиком
удаляется в finally не только *.bin, как было в subprocess-версии.
"""
hab_bin = await self._build_custom_hab(
raw_bin_path, use_dcd, progress_cb, sync_cb
)
if hab_bin is None: if hab_bin is None:
# Ошибка сборки HAB — чисто локальная операция (HabImage,
# временный файл), к USB-соединению отношения не имеет.
return FlashResult(ok=False)
fcb_path = flash_backend.fcb_blob_path(fcb_variant.fcb_filename)
try:
return await self._run_flash_op(
flash_backend.flash,
hab_bin,
fcb_path=fcb_path,
async_progress_cb=progress_cb,
sync_progress_cb=sync_cb,
)
finally:
shutil.rmtree(hab_bin.parent, ignore_errors=True)
async def _build_custom_hab(
self,
raw_bin_path: Path,
use_dcd: bool,
progress_cb: Optional[ProgressCallback],
sync_cb: Optional[flash_backend.ProgressCallback],
) -> Optional[Path]:
"""Обёртка над flash_backend.build_custom_hab() в потоке.
:return: путь к собранному *.hab.bin, либо None при ошибке.
"""
try:
return await asyncio.to_thread(
flash_backend.build_custom_hab,
raw_bin_path,
use_dcd,
progress_cb=sync_cb,
)
except flash_backend.FlashBackendError as exc:
logger.error("build_custom_hab: %s", exc)
if progress_cb is not None: if progress_cb is not None:
await progress_cb( await progress_cb(
FlashProgress( FlashProgress(
phase="error", phase="error",
percent=0, percent=0,
message="Ошибка сборки HAB-образа (nxpimage)", message=f"Ошибка сборки HAB-образа: {_format_error_message(exc)}",
) )
) )
return False return None
except Exception as exc: # noqa: BLE001 — safety net, см. _run_flash_op
fcb_path = _DCD_DIR / fcb_variant.fcb_filename logger.exception("build_custom_hab: непредвиденная ошибка")
try:
cmd = [
"uv",
"run",
"--directory",
str(_HOST_TOOLS_DIR),
"python",
str(_FLASH_USB_SCRIPT),
"--bin-path",
str(hab_bin),
"--fcb-path",
str(fcb_path),
]
return await self._run_cmd(cmd, raw_bin_path.stem, progress_cb)
finally:
hab_bin.unlink(missing_ok=True)
async def _build_custom_hab(
self,
raw_bin: Path,
use_dcd: bool,
progress_cb: Optional[ProgressCallback] = None,
) -> Optional[Path]:
"""
Собрать HAB-образ из сырого бинарника через nxpimage.
Временный YAML пишется прямо в tools/host/hab/ (как и штатные
hab_*.yaml) и nxpimage запускается с cwd=tools/host/hab/ это
обязательно: относительный DCDFilePath ("../dcd/dcd.bin") в
существующих конфигах резолвится именно так (см. build.just,
группа hab_image_gen `cd tools/host/hab && uv run nxpimage ...`).
Отходить от этой схемы рискованно nxpimage не документирует
явно, от чего резолвит относительные пути.
:return: путь к собранному *.hab.bin, либо None при ошибке nxpimage.
"""
yaml_f = tempfile.NamedTemporaryFile(
dir=_HAB_DIR, suffix=".yaml", prefix="_tui_custom_", delete=False
)
yaml_path = Path(yaml_f.name)
out_path = yaml_path.with_suffix(".hab.bin")
lines = [
"options:",
" flags: 0x00",
" startAddress: 0x60000000",
" ivtOffset: 0x1000",
" initialLoadSize: 0x2000",
" family: mimxrt1050",
]
if use_dcd:
lines.append(" DCDFilePath: ../dcd/dcd.bin")
lines.append(f'inputImageFile: "{raw_bin.resolve()}"')
lines.append("sections: []")
try:
yaml_f.write("\n".join(lines).encode("utf-8"))
yaml_f.close()
cmd = [
"uv",
"run",
"nxpimage",
"hab",
"export",
"--force",
"-c",
str(yaml_path),
"-o",
str(out_path),
]
logger.info("Building custom HAB image: %s", " ".join(cmd))
proc = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
cwd=str(_HAB_DIR),
)
assert proc.stdout is not None
async for raw_line in proc.stdout:
line = raw_line.decode("utf-8", errors="replace").rstrip()
logger.debug("nxpimage: %s", line)
if progress_cb is not None and line:
await progress_cb(
FlashProgress(phase="nxpimage", percent=0, message=line)
)
await proc.wait()
if proc.returncode != 0 or not out_path.exists():
logger.error("nxpimage hab export failed (rc=%s)", proc.returncode)
return None
return out_path
finally:
yaml_path.unlink(missing_ok=True)
async def _run_flash(
self,
firmware: str,
progress_cb: Optional[ProgressCallback],
) -> bool:
"""Запустить flash_usb.py для одного бинаря (стандартный firmware)."""
cmd = [
"uv",
"run",
"--directory",
str(_HOST_TOOLS_DIR),
"python",
str(_FLASH_USB_SCRIPT),
"--firmware",
firmware,
"--build-type",
_FIRMWARE_BUILD_TYPE,
]
return await self._run_cmd(cmd, firmware, progress_cb)
async def _run_flash_bin(
self,
bin_path: Path,
progress_cb: Optional[ProgressCallback],
) -> bool:
"""Запустить flash_usb.py для произвольного бинаря."""
cmd = [
"uv",
"run",
"--directory",
str(_HOST_TOOLS_DIR),
"python",
str(_FLASH_USB_SCRIPT),
"--bin-path",
str(bin_path.resolve()),
]
return await self._run_cmd(cmd, bin_path.stem, progress_cb)
async def _run_cmd(
self,
cmd: list[str],
label: str,
progress_cb: Optional[ProgressCallback],
) -> bool:
"""Общий subprocess runner для всех операций flash_usb.py."""
logger.info("Running: %s", " ".join(cmd))
try:
self._proc = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
cwd=str(_HOST_TOOLS_DIR),
)
assert self._proc.stdout is not None
async for raw_line in self._proc.stdout:
line = raw_line.decode("utf-8", errors="replace").rstrip()
logger.debug("flash_usb [%s]: %s", label, line)
if progress_cb is not None:
progress = _parse_progress(line)
if progress is not None:
await progress_cb(progress)
await self._proc.wait()
success = self._proc.returncode == 0
if progress_cb is not None:
phase = "done" if success else "error"
msg = "Завершено" if success else "Ошибка"
await progress_cb(FlashProgress(phase=phase, percent=100, message=msg))
return success
except Exception as exc:
logger.error("Subprocess error [%s]: %s", label, exc)
if progress_cb is not None: if progress_cb is not None:
await progress_cb( await progress_cb(
FlashProgress(phase="error", percent=0, message=str(exc)) FlashProgress(
phase="error",
percent=0,
message=f"Непредвиденная ошибка сборки HAB-образа: {exc}",
)
) )
return False return None
finally:
self._proc = None
def _parse_progress(line: str) -> Optional[FlashProgress]:
"""
Извлечь прогресс из строки stdout flash_usb.py.
Возвращает None если строка не несёт прогресс-информации.
"""
percent_m = _RE_PERCENT.search(line)
phase_m = _RE_PHASE.search(line)
if percent_m is None and phase_m is None:
return None
percent = int(percent_m.group(1)) if percent_m else 0
phase = phase_m.group(1).lower() if phase_m else "flash"
return FlashProgress(phase=phase, percent=percent, message=line.strip())

View file

@ -131,6 +131,26 @@ class ConfirmRequest:
class FlashProgress: class FlashProgress:
"""Прогресс прошивки.""" """Прогресс прошивки."""
phase: str # "sdphost" | "blhost" | "done" | "error" phase: str # "load_flashloader" | "configure" | "erase" | "fcb" | "write"
# | "reset" | "hab_build" | "done" | "error"
percent: int # 0..100 percent: int # 0..100
message: str message: str
@dataclass(frozen=True)
class FlashResult:
"""Результат Flasher.flash()/erase_chip() (Фаза 4a, вариант 2).
Раньше публичный API Flasher() возвращал голый bool экран не мог
отличить физический обрыв USB от логической ошибки (файл не найден,
битый custom-бинарь, ошибка сборки HAB) и одинаково уводил оператора
на WaitingScreen в обоих случаях, хотя при логической ошибке плата
остаётся на месте и разумнее остаться на FlashScreen.
connection_lost транслируется из FlashBackendError.connection_lost
(см. flash_backend.py) без парсинга текста сообщения тот же принцип,
что и там.
"""
ok: bool
connection_lost: bool = False

View file

@ -49,7 +49,20 @@ class FlashScreen(Screen, ConnectionWatcherMixin):
Если плата физически отключена в простое сессия считается Если плата физически отключена в простое сессия считается
недостоверной, экран сразу уходит на WaitingScreen (см. замечание недостоверной, экран сразу уходит на WaitingScreen (см. замечание
4 отчёта). Во время самой прошивки/erase мониторинг приостановлен 4 отчёта). Во время самой прошивки/erase мониторинг приостановлен
обрыв в этом случае обнаружит и обработает сам flash_usb.py subprocess. обрыв в этом случае обнаруживает сам flash_backend (SPSDKConnectionError
ConnectionLostError, см. Фазу 4) и репортит через #flash-log.
FlashResult (Фаза 4a, вариант 2) различает физический обрыв от
логической ошибки без парсинга текста см. models.FlashResult:
- connection_lost=True уходим на WaitingScreen (тот же маркер
target=None, что и watcher-детект в простое), текст ошибки
прокидывается через FlashDone.error_message, чтобы не терять
конкретику ради общего "Соединение с платой потеряно".
- connection_lost=False плата на месте, остаёмся на FlashScreen.
Раньше (до варианта 2) любая ошибка уводила на WaitingScreen,
который почти мгновенно переоткрывал FlashScreen заново (плата
на шине видна) и уничтожал #flash-log раньше, чем оператор
успевал прочитать (см. Гейт 4a, п.0 отчёта).
""" """
BINDINGS = [ BINDINGS = [
@ -62,17 +75,25 @@ class FlashScreen(Screen, ConnectionWatcherMixin):
success: bool, success: bool,
target: Optional[FlashTarget] = None, target: Optional[FlashTarget] = None,
preset: Optional[FlashPreset] = None, preset: Optional[FlashPreset] = None,
error_message: Optional[str] = None,
) -> None: ) -> None:
super().__init__() super().__init__()
self.success = success self.success = success
self.target = target self.target = target
self.preset = preset self.preset = preset
# Заполняется только при connection_lost=True — конкретный текст
# обрыва вместо общего "Соединение с платой потеряно" в app.py.
# При логической ошибке экран никуда не уходит (см. _do_flash),
# и это поле не используется.
self.error_message = error_message
def __init__(self, preset: Optional[FlashPreset] = None, **kwargs) -> None: def __init__(self, preset: Optional[FlashPreset] = None, **kwargs) -> None:
super().__init__(**kwargs) super().__init__(**kwargs)
self._flasher = Flasher() self._flasher = Flasher()
self._flashing = False self._flashing = False
self._preset = preset or FlashPreset() self._preset = preset or FlashPreset()
self._last_error_message: Optional[str] = None
self._write_log_bucket: int = -1 # см. _on_progress (Р11)
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
with AppFrame(id="flash-frame"): with AppFrame(id="flash-frame"):
@ -154,6 +175,8 @@ class FlashScreen(Screen, ConnectionWatcherMixin):
def _check_sdp_present(self) -> bool: def _check_sdp_present(self) -> bool:
# Не считаем потерей соединения, если идёт активная операция — # Не считаем потерей соединения, если идёт активная операция —
# flash_usb.py сам обработает реальный обрыв через subprocess. # flash_usb.py сам обработает реальный обрыв через subprocess.
# обрыв в этом случае обнаружит и обработает сам flash_backend
# (ConnectionLostError, см. Фазу 4), не watcher.
if self._flashing: if self._flashing:
return True return True
return Flasher.detect_sdp() return Flasher.detect_sdp()
@ -214,10 +237,12 @@ class FlashScreen(Screen, ConnectionWatcherMixin):
async def _do_flash( async def _do_flash(
self, target: FlashTarget, bin_path: Optional[Path], preset: FlashPreset self, target: FlashTarget, bin_path: Optional[Path], preset: FlashPreset
) -> None: ) -> None:
self._last_error_message = None
self._write_log_bucket = -1
self._set_busy(True) self._set_busy(True)
self._show_progress(True) self._show_progress(True)
self._log(f"▶ Прошивка: {target.value}") self._log(f"▶ Прошивка: {target.value}")
ok = await self._flasher.flash( result = await self._flasher.flash(
target=target, target=target,
bin_path=bin_path, bin_path=bin_path,
use_dcd=preset.use_dcd, use_dcd=preset.use_dcd,
@ -225,19 +250,47 @@ class FlashScreen(Screen, ConnectionWatcherMixin):
progress_cb=self._on_progress, progress_cb=self._on_progress,
) )
self._set_busy(False) self._set_busy(False)
self._finish_progress(ok) self._finish_progress(result.ok)
self._log("✅ Готово" if ok else "❌ Ошибка") self._log("✅ Готово" if result.ok else "❌ Ошибка")
self.post_message(self.FlashDone(success=ok, target=target, preset=preset))
if result.ok:
self.post_message(
self.FlashDone(success=True, target=target, preset=preset)
)
elif result.connection_lost:
# Обрыв во время активной прошивки — watcher в это время приглушён
# (см. _check_sdp_present), обрыв обнаружил сам backend. Тот же
# маркер target=None, что и у watcher-детекта в простое (Гейт 4a).
self.post_message(
self.FlashDone(
success=False,
target=None,
preset=preset,
error_message=self._last_error_message,
)
)
# else: логическая ошибка, плата на месте (вариант 2, Гейт 4a) —
# остаёмся на FlashScreen. Сообщение уже в #flash-log (_on_progress),
# кнопки уже разблокированы (_set_busy(False) выше).
@work(exclusive=True, thread=False) @work(exclusive=True, thread=False)
async def _do_erase(self) -> None: async def _do_erase(self) -> None:
self._last_error_message = None
self._set_busy(True) self._set_busy(True)
self._show_progress(True) self._show_progress(True)
self._log("⚠ Очистка памяти (~30 с)...") self._log("⚠ Очистка памяти (~30 с)...")
ok = await self._flasher.erase_chip(progress_cb=self._on_progress) result = await self._flasher.erase_chip(progress_cb=self._on_progress)
self._set_busy(False) self._set_busy(False)
self._finish_progress(ok) self._finish_progress(result.ok)
self._log("✅ Очистка памяти завершена" if ok else "❌ Очистка памяти: ошибка") self._log(
"✅ Очистка памяти завершена" if result.ok else "❌ Очистка памяти: ошибка"
)
if result.connection_lost:
self.post_message(
self.FlashDone(
success=False, target=None, error_message=self._last_error_message
)
)
# ── Вспомогательные ─────────────────────────────────────────────────────── # ── Вспомогательные ───────────────────────────────────────────────────────
@ -269,7 +322,20 @@ class FlashScreen(Screen, ConnectionWatcherMixin):
async def _on_progress(self, progress: FlashProgress) -> None: async def _on_progress(self, progress: FlashProgress) -> None:
bar = self.query_one("#flash-progress-bar", ProgressBar) bar = self.query_one("#flash-progress-bar", ProgressBar)
bar.update(total=100, progress=progress.percent) bar.update(total=100, progress=progress.percent)
if progress.phase == "write":
# Р11: без троттлинга запись HAB-образа даёт ~135 строк в лог
# (progress_callback spsdk дёргается на каждый пакет). Бар выше
# обновляется на КАЖДОМ событии — плавность не теряется,
# троттлинг только для #flash-log и только для фазы "write".
bucket = min(progress.percent // 10, 10)
if bucket == self._write_log_bucket:
return
self._write_log_bucket = bucket
self._log(progress.message) self._log(progress.message)
if progress.phase == "error":
self._last_error_message = progress.message
def _show_progress(self, visible: bool) -> None: def _show_progress(self, visible: bool) -> None:
"""Показать/скрыть прогресс-бар. Скрыт в простое — без анимации.""" """Показать/скрыть прогресс-бар. Скрыт в простое — без анимации."""

View file

@ -18,14 +18,14 @@ import logging
import tomllib import tomllib
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from textual import on
from textual.app import ComposeResult from textual.app import ComposeResult
from textual.containers import Center from textual.containers import Center, Horizontal
from textual.css.query import NoMatches from textual.css.query import NoMatches
from textual.message import Message from textual.message import Message
from textual.screen import Screen from textual.screen import Screen
from textual.timer import Timer from textual.timer import Timer
from textual.widgets import Static from textual.widgets import Button, Static
from ..boot_art import LOGO_ART from ..boot_art import LOGO_ART
from ..flasher import Flasher from ..flasher import Flasher
@ -92,6 +92,10 @@ class WaitingScreen(Screen):
yield Static("", id="waiting-reason", classes="hidden") yield Static("", id="waiting-reason", classes="hidden")
yield Static("Подключите плату индикатора к USB...", id="waiting-hint") yield Static("Подключите плату индикатора к USB...", id="waiting-hint")
yield Static(_SPINNER_FRAMES[0], id="waiting-spinner") yield Static(_SPINNER_FRAMES[0], id="waiting-spinner")
with Horizontal(id="waiting-btn-row"):
yield Button(
"✕ Выйти из приложения", id="waiting-btn-quit", variant="default"
)
def on_mount(self) -> None: def on_mount(self) -> None:
self._detect_timer = self.set_interval(_DETECT_INTERVAL_S, self._poll_usb) self._detect_timer = self.set_interval(_DETECT_INTERVAL_S, self._poll_usb)
@ -102,6 +106,12 @@ class WaitingScreen(Screen):
def on_unmount(self) -> None: def on_unmount(self) -> None:
self._stop_timers() self._stop_timers()
# ── Обработчики ───────────────────────────────────────────────────────────
@on(Button.Pressed, "#waiting-btn-quit")
def _on_quit_pressed(self) -> None:
self.app.exit()
# ── Internal ────────────────────────────────────────────────────────────── # ── Internal ──────────────────────────────────────────────────────────────
def _show_reason(self, reason: str) -> None: def _show_reason(self, reason: str) -> None:

View file

@ -0,0 +1,85 @@
"""
usb_ports.py резолвер serial-портов по VID:PID (Р8).
Принцип (см. MONOLITH_APP_PLAN.md §Р8): имя порта не переносимо даже в
пределах одной ОС (перевтыкание в другой физический разъём меняет имя:
cu.usbmodemXXXX / COMn / ttyACMn), поэтому единственный стабильный
идентификатор устройства VID:PID. Порядок резолва:
1. Явный override через переменную окружения (escape hatch).
2. Иначе поиск по VID:PID среди serial.tools.list_ports.comports().
3. Одно совпадение его имя порта.
4. Ноль совпадений None (штатное состояние: устройство не подключено,
для TUI это WaitingScreen, а не ошибка).
5. Несколько совпадений первое + warning в лог (дизамбигуация по
serial_number задел на будущее, см. MONOLITH_APP_PLAN.md §О3).
Модуль намеренно не хранит собственных VID/PID-констант они остаются
там же, где были (firmware_client.py, m5_client.py, flash_backend.py),
каждый со своим fallback-дефолтом, как уже принято в проекте.
"""
from __future__ import annotations
import logging
import os
from dataclasses import dataclass
from typing import Optional
import serial.tools.list_ports
logger = logging.getLogger(__name__)
@dataclass(frozen=True)
class UsbId:
"""VID:PID пара — единственный стабильный идентификатор USB-устройства."""
vid: int
pid: int
def __str__(self) -> str:
return f"{self.vid:04X}:{self.pid:04X}"
def resolve_serial_port(usb_id: UsbId, env_var: Optional[str] = None) -> Optional[str]:
"""
Найти serial-порт устройства по VID:PID.
:param usb_id: Идентичность устройства (VID:PID).
:param env_var: Имя переменной окружения-override (escape hatch, п.1
алгоритма). Если задана и непуста возвращается
as-is без обращения к list_ports; значение не
валидируется (ответственность вызывающего кода).
:return: Имя порта (например, "/dev/cu.usbmodem1101" или "COM8"),
либо None, если устройство не найдено.
"""
if env_var:
override = os.environ.get(env_var, "").strip()
if override:
logger.debug(
"resolve_serial_port(%s): override из %s = %s",
usb_id,
env_var,
override,
)
return override
matches = [
info.device
for info in serial.tools.list_ports.comports()
if info.vid == usb_id.vid and info.pid == usb_id.pid
]
if not matches:
return None
if len(matches) > 1:
logger.warning(
"Несколько устройств %s: %s — используем первое (%s). ",
usb_id,
matches,
matches[0],
)
return matches[0]

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View file

@ -0,0 +1 @@
Python.framework/Versions/3.14/Python

View file

@ -0,0 +1 @@
Versions/Current/Python

View file

@ -0,0 +1 @@
Versions/Current/Resources

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>Python</string>
<key>CFBundleIdentifier</key>
<string>org.python.python</string>
<key>CFBundleVersion</key>
<string>3.14.6</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleExecutable</key>
<string>Python</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleShortVersionString</key>
<string>3.14.6</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2001 Python Software Foundation. All rights reserved.</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,391 @@
/* ═══════════════════════════════════════════════════════════
service-tui — единый файл стилей
Путь резолвится относительно app/app.py → app/app.tcss
═══════════════════════════════════════════════════════════ */
/* ── Общая рамка приложения (AppFrame) ──────────────────── */
/* Все три экрана центрируют один AppFrame фиксированного */
/* размера — единообразный визуальный каркас независимо от */
/* размера окна терминала (как в ratatui-приложениях). */
Screen {
align: center middle;
}
AppFrame {
width: 100%;
height: 100%;
max-width: 112;
max-height: 40;
border: heavy $primary;
background: $surface;
padding: 1 2;
}
/* ── WaitingScreen ──────────────────────────────────────── */
#waiting-frame {
align: center top;
}
#waiting-logo-row {
width: 100%;
height: auto;
margin-top: 1;
}
#waiting-logo-art {
width: auto;
}
#waiting-version-row {
width: 100%;
height: auto;
margin-top: 1;
}
#waiting-version {
color: $warning;
text-style: bold;
text-align: center;
margin-bottom: 1;
}
#waiting-reason {
margin-top: 1;
padding: 1 2;
border: round $warning;
color: $warning;
text-style: bold;
content-align: center middle;
}
#waiting-reason.hidden {
display: none;
}
#waiting-hint {
margin-top: 2;
color: $text-muted;
content-align: center middle;
}
#waiting-spinner {
margin-top: 1;
color: $accent;
content-align: center middle;
}
/* ── FlashScreen ────────────────────────────────────────── */
#flash-title {
text-style: bold;
color: $warning;
margin-bottom: 1;
}
#flash-target-group {
border: round $panel;
padding: 1 2;
margin-bottom: 1;
height: auto;
max-height: 18;
overflow-y: auto;
}
#flash-target-group .section-title {
text-style: bold;
color: $text-muted;
padding: 0 0 1 0;
}
#flash-custom-group {
margin-top: 1;
height: auto;
}
#flash-custom-group.hidden {
display: none;
}
#flash-custom-select,
#flash-fcb-select {
width: 1fr;
margin-bottom: 1;
}
#flash-dcd-row {
height: auto;
align: left middle;
margin-top: 1;
}
#flash-dcd-switch {
margin-right: 1;
}
#flash-btn-row {
height: auto;
margin-top: 1;
align: left middle;
}
#flash-btn-flash,
#flash-btn-erase {
margin-right: 2;
}
#flash-btn-flash:disabled,
#flash-btn-erase:disabled,
#flash-btn-quit:disabled {
background: $panel;
color: $text-muted;
}
#flash-progress-bar {
margin-top: 1;
}
#flash-progress-bar.hidden {
display: none;
}
#flash-log {
height: 1fr;
min-height: 6;
margin-top: 1;
border: round $panel;
background: $surface-darken-1;
overflow-y: auto;
}
/* ── PostFlashScreen ────────────────────────────────────── */
#post-flash-frame {
align: center middle;
}
#post-flash-title {
text-style: bold;
color: $success;
content-align: center middle;
margin-bottom: 2;
}
#post-flash-instruction {
border: round $warning;
padding: 1 3;
color: $text;
text-style: bold;
content-align: center middle;
width: auto;
}
#post-flash-countdown {
margin-top: 2;
color: $text-muted;
content-align: center middle;
}
#post-flash-btn-row {
margin-top: 2;
height: auto;
align: center middle;
}
#post-flash-btn-ok {
margin-right: 2;
}
#post-flash-title-row,
#post-flash-instruction-row {
width: 100%;
height: auto;
}
/* ── DiagScreen ─────────────────────────────────────────── */
#diag-frame {
layout: vertical;
padding: 0;
}
#diag-header {
height: 3;
background: $panel;
padding: 0 2;
align: left middle;
}
#diag-header-fw {
width: auto;
min-width: 14;
color: $text-muted;
margin-right: 3;
}
#diag-header-uid {
width: auto;
min-width: 28;
color: $text-muted;
margin-right: 3;
}
#diag-header-m5 {
width: auto;
color: $success;
}
#diag-header-m5.m5-absent {
color: $text-muted;
}
#diag-main {
height: 1fr;
min-height: 10;
}
#diag-progress-row {
height: auto;
padding: 0 2;
}
#diag-progress-row.hidden {
display: none;
}
#diag-progress-bar {
height: 1;
margin-top: 1;
}
#diag-progress-label {
height: 1;
color: $text-muted;
}
#diag-btn-row {
height: 3;
align: left middle;
padding: 0 2;
background: $panel;
}
#diag-btn-run-selected,
#diag-btn-run-all {
margin-right: 2;
}
#diag-btn-run-selected:disabled,
#diag-btn-run-all:disabled {
background: $panel;
color: $text-muted;
}
/* ── TestListPanel ──────────────────────────────────────── */
TestListPanel {
width: 38;
border-right: solid $panel;
padding: 1 1;
overflow-y: auto;
}
TestListPanel .section-title {
text-style: bold;
color: $text-muted;
padding: 0 0 1 0;
}
#test-list-select-row {
height: auto;
margin-bottom: 1;
}
#test-list-select-row Button {
margin-right: 1;
min-width: 12;
}
.test-row {
height: auto;
align: left middle;
}
.test-row-hil-badge {
width: 6;
color: $accent;
}
.test-row-hil-badge.hil-disabled {
color: $text-muted;
}
/* ── ResultsPanel ───────────────────────────────────────── */
ResultsPanel {
width: 70;
padding: 1 2;
overflow-y: auto;
}
ResultsPanel .section-title {
text-style: bold;
color: $text-muted;
padding: 0 0 1 0;
}
#results-empty {
height: 1fr;
width: 100%;
}
#results-empty.hidden {
display: none;
}
#results-empty-text {
color: $text-muted;
text-align: center;
}
#results-table {
height: auto;
max-height: 100%;
}
#results-table.hidden {
display: none;
}
/* ── ConfirmPanel ───────────────────────────────────────── */
ConfirmPanel {
height: auto;
background: $warning 15%;
border-top: solid $warning;
padding: 1 2;
align: left middle;
}
ConfirmPanel.hidden {
display: none;
}
#confirm-prompt {
width: 1fr;
color: $warning;
text-style: bold;
}
#confirm-countdown {
color: $text-muted;
margin-right: 2;
}
#confirm-btn-ok {
margin-right: 1;
}
#confirm-btn-ok.hidden,
#confirm-btn-fail.hidden {
display: none;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,84 @@
Metadata-Version: 2.4
Name: click
Version: 8.4.2
Summary: Composable command line interface toolkit
Maintainer-email: Pallets <contact@palletsprojects.com>
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-Expression: BSD-3-Clause
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Typing :: Typed
License-File: LICENSE.txt
Requires-Dist: colorama; platform_system == 'Windows'
Project-URL: Changes, https://click.palletsprojects.com/page/changes/
Project-URL: Chat, https://discord.gg/pallets
Project-URL: Documentation, https://click.palletsprojects.com/
Project-URL: Donate, https://palletsprojects.com/donate
Project-URL: Source, https://github.com/pallets/click/
<div align="center"><img src="https://raw.githubusercontent.com/pallets/click/refs/heads/stable/docs/_static/click-name.svg" alt="" height="150"></div>
# Click
Click is a Python package for creating beautiful command line interfaces
in a composable way with as little code as necessary. It's the "Command
Line Interface Creation Kit". It's highly configurable but comes with
sensible defaults out of the box.
It aims to make the process of writing command line tools quick and fun
while also preventing any frustration caused by the inability to
implement an intended CLI API.
Click in three points:
- Arbitrary nesting of commands
- Automatic help page generation
- Supports lazy loading of subcommands at runtime
## A Simple Example
```python
import click
@click.command()
@click.option("--count", default=1, help="Number of greetings.")
@click.option("--name", prompt="Your name", help="The person to greet.")
def hello(count, name):
"""Simple program that greets NAME for a total of COUNT times."""
for _ in range(count):
click.echo(f"Hello, {name}!")
if __name__ == '__main__':
hello()
```
```
$ python hello.py --count=3
Your name: Click
Hello, Click!
Hello, Click!
Hello, Click!
```
## Donate
The Pallets organization develops and supports Click and other popular
packages. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, [please
donate today][].
[please donate today]: https://palletsprojects.com/donate
## Contributing
See our [detailed contributing documentation][contrib] for many ways to
contribute, including reporting issues, requesting features, asking or answering
questions, and making PRs.
[contrib]: https://palletsprojects.com/contributing/

View file

@ -0,0 +1,24 @@
click-8.4.2.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
click-8.4.2.dist-info/METADATA,sha256=GUyd2B1Wf5CB8CbH5AEGD7r6e8FHyOClizZotApkwDE,2621
click-8.4.2.dist-info/RECORD,,
click-8.4.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
click-8.4.2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
click-8.4.2.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475
click/__init__.py,sha256=FId2fXCSJB3yeWD-e2uON-mBhFa2Yc9MvXGmHu8OXG0,4634
click/_compat.py,sha256=gPNtXQ9q-G6Qil2b-MC5CsHsGGcQ4u6YSWy9_tlmuhc,18879
click/_termui_impl.py,sha256=CGdg24AeXijeGSzbu0Z7x3c4aaahVFjVBpEbbjhQ5K4,31730
click/_textwrap.py,sha256=7Z0N7Vmn-66TNSTUwp6OXJbcUXRmYET9h9c2ucD8oQQ,6270
click/_utils.py,sha256=eCZCtwJtsYD5QYkkNWJ8MY_8ABIjy8MczgMMyVY32rQ,996
click/_winconsole.py,sha256=KSxfNbMlYRa6GOJuCLgsg2Pb3dVkgJNPqLJPae-Pa10,8543
click/core.py,sha256=rZz76ihNTFV4Y2sxp3H-m93GxL2acD5Pqs0IobEvmuk,140616
click/decorators.py,sha256=9e1Ndu4jhGAcP6RGdNPAwAWtuP9hEs4ETp1u3lKmH1o,19709
click/exceptions.py,sha256=HvSY34G4auj_bYRR8-T8CU8Jwq_1-OcsRU4ezfozeEk,11862
click/formatting.py,sha256=8SW2KGkvjfz9Q1NbeojMHuZBN0cfnQJDs4mqDP6oXms,10444
click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923
click/parser.py,sha256=oJ-fU_3mvxugIuNtHaCATZ56lgEmHRggjJiSqEgYrjA,19052
click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
click/shell_completion.py,sha256=5tGGY5pV3mAZ17xT23OnuKrWqzEyyLVtrJ30npUxjkU,22618
click/termui.py,sha256=Vn9ehmrQl92z2_6R4bVZOsHUI6j8LrT8u0RzNZUpCvY,33213
click/testing.py,sha256=S9I-pspAlJH3RvZJWDQoJXb-M0nrAEJzXcUzrVXsT34,26458
click/types.py,sha256=9G4DB-nBj-omA_XWsYwbQ3H9BkpH82wJj-kxIPScKmA,44788
click/utils.py,sha256=XwrDxOzU__rnHn-rvJmJcD7ecbypUKMeDJQRjN2F-OA,20942

View file

@ -0,0 +1,4 @@
Wheel-Version: 1.0
Generator: flit 3.12.0
Root-Is-Purelib: true
Tag: py3-none-any

View file

@ -0,0 +1,28 @@
Copyright 2014 Pallets
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,139 @@
Metadata-Version: 2.4
Name: cryptography
Version: 46.0.7
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX
Classifier: Operating System :: POSIX :: BSD
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
Classifier: Topic :: Security :: Cryptography
Requires-Dist: cffi>=1.14 ; python_full_version == '3.8.*' and platform_python_implementation != 'PyPy'
Requires-Dist: cffi>=2.0.0 ; python_full_version >= '3.9' and platform_python_implementation != 'PyPy'
Requires-Dist: typing-extensions>=4.13.2 ; python_full_version < '3.11'
Requires-Dist: bcrypt>=3.1.5 ; extra == 'ssh'
Requires-Dist: nox[uv]>=2024.4.15 ; extra == 'nox'
Requires-Dist: cryptography-vectors==46.0.7 ; extra == 'test'
Requires-Dist: pytest>=7.4.0 ; extra == 'test'
Requires-Dist: pytest-benchmark>=4.0 ; extra == 'test'
Requires-Dist: pytest-cov>=2.10.1 ; extra == 'test'
Requires-Dist: pytest-xdist>=3.5.0 ; extra == 'test'
Requires-Dist: pretend>=0.7 ; extra == 'test'
Requires-Dist: certifi>=2024 ; extra == 'test'
Requires-Dist: pytest-randomly ; extra == 'test-randomorder'
Requires-Dist: sphinx>=5.3.0 ; extra == 'docs'
Requires-Dist: sphinx-rtd-theme>=3.0.0 ; extra == 'docs'
Requires-Dist: sphinx-inline-tabs ; extra == 'docs'
Requires-Dist: pyenchant>=3 ; extra == 'docstest'
Requires-Dist: readme-renderer>=30.0 ; extra == 'docstest'
Requires-Dist: sphinxcontrib-spelling>=7.3.1 ; extra == 'docstest'
Requires-Dist: build>=1.0.0 ; extra == 'sdist'
Requires-Dist: ruff>=0.11.11 ; extra == 'pep8test'
Requires-Dist: mypy>=1.14 ; extra == 'pep8test'
Requires-Dist: check-sdist ; extra == 'pep8test'
Requires-Dist: click>=8.0.1 ; extra == 'pep8test'
Provides-Extra: ssh
Provides-Extra: nox
Provides-Extra: test
Provides-Extra: test-randomorder
Provides-Extra: docs
Provides-Extra: docstest
Provides-Extra: sdist
Provides-Extra: pep8test
License-File: LICENSE
License-File: LICENSE.APACHE
License-File: LICENSE.BSD
Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers.
Author-email: The Python Cryptographic Authority and individual contributors <cryptography-dev@python.org>
License-Expression: Apache-2.0 OR BSD-3-Clause
Requires-Python: >=3.8, !=3.9.0, !=3.9.1
Description-Content-Type: text/x-rst; charset=UTF-8
Project-URL: homepage, https://github.com/pyca/cryptography
Project-URL: documentation, https://cryptography.io/
Project-URL: source, https://github.com/pyca/cryptography/
Project-URL: issues, https://github.com/pyca/cryptography/issues
Project-URL: changelog, https://cryptography.io/en/latest/changelog/
pyca/cryptography
=================
.. image:: https://img.shields.io/pypi/v/cryptography.svg
:target: https://pypi.org/project/cryptography/
:alt: Latest Version
.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest
:target: https://cryptography.io
:alt: Latest Docs
.. image:: https://github.com/pyca/cryptography/actions/workflows/ci.yml/badge.svg
:target: https://github.com/pyca/cryptography/actions/workflows/ci.yml?query=branch%3Amain
``cryptography`` is a package which provides cryptographic recipes and
primitives to Python developers. Our goal is for it to be your "cryptographic
standard library". It supports Python 3.8+ and PyPy3 7.3.11+.
``cryptography`` includes both high level recipes and low level interfaces to
common cryptographic algorithms such as symmetric ciphers, message digests, and
key derivation functions. For example, to encrypt something with
``cryptography``'s high level symmetric encryption recipe:
.. code-block:: pycon
>>> from cryptography.fernet import Fernet
>>> # Put this somewhere safe!
>>> key = Fernet.generate_key()
>>> f = Fernet(key)
>>> token = f.encrypt(b"A really secret message. Not for prying eyes.")
>>> token
b'...'
>>> f.decrypt(token)
b'A really secret message. Not for prying eyes.'
You can find more information in the `documentation`_.
You can install ``cryptography`` with:
.. code-block:: console
$ pip install cryptography
For full details see `the installation documentation`_.
Discussion
~~~~~~~~~~
If you run into bugs, you can file them in our `issue tracker`_.
We maintain a `cryptography-dev`_ mailing list for development discussion.
You can also join ``#pyca`` on ``irc.libera.chat`` to ask questions or get
involved.
Security
~~~~~~~~
Need to report a security issue? Please consult our `security reporting`_
documentation.
.. _`documentation`: https://cryptography.io/
.. _`the installation documentation`: https://cryptography.io/en/latest/installation/
.. _`issue tracker`: https://github.com/pyca/cryptography/issues
.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev
.. _`security reporting`: https://cryptography.io/en/latest/security/

View file

@ -0,0 +1,109 @@
cryptography-46.0.7.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
cryptography-46.0.7.dist-info/METADATA,sha256=zW5_rTueQjaDE9RZqkkUvVnzmJOCgUWgAhn7xhx1z_E,5748
cryptography-46.0.7.dist-info/RECORD,,
cryptography-46.0.7.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
cryptography-46.0.7.dist-info/WHEEL,sha256=vDyXGwAe_QBpYw-jD8eU-EbjMjQEXHzUZDoiosetxRI,108
cryptography-46.0.7.dist-info/licenses/LICENSE,sha256=Pgx8CRqUi4JTO6mP18u0BDLW8amsv4X1ki0vmak65rs,197
cryptography-46.0.7.dist-info/licenses/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360
cryptography-46.0.7.dist-info/licenses/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532
cryptography/__about__.py,sha256=gqlbnDo1OfcbS26uUxuoIbg0fLAR7YZMVNMBWcqjG2A,445
cryptography/__init__.py,sha256=mthuUrTd4FROCpUYrTIqhjz6s6T9djAZrV7nZ1oMm2o,364
cryptography/exceptions.py,sha256=835EWILc2fwxw-gyFMriciC2SqhViETB10LBSytnDIc,1087
cryptography/fernet.py,sha256=3Cvxkh0KJSbX8HbnCHu4wfCW7U0GgfUA3v_qQ8a8iWc,6963
cryptography/hazmat/__init__.py,sha256=5IwrLWrVp0AjEr_4FdWG_V057NSJGY_W4egNNsuct0g,455
cryptography/hazmat/_oid.py,sha256=p8ThjwJB56Ci_rAIrjyJ1f8VjgD6e39es2dh8JIUBOw,17240
cryptography/hazmat/asn1/__init__.py,sha256=hS_EWx3wVvZzfbCcNV8hzcDnyMM8H-BhIoS1TipUosk,293
cryptography/hazmat/asn1/asn1.py,sha256=eMEThEXa19LQjcyVofgHsW6tsZnjp3ddH7bWkkcxfLM,3860
cryptography/hazmat/backends/__init__.py,sha256=O5jvKFQdZnXhKeqJ-HtulaEL9Ni7mr1mDzZY5kHlYhI,361
cryptography/hazmat/backends/openssl/__init__.py,sha256=p3jmJfnCag9iE5sdMrN6VvVEu55u46xaS_IjoI0SrmA,305
cryptography/hazmat/backends/openssl/backend.py,sha256=tV5AxBoFJ2GfA0DMWSY-0TxQJrpQoexzI9R4Kybb--4,10215
cryptography/hazmat/bindings/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
cryptography/hazmat/bindings/_rust.abi3.so,sha256=ZkawmMdHvWppIFsThPZwMAFjqMcDpUqtQUeTdnbdJ-Q,21036640
cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=KhqLhXFPArPzzJ7DYO9Fl8FoXB_BagAd_r4Dm_Ze9Xo,1257
cryptography/hazmat/bindings/_rust/_openssl.pyi,sha256=mpNJLuYLbCVrd5i33FBTmWwL_55Dw7JPkSLlSX9Q7oI,230
cryptography/hazmat/bindings/_rust/asn1.pyi,sha256=BrGjC8J6nwuS-r3EVcdXJB8ndotfY9mbQYOfpbPG0HA,354
cryptography/hazmat/bindings/_rust/declarative_asn1.pyi,sha256=2ECFmYue1EPkHEE2Bm7aLwkjB0mSUTpr23v9MN4pri4,892
cryptography/hazmat/bindings/_rust/exceptions.pyi,sha256=exXr2xw_0pB1kk93cYbM3MohbzoUkjOms1ZMUi0uQZE,640
cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=VPVWuKHI9EMs09ZLRYAGvR0Iz0mCMmEzXAkgJHovpoM,4020
cryptography/hazmat/bindings/_rust/openssl/__init__.pyi,sha256=iOAMDyHoNwwCSZfZzuXDr64g4GpGUeDgEN-LjXqdrBM,1522
cryptography/hazmat/bindings/_rust/openssl/aead.pyi,sha256=4Nddw6-ynzIB3w2W86WvkGKTLlTDk_6F5l54RHCuy3E,2688
cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi,sha256=LhPzHWSXJq4grAJXn6zSvSSdV-aYIIscHDwIPlJGGPs,1315
cryptography/hazmat/bindings/_rust/openssl/cmac.pyi,sha256=nPH0X57RYpsAkRowVpjQiHE566ThUTx7YXrsadmrmHk,564
cryptography/hazmat/bindings/_rust/openssl/dh.pyi,sha256=Z3TC-G04-THtSdAOPLM1h2G7ml5bda1ElZUcn5wpuhk,1564
cryptography/hazmat/bindings/_rust/openssl/dsa.pyi,sha256=qBtkgj2albt2qFcnZ9UDrhzoNhCVO7HTby5VSf1EXMI,1299
cryptography/hazmat/bindings/_rust/openssl/ec.pyi,sha256=zJy0pRa5n-_p2dm45PxECB_-B6SVZyNKfjxFDpPqT38,1691
cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi,sha256=VXfXd5G6hUivg399R1DYdmW3eTb0EebzDTqjRC2gaRw,532
cryptography/hazmat/bindings/_rust/openssl/ed448.pyi,sha256=Yx49lqdnjsD7bxiDV1kcaMrDktug5evi5a6zerMiy2s,514
cryptography/hazmat/bindings/_rust/openssl/hashes.pyi,sha256=OWZvBx7xfo_HJl41Nc--DugVyCVPIprZ3HlOPTSWH9g,984
cryptography/hazmat/bindings/_rust/openssl/hmac.pyi,sha256=BXZn7NDjL3JAbYW0SQ8pg1iyC5DbQXVhUAiwsi8DFR8,702
cryptography/hazmat/bindings/_rust/openssl/kdf.pyi,sha256=xXfFBb9QehHfDtEaxV_65Z0YK7NquOVIChpTLkgAs_k,2029
cryptography/hazmat/bindings/_rust/openssl/keys.pyi,sha256=teIt8M6ZEMJrn4s3W0UnW0DZ-30Jd68WnSsKKG124l0,912
cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi,sha256=_SW9NtQ5FDlAbdclFtWpT4lGmxKIKHpN-4j8J2BzYfQ,585
cryptography/hazmat/bindings/_rust/openssl/rsa.pyi,sha256=2OQCNSXkxgc-3uw1xiCCloIQTV6p9_kK79Yu0rhZgPc,1364
cryptography/hazmat/bindings/_rust/openssl/x25519.pyi,sha256=ewn4GpQyb7zPwE-ni7GtyQgMC0A1mLuqYsSyqv6nI_s,523
cryptography/hazmat/bindings/_rust/openssl/x448.pyi,sha256=juTZTmli8jO_5Vcufg-vHvx_tCyezmSLIh_9PU3TczI,505
cryptography/hazmat/bindings/_rust/pkcs12.pyi,sha256=vEEd5wDiZvb8ZGFaziLCaWLzAwoG_tvPUxLQw5_uOl8,1605
cryptography/hazmat/bindings/_rust/pkcs7.pyi,sha256=txGBJijqZshEcqra6byPNbnisIdlxzOSIHP2hl9arPs,1601
cryptography/hazmat/bindings/_rust/test_support.pyi,sha256=PPhld-WkO743iXFPebeG0LtgK0aTzGdjcIsay1Gm5GE,757
cryptography/hazmat/bindings/_rust/x509.pyi,sha256=n9X0IQ6ICbdIi-ExdCFZoBgeY6njm3QOVAVZwDQdnbk,9784
cryptography/hazmat/bindings/openssl/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
cryptography/hazmat/bindings/openssl/_conditional.py,sha256=DMOpA_XN4l70zTc5_J9DpwlbQeUBRTWpfIJ4yRIn1-U,5791
cryptography/hazmat/bindings/openssl/binding.py,sha256=x8eocEmukO4cm7cHqfVmOoYY7CCXdoF1v1WhZQt9neo,4610
cryptography/hazmat/decrepit/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216
cryptography/hazmat/decrepit/ciphers/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216
cryptography/hazmat/decrepit/ciphers/algorithms.py,sha256=YrKgHS4MfwWaMmPBYRymRRlC0phwWp9ycICFezeJPGk,2595
cryptography/hazmat/primitives/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
cryptography/hazmat/primitives/_asymmetric.py,sha256=RhgcouUB6HTiFDBrR1LxqkMjpUxIiNvQ1r_zJjRG6qQ,532
cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=Eh3i7lwedHfi0eLSsH93PZxQKzY9I6lkK67vL4V5tOc,1522
cryptography/hazmat/primitives/_serialization.py,sha256=chgPCSF2jxI2Cr5gB-qbWXOvOfupBh4CARS0KAhv9AM,5123
cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
cryptography/hazmat/primitives/asymmetric/dh.py,sha256=0v_vEFFz5pQ1QG-FkWDyvgv7IfuVZSH5Q6LyFI5A8rg,3645
cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=Ld_bbbqQFz12dObHxIkzEQzX0SWWP41RLSWkYSaKhqE,4213
cryptography/hazmat/primitives/asymmetric/ec.py,sha256=dj0ZR_jTVI1wojjipjbXNVccPSIRObWxSZcTGQKGbHc,13437
cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=jZW5cs472wXXV3eB0sE1b8w64gdazwwU0_MT5UOTiXs,3700
cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=yAetgn2f2JYf0BO8MapGzXeThsvSMG5LmUCrxVOidAA,3729
cryptography/hazmat/primitives/asymmetric/padding.py,sha256=vQ6l6gOg9HqcbOsvHrSiJRVLdEj9L4m4HkRGYziTyFA,2854
cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=ZnKOo2f34MCCOupC03Y1uR-_jiSG5IrelHEmxaME3D4,8303
cryptography/hazmat/primitives/asymmetric/types.py,sha256=LnsOJym-wmPUJ7Knu_7bCNU3kIiELCd6krOaW_JU08I,2996
cryptography/hazmat/primitives/asymmetric/utils.py,sha256=DPTs6T4F-UhwzFQTh-1fSEpQzazH2jf2xpIro3ItF4o,790
cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=_4nQeZ3yJ3Lg0RpXnaqA-1yt6vbx1F-wzLcaZHwSpeE,3613
cryptography/hazmat/primitives/asymmetric/x448.py,sha256=WKBLtuVfJqiBRro654fGaQAlvsKbqbNkK7c4A_ZCdV0,3642
cryptography/hazmat/primitives/ciphers/__init__.py,sha256=eyEXmjk6_CZXaOPYDr7vAYGXr29QvzgWL2-4CSolLFs,680
cryptography/hazmat/primitives/ciphers/aead.py,sha256=Fzlyx7w8KYQakzDp1zWgJnIr62zgZrgVh1u2h4exB54,634
cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=Q7ZJwcsx83Mgxv5y7r6CyJKSdsOwC-my-5A67-ma2vw,3407
cryptography/hazmat/primitives/ciphers/base.py,sha256=aBC7HHBBoixebmparVr0UlODs3VD0A7B6oz_AaRjDv8,4253
cryptography/hazmat/primitives/ciphers/modes.py,sha256=20stpwhDtbAvpH0SMf9EDHIciwmTF-JMBUOZ9bU8WiQ,8318
cryptography/hazmat/primitives/cmac.py,sha256=sz_s6H_cYnOvx-VNWdIKhRhe3Ymp8z8J0D3CBqOX3gg,338
cryptography/hazmat/primitives/constant_time.py,sha256=xdunWT0nf8OvKdcqUhhlFKayGp4_PgVJRU2W1wLSr_A,422
cryptography/hazmat/primitives/hashes.py,sha256=M8BrlKB3U6DEtHvWTV5VRjpteHv1kS3Zxm_Bsk04cr8,5184
cryptography/hazmat/primitives/hmac.py,sha256=RpB3z9z5skirCQrm7zQbtnp9pLMnAjrlTUvKqF5aDDc,423
cryptography/hazmat/primitives/kdf/__init__.py,sha256=4XibZnrYq4hh5xBjWiIXzaYW6FKx8hPbVaa_cB9zS64,750
cryptography/hazmat/primitives/kdf/argon2.py,sha256=UFDNXG0v-rw3DqAQTB1UQAsQC2M5Ejg0k_6OCyhLKus,460
cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=Ua8KoLXXnzgsrAUmHpyKymaPt8aPRP0EHEaBz7QCQ9I,3737
cryptography/hazmat/primitives/kdf/hkdf.py,sha256=M0lAEfRoc4kpp4-nwDj9yB-vNZukIOYEQrUlWsBNn9o,543
cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=oZepvo4evhKkkJQWRDwaPoIbyTaFmDc5NPimxg6lfKg,9165
cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=1WIwhELR0w8ztTpTu8BrFiYWmK3hUfJq08I79TxwieE,1957
cryptography/hazmat/primitives/kdf/scrypt.py,sha256=XyWUdUUmhuI9V6TqAPOvujCSMGv1XQdg0a21IWCmO-U,590
cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=zLTcF665QFvXX2f8TS7fmBZTteXpFjKahzfjjQcCJyw,1999
cryptography/hazmat/primitives/keywrap.py,sha256=XV4Pj2fqSeD-RqZVvY2cA3j5_7RwJSFygYuLfk2ujCo,5650
cryptography/hazmat/primitives/padding.py,sha256=QT-U-NvV2eQGO1wVPbDiNGNSc9keRDS-ig5cQOrLz0E,1865
cryptography/hazmat/primitives/poly1305.py,sha256=P5EPQV-RB_FJPahpg01u0Ts4S_PnAmsroxIGXbGeRRo,355
cryptography/hazmat/primitives/serialization/__init__.py,sha256=Q7uTgDlt7n3WfsMT6jYwutC6DIg_7SEeoAm1GHZ5B5E,1705
cryptography/hazmat/primitives/serialization/base.py,sha256=ikq5MJIwp_oUnjiaBco_PmQwOTYuGi-XkYUYHKy8Vo0,615
cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=mS9cFNG4afzvseoc5e1MWoY2VskfL8N8Y_OFjl67luY,5104
cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=5OR_Tkysxaprn4FegvJIfbep9rJ9wok6FLWvWwQ5-Mg,13943
cryptography/hazmat/primitives/serialization/ssh.py,sha256=hPV5obFznz0QhFfXFPOeQ8y6MsurA0xVMQiLnLESEs8,53700
cryptography/hazmat/primitives/twofactor/__init__.py,sha256=tmMZGB-g4IU1r7lIFqASU019zr0uPp_wEBYcwdDCKCA,258
cryptography/hazmat/primitives/twofactor/hotp.py,sha256=ivZo5BrcCGWLsqql4nZV0XXCjyGPi_iHfDFltGlOJwk,3256
cryptography/hazmat/primitives/twofactor/totp.py,sha256=m5LPpRL00kp4zY8gTjr55Hfz9aMlPS53kHmVkSQCmdY,1652
cryptography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
cryptography/utils.py,sha256=nFHkPQZycOQGeBtBRkWSA4WjOHFo7pwummQt-PPSkZc,4349
cryptography/x509/__init__.py,sha256=xloN0swseNx-m2WFZmCA17gOoxQWqeU82UVjEdJBePQ,8257
cryptography/x509/base.py,sha256=OrmTw3y8B6AE_nGXQPN8x9kq-d7rDWeH13gCq6T6D6U,27997
cryptography/x509/certificate_transparency.py,sha256=JqoOIDhlwInrYMFW6IFn77WJ0viF-PB_rlZV3vs9MYc,797
cryptography/x509/extensions.py,sha256=QxYrqR6SF1qzR9ZraP8wDiIczlEVlAFuwDRVcltB6Tk,77724
cryptography/x509/general_name.py,sha256=sP_rV11Qlpsk4x3XXGJY_Mv0Q_s9dtjeLckHsjpLQoQ,7836
cryptography/x509/name.py,sha256=ty0_xf0LnHwZAdEf-d8FLO1K4hGqx_7DsD3CHwoLJiY,15101
cryptography/x509/ocsp.py,sha256=Yey6NdFV1MPjop24Mj_VenjEpg3kUaMopSWOK0AbeBs,12699
cryptography/x509/oid.py,sha256=BUzgXXGVWilkBkdKPTm9R4qElE9gAGHgdYPMZAp7PJo,931
cryptography/x509/verification.py,sha256=gR2C2c-XZQtblZhT5T5vjSKOtCb74ef2alPVmEcwFlM,958

View file

@ -0,0 +1,4 @@
Wheel-Version: 1.0
Generator: maturin (1.9.4)
Root-Is-Purelib: false
Tag: cp311-abi3-macosx_10_9_universal2

View file

@ -0,0 +1,3 @@
This software is made available under the terms of *either* of the licenses
found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made
under the terms of *both* these licenses.

View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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
https://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.

View file

@ -0,0 +1,27 @@
Copyright (c) Individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of PyCA Cryptography nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,130 @@
Metadata-Version: 2.4
Name: importlib_metadata
Version: 8.9.0
Summary: Read metadata from Python packages
Author-email: "Jason R. Coombs" <jaraco@jaraco.com>
License-Expression: Apache-2.0
Project-URL: Source, https://github.com/python/importlib_metadata
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Description-Content-Type: text/x-rst
License-File: LICENSE
Requires-Dist: zipp>=3.20
Provides-Extra: test
Requires-Dist: pytest!=8.1.*,>=6; extra == "test"
Requires-Dist: packaging; extra == "test"
Requires-Dist: pyfakefs; extra == "test"
Requires-Dist: pytest-perf>=0.9.2; extra == "test"
Provides-Extra: doc
Requires-Dist: sphinx>=3.5; extra == "doc"
Requires-Dist: jaraco.packaging>=9.3; extra == "doc"
Requires-Dist: rst.linker>=1.9; extra == "doc"
Requires-Dist: furo; extra == "doc"
Requires-Dist: sphinx-lint; extra == "doc"
Requires-Dist: jaraco.tidelift>=1.4; extra == "doc"
Provides-Extra: perf
Requires-Dist: ipython; extra == "perf"
Provides-Extra: check
Requires-Dist: pytest-checkdocs>=2.14; extra == "check"
Requires-Dist: pytest-ruff>=0.2.1; sys_platform != "cygwin" and extra == "check"
Provides-Extra: cover
Requires-Dist: pytest-cov; extra == "cover"
Provides-Extra: enabler
Requires-Dist: pytest-enabler>=3.4; extra == "enabler"
Provides-Extra: type
Requires-Dist: pytest-mypy>=1.0.1; platform_python_implementation != "PyPy" and extra == "type"
Dynamic: license-file
.. image:: https://img.shields.io/pypi/v/importlib_metadata.svg
:target: https://pypi.org/project/importlib_metadata
.. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg
.. image:: https://github.com/python/importlib_metadata/actions/workflows/main.yml/badge.svg
:target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22tests%22
:alt: tests
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
:target: https://github.com/astral-sh/ruff
:alt: Ruff
.. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest
:target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest
.. image:: https://img.shields.io/badge/skeleton-2025-informational
:target: https://blog.jaraco.com/skeleton
.. image:: https://tidelift.com/badges/package/pypi/importlib-metadata
:target: https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=readme
Library to access the metadata for a Python package.
This package supplies third-party access to the functionality of
`importlib.metadata <https://docs.python.org/3/library/importlib.metadata.html>`_
including improvements added to subsequent Python versions.
Compatibility
=============
New features are introduced in this third-party library and later merged
into CPython. The following table indicates which versions of this library
were contributed to different versions in the standard library:
.. list-table::
:header-rows: 1
* - importlib_metadata
- stdlib
* - 7.0
- 3.13
* - 6.5
- 3.12
* - 4.13
- 3.11
* - 4.6
- 3.10
* - 1.4
- 3.8
Usage
=====
See the `online documentation <https://importlib-metadata.readthedocs.io/>`_
for usage details.
`Finder authors
<https://docs.python.org/3/reference/import.html#finders-and-loaders>`_ can
also add support for custom package installers. See the above documentation
for details.
Caveats
=======
This project primarily supports third-party packages installed by PyPA
tools (or other conforming packages). It does not support:
- Packages in the stdlib.
- Packages installed without metadata.
Project details
===============
* Project home: https://github.com/python/importlib_metadata
* Report bugs at: https://github.com/python/importlib_metadata/issues
* Code hosting: https://github.com/python/importlib_metadata
* Documentation: https://importlib-metadata.readthedocs.io/
For Enterprise
==============
Available as part of the Tidelift Subscription.
This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.
`Learn more <https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=referral&utm_campaign=github>`_.

View file

@ -0,0 +1,20 @@
importlib_metadata-8.9.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
importlib_metadata-8.9.0.dist-info/METADATA,sha256=571mC1BVj1cZB0nBrwPCK51LVhroM9pG20A8Ulo3y88,4536
importlib_metadata-8.9.0.dist-info/RECORD,,
importlib_metadata-8.9.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_metadata-8.9.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
importlib_metadata-8.9.0.dist-info/licenses/LICENSE,sha256=4ve7BVfno4FJnxW6p8HXdtg9ZhZZkXnXHTEJuOOfeyU,10278
importlib_metadata-8.9.0.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19
importlib_metadata/__init__.py,sha256=l0bUNX8-gg5_malNOySP8DLhB1VH5pZnhrQ2kA6I2xc,38000
importlib_metadata/_adapters.py,sha256=r5i8XLrKT6xmrpoREZhZrfczOYDmrVZeJBW5u0HzIGU,3797
importlib_metadata/_collections.py,sha256=CxAhzlF3g1rwu_fMiB53JtRQiUFh0RgiMpoOvmK_ocg,760
importlib_metadata/_compat.py,sha256=VC5ZDLlT-BcshauCShdFJvMNLntJJfZzNK1meGa-enw,1313
importlib_metadata/_functools.py,sha256=hVPD-xQZF68JXAhQOzDqpsD-gav28Ga0p1T_wDzLuwc,3537
importlib_metadata/_itertools.py,sha256=nMvp9SfHAQ_JYwK4L2i64lr3GRXGlYlikGTVzWbys_E,5351
importlib_metadata/_meta.py,sha256=EtHyiJ5kGzWFDfKyQ2XQp6Vu113CeadKW1Vf6aGc1B4,1765
importlib_metadata/_text.py,sha256=HCsFksZpJLeTP3NEk_ngrAeXVRRtTrtyh9eOABoRP4A,2166
importlib_metadata/_typing.py,sha256=EQKhhsEgz_Sa-FnePI-faC72rNOOQwopjA1i5pG8FDU,367
importlib_metadata/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
importlib_metadata/compat/py311.py,sha256=uqm-K-uohyj1042TH4a9Er_I5o7667DvulcD-gC_fSA,608
importlib_metadata/diagnose.py,sha256=nkSRMiowlmkhLYhKhvCg9glmt_11Cox-EmLzEbqYTa8,379
importlib_metadata/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

View file

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: setuptools (82.0.1)
Root-Is-Purelib: true
Tag: py3-none-any

View file

@ -0,0 +1,73 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright 2026 [name of copyright owner]
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.

View file

@ -0,0 +1,26 @@
[project]
name = "service-tui"
version = "0.2.0"
description = "TUI сервисного инженера для диагностики платы MIMXRT1052"
requires-python = ">=3.11"
dependencies = [
"textual>=0.80.0",
"pyserial>=3.5",
"python-dotenv>=1.0.0",
"pyinstaller>=6.0.0",
"pyusb>=1.0.0",
"spsdk==3.7.0",
]
[project.scripts]
service-tui = "main:main"
[tool.uv]
package = false
[dependency-groups]
dev = ["pytest>=8.0.0"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

View file

@ -0,0 +1,141 @@
Metadata-Version: 2.4
Name: setuptools
Version: 80.10.2
Summary: Easily download, build, install, upgrade, and uninstall Python packages
Author-email: Python Packaging Authority <distutils-sig@python.org>
License-Expression: MIT
Project-URL: Source, https://github.com/pypa/setuptools
Project-URL: Documentation, https://setuptools.pypa.io/
Project-URL: Changelog, https://setuptools.pypa.io/en/stable/history.html
Keywords: CPAN PyPI distutils eggs package management
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Archiving :: Packaging
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Description-Content-Type: text/x-rst
License-File: LICENSE
Provides-Extra: test
Requires-Dist: pytest!=8.1.*,>=6; extra == "test"
Requires-Dist: virtualenv>=13.0.0; extra == "test"
Requires-Dist: wheel>=0.44.0; extra == "test"
Requires-Dist: pip>=19.1; extra == "test"
Requires-Dist: packaging>=24.2; extra == "test"
Requires-Dist: jaraco.envs>=2.2; extra == "test"
Requires-Dist: pytest-xdist>=3; extra == "test"
Requires-Dist: jaraco.path>=3.7.2; extra == "test"
Requires-Dist: build[virtualenv]>=1.0.3; extra == "test"
Requires-Dist: filelock>=3.4.0; extra == "test"
Requires-Dist: ini2toml[lite]>=0.14; extra == "test"
Requires-Dist: tomli-w>=1.0.0; extra == "test"
Requires-Dist: pytest-timeout; extra == "test"
Requires-Dist: pytest-perf; sys_platform != "cygwin" and extra == "test"
Requires-Dist: jaraco.develop>=7.21; (python_version >= "3.9" and sys_platform != "cygwin") and extra == "test"
Requires-Dist: pytest-home>=0.5; extra == "test"
Requires-Dist: pytest-subprocess; extra == "test"
Requires-Dist: pyproject-hooks!=1.1; extra == "test"
Requires-Dist: jaraco.test>=5.5; extra == "test"
Provides-Extra: doc
Requires-Dist: sphinx>=3.5; extra == "doc"
Requires-Dist: jaraco.packaging>=9.3; extra == "doc"
Requires-Dist: rst.linker>=1.9; extra == "doc"
Requires-Dist: furo; extra == "doc"
Requires-Dist: sphinx-lint; extra == "doc"
Requires-Dist: jaraco.tidelift>=1.4; extra == "doc"
Requires-Dist: pygments-github-lexers==0.0.5; extra == "doc"
Requires-Dist: sphinx-favicon; extra == "doc"
Requires-Dist: sphinx-inline-tabs; extra == "doc"
Requires-Dist: sphinx-reredirects; extra == "doc"
Requires-Dist: sphinxcontrib-towncrier; extra == "doc"
Requires-Dist: sphinx-notfound-page<2,>=1; extra == "doc"
Requires-Dist: pyproject-hooks!=1.1; extra == "doc"
Requires-Dist: towncrier<24.7; extra == "doc"
Provides-Extra: ssl
Provides-Extra: certs
Provides-Extra: core
Requires-Dist: packaging>=24.2; extra == "core"
Requires-Dist: more_itertools>=8.8; extra == "core"
Requires-Dist: jaraco.text>=3.7; extra == "core"
Requires-Dist: importlib_metadata>=6; python_version < "3.10" and extra == "core"
Requires-Dist: tomli>=2.0.1; python_version < "3.11" and extra == "core"
Requires-Dist: wheel>=0.43.0; extra == "core"
Requires-Dist: platformdirs>=4.2.2; extra == "core"
Requires-Dist: jaraco.functools>=4; extra == "core"
Requires-Dist: more_itertools; extra == "core"
Provides-Extra: check
Requires-Dist: pytest-checkdocs>=2.4; extra == "check"
Requires-Dist: pytest-ruff>=0.2.1; sys_platform != "cygwin" and extra == "check"
Requires-Dist: ruff>=0.8.0; sys_platform != "cygwin" and extra == "check"
Provides-Extra: cover
Requires-Dist: pytest-cov; extra == "cover"
Provides-Extra: enabler
Requires-Dist: pytest-enabler>=2.2; extra == "enabler"
Provides-Extra: type
Requires-Dist: pytest-mypy; extra == "type"
Requires-Dist: mypy==1.14.*; extra == "type"
Requires-Dist: importlib_metadata>=7.0.2; python_version < "3.10" and extra == "type"
Requires-Dist: jaraco.develop>=7.21; sys_platform != "cygwin" and extra == "type"
Dynamic: license-file
.. |pypi-version| image:: https://img.shields.io/pypi/v/setuptools.svg
:target: https://pypi.org/project/setuptools
.. |py-version| image:: https://img.shields.io/pypi/pyversions/setuptools.svg
.. |test-badge| image:: https://github.com/pypa/setuptools/actions/workflows/main.yml/badge.svg
:target: https://github.com/pypa/setuptools/actions?query=workflow%3A%22tests%22
:alt: tests
.. |ruff-badge| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json
:target: https://github.com/astral-sh/ruff
:alt: Ruff
.. |docs-badge| image:: https://img.shields.io/readthedocs/setuptools/latest.svg
:target: https://setuptools.pypa.io
.. |skeleton-badge| image:: https://img.shields.io/badge/skeleton-2025-informational
:target: https://blog.jaraco.com/skeleton
.. |codecov-badge| image:: https://img.shields.io/codecov/c/github/pypa/setuptools/master.svg?logo=codecov&logoColor=white
:target: https://codecov.io/gh/pypa/setuptools
.. |tidelift-badge| image:: https://tidelift.com/badges/github/pypa/setuptools?style=flat
:target: https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=readme
.. |discord-badge| image:: https://img.shields.io/discord/803025117553754132
:target: https://discord.com/channels/803025117553754132/815945031150993468
:alt: Discord
|pypi-version| |py-version| |test-badge| |ruff-badge| |docs-badge| |skeleton-badge| |codecov-badge| |discord-badge|
See the `Quickstart <https://setuptools.pypa.io/en/latest/userguide/quickstart.html>`_
and the `User's Guide <https://setuptools.pypa.io/en/latest/userguide/>`_ for
instructions on how to use Setuptools.
Questions and comments should be directed to `GitHub Discussions
<https://github.com/pypa/setuptools/discussions>`_.
Bug reports and especially tested patches may be
submitted directly to the `bug tracker
<https://github.com/pypa/setuptools/issues>`_.
Code of Conduct
===============
Everyone interacting in the setuptools project's codebases, issue trackers,
chat rooms, and fora is expected to follow the
`PSF Code of Conduct <https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md>`_.
For Enterprise
==============
Available as part of the Tidelift Subscription.
Setuptools and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.
`Learn more <https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=referral&utm_campaign=github>`_.

View file

@ -0,0 +1,460 @@
_distutils_hack/__init__.py,sha256=34HmvLo07j45Uvd2VR-2aRQ7lJD91sTK6zJgn5fphbQ,6755
_distutils_hack/override.py,sha256=Eu_s-NF6VIZ4Cqd0tbbA5wtWky2IZPNd8et6GLt1mzo,44
distutils-precedence.pth,sha256=JjjOniUA5XKl4N5_rtZmHrVp0baW_LoHsN0iPaX10iQ,151
pkg_resources/__init__.py,sha256=yxteYDjmlV_1pmFdIGMKt7J9dUXqoJ-6yhSSHeQ86g4,126234
pkg_resources/api_tests.txt,sha256=XEdvy4igHHrq2qNHNMHnlfO6XSQKNqOyLHbl6QcpfAI,12595
pkg_resources/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pkg_resources/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pkg_resources/tests/data/my-test-package-source/setup.cfg,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pkg_resources/tests/data/my-test-package-source/setup.py,sha256=1VobhAZbMb7M9mfhb_NE8PwDsvukoWLs9aUAS0pYhe8,105
pkg_resources/tests/data/my-test-package-zip/my-test-package.zip,sha256=AYRcQ39GVePPnMT8TknP1gdDHyJnXhthESmpAjnzSCI,1809
pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/PKG-INFO,sha256=JvWv9Io2PAuYwEEw2fBW4Qc5YvdbkscpKX1kmLzsoHk,187
pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/SOURCES.txt,sha256=4ClkH8eTovZrdVrJFsVuxdbMEF--lBVSuKonDAPE5Jc,208
pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/dependency_links.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
pkg_resources/tests/data/my-test-package_zipped-egg/my_test_package-1.0-py3.7.egg,sha256=ZTlMGxjRGiKDNkiA2c75jbQH2TWIteP00irF9gvczbo,843
pkg_resources/tests/test_find_distributions.py,sha256=U91cov5L1COAIWLNq3Xy4plU7_MnOE1WtXMu6iV2waM,1972
pkg_resources/tests/test_integration_zope_interface.py,sha256=nzVoK557KZQN0V3DIQ1sVeaCOgt4Kpl-CODAWsO7pmc,1652
pkg_resources/tests/test_markers.py,sha256=0orKg7UMDf7fnuNQvRMOc-EF9EAP_JTQnk4mtGgbW50,241
pkg_resources/tests/test_pkg_resources.py,sha256=5Mt4bJQhLCL8j8cC46Uv32Np2Xc1TTxLGawIfET55Fk,17111
pkg_resources/tests/test_resources.py,sha256=K0LqMAUGpRQ9pUb9K0vyI7GesvtlQvTH074m-E2VQlo,31252
pkg_resources/tests/test_working_set.py,sha256=lRtGJWIixSwSMSbjHgRxeJEQiLMRXcz3xzJL2qL7eXY,8602
setuptools-80.10.2.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools-80.10.2.dist-info/METADATA,sha256=28yYQTiLf7VcIZAoj9aDsYOw-1V_V6M42GVT70cdKH0,6573
setuptools-80.10.2.dist-info/RECORD,,
setuptools-80.10.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools-80.10.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
setuptools-80.10.2.dist-info/entry_points.txt,sha256=zkgthpf_Fa9NVE9p6FKT3Xk9DR1faAcRU4coggsV7jA,2449
setuptools-80.10.2.dist-info/licenses/LICENSE,sha256=htoPAa6uRjSKPD1GUZXcHOzN55956HdppkuNoEsqR0E,1023
setuptools-80.10.2.dist-info/top_level.txt,sha256=d9yL39v_W7qmKDDSH6sT4bE0j_Ls1M3P161OGgdsm4g,41
setuptools/__init__.py,sha256=v1rZDv-VYE8tsPawfxG8c7jEyI8c37yAWxYO_FFmTIY,9275
setuptools/_core_metadata.py,sha256=T7Tjp-WSoN881adev3R1wzXCPnkDHqbC2MgylN1yjS8,11978
setuptools/_discovery.py,sha256=HxEpgYQ8zUaLOOSp8JIA4y2Mdvn9ysVxspPT-ppfzM4,836
setuptools/_distutils/__init__.py,sha256=xGYuhWwLG07J0Q49BVnEjPy6wyDcd6veJMDJX7ljlyM,359
setuptools/_distutils/_log.py,sha256=i-lNTTcXS8TmWITJ6DODGvtW5z5tMattJQ76h8rZxQU,42
setuptools/_distutils/_macos_compat.py,sha256=JzUGhF4E5yIITHbUaPobZEWjGHdrrcNV63z86S4RjBc,239
setuptools/_distutils/_modified.py,sha256=RF1n1CexyDYV3lvGbeXS0s-XCJVboDOIUbA8wEQqYTY,3211
setuptools/_distutils/_msvccompiler.py,sha256=9PSfSHxvJnHnQL6Sqz4Xcz7iaBIT62p6BheQzGsSlwo,335
setuptools/_distutils/archive_util.py,sha256=Qw2z-Pt-NV8lNUQrzjs3XDGWCWHMPnqHLyt8TiD2XEA,8884
setuptools/_distutils/ccompiler.py,sha256=FKVjqzGJ7c-FtouNjhLiaMPm5LKMZHHAruXf8LU216c,524
setuptools/_distutils/cmd.py,sha256=hXtaRaH7QBnfNOIqEvCt47iwZzD9MVvBdhhdQctHsxM,22186
setuptools/_distutils/command/__init__.py,sha256=GfFAzbBqk1qxSH4BdaKioKS4hRRnD44BAmwEN85C4u8,386
setuptools/_distutils/command/_framework_compat.py,sha256=0iZdSJYzGRWCCvzRDKE-R0-_yaAYvFMd1ylXb2eYXug,1609
setuptools/_distutils/command/bdist.py,sha256=jWtk61R7fWNUUNxJV0thTZzU5n80L3Ay1waSiP9kiLA,5854
setuptools/_distutils/command/bdist_dumb.py,sha256=Hx1jAqoZNxYIy4N5TLzUp6J5fi8Ls18py7UlLNFhO2E,4631
setuptools/_distutils/command/bdist_rpm.py,sha256=nxcXXv5a7B-1ntWu4DbGmCtES4EBINrJaBQcRNAYCJI,21785
setuptools/_distutils/command/build.py,sha256=SpHlagf0iNaKVyIhxDfhPFZ8X1-LAWOCQACy-yt2K0w,5923
setuptools/_distutils/command/build_clib.py,sha256=aMqZcUfCbOAu_xr-A9iW-Q9YZHzpDGLRTezOgMQJmSQ,7777
setuptools/_distutils/command/build_ext.py,sha256=zrrsu9HXnzV6bXYbJuZCK4SwVZMjKnl4pG1o3bNcxtc,32710
setuptools/_distutils/command/build_py.py,sha256=Vfq-INemoMbg6f003BTy_Ufp8bjOZhmFIhpKMcfXLgs,16696
setuptools/_distutils/command/build_scripts.py,sha256=emMEOONkNLPC-AMjKy45UksUlY1wk06esOGThpwidIM,5135
setuptools/_distutils/command/check.py,sha256=yoNe2MPY4JcTM7rwoIQdfZ75q5Ri058I2coi-Gq9CjM,4946
setuptools/_distutils/command/clean.py,sha256=dQAacOabwBXU9JoZ-1GFusq3eFltDaeXJFSYncqGbvE,2644
setuptools/_distutils/command/config.py,sha256=qrrfz6NEQORmbqiY2XlvCDWYhsbLyxZXJsURKfYN_kw,12724
setuptools/_distutils/command/install.py,sha256=-JenB-mua4hc2RI_-W8F9PnP_J-OaFO7E0PJGKxLo1o,30072
setuptools/_distutils/command/install_data.py,sha256=GzBlUWWKubTYJlP-L0auUriq9cL-5RKOcoyHTttKj0Q,2875
setuptools/_distutils/command/install_egg_info.py,sha256=ffiLoU1ivQJ8q2_WL7ZygZbUcOsgdFLKL7otEIJWWkI,2868
setuptools/_distutils/command/install_headers.py,sha256=5ciKCj8c3XKsYNKdkdMvnypaUCKcoWCDeeZij3fD-Z4,1272
setuptools/_distutils/command/install_lib.py,sha256=2s9-m5-b1qKm51F28lB5L39Z6vv_GHMlv9dNBSupok0,8588
setuptools/_distutils/command/install_scripts.py,sha256=M0pPdiaqB7TGmqTMujpGGeiL0Iq_CTeGjMFtrmDmwzM,2002
setuptools/_distutils/command/sdist.py,sha256=cRIF6Ht1hJ6ayOOFVycMFBUNxjo94e_rFYPx4Hi8Ahc,19151
setuptools/_distutils/compat/__init__.py,sha256=J20aXGjJ86Rg41xFLIWlcWCgZ9edMdJ9vvdNEQ87vPQ,522
setuptools/_distutils/compat/numpy.py,sha256=UFgneZw9w97g4c-yGoAIOyLxUOWQ-fPRIhhfMs7_Ouc,167
setuptools/_distutils/compat/py39.py,sha256=hOsD6lwZLqZoMnacNJ3P6nUA-LJQhEpVtYTzVH0o96M,1964
setuptools/_distutils/compilers/C/base.py,sha256=XR1rBCStCquqm7QOYXD41-LfvsFcPpGxrwxeXzJyn_w,54876
setuptools/_distutils/compilers/C/cygwin.py,sha256=DUlwQSb55aj7OdcmcddrmCmVEjEaxIiJ5hHUO3GBPNs,11844
setuptools/_distutils/compilers/C/errors.py,sha256=sKOVzJajMUmNdfywo9UM_QQGsKFcclDhtI5TlCiXMLc,573
setuptools/_distutils/compilers/C/msvc.py,sha256=elzG8v9jN5QytLMwLCdUdSuZ3eZ3R98VUvnm9Y2PBCA,21404
setuptools/_distutils/compilers/C/tests/test_base.py,sha256=rdhHc56bhXtm5NnN9BSHwr6c69UqzMItZQzlw2AsdMc,2706
setuptools/_distutils/compilers/C/tests/test_cygwin.py,sha256=UgV2VgUXj3VulcbDc0UBWfEyJDx42tgSwS4LzHix3mY,2701
setuptools/_distutils/compilers/C/tests/test_mingw.py,sha256=hCmwyywISpRoyOySbFHBL4TprWRV0mUWDKmOLO8XBXE,1900
setuptools/_distutils/compilers/C/tests/test_msvc.py,sha256=DlGjmZ1mBSMXIgmlu80BKc7V-EJOZuYucwJwFh5dn28,4151
setuptools/_distutils/compilers/C/tests/test_unix.py,sha256=AyadWw1fR-UeDl2TvIbYBzOJVHkpE_oRRQ3JTJWqaEA,14642
setuptools/_distutils/compilers/C/unix.py,sha256=YH-y9g_pjBFjaJyHJQkDEBQ7q4D20I2-cWJNdgw-Yho,16531
setuptools/_distutils/compilers/C/zos.py,sha256=vnNeWLRZkdIkdZ-YyBnL8idTUfcCOn0tLMW5OBJ0ScU,6586
setuptools/_distutils/core.py,sha256=GEHKaFC48T3o-_SmH4864GvKyx1IgbVC6ISIPVlx7a4,9364
setuptools/_distutils/cygwinccompiler.py,sha256=mG_cU8SVZ4amD_VtF5vH6BXP0-kghGsDPbDSXrQ963c,594
setuptools/_distutils/debug.py,sha256=N6MrTAqK6l9SVk6tWweR108PM8Ol7qNlfyV-nHcLhsY,139
setuptools/_distutils/dep_util.py,sha256=xN75p6ZpHhMiHEc-rpL2XilJQynHnDNiafHteaZ4tjU,349
setuptools/_distutils/dir_util.py,sha256=DXPUlfVVGsg9B-Jgg4At_j9T7vM60OgwNXkQHqTo7-I,7236
setuptools/_distutils/dist.py,sha256=gW598UE0WMkzXQQ31Nr-8L7MPw0oIOz5OSSRzYZlwrM,55794
setuptools/_distutils/errors.py,sha256=PPE2oDRh5y9Q1beKK9rhdvDaCzQhi4HCXs4KcqfqgZY,3092
setuptools/_distutils/extension.py,sha256=Foyu4gULcPqm1_U9zrYYHxNk4NqglXv1rbsOk_QrSds,11155
setuptools/_distutils/fancy_getopt.py,sha256=PjdO-bWCW0imV_UN-MGEw9R2GP2OiE8pHjITgmTAY3Q,17895
setuptools/_distutils/file_util.py,sha256=YFQL_pD3hLuER9II_H6-hDC_YIGEookdd4wedLuiTW0,7978
setuptools/_distutils/filelist.py,sha256=MBeSRJmPcKmDv8ooZgSU4BiQPZ0Khwv8l_jhD50XycI,15337
setuptools/_distutils/log.py,sha256=VyBs5j7z4-K6XTEEBThUc9HyMpoPLGtQpERqbz5ylww,1200
setuptools/_distutils/spawn.py,sha256=zseCh9sEifyp0I5Vg719JNIASlROJ2ehXqQnHlpt89Q,4086
setuptools/_distutils/sysconfig.py,sha256=KeI8OHbMuEzHJ8Q0cBez9KZny8iRy6Z6Y0AkMz1jlsU,19728
setuptools/_distutils/tests/__init__.py,sha256=j-IoPZEtQv3EOPuqNTwalr6GLyRjzCC-OOaNvZzmHsI,1485
setuptools/_distutils/tests/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_distutils/tests/compat/py39.py,sha256=t0GBTM-30jX-9zCfkwlNBFtzzabemx6065mJ0d9_VRw,1026
setuptools/_distutils/tests/support.py,sha256=tjsYsyxvpTK4NrkCseh2ujvDIGV0Mf_b5SI5fP2T0yM,4099
setuptools/_distutils/tests/test_archive_util.py,sha256=jozimSwPBF-JoJfN_vDaiVGZp66BNcWZGh34FlW57DQ,11787
setuptools/_distutils/tests/test_bdist.py,sha256=xNHxUsLlHsZQRwkzLb_iSD24s-9Mk-NX2ffBWwOyPyc,1396
setuptools/_distutils/tests/test_bdist_dumb.py,sha256=QF05MHNhPOdZyh88Xpw8KsO64s7pRFkl8KL-RoV4XK0,2247
setuptools/_distutils/tests/test_bdist_rpm.py,sha256=Hdm-pwWgyaoGdGbEcGZa8cRhGU45y8gHK8umOanTjik,3932
setuptools/_distutils/tests/test_build.py,sha256=JJY5XpOZco25ZY0pstxl-iI8mHsWP0ujf5o8aOtuZYY,1742
setuptools/_distutils/tests/test_build_clib.py,sha256=Mo1ZFb4C1VXBYOGvnallwN7YCnTtr24akLDO8Zi4CsY,4331
setuptools/_distutils/tests/test_build_ext.py,sha256=QFO9qYVhWWdJu17HXc4x9RMnLZlhk0lAHi9HVppbuX4,22545
setuptools/_distutils/tests/test_build_py.py,sha256=NsfmRrojOHBXNMqWR_mp5g4PLTgjhD7iZFUffGZFIdw,6882
setuptools/_distutils/tests/test_build_scripts.py,sha256=cD-FRy-oX55sXRX5Ez5xQCaeHrWajyKc4Xuwv2fe48w,2880
setuptools/_distutils/tests/test_check.py,sha256=hHSV07qf7YoSxGsTbbsUQ9tssZz5RRNdbrY1s2SwaFI,6226
setuptools/_distutils/tests/test_clean.py,sha256=hPH6jfIpGFUrvWbF1txkiNVSNaAxt2wq5XjV499zO4E,1240
setuptools/_distutils/tests/test_cmd.py,sha256=bgRB79mitoOKR1OiyZHnCogvGxt3pWkxeTqIC04lQWQ,3254
setuptools/_distutils/tests/test_config_cmd.py,sha256=Zs6WX0IfxDvmuC19XzuVNnYCnTr9Y-hl73TAmDSBN4Y,2664
setuptools/_distutils/tests/test_core.py,sha256=L7XKVAxa-MGoAZeANopnuK9fRKneYhkSQpgw8XQvcF8,3829
setuptools/_distutils/tests/test_dir_util.py,sha256=E84lC-k4riVUwURyWaQ0Jqx2ui2-io-0RuJa3M7qkJs,4500
setuptools/_distutils/tests/test_dist.py,sha256=a6wlc5fQJd5qQ6HOndzcupNhjTxvj6-_JLtpuYvaP1M,18793
setuptools/_distutils/tests/test_extension.py,sha256=-YejLgZCuycFrOBd64pVH0JvwMc9NwhzHvQxvvjXHqk,3670
setuptools/_distutils/tests/test_file_util.py,sha256=livjnl3FkilQlrB2rFdFQq9nvjEVZHynNya0bfzv_b4,3522
setuptools/_distutils/tests/test_filelist.py,sha256=rJwkqCUfkGDgWlD22TozsT8ycbupMHB8DXqThzwT1T4,10766
setuptools/_distutils/tests/test_install.py,sha256=TfCB0ykhIxydIC2Q4SuTAZzSHvteMHgrBL9whoSgK9Q,8618
setuptools/_distutils/tests/test_install_data.py,sha256=vKq3K97k0hBAnOg38nmwEdf7cEDVr9rTVyCeJolgb4A,2464
setuptools/_distutils/tests/test_install_headers.py,sha256=PVAYpo_tYl980Qf64DPOmmSvyefIHdU06f7VsJeZykE,936
setuptools/_distutils/tests/test_install_lib.py,sha256=qri6Rl-maNTQrNDV8DbeXNl0hjsfRIKiI4rfZLrmWBI,3612
setuptools/_distutils/tests/test_install_scripts.py,sha256=KE3v0cDkFW-90IOID-OmZZGM2mhy-ZkEuuW7UXS2SHw,1600
setuptools/_distutils/tests/test_log.py,sha256=isFtOufloCyEdZaQOV7cVUr46GwtdVMj43mGBB5XH7k,323
setuptools/_distutils/tests/test_modified.py,sha256=h1--bOWmtJo1bpVV6uRhdnS9br71CBiNDM1MDwSGpug,4221
setuptools/_distutils/tests/test_sdist.py,sha256=cfzUhlCA418-1vH9ta3IBs26c_jUBbkJoFOK5GnAyNk,15062
setuptools/_distutils/tests/test_spawn.py,sha256=eS8w9D7bTxyFLSyRahJWeuh8Kc1F8RWWiY_dSG5B5Bc,4803
setuptools/_distutils/tests/test_sysconfig.py,sha256=lxM8LsUi1TomjDV4HoYK8u5nUoBkeNL60Uq8PY1DcwU,11986
setuptools/_distutils/tests/test_text_file.py,sha256=WQWSB5AfdBDZaMA8BFgipJPnsJb_2SKMfL90fSkRVtw,3460
setuptools/_distutils/tests/test_util.py,sha256=H9zlZ4z4Vh4TfjNYDBsxP7wguQLpxCfJYyOcm1yZU3c,7988
setuptools/_distutils/tests/test_version.py,sha256=ahfg_mP8wRy1sgwY-_Px5hrjgf6_upTIpnCgpR4yWRk,2750
setuptools/_distutils/tests/test_versionpredicate.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_distutils/tests/unix_compat.py,sha256=z-op6C2iVdX1aq5BIBR7cqOxijKE97alNwJqHNdLpoI,386
setuptools/_distutils/text_file.py,sha256=z4dkOJBr9Bo2LG0TNqm8sD63LEEaKSSP0J0bWBrFG3c,12101
setuptools/_distutils/unixccompiler.py,sha256=1bXJWH4fiu_A2WfriHzf88xjllQTXnnjUkZdRKs9cWU,212
setuptools/_distutils/util.py,sha256=Njfnqk60zMdkiAjRnGcTWX3t49-obHapOlbNvyIl02I,18094
setuptools/_distutils/version.py,sha256=vImT5-ECXkQ21oKL0XYFiTqK6NyM09cpzBNoA_34CQU,12619
setuptools/_distutils/versionpredicate.py,sha256=qBWQ6wTj12ODytoTmIydefIY2jb4uY1sdbgbuLn-IJM,5205
setuptools/_distutils/zosccompiler.py,sha256=svdiXZ2kdcwKrJKfhUhib03y8gz7aGZKukXH3I7YkBc,58
setuptools/_entry_points.py,sha256=10TjbzfGdqWGH06lQuPPGDDci-OnXoIzrfpIWba5AZw,2468
setuptools/_imp.py,sha256=YY1EjZEN-0zYci1cxO10B_adAEOr7i8eK8JoCc9Ierc,2435
setuptools/_importlib.py,sha256=aKIjcK0HKXNz2D-XTrxaixGn_juTkONwmu3dcheMOF0,223
setuptools/_itertools.py,sha256=jWRfsIrpC7myooz3hDURj9GtvpswZeKXg2HakmEhNjo,657
setuptools/_normalization.py,sha256=1H0YXdCuVkUcNX2zQqDyqa-4eWC8VI5vWjGGsbj7n8I,5798
setuptools/_path.py,sha256=2Bv1q9_Hrd4oizKwcH3pv_05YVR6meovQE6ZtyD45yI,2976
setuptools/_reqs.py,sha256=RRX-qYsz_fy6K66XchCHcIszK3bSAtU6aO1s3ZaLV14,1380
setuptools/_scripts.py,sha256=5TrIWDVOuO3cRcfzcZAUBKPRH7K4svQRdQLZKKiD1bQ,11247
setuptools/_shutil.py,sha256=IQQ1gcPX4X_wPilYGJGxChyMCqG43VOejoQZTIrCTY8,1578
setuptools/_static.py,sha256=GTR79gESF1_JaK4trLkpDrEuCeEtPlwQW0MRv7VNQX4,4855
setuptools/_vendor/.lock,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/autocommand-2.2.2.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/autocommand-2.2.2.dist-info/LICENSE,sha256=reeNBJgtaZctREqOFKlPh6IzTdOFXMgDSOqOJAqg3y0,7634
setuptools/_vendor/autocommand-2.2.2.dist-info/METADATA,sha256=OADZuR3O6iBlpu1ieTgzYul6w4uOVrk0P0BO5TGGAJk,15006
setuptools/_vendor/autocommand-2.2.2.dist-info/RECORD,sha256=K-5gcsvOxjkMVxB8jfywQikYqY7NtaLMNiGH8T1C6W8,1072
setuptools/_vendor/autocommand-2.2.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/autocommand-2.2.2.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
setuptools/_vendor/autocommand-2.2.2.dist-info/top_level.txt,sha256=AzfhgKKS8EdAwWUTSF8mgeVQbXOY9kokHB6kSqwwqu0,12
setuptools/_vendor/autocommand/__init__.py,sha256=zko5Rnvolvb-UXjCx_2ArPTGBWwUK5QY4LIQIKYR7As,1037
setuptools/_vendor/autocommand/autoasync.py,sha256=AMdyrxNS4pqWJfP_xuoOcImOHWD-qT7x06wmKN1Vp-U,5680
setuptools/_vendor/autocommand/autocommand.py,sha256=hmkEmQ72HtL55gnURVjDOnsfYlGd5lLXbvT4KG496Qw,2505
setuptools/_vendor/autocommand/automain.py,sha256=A2b8i754Mxc_DjU9WFr6vqYDWlhz0cn8miu8d8EsxV8,2076
setuptools/_vendor/autocommand/autoparse.py,sha256=WVWmZJPcbzUKXP40raQw_0HD8qPJ2V9VG1eFFmmnFxw,11642
setuptools/_vendor/autocommand/errors.py,sha256=7aa3roh9Herd6nIKpQHNWEslWE8oq7GiHYVUuRqORnA,886
setuptools/_vendor/backports.tarfile-1.2.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/backports.tarfile-1.2.0.dist-info/LICENSE,sha256=htoPAa6uRjSKPD1GUZXcHOzN55956HdppkuNoEsqR0E,1023
setuptools/_vendor/backports.tarfile-1.2.0.dist-info/METADATA,sha256=ghXFTq132dxaEIolxr3HK1mZqm9iyUmaRANZQSr6WlE,2020
setuptools/_vendor/backports.tarfile-1.2.0.dist-info/RECORD,sha256=D2nbcZtUIg1qSt_4v7BKyYr_6j3ItUBUoaeHoXVn9NE,1056
setuptools/_vendor/backports.tarfile-1.2.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/backports.tarfile-1.2.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
setuptools/_vendor/backports.tarfile-1.2.0.dist-info/top_level.txt,sha256=cGjaLMOoBR1FK0ApojtzWVmViTtJ7JGIK_HwXiEsvtU,10
setuptools/_vendor/backports/__init__.py,sha256=iOEMwnlORWezdO8-2vxBIPSR37D7JGjluZ8f55vzxls,81
setuptools/_vendor/backports/tarfile/__init__.py,sha256=Pwf2qUIfB0SolJPCKcx3vz3UEu_aids4g4sAfxy94qg,108491
setuptools/_vendor/backports/tarfile/__main__.py,sha256=Yw2oGT1afrz2eBskzdPYL8ReB_3liApmhFkN2EbDmc4,59
setuptools/_vendor/backports/tarfile/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/backports/tarfile/compat/py38.py,sha256=iYkyt_gvWjLzGUTJD9TuTfMMjOk-ersXZmRlvQYN2qE,568
setuptools/_vendor/importlib_metadata-8.7.1.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/importlib_metadata-8.7.1.dist-info/METADATA,sha256=o-OLnuQyYonUhkcE8w4pnudp4jCc6fSnXw3hpQrQo1Y,4670
setuptools/_vendor/importlib_metadata-8.7.1.dist-info/RECORD,sha256=Uqa47g3hXPf9mWJfQ7l80uOUKshvFgVOqQ3kjmbyk1U,1868
setuptools/_vendor/importlib_metadata-8.7.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/importlib_metadata-8.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
setuptools/_vendor/importlib_metadata-8.7.1.dist-info/licenses/LICENSE,sha256=RYUC4S2Xu_ZEOGBqIARKqF6wX7CoqAe7NdvsJT_R_AQ,10278
setuptools/_vendor/importlib_metadata-8.7.1.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19
setuptools/_vendor/importlib_metadata/__init__.py,sha256=u7Ew4-UkpzNY-ka6k-WRkDhQZS1akkLMfWs2eEnUmGo,37734
setuptools/_vendor/importlib_metadata/_adapters.py,sha256=r5i8XLrKT6xmrpoREZhZrfczOYDmrVZeJBW5u0HzIGU,3797
setuptools/_vendor/importlib_metadata/_collections.py,sha256=CxAhzlF3g1rwu_fMiB53JtRQiUFh0RgiMpoOvmK_ocg,760
setuptools/_vendor/importlib_metadata/_compat.py,sha256=VC5ZDLlT-BcshauCShdFJvMNLntJJfZzNK1meGa-enw,1313
setuptools/_vendor/importlib_metadata/_functools.py,sha256=0pA2OoiVK6wnsGq8HvVIzgdkvLiZ0nfnfw7IsndjoHk,3510
setuptools/_vendor/importlib_metadata/_itertools.py,sha256=nMvp9SfHAQ_JYwK4L2i64lr3GRXGlYlikGTVzWbys_E,5351
setuptools/_vendor/importlib_metadata/_meta.py,sha256=EtHyiJ5kGzWFDfKyQ2XQp6Vu113CeadKW1Vf6aGc1B4,1765
setuptools/_vendor/importlib_metadata/_text.py,sha256=HCsFksZpJLeTP3NEk_ngrAeXVRRtTrtyh9eOABoRP4A,2166
setuptools/_vendor/importlib_metadata/_typing.py,sha256=EQKhhsEgz_Sa-FnePI-faC72rNOOQwopjA1i5pG8FDU,367
setuptools/_vendor/importlib_metadata/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/importlib_metadata/compat/py311.py,sha256=uqm-K-uohyj1042TH4a9Er_I5o7667DvulcD-gC_fSA,608
setuptools/_vendor/importlib_metadata/compat/py39.py,sha256=J3W7PUVRPNYMmcvT12RF8ndBU9e8_T0Ac4U87Bsrq70,1187
setuptools/_vendor/importlib_metadata/diagnose.py,sha256=nkSRMiowlmkhLYhKhvCg9glmt_11Cox-EmLzEbqYTa8,379
setuptools/_vendor/importlib_metadata/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/jaraco.text-4.0.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/jaraco.text-4.0.0.dist-info/LICENSE,sha256=htoPAa6uRjSKPD1GUZXcHOzN55956HdppkuNoEsqR0E,1023
setuptools/_vendor/jaraco.text-4.0.0.dist-info/METADATA,sha256=XC_QkBLJVPE5sQYkl41TNaZUw0AUzQb29GbKaD28nFY,3731
setuptools/_vendor/jaraco.text-4.0.0.dist-info/RECORD,sha256=Y7k2wwjQ_L4TkOgkVnzAB1NsMqhJrbAieOlfHUxzbDE,1157
setuptools/_vendor/jaraco.text-4.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/jaraco.text-4.0.0.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
setuptools/_vendor/jaraco.text-4.0.0.dist-info/top_level.txt,sha256=0JnN3LfXH4LIRfXL-QFOGCJzQWZO3ELx4R1d_louoQM,7
setuptools/_vendor/jaraco/context/__init__.py,sha256=br1ydYGo1Xr_Pu1anuEdd-QrjUiz_EY5L_5E4C03L4w,9809
setuptools/_vendor/jaraco/context/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/jaraco/functools/__init__.py,sha256=ZJx9cMs2Nvk2xGUl8OjVGkpjdOaNlSzJrN4dGglgX2g,18599
setuptools/_vendor/jaraco/functools/__init__.pyi,sha256=K4DcbnYIHE5QlMxqf9-cVp-WhycrhuTao4J7O7TMq4Y,3907
setuptools/_vendor/jaraco/functools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/jaraco/text/Lorem ipsum.txt,sha256=N_7c_79zxOufBY9HZ3yzMgOkNv-TkOTTio4BydrSjgs,1335
setuptools/_vendor/jaraco/text/__init__.py,sha256=lazNYXo8IhOR1bFigLAyGiiQao6jtO3KGWh8bZZPx3c,16762
setuptools/_vendor/jaraco/text/layouts.py,sha256=HTC8aSTLZ7uXipyOXapRMC158juecjK6RVwitfmZ9_w,643
setuptools/_vendor/jaraco/text/show-newlines.py,sha256=jT0vp4gLhG20hX2lTB-zKo_i3NgKzj79yRAdz4eMzIM,903
setuptools/_vendor/jaraco/text/strip-prefix.py,sha256=NfVXV8JVNo6nqcuYASfMV7_y4Eo8zMQqlCOGvAnRIVw,412
setuptools/_vendor/jaraco/text/to-dvorak.py,sha256=36nPPsiifwv6RfpAb--3zpgbIx8ohnnI1aR29IJTO9s,118
setuptools/_vendor/jaraco/text/to-qwerty.py,sha256=IQoFY9v7vLTEybcput4KBYm_5GR35pmtgZ_xyrmdTgI,118
setuptools/_vendor/jaraco_context-6.1.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/jaraco_context-6.1.0.dist-info/METADATA,sha256=BDXr_FIFXFqZdO0gwXG2RUOD6vnbsVCIFLp62XxZ1xI,4270
setuptools/_vendor/jaraco_context-6.1.0.dist-info/RECORD,sha256=RZnYds60K37vA6o54jXE6-q2rqJAnb5jRJaFI5PR-Dc,777
setuptools/_vendor/jaraco_context-6.1.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/jaraco_context-6.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
setuptools/_vendor/jaraco_context-6.1.0.dist-info/licenses/LICENSE,sha256=l1WhhRlmbl8PTK49qtPXASvK5IpgCzEjfXXp_hNOZoM,1076
setuptools/_vendor/jaraco_context-6.1.0.dist-info/top_level.txt,sha256=0JnN3LfXH4LIRfXL-QFOGCJzQWZO3ELx4R1d_louoQM,7
setuptools/_vendor/jaraco_functools-4.4.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/jaraco_functools-4.4.0.dist-info/METADATA,sha256=LnnajcNGmSSr46yLIqP-tWkqeb-fR7vIa2U11hhkGEk,2960
setuptools/_vendor/jaraco_functools-4.4.0.dist-info/RECORD,sha256=uq_S1tlMG95FPkyAWsBVEdxTmG4KY7AvZ07w94i-wUY,882
setuptools/_vendor/jaraco_functools-4.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/jaraco_functools-4.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
setuptools/_vendor/jaraco_functools-4.4.0.dist-info/licenses/LICENSE,sha256=WlfLTbheKi3YjCkGKJCK3VfjRRRJ4KmnH9-zh3b9dZ0,1076
setuptools/_vendor/jaraco_functools-4.4.0.dist-info/top_level.txt,sha256=0JnN3LfXH4LIRfXL-QFOGCJzQWZO3ELx4R1d_louoQM,7
setuptools/_vendor/more_itertools-10.8.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/more_itertools-10.8.0.dist-info/METADATA,sha256=arNRUUWr5YsGfwh8hnYxz0z11lP-2BuWQu4SCGw5BLg,39413
setuptools/_vendor/more_itertools-10.8.0.dist-info/RECORD,sha256=ntGxNMCqg3IvNumfORiqlhDOOgpRTXk7u3SjaNRBoB0,1095
setuptools/_vendor/more_itertools-10.8.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/more_itertools-10.8.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
setuptools/_vendor/more_itertools-10.8.0.dist-info/licenses/LICENSE,sha256=CfHIyelBrz5YTVlkHqm4fYPAyw_QB-te85Gn4mQ8GkY,1053
setuptools/_vendor/more_itertools/__init__.py,sha256=5F7E_zpoGcEBW_T_3WE0WYYt8j-gJodIuiBcOJxrOv8,149
setuptools/_vendor/more_itertools/__init__.pyi,sha256=5B3eTzON1BBuOLob1vCflyEb2lSd6usXQQ-Cv-hXkeA,43
setuptools/_vendor/more_itertools/more.py,sha256=mNPKKu5UI7lRL460vgm0QTCWFiGMVCMosSPxVSdibos,163690
setuptools/_vendor/more_itertools/more.pyi,sha256=fpEgNX3O66wY5cnT-s5VYDKNUpAcaCyU3iP84It3OOM,27119
setuptools/_vendor/more_itertools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/more_itertools/recipes.py,sha256=Ma-kuBNZDFhaQDbIJgRmnrG86WzaupbOyUV3v8je3xw,41811
setuptools/_vendor/more_itertools/recipes.pyi,sha256=LNRwN-OL3nkMfQAqx-PPc1fBaetUObb_Z6mdePyzh1c,6226
setuptools/_vendor/packaging-26.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/packaging-26.0.dist-info/METADATA,sha256=M2K7fWom2iliuo2qpHhc0LrKwhq6kIoRlcyPWVgKJlo,3309
setuptools/_vendor/packaging-26.0.dist-info/RECORD,sha256=9QUDMzqulReAfS-02B_CfLYKpkRmb1AXaBJibWIkzl0,2113
setuptools/_vendor/packaging-26.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/packaging-26.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
setuptools/_vendor/packaging-26.0.dist-info/licenses/LICENSE,sha256=ytHvW9NA1z4HS6YU0m996spceUDD2MNIUuZcSQlobEg,197
setuptools/_vendor/packaging-26.0.dist-info/licenses/LICENSE.APACHE,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH4RuTjpRZQ,10174
setuptools/_vendor/packaging-26.0.dist-info/licenses/LICENSE.BSD,sha256=tw5-m3QvHMb5SLNMFqo5_-zpQZY2S8iP8NIYDwAo-sU,1344
setuptools/_vendor/packaging/__init__.py,sha256=y4lVbpeBzCGk-IPDw5BGBZ_b0P3ukEEJZAbGYc6Ey8c,494
setuptools/_vendor/packaging/_elffile.py,sha256=-sKkptYqzYw2-x3QByJa5mB4rfPWu1pxkZHRx1WAFCY,3211
setuptools/_vendor/packaging/_manylinux.py,sha256=Hf6nB0cOrayEs96-p3oIXAgGnFquv20DO5l-o2_Xnv0,9559
setuptools/_vendor/packaging/_musllinux.py,sha256=Z6swjH3MA7XS3qXnmMN7QPhqP3fnoYI0eQ18e9-HgAE,2707
setuptools/_vendor/packaging/_parser.py,sha256=U_DajsEx2VoC_F46fSVV3hDKNCWoQYkPkasO3dld0ig,10518
setuptools/_vendor/packaging/_structures.py,sha256=Hn49Ta8zV9Wo8GiCL8Nl2ARZY983Un3pruZGVNldPwE,1514
setuptools/_vendor/packaging/_tokenizer.py,sha256=M8EwNIdXeL9NMFuFrQtiOKwjka_xFx8KjRQnfE8O_z8,5421
setuptools/_vendor/packaging/licenses/__init__.py,sha256=TwXLHZCXwSgdFwRLPxW602T6mSieunSFHM6fp8pgW78,5819
setuptools/_vendor/packaging/licenses/_spdx.py,sha256=WW7DXiyg68up_YND_wpRYlr1SHhiV4FfJLQffghhMxQ,51122
setuptools/_vendor/packaging/markers.py,sha256=ZX-cLvW1S3cZcEc0fHI4z7zSx5U2T19yMpDP_mE-CYw,12771
setuptools/_vendor/packaging/metadata.py,sha256=CWVZpN_HfoYMSSDuCP7igOvGgqA9AOmpW8f3qTisfnc,39360
setuptools/_vendor/packaging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/packaging/pylock.py,sha256=-R1uNfJ4PaLto7Mg62YsGOHgvskuiIEqPwxOywl42Jk,22537
setuptools/_vendor/packaging/requirements.py,sha256=PMCAWD8aNMnVD-6uZMedhBuAVX2573eZ4yPBLXmz04I,2870
setuptools/_vendor/packaging/specifiers.py,sha256=EPNPimY_zFivthv1vdjZYz5IqkKGsnKR2yKh-EVyvZw,40797
setuptools/_vendor/packaging/tags.py,sha256=cXLV1pJD3UtJlDg7Wz3zrfdQhRZqr8jumSAKKAAd2xE,22856
setuptools/_vendor/packaging/utils.py,sha256=N4c6oZzFJy6klTZ3AnkNz7sSkJesuFWPp68LA3B5dAo,5040
setuptools/_vendor/packaging/version.py,sha256=7XWlL2IDYLwDYC0ht6cFEhapLwLWbmyo4rb7sEFj0x8,23272
setuptools/_vendor/platformdirs-4.4.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/platformdirs-4.4.0.dist-info/METADATA,sha256=u8UhbV9Md7-8VyJyZNUuZrzN5xzPeedeGmBG0CnTAiM,12831
setuptools/_vendor/platformdirs-4.4.0.dist-info/RECORD,sha256=PQ0vHMAYWTxNi6ojlbrwscHGRbvYwYzQZPSctOTJXqA,1218
setuptools/_vendor/platformdirs-4.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/platformdirs-4.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
setuptools/_vendor/platformdirs-4.4.0.dist-info/licenses/LICENSE,sha256=KeD9YukphQ6G6yjD_czwzv30-pSHkBHP-z0NS-1tTbY,1089
setuptools/_vendor/platformdirs/__init__.py,sha256=iORRy6_lZ9tXLvO0W6fJPn8QV7F532ivl-f2WGmabBc,22284
setuptools/_vendor/platformdirs/__main__.py,sha256=HnsUQHpiBaiTxwcmwVw-nFaPdVNZtQIdi1eWDtI-MzI,1493
setuptools/_vendor/platformdirs/android.py,sha256=r0DshVBf-RO1jXJGX8C4Til7F1XWt-bkdWMgmvEiaYg,9013
setuptools/_vendor/platformdirs/api.py,sha256=wPHOlwOsfz2oqQZ6A2FcCu5kEAj-JondzoNOHYFQ0h8,9281
setuptools/_vendor/platformdirs/macos.py,sha256=0XoOgin1NK7Qki7iskD-oS8xKxw6bXgoKEgdqpCRAFQ,6322
setuptools/_vendor/platformdirs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/platformdirs/unix.py,sha256=WZmkUA--L3JNRGmz32s35YfoD3ica6xKIPdCV_HhLcs,10458
setuptools/_vendor/platformdirs/version.py,sha256=i31fi3nNO19D2FdSx8aldD7IFLSqm2YrAo6SmkV0FLM,704
setuptools/_vendor/platformdirs/windows.py,sha256=IFpiohUBwxPtCzlyKwNtxyW4Jk8haa6W8o59mfrDXVo,10125
setuptools/_vendor/tomli-2.4.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/tomli-2.4.0.dist-info/METADATA,sha256=9awKH4-6kItGRs1lUwnpGq2Wm2eHYWrFccpGKjgy_84,10567
setuptools/_vendor/tomli-2.4.0.dist-info/RECORD,sha256=IlQwzpVkDo1Pzbk82uL8ONaFrsAW0OKT1fuZppWIb-0,822
setuptools/_vendor/tomli-2.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/tomli-2.4.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
setuptools/_vendor/tomli-2.4.0.dist-info/licenses/LICENSE,sha256=uAgWsNUwuKzLTCIReDeQmEpuO2GSLCte6S8zcqsnQv4,1072
setuptools/_vendor/tomli/__init__.py,sha256=ahtDjGJA2M_wWVvGpzx4YJtWxrWBx6qE-GH5-UYoECA,314
setuptools/_vendor/tomli/_parser.py,sha256=txeATLE3zHyZ-ushXtYfrZ3LoIs7JzQF2W2KL1gwJPg,25958
setuptools/_vendor/tomli/_re.py,sha256=oSNZ_ilFI6chEuQ01YRSoUydBQr_okF_mSdHTkFmv90,3396
setuptools/_vendor/tomli/_types.py,sha256=-GTG2VUqkpxwMqzmVO4F7ybKddIbAnuAHXfmWQcTi3Q,254
setuptools/_vendor/tomli/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
setuptools/_vendor/wheel-0.46.3.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/wheel-0.46.3.dist-info/METADATA,sha256=IpEKqXyonLzCCgGeJ_4xNgt5KaS9ZsoNMQ-ZpE9szTU,2410
setuptools/_vendor/wheel-0.46.3.dist-info/RECORD,sha256=sCl8OtoXuHJ-Fd3W0eOMipCpl_d5_Pl4mW9v7GLstwI,1734
setuptools/_vendor/wheel-0.46.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/wheel-0.46.3.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
setuptools/_vendor/wheel-0.46.3.dist-info/entry_points.txt,sha256=JJdtSAGTvMLbIkTVZUAMvGKO39FtWfCVF8mp_NH6e4g,110
setuptools/_vendor/wheel-0.46.3.dist-info/licenses/LICENSE.txt,sha256=MMI2GGeRCPPo6h0qZYx8pBe9_IkcmO8aifpP8MmChlQ,1107
setuptools/_vendor/wheel/__init__.py,sha256=UweKvhe4SyP7zFyDoYo8BOuwTA6q3-_WpMmY2NNO54c,59
setuptools/_vendor/wheel/__main__.py,sha256=_83wl9tyGU2cHiqfudpubGHdRL5uonPXnzeznznkxzs,512
setuptools/_vendor/wheel/_bdist_wheel.py,sha256=bpmNa7_s-CYFkVgXf9ENAYTiJ01XBhRW4pxH1T8XYsI,21729
setuptools/_vendor/wheel/_commands/__init__.py,sha256=fCRAQZNDyj2JLrufdgPsBlaRS_t_j_aBUMpXj09KZ4E,4432
setuptools/_vendor/wheel/_commands/convert.py,sha256=0wSJMU0m-6LY16Om8Wmmloy-hJWFZeOmI8hT-2Z7Qms,12743
setuptools/_vendor/wheel/_commands/pack.py,sha256=o3iwjfRHl7N9ul-M2kHbewLJZnqBLAWf0tzUCwoiTMw,3078
setuptools/_vendor/wheel/_commands/tags.py,sha256=Rv2ySVb8-qX3osKp3uJgxcIMXkjt43XUD0-zvC6KvnY,4775
setuptools/_vendor/wheel/_commands/unpack.py,sha256=AjDSS23XYyCSFfifnMutinrpPv-DK_2wbNHkKAUFwgM,1016
setuptools/_vendor/wheel/_metadata.py,sha256=BP5jC9uC1hyicp7nL4FJ2LYixNFpEJIV_uMDY1KBZBg,6188
setuptools/_vendor/wheel/_setuptools_logging.py,sha256=-5KC-lne0ilOUWIDfOkqapUWGMFZhuKYDIavIZiB5kM,781
setuptools/_vendor/wheel/bdist_wheel.py,sha256=HrzYiSzMkh5ohAAhlQnYBS1p8qbr85X6F59xqxd9kBg,1102
setuptools/_vendor/wheel/macosx_libfile.py,sha256=pL0wm88jRMl_4ASgGlNg_mz69Zmv5xm8JSkjLdwyvIQ,16712
setuptools/_vendor/wheel/metadata.py,sha256=GknOO7JJiZMlcEe_fiD7nqnDTTLd0sX_-IgipM4L3-4,757
setuptools/_vendor/wheel/wheelfile.py,sha256=m_g_7TNsEp-j-xnvSr5yDLEFb1nhyObueq9Q5_1_lBA,8720
setuptools/_vendor/zipp-3.23.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
setuptools/_vendor/zipp-3.23.0.dist-info/METADATA,sha256=vdZ9TRbPC_O4k-fRjNPS13StuC837Zhbx3cMYHIms1s,3563
setuptools/_vendor/zipp-3.23.0.dist-info/RECORD,sha256=O_q2YKJHBPhCKOS7HOHw4_qf-A5cgGNSpiay9GDq2DY,1078
setuptools/_vendor/zipp-3.23.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/zipp-3.23.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
setuptools/_vendor/zipp-3.23.0.dist-info/licenses/LICENSE,sha256=WlfLTbheKi3YjCkGKJCK3VfjRRRJ4KmnH9-zh3b9dZ0,1076
setuptools/_vendor/zipp-3.23.0.dist-info/top_level.txt,sha256=iAbdoSHfaGqBfVb2XuR9JqSQHCoOsOtG6y9C_LSpqFw,5
setuptools/_vendor/zipp/__init__.py,sha256=ieXh9GIMdABjKRX_JUJtP9k5wdBLK4Mt5X4nszSkmYE,11976
setuptools/_vendor/zipp/_functools.py,sha256=f6Kt9LxZ4TE-cY1lJVdXSId3memSXmH9IdgMbU-_x2k,575
setuptools/_vendor/zipp/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/zipp/compat/overlay.py,sha256=oEIGAnbr8yGjuKTrVSO2ByewPui71uppbX18BLnYTKE,783
setuptools/_vendor/zipp/compat/py310.py,sha256=S7i6N9mToEn3asNb2ILyjnzvITOXrATD_J4emjyBbDU,256
setuptools/_vendor/zipp/compat/py313.py,sha256=RndvDNtuY7H2D9ecnnzcPBMZ8mZc42gmXD_IwQAXXAE,654
setuptools/_vendor/zipp/glob.py,sha256=DLV9LBsDxA6YVW82e3-tkoNrus1h4R-j3BR6VqS0AzE,3382
setuptools/archive_util.py,sha256=Tl_64hSTtc4y8x7xa98rFVUbG24oArpjzLAYGYP2_sI,7356
setuptools/build_meta.py,sha256=8eEvuboZNOraTSixwLexIVVQU42oy-eH5Tel7QHAiS8,20140
setuptools/cli-32.exe,sha256=MqzBvFQxFsviz_EMuGd3LfLyVP8mNMhwrvC0bEtpb9s,11776
setuptools/cli-64.exe,sha256=u7PeVwdinmpgoMI4zUd7KPB_AGaYL9qVP6b87DkHOko,14336
setuptools/cli-arm64.exe,sha256=uafQjaiA36yLz1SOuksG-1m28JsX0zFIoPZhgyiSbGE,13824
setuptools/cli.exe,sha256=MqzBvFQxFsviz_EMuGd3LfLyVP8mNMhwrvC0bEtpb9s,11776
setuptools/command/__init__.py,sha256=wdSrlNR0P6nCz9_oFtCAiAkeFJMsZa1jPcpXT53f0SM,803
setuptools/command/_requirestxt.py,sha256=ItYMTJGh_i5TlQstX_nFopqEhkC4PJFadBL2Zd3V670,4228
setuptools/command/alias.py,sha256=rDdrMt32DS6qf3K7tjZZyHD_dMKrm77AXcAtx-nBQ0I,2380
setuptools/command/bdist_egg.py,sha256=nTongOhFu6vI6RXLjf6Qq_Fiel8rIt_EHxzdyOUPGZo,17355
setuptools/command/bdist_rpm.py,sha256=LyqI49w48SKk0FmuHsE9MLzX1SuXjL7YMNbZMFZqFII,1435
setuptools/command/bdist_wheel.py,sha256=SknYPVwhrRPfXudmO_gvqNHHHhzSfU8cEmFtQomQ9xI,22247
setuptools/command/build.py,sha256=eI7STMERGGZEpzk1tvJN8p9IOjAAXMcGLzljv2mwI3M,6052
setuptools/command/build_clib.py,sha256=AbgpPIF_3qL8fZr3JIebI-WHTMTBiMfrFkVQz8K40G4,4528
setuptools/command/build_ext.py,sha256=v4lBclgoM2TEZtlAH1AHRHBSmktMzHGytEHDF_1ZR4E,18526
setuptools/command/build_py.py,sha256=eHhfo9z7Qf79vSzrCnq-oEXayQC0R_nx3hWaTgWGv5M,15826
setuptools/command/develop.py,sha256=TYKWIzfv3c3wjAYhH5UD8tW6S6ozZi_fpF6IJILm8Kg,1751
setuptools/command/dist_info.py,sha256=HU752iLLmmYMHbsDBgz2ubRjkgJobugOp8H71LzzDys,3450
setuptools/command/easy_install.py,sha256=XrN5cV51mfzbCDoapZ6iT8nCzaLpumdwJYRKeMHEjCQ,780
setuptools/command/editable_wheel.py,sha256=1EhUMD0YkKTyFB0x6GhRuzSX7j91JgRTe2FDnbphFFs,34891
setuptools/command/egg_info.py,sha256=5xd5VtgfQ6U6hz8XAs4pcetv1CEvVraKfZpTExxnvJk,25888
setuptools/command/install.py,sha256=4x2hiNgBGQrFEXKuPBQMrb8ecSwIfYF4TYHZQLjPVAg,5066
setuptools/command/install_egg_info.py,sha256=3I9IPCH7D59Sh-6aVYz-h6wwyxq-wkxrKwKg3nDdJqs,2075
setuptools/command/install_lib.py,sha256=9n1_U83eHcERL_a_rv_LhHCkhXlLdqyZ4SdBow-9qcE,4319
setuptools/command/install_scripts.py,sha256=JmDGngHzCO2Y1j4maFNdHB_ILhGPhk-b5KhxsZwUwiQ,2490
setuptools/command/launcher manifest.xml,sha256=xlLbjWrB01tKC0-hlVkOKkiSPbzMml2eOPtJ_ucCnbE,628
setuptools/command/rotate.py,sha256=XNd_BEEOWAJHW1FcLTMUWWl4QB6zAuk7b8VWQg3FHos,2187
setuptools/command/saveopts.py,sha256=Np0PVb7SD7oTbu9Z9sosS7D-CkkIkU7x4glu5Es1tjA,692
setuptools/command/sdist.py,sha256=nS2xogcTfQZwbZH1AQ5WYh13KCvNda9xwUT57sVxTec,7426
setuptools/command/setopt.py,sha256=YV7qj2mB-aQsOrWCh3i_vbd9Kvt040o3Bb54eR8Yl5A,5116
setuptools/command/test.py,sha256=x9z3DDCQi-_3-TRf8yNeQ9QH-G6yR1au7kX0ijedKqU,1400
setuptools/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/compat/py310.py,sha256=JwjQZ3cNTizfpDLNl9GLsUGzBr-tVlMPxmMYVDTlhiI,344
setuptools/compat/py311.py,sha256=e6tJAFwZEP82hmMBl10HYeSypelo_Ti2wTjKZVKLwOE,790
setuptools/compat/py312.py,sha256=vYKVtdrdOTsO_R90dJkEXsFwfMJFuIFJflhIgHrjJ-Y,366
setuptools/compat/py39.py,sha256=BJMtnkfcqyTfccqjYQxfoRtU2nTnWaEESBVkshTiXqY,493
setuptools/config/NOTICE,sha256=Ld3wiBgpejuJ1D2V_2WdjahXQRCMkTbfo6TYVsBiO9g,493
setuptools/config/__init__.py,sha256=aiPnL9BJn1O6MfmuNXyn8W2Lp8u9qizRVqwPiOdPIjY,1499
setuptools/config/_apply_pyprojecttoml.py,sha256=tQXU9M4lcrd3iwO_2reihz22IbHaHg_Z-lAMBXZRzW8,19120
setuptools/config/_validate_pyproject/NOTICE,sha256=XTANv6ZDE4sBO3WsnK7uWR-VG4sO4kKIw0zNkmxHgMg,18737
setuptools/config/_validate_pyproject/__init__.py,sha256=dnp6T7ePP1R5z4OuC7Fd2dkFlIrtIfizUfvpGJP6nz0,1042
setuptools/config/_validate_pyproject/error_reporting.py,sha256=meldD7nBQdolQhvG-43r1Ue-gU1n7ORAJR86vh3Rrvk,11813
setuptools/config/_validate_pyproject/extra_validations.py,sha256=-GUG5S--ijY8WfXbdXPoHl6ywGsyEF9dtDpenSoJPHg,2858
setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py,sha256=w749JgqKi8clBFcObdcbZVqsmF4oJ_QByhZ1SGbUFNw,1612
setuptools/config/_validate_pyproject/fastjsonschema_validations.py,sha256=FihD5ZcM6p77BPZ04CGqh3BEwVNoPMKJZJAyuJpkAU0,354682
setuptools/config/_validate_pyproject/formats.py,sha256=TETokJBK9hjl-cVg1olsojkJwLxfP7_chgJQNmzAB98,13564
setuptools/config/distutils.schema.json,sha256=Tcp32kRnhwORGw_9p6GEi08lj2h15tQRzOYBbzGmcBU,972
setuptools/config/expand.py,sha256=STKJ6oNAo6avEBVUiR25WpfIthVPVZQG65Z-5-t78QI,16064
setuptools/config/pyprojecttoml.py,sha256=YMu5PdbJJI5azp6kR_boM1mflf5nqOA-InF4s6LnLgw,18320
setuptools/config/setupcfg.py,sha256=Wnfbrk6D0GQV-Z2AE0b0KnL-WGrw-KQUcsem3naImBw,26695
setuptools/config/setuptools.schema.json,sha256=dZBRuSEnZkatoVlt1kVwG8ocTeRdO7BD0xvOWKH54PY,16071
setuptools/depends.py,sha256=jKYfjmt_2ZQYVghb8L9bU7LJ6erHJ5ze-K_fKV1BMXk,5965
setuptools/discovery.py,sha256=XYIeFN20WEsEtssmpzCFlnda-Qxilj8KlLYKaJphAto,21286
setuptools/dist.py,sha256=vaXXehKAG8Axl1KyEDC1VoM6yW3_jcIA879B-caGsKA,45205
setuptools/errors.py,sha256=gY2x2PIaIgy01yRANRC-zcCwxDCqCScgJoCOZFe0yio,3024
setuptools/extension.py,sha256=GbCxJ9rRk2rZcXS4qgmnzWNG36HlhLfUEvNwB-OKGk8,6818
setuptools/glob.py,sha256=AC_B33DY8g-CHELxDsJrtwFrpiucSAZsakPFdSOQzhc,6062
setuptools/gui-32.exe,sha256=hdrh6V13hF8stZvKw9Sv50u-TJGpvMW_SnHNQxBNvnw,11776
setuptools/gui-64.exe,sha256=NHG2FA6txkEid9u-_j_vjDRaDxpZd2CGuAo2GMOoPjs,14336
setuptools/gui-arm64.exe,sha256=5pT0dDQFyLWSb_RX22_n8aEt7HwWqcOGR4TT9OB64Jc,13824
setuptools/gui.exe,sha256=hdrh6V13hF8stZvKw9Sv50u-TJGpvMW_SnHNQxBNvnw,11776
setuptools/installer.py,sha256=Wy_hG1g1r-45E6IWh7lvQ0Pk0QHNl6JJbu3hQmr1_Ek,5184
setuptools/launch.py,sha256=IBb5lEv69CyuZ9ewIrmKlXh154kdLmP29LKfTMkximE,820
setuptools/logging.py,sha256=W16iHJ1HcCXYQ0RxyrEfJ83FT4175tCtoYg-E6uSpVI,1261
setuptools/modified.py,sha256=ZwbfBfCFP88ltvbv_dJDz-t1LsQjnM-JUpgZnnQZjjM,568
setuptools/monkey.py,sha256=nOD5vgLG7IpKAs7LrnpJxGPaCW54Rzj-onJmm91otoY,3733
setuptools/msvc.py,sha256=IdCsRhdJLeyZG3gyDrGx2DqZymoay3ndBXC77taHHCA,42909
setuptools/namespaces.py,sha256=2GGqYY1BNDEhMtBc1rHTv7klgmNVRdksJeW-L1f--ys,3171
setuptools/script (dev).tmpl,sha256=RUzQzCQUaXtwdLtYHWYbIQmOaES5Brqq1FvUA_tu-5I,218
setuptools/script.tmpl,sha256=WGTt5piezO27c-Dbx6l5Q4T3Ff20A5z7872hv3aAhYY,138
setuptools/tests/__init__.py,sha256=AnBfls2iJbTDQzmMKeLRt-9lxhaOHUVOZEgXv89Uwvs,335
setuptools/tests/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/tests/compat/py39.py,sha256=eUy7_F-6KRTOIKl-veshUu6I0EdTSdBZMh0EV0lZ1-g,135
setuptools/tests/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/tests/config/downloads/__init__.py,sha256=9ixnDEdyL_arKbUzfuiJftAj9bGxKz8M9alOFZMjx9Y,1827
setuptools/tests/config/downloads/preload.py,sha256=sIGGZpY3cmMpMwiJYYYYHG2ifZJkvJgEotRFtiulV1I,450
setuptools/tests/config/setupcfg_examples.txt,sha256=cAbVvCbkFZuTUL6xRRzRgqyB0rLvJTfvw3D30glo2OE,1912
setuptools/tests/config/test_apply_pyprojecttoml.py,sha256=KVBqnElEW5p9HJpTYnztZqd3RXYaY6SrSY8ek9ysq7s,28822
setuptools/tests/config/test_expand.py,sha256=S0oT6JvgA_oujR4YS4RUuf5gmOt1CTQV66RQDzV8xd4,8933
setuptools/tests/config/test_pyprojecttoml.py,sha256=CzLH1qcKDQGxCyLHC_ZYMObms1D_Jtp6AuJROOFI_D8,12438
setuptools/tests/config/test_pyprojecttoml_dynamic_deps.py,sha256=1MRtzcxZag-ElRwVGt0kUk4KPRA-RSwKkibO8-Vy51w,3265
setuptools/tests/config/test_setupcfg.py,sha256=iwViCQFLGVWZLgCDrBv8HKBBCj-Onr8aNdioD9_lBEo,33712
setuptools/tests/contexts.py,sha256=Ozdfc2KydF9x9wODUsdun800myLuP27uxoeT06Gbk7M,3166
setuptools/tests/environment.py,sha256=95_UtTaRiuvwYC9eXKEHbn02kDtZysvZq3UZJmPUj1I,3102
setuptools/tests/fixtures.py,sha256=jE7pIFQt91dZIUc6Btsffi8OdBqmY_7DNeWI1Stv7i8,12224
setuptools/tests/indexes/test_links_priority/external.html,sha256=eL9euOuE93JKZdqlXxBOlHbKwIuNuIdq7GBRpsaPMcU,92
setuptools/tests/indexes/test_links_priority/simple/foobar/index.html,sha256=DD-TKr7UU4zAjHHz4VexYDNSAzR27levSh1c-k3ZdLE,174
setuptools/tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/tests/integration/helpers.py,sha256=ieQtGuIohqNI_RHMH0yxE602Uz4E8wysUj7XaXYH30Y,2688
setuptools/tests/integration/test_pbr.py,sha256=2eKuklFNmpnBgA_eEhYPBr6rLLG2Xm4MY6PlcmzZgGU,432
setuptools/tests/integration/test_pip_install_sdist.py,sha256=SFbvuYF_hDzt6OtsQ5GjFNnxmoJ_eElfvpYsiyyGJ-g,8256
setuptools/tests/mod_with_constant.py,sha256=X_Kj80M55w1tmQ4f7uZY91ZTALo4hKVT6EHxgYocUMQ,22
setuptools/tests/namespaces.py,sha256=HPcI3nR5MCFWXpaADIJ1fwKxymcQgBkuw87Ic5PUSAQ,2774
setuptools/tests/script-with-bom.py,sha256=hRRgIizEULGiG_ZTNoMY46HhKhxpWfy5FGcD6Qbh5fc,18
setuptools/tests/test_archive_util.py,sha256=buuKdY8XkW26Pe3IKAoBRGHG0MDumnuNoPg2WsAQzIg,845
setuptools/tests/test_bdist_deprecations.py,sha256=75Xq3gYn79LIIyusEltbHan0bEgAt2e_CaL7KLS8-KQ,775
setuptools/tests/test_bdist_egg.py,sha256=6PaYN1F3JDbIh1uK0urv7yJFcx98z5dn9SOJ8Mv91l8,1957
setuptools/tests/test_bdist_wheel.py,sha256=xGHVaggiYobkOuGwkLK2bNejcSh8z2Fiuq-ge_S-yKo,23091
setuptools/tests/test_build.py,sha256=wJgMz2hwHADcLFg-nXrwRVhus7hjmAeEGgrpIQwCGnA,798
setuptools/tests/test_build_clib.py,sha256=bX51XRAf4uO7IuHFpjePnoK8mE74N2gsoeEqF-ofgws,3123
setuptools/tests/test_build_ext.py,sha256=e4ZSxsYPB5zq1KSqGEuATZ0t0PJQzMhjjkKJ-hIjcgc,10099
setuptools/tests/test_build_meta.py,sha256=ToI7-2LUnHuIPhKN8EkDkSEfLCvLqLI6VJhqwR5pVuU,33320
setuptools/tests/test_build_py.py,sha256=SIcHFX3YNErcVkWjf0eDRuKmsO9kTymKjfK-PkOi9M0,14201
setuptools/tests/test_config_discovery.py,sha256=FqV-lOtkqaI-ayzU2zocSdD5TaRAgCZnixNDilKA6FQ,22580
setuptools/tests/test_core_metadata.py,sha256=vbVJ5_Lsx_hsO_GdB6nQEXJRjA2ydx6_qSbr5LpheAA,20881
setuptools/tests/test_depends.py,sha256=yQBXoQbNQlJit6mbRVoz6Bb553f3sNrq02lZimNz5XY,424
setuptools/tests/test_develop.py,sha256=MHYL_YDqNMU5jhKkjsBUGKMGCkrva8CFR8dRc6kkYKE,3072
setuptools/tests/test_dist.py,sha256=M4FikA-vL0_lZdA_5wry2Z9CBuSugr0Pj54dBZ3peBM,8951
setuptools/tests/test_dist_info.py,sha256=EihdrU9UZkPV7d19G-K_OtOByp64GvGnf4or-f8Iq54,5005
setuptools/tests/test_distutils_adoption.py,sha256=_eynrOfyEqXFEmjUJhzpe8GXPyTUPvNSObs4qAAmBy8,5987
setuptools/tests/test_editable_install.py,sha256=Tg4kunvwYoDLYsfvSkggneUgpKQferUDx3EEvvdfmwE,42619
setuptools/tests/test_egg_info.py,sha256=R7nT27YhVz9oSuDyimAGerWglkbRWiMSPBs5FzcSnBM,44941
setuptools/tests/test_extern.py,sha256=rpKU6oCcksumLwf5TeKlDluFQ0TUfbPwTLQbpxcFrCU,296
setuptools/tests/test_find_packages.py,sha256=CTLAcTzWGWBLCcd2aAsUVkvO3ibrlqexFBdDKOWPoq8,7819
setuptools/tests/test_find_py_modules.py,sha256=zQjuhIG5TQN2SJPix9ARo4DL_w84Ln8QsHDUjjbrtAQ,2404
setuptools/tests/test_glob.py,sha256=P3JvpH-kXQ4BZ3zvRF-zKxOgwyWzwIaQIz0WHdxS0kk,887
setuptools/tests/test_install_scripts.py,sha256=scIrJ6a_ssKqg4vIBNaUjmAKHEYLUUZ9WKnPeKnE6gc,3433
setuptools/tests/test_logging.py,sha256=zlE5DlldukC7Jc54FNvDV_7ux3ErAkrfrN5CSsnNOUQ,2099
setuptools/tests/test_manifest.py,sha256=eMg65pIA52DizB6mpktSU-b8CjwaNCS5MSgL_V1LrFI,18562
setuptools/tests/test_namespaces.py,sha256=Y6utoe5PHHqL_DlgawqB9F8XpsUDPvvw1sQMenK04e0,4515
setuptools/tests/test_scripts.py,sha256=_ra506yQF7n72ROUDcz2r3CTsGsawO1m-1oqA9EQCfw,379
setuptools/tests/test_sdist.py,sha256=oKMgvBrkfTsPH5jqsrhFxRMbtUDoOy4vKfwll3kGCg0,32808
setuptools/tests/test_setopt.py,sha256=3VxxM4ATfP-P4AGnDjoWCnHr5-i9CSEQTFYU1-FTnvI,1365
setuptools/tests/test_setuptools.py,sha256=_eIhqKf45-OtHqxRf20KndOZJlJdS0PuFLXBO3M-LN8,9008
setuptools/tests/test_shutil_wrapper.py,sha256=g15E11PtZxG-InB2BWNFyH-svObXx2XcMhgMLJPuFnc,641
setuptools/tests/test_unicode_utils.py,sha256=xWfEEl8jkQCt9othUTXJfFmdyATAFggJs2tTxjbumbw,316
setuptools/tests/test_virtualenv.py,sha256=g-njC_9JTAs1YVx_1dGJ_Q6RlInO4qKVu9-XAgNb6TY,3730
setuptools/tests/test_warnings.py,sha256=zwR2zcnCeCeDqILZlJOPAcuyPHoDvGu1OtOVYiLMk74,3347
setuptools/tests/test_wheel.py,sha256=iMfVTNixu4puf6xvRYjQDw4Zg_OHVCQjSy7SztvVYqE,18722
setuptools/tests/test_windows_wrappers.py,sha256=wBjXN3iGldkzRGTgKTrx99xqUqwPJ0V-ldyiB1pWD-g,7868
setuptools/tests/text.py,sha256=a12197pMVTvB6FAWQ0ujT8fIQiLIWJlFAl1UCaDUDfg,123
setuptools/tests/textwrap.py,sha256=FNNNq_MiaEJx88PnsbJQIRxmj1qmgcAOCXXRsODPJN4,98
setuptools/unicode_utils.py,sha256=ukMGh8pEAw6F_Ezb-K5D3c-078RgA_GcF0oW6lg4lSs,3189
setuptools/version.py,sha256=WJCeUuyq74Aok2TeK9-OexZOu8XrlQy7-y0BEuWNovQ,161
setuptools/warnings.py,sha256=oY0Se5eOqje_FEyjTgonUc0XGwgsrI5cgm1kkwulz_w,3796
setuptools/wheel.py,sha256=iI-LSDrgHMlJIzQMALVlJRq3Qesgbj7xa6hWZYJyZl4,9532
setuptools/windows_support.py,sha256=wW4IYLM1Bv7Z1MaauP2xmPjyy-wkmQnXdyvXscAf9fw,726

View file

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: setuptools (80.10.2)
Root-Is-Purelib: true
Tag: py3-none-any

View file

@ -0,0 +1,51 @@
[distutils.commands]
alias = setuptools.command.alias:alias
bdist_egg = setuptools.command.bdist_egg:bdist_egg
bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
bdist_wheel = setuptools.command.bdist_wheel:bdist_wheel
build = setuptools.command.build:build
build_clib = setuptools.command.build_clib:build_clib
build_ext = setuptools.command.build_ext:build_ext
build_py = setuptools.command.build_py:build_py
develop = setuptools.command.develop:develop
dist_info = setuptools.command.dist_info:dist_info
easy_install = setuptools.command.easy_install:easy_install
editable_wheel = setuptools.command.editable_wheel:editable_wheel
egg_info = setuptools.command.egg_info:egg_info
install = setuptools.command.install:install
install_egg_info = setuptools.command.install_egg_info:install_egg_info
install_lib = setuptools.command.install_lib:install_lib
install_scripts = setuptools.command.install_scripts:install_scripts
rotate = setuptools.command.rotate:rotate
saveopts = setuptools.command.saveopts:saveopts
sdist = setuptools.command.sdist:sdist
setopt = setuptools.command.setopt:setopt
[distutils.setup_keywords]
dependency_links = setuptools.dist:assert_string_list
eager_resources = setuptools.dist:assert_string_list
entry_points = setuptools.dist:check_entry_points
exclude_package_data = setuptools.dist:check_package_data
extras_require = setuptools.dist:check_extras
include_package_data = setuptools.dist:assert_bool
install_requires = setuptools.dist:check_requirements
namespace_packages = setuptools.dist:check_nsp
package_data = setuptools.dist:check_package_data
packages = setuptools.dist:check_packages
python_requires = setuptools.dist:check_specifier
setup_requires = setuptools.dist:check_requirements
use_2to3 = setuptools.dist:invalid_unless_false
zip_safe = setuptools.dist:assert_bool
[egg_info.writers]
PKG-INFO = setuptools.command.egg_info:write_pkg_info
dependency_links.txt = setuptools.command.egg_info:overwrite_arg
eager_resources.txt = setuptools.command.egg_info:overwrite_arg
entry_points.txt = setuptools.command.egg_info:write_entries
namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
requires.txt = setuptools.command.egg_info:write_requirements
top_level.txt = setuptools.command.egg_info:write_toplevel_names
[setuptools.finalize_distribution_options]
keywords = setuptools.dist:Distribution._finalize_setup_keywords
parent_finalize = setuptools.dist:_Distribution.finalize_options

View file

@ -0,0 +1,17 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

View file

@ -0,0 +1,3 @@
_distutils_hack
pkg_resources
setuptools

View file

@ -0,0 +1,2 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, eros est euismod turpis, id tincidunt sapien risus a quam. Maecenas fermentum consequat mi. Donec fermentum. Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, commodo eget, consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl adipiscing sapien, sed malesuada diam lacus eget erat. Cras mollis scelerisque nunc. Nullam arcu. Aliquam consequat. Curabitur augue lorem, dapibus quis, laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, molestie eu, feugiat in, orci. In hac habitasse platea dictumst.

View file

@ -0,0 +1,26 @@
# SPSDK Applications
After installing SPSDK, several applications are present directly on PATH as executables.
- [spsdk](spsdk_apps.py) - entry point for all available applications.
- [blhost](blhost.py) - console script for MBoot module.
- [dk6prog](dk6prog.py) - utility for DK6 Programming tool.
- [nxpcrypto](nxpcrypto.py) - utility for generating/verifying RSA/ECC key pairs, and converting key file format (PEM/DER/RAW).
- [nxpdebugmbox](nxpdebugmbox.py) - utility for performing the Debug Authentication.
- [nxpdevhsm](nxpdevhsm.py) - utility for generating initialization SB file.
- [nxpdevscan](nxpdevscan.py) - utility for listing all connected NXP USB and UART devices.
- [nxpele](nxpele.py) - utility for communication with NXP EdgeLock Enclave.
- [nxpimage](nxpimage.py) - utility for generating TrustZone, MasterBootImage and SecureBinary images.
- [pfr](pfr.py) - simple utility for creation and analysis of protected regions(PFR /IFR) - CMPA, CFPA, ROMCFG and CMACTABLE.
- [sdphost](sdphost.py) - console script for SDP module.
- [sdpshost](sdpshost.py) - console script for SDPS module.
- [shadowregs](shadowregs.py) - utility for Shadow Registers controlling.
- [tpconfig](tpconfig.py) - utility for Trust provisioning config application.
- [tphost](tphost.py) - utility for Trust provisioning host application.
`` spsdk --help`` - lists all available commands.
`` spsdk <application> --help`` - print help for given application.
`` spsdk <application> <command> --help `` - print help for given command.

View file

@ -0,0 +1,65 @@
# Copyright 2023-2024 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
# This is template for configuration file used for generating certificates
# ==============================================
# Issuer identification fields
# ==============================================
# All available option can be found within class NameOID in
# cryptography/src/cryptography/x509/oid.py at https://github.com/pyca/cryptography
issuer:
COMMON_NAME: NXP
COUNTRY_NAME: CZ
LOCALITY_NAME: Roznov pod Radhostem
STATE_OR_PROVINCE_NAME: Morava
STREET_ADDRESS: 1.maje 1009
ORGANIZATION_NAME: SPSDK Team
# ==============================================
# Subject identification fields
# ==============================================
# All available option can be found within class NameOID in
# cryptography/src/cryptography/x509/oid.py at https://github.com/pyca/cryptography
subject:
COMMON_NAME: NXP - SPSDK
COUNTRY_NAME: CZ
LOCALITY_NAME: Roznov pod Radhostem
STATE_OR_PROVINCE_NAME: Morava
STREET_ADDRESS: 1.maje 1009
ORGANIZATION_NAME: SPSDK Team
POSTAL_CODE: 756 61
# ==============================================
# The certificate settings
# ==============================================
# Path, where issuer private key is stored
# If the issuer_private_key is encrypted, the interactive prompt will ask for password
# For loading the password in non-interactive way, the configuration parameter 'issuer_private_key_password' can be used.
# There are multiple formats of issuer_private_key_password values:
# 1. If the value is an existing path, first line of file is read and returned
# 2. If the value has format '$ENV_VAR', the value of environment variable ENV_VAR is returned
# 3. If the value has format '$ENV_VAR' and the value contains a valid path to a file, the first line of a file is returned
# 4. If the value does not match any options above, the input value itself is returned
issuer_private_key: issuer_key.pem
# Use PSS padding in case of RSA private key
pss_padding: false
# Path, where subject public key is stored
subject_public_key: subject_key.pub
# Serial number of certificate
serial_number: 12346578
# Validity duration in days
duration: 3650
# ==============================================
# Certificate basic extensions
# ==============================================
extensions:
BASIC_CONSTRAINTS:
# Delegate certificate as a signing authority to create an intermediate certificates.
ca: false # Valid values true|false
# Integer length of the path of certificate signature from a given certificate, back to the root certificate
path_length:

View file

@ -0,0 +1,27 @@
-- Definition derived from openssl 3.0
OSCCA DEFINITIONS ::= BEGIN
Signature ::= SEQUENCE {
r INTEGER,
s INTEGER
}
KeySet ::= SEQUENCE {
number INTEGER,
prk OCTET STRING,
puk [1] EXPLICIT BIT STRING
}
Private ::= SEQUENCE {
number INTEGER,
ids SEQUENCE OF OBJECT IDENTIFIER,
keyset OCTET STRING
}
Public ::= SEQUENCE {
ids SEQUENCE OF OBJECT IDENTIFIER,
puk BIT STRING
}
END

View file

@ -0,0 +1,25 @@
-- Definition based on OTPS HSM implementation
-- To generate Python code use 'asn1ate' with pyparsing<3
OTPS DEFINITIONS ::= BEGIN
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
IdentifiedSubjectPublicKeyInfo ::= SEQUENCE {
identifier [0] IMPLICIT IA5String,
version [1] IMPLICIT INTEGER,
typeName [2] IMPLICIT IA5String,
owner [3] IMPLICIT IA5String OPTIONAL,
usage [4] IMPLICIT INTEGER,
subjectPublicKeyInfo SubjectPublicKeyInfo
}
END

View file

@ -0,0 +1,480 @@
# Copyright 2023-2025 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
revisions: {}
latest: latest
# General MCU information
info:
use_in_doc: True # Include this MCU in generated documentation
purpose: General Purpose Processor
# Web page of MCU representative
web: https://www.nxp.com
memory_map: {} # Memory map basic info
isp:
rom:
protocol: mboot # Possible options:[mboot, sdps, sdp]
interfaces: ["uart", "usb", "spi", "i2c"]
flashloader: {}
features:
# ======== Communication buffer section ========
comm_buffer:
address: 0x2000_8000
size: 0x1000
tool: blhost
# ======== Fuses description section ========
fuses:
tool: blhost
reg_spec: fuses.json
grouped_registers: []
# ======== Blhost section ========
blhost: {}
# properties:
# 0: list-properties
# 1: current-version
# 2: available-peripherals
# 3: flash-start-address
# 4: flash-size-in-bytes
# 5: flash-sector-size
# 6: flash-block-count
# 7: available-commands
# 8: check-status
# 9: reserved
# 10: verify-writes
# 11: max-packet-size
# 12: reserved-regions
# 13: reserved_1
# 14: ram-start-address
# 15: ram-size-in-bytes
# 16: system-device-id
# 17: security-state
# 18: unique-device-id
# 19: flash-fac-support
# 20: flash-access-segment-size
# 21: flash-access-segment-count
# 22: flash-read-margin
# 23: qspi/otfad-init-status
# 24: target-version
# 25: external-memory-attributes
# 26: reliable-update-status
# 27: flash-page-size
# 28: irq-notify-pin
# 29: pfr-keystore-update-opt
# 30: byte-write-timeout-ms
# 31: fuse-locked-status
# ======== Certificate block section ========
cert_block:
sub_features: [based_on_cert1]
rot_type: "cert_block_1"
isk_data_alignment: 4
isk_data_limit: 96
# ======== DAT section ========
dat:
socc: 0 # SOCC identification
based_on_ele: False # Flag if the implementation of DAT is based on EdgeLock Enclave
# famode_cert: [] # List of Fault analysis Mode certificates (names of MBI classes)
# famode_cfg_defaults: {} # Dictionary of default values of standard MBI members for FAmode image
used_beacons_on_ele: False # The DAT ELE implementation is using certificate and authentication beacons
auth_beacon_length: 2 # The length in bytes of authentication beacon
dmbox_ap_ix: -1 # Typical Index of debug mailbox access port is 2
mem_ap_ix: -1 # Typical Index of debug mailbox access port is 0
# non_standard_statuses: # dictionary of non standard return statuses from various commands
# 2: # Command get_crp_level
# 0xFFFF_FFFF: ROP_LEVEL0
# 0xEEBA_04C3: ROP_LEVEL1
# 0x4939_8D8B: ROP_LEVEL2
# 0xB0AB_B703: ROP_LEVEL3
dac_rot_type: default # Default type is full RKTH/SRK value
command_delays: # Additional standard command delays per individual DM commands
ERASE_FLASH: 0.5
# Memory addresses for SSF certificate data
ssf_cert_memory:
ecdsa_puk_address: 0x0 # Default address for ECDSA PUK (will be overridden by device-specific values)
ecdsa_puk_size: 0x0 # Default size for ECDSA PUK
hybrid_puk_address: 0x0 # Default address for Hybrid PUK
hybrid_puk_size: 0x0 # Default size for Hybrid PUK
# ======== MBI section ========
mbi:
mbi_classes: {}
images: {}
# ======== HABv4 section ========
hab: {}
# ======== AHAB section ========
ahab:
sub_features: [ahab_image]
containers_max_cnt: 2
oem_images_max_cnt: 8
valid_offset_minimal_alignment: 4
container_types: [1] # Supported container types
certificate_type: standard # The standard certificate
iae_has_signed_offsets: False # There is a special cases when the Container is after images
core_ids: {}
image_types: {}
image_types_mapping: {}
allow_empty_hash: False # Some chips allow empty image hash in OEM Open LC
# image_types: Keep it here as a template for new NPI
# CSF: [0x01, csf, CSF Image]
# SCD: [0x02, scd, SCD Image]
# EXECUTABLE: [0x03, executable, Executable Image]
# DATA: [0x04, data, Data Image]
# DCD_IMAGE: [0x05, dcd_image, DCD Image]
# ELE: [0x06, ele, EdgeLock Enclave Image]
# PROVISIONING_IMAGE: [0x07, provisioning_image, Provisioning Image]
# DEK_VALIDATION_FCB_CHK: [0x08, dek_validation_fcb_chk, DEK validation FCB check Image]
# PROVISIONING_DATA: [0x09, provisioning_data, Provisioning data Image]
# EXECUTABLE_FAST_BOOT_IMAGE: [0x0A, executable_fast_boot_image, Executable fast boot Image]
# V2X_PRIMARY: [0x0B, v2x_primary, V2X primary Image]
# V2X_SECONDARY: [0x0C, v2x_secondary, V2X secondary Image]
# V2X_ROM_PATCH: [0x0D, v2x_rom_patch, V2X rom patch Image]
# V2X_DUMMY: [0x0E, v2x_dummy, V2X dummy Image]
double_authentication_load_address: 0
double_authentication_core_id: 0
double_authentication_image_type: 0
extra_containers: []
fuses:
_name: "AHAB SRK"
srkh: "__srk_hash" # SRK hash fuse
# ======== PFR section ========
pfr:
sub_features: [cmpa, cfpa]
cmpa:
erase_method: write_memory
additional_data: # extra data defined by customer
enabled: False
offset: -1
max_size: 0
cfpa:
additional_data: # extra data defined by customer
enabled: False
offset: -1
max_size: 0
requires_reset: False
requires_scratch_erase: False
# ======== Bootable image section ========
bootable_image:
mem_types: {}
# ======== FCB section ========
fcb:
mem_types: {}
# ======== XMCD section ========
xmcd:
header:
reg_spec: ../../common/xmcd/flexspi_ram_header.json
mem_types: {}
fuses: {}
# ======== BEE section ========
bee: {}
# ======== IEE section ========
iee:
key_blob_rec_size: 96
key_blob_max_cnt: 4
key_blob_min_cnt: 4
has_kek_fuses: False
additional_template: []
additional_template_text: ""
generate_keyblob: True
# ======== OTFAD section ========
otfad:
key_blob_rec_size: 64
key_blob_max_cnt: 4
key_blob_min_cnt: 4
byte_swap: false
keyblob_byte_swap_cnt: 0
sb_21_supported: True
has_kek_fuses: False
additional_template: []
additional_template_text: ""
supports_key_scrambling: False
reversed_scramble_key: False
# ======== Secure binary v2.1 section ========
sb21:
keyblobs: true
supported_commands: []
# ======== Secure binary v3.1 section ========
sb31:
supported_commands: []
key_wraps_version: 1
variable_block_length: false
commands_block_length: 256
supports_compression: false
command_rules: []
# ======== Secure binary v4.0 section ========
sb40:
supported_commands: []
key_wraps_version: 2
variable_block_length: true
commands_block_length: 4096
supports_compression: true
# ======== Secure binary vX section ========
sbx:
commands_block_length: 256
variable_block_length: false
supported_commands: []
# ======== Secure binary c section ========
sbc:
commands_block_length: 256
key_wraps_version: 2
variable_block_length: false
supported_commands: []
# ======== Shadow registers section ========
shadow_regs:
inverted_regs: {}
computed_fields: {}
reset_type: hw_reset # possible options: [hw_reset, nvic_reset]
# ======== Device Hardware Security Module (HSM) section ========
devhsm:
sub_features: [DevHsm]
supported_commands:
- erase
- load
- programFuses
- programIFR
- copy
- loadKeyBlob
- configureMemory
- fillMemory
- checkFwVersion
flag: 0x1
key_blob_offset: 0x4
key_blob_command_position: -1
devbuff_wrapped_cust_mk_sk_key_size: 0x30
# ======== Trust Zone section ========
tz:
version: v1 # TrustZone configuration version v1.0
reg_spec: tz.json
# ======== EdgeLock Enclave section ========
ele:
ele_device: uboot_fastboot
# ======== Memory configuration ========
memcfg:
data_file: ../../common/memcfg/memcfg_data.yaml
peripherals:
flexspi_nor:
reg_spec: ../../common/memcfg/opt_word_flexspi_nor.json
region_number: 0x09
ow_counts_rule: OptionSize
runtime_instance: True
mem_type: nor
interfaces: [octal_spi, quad_spi, hyper_flash]
instances: []
xspi_nor:
reg_spec: ../../common/memcfg/opt_word_xspi_nor.json
region_number: 0x0b
ow_counts_rule: OptionSize
runtime_instance: True
mem_type: nor
interfaces: [octal_spi, quad_spi]
instances: []
flexspi_nand:
reg_spec: ../../common/memcfg/opt_word_flexspi_nand.json
region_number: 0x101
ow_counts_rule: OptionSize
runtime_instance: True
mem_type: nand
interfaces: [quad_spi]
instances: []
semc_nor:
reg_spec: ../../common/memcfg/opt_word_semc_nor.json
region_number: 0x08
ow_counts_rule: AcTimingMode
mem_type: nor
interfaces: [parallel]
instances: []
semc_nand:
reg_spec: ../../common/memcfg/opt_word_semc_nand.json
region_number: 0x100
ow_counts_rule: All
mem_type: nand
interfaces: [parallel]
instances: []
spi_nor:
reg_spec: ../../common/memcfg/opt_word_spi_nor.json
region_number: 0x110
ow_counts_rule: OptionSize
mem_type: nor
interfaces: [spi]
instances: []
# spi_nand:
# region_number: 0x101
# instances: []
mmc:
reg_spec: ../../common/memcfg/opt_word_mmc.json
region_number: 0x121
ow_counts_rule: All
mem_type: sd
interfaces: [instance_0, instance_1, instance_2, instance_3]
instances: []
emmc:
reg_spec: ../../common/memcfg/opt_word_emmc.json
region_number: 0x121
ow_counts_rule: All
mem_type: sd
interfaces: [instance_0, instance_1, instance_2, instance_3]
instances: []
sd:
reg_spec: ../../common/memcfg/opt_word_sd.json
region_number: 0x120
ow_counts_rule: All
mem_type: sd
interfaces: [instance_0, instance_1, instance_2, instance_3]
instances: []
# XIP Memories in internal memory address range
# mem_region_internal = 0x0 # Internal memory (include all on chip memory)
# mem_region_quad_spi0 = 0x1 # Quad SPI memory 0
# mem_region_ifr0_fuse = 0x4 # Nonvolatile information register 0. Only used by SB loader.
# mem_region_semc_nor = 0x8 # SEMC Nor memory
# mem_region_flexspi_nor = 0x9 # Flex SPI Nor memory
# mem_region_spifi_nor = 0xA # SPIFI Nor memory
# mem_region_flash_execute_only = 0x10 # Execute-only region on internal Flash
# # NON-XIP Memories in external memory address range
# mem_region_semc_nand = 0x100 + 0x0 # SEMC NAND memory
# mem_region_spi_nand = 0x100 + 0x1 # SPI NAND memory
# mem_region_spi_nor_eeprom = 0x100 + 0x10 # SPI NOR/EEPROM memory
# mem_region_i2c_nor_eeprom = 0x100 + 0x11 # I2C NOR/EEPROM memory
# mem_region_sd = 0x100 + 0x20 # eSD, SD, SDHC, SDXC memory Card
# mem_region_mmc = 0x100 + 0x21 # MMC, eMMC memory Card
# ======== Wireless Power section ========
wpc:
insert_puc_only: false
need_reset: false
need_address_adjust: false
check_lifecycle: 0
# ======== Misc signing section ========
signing:
pss_padding: false
# ======== EL2GO TP section ========
el2go_tp:
el2go_interface: mboot
el2go_name: null
prov_method: null
use_additional_data: false
fw_load_address: -1
fw_read_address: -1
user_data_address: -1
ignored_otp: [] # format: index of a fuse (not uid, just the number)
ignored_otp_ranges: [] # format: [range1_start, range1_end, range2_start, range2_end,...]
clean_method: "none"
# format: "method1=value1[,value2];method2=value3;..." or "none" (default)
# methods are in secure_object.py:ValidationMethod
validation_method: "none"
uuid_fuse_index: "6 0 4"
use_prov_report: false
# ======== LPCPROG section ========
lpcprog:
part_ids: {}
buffer_address: 0x1000_0800
buffer_size: 0x400
page_size: 0x40
sector_size: 0x400
# ======== DICE configuration ========
dice:
had_length: 48
had_members:
[
ELS_AS_CFG0,
ELS_AS_CFG1,
ELS_AS_CFG2,
ELS_AS_ST0,
ELS_AS_ST1,
ELS_AS_ST2,
ELS_AS_FLAG0,
]
critical_had_members: [ELS_AS_CFG0, ELS_AS_CFG1, ELS_AS_CFG2]
rtf_length: 32
ca_puk_length: 64
rkth_length: 32
rkth_truncated_length: 32
need_reset: false
# ======== Fastboot ========
fastboot:
address: 0x8280_0000
size: 0x2000_0000
# ======== nxpuuu ==========
nxpuuu:
boot_devices:
emmc:
script: ../../common/uuu/emmc_burn_loader.lst
arguments: [_flash.bin, _image]
emmc_all:
script: ../../common/uuu/emmc_burn_all.lst
arguments: [_flash.bin, _image]
fat_write:
script: ../../common/uuu/fat_write.lst
arguments: [_image, _device, _partition, _filename]
nand:
script: ../../common/uuu/nand_burn_loader.lst
arguments: [_flash.bin, _image]
nvme_all:
script: ../../common/uuu/nvme_burn_all.lst
arguments: [_flash.bin, _image]
qspi:
script: ../../common/uuu/qspi_burn_loader.lst
arguments: [_flash.bin, _image]
sd:
script: ../../common/uuu/sd_burn_loader.lst
arguments: [_flash.bin, _image]
sd_all:
script: ../../common/uuu/sd_burn_all.lst
arguments: [_flash.bin, _image]
spi_nand:
script: ../../common/uuu/fspinand_burn_loader.lst
arguments: [_flash.bin, _image]
spl:
script: ../../common/uuu/spl_boot.lst
arguments: [_flash.bin]
# ======== BCA section ========
bca:
reg_spec: bca.json
# ======== FCF section ========
fcf:
reg_spec: fcf.json
# ======== SHE section ========
she_scec: {}
# ===== TLV =====
tlv_blob: {}
# ======== Hardware Security Engine section ========
hse: {}

View file

@ -0,0 +1,28 @@
# Copyright 2025 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
# issuer common name; required
issuer_name: NXP DICE 2.0 - IDevID
# subject common name; required
subject_name: NXP DICE 2.0 - FMC Alias
# Include Customer TCB Table; optional (default=false)
include_cust_table: true
# Customer SVN for Customer TCB Table; required if include_cust_table = true
cust_svn: 0xabcd
# Include NXP TCB Table; optional (default=false)
include_nxp_table: true
# ECDSA/MLDSA mode; optional (default=ecdsa)
mode: ecdsa
# Template key; optional (if omitted a new temporary key will be generated each time)
template_key: idevid_ecc384.pem
# Where to store the FMC Alias certificate; optional
template_output: alias_fmc.der
# Where to store the FMC Alias certificate offset descriptor; optional
descriptor_output: descriptor.bin
# Where to store the final FMC Alias certificate container; required
container_output: container.bin

View file

@ -0,0 +1,65 @@
TCG DEFINITIONS ::= BEGIN
tcg OBJECT IDENTIFIER ::= { 2 23 133 }
tcg-dice OBJECT IDENTIFIER ::= { tcg platformClass(5) 4 }
FWID ::= SEQUENCE {
hashAlg OBJECT IDENTIFIER,
digest OCTET STRING
}
FWIDLIST ::= SEQUENCE SIZE (1..10) OF FWID
OperationalFlags ::= BIT STRING {
notConfigured (0),
notSecure (1),
recovery (2),
debug (3),
notReplayProtected (4),
notIntegrityProtected (5),
notRuntimeMeasured (6),
notImmutable (7),
notTcb (8),
fixedWidth (31)
}
OperationalFlagsMask ::= BIT STRING {
notConfigured (0),
notSecure (1),
recovery (2),
debug (3),
notReplayProtected (4),
notIntegrityProtected (5),
notRuntimeMeasured (6),
notImmutable (7),
notTcb (8),
fixedWidth (31)
}
tcg-dice-TcbInfo OBJECT IDENTIFIER ::= { tcg-dice 1 }
DiceTcbInfo ::= SEQUENCE {
vendor [0] IMPLICIT UTF8String OPTIONAL,
model [1] IMPLICIT UTF8String OPTIONAL,
version [2] IMPLICIT UTF8String OPTIONAL,
svn [3] IMPLICIT INTEGER OPTIONAL,
layer [4] IMPLICIT INTEGER OPTIONAL,
index [5] IMPLICIT INTEGER OPTIONAL,
fwids [6] IMPLICIT FWIDLIST OPTIONAL,
flags [7] IMPLICIT OperationalFlags OPTIONAL,
vendorInfo [8] IMPLICIT OCTET STRING OPTIONAL,
type [9] IMPLICIT OCTET STRING OPTIONAL,
flagsMask [10]IMPLICIT OperationalFlagsMask OPTIONAL
}
tcg-dice-MultiTcbInfo OBJECT IDENTIFIER ::= { tcg-dice 5 }
DiceTcbInfoSeq ::= SEQUENCE SIZE (1..3) OF DiceTcbInfo
tcg-dice-Ueid OBJECT IDENTIFIER ::= { tcg-dice 4 }
TcgUeid ::= SEQUENCE {
ueid OCTET STRING
}
END

View file

@ -0,0 +1,508 @@
# Copyright 2025 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
field082:
bitfields:
field082-bits-0-7:
no_yaml_comments: true
field082-bits-10-15:
no_yaml_comments: true
field082-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field084:
bitfields:
field084-bits-0-7:
no_yaml_comments: true
field084-bits-10-15:
no_yaml_comments: true
field084-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field086:
bitfields:
field086-bits-0-7:
no_yaml_comments: true
field086-bits-10-15:
no_yaml_comments: true
field086-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field088:
bitfields:
field088-bits-0-7:
no_yaml_comments: true
field088-bits-10-15:
no_yaml_comments: true
field088-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field08A:
bitfields:
field08A-bits-0-7:
no_yaml_comments: true
field08A-bits-10-15:
no_yaml_comments: true
field08A-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field08C:
bitfields:
field08C-bits-0-7:
no_yaml_comments: true
field08C-bits-10-15:
no_yaml_comments: true
field08C-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field08E:
bitfields:
field08E-bits-0-7:
no_yaml_comments: true
field08E-bits-10-15:
no_yaml_comments: true
field08E-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field092:
bitfields:
field092-bits-0-7:
no_yaml_comments: true
field092-bits-10-15:
no_yaml_comments: true
field092-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field094:
bitfields:
field094-bits-0-7:
no_yaml_comments: true
field094-bits-10-15:
no_yaml_comments: true
field094-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field096:
bitfields:
field096-bits-0-7:
no_yaml_comments: true
field096-bits-10-15:
no_yaml_comments: true
field096-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field098:
bitfields:
field098-bits-0-7:
no_yaml_comments: true
field098-bits-10-15:
no_yaml_comments: true
field098-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field09A:
bitfields:
field09A-bits-0-7:
no_yaml_comments: true
field09A-bits-10-15:
no_yaml_comments: true
field09A-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field09C:
bitfields:
field09C-bits-0-7:
no_yaml_comments: true
field09C-bits-10-15:
no_yaml_comments: true
field09C-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field09E:
bitfields:
field09E-bits-0-7:
no_yaml_comments: true
field09E-bits-10-15:
no_yaml_comments: true
field09E-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0A2:
bitfields:
field0A2-bits-0-7:
no_yaml_comments: true
field0A2-bits-10-15:
no_yaml_comments: true
field0A2-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0A4:
bitfields:
field0A4-bits-0-7:
no_yaml_comments: true
field0A4-bits-10-15:
no_yaml_comments: true
field0A4-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0A6:
bitfields:
field0A6-bits-0-7:
no_yaml_comments: true
field0A6-bits-10-15:
no_yaml_comments: true
field0A6-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0A8:
bitfields:
field0A8-bits-0-7:
no_yaml_comments: true
field0A8-bits-10-15:
no_yaml_comments: true
field0A8-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0AA:
bitfields:
field0AA-bits-0-7:
no_yaml_comments: true
field0AA-bits-10-15:
no_yaml_comments: true
field0AA-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0AC:
bitfields:
field0AC-bits-0-7:
no_yaml_comments: true
field0AC-bits-10-15:
no_yaml_comments: true
field0AC-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0AE:
bitfields:
field0AE-bits-0-7:
no_yaml_comments: true
field0AE-bits-10-15:
no_yaml_comments: true
field0AE-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0B2:
bitfields:
field0B2-bits-0-7:
no_yaml_comments: true
field0B2-bits-10-15:
no_yaml_comments: true
field0B2-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0B4:
bitfields:
field0B4-bits-0-7:
no_yaml_comments: true
field0B4-bits-10-15:
no_yaml_comments: true
field0B4-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0B6:
bitfields:
field0B6-bits-0-7:
no_yaml_comments: true
field0B6-bits-10-15:
no_yaml_comments: true
field0B6-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0B8:
bitfields:
field0B8-bits-0-7:
no_yaml_comments: true
field0B8-bits-10-15:
no_yaml_comments: true
field0B8-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0BA:
bitfields:
field0BA-bits-0-7:
no_yaml_comments: true
field0BA-bits-10-15:
no_yaml_comments: true
field0BA-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0BC:
bitfields:
field0BC-bits-0-7:
no_yaml_comments: true
field0BC-bits-10-15:
no_yaml_comments: true
field0BC-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0BE:
bitfields:
field0BE-bits-0-7:
no_yaml_comments: true
field0BE-bits-10-15:
no_yaml_comments: true
field0BE-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0C2:
bitfields:
field0C2-bits-0-7:
no_yaml_comments: true
field0C2-bits-10-15:
no_yaml_comments: true
field0C2-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0C4:
bitfields:
field0C4-bits-0-7:
no_yaml_comments: true
field0C4-bits-10-15:
no_yaml_comments: true
field0C4-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0C6:
bitfields:
field0C6-bits-0-7:
no_yaml_comments: true
field0C6-bits-10-15:
no_yaml_comments: true
field0C6-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0C8:
bitfields:
field0C8-bits-0-7:
no_yaml_comments: true
field0C8-bits-10-15:
no_yaml_comments: true
field0C8-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0CA:
bitfields:
field0CA-bits-0-7:
no_yaml_comments: true
field0CA-bits-10-15:
no_yaml_comments: true
field0CA-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0CC:
bitfields:
field0CC-bits-0-7:
no_yaml_comments: true
field0CC-bits-10-15:
no_yaml_comments: true
field0CC-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0CE:
bitfields:
field0CE-bits-0-7:
no_yaml_comments: true
field0CE-bits-10-15:
no_yaml_comments: true
field0CE-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0D2:
bitfields:
field0D2-bits-0-7:
no_yaml_comments: true
field0D2-bits-10-15:
no_yaml_comments: true
field0D2-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0D4:
bitfields:
field0D4-bits-0-7:
no_yaml_comments: true
field0D4-bits-10-15:
no_yaml_comments: true
field0D4-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0D6:
bitfields:
field0D6-bits-0-7:
no_yaml_comments: true
field0D6-bits-10-15:
no_yaml_comments: true
field0D6-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0D8:
bitfields:
field0D8-bits-0-7:
no_yaml_comments: true
field0D8-bits-10-15:
no_yaml_comments: true
field0D8-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0DA:
bitfields:
field0DA-bits-0-7:
no_yaml_comments: true
field0DA-bits-10-15:
no_yaml_comments: true
field0DA-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0DC:
bitfields:
field0DC-bits-0-7:
no_yaml_comments: true
field0DC-bits-10-15:
no_yaml_comments: true
field0DC-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0DE:
bitfields:
field0DE-bits-0-7:
no_yaml_comments: true
field0DE-bits-10-15:
no_yaml_comments: true
field0DE-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0E2:
bitfields:
field0E2-bits-0-7:
no_yaml_comments: true
field0E2-bits-10-15:
no_yaml_comments: true
field0E2-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0E4:
bitfields:
field0E4-bits-0-7:
no_yaml_comments: true
field0E4-bits-10-15:
no_yaml_comments: true
field0E4-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0E6:
bitfields:
field0E6-bits-0-7:
no_yaml_comments: true
field0E6-bits-10-15:
no_yaml_comments: true
field0E6-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0E8:
bitfields:
field0E8-bits-0-7:
no_yaml_comments: true
field0E8-bits-10-15:
no_yaml_comments: true
field0E8-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0EA:
bitfields:
field0EA-bits-0-7:
no_yaml_comments: true
field0EA-bits-10-15:
no_yaml_comments: true
field0EA-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0EC:
bitfields:
field0EC-bits-0-7:
no_yaml_comments: true
field0EC-bits-10-15:
no_yaml_comments: true
field0EC-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0EE:
bitfields:
field0EE-bits-0-7:
no_yaml_comments: true
field0EE-bits-10-15:
no_yaml_comments: true
field0EE-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0F2:
bitfields:
field0F2-bits-0-7:
no_yaml_comments: true
field0F2-bits-10-15:
no_yaml_comments: true
field0F2-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0F4:
bitfields:
field0F4-bits-0-7:
no_yaml_comments: true
field0F4-bits-10-15:
no_yaml_comments: true
field0F4-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0F6:
bitfields:
field0F6-bits-0-7:
no_yaml_comments: true
field0F6-bits-10-15:
no_yaml_comments: true
field0F6-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0F8:
bitfields:
field0F8-bits-0-7:
no_yaml_comments: true
field0F8-bits-10-15:
no_yaml_comments: true
field0F8-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0FA:
bitfields:
field0FA-bits-0-7:
no_yaml_comments: true
field0FA-bits-10-15:
no_yaml_comments: true
field0FA-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0FC:
bitfields:
field0FC-bits-0-7:
no_yaml_comments: true
field0FC-bits-10-15:
no_yaml_comments: true
field0FC-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true
field0FE:
bitfields:
field0FE-bits-0-7:
no_yaml_comments: true
field0FE-bits-10-15:
no_yaml_comments: true
field0FE-bits-8-9:
no_yaml_comments: true
no_yaml_comments: true

View file

@ -0,0 +1,380 @@
# Copyright 2023-2025 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
# ======== Flash memories configuration ========
# ***********************************************************************
# NOR
# ***********************************************************************
# Winbond
W25QxxxJV:
manufacturer: Winbond
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
tested: True
W35T51NW:
manufacturer: Winbond
type: nor
interfaces:
octal_spi:
option_words: [0xc0603005]
# Macronix
MX25Uxxx32F:
manufacturer: Macronix
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
tested: True
MX25Lxxx45G:
manufacturer: Macronix
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
tested: True
MX25UMxxx45G:
manufacturer: Macronix
type: nor
interfaces:
octal_spi:
option_words: [0xc0403007]
MX66UMxxx45G:
manufacturer: Macronix
type: nor
interfaces:
octal_spi:
option_words: [0xc0403007]
MX25LMxxx45G:
manufacturer: Macronix
type: nor
interfaces:
octal_spi:
option_words: [0xc0403007]
MX25UM51345G:
manufacturer: Macronix
type: nor
interfaces:
octal_spi:
option_words: [0xc0403007]
# GigaDevice
GD25QxxxC:
manufacturer: GigaDevice
type: nor
interfaces:
quad_spi:
option_words: [0xc0000406]
GD25LBxxxE:
manufacturer: GigaDevice
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
GD25LTxxxE:
manufacturer: GigaDevice
type: nor
interfaces:
quad_spi:
option_words: [0xc0000008]
GD25LXxxxE:
manufacturer: GigaDevice
type: nor
interfaces:
quad_spi:
option_words: [0xc0603008]
# ISSI
IS25LPxxxA:
manufacturer: ISSI
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
IS25WPxxxA:
manufacturer: ISSI
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
IS25LXxxx:
manufacturer: ISSI
type: nor
interfaces:
octal_spi:
option_words: [0xC0603005]
IS25WXxxx:
manufacturer: ISSI
type: nor
interfaces:
octal_spi:
option_words: [0xC0603005]
IS26KSxxxS:
manufacturer: ISSI
type: nor
interfaces:
hyper_flash:
option_words: [0xc0233007]
IS26KLxxxS:
manufacturer: ISSI
type: nor
interfaces:
hyper_flash:
option_words: [0xc0233007]
# Micron
MT25QLxxxA:
manufacturer: Micron
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
MT35XUxxxABA1G:
manufacturer: Micron
type: nor
interfaces:
octal_spi:
option_words: [0xC0703005]
MT35XUxxxABA2G:
manufacturer: Micron
type: nor
interfaces:
octal_spi:
option_words: [0xC0633005]
tested: True
MT28EW128ABA:
manufacturer: Micron
type: nor
interfaces:
parallel:
option_words: [0xD0000600]
MT28UG128ABA:
manufacturer: Micron
type: nor
interfaces:
parallel:
option_words: [0xD0000601]
# Adesto
AT25SFxxxA:
manufacturer: Adesto
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
ATXPxxx:
manufacturer: Adesto
type: nor
interfaces:
octal_spi:
option_words: [0xc0803007]
# Cypress
S25FSxxxS:
manufacturer: Cypress
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
S25FLxxxS:
manufacturer: Cypress
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
S26KSxxxS:
manufacturer: Cypress
type: nor
interfaces:
hyper_flash:
option_words: [0xc0233007]
S26KLxxxS:
manufacturer: Cypress
type: nor
interfaces:
hyper_flash:
option_words: [0xc0233007]
# Microchip
SST26VFxxxB:
manufacturer: Microchip
type: nor
interfaces:
quad_spi:
option_words: [0xc0000005]
# FudanMicro
FM25Qxxx:
manufacturer: FudanMicro
type: nor
interfaces:
quad_spi:
option_words: [0xc0000205]
# BoyaMicro
BY25QxxxBS:
manufacturer: BoyaMicro
type: nor
interfaces:
quad_spi:
option_words: [0xc0000405]
# XMC
XM25QHxxxB:
manufacturer: XMC
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
XM25QUxxxB:
manufacturer: XMC
type: nor
interfaces:
quad_spi:
option_words: [0xc0000007]
# XTXtech
X25FxxxB:
manufacturer: XTXtech
type: nor
interfaces:
quad_spi:
option_words: [0xc0000407]
X25QxxxD:
manufacturer: XTXtech
type: nor
interfaces:
quad_spi:
option_words: [0xc0000407]
# Puya
P25QxxxLE:
manufacturer: Puya
type: nor
interfaces:
quad_spi:
option_words: [0xc0000405]
P25QxxxH:
manufacturer: Puya
type: nor
interfaces:
quad_spi:
option_words: [0xc0000405]
P25QxxxU:
manufacturer: Puya
type: nor
interfaces:
quad_spi:
option_words: [0xc0000405]
# AMIC
A25LQxxx:
manufacturer: AMIC
type: nor
interfaces:
quad_spi:
option_words: [0xc0000105]
# ***********************************************************************
# NAND
# ***********************************************************************
# Winbond
W25N01G:
manufacturer: Winbond
type: nand
interfaces:
quad_spi:
option_words: [0xC1010026, 0x000000ef]
W25N02K:
manufacturer: Winbond
type: nand
interfaces:
quad_spi:
option_words: [0xC1020026, 0x000000ef]
# Macronix
MX35UF1G:
manufacturer: Macronix
type: nand
interfaces:
quad_spi:
option_words: [0xC1010026, 0x000000c2]
MX35LF1G:
manufacturer: Macronix
type: nand
interfaces:
quad_spi:
option_words: [0xC1010026, 0x000000c2]
MX35UF2G:
manufacturer: Macronix
type: nand
interfaces:
quad_spi:
option_words: [0xC1020026, 0x000000c2]
MX35LF2G:
manufacturer: Macronix
type: nand
interfaces:
quad_spi:
option_words: [0xC1020026, 0x000000c2]
# GigaDevice
GD5F1GQ5:
manufacturer: GigaDevice
type: nand
interfaces:
quad_spi:
option_words: [0xC1010026, 0x000000c8]
GD5F2GQ5:
manufacturer: GigaDevice
type: nand
interfaces:
quad_spi:
option_words: [0xC1020026, 0x000000c8]
# Micron
MT29F1G01AA:
manufacturer: Micron
type: nand
interfaces:
quad_spi:
option_words: [0xC1011022, 0x0000002c]
MT29F2G01AA:
manufacturer: Micron
type: nand
interfaces:
quad_spi:
option_words: [0xC1021022, 0x0000002c]
# Paragon
PN26Q01A:
manufacturer: Paragon
type: nand
interfaces:
quad_spi:
option_words: [0xC1010026, 0x000000a1]
PN26G01A:
manufacturer: Paragon
type: nand
interfaces:
quad_spi:
option_words: [0xC1010026, 0x000000a1]
PN26Q02A:
manufacturer: Paragon
type: nand
interfaces:
quad_spi:
option_words: [0xC1020026, 0x000000a1]
PN26G02A:
manufacturer: Paragon
type: nand
interfaces:
quad_spi:
option_words: [0xC1020026, 0x000000a1]
# ***********************************************************************
# SD
# ***********************************************************************
# General
1bit_sdr12:
manufacturer: General
type: sd
interfaces:
instance_0:
option_words: [0xD0000000]
instance_1:
option_words: [0xD0000001]
instance_2:
option_words: [0xD0000002]
instance_3:
option_words: [0xD0000003]

View file

@ -0,0 +1,395 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "eMMC card Configuration Option 0",
"default_value_int": "0xc0000000",
"bitfields": [
{
"id": "field000-bit0",
"width": 1,
"name": "BootConfigEnable",
"access": "RW",
"description": "Boot configuration",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "Boot configuration disabled"
},
{
"name": "Enabled",
"value": 1,
"description": "Boot configuration enabled"
}
]
},
{
"width": 1
},
{
"id": "field000-bit2",
"width": 1,
"name": "BootAcknowledge",
"access": "RW",
"description": "Boot acknowledge",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "Boot acknowledge disabled"
},
{
"name": "Enabled",
"value": 1,
"description": "Boot acknowledge enabled"
}
]
},
{
"id": "field000-bit3",
"width": 1,
"name": "ResetBootBusConditions",
"access": "RW",
"description": "Reset boot BUS conditions",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "Don't change BUS conditions"
},
{
"name": "Enabled",
"value": 1,
"description": "Reset boot BUS conditions"
}
]
},
{
"id": "field000-bits4-5",
"width": 2,
"name": "BootMode",
"access": "RW",
"description": "Boot mode configuration",
"values": [
{
"name": "SDRWithDefaultTiming",
"value": 0,
"description": "Single data rate with backward compatible timings"
},
{
"name": "SDRWithHighSpeedTiming",
"value": 1,
"description": "Single data rate with high speed timing"
},
{
"name": "DDRTiming",
"value": 2,
"description": "Dual date rate"
}
]
},
{
"width": 2
},
{
"id": "field000-bits8-11",
"width": 4,
"name": "BusWidth",
"access": "RW",
"description": "eMMC card data bus width(BUS_WIDTH in Extended CSD)",
"values": [
{
"name": "1bit",
"value": 0,
"description": "eMMC data bus width is 1 bit"
},
{
"name": "4bit",
"value": 1,
"description": "eMMC data bus width is 4 bits"
},
{
"name": "8bit",
"value": 2,
"description": "eMMC data bus width is 8 bits"
},
{
"name": "4bitDDR",
"value": 5,
"description": "eMMC data bus width is 4 bits ddr"
},
{
"name": "8bitDDR",
"value": 6,
"description": "eMMC data bus width is 8 bits ddr"
}
]
},
{
"id": "field000-bits12-15",
"width": 4,
"name": "TimingMode",
"access": "RW",
"description": "Select the bus timing when accesses eMMC memory",
"values": [
{
"name": "HighSpeedTimingNormal",
"value": 0,
"description": "eMMC card using none high-speed timing"
},
{
"name": "HighSpeedTiming",
"value": 1,
"description": "eMMC card using high-speed timing"
},
{
"name": "HighSpeed200Timing",
"value": 2,
"description": "eMMC card high speed 200 timing"
},
{
"name": "HighSpeed400Timing",
"value": 3,
"description": "eMMC card high speed 400 timing"
}
]
},
{
"id": "field000-bits16-17",
"width": 2,
"name": "BootBusWidth",
"access": "RW",
"description": "eMMC card boot bus width(BOOT_BUS_WIDTH in Extended CSD)",
"values": [
{
"name": "1bitSDR4bitDDR",
"value": 0,
"description": "x1 (sdr) or x4 (ddr) bus width in boot operation mode(default)"
},
{
"name": "4bitSDR4bitDDR",
"value": 1,
"description": "x4 (sdr/ddr) bus width in boot operation mode"
},
{
"name": "8bitSDR8bitDDR",
"value": 2,
"description": "x8 (sdr/ddr) bus width in boot operation mode"
}
]
},
{
"width": 2
},
{
"id": "field000-bits20-22",
"width": 3,
"name": "BootPartitionEnabled",
"access": "RW",
"description": "eMMC card boot partition enabled(BOOT_PARTITION_ENABLE in Extended CSD)",
"values": [
{
"name": "Not",
"value": 0,
"description": "Device not boot enabled (default)"
},
{
"name": "Partition1",
"value": 1,
"description": "Boot partition 1 enabled for boot"
},
{
"name": "Partition2",
"value": 2,
"description": "Boot partition 2 enabled for boot"
},
{
"name": "UserAera",
"value": 7,
"description": "User area enabled for boot"
}
]
},
{
"width": 1
},
{
"id": "field000-bits24-26",
"width": 3,
"name": "PartitionAccess",
"access": "RW",
"description": "eMMC card partition to be accessed(BOOT_PARTITION_ACCESS in Extended CSD)",
"values": [
{
"name": "PartitionUserAera",
"value": 0,
"description": "No access to boot partition (default), normal partition"
},
{
"name": "PartitionBoot1",
"value": 1,
"description": "Read/Write boot partition 1"
},
{
"name": "PartitionBoot2",
"value": 2,
"description": "Read/Write boot partition 2"
},
{
"name": "RPMB",
"value": 3,
"description": "Replay protected mem block"
},
{
"name": "GeneralPurposePartition1",
"value": 4,
"description": "access to general purpose partition 1"
},
{
"name": "GeneralPurposePartition2",
"value": 5,
"description": "access to general purpose partition 2"
},
{
"name": "GeneralPurposePartition3",
"value": 6,
"description": "access to general purpose partition 3"
},
{
"name": "GeneralPurposePartition4",
"value": 7,
"description": "access to general purpose partition 4"
}
]
},
{
"width": 1
},
{
"width": 4
}
]
},
{
"id": "field004",
"offset_int": "0x4",
"reg_width": 32,
"name": "ConfigOption1",
"description": "eMMC card Configuration Option 1 - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"width": 19
},
{
"id": "field004-bit19",
"width": 1,
"name": "EnablePowerCycle",
"access": "RW",
"description": "Execute power cycle before initialization",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "Power cycle disabled"
},
{
"name": "Enabled",
"value": 1,
"description": "Execute power cycle before initialization"
}
]
},
{
"id": "field004-bit20",
"width": 1,
"name": "PowerUpDelay",
"access": "RW",
"description": "Set power up delay",
"values": [
{
"name": "5ms",
"value": 0,
"description": "Power up delay 5ms"
},
{
"name": "2.5ms",
"value": 1,
"description": "Power up delay 2.5ms"
}
]
},
{
"width": 2
},
{
"id": "field004-bit23",
"width": 1,
"name": "PowerUpPolarity",
"access": "RW",
"description": "eMMC power control polarity. Only valid when PWR_CYCLE_ENABLE is enabled",
"values": [
{
"name": "Low",
"value": 0,
"description": "Power down when uSDHC.RST set low"
},
{
"name": "High",
"value": 1,
"description": "Power down when uSDHC.RST set high"
}
]
},
{
"id": "field004-bits24-25",
"width": 2,
"name": "PowerDownTime",
"access": "RW",
"description": "Set power down time",
"values": [
{
"name": "20ms",
"value": 0,
"description": "Power up delay 20ms"
},
{
"name": "10ms",
"value": 1,
"description": "Power up delay 10ms"
},
{
"name": "5ms",
"value": 2,
"description": "Power up delay 5ms"
},
{
"name": "2.5ms",
"value": 3,
"description": "Power up delay 2.5ms"
}
]
},
{
"width": 2
},
{
"width": 4
}
]
}
]
}
]
}

View file

@ -0,0 +1,276 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "FlexSPI NAND Configuration Option 0",
"default_value_int": "0xc0000020",
"bitfields": [
{
"id": "field000-bits0-3",
"width": 4,
"name": "MaxFreq",
"access": "RW",
"description": "The maximum work frequency for specified Flash device",
"values": [
{
"name": "NoChange",
"value": 0,
"description": "Don't change FlexSPI clock setting"
},
{
"name": "30Mhz",
"value": 1,
"description": "30MHz"
},
{
"name": "50Mhz",
"value": 2,
"description": "50MHz"
},
{
"name": "60Mhz",
"value": 3,
"description": "60MHz"
},
{
"name": "80Mhz",
"value": 4,
"description": "80MHz"
},
{
"name": "100Mhz",
"value": 5,
"description": "100MHz"
},
{
"name": "120Mhz",
"value": 6,
"description": "120MHz"
},
{
"name": "133Mhz",
"value": 7,
"description": "133MHz"
},
{
"name": "166Mhz",
"value": 8,
"description": "166MHz"
}
]
},
{
"id": "field000-bits4-7",
"width": 4,
"name": "PageSize",
"access": "RW",
"description": "Specify page size in KB.",
"values": [
{
"name": "2KB",
"value": 2,
"description": "NAND is using 2KB pages"
},
{
"name": "4KB",
"value": 4,
"description": "NAND is using 4KB pages"
}
]
},
{
"id": "field000-bits8-11",
"width": 4,
"name": "PagesPerBlock",
"access": "RW",
"description": "Specify the count of pages per one block",
"values": [
{
"name": "64",
"value": 0,
"description": "64 pages per one block"
},
{
"name": "128",
"value": 1,
"description": "128 pages per one block"
},
{
"name": "256",
"value": 2,
"description": "256 pages per one block"
},
{
"name": "32",
"value": 3,
"description": "32 pages per one block"
}
]
},
{
"id": "field000-bits12-15",
"width": 4,
"name": "HasMultiPlanes",
"access": "RW",
"description": "Has or no multiplanes",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "NAND memory has not multiplanes"
},
{
"name": "Enabled",
"value": 1,
"description": "NAND memory has multiplanes"
}
]
},
{
"id": "field000-bits16-19",
"width": 4,
"name": "FlashSize",
"access": "RW",
"description": "Overall flash size",
"values": [
{
"name": "512Mbit",
"value": 0,
"description": "Memory size is 512Mbit"
},
{
"name": "1Gbit",
"value": 1,
"description": "Memory size is 1Gbit"
},
{
"name": "2Gbit",
"value": 2,
"description": "Memory size is 2Gbit"
},
{
"name": "4Gbit",
"value": 4,
"description": "Memory size is 4Gbit"
},
{
"name": "8Gbit",
"value": 8,
"description": "Memory size is 8Gbit"
}
]
},
{
"id": "field000-bits20-23",
"width": 4,
"name": "DeviceType",
"access": "RW",
"description": "Device type of NAND.",
"values": [
{
"name": "QuadSpi",
"value": 0,
"description": "QuadSPI NAND"
},
{
"name": "Octal",
"value": 1,
"description": "OctalSPI NAND"
}
]
},
{
"id": "field000-bits24-27",
"width": 4,
"name": "OptionSize",
"access": "RW",
"description": "Option Size",
"values": [
{
"name": "OptionSize1",
"value": 0,
"description": "Option words = 1"
},
{
"name": "OptionSize2",
"value": 1,
"description": "Option words = 2"
}
]
},
{
"width": 4
}
]
},
{
"id": "field004",
"offset_int": "0x4",
"reg_width": 32,
"name": "ConfigOption1",
"description": "FlexSPI NAND flash Configuration Option 1 - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field004-bits0-7",
"width": 8,
"name": "ManufacturerId",
"access": "RW",
"description": "Manufacture ID"
},
{
"id": "field004-bits8-15",
"width": 8,
"name": "EccFailureMask",
"access": "RW",
"description": "ECC Failure mask"
},
{
"id": "field004-bits16-23",
"width": 8,
"name": "EccCheckMask",
"access": "RW",
"description": "ECC Check Mask"
},
{
"id": "field004-bits24-27",
"width": 4,
"name": "PinMuxGroup",
"access": "RW",
"description": "Select the FlexSPI Pin MUx group"
},
{
"id": "field004-bits28-31",
"width": 4,
"name": "FlashConnection",
"access": "RW",
"description": "Select the FlexSPI Port A/B",
"values": [
{
"name": "SingleFlashPort_A",
"value": 0,
"description": "Single Flash connected to port A"
},
{
"name": "SingleFlashPort_B",
"value": 2,
"description": "Single Flash connected to port B"
}
]
}
]
}
]
}
]
}

View file

@ -0,0 +1,338 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "FlexSPI NOR Configuration Option 0",
"default_value_int": "0xc0000000",
"bitfields": [
{
"id": "field000-bits0-3",
"width": 4,
"name": "MaxFreq",
"access": "RW",
"description": "The maximum work frequency for specified Flash device",
"values": [
{
"name": "NoChange",
"value": 0,
"description": "Don't change FlexSPI clock setting"
},
{
"name": "30Mhz",
"value": 1,
"description": "30MHz"
},
{
"name": "50Mhz",
"value": 2,
"description": "50MHz"
},
{
"name": "60Mhz",
"value": 3,
"description": "60MHz"
},
{
"name": "75Mhz",
"value": 4,
"description": "75MHz"
},
{
"name": "80Mhz",
"value": 5,
"description": "80MHz"
},
{
"name": "100Mhz",
"value": 6,
"description": "100MHz"
},
{
"name": "133Mhz",
"value": 7,
"description": "133MHz"
},
{
"name": "166Mhz",
"value": 8,
"description": "166MHz"
}
]
},
{
"id": "field000-bits4-7",
"width": 4,
"name": "Misc",
"access": "RW",
"description": "Specify miscellaneous mode for selected flash type; Experimental feature, do not use in products, keep it as 0.",
"values": [
{
"name": "NotEnabled",
"value": 0,
"description": "Miscellaneous mode is not enabled"
},
{
"name": "Mode0-4-4",
"value": 1,
"description": "Enable 0-4-4 mode for High Random Read performance"
},
{
"name": "SwappedMode",
"value": 3,
"description": " Data Order Swapped mode (for MXIC OctaFlash only)"
},
{
"name": "InternalLoopBack",
"value": 5,
"description": " Select the FlexSPI data sample source as internal loop back, more details please refer FlexSPI usage"
},
{
"name": "StandSpiMode",
"value": 6,
"description": " Config the FlexSPI NOR flash running at stand SPI mode"
}
]
},
{
"id": "field000-bits8-11",
"width": 4,
"name": "QuadEnableType",
"access": "RW",
"description": "Specify the Quad Enable sequence, only applicable for device that only JESD216 compliant, this field is ignored if device support JESD216A or later version. This field will be effective only if device is compliant with JESD216 only (9 longword SDFP table)",
"values": [
{
"name": "NotConfigure",
"value": 0,
"description": "Not Configured"
},
{
"name": "Bit6InSR1",
"value": 1,
"description": "QE bit is bit6 in StatusReg1"
},
{
"name": "Bit1InSR2",
"value": 2,
"description": "QE bit is bit1 in StatusReg2"
},
{
"name": "Bit7InSR2",
"value": 3,
"description": "QE bit is bit7 in StatusReg2"
},
{
"name": "Bit1InSR2EnableCmdIs0x31",
"value": 4,
"description": "QE bit is bit1 in StatusReg2, enable command is 0x31"
}
]
},
{
"id": "field000-bits12-15",
"width": 4,
"name": "CMDPad(s)",
"access": "RW",
"description": "Commands pads for the Flash device (1/4/8), for device that works under 1-1-4,1-4-4,1-1-8 or 1-8-8 mode, CMD pad(s) value is always 0x0, for devices that only support 4-4-4 mode for high performance, CMD pads value is 2, for devices that only support 8-8-8 mode for high performance, CMD pads value is 3",
"values": [
{
"name": "1",
"value": 0,
"description": "1 bit"
},
{
"name": "4",
"value": 2,
"description": "4 bits"
},
{
"name": "8",
"value": 3,
"description": "8 bits"
}
]
},
{
"id": "field000-bits16-19",
"width": 4,
"name": "Query CMDPad(s)",
"access": "RW",
"description": "Command pads (1/4/8) for the SFDP command",
"values": [
{
"name": "1",
"value": 0,
"description": "1 bit"
},
{
"name": "4",
"value": 2,
"description": "4 bits"
},
{
"name": "8",
"value": 3,
"description": "8 bits"
}
]
},
{
"id": "field000-bits20-23",
"width": 4,
"name": "Device Detection Type",
"access": "RW",
"description": "SW defined device types used for config block autodetection",
"values": [
{
"name": "QuadSPI_SDR",
"value": 0,
"description": "QuadSPI SDR"
},
{
"name": "QuadSPI_DDR",
"value": 1,
"description": "QuadSPI DDR"
},
{
"name": "HyperFLASH_1V8",
"value": 2,
"description": "HyperFLASH 1V8"
},
{
"name": "HyperFLASH_3V",
"value": 3,
"description": "HyperFLASH 3V"
},
{
"name": "MXICOPI_DDR",
"value": 4,
"description": "MXICOPI DDR"
},
{
"name": "MicronOPI_DDR",
"value": 6,
"description": "MicronOPI DDR"
},
{
"name": "MicronOPI_SDR",
"value": 7,
"description": "MicronOPI SDR"
},
{
"name": "AdestoOPI_DDR",
"value": 8,
"description": "AdestoOPI DDR"
},
{
"name": "AdestoOPI_SDR",
"value": 9,
"description": "AdestoOPI SDR"
}
]
},
{
"id": "field000-bits24-27",
"width": 4,
"name": "OptionSize",
"access": "RW",
"description": "Option Size",
"values": [
{
"name": "OptionSize1",
"value": 0,
"description": "Option words = 1"
},
{
"name": "OptionSize2",
"value": 1,
"description": "Option words = 2"
}
]
},
{
"width": 4
}
]
},
{
"id": "field004",
"offset_int": "0x4",
"reg_width": 32,
"name": "ConfigOption1",
"description": "FlexSPI NOR Flash Configuration Option 1 - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field004-bits0-7",
"width": 8,
"name": "DummyCycles",
"access": "RW",
"description": "User provided dummy cycles for SDR/DDR read command: 0 - Auto detection, Others - Specified dummy cycles"
},
{
"id": "field004-bits8-15",
"width": 8,
"name": "StatusOverride",
"access": "RW",
"description": "Override status register value during device mode configuration"
},
{
"id": "field004-bits16-19",
"width": 4,
"name": "PinMuxGroup",
"access": "RW",
"description": "Pin multiplexer group selection"
},
{
"id": "field004-bits20-23",
"width": 4,
"name": "DqsPinMuxGroup",
"access": "RW",
"description": "DQS Pin multiplexer group selection"
},
{
"id": "field004-bits24-27",
"width": 4,
"name": "PinDriveStrength",
"access": "RW",
"description": "The Drive Strength of FlexSPI Pads"
},
{
"id": "field004-bits28-31",
"width": 4,
"name": "FlashConnection",
"access": "RW",
"description": "Select the FlexSPI Port A/B",
"values": [
{
"name": "SingleFlashPort_A",
"value": 0,
"description": "Single Flash connected to port A"
},
{
"name": "ParallelMode",
"value": 1,
"description": "Parallel mode"
},
{
"name": "SingleFlashPort_B",
"value": 2,
"description": "Single Flash connected to port B"
}
]
}
]
}
]
}
]
}

View file

@ -0,0 +1,273 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "FlexSPI NOR Configuration Option 0",
"default_value_int": "0xc0000000",
"bitfields": [
{
"id": "field000-bits0-3",
"width": 4,
"name": "MaxFreq",
"access": "RW",
"description": "The maximum work frequency for specified Flash device; 0 - Don't change FlexSPI clock setting"
},
{
"id": "field000-bits4-7",
"width": 4,
"name": "Misc",
"access": "RW",
"description": "Specify miscellaneous mode for selected flash type; Experimental feature, do not use in products, keep it as 0.",
"values": [
{
"name": "NotEnabled",
"value": 0,
"description": "Miscellaneous mode is not enabled"
},
{
"name": "Mode0-4-4",
"value": 1,
"description": "Enable 0-4-4 mode for High Random Read performance"
},
{
"name": "SwappedMode",
"value": 3,
"description": " Data Order Swapped mode (for MXIC OctaFlash only)"
},
{
"name": "InternalLoopBack",
"value": 5,
"description": " Select the FlexSPI data sample source as internal loop back, more details please refer FlexSPI usage"
},
{
"name": "StandSpiMode",
"value": 6,
"description": " Config the FlexSPI NOR flash running at stand SPI mode"
}
]
},
{
"id": "field000-bits8-11",
"width": 4,
"name": "QuadEnableType",
"access": "RW",
"description": "Specify the Quad Enable sequence, only applicable for device that only JESD216 compliant, this field is ignored if device support JESD216A or later version. This field will be effective only if device is compliant with JESD216 only (9 longword SDFP table)",
"values": [
{
"name": "NotConfigure",
"value": 0,
"description": "Not Configured"
},
{
"name": "Bit6InSR1",
"value": 1,
"description": "QE bit is bit6 in StatusReg1"
},
{
"name": "Bit1InSR2",
"value": 2,
"description": "QE bit is bit1 in StatusReg2"
},
{
"name": "Bit7InSR2",
"value": 3,
"description": "QE bit is bit7 in StatusReg2"
},
{
"name": "Bit1InSR2EnableCmdIs0x31",
"value": 4,
"description": "QE bit is bit1 in StatusReg2, enable command is 0x31"
}
]
},
{
"id": "field000-bits12-15",
"width": 4,
"name": "CMDPad(s)",
"access": "RW",
"description": "Commands pads for the Flash device (1/4/8), for device that works under 1-1-4,1-4-4,1-1-8 or 1-8-8 mode, CMD pad(s) value is always 0x0, for devices that only support 4-4-4 mode for high performance, CMD pads value is 2, for devices that only support 8-8-8 mode for high performance, CMD pads value is 3",
"values": [
{
"name": "1",
"value": 0,
"description": "1 bit"
},
{
"name": "4",
"value": 2,
"description": "4 bits"
},
{
"name": "8",
"value": 3,
"description": "8 bits"
}
]
},
{
"id": "field000-bits16-19",
"width": 4,
"name": "QueryCMDPad(s)",
"access": "RW",
"description": "Command pads (1/4/8) for the SFDP command",
"values": [
{
"name": "1",
"value": 0,
"description": "1 bit"
},
{
"name": "4",
"value": 2,
"description": "4 bits"
},
{
"name": "8",
"value": 3,
"description": "8 bits"
}
]
},
{
"id": "field000-bits20-23",
"width": 4,
"name": "DeviceDetectionType",
"access": "RW",
"description": "SW defined device types used for config block autodetection",
"values": [
{
"name": "QuadSPI_SDR",
"value": 0,
"description": "QuadSPI SDR"
},
{
"name": "QuadSPI_DDR",
"value": 1,
"description": "QuadSPI DDR"
},
{
"name": "HyperFLASH_1V8",
"value": 2,
"description": "HyperFLASH 1V8"
},
{
"name": "HyperFLASH_3V",
"value": 3,
"description": "HyperFLASH 3V"
},
{
"name": "MXICOPI_DDR",
"value": 4,
"description": "MXICOPI DDR"
},
{
"name": "MicronOPI_DDR",
"value": 6,
"description": "MicronOPI DDR"
},
{
"name": "MicronOPI_SDR",
"value": 7,
"description": "MicronOPI SDR"
},
{
"name": "AdestoOPI_DDR",
"value": 8,
"description": "AdestoOPI DDR"
},
{
"name": "AdestoOPI_SDR",
"value": 9,
"description": "AdestoOPI SDR"
}
]
},
{
"id": "field000-bits24-27",
"width": 4,
"name": "OptionSize",
"access": "RW",
"description": "Option Size",
"values": [
{
"name": "OptionSize1",
"value": 0,
"description": "Option words = 1"
},
{
"name": "OptionSize2",
"value": 1,
"description": "Option words = 2"
}
]
},
{
"width": 4
}
]
},
{
"id": "field004",
"offset_int": "0x4",
"reg_width": 32,
"name": "ConfigOption1",
"description": "FlexSPI NOR Flash Configuration Option 1 - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field004-bits0-7",
"width": 8,
"name": "DummyCycles",
"access": "RW",
"description": "User provided dummy cycles for SDR/DDR read command: 0 - Auto detection, Others - Specified dummy cycles"
},
{
"id": "field004-bits8-15",
"width": 8,
"name": "StatusOverride",
"access": "RW",
"description": "Override status register value during device mode configuration"
},
{
"width": 8
},
{
"id": "field004-bits24-31",
"width": 8,
"name": "FlashConnection",
"access": "RW",
"description": "Select the FlexSPI Port A/B",
"values": [
{
"name": "SingleFlashPort_A",
"value": 0,
"description": "Single Flash connected to port A"
},
{
"name": "ParallelMode",
"value": 1,
"description": "Parallel mode"
},
{
"name": "SingleFlashPort_B",
"value": 2,
"description": "Single Flash connected to port B"
}
]
}
]
}
]
}
]
}

View file

@ -0,0 +1,430 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "MMC card Configuration Option 0",
"default_value_int": "0xc0000000",
"bitfields": [
{
"id": "field000-bit0",
"width": 1,
"name": "BootConfigEnable",
"access": "RW",
"description": "Boot configuration",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "Boot configuration disabled"
},
{
"name": "Enabled",
"value": 1,
"description": "Boot configuration enabled"
}
]
},
{
"width": 1
},
{
"id": "field000-bit2",
"width": 1,
"name": "BootAcknowledge",
"access": "RW",
"description": "Boot acknowledge",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "Boot acknowledge disabled"
},
{
"name": "Enabled",
"value": 1,
"description": "Boot acknowledge enabled"
}
]
},
{
"id": "field000-bit3",
"width": 1,
"name": "ResetBootBusConditions",
"access": "RW",
"description": "Reset boot BUS conditions",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "Don't change BUS conditions"
},
{
"name": "Enabled",
"value": 1,
"description": "Reset boot BUS conditions"
}
]
},
{
"id": "field000-bits4-5",
"width": 2,
"name": "BootMode",
"access": "RW",
"description": "Boot mode configuration",
"values": [
{
"name": "SDRWithDefaultTiming",
"value": 0,
"description": "Single data rate with backward compatible timings"
},
{
"name": "SDRWithHighSpeedTiming",
"value": 1,
"description": "Single data rate with high speed timing"
},
{
"name": "DDRTiming",
"value": 2,
"description": "Dual date rate"
}
]
},
{
"width": 2
},
{
"id": "field000-bits8-11",
"width": 4,
"name": "BusWidth",
"access": "RW",
"description": "MMC card data bus width(BUS_WIDTH in Extended CSD)",
"values": [
{
"name": "1bit",
"value": 0,
"description": "MMC data bus width is 1 bit"
},
{
"name": "4bit",
"value": 1,
"description": "MMC data bus width is 4 bits"
},
{
"name": "8bit",
"value": 2,
"description": "MMC data bus width is 8 bits"
},
{
"name": "4bitDDR",
"value": 5,
"description": "MMC data bus width is 4 bits ddr"
},
{
"name": "8bitDDR",
"value": 6,
"description": "MMC data bus width is 8 bits ddr"
}
]
},
{
"id": "field000-bits12-15",
"width": 4,
"name": "TimingMode",
"access": "RW",
"description": "MMC card high-speed timing(HS_TIMING in Extended CSD)",
"values": [
{
"name": "HighSpeedTimingNone",
"value": 0,
"description": "MMC card using none high-speed timing"
},
{
"name": "HighSpeedTiming",
"value": 1,
"description": "MMC card using high-speed timing"
},
{
"name": "HighSpeed200Timing",
"value": 2,
"description": "MMC card high speed 200 timing"
},
{
"name": "HighSpeed400Timing",
"value": 3,
"description": "MMC card high speed 400 timing"
},
{
"name": "HighSpeed26MHZTiming",
"value": 4,
"description": "MMC high speed 26MHZ timing"
},
{
"name": "HighSpeed52MHZTiming",
"value": 5,
"description": "MMC high speed 52MHZ timing"
},
{
"name": "HighSpeedDDR52Timing",
"value": 6,
"description": "MMC high speed timing DDR52 1.8V"
}
]
},
{
"id": "field000-bits16-17",
"width": 2,
"name": "BootBusWidth",
"access": "RW",
"description": "MMC card boot bus width(BOOT_BUS_WIDTH in Extended CSD)",
"values": [
{
"name": "1bitSDR4bitDDR",
"value": 0,
"description": "x1 (sdr) or x4 (ddr) bus width in boot operation mode(default)"
},
{
"name": "4bitSDR4bitDDR",
"value": 1,
"description": "x4 (sdr/ddr) bus width in boot operation mode"
},
{
"name": "8bitSDR8bitDDR",
"value": 2,
"description": "x8 (sdr/ddr) bus width in boot operation mode"
}
]
},
{
"width": 2
},
{
"id": "field000-bits20-22",
"width": 3,
"name": "BootPartitionEnabled",
"access": "RW",
"description": "MMC card boot partition enabled(BOOT_PARTITION_ENABLE in Extended CSD)",
"values": [
{
"name": "Not",
"value": 0,
"description": "Device not boot enabled (default)"
},
{
"name": "Partition1",
"value": 1,
"description": "Boot partition 1 enabled for boot"
},
{
"name": "Partition2",
"value": 2,
"description": "Boot partition 2 enabled for boot"
},
{
"name": "UserAera",
"value": 7,
"description": "User area enabled for boot"
}
]
},
{
"width": 1
},
{
"id": "field000-bits24-26",
"width": 3,
"name": "PartitionAccess",
"access": "RW",
"description": "MMC card partition to be accessed(BOOT_PARTITION_ACCESS in Extended CSD)",
"values": [
{
"name": "PartitionUserAera",
"value": 0,
"description": "No access to boot partition (default), normal partition"
},
{
"name": "PartitionBoot1",
"value": 1,
"description": "Read/Write boot partition 1"
},
{
"name": "PartitionBoot2",
"value": 2,
"description": "Read/Write boot partition 2"
},
{
"name": "RPMB",
"value": 3,
"description": "Replay protected mem block"
},
{
"name": "GeneralPurposePartition1",
"value": 4,
"description": "access to general purpose partition 1"
},
{
"name": "GeneralPurposePartition2",
"value": 5,
"description": "access to general purpose partition 2"
},
{
"name": "GeneralPurposePartition3",
"value": 6,
"description": "access to general purpose partition 3"
},
{
"name": "GeneralPurposePartition4",
"value": 7,
"description": "access to general purpose partition 4"
}
]
},
{
"width": 1
},
{
"width": 4
}
]
},
{
"id": "field004",
"offset_int": "0x4",
"reg_width": 32,
"name": "ConfigOption1",
"description": "MMC card Configuration Option 1 - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field004-bits0-3",
"width": 4,
"name": "Instance",
"access": "RW",
"description": "MMC peripheral instance"
},
{
"width": 2
},
{
"width": 10
},
{
"width": 2
},
{
"id": "field004-bit18",
"width": 1,
"name": "1V8",
"access": "RW",
"description": "MMC interface BUS use 1V8",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "1V8 disabled"
},
{
"name": "Enabled",
"value": 1,
"description": "1V8 enabled"
}
]
},
{
"id": "field004-bit19",
"width": 1,
"name": "EnablePowerCycle",
"access": "RW",
"description": "Execute power cycle before initialization",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "Power cycle disabled"
},
{
"name": "Enabled",
"value": 1,
"description": "Execute power cycle before initialization"
}
]
},
{
"id": "field004-bit20",
"width": 1,
"name": "PowerUpDelay",
"access": "RW",
"description": "Set power up delay",
"values": [
{
"name": "5ms",
"value": 0,
"description": "Power up delay 5ms"
},
{
"name": "2.5ms",
"value": 1,
"description": "Power up delay 2.5ms"
}
]
},
{
"width": 2
},
{
"id": "field004-bit23",
"width": 1,
"name": "PowerUpPolarity",
"access": "RW",
"description": "Power up polarity - May vary on different devices"
},
{
"id": "field004-bits24-25",
"width": 2,
"name": "PowerDownTime",
"access": "RW",
"description": "Set power down time",
"values": [
{
"name": "20ms",
"value": 0,
"description": "Power up delay 20ms"
},
{
"name": "10ms",
"value": 1,
"description": "Power up delay 10ms"
},
{
"name": "5ms",
"value": 2,
"description": "Power up delay 5ms"
},
{
"name": "2.5ms",
"value": 3,
"description": "Power up delay 2.5ms"
}
]
},
{
"width": 2
},
{
"width": 4
}
]
}
]
}
]
}

View file

@ -0,0 +1,183 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "SD card Configuration Option 0",
"default_value_int": "0xd0000000",
"bitfields": [
{
"id": "field000-bits0-3",
"width": 4,
"name": "Instance",
"access": "RW",
"description": "SD peripheral instance"
},
{
"width": 4
},
{
"id": "field000-bit8",
"width": 1,
"name": "BusWidth",
"access": "RW",
"description": "SD interface BUS width",
"values": [
{
"name": "1bit",
"value": 0,
"description": "BUS width 1 bit"
},
{
"name": "4bit",
"value": 1,
"description": "BUS width 4 bit"
}
]
},
{
"id": "field000-bits9-11",
"width": 3,
"name": "TunningStart",
"access": "RW",
"description": "Tunning start - the final value will be multiplicated by 32"
},
{
"id": "field000-bits12-14",
"width": 3,
"name": "TimingMode",
"access": "RW",
"description": "SD card timing mode flags",
"values": [
{
"name": "SDR12DefaultMode",
"value": 0,
"description": "Identification mode and SDR12"
},
{
"name": "SDR25HighSpeedMode",
"value": 1,
"description": "High speed mode and SDR25"
},
{
"name": "SDR50Mode",
"value": 2,
"description": "SDR50 mode"
},
{
"name": "SDR104Mode",
"value": 3,
"description": "SDR104 mode"
},
{
"name": "DDR50Mode",
"value": 4,
"description": "DDR50 mode"
}
]
},
{
"width": 4
},
{
"id": "field000-bit19",
"width": 1,
"name": "EnablePowerCycle",
"access": "RW",
"description": "Execute power cycle before initialization",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "Power cycle disabled"
},
{
"name": "Enabled",
"value": 1,
"description": "Execute power cycle before initialization"
}
]
},
{
"id": "field000-bit20",
"width": 1,
"name": "PowerUpDelay",
"access": "RW",
"description": "Set power up delay",
"values": [
{
"name": "5ms",
"value": 0,
"description": "Power up delay 5ms"
},
{
"name": "2.5ms",
"value": 1,
"description": "Power up delay 2.5ms"
}
]
},
{
"id": "field000-bits21-22",
"width": 2,
"name": "TunningStep",
"access": "RW",
"description": "Tunning step - the final value will be multiplicated by 2. In case of zero it used value 1"
},
{
"id": "field000-bit23",
"width": 1,
"name": "PowerUpPolarity",
"access": "RW",
"description": "Power up polarity - May vary on different devices"
},
{
"id": "field000-bits24-25",
"width": 2,
"name": "PowerDownTime",
"access": "RW",
"description": "Set power down time",
"values": [
{
"name": "20ms",
"value": 0,
"description": "Power up delay 20ms"
},
{
"name": "10ms",
"value": 1,
"description": "Power up delay 10ms"
},
{
"name": "5ms",
"value": 2,
"description": "Power up delay 5ms"
},
{
"name": "2.5ms",
"value": 3,
"description": "Power up delay 2.5ms"
}
]
},
{
"width": 2
},
{
"width": 4
}
]
}
]
}
]
}

View file

@ -0,0 +1,195 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "SEMC NAND Configuration Option 0",
"default_value_int": "0xd0000100",
"bitfields": [
{
"id": "field000-bits0-2",
"width": 3,
"name": "OnfiVersion",
"access": "RW",
"description": "ONFI version"
},
{
"id": "field000-bit3",
"width": 1,
"name": "EdoMode",
"access": "RW",
"description": "EDO mode",
"values": [
{
"name": "Disabled",
"value": 0,
"description": "EDO mode disabled"
},
{
"name": "Enabled",
"value": 1,
"description": "EDO mode enabled"
}
]
},
{
"id": "field000-bits4-6",
"width": 3,
"name": "OnfiTimingMode",
"access": "RW",
"description": "ONFI Timing mode",
"values": [
{
"name": "10MHz",
"value": 0,
"description": "Mode 0, 10MHz"
},
{
"name": "20MHz",
"value": 1,
"description": "Mode 1, 20MHz"
},
{
"name": "28MHz",
"value": 2,
"description": "Mode 2, 28MHz"
},
{
"name": "33MHz",
"value": 3,
"description": "Mode 3, 33MHz"
},
{
"name": "40MHz",
"value": 4,
"description": "Mode 4, 40MHz"
},
{
"name": "50MHz",
"value": 5,
"description": "Mode 5, 50MHz"
},
{
"name": "Fastest0",
"value": 6,
"description": "Mode 6, Fastest mode 0"
},
{
"name": "Fastest1",
"value": 7,
"description": "Mode 7, Fastest mode 1"
}
]
},
{
"width": 1
},
{
"id": "field000-bits8-9",
"width": 2,
"name": "IoPortDiv8",
"access": "RW",
"description": "IO port size, Minimum is 1"
},
{
"width": 2
},
{
"id": "field000-bits12-14",
"width": 3,
"name": "PcsSelection",
"access": "RW",
"description": "SEMC NAND PCS selection",
"values": [
{
"name": "CSX0",
"value": 0,
"description": "SEMC NAND CSX0"
},
{
"name": "CSX1",
"value": 1,
"description": "SEMC NAND CSX1"
},
{
"name": "CSX2",
"value": 2,
"description": "SEMC NAND CSX2"
},
{
"name": "CSX3",
"value": 3,
"description": "SEMC NAND CSX3"
},
{
"name": "A8",
"value": 4,
"description": "SEMC NAND A8"
}
]
},
{
"width": 1
},
{
"id": "field000-bit16",
"width": 1,
"name": "EccType",
"access": "RW",
"description": "ECC type",
"values": [
{
"name": "SW",
"value": 0,
"description": "Software ECC"
},
{
"name": "HW",
"value": 1,
"description": "Hardware ECC"
}
]
},
{
"id": "field000-bit17",
"width": 1,
"name": "EccStatus",
"access": "RW",
"description": "ECC status",
"values": [
{
"name": "Enabled",
"value": 0,
"description": "ECC enabled"
},
{
"name": "Disabled",
"value": 1,
"description": "ECC disabled"
}
]
},
{
"width": 6
},
{
"width": 4
},
{
"width": 4
}
]
}
]
}
]
}

View file

@ -0,0 +1,289 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "SEMC NOR Configuration Option 0",
"default_value_int": "0xd0000100",
"bitfields": [
{
"id": "field000-bits0-1",
"width": 2,
"name": "CommandSet",
"access": "RW",
"description": "SEMC Parallel NOR Flash command set",
"values": [
{
"name": "EPSCD",
"value": 0,
"description": "As Micron MT28EW Embedded Parallel NOR Standard Command Definitions"
},
{
"name": "SFMCD",
"value": 1,
"description": "As Micron MT28GU StrataFlash Memory Command Definitions"
}
]
},
{
"id": "field000-bits2-3",
"width": 2,
"name": "AcTimingMode",
"access": "RW",
"description": "SEMC Parallel NOR AC timing mode (Async read mode)",
"values": [
{
"name": "DefaultSafe",
"value": 0,
"description": "Timing default safe"
},
{
"name": "DefaultSast",
"value": 1,
"description": "Timing default fast"
},
{
"name": "UserDefined",
"value": 2,
"description": "Timing user defined. The definition (next 6 option words) MUST follow this option word"
}
]
},
{
"width": 4
},
{
"id": "field000-bits8-9",
"width": 2,
"name": "IoPortDiv8",
"access": "RW",
"description": "IO port size, Minimum is 1"
},
{
"id": "field000-bit10",
"width": 1,
"name": "AdvPortPolarity",
"access": "RW",
"description": "ADV# polarity",
"values": [
{
"name": "Low",
"value": 0,
"description": "ADV polarity low"
},
{
"name": "High",
"value": 1,
"description": "ADV polarity high"
}
]
},
{
"width": 1
},
{
"id": "field000-bits12-14",
"width": 3,
"name": "PcsSelection",
"access": "RW",
"description": "SEMC NOR PCS selection",
"values": [
{
"name": "CSX0",
"value": 0,
"description": "SEMC NOR CSX0"
},
{
"name": "CSX1",
"value": 1,
"description": "SEMC NOR CSX1"
},
{
"name": "CSX2",
"value": 2,
"description": "SEMC NOR CSX2"
},
{
"name": "CSX3",
"value": 3,
"description": "SEMC NOR CSX3"
},
{
"name": "A8",
"value": 4,
"description": "SEMC NOR A8"
},
{
"name": "RDY",
"value": 5,
"description": "SEMC NOR RDY"
}
]
},
{
"width": 1
},
{
"width": 8
},
{
"width": 4
},
{
"width": 4
}
]
},
{
"id": "field004",
"offset_int": "0x4",
"reg_width": 32,
"name": "ConfigOption1",
"description": "SEMC NOR Configuration Option 1 - User definition - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field004-bits0-15",
"width": 16,
"name": "min_tCEH_ns",
"access": "RW",
"description": "User definition min_tCEH_ns"
},
{
"id": "field004-bits16-31",
"width": 16,
"name": "min_tCES_ns",
"access": "RW",
"description": "User definition min_tCES_ns"
}
]
},
{
"id": "field008",
"offset_int": "0x8",
"reg_width": 32,
"name": "ConfigOption2",
"description": "SEMC NOR Configuration Option 2 - User definition - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field008-bits0-15",
"width": 16,
"name": "min_tAS_ns",
"access": "RW",
"description": "User definition min_tAS_ns"
},
{
"id": "field008-bits16-31",
"width": 16,
"name": "min_tCEITV_ns",
"access": "RW",
"description": "User definition min_tCEITV_ns"
}
]
},
{
"id": "field00C",
"offset_int": "0xc",
"reg_width": 32,
"name": "ConfigOption3",
"description": "SEMC NOR Configuration Option 3 - User definition - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field00C-bits0-15",
"width": 16,
"name": "min_tTA_ns",
"access": "RW",
"description": "User definition min_tTA_ns"
},
{
"id": "field00C-bits16-31",
"width": 16,
"name": "min_tAH_ns",
"access": "RW",
"description": "User definition min_tAH_ns"
}
]
},
{
"id": "field010",
"offset_int": "0x10",
"reg_width": 32,
"name": "ConfigOption4",
"description": "SEMC NOR Configuration Option 4 - User definition - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field010-bits0-15",
"width": 16,
"name": "min_tWEH_ns",
"access": "RW",
"description": "User definition min_tWEH_ns"
},
{
"id": "field010-bits16-31",
"width": 16,
"name": "min_tWEL_ns",
"access": "RW",
"description": "User definition min_tWEL_ns"
}
]
},
{
"id": "field014",
"offset_int": "0x14",
"reg_width": 32,
"name": "ConfigOption5",
"description": "SEMC NOR Configuration Option 5 - User definition - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field014-bits0-15",
"width": 16,
"name": "min_tREL_ns",
"access": "RW",
"description": "User definition min_tREL_ns"
},
{
"id": "field014-bits16-31",
"width": 16,
"name": "min_tAWDH_ns",
"access": "RW",
"description": "User definition min_tAWDH_ns"
}
]
},
{
"id": "field018",
"offset_int": "0x18",
"reg_width": 32,
"name": "ConfigOption6",
"description": "SEMC NOR Configuration Option 6 - User definition - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"width": 16
},
{
"id": "field018-bits16-31",
"width": 16,
"name": "max_tREH_ns",
"access": "RW",
"description": "User definition max_tREH_ns"
}
]
}
]
}
]
}

View file

@ -0,0 +1,356 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "FlexSPI NOR Configuration Option 0",
"default_value_int": "0xc0000000",
"bitfields": [
{
"id": "field000-bits0-3",
"width": 4,
"name": "PageSize",
"access": "RW",
"description": "Page size of the NOR flash device",
"values": [
{
"name": "256B",
"value": 0,
"description": "Page size 256B"
},
{
"name": "512B",
"value": 1,
"description": "Page size 512B"
},
{
"name": "1MB",
"value": 2,
"description": "Page size 1MB"
},
{
"name": "32B",
"value": 3,
"description": "Page size 32B"
},
{
"name": "64B",
"value": 4,
"description": "Page size 64B"
},
{
"name": "128B",
"value": 5,
"description": "Page size 128B"
}
]
},
{
"id": "field000-bits4-7",
"width": 4,
"name": "SectorSize",
"access": "RW",
"description": "Sector size of the NOR flash device",
"values": [
{
"name": "4KB",
"value": 0,
"description": "Page size 4KB"
},
{
"name": "8KB",
"value": 1,
"description": "Page size 8KB"
},
{
"name": "32KB",
"value": 2,
"description": "Page size 32KB"
},
{
"name": "64KB",
"value": 3,
"description": "Page size 64KB"
},
{
"name": "128KB",
"value": 4,
"description": "Page size 128KB"
},
{
"name": "256KB",
"value": 5,
"description": "Page size 256KB"
}
]
},
{
"id": "field000-bits8-11",
"width": 4,
"name": "MemorySize",
"access": "RW",
"description": "Memory capacity of the NOR flash device",
"values": [
{
"name": "512KB",
"value": 0,
"description": "Page size 512KB"
},
{
"name": "1MB",
"value": 1,
"description": "Page size 1MB"
},
{
"name": "2MB",
"value": 2,
"description": "Page size 2MB"
},
{
"name": "4MB",
"value": 3,
"description": "Page size 4MB"
},
{
"name": "8MB",
"value": 4,
"description": "Page size 8MB"
},
{
"name": "16MB",
"value": 5,
"description": "Page size 16MB"
},
{
"name": "32MB",
"value": 6,
"description": "Page size 32MB"
},
{
"name": "64MB",
"value": 7,
"description": "Page size 64MB"
},
{
"name": "128MB",
"value": 8,
"description": "Page size 128MB"
},
{
"name": "256MB",
"value": 9,
"description": "Page size 256MB"
},
{
"name": "512MB",
"value": 10,
"description": "Page size 512MB"
},
{
"name": "1GB",
"value": 11,
"description": "Page size 1GB"
},
{
"name": "32KB",
"value": 12,
"description": "Page size 32KB"
},
{
"name": "64KB",
"value": 13,
"description": "Page size 64KB"
},
{
"name": "128KB",
"value": 14,
"description": "Page size 128KB"
},
{
"name": "256KB",
"value": 15,
"description": "Page size 256KB"
}
]
},
{
"id": "field000-bits12-15",
"width": 4,
"name": "MemoryType",
"access": "RW",
"description": "Memory type used to configure and access the NOR flash",
"values": [
{
"name": "NorFlash",
"value": 0,
"description": "SPI NOR FLASH"
},
{
"name": "EEPROM",
"value": 1,
"description": "SPI EEPROM"
},
{
"name": "Terminator",
"value": 2,
"description": "Terminator"
}
]
},
{
"id": "field000-bits16-19",
"width": 4,
"name": "PcsIndex",
"access": "RW",
"description": "PCS index used by SPI to access serial NOR flash",
"values": [
{
"name": "PCS0",
"value": 0,
"description": "Use SPIx PCS0"
},
{
"name": "PCS1",
"value": 1,
"description": "Use SPIx PCS1"
},
{
"name": "PCS2",
"value": 2,
"description": "Use SPIx PCS2"
},
{
"name": "PCS3",
"value": 3,
"description": "Use SPIx PCS3"
}
]
},
{
"id": "field000-bits20-23",
"width": 4,
"name": "SpiIndex",
"access": "RW",
"description": "SPI interface used to access serial NOR flash",
"values": [
{
"name": "SPI0",
"value": 0,
"description": "Use SPI0"
},
{
"name": "SPI1",
"value": 1,
"description": "Use SPI1"
},
{
"name": "SPI2",
"value": 2,
"description": "Use SPI2"
},
{
"name": "SPI3",
"value": 3,
"description": "Use SPI3"
},
{
"name": "SPI4",
"value": 4,
"description": "Use SPI4"
},
{
"name": "SPI5",
"value": 5,
"description": "Use SPI5"
},
{
"name": "SPI6",
"value": 6,
"description": "Use SPI6"
},
{
"name": "SPI7",
"value": 7,
"description": "Use SPI7"
}
]
},
{
"id": "field000-bits24-27",
"width": 4,
"name": "OptionSize",
"access": "RW",
"description": "Option Size",
"values": [
{
"name": "OptionSize1",
"value": 0,
"description": "Option words = 1"
},
{
"name": "OptionSize2",
"value": 1,
"description": "Option words = 2"
}
]
},
{
"width": 4
}
]
},
{
"id": "field004",
"offset_int": "0x4",
"reg_width": 32,
"name": "ConfigOption1",
"description": "SPI NOR flash Configuration Option 1 - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field004-bits0-3",
"width": 4,
"name": "SpiSpeed",
"access": "RW",
"description": "Spi NOR/EEPROM module clock freq",
"values": [
{
"name": "20MHz",
"value": 0,
"description": "SPI Clock set to 20MHz"
},
{
"name": "10MHz",
"value": 1,
"description": "SPI Clock set to 10MHz"
},
{
"name": "5MHz",
"value": 2,
"description": "SPI Clock set to 5MHz"
},
{
"name": "2MHz",
"value": 3,
"description": "SPI Clock set to 2MHz"
}
]
},
{
"width": 28
}
]
}
]
}
]
}

View file

@ -0,0 +1,267 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "FlexSPI NOR Configuration Option 0",
"default_value_int": "0xc0000000",
"bitfields": [
{
"id": "field000-bits0-3",
"width": 4,
"name": "PageSize",
"access": "RW",
"description": "Page size of the NOR flash device",
"values": [
{
"name": "256B",
"value": 0,
"description": "Page size 256B"
},
{
"name": "512B",
"value": 1,
"description": "Page size 512B"
},
{
"name": "1MB",
"value": 2,
"description": "Page size 1MB"
},
{
"name": "32B",
"value": 3,
"description": "Page size 32B"
},
{
"name": "64B",
"value": 4,
"description": "Page size 64B"
},
{
"name": "128B",
"value": 5,
"description": "Page size 128B"
}
]
},
{
"id": "field000-bits4-7",
"width": 4,
"name": "SectorSize",
"access": "RW",
"description": "Sector size of the NOR flash device",
"values": [
{
"name": "4KB",
"value": 0,
"description": "Page size 4KB"
},
{
"name": "8KB",
"value": 1,
"description": "Page size 8KB"
},
{
"name": "32KB",
"value": 2,
"description": "Page size 32KB"
},
{
"name": "64KB",
"value": 3,
"description": "Page size 64KB"
},
{
"name": "128KB",
"value": 4,
"description": "Page size 128KB"
},
{
"name": "256KB",
"value": 5,
"description": "Page size 256KB"
}
]
},
{
"id": "field000-bits8-11",
"width": 4,
"name": "MemorySize",
"access": "RW",
"description": "Memory capacity of the NOR flash device",
"values": [
{
"name": "512KB",
"value": 0,
"description": "Page size 512KB"
},
{
"name": "1MB",
"value": 1,
"description": "Page size 1MB"
},
{
"name": "2MB",
"value": 2,
"description": "Page size 2MB"
},
{
"name": "4MB",
"value": 3,
"description": "Page size 4MB"
},
{
"name": "8MB",
"value": 4,
"description": "Page size 8MB"
},
{
"name": "16MB",
"value": 5,
"description": "Page size 16MB"
},
{
"name": "32MB",
"value": 6,
"description": "Page size 32MB"
},
{
"name": "64MB",
"value": 7,
"description": "Page size 64MB"
},
{
"name": "128MB",
"value": 8,
"description": "Page size 128MB"
},
{
"name": "256MB",
"value": 9,
"description": "Page size 256MB"
},
{
"name": "512MB",
"value": 10,
"description": "Page size 512MB"
},
{
"name": "1GB",
"value": 11,
"description": "Page size 1GB"
},
{
"name": "32KB",
"value": 12,
"description": "Page size 32KB"
},
{
"name": "64KB",
"value": 13,
"description": "Page size 64KB"
},
{
"name": "128KB",
"value": 14,
"description": "Page size 128KB"
},
{
"name": "256KB",
"value": 15,
"description": "Page size 256KB"
}
]
},
{
"id": "field000-bits12-15",
"width": 4,
"name": "MemoryType",
"access": "RW",
"description": "Memory type used to configure and access the NOR flash",
"values": [
{
"name": "Manual",
"value": 0,
"description": "Configure manually based on configure option block"
},
{
"name": "Auto",
"value": 2,
"description": "AutoConfigure the Nor flash via SFDP info"
}
]
},
{
"width": 4
},
{
"id": "field000-bits20-23",
"width": 4,
"name": "SpiIndex",
"access": "RW",
"description": "SPI interface used to access serial NOR flash",
"values": [
{
"name": "SPI0",
"value": 0,
"description": "Use SPI0"
},
{
"name": "SPI1",
"value": 1,
"description": "Use SPI1"
},
{
"name": "SPI2",
"value": 2,
"description": "Use SPI2"
},
{
"name": "SPI3",
"value": 3,
"description": "Use SPI3"
},
{
"name": "SPI4",
"value": 4,
"description": "Use SPI4"
},
{
"name": "SPI5",
"value": 5,
"description": "Use SPI5"
},
{
"name": "SPI6",
"value": 6,
"description": "Use SPI6"
},
{
"name": "SPI7",
"value": 7,
"description": "Use SPI7"
}
]
},
{
"width": 4
},
{
"width": 4
}
]
}
]
}
]
}

View file

@ -0,0 +1,318 @@
{
"cpu": "General",
"groups": [
{
"group": {
"name": "General regs",
"description": "General register generated by SPSDK"
},
"registers": [
{
"id": "field000",
"offset_int": "0x0",
"reg_width": 32,
"name": "ConfigOption0",
"description": "FlexSPI NOR Configuration Option 0",
"default_value_int": "0xc0000000",
"bitfields": [
{
"id": "field000-bits0-3",
"width": 4,
"name": "MaxFreq",
"access": "RW",
"description": "The maximum work frequency for specified Flash device",
"values": [
{
"name": "NoChange",
"value": 0,
"description": "Don't change FlexSPI clock setting"
},
{
"name": "30Mhz",
"value": 1,
"description": "30MHz"
},
{
"name": "50Mhz",
"value": 2,
"description": "50MHz"
},
{
"name": "60Mhz",
"value": 3,
"description": "60MHz"
},
{
"name": "80Mhz",
"value": 4,
"description": "80MHz"
},
{
"name": "100Mhz",
"value": 5,
"description": "100MHz"
},
{
"name": "120Mhz",
"value": 6,
"description": "120MHz"
},
{
"name": "133Mhz",
"value": 7,
"description": "133MHz"
},
{
"name": "166Mhz",
"value": 8,
"description": "166MHz"
},
{
"name": "200Mhz",
"value": 8,
"description": "200MHz"
}
]
},
{
"id": "field000-bits4-7",
"width": 4,
"name": "Misc",
"access": "RW",
"description": "Specify miscellaneous mode for selected flash type; Experimental feature, do not use in products, keep it as 0.",
"values": [
{
"name": "NotEnabled",
"value": 0,
"description": "Miscellaneous mode is not enabled"
},
{
"name": "Mode0-4-4",
"value": 1,
"description": "Enable 0-4-4 mode for High Random Read performance"
},
{
"name": "SwappedMode",
"value": 3,
"description": " Data Order Swapped mode (for MXIC OctaFlash only)"
}
]
},
{
"id": "field000-bits8-11",
"width": 4,
"name": "QuadEnableType",
"access": "RW",
"description": "Specify the Quad Enable sequence, only applicable for device that only JESD216 compliant, this field is ignored if device support JESD216A or later version. This field will be effective only if device is compliant with JESD216 only (9 longword SDFP table)",
"values": [
{
"name": "NotConfigure",
"value": 0,
"description": "Not Configured"
},
{
"name": "Bit6InSR1",
"value": 1,
"description": "QE bit is bit6 in StatusReg1"
},
{
"name": "Bit1InSR2",
"value": 2,
"description": "QE bit is bit1 in StatusReg2"
},
{
"name": "Bit7InSR2",
"value": 3,
"description": "QE bit is bit7 in StatusReg2"
},
{
"name": "Bit1InSR2EnableCmdIs0x31",
"value": 4,
"description": "QE bit is bit1 in StatusReg2, enable command is 0x31"
}
]
},
{
"id": "field000-bits12-15",
"width": 4,
"name": "CMDPad(s)",
"access": "RW",
"description": "Commands pads for the Flash device (1/4/8), for device that works under 1-1-4,1-4-4,1-1-8 or 1-8-8 mode, CMD pad(s) value is always 0x0, for devices that only support 4-4-4 mode for high performance, CMD pads value is 2, for devices that only support 8-8-8 mode for high performance, CMD pads value is 3",
"values": [
{
"name": "1",
"value": 0,
"description": "1 bit"
},
{
"name": "4",
"value": 2,
"description": "4 bits"
},
{
"name": "8",
"value": 3,
"description": "8 bits"
}
]
},
{
"id": "field000-bits16-19",
"width": 4,
"name": "Query CMDPad(s)",
"access": "RW",
"description": "Command pads (1/4/8) for the SFDP command",
"values": [
{
"name": "1",
"value": 0,
"description": "1 bit"
},
{
"name": "4",
"value": 2,
"description": "4 bits"
},
{
"name": "8",
"value": 3,
"description": "8 bits"
}
]
},
{
"id": "field000-bits20-23",
"width": 4,
"name": "Device Detection Type",
"access": "RW",
"description": "SW defined device types used for config block autodetection",
"values": [
{
"name": "QuadSPI_SDR",
"value": 0,
"description": "QuadSPI SDR"
},
{
"name": "QuadSPI_DDR",
"value": 1,
"description": "QuadSPI DDR"
},
{
"name": "HyperFLASH_3V",
"value": 3,
"description": "HyperFLASH 3V"
},
{
"name": "MXICOPI_DDR",
"value": 4,
"description": "MXICOPI DDR"
},
{
"name": "MicronOPI_DDR",
"value": 6,
"description": "MicronOPI DDR"
},
{
"name": "AdestoOPI_DDR",
"value": 8,
"description": "AdestoOPI DDR"
}
]
},
{
"id": "field000-bits24-27",
"width": 4,
"name": "OptionSize",
"access": "RW",
"description": "Option Size",
"values": [
{
"name": "OptionSize1",
"value": 0,
"description": "Option words = 1"
},
{
"name": "OptionSize2",
"value": 1,
"description": "Option words = 2"
}
]
},
{
"width": 4
}
]
},
{
"id": "field004",
"offset_int": "0x4",
"reg_width": 32,
"name": "ConfigOption1",
"description": "FlexSPI NOR Flash Configuration Option 1 - Optional",
"default_value_int": "0x0",
"bitfields": [
{
"id": "field004-bits0-7",
"width": 8,
"name": "DummyCycles",
"access": "RW",
"description": "User provided dummy cycles for SDR/DDR read command: 0 - Auto detection, Others - Specified dummy cycles"
},
{
"id": "field004-bits8-15",
"width": 8,
"name": "StatusOverride",
"access": "RW",
"description": "Override status register value during device mode configuration"
},
{
"id": "field004-bits16-19",
"width": 4,
"name": "PinMuxGroup",
"access": "RW",
"description": "Pin multiplexer group selection"
},
{
"id": "field004-bits20-23",
"width": 4,
"name": "DqsPinMuxGroup",
"access": "RW",
"description": "DQS Pin multiplexer group selection"
},
{
"id": "field004-bits24-27",
"width": 4,
"name": "PinDriveStrength",
"access": "RW",
"description": "The Drive Strength of FlexSPI Pads"
},
{
"id": "field004-bits28-31",
"width": 4,
"name": "FlashConnection",
"access": "RW",
"description": "Select the FlexSPI Port A/B",
"values": [
{
"name": "SingleFlashPort_A",
"value": 0,
"description": "Single Flash connected to port A"
},
{
"name": "ParallelMode",
"value": 1,
"description": "Parallel mode"
},
{
"name": "SingleFlashPort_B",
"value": 2,
"description": "Single Flash connected to port B"
}
]
}
]
}
]
}
]
}

View file

@ -0,0 +1,77 @@
# Copyright 2020-2024 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
rules:
- req_id: "1.1"
desc:
Never write any non-zero configuration into DCFG_CC_SOCU_NS_PIN before DCFG_CC_SOCU_PIN
contains any valid (non-zero) configuration.
msg: The CMPA.DCFG_CC_SOCU_PIN[0:9] must be set in case the CFPA.DCFG_CC_SOCU_NS_PIN[0:9] is set.
cond: any(True if (((CFPA.DCFG_CC_SOCU_NS_PIN >> index) & 1) and not ((CMPA.DCFG_CC_SOCU_PIN >> index) & 1)) else False for index in range(0, int(10)))
- req_id: "1.2"
desc:
Never write any non-zero configuration into DCFG_CC_SOCU_NS_DFLT before DCFG_CC_SOCU_DFLT
contains any valid (non-zero) configuration.
msg: The CMPA.DCFG_CC_SOCU_DFLT[0:9] must be set in case the CFPA.DCFG_CC_SOCU_NS_DFLT[0:9] is set.
cond: any(True if (((CFPA.DCFG_CC_SOCU_NS_DFLT >> index) & 1) and not ((CMPA.DCFG_CC_SOCU_DFLT >> index) & 1)) else False for index in range(0, int(10)))
- req_id: "1.3"
desc: Inverse value (upper 16 bits) of DCFG_CC_SOCU_PIN must be always
valid. Only exception are blank devices where CC_SOCU_PIN contains all
zeros.
msg: Inverse values are generated automatically based on configuration.
cond: CMPA.DCFG_CC_SOCU_PIN != 0 and (~(CMPA.DCFG_CC_SOCU_PIN>>int(16)) & 0xFFFF) != (CMPA.DCFG_CC_SOCU_PIN & 0xFFFF)
- req_id: "1.4"
desc: Inverse value (upper 16 bits) of DCFG_CC_SOCU_DFLT must be always
valid. Only exception are blank devices where CC_SOCU_DFLT contains all
zeros.
msg: Inverse values are generated automatically based on configuration.
cond: CMPA.DCFG_CC_SOCU_DFLT != 0 and (~(CMPA.DCFG_CC_SOCU_DFLT>>int(16)) & 0xFFFF) != (CMPA.DCFG_CC_SOCU_DFLT & 0xFFFF)
- req_id: "1.5"
desc: Inverse value (upper 16 bits) of DCFG_CC_SOCU_NS_PIN must be always
valid. Only exception are blank devices where CC_SOCU_xxx contains all
zeros.
msg: Inverse values are generated automatically based on configuration.
cond: CFPA.DCFG_CC_SOCU_NS_PIN != 0 and (~(CFPA.DCFG_CC_SOCU_NS_PIN>>int(16)) & 0xFFFF) != (CFPA.DCFG_CC_SOCU_NS_PIN & 0xFFFF)
- req_id: "1.6"
desc: Inverse value (upper 16 bits) of DCFG_CC_SOCU_NS_DFLT must be always
valid. Only exception are blank devices where CC_SOCU_DFLT contains all
zeros.
msg: Inverse values are generated automatically based on configuration.
cond: CFPA.DCFG_CC_SOCU_NS_DFLT != 0 and (~(CFPA.DCFG_CC_SOCU_NS_DFLT>>int(16)) & 0xFFFF) != (CFPA.DCFG_CC_SOCU_NS_DFLT & 0xFFFF)
- req_id: "1.7"
desc:
Do not write invalid PIN/DFLT configuration in CMPA area. Setting PIN bit
to 0 and DFLT bit to 1 for given feature is not allowed
msg: Invalid bit combination. If CMPA.DCFG_CC_SOCU_PIN[0:9] is 0, CMPA.DCFG_CC_SOCU_DFLT[0:9] can't be set to 1!
cond: any(True if (not ((CMPA.DCFG_CC_SOCU_PIN >> index) & 1) and ((CMPA.DCFG_CC_SOCU_DFLT >> index) & 1)) else False for index in range(0, int(10)))
- req_id: "1.8"
desc:
Do not write invalid PIN/DFLT configuration in CFPA area. Setting PIN bit
to 0 and DFLT bit to 1 for given feature is not allowed
msg: Invalid bit combination. If CFPA.DCFG_CC_SOCU_NS_PIN[0:9] is 0, CFPA.DCFG_CC_SOCU_NS_DFLT[0:9] can't be set to 1!
cond: any(True if (not ((CFPA.DCFG_CC_SOCU_NS_PIN >> index) & 1) and ((CFPA.DCFG_CC_SOCU_NS_DFLT >> index) & 1)) else False for index in range(0, int(10)))
- req_id: "1.9"
desc: If CMPA DCFG_CC_SOCU_DFLT is used the DCFG_CC_SOCU_PIN must be used also.
msg: The CMPA DCFG_CC_SOCU_PIN is not set, but the DCFG_CC_SOCU_DFLT is defined.
cond: CMPA.DCFG_CC_SOCU_DFLT != 0 and CMPA.DCFG_CC_SOCU_PIN==0
- req_id: "1.10"
desc: If CMPA DCFG_CC_SOCU_PIN is used the DCFG_CC_SOCU_DFLT must be used also.
msg: The CMPA DCFG_CC_SOCU_DFLT is not set, but the DCFG_CC_SOCU_PIN is defined.
cond: CMPA.DCFG_CC_SOCU_PIN != 0 and CMPA.DCFG_CC_SOCU_DFLT==0
- req_id: "2.1"
desc:
This CMPA_PROG_IN_PROGRESS must be always 0x00000000. Only ROM bootloader
is allowed to write anything to this field.
msg: The CMPA_PROG_IN_PROGRESS must be set to 0!
cond: CFPA.CMPA_PROG_IN_PROGRESS != 0

View file

@ -0,0 +1,38 @@
uuu_version 1.4.149
# @_flash.bin | bootloader, which can extract from wic image
# @_image [_flash.bin] | wic image burn to emmc.
# This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ
SDP: boot -f _flash.bin -scanlimited 0x800000
# This command will be run when ROM support stream mode
# i.MX8QXP, i.MX8QM
SDPS: boot -scanterm -f _flash.bin -scanlimited 0x800000
# These commands will be run when use SPL and will be skipped if no spl
# SDPU will be deprecated. please use SDPV instead of SDPU
# {
SDPU: delay 1000
SDPU: write -f _flash.bin -offset 0x57c00
SDPU: jump -scanlimited 0x800000
# }
# These commands will be run when use SPL and will be skipped if no spl
# if (SPL support SDPV)
# {
SDPV: delay 1000
SDPV: write -f _flash.bin -skipspl -scanterm -scanlimited 0x800000
SDPV: jump -scanlimited 0x800000
# }
FB: ucmd setenv fastboot_dev mmc
FB: ucmd setenv mmcdev ${emmc_dev}
FB: ucmd mmc dev ${emmc_dev}
FB: flash -raw2sparse all _image
FB: flash -scanterm -scanlimited 0x800000 bootloader _flash.bin
FB: ucmd if env exists emmc_ack; then ; else setenv emmc_ack 0; fi;
FB: ucmd mmc partconf ${emmc_dev} ${emmc_ack} 1 0
FB: done

View file

@ -0,0 +1,35 @@
uuu_version 1.2.39
# @_flash.bin | bootloader
# @_image [_flash.bin] | image burn to emmc, default is the same as bootloader
# This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ
SDP: boot -f _flash.bin
# This command will be run when ROM support stream mode
# i.MX8QXP, i.MX8QM
SDPS: boot -f _flash.bin
# These commands will be run when use SPL and will be skipped if no spl
# SDPU will be deprecated. please use SDPV instead of SDPU
# {
SDPU: delay 1000
SDPU: write -f _flash.bin -offset 0x57c00
SDPU: jump
# }
# These commands will be run when use SPL and will be skipped if no spl
# if (SPL support SDPV)
# {
SDPV: delay 1000
SDPV: write -f _flash.bin -skipspl
SDPV: jump
# }
FB: ucmd setenv fastboot_dev mmc
FB: ucmd setenv mmcdev ${emmc_dev}
FB: ucmd mmc dev ${emmc_dev}
FB: flash bootloader _image
FB: ucmd if env exists emmc_ack; then ; else setenv emmc_ack 0; fi;
FB: ucmd mmc partconf ${emmc_dev} ${emmc_ack} 1 0
FB: Done

View file

@ -0,0 +1,12 @@
uuu_version 1.1.4
# @_image | image, which cp to fat partition
# @_device | storage device, mmc\sata
# @_partition | fat partition number, like 1:1
# @_filename [_image] | file name in target fat partition, only support rootdir now
FB: ucmd setenv fastboot_buffer ${loadaddr}
FB: download -f _image
FB: ucmd if test ! -n "$fastboot_bytes"; then setenv fastboot_bytes $filesize; else true; fi
FB[-t 20000]: ucmd fatwrite _device _partition ${fastboot_buffer} _filename ${fastboot_bytes}
FB: done

View file

@ -0,0 +1,36 @@
uuu_version 1.2.39
# @_flexspi.bin | bootloader
# @_image [_flexspi.bin] | image burn to fspinand, default is the same as bootloader
# This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ
SDP: boot -f _flexspi.bin
# This command will be run when ROM support stream mode
# i.MX8QXP, i.MX8QM, skip QSPI header
SDPS: boot -f _flexspi.bin -skipfhdr
# These commands will be run when use SPL and will be skipped if no spl
# SDPU will be deprecated. please use SDPV instead of SDPU
# {
SDPU: delay 1000
SDPU: write -f _flexspi.bin -offset 0x10000 -skipfhdr
SDPU: jump
# }
# These commands will be run when use SPL and will be skipped if no spl
# if (SPL support SDPV)
# {
SDPV: delay 1000
SDPV: write -f _flexspi.bin -skipspl -skipfhdr
SDPV: jump
# }
FB: ucmd setenv fastboot_buffer ${loadaddr}
FB: download -f _image
FB: ucmd if test ! -n "$fastboot_bytes"; then setenv fastboot_bytes $filesize; else true; fi
FB[-t 60000]: ucmd fspinand init spi-nand0 ${fastboot_buffer} ${fastboot_bytes}
FB: done

View file

@ -0,0 +1,35 @@
uuu_version 1.2.39
# @_flash.bin | bootloader
# @_image [_flash.bin] | image burn to nand, default is the same as bootloader
# This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ
SDP: boot -f _flash.bin
# This command will be run when ROM support stream mode
# i.MX8QXP, i.MX8QM
SDPS: boot -f _flash.bin
# These commands will be run when use SPL and will be skipped if no spl
# SDPU will be deprecated. please use SDPV instead of SDPU
# {
SDPU: delay 1000
SDPU: write -f _flash.bin -offset 0x57c00
SDPU: jump
# }
# These commands will be run when use SPL and will be skipped if no spl
# if (SPL support SDPV)
# {
SDPV: delay 1000
SDPV: write -f _flash.bin -skipspl
SDPV: jump
# }
FB: ucmd setenv fastboot_buffer ${loadaddr}
FB: download -f _image
FB: ucmd if test ! -n "$fastboot_bytes"; then setenv fastboot_bytes $filesize; else true; fi
# Burn image to nandfit partition if needed
FB: ucmd if env exists nandfit_part; then nand erase.part nandfit; nand write ${fastboot_buffer} nandfit ${fastboot_bytes}; else true; fi;
FB: ucmd nandbcb init ${fastboot_buffer} nandboot ${fastboot_bytes}
FB: Done

View file

@ -0,0 +1,34 @@
uuu_version 1.4.149
# @_flash.bin | bootloader, which can extract from wic image
# @_image [_flash.bin] | wic image burn to emmc.
# This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ
SDP: boot -f _flash.bin -scanlimited 0x800000
# This command will be run when ROM support stream mode
# i.MX8QXP, i.MX8QM
SDPS: boot -scanterm -f _flash.bin -scanlimited 0x800000
# These commands will be run when use SPL and will be skipped if no spl
# SDPU will be deprecated. please use SDPV instead of SDPU
# {
SDPU: delay 1000
SDPU: write -f _flash.bin -offset 0x57c00
SDPU: jump -scanlimited 0x800000
# }
# These commands will be run when use SPL and will be skipped if no spl
# if (SPL support SDPV)
# {
SDPV: delay 1000
SDPV: write -f _flash.bin -skipspl -scanterm -scanlimited 0x800000
SDPV: jump -scanlimited 0x800000
# }
FB: ucmd pci
FB: ucmd nvme scan
FB: ucmd setenv fastboot_buffer ${loadaddr}
FB: write -format "nvme write ${fastboot_buffer} @off @size" -blksz 512 -f _image
FB: done

View file

@ -0,0 +1,43 @@
uuu_version 1.2.39
# @_flexspi.bin | bootloader
# @_image [_flexspi.bin] | image burn to flexspi, default is the same as bootloader
# This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ
SDP: boot -f _flexspi.bin
# This command will be run when ROM support stream mode
# i.MX8QXP, i.MX8QM, skip QSPI header
SDPS: boot -f _flexspi.bin -skipfhdr
# These commands will be run when use SPL and will be skipped if no spl
# SDPU will be deprecated. please use SDPV instead of SDPU
# {
SDPU: delay 1000
SDPU: write -f _flexspi.bin -offset 0x10000 -skipfhdr
SDPU: jump
# }
# These commands will be run when use SPL and will be skipped if no spl
# if (SPL support SDPV)
# {
SDPV: delay 1000
SDPV: write -f _flexspi.bin -skipspl -skipfhdr
SDPV: jump
# }
FB: ucmd setenv fastboot_buffer ${loadaddr}
FB: download -f _image
FB: ucmd if test ! -n "$fastboot_bytes"; then setenv fastboot_bytes $filesize; else true; fi
# Check Image if include flexspi header
FB: ucmd if qspihdr dump ${fastboot_buffer}; then setenv qspihdr_exist yes; else setenv qspihdr_exist no; fi;
FB[-t 60000]: ucmd if test ${qspihdr_exist} = yes; then qspihdr init ${fastboot_buffer} ${fastboot_bytes} safe; else true; fi;
#if uboot can't support qspihdr command, use uboot image to write qspi image, which require image include qspi flash header
FB: ucmd if test ${qspihdr_exist} = no; then sf probe; else true; fi;
FB[-t 40000]: ucmd if test ${qspihdr_exist} = no; then sf erase 0 +${fastboot_bytes}; else true; fi;
FB[-t 20000]: ucmd if test ${qspihdr_exist} = no; then sf write ${fastboot_buffer} 0 ${fastboot_bytes}; else true; fi;
FB: done

View file

@ -0,0 +1,35 @@
uuu_version 1.4.149
# @_flash.bin | bootloader, which can extract from wic image
# @_image [_flash.bin] | wic image burn to emmc.
# This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ
SDP: boot -f _flash.bin -scanlimited 0x800000
# This command will be run when ROM support stream mode
# i.MX8QXP, i.MX8QM
SDPS: boot -scanterm -f _flash.bin -scanlimited 0x800000
# These commands will be run when use SPL and will be skipped if no spl
# SDPU will be deprecated. please use SDPV instead of SDPU
# {
SDPU: delay 1000
SDPU: write -f _flash.bin -offset 0x57c00 -scanlimited 0x800000
SDPU: jump -scanlimited 0x800000
# }
# These commands will be run when use SPL and will be skipped if no spl
# if (SPL support SDPV)
# {
SDPV: delay 1000
SDPV: write -f _flash.bin -skipspl -scanterm -scanlimited 0x800000
SDPV: jump -scanlimited 0x800000
# }
FB: ucmd setenv fastboot_dev mmc
FB: ucmd setenv mmcdev ${sd_dev}
FB: ucmd mmc dev ${sd_dev}
FB: flash -raw2sparse all _image
FB: flash -scanterm -scanlimited 0x800000 bootloader _flash.bin
FB: done

View file

@ -0,0 +1,33 @@
uuu_version 1.2.39
# @_flash.bin | bootloader
# @_image [_flash.bin] | image burn to emmc, default is the same as bootloader
# This command will be run when i.MX6/7 i.MX8MM, i.MX8MQ
SDP: boot -f _flash.bin
# This command will be run when ROM support stream mode
# i.MX8QXP, i.MX8QM
SDPS: boot -f _flash.bin
# These commands will be run when use SPL and will be skipped if no spl
# SDPU will be deprecated. please use SDPV instead of SDPU
# {
SDPU: delay 1000
SDPU: write -f _flash.bin -offset 0x57c00
SDPU: jump
# }
# These commands will be run when use SPL and will be skipped if no spl
# if (SPL support SDPV)
# {
SDPV: delay 1000
SDPV: write -f _flash.bin -skipspl
SDPV: jump
# }
FB: ucmd setenv fastboot_dev mmc
FB: ucmd setenv mmcdev ${sd_dev}
FB: ucmd mmc dev ${sd_dev}
FB: flash bootloader _image
FB: Done

Some files were not shown because too many files have changed in this diff Show more