feat: Add ci to test all API of multinet, wakenet and afe

This commit is contained in:
xysun 2023-07-12 14:15:29 +08:00
parent 85b75fba3a
commit 297596c0f9
36 changed files with 27640 additions and 371 deletions

8
.gitignore vendored
View File

@ -24,4 +24,10 @@ _build/*
# Downloaded font files
docs/_static/DejaVuSans.ttf
docs/_static/NotoSansSC-Regular.otf
docs/_static/NotoSansSC-Regular.otf
# ci
test_apps/dependencies.lock
test_apps/managed_components
test_apps/*/build_*
pytest_log

215
conftest.py Normal file
View File

@ -0,0 +1,215 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
import logging
import os
import pathlib
import re
import sys
from datetime import datetime
from typing import Callable, List, Optional, Tuple
import pytest
from pytest import Config, FixtureRequest, Function, Session
from pytest_embedded.plugin import multi_dut_argument, multi_dut_fixture
IDF_VERSION = os.environ.get('IDF_VERSION')
PYTEST_ROOT_DIR = str(pathlib.Path(__file__).parent)
logging.info(f'Pytest root dir: {PYTEST_ROOT_DIR}')
@pytest.fixture(scope='session', autouse=True)
def idf_version() -> str:
if os.environ.get('IDF_VERSION'):
return os.environ.get('IDF_VERSION')
idf_path = os.environ.get('IDF_PATH')
if not idf_path:
logging.warning('Failed to get IDF_VERSION!')
return ''
version_path = os.path.join(os.environ['IDF_PATH'], 'tools/cmake/version.cmake')
regex = re.compile(r'^\s*set\s*\(\s*IDF_VERSION_([A-Z]{5})\s+(\d+)')
ver = {}
with open(version_path) as f:
for line in f:
m = regex.match(line)
if m:
ver[m.group(1)] = m.group(2)
return '{}.{}'.format(int(ver['MAJOR']), int(ver['MINOR']))
@pytest.fixture(scope='session', autouse=True)
def session_tempdir() -> str:
_tmpdir = os.path.join(
os.path.dirname(__file__),
'pytest_log',
datetime.now().strftime('%Y-%m-%d_%H-%M-%S'),
)
os.makedirs(_tmpdir, exist_ok=True)
return _tmpdir
@pytest.fixture
@multi_dut_argument
def config(request: FixtureRequest) -> str:
config_marker = list(request.node.iter_markers(name='config'))
return config_marker[0].args[0] if config_marker else 'default'
@pytest.fixture
@multi_dut_argument
def app_path(request: FixtureRequest, test_file_path: str) -> str:
config_marker = list(request.node.iter_markers(name='app_path'))
if config_marker:
return config_marker[0].args[0]
else:
# compatible with old pytest-embedded parametrize --app_path
return request.config.getoption('app_path', None) or os.path.dirname(test_file_path)
@pytest.fixture
def test_case_name(request: FixtureRequest, target: str, config: str) -> str:
if not isinstance(target, str):
target = '|'.join(sorted(list(set(target))))
if not isinstance(config, str):
config = '|'.join(sorted(list(config)))
return f'{target}.{config}.{request.node.originalname}'
@pytest.fixture
@multi_dut_fixture
def build_dir(
app_path: str,
target: Optional[str],
config: Optional[str],
idf_version: str
) -> Optional[str]:
"""
Check local build dir with the following priority:
1. <app_path>/${IDF_VERSION}/build_<target>_<config>
2. <app_path>/${IDF_VERSION}/build_<target>
3. <app_path>/build_<target>_<config>
4. <app_path>/build
5. <app_path>
Args:
app_path: app path
target: target
config: config
Returns:
valid build directory
"""
assert target
assert config
check_dirs = []
if idf_version:
check_dirs.append(os.path.join(idf_version, f'build_{target}_{config}'))
check_dirs.append(os.path.join(idf_version, f'build_{target}'))
check_dirs.append(f'build_{target}_{config}')
check_dirs.append('build')
check_dirs.append('.')
for check_dir in check_dirs:
binary_path = os.path.join(app_path, check_dir)
if os.path.isdir(binary_path):
logging.info(f'find valid binary path: {binary_path}')
return check_dir
logging.warning(
f'checking binary path: {binary_path} ... missing ... try another place')
logging.error(
f'no build dir. Please build the binary "python tools/build_apps.py {app_path}" and run pytest again')
sys.exit(1)
@pytest.fixture(autouse=True)
@multi_dut_fixture
def junit_properties(
test_case_name: str, record_xml_attribute: Callable[[str, object], None]
) -> None:
"""
This fixture is autoused and will modify the junit report test case name to <target>.<config>.<case_name>
"""
record_xml_attribute('name', test_case_name)
##################
# Hook functions #
##################
_idf_pytest_embedded_key = pytest.StashKey['IdfPytestEmbedded']
def pytest_addoption(parser: pytest.Parser) -> None:
base_group = parser.getgroup('idf')
base_group.addoption(
'--env',
help='only run tests matching the environment NAME.',
)
def pytest_configure(config: Config) -> None:
# Require cli option "--target"
help_commands = ['--help', '--fixtures', '--markers', '--version']
for cmd in help_commands:
if cmd in config.invocation_params.args:
target = 'unneeded'
break
else:
target = config.getoption('target')
if not target:
raise ValueError('Please specify one target marker via "--target [TARGET]"')
config.stash[_idf_pytest_embedded_key] = IdfPytestEmbedded(
target=target,
env_name=config.getoption('env'),
)
config.pluginmanager.register(config.stash[_idf_pytest_embedded_key])
def pytest_unconfigure(config: Config) -> None:
_pytest_embedded = config.stash.get(_idf_pytest_embedded_key, None)
if _pytest_embedded:
del config.stash[_idf_pytest_embedded_key]
config.pluginmanager.unregister(_pytest_embedded)
class IdfPytestEmbedded:
def __init__(
self,
target: Optional[str] = None,
env_name: Optional[str] = None,
):
# CLI options to filter the test cases
self.target = target
self.env_name = env_name
self._failed_cases: List[
Tuple[str, bool, bool]
] = [] # (test_case_name, is_known_failure_cases, is_xfail)
@pytest.hookimpl(tryfirst=True)
def pytest_sessionstart(self, session: Session) -> None:
if self.target:
self.target = self.target.lower()
session.config.option.target = self.target
# @pytest.hookimpl(tryfirst=True)
def pytest_collection_modifyitems(self, items: List[Function]) -> None:
# set default timeout 10 minutes for each case
for item in items:
# default timeout 5 mins
if 'timeout' not in item.keywords:
item.add_marker(pytest.mark.timeout(5 * 60))
# filter all the test cases with "--target"
if self.target:
def item_targets(item): return [m.args[0] for m in item.iter_markers(name='target')]
items[:] = [item for item in items if self.target in item_targets(item)]
# filter all the test cases with "--env"
if self.env_name:
def item_envs(item): return [m.args[0] for m in item.iter_markers(name='env')]
items[:] = [item for item in items if self.env_name in item_envs(item)]

42
pytest.ini Normal file
View File

@ -0,0 +1,42 @@
[pytest]
# exclude examples/ota/simple_ota_example/pytest_simple_ota.py
norecursedirs = examples/ota/*
# only the files with prefix `pytest_` would be recognized as pytest test scripts.
python_files = pytest_*.py
# set traceback to "short" to prevent the overwhelming tracebacks
addopts =
-s
--embedded-services esp,idf
--tb short
--skip-check-coredump y
# ignore PytestExperimentalApiWarning for record_xml_attribute
filterwarnings =
ignore::_pytest.warning_types.PytestExperimentalApiWarning
markers =
# target markers
target: target chip name (--target)
# env markers
env: target test env name (--env)
# config markers
config: choose specific bins built by `sdkconfig.ci.<config>`
# app_path markers
app_path: choose specific app_path, <app_path>[/build_xxx]
# log related
log_cli = True
log_cli_level = INFO
log_cli_format = %(asctime)s %(levelname)s %(message)s
log_cli_date_format = %Y-%m-%d %H:%M:%S
# junit related
junit_family = xunit1
## log all to `system-out` when case fail
junit_logging = stdout
junit_log_passing_tests = False

View File

@ -1,19 +0,0 @@
set(srcs
test_chinese_tts.c
)
if(IDF_TARGET STREQUAL "esp32")
list(APPEND srcs test_wakenet.c
test_afe.c
test_multinet.c)
elseif(IDF_TARGET STREQUAL "esp32s3")
list(APPEND srcs test_wakenet.c
test_afe.c
test_multinet.c)
endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS "."
REQUIRES cmock esp-sr)

View File

@ -1,96 +0,0 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#include <limits.h>
#include "unity.h"
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_tts.h"
#include "esp_tts_voice_xiaole.h"
#include "esp_tts_voice_template.h"
#include "esp_tts_player.h"
#include "esp_partition.h"
#include "esp_idf_version.h"
TEST_CASE("chinese tts create/destroy API & memory leak", "[tts]")
{
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
/*** 1. create esp tts handle ***/
void* voicedata;
const esp_partition_t* partition=esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "voice_data");
assert(partition != NULL);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_partition_mmap_handle_t mmap_handle;
ESP_ERROR_CHECK(esp_partition_mmap(partition, 0, partition->size, ESP_PARTITION_MMAP_DATA, &voicedata, &mmap_handle));
#else
spi_flash_mmap_handle_t mmap_handle;
ESP_ERROR_CHECK(esp_partition_mmap(partition, 0, partition->size, SPI_FLASH_MMAP_DATA, &voicedata, &mmap_handle));
#endif
// test model loading time
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
esp_tts_voice_t *voice=esp_tts_voice_set_init(&esp_tts_voice_template, (int16_t*)voicedata);
esp_tts_handle_t *tts_handle=esp_tts_create(voice);
gettimeofday(&tv_end, NULL);
int tv_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000;
printf("create latency:%d ms\n", tv_ms);
// test model memory concumption
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size - create_internal_size);
// test memory leak
esp_tts_voice_set_free(voice);
esp_tts_destroy(tts_handle);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_partition_munmap(mmap_handle); // support esp-idf v5
#else
spi_flash_munmap(mmap_handle); // support esp-idf v4
#endif
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int last_end_size = first_end_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i = 0; i < 6; i++) {
printf("init partition ...\n");
partition=esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "voice_data");
assert(partition != NULL);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
ESP_ERROR_CHECK(esp_partition_mmap(partition, 0, partition->size, ESP_PARTITION_MMAP_DATA, &voicedata, &mmap_handle));
#else
ESP_ERROR_CHECK(esp_partition_mmap(partition, 0, partition->size, SPI_FLASH_MMAP_DATA, &voicedata, &mmap_handle));
#endif
printf("create ...\n");
voice=esp_tts_voice_set_init(&esp_tts_voice_template, (int16_t*)voicedata);
tts_handle=esp_tts_create(voice);
printf("destroy ...\n");
esp_tts_voice_set_free(voice);
esp_tts_destroy(tts_handle);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_partition_munmap(mmap_handle); // support esp-idf v5
#else
spi_flash_munmap(mmap_handle); // support esp-idf v4
#endif
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i + 2, mem_leak);
}
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}

View File

@ -1,186 +0,0 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "string.h"
#include <limits.h>
#include "unity.h"
#include "model_path.h"
#include "esp_mn_iface.h"
#include "esp_mn_models.h"
#include "dakaidiandeng.h"
#include "alexa.h"
#include "dl_lib_convq_queue.h"
#include <sys/time.h>
TEST_CASE("multinet create/destroy API & memory leak", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
// test model loading time
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
printf("load multinet!\n");
model_iface_data_t *model_data = multinet->create(model_name, 6000);
gettimeofday(&tv_end, NULL);
int tv_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000;
printf("create latency:%d ms\n", tv_ms);
// test model memory concumption
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size - create_internal_size);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
// test memory leak
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int last_end_size = first_end_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i = 0; i < 5; i++) {
printf("init partition ...\n");
models = esp_srmodel_init("model");
model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
multinet = esp_mn_handle_from_name(model_name);
int time_out = 3000 + i * 2000;
printf("create ..., time out = %d\n", time_out);
model_data = multinet->create(model_name, time_out);
printf("destroy ...\n");
multinet->destroy(model_data);
esp_srmodel_deinit(models);
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i + 2, mem_leak);
}
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}
TEST_CASE("multinet detect/get_results API & cpu loading", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
int frequency = multinet->get_samp_rate(model_data);
int audio_chunksize = multinet->get_samp_chunksize(model_data) * sizeof(int16_t);
int16_t *buffer = malloc(audio_chunksize);
int chunks = 0;
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
while (1) {
if ((chunks + 1)*audio_chunksize <= sizeof(alexa)) {
memcpy(buffer, alexa + chunks * audio_chunksize, audio_chunksize);
} else {
memset(buffer, 0, audio_chunksize);
}
esp_mn_state_t mn_state = multinet->detect(model_data, buffer);
if (mn_state == ESP_MN_STATE_DETECTED) {
esp_mn_results_t *mn_result = multinet->get_results(model_data);
printf("Command id:%d\n", mn_result->command_id[0]);
}
chunks++;
if (chunks == 64) {
break;
}
}
gettimeofday(&tv_end, NULL);
int tv_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000;
chunks -= 7;
int run_ms = (chunks) * audio_chunksize / sizeof(int16_t) * 1000 / frequency;
float cpu_loading = tv_ms * 100.0 / run_ms;
printf("Done! Took %d ms to parse %d ms worth of samples in %d iterations. CPU loading(single core):%.1f%%\n",
tv_ms, run_ms, chunks, cpu_loading);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, (cpu_loading < 75 && tv_ms > 0));
}
TEST_CASE("multinet switch loader mode", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, "mn6", NULL);
if (model_name != NULL) {
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
int first_create_size = create_size;
printf("Internal RAM: %d, PSRAM:%d\n\n", create_internal_size, create_size-create_internal_size);
model_data = multinet->switch_loader_mode(model_data, ESP_MN_LOAD_FROM_PSRAM_FLASH);
create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n\n", create_internal_size, create_size-create_internal_size);
model_data = multinet->switch_loader_mode(model_data, ESP_MN_LOAD_FROM_PSRAM);
create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n\n", create_internal_size, create_size-create_internal_size);
model_data = multinet->switch_loader_mode(model_data, ESP_MN_LOAD_FROM_PSRAM);
model_data = multinet->switch_loader_mode(model_data, ESP_MN_LOAD_FROM_PSRAM_FLASH);
create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n\n", create_internal_size, create_size-create_internal_size);
model_data = multinet->switch_loader_mode(model_data, ESP_MN_LOAD_FROM_FLASH);
create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n\n", create_internal_size, create_size-create_internal_size);
model_data = multinet->switch_loader_mode(model_data, ESP_MN_LOAD_FROM_FLASH);
model_data = multinet->switch_loader_mode(model_data, ESP_MN_LOAD_FROM_PSRAM);
model_data = multinet->switch_loader_mode(model_data, ESP_MN_LOAD_FROM_FLASH);
model_data = multinet->switch_loader_mode(model_data, ESP_MN_LOAD_FROM_PSRAM_FLASH);
create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n\n", create_internal_size, create_size-create_internal_size);
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
printf("create latency:%d ms\n", tv_ms);
multinet->destroy(model_data);
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int first_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
int last_end_size = first_end_size;
int last_end_internal_size = first_end_internal_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && first_create_size == create_size);
} else {
printf("Just support multinet6 and the later versions\n");
TEST_ASSERT_EQUAL(true, 1);
}
}

View File

@ -0,0 +1,4 @@
test_apps:
enable:
- if: IDF_TARGET in ["esp32s3"]
temporary: false

11
test_apps/README.md Normal file
View File

@ -0,0 +1,11 @@
Steps to run these cases:
- Build
- . ${IDF_PATH}/export.sh
- pip install idf_build_apps
- python test_apps/build_apps.py test_apps -t esp32s3
- Test
- pip install -r test_apps/requirement.txt
- pytest test_apps --target esp32s3

151
test_apps/build_apps.py Normal file
View File

@ -0,0 +1,151 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
"""
This file is used in CI generate binary files for different kinds of apps
"""
import argparse
import sys
import os
import re
from pathlib import Path
from typing import List
from idf_build_apps import LOGGER, App, build_apps, find_apps, setup_logging
PROJECT_ROOT = Path(__file__).parent.parent.absolute()
print(PROJECT_ROOT)
APPS_BUILD_PER_JOB = 30
IGNORE_WARNINGS = [
r'1/2 app partitions are too small',
r'This clock source will be affected by the DFS of the power management',
r'The current IDF version does not support using the gptimer API',
]
def _get_idf_version():
if os.environ.get('IDF_VERSION'):
return os.environ.get('IDF_VERSION')
version_path = os.path.join(os.environ['IDF_PATH'], 'tools/cmake/version.cmake')
regex = re.compile(r'^\s*set\s*\(\s*IDF_VERSION_([A-Z]{5})\s+(\d+)')
ver = {}
with open(version_path) as f:
for line in f:
m = regex.match(line)
if m:
ver[m.group(1)] = m.group(2)
return '{}.{}'.format(int(ver['MAJOR']), int(ver['MINOR']))
def get_cmake_apps(
paths,
target,
config_rules_str,
default_build_targets,
): # type: (List[str], str, List[str]) -> List[App]
idf_ver = _get_idf_version()
apps = find_apps(
paths,
recursive=True,
target=target,
build_dir=f'{idf_ver}/build_@t_@w',
config_rules_str=config_rules_str,
build_log_path='build_log.txt',
size_json_path='size.json',
check_warnings=True,
preserve=True,
default_build_targets=default_build_targets,
manifest_files=[
# str(Path(PROJECT_ROOT) /'examples'/'.build-rules.yml'),
str(Path(PROJECT_ROOT) /'test_apps'/'.build-rules.yml'),
],
)
return apps
def main(args): # type: (argparse.Namespace) -> None
default_build_targets = args.default_build_targets.split(',') if args.default_build_targets else None
apps = get_cmake_apps(args.paths, args.target, args.config, default_build_targets)
print(apps)
if args.exclude_apps:
apps_to_build = [app for app in apps if app.name not in args.exclude_apps]
else:
apps_to_build = apps[:]
LOGGER.info('Found %d apps after filtering', len(apps_to_build))
LOGGER.info(
'Suggest setting the parallel count to %d for this build job',
len(apps_to_build) // APPS_BUILD_PER_JOB + 1,
)
ret_code = build_apps(
apps_to_build,
parallel_count=args.parallel_count,
parallel_index=args.parallel_index,
dry_run=False,
collect_size_info=args.collect_size_info,
keep_going=True,
ignore_warning_strs=IGNORE_WARNINGS,
copy_sdkconfig=True,
)
sys.exit(ret_code)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Build all the apps for different test types. Will auto remove those non-test apps binaries',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument('paths', nargs='*', help='Paths to the apps to build.')
parser.add_argument(
'-t', '--target',
default='all',
help='Build apps for given target. could pass "all" to get apps for all targets',
)
parser.add_argument(
'--config',
default=['sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'],
action='append',
help='Adds configurations (sdkconfig file names) to build. This can either be '
'FILENAME[=NAME] or FILEPATTERN. FILENAME is the name of the sdkconfig file, '
'relative to the project directory, to be used. Optional NAME can be specified, '
'which can be used as a name of this configuration. FILEPATTERN is the name of '
'the sdkconfig file, relative to the project directory, with at most one wildcard. '
'The part captured by the wildcard is used as the name of the configuration.',
)
parser.add_argument(
'--parallel-count', default=1, type=int, help='Number of parallel build jobs.'
)
parser.add_argument(
'--parallel-index',
default=1,
type=int,
help='Index (1-based) of the job, out of the number specified by --parallel-count.',
)
parser.add_argument(
'--collect-size-info',
type=argparse.FileType('w'),
help='If specified, the test case name and size info json will be written to this file',
)
parser.add_argument(
'--exclude-apps',
nargs='*',
help='Exclude build apps',
)
parser.add_argument(
'--default-build-targets',
default=None,
help='default build targets used in manifest files',
)
parser.add_argument(
'-v', '--verbose',
action='count', default=0,
help='Show verbose log message',
)
arguments = parser.parse_args()
if not arguments.paths:
arguments.paths = [PROJECT_ROOT]
setup_logging(verbose=arguments.verbose) # Info
main(arguments)

View File

@ -0,0 +1,10 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.5)
# Include the components directory of the main application:
#
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
"../../../esp-sr")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_sr_test)

View File

@ -0,0 +1,15 @@
dependencies:
espressif/esp-dsp:
component_hash: 59a67ce3be799201752ebde99890b0ab947054eff6463d83e944f2d4165d6905
source:
service_url: https://api.components.espressif.com/
type: service
version: 1.4.4
idf:
component_hash: null
source:
type: idf
version: 5.0.2
manifest_hash: 1c2a956562f88dbb4682372296ee9497ceb4a13d8ecd1e49e6be10eca321dd51
target: esp32s3
version: 1.0.0

View File

@ -0,0 +1,16 @@
if(IDF_TARGET STREQUAL "esp32s3")
set(srcs
"test_app_main.c"
"test_wakenet.c"
"test_multinet.c"
"test_afe.c"
)
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS "." "samples"
REQUIRES unity esp-sr
WHOLE_ARCHIVE)
endif()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
/* Example test application for testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "unity.h"
void app_main(void)
{
/* These are the different ways of running registered tests.
* In practice, only one of them is usually needed.
*
* UNITY_BEGIN() and UNITY_END() calls tell Unity to print a summary
* (number of tests executed/failed/ignored) of tests executed between these calls.
*/
// print_banner("Executing one test by its name");
// UNITY_BEGIN();
// unity_run_test_by_name("Mean of an empty array is zero");
// UNITY_END();
// print_banner("Running tests with [mean] tag");
// UNITY_BEGIN();
// unity_run_tests_by_tag("[mean]", false);
// UNITY_END();
// print_banner("Running tests without [fails] tag");
// UNITY_BEGIN();
// unity_run_tests_by_tag("[fails]", true);
// UNITY_END();
// print_banner("Running all the registered tests");
// UNITY_BEGIN();
// unity_run_all_tests();
// UNITY_END();
// print_banner("Starting interactive test menu");
/* This function will not return, and will be busy waiting for UART input.
* Make sure that task watchdog is disabled if you use this function.
*/
unity_run_menu();
}

View File

@ -0,0 +1,395 @@
/* test_mean.c: Implementation of a testable component.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRAMTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "string.h"
#include <limits.h>
#include "unity.h"
#include "model_path.h"
#include "esp_mn_iface.h"
#include "esp_mn_models.h"
#include "da_kai_kong_tiao.h"
#include "tell_me_a_joke.h"
#include "alexa.h"
#include "dl_lib_convq_queue.h"
#include <sys/time.h>
#include "esp_mn_speech_commands.h"
#include "esp_process_sdkconfig.h"
TEST_CASE("multinet create/destroy API & memory leak", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
int create_size = start_size - heap_caps_get_free_size(MALLOC_CAP_8BIT);
int create_internal_size = start_internal_size - heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
printf("Internal RAM: %d, PSRAM:%d\n", create_internal_size, create_size-create_internal_size);
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
printf("create latency:%d ms\n", tv_ms);
multinet->destroy(model_data);
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int last_end_size = first_end_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
for (int i=0; i<3; i++) {
printf("create ...\n");
model_data = multinet->create(model_name, 6000);
printf("destroy ...\n");
multinet->destroy(model_data);
last_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", i+2, mem_leak);
}
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, (mem_leak) < 1000 && last_end_size == first_end_size);
}
TEST_CASE("multinet cpu loading", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
int frequency = multinet->get_samp_rate(model_data);
int audio_chunksize = multinet->get_samp_chunksize(model_data) * sizeof(int16_t);
char *lang = multinet->get_language(model_data);
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
unsigned char* data = NULL;
size_t data_size = 0;
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
data = (unsigned char*)tell_me_a_joke;
data_size = sizeof(tell_me_a_joke);
printf("commands: tell me a joke, size:%d\n", data_size);
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
data = (unsigned char*)da_kai_kong_tiao;
data_size = sizeof(da_kai_kong_tiao);
printf("commands: da kai kong tiao, size:%d\n", data_size);
}
int16_t *buffer = malloc(audio_chunksize);
int chunks = 0;
struct timeval tv_start, tv_end;
gettimeofday(&tv_start, NULL);
esp_mn_state_t mn_state;
while (1) {
if ((chunks + 1)*audio_chunksize <= data_size) {
memcpy(buffer, data + chunks * audio_chunksize, audio_chunksize);
} else {
memset(buffer, 0, audio_chunksize);
}
mn_state = multinet->detect(model_data, buffer);
if (mn_state == ESP_MN_STATE_DETECTED) {
esp_mn_results_t *mn_result = multinet->get_results(model_data);
if (mn_result->num > 0)
printf("detected: command id:%d, string:%s\n",mn_result->command_id[0], mn_result->string);
else
printf("timeout\n");
break;
}
chunks++;
if (chunks > 600)
break;
}
gettimeofday(&tv_end, NULL);
int tv_ms=(tv_end.tv_sec-tv_start.tv_sec)*1000+(tv_end.tv_usec-tv_start.tv_usec)/1000;
chunks -= 7;
int run_ms = (chunks)*audio_chunksize/sizeof(int16_t)*1000/frequency;
printf("Done! Took %d ms to parse %d ms worth of samples in %d iterations. CPU loading(single core):%.1f%%\n",
tv_ms, run_ms, chunks, tv_ms*100.0/run_ms);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, mn_state == ESP_MN_STATE_DETECTED);
}
TEST_CASE("multinet set commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
printf("MODEL NAME %s\n", model_name);
// first
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
TEST_ESP_OK(esp_mn_commands_add(1, "TfL Mm c qbK"));
TEST_ESP_OK(esp_mn_commands_add(2, "hicST qbK"));
} else {
TEST_ESP_OK(esp_mn_commands_add(1, "TURN ON THE LIGHT"));
TEST_ESP_OK(esp_mn_commands_add(2, "TURN OFF THE KITCHEN LIGHT"));
}
error_phrases = esp_mn_commands_update();
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
TEST_ESP_OK(esp_mn_commands_add(1, "da kai dian deng"));
TEST_ESP_OK(esp_mn_commands_add(2, "guan bi chu fang dian deng"));
error_phrases = esp_mn_commands_update();
} else {
printf("Invalid language\n");
}
TEST_ASSERT_EQUAL(true, error_phrases == NULL);
// second
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
TEST_ESP_OK(esp_mn_commands_add(3, "TkN nN eL jc LiTS"));
TEST_ESP_OK(esp_mn_commands_add(4, "TkN eF eL jc LiTS"));
} else {
TEST_ESP_OK(esp_mn_commands_add(3, "TURN OFF THE LIGHT"));
TEST_ESP_OK(esp_mn_commands_add(4, "TURN OM THE KITCHEN LIGHT"));
}
error_phrases = esp_mn_commands_update();
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_add(3, "guan bi dian deng");
esp_mn_commands_add(4, "da kai chu fang dian deng");
error_phrases = esp_mn_commands_update();
} else {
printf("Invalid language\n");
}
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, error_phrases == NULL);
}
TEST_CASE("multinet add incorrect commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
esp_err_t state = ESP_OK;
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
state = esp_mn_commands_add(1, "TURN ON THE LIGHT 123");
assert(state == ESP_ERR_INVALID_STATE);
state = esp_mn_commands_add(2, "TURN. OFF THE LIGHT?");
assert(state == ESP_ERR_INVALID_STATE);
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
if (strcmp(model_name, "mn6_cn_ac") == 0 || strcmp(model_name, "mn6_cn") == 0) {
state = esp_mn_commands_add(1, "dakai dian deng");
assert(state == ESP_ERR_INVALID_STATE);
state = esp_mn_commands_add(2, "关闭电灯");
assert(state == ESP_ERR_INVALID_STATE);
} else {
state = esp_mn_commands_add(1, "k");
assert(state == ESP_ERR_INVALID_STATE);
}
} else {
printf("Invalid language\n");
}
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, error_phrases == NULL);
}
TEST_CASE("multinet add duplicated commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_add(1, "TfL Mm c qbK");
esp_mn_commands_add(1, "TfL Mm c qbK");
} else {
esp_mn_commands_add(1, "TURN ON THE LIGHT");
esp_mn_commands_add(1, "TURN ON THE LIGHT");
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_add(1, "da kai dian deng");
esp_mn_commands_add(1, "da kai dian deng");
} else {
printf("Invalid language\n");
}
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, error_phrases == NULL);
}
TEST_CASE("multinet print active commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_add(1, "TfL Mm qbK");
} else {
esp_mn_commands_add(1, "THIS SHOULD NOT APPEAR IN ACTIVE COMMANDS");
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_add(1, "bu ying gai chu xian zai biao zhong");
} else {
printf("Invalid language\n");
}
multinet->print_active_speech_commands(model_data);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, 1);
}
TEST_CASE("multinet remove commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_remove("TfL Mm c qbK");
} else {
esp_mn_commands_remove("TURN ON THE LIGHT");;
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_remove("da kai dian deng");
} else {
printf("Invalid language\n");
}
esp_mn_commands_update();
multinet->print_active_speech_commands(model_data);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, 1);
}
TEST_CASE("multinet clear and add commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
esp_mn_commands_clear();
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_add(1, "TfL Mm c qbK");
} else {
esp_mn_commands_add(1, "TURN ON THE LIGHT");
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_add(1, "da kai dian deng");
} else {
printf("Invalid language\n");
}
esp_mn_commands_update();
esp_mn_commands_print();
multinet->print_active_speech_commands(model_data);
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_add(2, "Sgl c Sel");
} else {
esp_mn_commands_add(2, "SING A SONG");
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_add(1, "guan bi dian deng");
} else {
printf("Invalid language\n");
}
esp_mn_commands_update();
esp_mn_commands_print();
multinet->print_active_speech_commands(model_data);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, 1);
}
TEST_CASE("multinet modify commands", "[mn]")
{
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
if (strcmp(model_name, "mn5q8_en") == 0) {
esp_mn_commands_modify("TfL Mm c qbK", "TfL TfL Mm c qbK");
} else {
esp_mn_commands_modify("TURN ON THE LIGHT", "TURN ON THE KITCHEN LIGHT");
}
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
esp_mn_commands_modify("da kai dian deng", "da kai chu fang deng");
} else {
printf("Invalid language\n");
}
esp_mn_commands_update();
multinet->print_active_speech_commands(model_data);
multinet->destroy(model_data);
esp_srmodel_deinit(models);
TEST_ASSERT_EQUAL(true, 1);
}

View File

@ -25,7 +25,7 @@ TEST_CASE("wakenet create/destroy API & memory leak", "[wn]")
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_wn_iface_t *wakenet = esp_wn_handle_from_name(model_name);
esp_wn_iface_t *wakenet = (esp_wn_iface_t*)esp_wn_handle_from_name(model_name);
// test model loading time
struct timeval tv_start, tv_end;
@ -52,7 +52,7 @@ TEST_CASE("wakenet create/destroy API & memory leak", "[wn]")
printf("init partition ...\n");
models = esp_srmodel_init("model");
model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
wakenet = esp_wn_handle_from_name(model_name);
wakenet = (esp_wn_iface_t*)esp_wn_handle_from_name(model_name);
printf("create ...\n");
// typedef enum {
@ -82,7 +82,7 @@ TEST_CASE("wakenet detect API & cpu loading", "[wn]")
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_wn_iface_t *wakenet = esp_wn_handle_from_name(model_name);
esp_wn_iface_t *wakenet = (esp_wn_iface_t*)esp_wn_handle_from_name(model_name);
model_iface_data_t *model_data = wakenet->create(model_name, DET_MODE_95);
int frequency = wakenet->get_samp_rate(model_data);
int audio_chunksize = wakenet->get_samp_chunksize(model_data) * sizeof(int16_t);

View File

@ -0,0 +1,4 @@
# Espressif ESP32 Partition Table
# Name, Type, SubType, Offset, Size
factory, app, factory, 0x010000, 8000k
model, data, , , 7000K,
1 # Espressif ESP32 Partition Table
2 # Name, Type, SubType, Offset, Size
3 factory, app, factory, 0x010000, 8000k
4 model, data, , , 7000K,

View File

@ -0,0 +1,36 @@
import pytest
from pytest_embedded import Dut
# @pytest.mark.target('esp32s3')
# @pytest.mark.parametrize(
# 'config',
# [
# 'mn5q8_cn',
# 'mn6_cn',
# ],
# )
# def test_multinet(dut: Dut)-> None:
# dut.run_all_single_board_cases(group="mn")
@pytest.mark.target('esp32s3')
@pytest.mark.parametrize(
'config',
[
'mn5q8_cn',
'wn9_hilexin',
],
)
def test_wakenet(dut: Dut)-> None:
dut.run_all_single_board_cases(group="wn")
@pytest.mark.target('esp32s3')
@pytest.mark.parametrize(
'config',
[
'wn9_hilexin',
],
)
def test_afe(dut: Dut)-> None:
dut.run_all_single_board_cases(group="afe")

View File

@ -0,0 +1,5 @@
pytest
pytest-embedded-idf
pytest-embedded-serial-esp
pytest-rerunfailures
pytest-timeout

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@
#include <string.h>
#include "unity.h"
static void print_banner(const char* text);
void app_main(void)
{
@ -46,10 +45,4 @@ void app_main(void)
* Make sure that task watchdog is disabled if you use this function.
*/
unity_run_menu();
// unity_run_all_tests();
}
static void print_banner(const char* text)
{
printf("\n#### %s #####\n\n", text);
}
}

View File

@ -27,7 +27,7 @@ TEST_CASE("chinese tts create/destroy API & memory leak", "[tts]")
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
/*** 1. create esp tts handle ***/
void* voicedata;
const void* voicedata;
const esp_partition_t* partition=esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "voice_data");
assert(partition != NULL);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)

View File

@ -45,7 +45,6 @@ TEST_CASE("multinet create/destroy API & memory leak", "[mn]")
multinet->destroy(model_data);
int first_end_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int first_end_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
int last_end_size = first_end_size;
int mem_leak = start_size - last_end_size;
printf("create&destroy times:%d, memory leak:%d\n", 1, mem_leak);
@ -72,21 +71,19 @@ TEST_CASE("multinet cpu loading", "[mn]")
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
int frequency = multinet->get_samp_rate(model_data);
int audio_chunksize = multinet->get_samp_chunksize(model_data) * sizeof(int16_t);
char *lang = multinet->get_language(model_data);
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
unsigned char* data = NULL;
int data_size = 0;
size_t data_size = 0;
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
data = tell_me_a_joke;
data = (unsigned char*)tell_me_a_joke;
data_size = sizeof(tell_me_a_joke);
printf("commands: tell me a joke, size:%d\n", data_size);
} else if(strcmp(lang, ESP_MN_CHINESE) == 0) {
data = da_kai_kong_tiao;
data = (unsigned char*)da_kai_kong_tiao;
data_size = sizeof(da_kai_kong_tiao);
printf("commands: da kai kong tiao, size:%d\n", data_size);
}
@ -106,7 +103,7 @@ TEST_CASE("multinet cpu loading", "[mn]")
mn_state = multinet->detect(model_data, buffer);
if (mn_state == ESP_MN_STATE_DETECTED) {
esp_mn_results_t *mn_result = multinet->get_results(model_data);
if (mn_result > 0)
if (mn_result->num > 0)
printf("detected: command id:%d, string:%s\n",mn_result->command_id[0], mn_result->string);
else
printf("timeout\n");
@ -135,13 +132,10 @@ TEST_CASE("multinet set commands", "[mn]")
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
printf("MODEL NAME %s\n", model_name);
esp_err_t state = ESP_OK;
// first
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
@ -193,8 +187,6 @@ TEST_CASE("multinet add incorrect commands", "[mn]")
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
@ -232,8 +224,6 @@ TEST_CASE("multinet add duplicated commands", "[mn]")
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
@ -266,8 +256,6 @@ TEST_CASE("multinet print active commands", "[mn]")
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
@ -299,11 +287,8 @@ TEST_CASE("multinet remove commands", "[mn]")
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {
@ -334,11 +319,8 @@ TEST_CASE("multinet clear and add commands", "[mn]")
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
esp_mn_commands_clear();
@ -388,11 +370,8 @@ TEST_CASE("multinet modify commands", "[mn]")
char *model_name = esp_srmodel_filter(models, ESP_MN_PREFIX, NULL);
esp_mn_iface_t *multinet = esp_mn_handle_from_name(model_name);
int start_size = heap_caps_get_free_size(MALLOC_CAP_8BIT);
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
model_iface_data_t *model_data = multinet->create(model_name, 6000);
char *lang = multinet->get_language(model_data);
esp_mn_error_t *error_phrases = NULL;
esp_mn_commands_update_from_sdkconfig(multinet, model_data);
if (strcmp(lang, ESP_MN_ENGLISH) == 0) {

View File

@ -25,7 +25,7 @@ TEST_CASE("wakenet create/destroy API & memory leak", "[wn]")
int start_internal_size = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_wn_iface_t *wakenet = esp_wn_handle_from_name(model_name);
esp_wn_iface_t *wakenet = (esp_wn_iface_t*)esp_wn_handle_from_name(model_name);
// test model loading time
struct timeval tv_start, tv_end;
@ -52,7 +52,7 @@ TEST_CASE("wakenet create/destroy API & memory leak", "[wn]")
printf("init partition ...\n");
models = esp_srmodel_init("model");
model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
wakenet = esp_wn_handle_from_name(model_name);
wakenet = (esp_wn_iface_t*)esp_wn_handle_from_name(model_name);
printf("create ...\n");
// typedef enum {
@ -82,7 +82,7 @@ TEST_CASE("wakenet detect API & cpu loading", "[wn]")
vTaskDelay(500 / portTICK_PERIOD_MS);
srmodel_list_t *models = esp_srmodel_init("model");
char *model_name = esp_srmodel_filter(models, ESP_WN_PREFIX, NULL);
esp_wn_iface_t *wakenet = esp_wn_handle_from_name(model_name);
esp_wn_iface_t *wakenet = (esp_wn_iface_t*)esp_wn_handle_from_name(model_name);
model_iface_data_t *model_data = wakenet->create(model_name, DET_MODE_95);
int frequency = wakenet->get_samp_rate(model_data);
int audio_chunksize = wakenet->get_samp_chunksize(model_data) * sizeof(int16_t);

View File

@ -0,0 +1,35 @@
'''
Steps to run these cases:
- Build
- . ${IDF_PATH}/export.sh
- pip install idf_build_apps
- python test_apps/build_apps.py test_apps -t esp32s3
- Test
- pip install -r tools/requirements/requirement.pytest.txt
- pytest test_apps --target esp32s2
'''
import pytest
from pytest_embedded import Dut
@pytest.mark.target('esp32s3')
@pytest.mark.parametrize(
'config',
[
'mn5q8_cn',
'mn6_cn',
],
)
def test_multinet(dut: Dut)-> None:
dut.run_all_single_board_cases(group="mn")
@pytest.mark.target('esp32s3')
@pytest.mark.parametrize(
'config',
[
'hilexin',
'hiesp',
],
)
def test_multinet(dut: Dut)-> None:
dut.run_all_single_board_cases(group="mn")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +0,0 @@
CONFIG_IDF_TARGET="esp32s3"
CONFIG_IDF_TARGET_ESP32S3=y
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y
CONFIG_ESP32S3_DATA_CACHE_64KB=y
CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set
CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y
CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y
CONFIG_MODEL_IN_SPIFFS=y
# CONFIG_MODEL_IN_SDCARD is not set
CONFIG_USE_WAKENET=y
CONFIG_SR_WN_MODEL_WN7_QUANT8=y
CONFIG_SR_WN_WN7_HILEXIN=y
# CONFIG_USE_MULTINET is not set