diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f3f95e --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# ---> esp-idf +# gitignore template for esp-idf, the official development framework for ESP32 +# https://github.com/espressif/esp-idf + +build/ +sdkconfig.old +.vscode/* diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3c16efc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "components/SystemK"] + path = components/SystemK + url = https://git.ktag.clubk.club/Software/SystemK diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..469c6c0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,9 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(2024A-SW) + diff --git a/README.md b/README.md index f703211..35c2cc2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,43 @@ -# 2024A-SW +# 2024A Software -Software for the 2024A using the ESP-IDF. \ No newline at end of file +## Overview + +This is software for the [2024A](https://git.clubk.club/KTag/2024A-HW) based on the +[ESP-IDF](https://github.com/espressif/esp-idf/). + +## License: [AGPL-3.0-or-later](https://spdx.org/licenses/AGPL-3.0-or-later.html) + +This software is part of the KTag project. + +🛡️ 🃞 + +Copyright © 2023-2025 Joseph P. Kearney and the KTag developers. + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU Affero General Public License as published by the Free +Software Foundation, either version 3 of the License, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +details. + +There should be a copy of the GNU Affero General Public License in the [LICENSE](LICENSE) +file in the root of this repository. If not, see . + +## Open-Source Software + +This software in turn makes use of the following open-source software libraries and components: + +| Name | Version | License ([SPDX](https://spdx.org/licenses/)) | URL +|----------------------------|--------:|--------------------------------------------------------------------------|--------------------------------------------- +| SystemK | 1.0 | [AGPL-3.0-or-later](https://spdx.org/licenses/AGPL-3.0-or-later.html) | https://git.clubk.club/KTag/SystemK +| ESP-IDF | 5.4.0 | [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) | https://github.com/espressif/esp-idf/ +| espressif/button | 3.5.0 | [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) | https://components.espressif.com/components/espressif/button +| espressif/led_strip | 2.5.3 | [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) | https://components.espressif.com/components/espressif/led_strip +| espressif/usb_host_msc | 1.1.3 | [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) | https://components.espressif.com/components/espressif/usb_host_msc +| espressif/mdns | 1.4.3 | [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) | https://components.espressif.com/components/espressif/mdns +| chmorgan/esp-audio-player | 1.0.7 | [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) | https://components.espressif.com/components/chmorgan/esp-audio-player +| esp-libhelix-mp3 | 1.0.3 | [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) | https://github.com/chmorgan/esp-libhelix-mp3 +| libhelix-mp3 | f443079 | [RPSL](https://github.com/chmorgan/libhelix-mp3/blob/master/LICENSE.txt) | https://github.com/chmorgan/libhelix-mp3 diff --git a/components/Audio/CMakeLists.txt b/components/Audio/CMakeLists.txt new file mode 100644 index 0000000..ec732cd --- /dev/null +++ b/components/Audio/CMakeLists.txt @@ -0,0 +1,11 @@ +idf_component_register( + SRCS + "I2S_Audio.c" + INCLUDE_DIRS + "." + REQUIRES + "SystemK" + "driver" + "spiffs" + "esp-audio-player" +) diff --git a/components/Audio/I2S_Audio.c b/components/Audio/I2S_Audio.c new file mode 100644 index 0000000..547255c --- /dev/null +++ b/components/Audio/I2S_Audio.c @@ -0,0 +1,462 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// I2S Configuration +#define I2S_DOUT GPIO_NUM_11 +#define I2S_BCLK GPIO_NUM_12 +#define I2S_LRC GPIO_NUM_13 +#define I2S_DIN I2S_GPIO_UNUSED +#define I2S_SCLK I2S_GPIO_UNUSED + +#define AUDIO_TASK_STACK_SIZE 4096 + +static StackType_t xStack[AUDIO_TASK_STACK_SIZE]; +static StaticTask_t xTaskBuffer; +static QueueHandle_t xQueueAudio; +static TaskHandle_t xAudioTaskHandle; +void I2SAudioTask(void *pvParameters); + +static const char *TAG = "I2S Audio"; +static i2s_chan_handle_t tx_handle; + +#define I2S_GPIO_CFG \ + { \ + .mclk = I2S_SCLK, \ + .bclk = I2S_BCLK, \ + .ws = I2S_LRC, \ + .dout = I2S_DOUT, \ + .din = I2S_DIN, \ + .invert_flags = { \ + .mclk_inv = false, \ + .bclk_inv = false, \ + .ws_inv = false, \ + }, \ + } + +#define I2S_DUPLEX_STEREO_CFG(_sample_rate) \ + { \ + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(_sample_rate), \ + .slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), \ + .gpio_cfg = I2S_GPIO_CFG, \ + } + +static esp_err_t I2S_Audio_Set_Mute(AUDIO_PLAYER_MUTE_SETTING setting) +{ + if (setting == AUDIO_PLAYER_MUTE) + { + KLOG_DEBUG(TAG, "Muted."); + } + else + { + KLOG_DEBUG(TAG, "Muted."); + } + return ESP_OK; +} +static esp_err_t I2S_Audio_Write(void *audio_buffer, size_t len, size_t *bytes_written, uint32_t timeout_ms) +{ + esp_err_t ret = ESP_OK; + ret = i2s_channel_write(tx_handle, (char *)audio_buffer, len, bytes_written, timeout_ms); + return ret; +} + +static esp_err_t I2S_Audio_Reconfigure_Clock(uint32_t rate, uint32_t bits_cfg, i2s_slot_mode_t ch) +{ + KLOG_INFO(TAG, "Reconfiguring clock for %lu sps, %lu bps, %d channels.", rate, bits_cfg, ch); + + esp_err_t ret = ESP_OK; + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(rate), + .slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t)bits_cfg, (i2s_slot_mode_t)ch), + .gpio_cfg = I2S_GPIO_CFG}; + + ret |= i2s_channel_disable(tx_handle); + ret |= i2s_channel_reconfig_std_clock(tx_handle, &std_cfg.clk_cfg); + ret |= i2s_channel_reconfig_std_slot(tx_handle, &std_cfg.slot_cfg); + ret |= i2s_channel_enable(tx_handle); + return ret; +} + +void Initialize_Audio(void) +{ + KLOG_INFO(TAG, "Initializing I2S Audio..."); + + // Setup a standard configuration and the channel. + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); + chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer. + ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, NULL)); + + // Setup the I2S configuration. + i2s_std_config_t std_cfg = I2S_DUPLEX_STEREO_CFG(44100); + esp_err_t ret = i2s_channel_init_std_mode(tx_handle, &std_cfg); + + if (ret != ESP_OK) + { + if (ret == ESP_ERR_NO_MEM) + { + KLOG_ERROR(TAG, "No memory for storing the channel information"); + } + else if (ret == ESP_ERR_INVALID_ARG) + { + KLOG_ERROR(TAG, "NULL pointer or invalid configuration"); + } + else if (ret == ESP_ERR_INVALID_STATE) + { + KLOG_ERROR(TAG, "This channel is not registered"); + } + else + { + KLOG_ERROR(TAG, "Failed to initialize I2S Audio (%s)", esp_err_to_name(ret)); + } + } + + i2s_channel_enable(tx_handle); + + xQueueAudio = xQueueCreate(5, sizeof(AudioAction_T)); + if (xQueueAudio == NULL) + { + KLOG_ERROR(TAG, "Couldn't create the I2S Audio queue."); + } + + audio_player_config_t config = {.mute_fn = I2S_Audio_Set_Mute, + .write_fn = I2S_Audio_Write, + .clk_set_fn = I2S_Audio_Reconfigure_Clock, + .priority = 10, + .coreID = APP_CPU_NUM}; + ret = audio_player_new(config); + if (ret != ESP_OK) + { + KLOG_ERROR(TAG, "Couldn't create the audio player."); + } + + xAudioTaskHandle = xTaskCreateStaticPinnedToCore( + I2SAudioTask, // Function that implements the task. + "I2S Audio", // Text name for the task. + AUDIO_TASK_STACK_SIZE, // Stack size in words, not bytes. + NULL, // Parameter passed into the task. + 1, // Priority at which the task is created. + xStack, // Array to use as the task's stack. + &xTaskBuffer, // Variable to hold the task's data structure. + APP_CPU_NUM); // Core where the task should run. + + if (xAudioTaskHandle == NULL) + { + KLOG_ERROR(TAG, "Couldn't create the I2S Audio task."); + } +} + +esp_err_t Play_Audio_File(const char *filename) +{ + KLOG_INFO(TAG, "Attempting to play file: %s", filename); + KLOG_DEBUG(TAG, "Free heap: %ld bytes", esp_get_free_heap_size()); + + FILE *fh = fopen(filename, "rb"); + if (fh == NULL) + { + KLOG_ERROR(TAG, "Failed to open audio file %s! Error: %s", filename, strerror(errno)); + return ESP_ERR_NOT_FOUND; + } + + fseek(fh, 0, SEEK_END); + long file_size = ftell(fh); + fseek(fh, 0, SEEK_SET); + KLOG_DEBUG(TAG, "File size: %ld bytes", file_size); + + esp_err_t ret = audio_player_play(fh); + if (ret != ESP_OK) + { + KLOG_ERROR(TAG, "Couldn't play audio file %s! Error: %d", filename, ret); + fclose(fh); + return ret; + } + + return ESP_OK; +} + +SystemKResult_T Perform_Audio_Action(AudioAction_T *action) +{ + if (xQueueSend(xQueueAudio, action, 0) == pdTRUE) + { + return SYSTEMK_RESULT_SUCCESS; + } + else + { + return SYSTEMK_RESULT_QUEUE_IS_FULL; + } +} + +char *concat_path(const char *directory_path, const char *filename) +{ + size_t needed = snprintf(NULL, 0, "%s/%s", directory_path, filename) + 1; + char *full_path = malloc(needed); + if (full_path != NULL) + { + snprintf(full_path, needed, "%s/%s", directory_path, filename); + } + return full_path; +} + +char *find_filename(const char *directory_path, const char *prefix) +{ + DIR *dir = opendir(directory_path); + if (dir == NULL) + { + KLOG_ERROR(TAG, "Failed to open directory '%s': %s!", directory_path, strerror(errno)); + return NULL; + } + + struct dirent *entry; + char *filename = NULL; + + while ((entry = readdir(dir)) != NULL) + { + if (entry->d_type == DT_REG && strncmp(entry->d_name, prefix, strlen(prefix)) == 0) + { + filename = strdup(entry->d_name); + if (filename == NULL) + { + KLOG_ERROR(TAG, "Memory allocation failed!"); + } + else + { + KLOG_DEBUG(TAG, "Found matching file: %s", filename); + } + break; + } + } + + closedir(dir); + + if (filename == NULL) + { + KLOG_WARN(TAG, "No file beginning with '%s' found in directory '%s'!", prefix, directory_path); + } + + return filename; +} + +SystemKResult_T Play_Sound_By_Prefix(const char *prefix) +{ + SystemKResult_T result = SYSTEMK_RESULT_SUCCESS; + + const char *sounds_dir = "/usb/01"; + + char *filename = find_filename(sounds_dir, prefix); + + if (filename != NULL) + { + if (audio_player_get_state() == AUDIO_PLAYER_STATE_PLAYING) + { + audio_player_stop(); + } + Play_Audio_File(concat_path(sounds_dir, filename)); + } + else + { + result = SYSTEMK_RESULT_FILE_NOT_FOUND; + } + + return result; +} + +SystemKResult_T Play_Number_Sound(uint8_t number) +{ + SystemKResult_T result = SYSTEMK_RESULT_SUCCESS; + + char number_str[4]; + snprintf(number_str, 4, "%03u", number); + + const char *sounds_dir = "/usb/10"; + + char *filename = find_filename(sounds_dir, (const char *)number_str); + + if (filename != NULL) + { + if (audio_player_get_state() == AUDIO_PLAYER_STATE_PLAYING) + { + audio_player_stop(); + } + Play_Audio_File(concat_path(sounds_dir, filename)); + } + else + { + result = SYSTEMK_RESULT_FILE_NOT_FOUND; + } + + return result; +} + +void I2SAudioTask(void *pvParameters) +{ + // Wait for system initialization. + // TODO: Make this closed-loop! + vTaskDelay(1000 / portTICK_PERIOD_MS); + + while (true) + { + AudioAction_T action; + + if (xQueueReceive(xQueueAudio, &action, portMAX_DELAY) == pdPASS) + { + + switch (action.ID) + { + case AUDIO_SET_VOLUME: + break; + + case AUDIO_SILENCE: + if (audio_player_get_state() == AUDIO_PLAYER_STATE_PLAYING) + { + audio_player_stop(); + } + break; + + case AUDIO_PLAY_STARTUP_SOUND: + Play_Sound_By_Prefix("001"); + break; + + case AUDIO_PLAY_SHOT_FIRED: + Play_Sound_By_Prefix("002"); + break; + + case AUDIO_PLAY_TAG_RECEIVED: + Play_Sound_By_Prefix("003"); + break; + + case AUDIO_PLAY_TAGGED_OUT: + Play_Sound_By_Prefix("004"); + break; + + case AUDIO_PLAY_MISFIRE: + Play_Sound_By_Prefix("005"); + break; + + case AUDIO_PRONOUNCE_NUMBER_0_TO_100: + uint8_t number = *((uint8_t *)action.Data); + if (number > 100) + { + number = 100; + } + else if (number == 0) + { + number = 101; + } + Play_Number_Sound(number); + break; + + case AUDIO_PLAY_MENU_PROMPT: + Play_Sound_By_Prefix("006"); + break; + + case AUDIO_PLAY_SELECTION_INDICATOR: + Play_Sound_By_Prefix("007"); + break; + + case AUDIO_PLAY_HEALTH_REMAINING: + Play_Sound_By_Prefix("008"); + break; + + case AUDIO_PLAY_ELECTRONIC_DANCE_MUSIC: + Play_Sound_By_Prefix("009"); + break; + + case AUDIO_PLAY_GENERIC_ERROR: + Play_Sound_By_Prefix("010"); + break; + + case AUDIO_PLAY_VOLUME_PROMPT: + Play_Sound_By_Prefix("011"); + break; + + case AUDIO_PLAY_RIGHT_HANDED: + Play_Sound_By_Prefix("012"); + break; + + case AUDIO_PLAY_LEFT_HANDED: + Play_Sound_By_Prefix("013"); + break; + + case AUDIO_PLAY_GAME_ON: + Play_Sound_By_Prefix("014"); + break; + + case AUDIO_PLAY_HARDWARE_SETTINGS_PROMPT: + Play_Sound_By_Prefix("015"); + break; + + case AUDIO_PLAY_GAME_SETTINGS_PROMPT: + Play_Sound_By_Prefix("016"); + break; + + case AUDIO_PLAY_BONK: + Play_Sound_By_Prefix("017"); + break; + + case AUDIO_PLAY_NEAR_MISS: + Play_Sound_By_Prefix("018"); + break; + + case AUDIO_PLAY_PLAYER_ID_PROMPT: + Play_Sound_By_Prefix("019"); + break; + + case AUDIO_PLAY_TEAM_ID_PROMPT: + Play_Sound_By_Prefix("020"); + break; + + case AUDIO_PLAY_FRIENDLY_FIRE: + KLOG_WARN(TAG, "\"Friendly Fire\" audio is disabled in this build."); + //Play_Sound_By_Prefix("021"); + break; + + case AUDIO_PLAY_STARTING_THEME: + Play_Sound_By_Prefix("022"); + break; + + case AUDIO_PLAY_BOOP: + Play_Sound_By_Prefix("023"); + break; + + case AUDIO_PLAY_BEEP: + Play_Sound_By_Prefix("024"); + break; + + case AUDIO_PLAY_REPROGRAMMING: + Play_Sound_By_Prefix("025"); + break; + + case AUDIO_PLAY_BOMB: + Play_Sound_By_Prefix("026"); + break; + + case AUDIO_PLAY_GAME_OVER: + Play_Sound_By_Prefix("027"); + break; + + default: + Play_Audio_File("/spiffs/bad.wav"); + break; + } + + if (action.Play_To_Completion == true) + { + // Allow some time for the audio to start. + vTaskDelay(100 / portTICK_PERIOD_MS); + + while (audio_player_get_state() != AUDIO_PLAYER_STATE_IDLE) + { + vTaskDelay(100 / portTICK_PERIOD_MS); + } + + KEvent_T command_received_event = {.ID = KEVENT_AUDIO_COMPLETED, .Data = (void *)action.ID}; + Post_KEvent(&command_received_event); + } + } + } +} \ No newline at end of file diff --git a/components/Audio/I2S_Audio.h b/components/Audio/I2S_Audio.h new file mode 100644 index 0000000..3cac360 --- /dev/null +++ b/components/Audio/I2S_Audio.h @@ -0,0 +1,4 @@ +#include "esp_err.h" + +void Initialize_Audio(void); +esp_err_t Play_WAV_File(char * filename); \ No newline at end of file diff --git a/components/BLE/BLE.c b/components/BLE/BLE.c new file mode 100644 index 0000000..15dfe83 --- /dev/null +++ b/components/BLE/BLE.c @@ -0,0 +1,276 @@ +#include +#include "esp_log.h" +/* BLE */ +#include "esp_nimble_hci.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#include "host/util/util.h" +#include "console/console.h" +#include "services/gap/ble_svc_gap.h" + +static const char *TAG = "BLE"; +static bool Host_And_Controller_Synced = false; +static bool Is_Scanning_And_Advertising = false; + +static uint8_t Advertising_Data[BLE_KTAG_PACKET_TOTAL_SIZE] = {0x1E, 0xFF, 0xFF, 0xFF, 'K', 'T', 'a', 'g'}; + +// Forward declarations of NimBLE functions. +void ble_store_config_init(void); +static int ble_gap_event(struct ble_gap_event *event, void *arg); + +/** + * Initiates the GAP general discovery procedure. + */ +static void ble_scan(void) +{ + uint8_t own_addr_type; + struct ble_gap_disc_params disc_params; + int rc; + + /* Figure out address to use while advertising (no privacy for now) */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) + { + KLOG_ERROR(TAG, "Error determining address type; rc=%d", rc); + return; + } + + /* Tell the controller not to filter duplicates; we want to process + * repeated advertisements from the same device. + */ + disc_params.filter_duplicates = 0; + + /** + * Perform a passive scan. I.e., don't send follow-up scan requests to + * each advertiser. + */ + disc_params.passive = 1; + + /* Use defaults for the rest of the parameters. */ + disc_params.itvl = BLE_GAP_SCAN_ITVL_MS(40); + disc_params.window = BLE_GAP_SCAN_WIN_MS(30); + disc_params.filter_policy = 0; + disc_params.limited = 0; + + rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params, ble_gap_event, NULL); + if (rc != 0) + { + KLOG_ERROR(TAG, "Error initiating GAP discovery procedure; rc=%d", rc); + } +} + +static void ble_advertise(void) +{ + struct ble_gap_adv_params adv_params; + + int rc = ble_gap_adv_set_data((const uint8_t *)&Advertising_Data, sizeof(Advertising_Data)); + if (rc != 0) + { + KLOG_ERROR(TAG, "Error setting advertisement data; rc=%d", rc); + return; + } + + /* Begin advertising. */ + memset(&adv_params, 0, sizeof adv_params); + adv_params.conn_mode = BLE_GAP_CONN_MODE_NON; + adv_params.disc_mode = BLE_GAP_DISC_MODE_NON; + + // N.B. High duty-cycle mode requires modification to NimBLE, or you will get an "Error enabling advertisement; rc=530" + // adv_params.high_duty_cycle = 1; + // adv_params.itvl_min = BLE_GAP_ADV_ITVL_MS(20); + // adv_params.itvl_max = BLE_GAP_ADV_ITVL_MS(25); + + adv_params.itvl_min = BLE_GAP_ADV_ITVL_MS(32); + adv_params.itvl_max = BLE_GAP_ADV_ITVL_MS(37); + + rc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, + &adv_params, ble_gap_event, NULL); + if (rc != 0) + { + KLOG_ERROR(TAG, "Error enabling advertisement; rc=%d", rc); + return; + } +} + +// https://mynewt.apache.org/latest/network/ble_setup/ble_sync_cb.html#reset +static void ble_on_reset(int reason) +{ + KLOG_ERROR(TAG, "Resetting state for reason %d.", reason); + Host_And_Controller_Synced = false; +} + +// https://mynewt.apache.org/latest/network/ble_setup/ble_sync_cb.html#sync +static void ble_on_sync(void) +{ + KLOG_INFO(TAG, "Host and controller synchronized."); + + /* Make sure we have proper identity address set (public preferred) */ + int rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + Host_And_Controller_Synced = true; +} + +/** + * The NimBLE host executes this callback when a GAP event occurs. The + * application associates a GAP event callback with each connection that is + * established. KTag uses the same callback for all connections. + * + * @param event The event being signalled. + * @param arg Application-specified argument; unused by KTag. + * + * @return 0 if the application successfully handled the + * event; nonzero on failure. The semantics + * of the return code is specific to the + * particular GAP event being signalled. + */ +static int ble_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_hs_adv_fields fields; + int rc; + + switch (event->type) + { + case BLE_GAP_EVENT_DISC: + rc = ble_hs_adv_parse_fields(&fields, event->disc.data, + event->disc.length_data); + if (rc != 0) + { + return 0; + } + + BLE_Packet_T *packet = BLE_DecodeKTagPacket(event->disc.data, + event->disc.length_data, + &(event->disc.addr.val[0]), + event->disc.rssi); + + if (packet != NULL) + { + if (packet->Generic.type == BLE_PACKET_TYPE_CONSOLE) + { + packet->Console.console_data[BLE_KTAG_PACKET_DATA_SIZE - 1] = '\0'; + HW_Execute_Console_Command(packet->Console.console_data); + } + else + { + KEvent_T packet_received_event = {.ID = KEVENT_BLE_PACKET_RECEIVED, .Data = packet}; + Post_KEvent(&packet_received_event); + } + } + return 0; + + case BLE_GAP_EVENT_ADV_COMPLETE: + KLOG_INFO(TAG, "Advertise complete; reason=%d", event->adv_complete.reason); + ble_advertise(); + return 0; + + default: + return 0; + } +} + +void ble_host_task(void *param) +{ + KLOG_INFO(TAG, "BLE Host Task Started"); + + // This function will return only after nimble_port_stop() is called: + nimble_port_run(); + + nimble_port_freertos_deinit(); +} + +void Initialize_BLE(void) +{ + KLOG_INFO(TAG, "Initializing BLE..."); + + esp_err_t ret = nimble_port_init(); + if (ret != ESP_OK) + { + KLOG_ERROR(TAG, "Failed to initialize NimBLE for reason %d.", ret); + return; + } + /* Configure the host. */ + ble_hs_cfg.reset_cb = ble_on_reset; + ble_hs_cfg.sync_cb = ble_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + ble_store_config_init(); + + nimble_port_freertos_init(ble_host_task); +} + +void Disable_BLE(void) +{ + KLOG_INFO(TAG, "Disabling BLE..."); + + esp_err_t ret = nimble_port_deinit(); + + if (ret != ESP_OK) + { + KLOG_ERROR(TAG, "Failed to deinitialize NimBLE for reason %d.", ret); + } + else + { + KLOG_INFO(TAG, "NimBLE deinitialized--BLE disabled."); + } +} + +SystemKResult_T BLE_GetMyAddress(uint8_t *BD_ADDR) +{ + /* Try to load a public address. */ + int result = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, BD_ADDR, NULL); + if (result == BLE_HS_ENOADDR) + { + return SYSTEMK_RESULT_NOT_IMPLEMENTED; + } + else + { + return SYSTEMK_RESULT_SUCCESS; + } +} + +SystemKResult_T BLE_SetAdvertisingData(BLE_AdvertisingData_T *data) +{ + SystemKResult_T result = SYSTEMK_RESULT_SUCCESS; + + if (data->length > BLE_MAX_ADVERTISING_BYTES) + { + result = SYSTEMK_RESULT_TOO_MANY_DATA; + } + else if (data->length < BLE_KTAG_PACKET_TOTAL_SIZE) + { + result = SYSTEMK_RESULT_TOO_FEW_DATA; + } + else + { + memcpy(Advertising_Data, data, BLE_KTAG_PACKET_TOTAL_SIZE); + } + + if (Is_Scanning_And_Advertising == true) + { + // Restart advertising to put the new data into the advertisement. + ble_gap_adv_stop(); + ble_advertise(); + } + + return result; +} + +SystemKResult_T BLE_ScanAndAdvertise(void) +{ + SystemKResult_T result = SYSTEMK_RESULT_NOT_READY; + + if (Host_And_Controller_Synced == true) + { + if (Is_Scanning_And_Advertising == false) + { + ble_scan(); + ble_advertise(); + Is_Scanning_And_Advertising = true; + } + result = SYSTEMK_RESULT_SUCCESS; + } + + return result; +} \ No newline at end of file diff --git a/components/BLE/BLE.h b/components/BLE/BLE.h new file mode 100644 index 0000000..404c73c --- /dev/null +++ b/components/BLE/BLE.h @@ -0,0 +1,4 @@ +#include "esp_err.h" + +void Initialize_BLE(void); +void Disable_BLE(void); \ No newline at end of file diff --git a/components/BLE/CMakeLists.txt b/components/BLE/CMakeLists.txt new file mode 100644 index 0000000..ed6be1e --- /dev/null +++ b/components/BLE/CMakeLists.txt @@ -0,0 +1,10 @@ +idf_component_register( + SRCS + "BLE.c" + INCLUDE_DIRS + "." + REQUIRES + "SystemK" + "driver" + "bt" +) diff --git a/components/IR/CMakeLists.txt b/components/IR/CMakeLists.txt new file mode 100644 index 0000000..3b94569 --- /dev/null +++ b/components/IR/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_component_register( + SRCS + "IR.c" + INCLUDE_DIRS + "." + REQUIRES + "SystemK" + "driver" +) diff --git a/components/IR/IR.c b/components/IR/IR.c new file mode 100644 index 0000000..6d393f8 --- /dev/null +++ b/components/IR/IR.c @@ -0,0 +1,362 @@ +#include +#include +#include +#include + +#define IR_RESOLUTION_HZ (1 * 1000 * 1000) // 1MHz resolution, 1 tick = 1us + +#define IR_TX_PIN GPIO_NUM_6 +#define IR_TX_RIGHT_ENABLE GPIO_NUM_7 +#define IR_TX_LEFT_ENABLE GPIO_NUM_5 + +#define IR_RX_LEFT_PIN GPIO_NUM_2 +#define IR_RX_FORWARD_PIN GPIO_NUM_15 +#define IR_RX_RIGHT_PIN GPIO_NUM_42 + +static const char *TAG = "IR"; +static rmt_channel_handle_t Tx_Channel = NULL; + +static gpio_config_t tx_right_enable_gpio_config = { + .pin_bit_mask = (1ULL << IR_TX_RIGHT_ENABLE), + .mode = GPIO_MODE_OUTPUT, // Set mode to output + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE}; + +static gpio_config_t tx_left_enable_gpio_config = { + .pin_bit_mask = (1ULL << IR_TX_LEFT_ENABLE), + .mode = GPIO_MODE_OUTPUT, // Set mode to output + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE}; + +// Create simple encoder +rmt_copy_encoder_config_t Copy_Encoder_Config; +rmt_encoder_handle_t Tx_Encoder; + +rmt_transmit_config_t Tx_Config = { + .loop_count = 0, // no transfer loop +}; + +rmt_receive_config_t Rx_Config = { + .signal_range_min_ns = 5 * 1000, // A pulse whose width is smaller than this threshold will be treated as glitch and ignored. + .signal_range_max_ns = 20 * 1000 * 1000, // RMT will stop receiving if one symbol level has kept longer than this value. + .flags.en_partial_rx = false}; + +static rmt_channel_handle_t Left_Rx_Channel = NULL; +static rmt_channel_handle_t Forward_Rx_Channel = NULL; +static rmt_channel_handle_t Right_Rx_Channel = NULL; + +static QueueHandle_t Receive_Queue; + +static TimedPulseTrain_T Left_Rxd_RMT_Data; +static TimedPulseTrain_T Forward_Rxd_RMT_Data; +static TimedPulseTrain_T Right_Rxd_RMT_Data; + +#define IR_RX_STACK_SIZE 4096 +static StaticTask_t xTaskBuffer; +static StackType_t xStack[IR_RX_STACK_SIZE]; +static TaskHandle_t IR_Rx_Task_Handle; + +static TagPacket_T Shot_Packet; + +typedef struct +{ + uint8_t count; + TagSensorLocation_T location; +} RxNotification_T; + +static bool RMT_Rx_Left_Done_Callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + RxNotification_T notice; + + notice.count = edata->num_symbols * 2; + notice.location = TAG_SENSOR_LEFT; + xQueueSendFromISR(Receive_Queue, ¬ice, &xHigherPriorityTaskWoken); + + return xHigherPriorityTaskWoken; +} + +static bool RMT_Rx_Forward_Done_Callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + RxNotification_T notice; + + notice.count = edata->num_symbols * 2; + notice.location = TAG_SENSOR_FORWARD; + xQueueSendFromISR(Receive_Queue, ¬ice, &xHigherPriorityTaskWoken); + + return xHigherPriorityTaskWoken; +} + +static bool RMT_Rx_Right_Done_Callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + RxNotification_T notice; + + notice.count = edata->num_symbols * 2; + notice.location = TAG_SENSOR_RIGHT; + xQueueSendFromISR(Receive_Queue, ¬ice, &xHigherPriorityTaskWoken); + + return xHigherPriorityTaskWoken; +} + +static const rmt_rx_event_callbacks_t left_cbs = { + .on_recv_done = RMT_Rx_Left_Done_Callback, +}; + +static const rmt_rx_event_callbacks_t forward_cbs = { + .on_recv_done = RMT_Rx_Forward_Done_Callback, +}; + +static const rmt_rx_event_callbacks_t right_cbs = { + .on_recv_done = RMT_Rx_Right_Done_Callback, +}; + +static void IR_Receive_Task(void *param) +{ + KLOG_INFO(TAG, "IR Receive Task Started"); + + while (true) + { + RxNotification_T notice; + DecodedPacket_T *result = NULL; + + if (xQueueReceive(Receive_Queue, ¬ice, portMAX_DELAY) == pdPASS) + { + if (notice.location == TAG_SENSOR_FORWARD) + { + KLOG_INFO(TAG, "TAG_SENSOR_FORWARD Rx'd"); + Forward_Rxd_RMT_Data.count = notice.count; + result = PROTOCOLS_MaybeDecodePacket(&Forward_Rxd_RMT_Data); + } + else if (notice.location == TAG_SENSOR_LEFT) + { + KLOG_INFO(TAG, "TAG_SENSOR_LEFT Rx'd"); + Left_Rxd_RMT_Data.count = notice.count; + result = PROTOCOLS_MaybeDecodePacket(&Left_Rxd_RMT_Data); + } + else if (notice.location == TAG_SENSOR_RIGHT) + { + KLOG_INFO(TAG, "TAG_SENSOR_RIGHT Rx'd"); + Right_Rxd_RMT_Data.count = notice.count; + result = PROTOCOLS_MaybeDecodePacket(&Right_Rxd_RMT_Data); + } + + if (result != NULL) + { + if (result->Generic.type == DECODED_PACKET_TYPE_TAG_RECEIVED) + { + KEvent_T tag_received_event = {.ID = KEVENT_TAG_RECEIVED, .Data = result}; + Post_KEvent(&tag_received_event); + } + else if (result->Generic.type == DECODED_PACKET_TYPE_COMMAND_RECEIVED) + { + KEvent_T command_received_event = {.ID = KEVENT_COMMAND_RECEIVED, .Data = result}; + Post_KEvent(&command_received_event); + } + } + else + { + KEvent_T near_miss_event = {.ID = KEVENT_NEAR_MISS, .Data = NULL}; + Post_KEvent(&near_miss_event); + } + + // Start receiving again. + // We need to reset all three channels for some reason--why? + { + ESP_ERROR_CHECK(rmt_disable(Forward_Rx_Channel)); + ESP_ERROR_CHECK(rmt_enable(Forward_Rx_Channel)); + ESP_ERROR_CHECK(rmt_receive(Forward_Rx_Channel, &Forward_Rxd_RMT_Data, sizeof(Forward_Rxd_RMT_Data.pulsetrain), &Rx_Config)); + } + { + ESP_ERROR_CHECK(rmt_disable(Left_Rx_Channel)); + ESP_ERROR_CHECK(rmt_enable(Left_Rx_Channel)); + ESP_ERROR_CHECK(rmt_receive(Left_Rx_Channel, &Left_Rxd_RMT_Data, sizeof(Left_Rxd_RMT_Data.pulsetrain), &Rx_Config)); + } + { + ESP_ERROR_CHECK(rmt_disable(Right_Rx_Channel)); + ESP_ERROR_CHECK(rmt_enable(Right_Rx_Channel)); + ESP_ERROR_CHECK(rmt_receive(Right_Rx_Channel, &Right_Rxd_RMT_Data, sizeof(Right_Rxd_RMT_Data.pulsetrain), &Rx_Config)); + } + } + } +} + +static void Initialize_Receive_Task(void) +{ + IR_Rx_Task_Handle = xTaskCreateStaticPinnedToCore( + IR_Receive_Task, // Function that implements the task. + "IR Rx", // Text name for the task. + IR_RX_STACK_SIZE, // Stack size in words, not bytes. + 0, // Parameter passed into the task. + tskIDLE_PRIORITY + 1, // Priority at which the task is created. + xStack, // Array to use as the task's stack. + &xTaskBuffer, // Variable to hold the task's data structure. + APP_CPU_NUM); // Core where the task should run. + + if (IR_Rx_Task_Handle == NULL) + { + KLOG_ERROR(TAG, "Failed to create IR Receive task!"); + } +} + +void Initialize_IR(SemaphoreHandle_t init_complete) +{ + KLOG_INFO(TAG, "Initializing IR..."); + + KLOG_INFO(TAG, "Creating RMT TX channel..."); + rmt_tx_channel_config_t tx_channel_cfg = { + .gpio_num = IR_TX_PIN, // GPIO number used by RMT TX channel. + .clk_src = RMT_CLK_SRC_XTAL, // Clock source of RMT TX channel, channels in the same group must use the same clock source + .resolution_hz = IR_RESOLUTION_HZ, // Channel clock resolution, in Hz. + .mem_block_symbols = 48, // If DMA is not used, this field controls the size of the dedicated memory block owned by the channel. + // THIS IS WRONG IN THE DOCS! See https://github.com/espressif/esp-idf/issues/12084#issuecomment-1679881770. + .trans_queue_depth = 1, // Depth of the internal transaction queue. + .flags.invert_out = false, // Should the signal be inverted before sending it to the GPIO? + .flags.with_dma = true, // Should this channel use the DMA backend? + .flags.io_loop_back = false, // Should the signal output from the GPIO be fed to the input path as well? + .flags.io_od_mode = false, // Should the GPIO be configured in open-drain mode? + .intr_priority = 1 // RMT interrupt priority. If set to 0 , then the driver will use a interrupt with low or medium priority (priority level may be one of 1, 2, or 3). + }; + ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_channel_cfg, &Tx_Channel)); + + KLOG_INFO(TAG, "Modulate carrier to TX channel"); + rmt_carrier_config_t carrier_cfg = { + .duty_cycle = 0.30, // 30% duty cycle + .frequency_hz = 38000, // 38KHz + }; + ESP_ERROR_CHECK(rmt_apply_carrier(Tx_Channel, &carrier_cfg)); + + ESP_ERROR_CHECK(rmt_enable(Tx_Channel)); + + ESP_ERROR_CHECK(gpio_config(&tx_right_enable_gpio_config)); + KLOG_INFO(TAG, "Initialized right IR Tx enable as GPIO[%d].", IR_TX_RIGHT_ENABLE); + + ESP_ERROR_CHECK(gpio_config(&tx_left_enable_gpio_config)); + KLOG_INFO(TAG, "Initialized left IR Tx enable as GPIO[%d].", IR_TX_LEFT_ENABLE); + + ESP_ERROR_CHECK(rmt_new_copy_encoder(&Copy_Encoder_Config, &Tx_Encoder)); + + KLOG_INFO(TAG, "Creating RMT Rx channels..."); + rmt_rx_channel_config_t rx_left_channel_cfg = { + .gpio_num = IR_RX_LEFT_PIN, // GPIO number used by RMT RX channel. Set to -1 if unused. + .clk_src = RMT_CLK_SRC_XTAL, // Clock source of RMT RX channel; channels in the same group must use the same clock source. + .resolution_hz = IR_RESOLUTION_HZ, // Channel clock resolution, in Hz. + .mem_block_symbols = 48, // Size of memory block, in number of `rmt_symbol_word_t`, must be an even. + // In the DMA mode, this field controls the DMA buffer size, it can be set to a large value (e.g. 1024); + // In the normal mode, this field controls the number of RMT memory block that will be used by the channel. + .flags.invert_in = true, // Should the incoming signal be inverted before processing? + .flags.with_dma = false, // Should this channel use the DMA backend? + .flags.io_loop_back = false, // Should the signal output from the GPIO be fed to the input path as well? + .intr_priority = 1 // RMT interrupt priority. If set to 0 , then the driver will use a interrupt with low or medium priority (priority level may be one of 1, 2, or 3). + }; + ESP_ERROR_CHECK(rmt_new_rx_channel(&rx_left_channel_cfg, &Left_Rx_Channel)); + + rmt_rx_channel_config_t rx_forward_channel_cfg = { + .gpio_num = IR_RX_FORWARD_PIN, // GPIO number used by RMT RX channel. Set to -1 if unused. + .clk_src = RMT_CLK_SRC_XTAL, // Clock source of RMT RX channel; channels in the same group must use the same clock source. + .resolution_hz = IR_RESOLUTION_HZ, // Channel clock resolution, in Hz. + .mem_block_symbols = 48, // Size of memory block, in number of `rmt_symbol_word_t`, must be an even. + // In the DMA mode, this field controls the DMA buffer size, it can be set to a large value (e.g. 1024); + // In the normal mode, this field controls the number of RMT memory block that will be used by the channel. + .flags.invert_in = true, // Should the incoming signal be inverted before processing? + .flags.with_dma = false, // Should this channel use the DMA backend? + .flags.io_loop_back = false, // Should the signal output from the GPIO be fed to the input path as well? + .intr_priority = 1 // RMT interrupt priority. If set to 0 , then the driver will use a interrupt with low or medium priority (priority level may be one of 1, 2, or 3). + }; + ESP_ERROR_CHECK(rmt_new_rx_channel(&rx_forward_channel_cfg, &Forward_Rx_Channel)); + + rmt_rx_channel_config_t rx_right_channel_cfg = { + .gpio_num = IR_RX_RIGHT_PIN, // GPIO number used by RMT RX channel. Set to -1 if unused. + .clk_src = RMT_CLK_SRC_XTAL, // Clock source of RMT RX channel; channels in the same group must use the same clock source. + .resolution_hz = IR_RESOLUTION_HZ, // Channel clock resolution, in Hz. + .mem_block_symbols = 48, // Size of memory block, in number of `rmt_symbol_word_t`, must be an even. + // In the DMA mode, this field controls the DMA buffer size, it can be set to a large value (e.g. 1024); + // In the normal mode, this field controls the number of RMT memory block that will be used by the channel. + .flags.invert_in = true, // Should the incoming signal be inverted before processing? + .flags.with_dma = false, // Should this channel use the DMA backend? + .flags.io_loop_back = false, // Should the signal output from the GPIO be fed to the input path as well? + .intr_priority = 1 // RMT interrupt priority. If set to 0 , then the driver will use a interrupt with low or medium priority (priority level may be one of 1, 2, or 3). + }; + ESP_ERROR_CHECK(rmt_new_rx_channel(&rx_right_channel_cfg, &Right_Rx_Channel)); + + ESP_LOGI(TAG, "register RX done callbacks"); + Receive_Queue = xQueueCreate(1, sizeof(RxNotification_T)); + assert(Receive_Queue); + + ESP_ERROR_CHECK(rmt_rx_register_event_callbacks(Left_Rx_Channel, &left_cbs, 0)); + ESP_ERROR_CHECK(rmt_rx_register_event_callbacks(Forward_Rx_Channel, &forward_cbs, 0)); + ESP_ERROR_CHECK(rmt_rx_register_event_callbacks(Right_Rx_Channel, &right_cbs, 0)); + + Initialize_Receive_Task(); + + Left_Rxd_RMT_Data.receiver = TAG_SENSOR_LEFT; + Forward_Rxd_RMT_Data.receiver = TAG_SENSOR_FORWARD; + Right_Rxd_RMT_Data.receiver = TAG_SENSOR_RIGHT; + + ESP_ERROR_CHECK(rmt_enable(Left_Rx_Channel)); + ESP_ERROR_CHECK(rmt_receive(Left_Rx_Channel, &Left_Rxd_RMT_Data, sizeof(Left_Rxd_RMT_Data.pulsetrain), &Rx_Config)); + + ESP_ERROR_CHECK(rmt_enable(Forward_Rx_Channel)); + ESP_ERROR_CHECK(rmt_receive(Forward_Rx_Channel, &Forward_Rxd_RMT_Data, sizeof(Forward_Rxd_RMT_Data.pulsetrain), &Rx_Config)); + + ESP_ERROR_CHECK(rmt_enable(Right_Rx_Channel)); + ESP_ERROR_CHECK(rmt_receive(Right_Rx_Channel, &Right_Rxd_RMT_Data, sizeof(Right_Rxd_RMT_Data.pulsetrain), &Rx_Config)); + + xSemaphoreGive(init_complete); +} + +static inline void PrintPulseTrainToConsole(TimedPulseTrain_T *train) +{ + for (uint_fast16_t i = 0; i < train->count; i += 2) + { + KLOG_INFO(TAG, "%2d: (%d, %4d) (%d, %4d)", i + 1, train->bitstream[i].symbol, train->bitstream[i].duration, train->bitstream[i + 1].symbol, train->bitstream[i + 1].duration); + vTaskDelay(pdMS_TO_TICKS(10)); + } +} + +SystemKResult_T Prepare_Tag(void) +{ + TimedPulseTrain_T *Shot_Buffer; + + uint8_t team_ID; + uint8_t player_ID; + uint8_t weapon_ID; + + (void)SETTINGS_get_uint8_t(SYSTEMK_SETTING_TEAMID, &team_ID); + (void)SETTINGS_get_uint8_t(SYSTEMK_SETTING_PLAYERID, &player_ID); + (void)SETTINGS_get_uint8_t(SYSTEMK_SETTING_WEAPONID, &weapon_ID); + Weapon_t weapon = GetWeaponFromID(weapon_ID); + + Shot_Packet.player_ID = player_ID; + Shot_Packet.team_ID = team_ID; + Shot_Packet.color = (uint32_t)PROTOCOLS_GetColor(weapon.Protocol, team_ID, player_ID); + Shot_Packet.protocol = weapon.Protocol; + Shot_Packet.damage = weapon.Damage_Per_Shot; + + Shot_Buffer = PROTOCOLS_EncodePacket(&Shot_Packet); + + KLOG_INFO(TAG, "Tag prepared (%u pulses):", Shot_Buffer->count); + PrintPulseTrainToConsole(Shot_Buffer); + + gpio_set_level(IR_TX_RIGHT_ENABLE, 0); + gpio_set_level(IR_TX_LEFT_ENABLE, 0); + + return SYSTEMK_RESULT_SUCCESS; +} + +SystemKResult_T Send_Tag(void) +{ + TimedPulseTrain_T *Shot_Buffer; + + Shot_Buffer = PROTOCOLS_EncodePacket(&Shot_Packet); + + ESP_ERROR_CHECK(rmt_transmit(Tx_Channel, Tx_Encoder, Shot_Buffer->pulsetrain, sizeof(rmt_symbol_word_t) * Shot_Buffer->count, &Tx_Config)); + + KEvent_T tag_sent_event = {.ID = KEVENT_TAG_SENT, .Data = (void *)0x00}; + Post_KEvent(&tag_sent_event); + + return SYSTEMK_RESULT_SUCCESS; +} diff --git a/components/IR/IR.h b/components/IR/IR.h new file mode 100644 index 0000000..c1f0132 --- /dev/null +++ b/components/IR/IR.h @@ -0,0 +1,3 @@ +#include "esp_err.h" + +void Initialize_IR(SemaphoreHandle_t init_complete); \ No newline at end of file diff --git a/components/MuxedLedStrip/CHANGELOG.md b/components/MuxedLedStrip/CHANGELOG.md new file mode 100644 index 0000000..51c0cd3 --- /dev/null +++ b/components/MuxedLedStrip/CHANGELOG.md @@ -0,0 +1,38 @@ +## 2.5.0 + +- Enabled support for IDF4.4 and above + - with RMT backend only +- Added API `led_strip_set_pixel_hsv` + +## 2.4.0 + +- Support configurable SPI mode to control leds + - recommend enabling DMA when using SPI mode + +## 2.3.0 + +- Support configurable RMT channel size by setting `mem_block_symbols` + +## 2.2.0 + +- Support for 4 components RGBW leds (SK6812): + - in led_strip_config_t new fields + led_pixel_format, controlling byte format (LED_PIXEL_FORMAT_GRB, LED_PIXEL_FORMAT_GRBW) + led_model, used to configure bit timing (LED_MODEL_WS2812, LED_MODEL_SK6812) + - new API led_strip_set_pixel_rgbw + - new interface type set_pixel_rgbw + +## 2.1.0 + +- Support DMA feature, which offloads the CPU by a lot when it comes to drive a bunch of LEDs +- Support various RMT clock sources +- Acquire and release the power management lock before and after each refresh +- New driver flag: `invert_out` which can invert the led control signal by hardware + +## 2.0.0 + +- Reimplemented the driver using the new RMT driver (`driver/rmt_tx.h`) + +## 1.0.0 + +- Initial driver version, based on the legacy RMT driver (`driver/rmt.h`) diff --git a/components/MuxedLedStrip/CMakeLists.txt b/components/MuxedLedStrip/CMakeLists.txt new file mode 100644 index 0000000..8314399 --- /dev/null +++ b/components/MuxedLedStrip/CMakeLists.txt @@ -0,0 +1,22 @@ +include($ENV{IDF_PATH}/tools/cmake/version.cmake) + +set(srcs "src/led_strip_api.c" "src/muxed_led_strip_api.c") + +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + if(CONFIG_SOC_RMT_SUPPORTED) + list(APPEND srcs "src/led_strip_rmt_dev.c" "src/muxed_led_strip_rmt_dev.c" "src/led_strip_rmt_encoder.c") + endif() +else() + list(APPEND srcs "src/led_strip_rmt_dev_idf4.c") +endif() + +# the SPI backend driver relies on something that was added in IDF 5.1 +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.1") + if(CONFIG_SOC_GPSPI_SUPPORTED) + list(APPEND srcs "src/led_strip_spi_dev.c") + endif() +endif() + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS "include" "interface" + REQUIRES "driver") diff --git a/components/MuxedLedStrip/LICENSE b/components/MuxedLedStrip/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/components/MuxedLedStrip/LICENSE @@ -0,0 +1,202 @@ + + 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 [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 + + 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. diff --git a/components/MuxedLedStrip/README.md b/components/MuxedLedStrip/README.md new file mode 100644 index 0000000..bb08cca --- /dev/null +++ b/components/MuxedLedStrip/README.md @@ -0,0 +1,97 @@ +# LED Strip Driver + +[![Component Registry](https://components.espressif.com/components/espressif/led_strip/badge.svg)](https://components.espressif.com/components/espressif/led_strip) + +This driver is designed for addressable LEDs like [WS2812](http://www.world-semi.com/Certifications/WS2812B.html), where each LED is controlled by a single data line. + +## Backend Controllers + +### The [RMT](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/rmt.html) Peripheral + +This is the most economical way to drive the LEDs because it only consumes one RMT channel, leaving other channels free to use. However, the memory usage increases dramatically with the number of LEDs. If the RMT hardware can't be assist by DMA, the driver will going into interrupt very frequently, thus result in a high CPU usage. What's worse, if the RMT interrupt is delayed or not serviced in time (e.g. if Wi-Fi interrupt happens on the same CPU core), the RMT transaction will be corrupted and the LEDs will display incorrect colors. If you want to use RMT to drive a large number of LEDs, you'd better to enable the DMA feature if possible [^1]. + +#### Allocate LED Strip Object with RMT Backend + +```c +#define BLINK_GPIO 0 + +led_strip_handle_t led_strip; + +/* LED strip initialization with the GPIO and pixels number*/ +led_strip_config_t strip_config = { + .strip_gpio_num = BLINK_GPIO, // The GPIO that connected to the LED strip's data line + .max_leds = 1, // The number of LEDs in the strip, + .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip + .led_model = LED_MODEL_WS2812, // LED strip model + .flags.invert_out = false, // whether to invert the output signal (useful when your hardware has a level inverter) +}; + +led_strip_rmt_config_t rmt_config = { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) + .rmt_channel = 0, +#else + .clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption + .resolution_hz = 10 * 1000 * 1000, // 10MHz + .flags.with_dma = false, // whether to enable the DMA feature +#endif +}; +ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); +``` + +You can create multiple LED strip objects with different GPIOs and pixel numbers. The backend driver will automatically allocate the RMT channel for you if there is more available. + +### The [SPI](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_master.html) Peripheral + +SPI peripheral can also be used to generate the timing required by the LED strip. However this backend is not as economical as the RMT one, because it will take up the whole **bus**, unlike the RMT just takes one **channel**. You **CANT** connect other devices to the same SPI bus if it's been used by the led_strip, because the led_strip doesn't have the concept of "Chip Select". + +Please note, the SPI backend has a dependency of **ESP-IDF >= 5.1** + +#### Allocate LED Strip Object with SPI Backend + +```c +#define BLINK_GPIO 0 + +led_strip_handle_t led_strip; + +/* LED strip initialization with the GPIO and pixels number*/ +led_strip_config_t strip_config = { + .strip_gpio_num = BLINK_GPIO, // The GPIO that connected to the LED strip's data line + .max_leds = 1, // The number of LEDs in the strip, + .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip + .led_model = LED_MODEL_WS2812, // LED strip model + .flags.invert_out = false, // whether to invert the output signal (useful when your hardware has a level inverter) +}; + +led_strip_spi_config_t spi_config = { + .clk_src = SPI_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption + .flags.with_dma = true, // Using DMA can improve performance and help drive more LEDs + .spi_bus = SPI2_HOST, // SPI bus ID +}; +ESP_ERROR_CHECK(led_strip_new_spi_device(&strip_config, &spi_config, &led_strip)); +``` + +The number of LED strip objects can be created depends on how many free SPI buses are free to use in your project. + +## FAQ + +* Which led_strip backend should I choose? + * It depends on your application requirement and target chip's ability. + + ```mermaid + flowchart LR + A{Is RMT supported?} + A --> |No| B[SPI backend] + B --> C{Does the led strip has \n a larger number of LEDs?} + C --> |No| D[Don't have to enable the DMA of the backend] + C --> |Yes| E[Enable the DMA of the backend] + A --> |Yes| F{Does the led strip has \n a larger number of LEDs?} + F --> |Yes| G{Does RMT support DMA?} + G --> |Yes| E + G --> |No| B + F --> |No| H[RMT backend] --> D + ``` + +* How to set the brightness of the LED strip? + * You can tune the brightness by scaling the value of each R-G-B element with a **same** factor. But pay attention to the overflow of the value. + +[^1]: The RMT DMA feature is not available on all ESP chips. Please check the data sheet before using it. diff --git a/components/MuxedLedStrip/api.md b/components/MuxedLedStrip/api.md new file mode 100644 index 0000000..6581d66 --- /dev/null +++ b/components/MuxedLedStrip/api.md @@ -0,0 +1,454 @@ +# API Reference + +## Header files + +- [include/led_strip.h](#file-includeled_striph) +- [include/led_strip_rmt.h](#file-includeled_strip_rmth) +- [include/led_strip_spi.h](#file-includeled_strip_spih) +- [include/led_strip_types.h](#file-includeled_strip_typesh) +- [interface/led_strip_interface.h](#file-interfaceled_strip_interfaceh) + +## File include/led_strip.h + +## Functions + +| Type | Name | +| ---: | :--- | +| esp\_err\_t | [**led\_strip\_clear**](#function-led_strip_clear) ([**led\_strip\_handle\_t**](#struct-led_strip_t) strip)
_Clear LED strip (turn off all LEDs)_ | +| esp\_err\_t | [**led\_strip\_del**](#function-led_strip_del) ([**led\_strip\_handle\_t**](#struct-led_strip_t) strip)
_Free LED strip resources._ | +| esp\_err\_t | [**led\_strip\_refresh**](#function-led_strip_refresh) ([**led\_strip\_handle\_t**](#struct-led_strip_t) strip)
_Refresh memory colors to LEDs._ | +| esp\_err\_t | [**led\_strip\_set\_pixel**](#function-led_strip_set_pixel) ([**led\_strip\_handle\_t**](#struct-led_strip_t) strip, uint32\_t index, uint32\_t red, uint32\_t green, uint32\_t blue)
_Set RGB for a specific pixel._ | +| esp\_err\_t | [**led\_strip\_set\_pixel\_hsv**](#function-led_strip_set_pixel_hsv) ([**led\_strip\_handle\_t**](#struct-led_strip_t) strip, uint32\_t index, uint16\_t hue, uint8\_t saturation, uint8\_t value)
_Set HSV for a specific pixel._ | +| esp\_err\_t | [**led\_strip\_set\_pixel\_rgbw**](#function-led_strip_set_pixel_rgbw) ([**led\_strip\_handle\_t**](#struct-led_strip_t) strip, uint32\_t index, uint32\_t red, uint32\_t green, uint32\_t blue, uint32\_t white)
_Set RGBW for a specific pixel._ | + +## Functions Documentation + +### function `led_strip_clear` + +_Clear LED strip (turn off all LEDs)_ + +```c +esp_err_t led_strip_clear ( + led_strip_handle_t strip +) +``` + +**Parameters:** + +- `strip` LED strip + +**Returns:** + +- ESP\_OK: Clear LEDs successfully +- ESP\_FAIL: Clear LEDs failed because some other error occurred + +### function `led_strip_del` + +_Free LED strip resources._ + +```c +esp_err_t led_strip_del ( + led_strip_handle_t strip +) +``` + +**Parameters:** + +- `strip` LED strip + +**Returns:** + +- ESP\_OK: Free resources successfully +- ESP\_FAIL: Free resources failed because error occurred + +### function `led_strip_refresh` + +_Refresh memory colors to LEDs._ + +```c +esp_err_t led_strip_refresh ( + led_strip_handle_t strip +) +``` + +**Parameters:** + +- `strip` LED strip + +**Returns:** + +- ESP\_OK: Refresh successfully +- ESP\_FAIL: Refresh failed because some other error occurred + +**Note:** + +: After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip. + +### function `led_strip_set_pixel` + +_Set RGB for a specific pixel._ + +```c +esp_err_t led_strip_set_pixel ( + led_strip_handle_t strip, + uint32_t index, + uint32_t red, + uint32_t green, + uint32_t blue +) +``` + +**Parameters:** + +- `strip` LED strip +- `index` index of pixel to set +- `red` red part of color +- `green` green part of color +- `blue` blue part of color + +**Returns:** + +- ESP\_OK: Set RGB for a specific pixel successfully +- ESP\_ERR\_INVALID\_ARG: Set RGB for a specific pixel failed because of invalid parameters +- ESP\_FAIL: Set RGB for a specific pixel failed because other error occurred + +### function `led_strip_set_pixel_hsv` + +_Set HSV for a specific pixel._ + +```c +esp_err_t led_strip_set_pixel_hsv ( + led_strip_handle_t strip, + uint32_t index, + uint16_t hue, + uint8_t saturation, + uint8_t value +) +``` + +**Parameters:** + +- `strip` LED strip +- `index` index of pixel to set +- `hue` hue part of color (0 - 360) +- `saturation` saturation part of color (0 - 255) +- `value` value part of color (0 - 255) + +**Returns:** + +- ESP\_OK: Set HSV color for a specific pixel successfully +- ESP\_ERR\_INVALID\_ARG: Set HSV color for a specific pixel failed because of an invalid argument +- ESP\_FAIL: Set HSV color for a specific pixel failed because other error occurred + +### function `led_strip_set_pixel_rgbw` + +_Set RGBW for a specific pixel._ + +```c +esp_err_t led_strip_set_pixel_rgbw ( + led_strip_handle_t strip, + uint32_t index, + uint32_t red, + uint32_t green, + uint32_t blue, + uint32_t white +) +``` + +**Note:** + +Only call this function if your led strip does have the white component (e.g. SK6812-RGBW) + +**Note:** + +Also see `led_strip_set_pixel` if you only want to specify the RGB part of the color and bypass the white component + +**Parameters:** + +- `strip` LED strip +- `index` index of pixel to set +- `red` red part of color +- `green` green part of color +- `blue` blue part of color +- `white` separate white component + +**Returns:** + +- ESP\_OK: Set RGBW color for a specific pixel successfully +- ESP\_ERR\_INVALID\_ARG: Set RGBW color for a specific pixel failed because of an invalid argument +- ESP\_FAIL: Set RGBW color for a specific pixel failed because other error occurred + +## File include/led_strip_rmt.h + +## Structures and Types + +| Type | Name | +| ---: | :--- | +| struct | [**led\_strip\_rmt\_config\_t**](#struct-led_strip_rmt_config_t)
_LED Strip RMT specific configuration._ | + +## Functions + +| Type | Name | +| ---: | :--- | +| esp\_err\_t | [**led\_strip\_new\_rmt\_device**](#function-led_strip_new_rmt_device) (const [**led\_strip\_config\_t**](#struct-led_strip_config_t) \*led\_config, const [**led\_strip\_rmt\_config\_t**](#struct-led_strip_rmt_config_t) \*rmt\_config, [**led\_strip\_handle\_t**](#struct-led_strip_t) \*ret\_strip)
_Create LED strip based on RMT TX channel._ | + +## Structures and Types Documentation + +### struct `led_strip_rmt_config_t` + +_LED Strip RMT specific configuration._ + +Variables: + +- rmt\_clock\_source\_t clk_src
RMT clock source + +- struct [**led\_strip\_rmt\_config\_t**](#struct-led_strip_rmt_config_t) flags
Extra driver flags + +- size\_t mem_block_symbols
How many RMT symbols can one RMT channel hold at one time. Set to 0 will fallback to use the default size. + +- uint32\_t resolution_hz
RMT tick resolution, if set to zero, a default resolution (10MHz) will be applied + +- uint32\_t with_dma
Use DMA to transmit data + +## Functions Documentation + +### function `led_strip_new_rmt_device` + +_Create LED strip based on RMT TX channel._ + +```c +esp_err_t led_strip_new_rmt_device ( + const led_strip_config_t *led_config, + const led_strip_rmt_config_t *rmt_config, + led_strip_handle_t *ret_strip +) +``` + +**Parameters:** + +- `led_config` LED strip configuration +- `rmt_config` RMT specific configuration +- `ret_strip` Returned LED strip handle + +**Returns:** + +- ESP\_OK: create LED strip handle successfully +- ESP\_ERR\_INVALID\_ARG: create LED strip handle failed because of invalid argument +- ESP\_ERR\_NO\_MEM: create LED strip handle failed because of out of memory +- ESP\_FAIL: create LED strip handle failed because some other error + +## File include/led_strip_spi.h + +## Structures and Types + +| Type | Name | +| ---: | :--- | +| struct | [**led\_strip\_spi\_config\_t**](#struct-led_strip_spi_config_t)
_LED Strip SPI specific configuration._ | + +## Functions + +| Type | Name | +| ---: | :--- | +| esp\_err\_t | [**led\_strip\_new\_spi\_device**](#function-led_strip_new_spi_device) (const [**led\_strip\_config\_t**](#struct-led_strip_config_t) \*led\_config, const [**led\_strip\_spi\_config\_t**](#struct-led_strip_spi_config_t) \*spi\_config, [**led\_strip\_handle\_t**](#struct-led_strip_t) \*ret\_strip)
_Create LED strip based on SPI MOSI channel._ | + +## Structures and Types Documentation + +### struct `led_strip_spi_config_t` + +_LED Strip SPI specific configuration._ + +Variables: + +- spi\_clock\_source\_t clk_src
SPI clock source + +- struct [**led\_strip\_spi\_config\_t**](#struct-led_strip_spi_config_t) flags
Extra driver flags + +- spi\_host\_device\_t spi_bus
SPI bus ID. Which buses are available depends on the specific chip + +- uint32\_t with_dma
Use DMA to transmit data + +## Functions Documentation + +### function `led_strip_new_spi_device` + +_Create LED strip based on SPI MOSI channel._ + +```c +esp_err_t led_strip_new_spi_device ( + const led_strip_config_t *led_config, + const led_strip_spi_config_t *spi_config, + led_strip_handle_t *ret_strip +) +``` + +**Note:** + +Although only the MOSI line is used for generating the signal, the whole SPI bus can't be used for other purposes. + +**Parameters:** + +- `led_config` LED strip configuration +- `spi_config` SPI specific configuration +- `ret_strip` Returned LED strip handle + +**Returns:** + +- ESP\_OK: create LED strip handle successfully +- ESP\_ERR\_INVALID\_ARG: create LED strip handle failed because of invalid argument +- ESP\_ERR\_NOT\_SUPPORTED: create LED strip handle failed because of unsupported configuration +- ESP\_ERR\_NO\_MEM: create LED strip handle failed because of out of memory +- ESP\_FAIL: create LED strip handle failed because some other error + +## File include/led_strip_types.h + +## Structures and Types + +| Type | Name | +| ---: | :--- | +| enum | [**led\_model\_t**](#enum-led_model_t)
_LED strip model._ | +| enum | [**led\_pixel\_format\_t**](#enum-led_pixel_format_t)
_LED strip pixel format._ | +| struct | [**led\_strip\_config\_t**](#struct-led_strip_config_t)
_LED Strip Configuration._ | +| typedef struct [**led\_strip\_t**](#struct-led_strip_t) \* | [**led\_strip\_handle\_t**](#typedef-led_strip_handle_t)
_LED strip handle._ | + +## Structures and Types Documentation + +### enum `led_model_t` + +_LED strip model._ + +```c +enum led_model_t { + LED_MODEL_WS2812, + LED_MODEL_SK6812, + LED_MODEL_INVALID +}; +``` + +**Note:** + +Different led model may have different timing parameters, so we need to distinguish them. + +### enum `led_pixel_format_t` + +_LED strip pixel format._ + +```c +enum led_pixel_format_t { + LED_PIXEL_FORMAT_GRB, + LED_PIXEL_FORMAT_GRBW, + LED_PIXEL_FORMAT_INVALID +}; +``` + +### struct `led_strip_config_t` + +_LED Strip Configuration._ + +Variables: + +- struct [**led\_strip\_config\_t**](#struct-led_strip_config_t) flags
Extra driver flags + +- uint32\_t invert_out
Invert output signal + +- led\_model\_t led_model
LED model + +- led\_pixel\_format\_t led_pixel_format
LED pixel format + +- uint32\_t max_leds
Maximum LEDs in a single strip + +- int strip_gpio_num
GPIO number that used by LED strip + +### typedef `led_strip_handle_t` + +_LED strip handle._ + +```c +typedef struct led_strip_t* led_strip_handle_t; +``` + +## File interface/led_strip_interface.h + +## Structures and Types + +| Type | Name | +| ---: | :--- | +| struct | [**led\_strip\_t**](#struct-led_strip_t)
_LED strip interface definition._ | +| typedef struct [**led\_strip\_t**](#struct-led_strip_t) | [**led\_strip\_t**](#typedef-led_strip_t)
| + +## Structures and Types Documentation + +### struct `led_strip_t` + +_LED strip interface definition._ + +Variables: + +- esp\_err\_t(\* clear
_Clear LED strip (turn off all LEDs)_
**Parameters:** + +- `strip` LED strip +- `timeout_ms` timeout value for clearing task + +**Returns:** + +- ESP\_OK: Clear LEDs successfully +- ESP\_FAIL: Clear LEDs failed because some other error occurred + +- esp\_err\_t(\* del
_Free LED strip resources._
**Parameters:** + +- `strip` LED strip + +**Returns:** + +- ESP\_OK: Free resources successfully +- ESP\_FAIL: Free resources failed because error occurred + +- esp\_err\_t(\* refresh
_Refresh memory colors to LEDs._
**Parameters:** + +- `strip` LED strip +- `timeout_ms` timeout value for refreshing task + +**Returns:** + +- ESP\_OK: Refresh successfully +- ESP\_FAIL: Refresh failed because some other error occurred + +**Note:** + +: After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip. + +- esp\_err\_t(\* set_pixel
_Set RGB for a specific pixel._
**Parameters:** + +- `strip` LED strip +- `index` index of pixel to set +- `red` red part of color +- `green` green part of color +- `blue` blue part of color + +**Returns:** + +- ESP\_OK: Set RGB for a specific pixel successfully +- ESP\_ERR\_INVALID\_ARG: Set RGB for a specific pixel failed because of invalid parameters +- ESP\_FAIL: Set RGB for a specific pixel failed because other error occurred + +- esp\_err\_t(\* set_pixel_rgbw
_Set RGBW for a specific pixel. Similar to_ `set_pixel`_but also set the white component._
**Parameters:** + +- `strip` LED strip +- `index` index of pixel to set +- `red` red part of color +- `green` green part of color +- `blue` blue part of color +- `white` separate white component + +**Returns:** + +- ESP\_OK: Set RGBW color for a specific pixel successfully +- ESP\_ERR\_INVALID\_ARG: Set RGBW color for a specific pixel failed because of an invalid argument +- ESP\_FAIL: Set RGBW color for a specific pixel failed because other error occurred + +### typedef `led_strip_t` + +```c +typedef struct led_strip_t led_strip_t; +``` + +Type of LED strip diff --git a/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/CMakeLists.txt b/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/CMakeLists.txt new file mode 100644 index 0000000..fc2dfc7 --- /dev/null +++ b/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(led_strip_rmt_ws2812) diff --git a/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/README.md b/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/README.md new file mode 100644 index 0000000..ad52235 --- /dev/null +++ b/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/README.md @@ -0,0 +1,31 @@ +# LED Strip Example (RMT backend + WS2812) + +This example demonstrates how to blink the WS2812 LED using the [led_strip](https://components.espressif.com/component/espressif/led_strip) component. + +## How to Use Example + +### Hardware Required + +* A development board with Espressif SoC +* A USB cable for Power supply and programming +* WS2812 LED strip + +### Configure the Example + +Before project configuration and build, be sure to set the correct chip target using `idf.py set-target `. Then assign the proper GPIO in the [source file](main/led_strip_rmt_ws2812_main.c). If your led strip has multiple LEDs, don't forget update the number. + +### Build and Flash + +Run `idf.py -p PORT build flash monitor` to build, flash and monitor the project. + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +```text +I (299) gpio: GPIO[8]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 +I (309) example: Created LED strip object with RMT backend +I (309) example: Start blinking LED strip +``` diff --git a/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/main/CMakeLists.txt b/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/main/CMakeLists.txt new file mode 100644 index 0000000..37b9c14 --- /dev/null +++ b/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "led_strip_rmt_ws2812_main.c" + INCLUDE_DIRS ".") diff --git a/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/main/idf_component.yml b/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/main/idf_component.yml new file mode 100644 index 0000000..916c366 --- /dev/null +++ b/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/main/idf_component.yml @@ -0,0 +1,5 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/led_strip: + version: '^2' + override_path: '../../../' diff --git a/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c b/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c new file mode 100644 index 0000000..5cae3f0 --- /dev/null +++ b/components/MuxedLedStrip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "led_strip.h" +#include "esp_log.h" +#include "esp_err.h" + +// GPIO assignment +#define LED_STRIP_BLINK_GPIO 2 +// Numbers of the LED in the strip +#define LED_STRIP_LED_NUMBERS 24 +// 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) +#define LED_STRIP_RMT_RES_HZ (10 * 1000 * 1000) + +static const char *TAG = "example"; + +led_strip_handle_t configure_led(void) +{ + // LED strip general initialization, according to your led board design + led_strip_config_t strip_config = { + .strip_gpio_num = LED_STRIP_BLINK_GPIO, // The GPIO that connected to the LED strip's data line + .max_leds = LED_STRIP_LED_NUMBERS, // The number of LEDs in the strip, + .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip + .led_model = LED_MODEL_WS2812, // LED strip model + .flags.invert_out = false, // whether to invert the output signal + }; + + // LED strip backend configuration: RMT + led_strip_rmt_config_t rmt_config = { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) + .rmt_channel = 0, +#else + .clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption + .resolution_hz = LED_STRIP_RMT_RES_HZ, // RMT counter clock frequency + .flags.with_dma = false, // DMA feature is available on ESP target like ESP32-S3 +#endif + }; + + // LED Strip object handle + led_strip_handle_t led_strip; + ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); + ESP_LOGI(TAG, "Created LED strip object with RMT backend"); + return led_strip; +} + +void app_main(void) +{ + led_strip_handle_t led_strip = configure_led(); + bool led_on_off = false; + + ESP_LOGI(TAG, "Start blinking LED strip"); + while (1) { + if (led_on_off) { + /* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */ + for (int i = 0; i < LED_STRIP_LED_NUMBERS; i++) { + ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, i, 5, 5, 5)); + } + /* Refresh the strip to send data */ + ESP_ERROR_CHECK(led_strip_refresh(led_strip)); + ESP_LOGI(TAG, "LED ON!"); + } else { + /* Set all LED off to clear all pixels */ + ESP_ERROR_CHECK(led_strip_clear(led_strip)); + ESP_LOGI(TAG, "LED OFF!"); + } + + led_on_off = !led_on_off; + vTaskDelay(pdMS_TO_TICKS(500)); + } +} diff --git a/components/MuxedLedStrip/examples/led_strip_spi_ws2812/CMakeLists.txt b/components/MuxedLedStrip/examples/led_strip_spi_ws2812/CMakeLists.txt new file mode 100644 index 0000000..7d3af2d --- /dev/null +++ b/components/MuxedLedStrip/examples/led_strip_spi_ws2812/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(led_strip_spi_ws2812) diff --git a/components/MuxedLedStrip/examples/led_strip_spi_ws2812/README.md b/components/MuxedLedStrip/examples/led_strip_spi_ws2812/README.md new file mode 100644 index 0000000..c545c84 --- /dev/null +++ b/components/MuxedLedStrip/examples/led_strip_spi_ws2812/README.md @@ -0,0 +1,31 @@ +# LED Strip Example (SPI backend + WS2812) + +This example demonstrates how to blink the WS2812 LED using the [led_strip](https://components.espressif.com/component/espressif/led_strip) component. + +## How to Use Example + +### Hardware Required + +* A development board with Espressif SoC +* A USB cable for Power supply and programming +* WS2812 LED strip + +### Configure the Example + +Before project configuration and build, be sure to set the correct chip target using `idf.py set-target `. Then assign the proper GPIO in the [source file](main/led_strip_spi_ws2812_main.c). If your led strip has multiple LEDs, don't forget update the number. + +### Build and Flash + +Run `idf.py -p PORT build flash monitor` to build, flash and monitor the project. + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +```text +I (299) gpio: GPIO[14]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 +I (309) example: Created LED strip object with SPI backend +I (309) example: Start blinking LED strip +``` diff --git a/components/MuxedLedStrip/examples/led_strip_spi_ws2812/main/CMakeLists.txt b/components/MuxedLedStrip/examples/led_strip_spi_ws2812/main/CMakeLists.txt new file mode 100644 index 0000000..5ad7dd5 --- /dev/null +++ b/components/MuxedLedStrip/examples/led_strip_spi_ws2812/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "led_strip_spi_ws2812_main.c" + INCLUDE_DIRS ".") diff --git a/components/MuxedLedStrip/examples/led_strip_spi_ws2812/main/idf_component.yml b/components/MuxedLedStrip/examples/led_strip_spi_ws2812/main/idf_component.yml new file mode 100644 index 0000000..050d8d2 --- /dev/null +++ b/components/MuxedLedStrip/examples/led_strip_spi_ws2812/main/idf_component.yml @@ -0,0 +1,6 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/led_strip: + version: '^2.4' + override_path: '../../../' + idf: ">=5.1" diff --git a/components/MuxedLedStrip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c b/components/MuxedLedStrip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c new file mode 100644 index 0000000..69b780c --- /dev/null +++ b/components/MuxedLedStrip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c @@ -0,0 +1,69 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "led_strip.h" +#include "esp_log.h" +#include "esp_err.h" + +// GPIO assignment +#define LED_STRIP_BLINK_GPIO 2 +// Numbers of the LED in the strip +#define LED_STRIP_LED_NUMBERS 24 + +static const char *TAG = "example"; + +led_strip_handle_t configure_led(void) +{ + // LED strip general initialization, according to your led board design + led_strip_config_t strip_config = { + .strip_gpio_num = LED_STRIP_BLINK_GPIO, // The GPIO that connected to the LED strip's data line + .max_leds = LED_STRIP_LED_NUMBERS, // The number of LEDs in the strip, + .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip + .led_model = LED_MODEL_WS2812, // LED strip model + .flags.invert_out = false, // whether to invert the output signal + }; + + // LED strip backend configuration: SPI + led_strip_spi_config_t spi_config = { + .clk_src = SPI_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption + .flags.with_dma = true, // Using DMA can improve performance and help drive more LEDs + .spi_bus = SPI2_HOST, // SPI bus ID + }; + + // LED Strip object handle + led_strip_handle_t led_strip; + ESP_ERROR_CHECK(led_strip_new_spi_device(&strip_config, &spi_config, &led_strip)); + ESP_LOGI(TAG, "Created LED strip object with SPI backend"); + return led_strip; +} + +void app_main(void) +{ + led_strip_handle_t led_strip = configure_led(); + bool led_on_off = false; + + ESP_LOGI(TAG, "Start blinking LED strip"); + while (1) { + if (led_on_off) { + /* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */ + for (int i = 0; i < LED_STRIP_LED_NUMBERS; i++) { + ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, i, 5, 5, 5)); + } + /* Refresh the strip to send data */ + ESP_ERROR_CHECK(led_strip_refresh(led_strip)); + ESP_LOGI(TAG, "LED ON!"); + } else { + /* Set all LED off to clear all pixels */ + ESP_ERROR_CHECK(led_strip_clear(led_strip)); + ESP_LOGI(TAG, "LED OFF!"); + } + + led_on_off = !led_on_off; + vTaskDelay(pdMS_TO_TICKS(500)); + } +} diff --git a/components/MuxedLedStrip/idf_component.yml b/components/MuxedLedStrip/idf_component.yml new file mode 100644 index 0000000..0dfa145 --- /dev/null +++ b/components/MuxedLedStrip/idf_component.yml @@ -0,0 +1,6 @@ +dependencies: + idf: + version: '>=4.4' +description: Multiplexed Driver for Addressable LED Strip (WS2812, etc) +url: https://github.com/espressif/idf-extra-components/tree/master/led_strip +version: 2.5.3 diff --git a/components/MuxedLedStrip/include/led_strip.h b/components/MuxedLedStrip/include/led_strip.h new file mode 100644 index 0000000..3871174 --- /dev/null +++ b/components/MuxedLedStrip/include/led_strip.h @@ -0,0 +1,111 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "led_strip_rmt.h" +#include "esp_idf_version.h" + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0) +#include "led_strip_spi.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set RGB for a specific pixel + * + * @param strip: LED strip + * @param index: index of pixel to set + * @param red: red part of color + * @param green: green part of color + * @param blue: blue part of color + * + * @return + * - ESP_OK: Set RGB for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters + * - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred + */ +esp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue); + +/** + * @brief Set RGBW for a specific pixel + * + * @note Only call this function if your led strip does have the white component (e.g. SK6812-RGBW) + * @note Also see `led_strip_set_pixel` if you only want to specify the RGB part of the color and bypass the white component + * + * @param strip: LED strip + * @param index: index of pixel to set + * @param red: red part of color + * @param green: green part of color + * @param blue: blue part of color + * @param white: separate white component + * + * @return + * - ESP_OK: Set RGBW color for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set RGBW color for a specific pixel failed because of an invalid argument + * - ESP_FAIL: Set RGBW color for a specific pixel failed because other error occurred + */ +esp_err_t led_strip_set_pixel_rgbw(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white); + +/** + * @brief Set HSV for a specific pixel + * + * @param strip: LED strip + * @param index: index of pixel to set + * @param hue: hue part of color (0 - 360) + * @param saturation: saturation part of color (0 - 255) + * @param value: value part of color (0 - 255) + * + * @return + * - ESP_OK: Set HSV color for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set HSV color for a specific pixel failed because of an invalid argument + * - ESP_FAIL: Set HSV color for a specific pixel failed because other error occurred + */ +esp_err_t led_strip_set_pixel_hsv(led_strip_handle_t strip, uint32_t index, uint16_t hue, uint8_t saturation, uint8_t value); + +/** + * @brief Refresh memory colors to LEDs + * + * @param strip: LED strip + * + * @return + * - ESP_OK: Refresh successfully + * - ESP_FAIL: Refresh failed because some other error occurred + * + * @note: + * After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip. + */ +esp_err_t led_strip_refresh(led_strip_handle_t strip); + +/** + * @brief Clear LED strip (turn off all LEDs) + * + * @param strip: LED strip + * + * @return + * - ESP_OK: Clear LEDs successfully + * - ESP_FAIL: Clear LEDs failed because some other error occurred + */ +esp_err_t led_strip_clear(led_strip_handle_t strip); + +/** + * @brief Free LED strip resources + * + * @param strip: LED strip + * + * @return + * - ESP_OK: Free resources successfully + * - ESP_FAIL: Free resources failed because error occurred + */ +esp_err_t led_strip_del(led_strip_handle_t strip); + +#ifdef __cplusplus +} +#endif diff --git a/components/MuxedLedStrip/include/led_strip_rmt.h b/components/MuxedLedStrip/include/led_strip_rmt.h new file mode 100644 index 0000000..b575aea --- /dev/null +++ b/components/MuxedLedStrip/include/led_strip_rmt.h @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "led_strip_types.h" +#include "esp_idf_version.h" + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#include "driver/rmt_types.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief LED Strip RMT specific configuration + */ +typedef struct { +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) + uint8_t rmt_channel; /*!< Specify the channel number, the legacy RMT driver doesn't support channel allocator */ +#else // new driver supports specify the clock source and clock resolution + rmt_clock_source_t clk_src; /*!< RMT clock source */ + uint32_t resolution_hz; /*!< RMT tick resolution, if set to zero, a default resolution (10MHz) will be applied */ +#endif + size_t mem_block_symbols; /*!< How many RMT symbols can one RMT channel hold at one time. Set to 0 will fallback to use the default size. */ + struct { + uint32_t with_dma: 1; /*!< Use DMA to transmit data */ + } flags; /*!< Extra driver flags */ +} led_strip_rmt_config_t; + +/** + * @brief Create LED strip based on RMT TX channel + * + * @param led_config LED strip configuration + * @param rmt_config RMT specific configuration + * @param ret_strip Returned LED strip handle + * @return + * - ESP_OK: create LED strip handle successfully + * - ESP_ERR_INVALID_ARG: create LED strip handle failed because of invalid argument + * - ESP_ERR_NO_MEM: create LED strip handle failed because of out of memory + * - ESP_FAIL: create LED strip handle failed because some other error + */ +esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *rmt_config, led_strip_handle_t *ret_strip); + +#ifdef __cplusplus +} +#endif diff --git a/components/MuxedLedStrip/include/led_strip_spi.h b/components/MuxedLedStrip/include/led_strip_spi.h new file mode 100644 index 0000000..eb35249 --- /dev/null +++ b/components/MuxedLedStrip/include/led_strip_spi.h @@ -0,0 +1,46 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "driver/spi_master.h" +#include "led_strip_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief LED Strip SPI specific configuration + */ +typedef struct { + spi_clock_source_t clk_src; /*!< SPI clock source */ + spi_host_device_t spi_bus; /*!< SPI bus ID. Which buses are available depends on the specific chip */ + struct { + uint32_t with_dma: 1; /*!< Use DMA to transmit data */ + } flags; /*!< Extra driver flags */ +} led_strip_spi_config_t; + +/** + * @brief Create LED strip based on SPI MOSI channel + * @note Although only the MOSI line is used for generating the signal, the whole SPI bus can't be used for other purposes. + * + * @param led_config LED strip configuration + * @param spi_config SPI specific configuration + * @param ret_strip Returned LED strip handle + * @return + * - ESP_OK: create LED strip handle successfully + * - ESP_ERR_INVALID_ARG: create LED strip handle failed because of invalid argument + * - ESP_ERR_NOT_SUPPORTED: create LED strip handle failed because of unsupported configuration + * - ESP_ERR_NO_MEM: create LED strip handle failed because of out of memory + * - ESP_FAIL: create LED strip handle failed because some other error + */ +esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const led_strip_spi_config_t *spi_config, led_strip_handle_t *ret_strip); + +#ifdef __cplusplus +} +#endif diff --git a/components/MuxedLedStrip/include/led_strip_types.h b/components/MuxedLedStrip/include/led_strip_types.h new file mode 100644 index 0000000..691f0bc --- /dev/null +++ b/components/MuxedLedStrip/include/led_strip_types.h @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief LED strip pixel format + */ +typedef enum { + LED_PIXEL_FORMAT_GRB, /*!< Pixel format: GRB */ + LED_PIXEL_FORMAT_GRBW, /*!< Pixel format: GRBW */ + LED_PIXEL_FORMAT_INVALID /*!< Invalid pixel format */ +} led_pixel_format_t; + +/** + * @brief LED strip model + * @note Different led model may have different timing parameters, so we need to distinguish them. + */ +typedef enum { + LED_MODEL_WS2812, /*!< LED strip model: WS2812 */ + LED_MODEL_SK6812, /*!< LED strip model: SK6812 */ + LED_MODEL_INVALID /*!< Invalid LED strip model */ +} led_model_t; + +/** + * @brief LED strip handle + */ +typedef struct led_strip_t *led_strip_handle_t; + +/** + * @brief LED Strip Configuration + */ +typedef struct { + int strip_gpio_num; /*!< GPIO number that used by LED strip */ + uint32_t max_leds; /*!< Maximum LEDs in a single strip */ + led_pixel_format_t led_pixel_format; /*!< LED pixel format */ + led_model_t led_model; /*!< LED model */ + + struct { + uint32_t invert_out: 1; /*!< Invert output signal */ + } flags; /*!< Extra driver flags */ +} led_strip_config_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/MuxedLedStrip/include/muxed_led_strip.h b/components/MuxedLedStrip/include/muxed_led_strip.h new file mode 100644 index 0000000..3214634 --- /dev/null +++ b/components/MuxedLedStrip/include/muxed_led_strip.h @@ -0,0 +1,116 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "muxed_led_strip_rmt.h" +#include "esp_idf_version.h" + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0) +#include "led_strip_spi.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set RGB for a specific pixel + * + * @param strip: LED strip + * @param channel: channel of pixel to set + * @param index: index of pixel to set + * @param red: red part of color + * @param green: green part of color + * @param blue: blue part of color + * + * @return + * - ESP_OK: Set RGB for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters + * - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred + */ +esp_err_t muxed_led_strip_set_pixel(muxed_led_strip_handle_t strip, uint32_t channel, uint32_t index, uint32_t red, uint32_t green, uint32_t blue); + +/** + * @brief Set RGBW for a specific pixel + * + * @note Only call this function if your led strip does have the white component (e.g. SK6812-RGBW) + * @note Also see `led_strip_set_pixel` if you only want to specify the RGB part of the color and bypass the white component + * + * @param strip: LED strip + * @param channel: channel of pixel to set + * @param index: index of pixel to set + * @param red: red part of color + * @param green: green part of color + * @param blue: blue part of color + * @param white: separate white component + * + * @return + * - ESP_OK: Set RGBW color for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set RGBW color for a specific pixel failed because of an invalid argument + * - ESP_FAIL: Set RGBW color for a specific pixel failed because other error occurred + */ +esp_err_t muxed_led_strip_set_pixel_rgbw(muxed_led_strip_handle_t strip, uint32_t channel, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white); + +/** + * @brief Set HSV for a specific pixel + * + * @param strip: LED strip + * @param channel: channel of pixel to set + * @param index: index of pixel to set + * @param hue: hue part of color (0 - 360) + * @param saturation: saturation part of color (0 - 255) + * @param value: value part of color (0 - 255) + * + * @return + * - ESP_OK: Set HSV color for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set HSV color for a specific pixel failed because of an invalid argument + * - ESP_FAIL: Set HSV color for a specific pixel failed because other error occurred + */ +esp_err_t muxed_led_strip_set_pixel_hsv(muxed_led_strip_handle_t strip, uint32_t channel, uint32_t index, uint16_t hue, uint8_t saturation, uint8_t value); + +/** + * @brief Refresh memory colors to LEDs + * + * @param strip: LED strip + * @param channel: which channel to refresh + * + * @return + * - ESP_OK: Refresh successfully + * - ESP_FAIL: Refresh failed because some other error occurred + * + * @note: + * After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip. + */ +esp_err_t muxed_led_strip_refresh(muxed_led_strip_handle_t strip, uint32_t channel); + +/** + * @brief Clear LED strip (turn off all LEDs) + * + * @param strip: LED strip + * @param channel: which channel to clear + * + * @return + * - ESP_OK: Clear LEDs successfully + * - ESP_FAIL: Clear LEDs failed because some other error occurred + */ +esp_err_t muxed_led_strip_clear(muxed_led_strip_handle_t strip, uint32_t channel); + +/** + * @brief Free LED strip resources + * + * @param strip: LED strip + * + * @return + * - ESP_OK: Free resources successfully + * - ESP_FAIL: Free resources failed because error occurred + */ +esp_err_t muxed_led_strip_del(muxed_led_strip_handle_t strip); + +#ifdef __cplusplus +} +#endif diff --git a/components/MuxedLedStrip/include/muxed_led_strip_rmt.h b/components/MuxedLedStrip/include/muxed_led_strip_rmt.h new file mode 100644 index 0000000..1ca2522 --- /dev/null +++ b/components/MuxedLedStrip/include/muxed_led_strip_rmt.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "led_strip_types.h" +#include "muxed_led_strip_types.h" +#include "led_strip_rmt.h" +#include "esp_idf_version.h" +#include + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#include "driver/rmt_types.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Create multiplexed LED strip based on RMT TX channel + * + * @param led_config LED strip configuration + * @param rmt_config RMT specific configuration + * @param cbs Group of RMT TX callback functions + * @param ret_strip Returned LED strip handle + * @return + * - ESP_OK: create LED strip handle successfully + * - ESP_ERR_INVALID_ARG: create LED strip handle failed because of invalid argument + * - ESP_ERR_NO_MEM: create LED strip handle failed because of out of memory + * - ESP_FAIL: create LED strip handle failed because some other error + */ +esp_err_t muxed_led_strip_new_rmt_device(const muxed_led_strip_config_t *led_config, const led_strip_rmt_config_t *rmt_config, const rmt_tx_event_callbacks_t *cbs, muxed_led_strip_handle_t *ret_strip); + +#ifdef __cplusplus +} +#endif diff --git a/components/MuxedLedStrip/include/muxed_led_strip_types.h b/components/MuxedLedStrip/include/muxed_led_strip_types.h new file mode 100644 index 0000000..efb1e0b --- /dev/null +++ b/components/MuxedLedStrip/include/muxed_led_strip_types.h @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Multiplexed LED strip handle + */ +typedef struct muxed_led_strip_t *muxed_led_strip_handle_t; + +/** + * @brief LED Strip Configuration + */ +typedef struct { + int strip_gpio_num; /*!< GPIO number that used by LED strip */ + uint32_t channels; /*!< Number of multiplexed channels */ + uint32_t max_leds; /*!< Maximum LEDs in a single strip */ + led_pixel_format_t led_pixel_format; /*!< LED pixel format */ + led_model_t led_model; /*!< LED model */ + + struct { + uint32_t invert_out: 1; /*!< Invert output signal */ + } flags; /*!< Extra driver flags */ +} muxed_led_strip_config_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/MuxedLedStrip/interface/led_strip_interface.h b/components/MuxedLedStrip/interface/led_strip_interface.h new file mode 100644 index 0000000..3de4c27 --- /dev/null +++ b/components/MuxedLedStrip/interface/led_strip_interface.h @@ -0,0 +1,95 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct led_strip_t led_strip_t; /*!< Type of LED strip */ + +/** + * @brief LED strip interface definition + */ +struct led_strip_t { + /** + * @brief Set RGB for a specific pixel + * + * @param strip: LED strip + * @param index: index of pixel to set + * @param red: red part of color + * @param green: green part of color + * @param blue: blue part of color + * + * @return + * - ESP_OK: Set RGB for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters + * - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred + */ + esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue); + + /** + * @brief Set RGBW for a specific pixel. Similar to `set_pixel` but also set the white component + * + * @param strip: LED strip + * @param index: index of pixel to set + * @param red: red part of color + * @param green: green part of color + * @param blue: blue part of color + * @param white: separate white component + * + * @return + * - ESP_OK: Set RGBW color for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set RGBW color for a specific pixel failed because of an invalid argument + * - ESP_FAIL: Set RGBW color for a specific pixel failed because other error occurred + */ + esp_err_t (*set_pixel_rgbw)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white); + + /** + * @brief Refresh memory colors to LEDs + * + * @param strip: LED strip + * @param timeout_ms: timeout value for refreshing task + * + * @return + * - ESP_OK: Refresh successfully + * - ESP_FAIL: Refresh failed because some other error occurred + * + * @note: + * After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip. + */ + esp_err_t (*refresh)(led_strip_t *strip); + + /** + * @brief Clear LED strip (turn off all LEDs) + * + * @param strip: LED strip + * @param timeout_ms: timeout value for clearing task + * + * @return + * - ESP_OK: Clear LEDs successfully + * - ESP_FAIL: Clear LEDs failed because some other error occurred + */ + esp_err_t (*clear)(led_strip_t *strip); + + /** + * @brief Free LED strip resources + * + * @param strip: LED strip + * + * @return + * - ESP_OK: Free resources successfully + * - ESP_FAIL: Free resources failed because error occurred + */ + esp_err_t (*del)(led_strip_t *strip); +}; + +#ifdef __cplusplus +} +#endif diff --git a/components/MuxedLedStrip/interface/muxed_led_strip_interface.h b/components/MuxedLedStrip/interface/muxed_led_strip_interface.h new file mode 100644 index 0000000..a70399a --- /dev/null +++ b/components/MuxedLedStrip/interface/muxed_led_strip_interface.h @@ -0,0 +1,97 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct muxed_led_strip_t muxed_led_strip_t; /*!< Type of LED strip */ + +/** + * @brief LED strip interface definition + */ +struct muxed_led_strip_t { + /** + * @brief Set RGB for a specific pixel + * + * @param strip: LED strip + * @param channel: channel of pixel to set + * @param index: index of pixel to set + * @param red: red part of color + * @param green: green part of color + * @param blue: blue part of color + * + * @return + * - ESP_OK: Set RGB for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters + * - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred + */ + esp_err_t (*set_pixel)(muxed_led_strip_t *strip, uint32_t channel, uint32_t index, uint32_t red, uint32_t green, uint32_t blue); + + /** + * @brief Set RGBW for a specific pixel. Similar to `set_pixel` but also set the white component + * + * @param strip: LED strip + * @param channel: channel of pixel to set + * @param index: index of pixel to set + * @param red: red part of color + * @param green: green part of color + * @param blue: blue part of color + * @param white: separate white component + * + * @return + * - ESP_OK: Set RGBW color for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set RGBW color for a specific pixel failed because of an invalid argument + * - ESP_FAIL: Set RGBW color for a specific pixel failed because other error occurred + */ + esp_err_t (*set_pixel_rgbw)(muxed_led_strip_t *strip, uint32_t channel, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white); + + /** + * @brief Refresh memory colors to LEDs + * + * @param strip: LED strip + * @param channel: which channel to refresh + * + * @return + * - ESP_OK: Refresh successfully + * - ESP_FAIL: Refresh failed because some other error occurred + * + * @note: + * After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip. + */ + esp_err_t (*refresh)(muxed_led_strip_t *strip, uint32_t channel); + + /** + * @brief Clear LED strip (turn off all LEDs) + * + * @param strip: LED strip + * @param channel: which channel to clear + * + * @return + * - ESP_OK: Clear LEDs successfully + * - ESP_FAIL: Clear LEDs failed because some other error occurred + */ + esp_err_t (*clear)(muxed_led_strip_t *strip, uint32_t channel); + + /** + * @brief Free LED strip resources + * + * @param strip: LED strip + * + * @return + * - ESP_OK: Free resources successfully + * - ESP_FAIL: Free resources failed because error occurred + */ + esp_err_t (*del)(muxed_led_strip_t *strip); +}; + +#ifdef __cplusplus +} +#endif diff --git a/components/MuxedLedStrip/src/led_strip_api.c b/components/MuxedLedStrip/src/led_strip_api.c new file mode 100644 index 0000000..6eb86b8 --- /dev/null +++ b/components/MuxedLedStrip/src/led_strip_api.c @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "esp_log.h" +#include "esp_check.h" +#include "led_strip.h" +#include "led_strip_interface.h" + +static const char *TAG = "led_strip"; + +esp_err_t led_strip_set_pixel(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + return strip->set_pixel(strip, index, red, green, blue); +} + +esp_err_t led_strip_set_pixel_hsv(led_strip_handle_t strip, uint32_t index, uint16_t hue, uint8_t saturation, uint8_t value) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + uint32_t red = 0; + uint32_t green = 0; + uint32_t blue = 0; + + uint32_t rgb_max = value; + uint32_t rgb_min = rgb_max * (255 - saturation) / 255.0f; + + uint32_t i = hue / 60; + uint32_t diff = hue % 60; + + // RGB adjustment amount by hue + uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60; + + switch (i) { + case 0: + red = rgb_max; + green = rgb_min + rgb_adj; + blue = rgb_min; + break; + case 1: + red = rgb_max - rgb_adj; + green = rgb_max; + blue = rgb_min; + break; + case 2: + red = rgb_min; + green = rgb_max; + blue = rgb_min + rgb_adj; + break; + case 3: + red = rgb_min; + green = rgb_max - rgb_adj; + blue = rgb_max; + break; + case 4: + red = rgb_min + rgb_adj; + green = rgb_min; + blue = rgb_max; + break; + default: + red = rgb_max; + green = rgb_min; + blue = rgb_max - rgb_adj; + break; + } + + return strip->set_pixel(strip, index, red, green, blue); +} + +esp_err_t led_strip_set_pixel_rgbw(led_strip_handle_t strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + return strip->set_pixel_rgbw(strip, index, red, green, blue, white); +} + +esp_err_t led_strip_refresh(led_strip_handle_t strip) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + return strip->refresh(strip); +} + +esp_err_t led_strip_clear(led_strip_handle_t strip) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + return strip->clear(strip); +} + +esp_err_t led_strip_del(led_strip_handle_t strip) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + return strip->del(strip); +} diff --git a/components/MuxedLedStrip/src/led_strip_rmt_dev.c b/components/MuxedLedStrip/src/led_strip_rmt_dev.c new file mode 100644 index 0000000..1cbf0e4 --- /dev/null +++ b/components/MuxedLedStrip/src/led_strip_rmt_dev.c @@ -0,0 +1,164 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "esp_log.h" +#include "esp_check.h" +#include "driver/rmt_tx.h" +#include "led_strip.h" +#include "led_strip_interface.h" +#include "led_strip_rmt_encoder.h" + +#define LED_STRIP_RMT_DEFAULT_RESOLUTION 10000000 // 10MHz resolution +#define LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE 4 +// the memory size of each RMT channel, in words (4 bytes) +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 +#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 64 +#else +#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 48 +#endif + +static const char *TAG = "led_strip_rmt"; + +typedef struct { + led_strip_t base; + rmt_channel_handle_t rmt_chan; + rmt_encoder_handle_t strip_encoder; + uint32_t strip_len; + uint8_t bytes_per_pixel; + uint8_t pixel_buf[]; +} led_strip_rmt_obj; + +static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue) +{ + led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); + ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs"); + uint32_t start = index * rmt_strip->bytes_per_pixel; + // In thr order of GRB, as LED strip like WS2812 sends out pixels in this order + rmt_strip->pixel_buf[start + 0] = green & 0xFF; + rmt_strip->pixel_buf[start + 1] = red & 0xFF; + rmt_strip->pixel_buf[start + 2] = blue & 0xFF; + if (rmt_strip->bytes_per_pixel > 3) { + rmt_strip->pixel_buf[start + 3] = 0; + } + return ESP_OK; +} + +static esp_err_t led_strip_rmt_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) +{ + led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); + ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs"); + ESP_RETURN_ON_FALSE(rmt_strip->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "wrong LED pixel format, expected 4 bytes per pixel"); + uint8_t *buf_start = rmt_strip->pixel_buf + index * 4; + // SK6812 component order is GRBW + *buf_start = green & 0xFF; + *++buf_start = red & 0xFF; + *++buf_start = blue & 0xFF; + *++buf_start = white & 0xFF; + return ESP_OK; +} + +static esp_err_t led_strip_rmt_refresh(led_strip_t *strip) +{ + led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); + rmt_transmit_config_t tx_conf = { + .loop_count = 0, + }; + + ESP_RETURN_ON_ERROR(rmt_enable(rmt_strip->rmt_chan), TAG, "enable RMT channel failed"); + ESP_RETURN_ON_ERROR(rmt_transmit(rmt_strip->rmt_chan, rmt_strip->strip_encoder, rmt_strip->pixel_buf, + rmt_strip->strip_len * rmt_strip->bytes_per_pixel, &tx_conf), TAG, "transmit pixels by RMT failed"); + ESP_RETURN_ON_ERROR(rmt_tx_wait_all_done(rmt_strip->rmt_chan, -1), TAG, "flush RMT channel failed"); + ESP_RETURN_ON_ERROR(rmt_disable(rmt_strip->rmt_chan), TAG, "disable RMT channel failed"); + return ESP_OK; +} + +static esp_err_t led_strip_rmt_clear(led_strip_t *strip) +{ + led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); + // Write zero to turn off all leds + memset(rmt_strip->pixel_buf, 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel); + return led_strip_rmt_refresh(strip); +} + +static esp_err_t led_strip_rmt_del(led_strip_t *strip) +{ + led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); + ESP_RETURN_ON_ERROR(rmt_del_channel(rmt_strip->rmt_chan), TAG, "delete RMT channel failed"); + ESP_RETURN_ON_ERROR(rmt_del_encoder(rmt_strip->strip_encoder), TAG, "delete strip encoder failed"); + free(rmt_strip); + return ESP_OK; +} + +esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *rmt_config, led_strip_handle_t *ret_strip) +{ + led_strip_rmt_obj *rmt_strip = NULL; + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE(led_config && rmt_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format"); + uint8_t bytes_per_pixel = 3; + if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) { + bytes_per_pixel = 4; + } else if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRB) { + bytes_per_pixel = 3; + } else { + assert(false); + } + rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel); + ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt strip"); + uint32_t resolution = rmt_config->resolution_hz ? rmt_config->resolution_hz : LED_STRIP_RMT_DEFAULT_RESOLUTION; + + // for backward compatibility, if the user does not set the clk_src, use the default value + rmt_clock_source_t clk_src = RMT_CLK_SRC_DEFAULT; + if (rmt_config->clk_src) { + clk_src = rmt_config->clk_src; + } + size_t mem_block_symbols = LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS; + // override the default value if the user sets it + if (rmt_config->mem_block_symbols) { + mem_block_symbols = rmt_config->mem_block_symbols; + } + rmt_tx_channel_config_t rmt_chan_config = { + .clk_src = clk_src, + .gpio_num = led_config->strip_gpio_num, + .mem_block_symbols = mem_block_symbols, + .resolution_hz = resolution, + .trans_queue_depth = LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE, + .flags.with_dma = rmt_config->flags.with_dma, + .flags.invert_out = led_config->flags.invert_out, + }; + ESP_GOTO_ON_ERROR(rmt_new_tx_channel(&rmt_chan_config, &rmt_strip->rmt_chan), err, TAG, "create RMT TX channel failed"); + + led_strip_encoder_config_t strip_encoder_conf = { + .resolution = resolution, + .led_model = led_config->led_model + }; + ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, "create LED strip encoder failed"); + + + rmt_strip->bytes_per_pixel = bytes_per_pixel; + rmt_strip->strip_len = led_config->max_leds; + rmt_strip->base.set_pixel = led_strip_rmt_set_pixel; + rmt_strip->base.set_pixel_rgbw = led_strip_rmt_set_pixel_rgbw; + rmt_strip->base.refresh = led_strip_rmt_refresh; + rmt_strip->base.clear = led_strip_rmt_clear; + rmt_strip->base.del = led_strip_rmt_del; + + *ret_strip = &rmt_strip->base; + return ESP_OK; +err: + if (rmt_strip) { + if (rmt_strip->rmt_chan) { + rmt_del_channel(rmt_strip->rmt_chan); + } + if (rmt_strip->strip_encoder) { + rmt_del_encoder(rmt_strip->strip_encoder); + } + free(rmt_strip); + } + return ret; +} diff --git a/components/MuxedLedStrip/src/led_strip_rmt_dev_idf4.c b/components/MuxedLedStrip/src/led_strip_rmt_dev_idf4.c new file mode 100644 index 0000000..a1067cd --- /dev/null +++ b/components/MuxedLedStrip/src/led_strip_rmt_dev_idf4.c @@ -0,0 +1,194 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "esp_log.h" +#include "esp_check.h" +#include "driver/rmt.h" +#include "led_strip.h" +#include "led_strip_interface.h" + +static const char *TAG = "led_strip_rmt"; + +#define WS2812_T0H_NS (300) +#define WS2812_T0L_NS (900) +#define WS2812_T1H_NS (900) +#define WS2812_T1L_NS (300) + +#define SK6812_T0H_NS (300) +#define SK6812_T0L_NS (900) +#define SK6812_T1H_NS (600) +#define SK6812_T1L_NS (600) + +#define LED_STRIP_RESET_MS (10) + +// the memory size of each RMT channel, in words (4 bytes) +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 +#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 64 +#else +#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 48 +#endif + +static uint32_t led_t0h_ticks = 0; +static uint32_t led_t1h_ticks = 0; +static uint32_t led_t0l_ticks = 0; +static uint32_t led_t1l_ticks = 0; + +typedef struct { + led_strip_t base; + rmt_channel_t rmt_channel; + uint32_t strip_len; + uint8_t bytes_per_pixel; + uint8_t buffer[0]; +} led_strip_rmt_obj; + +static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size, + size_t wanted_num, size_t *translated_size, size_t *item_num) +{ + if (src == NULL || dest == NULL) { + *translated_size = 0; + *item_num = 0; + return; + } + const rmt_item32_t bit0 = {{{ led_t0h_ticks, 1, led_t0l_ticks, 0 }}}; //Logical 0 + const rmt_item32_t bit1 = {{{ led_t1h_ticks, 1, led_t1l_ticks, 0 }}}; //Logical 1 + size_t size = 0; + size_t num = 0; + uint8_t *psrc = (uint8_t *)src; + rmt_item32_t *pdest = dest; + while (size < src_size && num < wanted_num) { + for (int i = 0; i < 8; i++) { + // MSB first + if (*psrc & (1 << (7 - i))) { + pdest->val = bit1.val; + } else { + pdest->val = bit0.val; + } + num++; + pdest++; + } + size++; + psrc++; + } + *translated_size = size; + *item_num = num; +} + +static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue) +{ + led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); + ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of the maximum number of leds"); + uint32_t start = index * rmt_strip->bytes_per_pixel; + // In thr order of GRB + rmt_strip->buffer[start + 0] = green & 0xFF; + rmt_strip->buffer[start + 1] = red & 0xFF; + rmt_strip->buffer[start + 2] = blue & 0xFF; + if (rmt_strip->bytes_per_pixel > 3) { + rmt_strip->buffer[start + 3] = 0; + } + return ESP_OK; +} + +static esp_err_t led_strip_rmt_refresh(led_strip_t *strip) +{ + led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); + ESP_RETURN_ON_ERROR(rmt_write_sample(rmt_strip->rmt_channel, rmt_strip->buffer, rmt_strip->strip_len * rmt_strip->bytes_per_pixel, true), TAG, + "transmit RMT samples failed"); + vTaskDelay(pdMS_TO_TICKS(LED_STRIP_RESET_MS)); + return ESP_OK; +} + +static esp_err_t led_strip_rmt_clear(led_strip_t *strip) +{ + led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); + // Write zero to turn off all LEDs + memset(rmt_strip->buffer, 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel); + return led_strip_rmt_refresh(strip); +} + +static esp_err_t led_strip_rmt_del(led_strip_t *strip) +{ + led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); + ESP_RETURN_ON_ERROR(rmt_driver_uninstall(rmt_strip->rmt_channel), TAG, "uninstall RMT driver failed"); + free(rmt_strip); + return ESP_OK; +} + +esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *dev_config, led_strip_handle_t *ret_strip) +{ + led_strip_rmt_obj *rmt_strip = NULL; + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(led_config && dev_config && ret_strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, TAG, "invalid led_pixel_format"); + ESP_RETURN_ON_FALSE(dev_config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, TAG, "DMA is not supported"); + + uint8_t bytes_per_pixel = 3; + if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) { + bytes_per_pixel = 4; + } else if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRB) { + bytes_per_pixel = 3; + } else { + assert(false); + } + + // allocate memory for led_strip object + rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel); + ESP_RETURN_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, TAG, "request memory for les_strip failed"); + + // install RMT channel driver + rmt_config_t config = RMT_DEFAULT_CONFIG_TX(led_config->strip_gpio_num, dev_config->rmt_channel); + // set the minimal clock division because the LED strip needs a high clock resolution + config.clk_div = 2; + + uint8_t mem_block_num = 2; + // override the default value if the user specify the mem block size + if (dev_config->mem_block_symbols) { + mem_block_num = (dev_config->mem_block_symbols + LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS / 2) / LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS; + } + config.mem_block_num = mem_block_num; + + ESP_GOTO_ON_ERROR(rmt_config(&config), err, TAG, "RMT config failed"); + ESP_GOTO_ON_ERROR(rmt_driver_install(config.channel, 0, 0), err, TAG, "RMT install failed"); + + uint32_t counter_clk_hz = 0; + rmt_get_counter_clock((rmt_channel_t)dev_config->rmt_channel, &counter_clk_hz); + // ns -> ticks + float ratio = (float)counter_clk_hz / 1e9; + if (led_config->led_model == LED_MODEL_WS2812) { + led_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS); + led_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS); + led_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS); + led_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS); + } else if (led_config->led_model == LED_MODEL_SK6812) { + led_t0h_ticks = (uint32_t)(ratio * SK6812_T0H_NS); + led_t0l_ticks = (uint32_t)(ratio * SK6812_T0L_NS); + led_t1h_ticks = (uint32_t)(ratio * SK6812_T1H_NS); + led_t1l_ticks = (uint32_t)(ratio * SK6812_T1L_NS); + } else { + assert(false); + } + + // adapter to translates the LES strip date frame into RMT symbols + rmt_translator_init((rmt_channel_t)dev_config->rmt_channel, ws2812_rmt_adapter); + + rmt_strip->bytes_per_pixel = bytes_per_pixel; + rmt_strip->rmt_channel = (rmt_channel_t)dev_config->rmt_channel; + rmt_strip->strip_len = led_config->max_leds; + rmt_strip->base.set_pixel = led_strip_rmt_set_pixel; + rmt_strip->base.refresh = led_strip_rmt_refresh; + rmt_strip->base.clear = led_strip_rmt_clear; + rmt_strip->base.del = led_strip_rmt_del; + + *ret_strip = &rmt_strip->base; + return ESP_OK; + +err: + if (rmt_strip) { + free(rmt_strip); + } + return ret; +} diff --git a/components/MuxedLedStrip/src/led_strip_rmt_encoder.c b/components/MuxedLedStrip/src/led_strip_rmt_encoder.c new file mode 100644 index 0000000..2e6f570 --- /dev/null +++ b/components/MuxedLedStrip/src/led_strip_rmt_encoder.c @@ -0,0 +1,146 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "led_strip_rmt_encoder.h" + +static const char *TAG = "led_rmt_encoder"; + +typedef struct { + rmt_encoder_t base; + rmt_encoder_t *bytes_encoder; + rmt_encoder_t *copy_encoder; + int state; + rmt_symbol_word_t reset_code; +} rmt_led_strip_encoder_t; + +static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder; + rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder; + rmt_encode_state_t session_state = 0; + rmt_encode_state_t state = 0; + size_t encoded_symbols = 0; + switch (led_encoder->state) { + case 0: // send RGB data + encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = 1; // switch to next state when current encoding session finished + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + // fall-through + case 1: // send reset code + encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code, + sizeof(led_encoder->reset_code), &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = 0; // back to the initial encoding session + state |= RMT_ENCODING_COMPLETE; + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + } +out: + *ret_state = state; + return encoded_symbols; +} + +static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_del_encoder(led_encoder->bytes_encoder); + rmt_del_encoder(led_encoder->copy_encoder); + free(led_encoder); + return ESP_OK; +} + +static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_reset(led_encoder->bytes_encoder); + rmt_encoder_reset(led_encoder->copy_encoder); + led_encoder->state = 0; + return ESP_OK; +} + +esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder) +{ + esp_err_t ret = ESP_OK; + rmt_led_strip_encoder_t *led_encoder = NULL; + ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + ESP_GOTO_ON_FALSE(config->led_model < LED_MODEL_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led model"); + led_encoder = calloc(1, sizeof(rmt_led_strip_encoder_t)); + ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder"); + led_encoder->base.encode = rmt_encode_led_strip; + led_encoder->base.del = rmt_del_led_strip_encoder; + led_encoder->base.reset = rmt_led_strip_encoder_reset; + rmt_bytes_encoder_config_t bytes_encoder_config; + if (config->led_model == LED_MODEL_SK6812) { + bytes_encoder_config = (rmt_bytes_encoder_config_t) { + .bit0 = { + .level0 = 1, + .duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us + .level1 = 0, + .duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us + }, + .bit1 = { + .level0 = 1, + .duration0 = 0.6 * config->resolution / 1000000, // T1H=0.6us + .level1 = 0, + .duration1 = 0.6 * config->resolution / 1000000, // T1L=0.6us + }, + .flags.msb_first = 1 // SK6812 transfer bit order: G7...G0R7...R0B7...B0(W7...W0) + }; + } else if (config->led_model == LED_MODEL_WS2812) { + // different led strip might have its own timing requirements, following parameter is for WS2812 + bytes_encoder_config = (rmt_bytes_encoder_config_t) { + .bit0 = { + .level0 = 1, + .duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us + .level1 = 0, + .duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us + }, + .bit1 = { + .level0 = 1, + .duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us + .level1 = 0, + .duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us + }, + .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0 + }; + } else { + assert(false); + } + ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed"); + rmt_copy_encoder_config_t copy_encoder_config = {}; + ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed"); + + uint32_t reset_ticks = config->resolution / 1000000 * 280 / 2; // reset code duration defaults to 280us to accomodate WS2812B-V5 + led_encoder->reset_code = (rmt_symbol_word_t) { + .level0 = 0, + .duration0 = reset_ticks, + .level1 = 0, + .duration1 = reset_ticks, + }; + *ret_encoder = &led_encoder->base; + return ESP_OK; +err: + if (led_encoder) { + if (led_encoder->bytes_encoder) { + rmt_del_encoder(led_encoder->bytes_encoder); + } + if (led_encoder->copy_encoder) { + rmt_del_encoder(led_encoder->copy_encoder); + } + free(led_encoder); + } + return ret; +} diff --git a/components/MuxedLedStrip/src/led_strip_rmt_encoder.h b/components/MuxedLedStrip/src/led_strip_rmt_encoder.h new file mode 100644 index 0000000..ba71e60 --- /dev/null +++ b/components/MuxedLedStrip/src/led_strip_rmt_encoder.h @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "driver/rmt_encoder.h" +#include "led_strip_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Type of led strip encoder configuration + */ +typedef struct { + uint32_t resolution; /*!< Encoder resolution, in Hz */ + led_model_t led_model; /*!< LED model */ +} led_strip_encoder_config_t; + +/** + * @brief Create RMT encoder for encoding LED strip pixels into RMT symbols + * + * @param[in] config Encoder configuration + * @param[out] ret_encoder Returned encoder handle + * @return + * - ESP_ERR_INVALID_ARG for any invalid arguments + * - ESP_ERR_NO_MEM out of memory when creating led strip encoder + * - ESP_OK if creating encoder successfully + */ +esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder); + +#ifdef __cplusplus +} +#endif diff --git a/components/MuxedLedStrip/src/led_strip_spi_dev.c b/components/MuxedLedStrip/src/led_strip_spi_dev.c new file mode 100644 index 0000000..12ea8fb --- /dev/null +++ b/components/MuxedLedStrip/src/led_strip_spi_dev.c @@ -0,0 +1,209 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "esp_log.h" +#include "esp_check.h" +#include "esp_rom_gpio.h" +#include "soc/spi_periph.h" +#include "led_strip.h" +#include "led_strip_interface.h" +#include "hal/spi_hal.h" + +#define LED_STRIP_SPI_DEFAULT_RESOLUTION (2.5 * 1000 * 1000) // 2.5MHz resolution +#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4 + +#define SPI_BYTES_PER_COLOR_BYTE 3 +#define SPI_BITS_PER_COLOR_BYTE (SPI_BYTES_PER_COLOR_BYTE * 8) + +static const char *TAG = "led_strip_spi"; + +typedef struct { + led_strip_t base; + spi_host_device_t spi_host; + spi_device_handle_t spi_device; + uint32_t strip_len; + uint8_t bytes_per_pixel; + uint8_t pixel_buf[]; +} led_strip_spi_obj; + +// please make sure to zero-initialize the buf before calling this function +static void __led_strip_spi_bit(uint8_t data, uint8_t *buf) +{ + // Each color of 1 bit is represented by 3 bits of SPI, low_level:100 ,high_level:110 + // So a color byte occupies 3 bytes of SPI. + *(buf + 2) |= data & BIT(0) ? BIT(2) | BIT(1) : BIT(2); + *(buf + 2) |= data & BIT(1) ? BIT(5) | BIT(4) : BIT(5); + *(buf + 2) |= data & BIT(2) ? BIT(7) : 0x00; + *(buf + 1) |= BIT(0); + *(buf + 1) |= data & BIT(3) ? BIT(3) | BIT(2) : BIT(3); + *(buf + 1) |= data & BIT(4) ? BIT(6) | BIT(5) : BIT(6); + *(buf + 0) |= data & BIT(5) ? BIT(1) | BIT(0) : BIT(1); + *(buf + 0) |= data & BIT(6) ? BIT(4) | BIT(3) : BIT(4); + *(buf + 0) |= data & BIT(7) ? BIT(7) | BIT(6) : BIT(7); +} + +static esp_err_t led_strip_spi_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue) +{ + led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base); + ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs"); + // LED_PIXEL_FORMAT_GRB takes 72bits(9bytes) + uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE; + memset(spi_strip->pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + __led_strip_spi_bit(green, &spi_strip->pixel_buf[start]); + __led_strip_spi_bit(red, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]); + __led_strip_spi_bit(blue, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]); + if (spi_strip->bytes_per_pixel > 3) { + __led_strip_spi_bit(0, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]); + } + return ESP_OK; +} + +static esp_err_t led_strip_spi_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) +{ + led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base); + ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs"); + ESP_RETURN_ON_FALSE(spi_strip->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "wrong LED pixel format, expected 4 bytes per pixel"); + // LED_PIXEL_FORMAT_GRBW takes 96bits(12bytes) + uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE; + // SK6812 component order is GRBW + memset(spi_strip->pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + __led_strip_spi_bit(green, &spi_strip->pixel_buf[start]); + __led_strip_spi_bit(red, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]); + __led_strip_spi_bit(blue, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]); + __led_strip_spi_bit(white, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]); + + return ESP_OK; +} + +static esp_err_t led_strip_spi_refresh(led_strip_t *strip) +{ + led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base); + spi_transaction_t tx_conf; + memset(&tx_conf, 0, sizeof(tx_conf)); + + tx_conf.length = spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BITS_PER_COLOR_BYTE; + tx_conf.tx_buffer = spi_strip->pixel_buf; + tx_conf.rx_buffer = NULL; + ESP_RETURN_ON_ERROR(spi_device_transmit(spi_strip->spi_device, &tx_conf), TAG, "transmit pixels by SPI failed"); + + return ESP_OK; +} + +static esp_err_t led_strip_spi_clear(led_strip_t *strip) +{ + led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base); + //Write zero to turn off all leds + memset(spi_strip->pixel_buf, 0, spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + uint8_t *buf = spi_strip->pixel_buf; + for (int index = 0; index < spi_strip->strip_len * spi_strip->bytes_per_pixel; index++) { + __led_strip_spi_bit(0, buf); + buf += SPI_BYTES_PER_COLOR_BYTE; + } + + return led_strip_spi_refresh(strip); +} + +static esp_err_t led_strip_spi_del(led_strip_t *strip) +{ + led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base); + + ESP_RETURN_ON_ERROR(spi_bus_remove_device(spi_strip->spi_device), TAG, "delete spi device failed"); + ESP_RETURN_ON_ERROR(spi_bus_free(spi_strip->spi_host), TAG, "free spi bus failed"); + + free(spi_strip); + return ESP_OK; +} + +esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const led_strip_spi_config_t *spi_config, led_strip_handle_t *ret_strip) +{ + led_strip_spi_obj *spi_strip = NULL; + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format"); + uint8_t bytes_per_pixel = 3; + if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) { + bytes_per_pixel = 4; + } else if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRB) { + bytes_per_pixel = 3; + } else { + assert(false); + } + uint32_t mem_caps = MALLOC_CAP_DEFAULT; + if (spi_config->flags.with_dma) { + // DMA buffer must be placed in internal SRAM + mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA; + } + spi_strip = heap_caps_calloc(1, sizeof(led_strip_spi_obj) + led_config->max_leds * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, mem_caps); + + ESP_GOTO_ON_FALSE(spi_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for spi strip"); + + spi_strip->spi_host = spi_config->spi_bus; + // for backward compatibility, if the user does not set the clk_src, use the default value + spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT; + if (spi_config->clk_src) { + clk_src = spi_config->clk_src; + } + + spi_bus_config_t spi_bus_cfg = { + .mosi_io_num = led_config->strip_gpio_num, + //Only use MOSI to generate the signal, set -1 when other pins are not used. + .miso_io_num = -1, + .sclk_io_num = -1, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = led_config->max_leds * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, + }; + ESP_GOTO_ON_ERROR(spi_bus_initialize(spi_strip->spi_host, &spi_bus_cfg, spi_config->flags.with_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED), err, TAG, "create SPI bus failed"); + + if (led_config->flags.invert_out == true) { + esp_rom_gpio_connect_out_signal(led_config->strip_gpio_num, spi_periph_signal[spi_strip->spi_host].spid_out, true, false); + } + + spi_device_interface_config_t spi_dev_cfg = { + .clock_source = clk_src, + .command_bits = 0, + .address_bits = 0, + .dummy_bits = 0, + .clock_speed_hz = LED_STRIP_SPI_DEFAULT_RESOLUTION, + .mode = 0, + //set -1 when CS is not used + .spics_io_num = -1, + .queue_size = LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE, + }; + + ESP_GOTO_ON_ERROR(spi_bus_add_device(spi_strip->spi_host, &spi_dev_cfg, &spi_strip->spi_device), err, TAG, "Failed to add spi device"); + + int clock_resolution_khz = 0; + spi_device_get_actual_freq(spi_strip->spi_device, &clock_resolution_khz); + // TODO: ideally we should decide the SPI_BYTES_PER_COLOR_BYTE by the real clock resolution + // But now, let's fixed the resolution, the downside is, we don't support a clock source whose frequency is not multiple of LED_STRIP_SPI_DEFAULT_RESOLUTION + ESP_GOTO_ON_FALSE(clock_resolution_khz == LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000, ESP_ERR_NOT_SUPPORTED, err, + TAG, "unsupported clock resolution:%dKHz", clock_resolution_khz); + + spi_strip->bytes_per_pixel = bytes_per_pixel; + spi_strip->strip_len = led_config->max_leds; + spi_strip->base.set_pixel = led_strip_spi_set_pixel; + spi_strip->base.set_pixel_rgbw = led_strip_spi_set_pixel_rgbw; + spi_strip->base.refresh = led_strip_spi_refresh; + spi_strip->base.clear = led_strip_spi_clear; + spi_strip->base.del = led_strip_spi_del; + + *ret_strip = &spi_strip->base; + return ESP_OK; +err: + if (spi_strip) { + if (spi_strip->spi_device) { + spi_bus_remove_device(spi_strip->spi_device); + } + if (spi_strip->spi_host) { + spi_bus_free(spi_strip->spi_host); + } + free(spi_strip); + } + return ret; +} diff --git a/components/MuxedLedStrip/src/muxed_led_strip_api.c b/components/MuxedLedStrip/src/muxed_led_strip_api.c new file mode 100644 index 0000000..b8d7c1a --- /dev/null +++ b/components/MuxedLedStrip/src/muxed_led_strip_api.c @@ -0,0 +1,97 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "esp_log.h" +#include "esp_check.h" +#include "led_strip_types.h" +#include "muxed_led_strip_types.h" +#include "muxed_led_strip.h" +#include "muxed_led_strip_interface.h" + +static const char *TAG = "muxed_led_strip"; + +esp_err_t muxed_led_strip_set_pixel(muxed_led_strip_handle_t strip, uint32_t channel, uint32_t index, uint32_t red, uint32_t green, uint32_t blue) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + return strip->set_pixel(strip, channel, index, red, green, blue); +} + +esp_err_t muxed_led_strip_set_pixel_hsv(muxed_led_strip_handle_t strip, uint32_t channel, uint32_t index, uint16_t hue, uint8_t saturation, uint8_t value) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + uint32_t red = 0; + uint32_t green = 0; + uint32_t blue = 0; + + uint32_t rgb_max = value; + uint32_t rgb_min = rgb_max * (255 - saturation) / 255.0f; + + uint32_t i = hue / 60; + uint32_t diff = hue % 60; + + // RGB adjustment amount by hue + uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60; + + switch (i) { + case 0: + red = rgb_max; + green = rgb_min + rgb_adj; + blue = rgb_min; + break; + case 1: + red = rgb_max - rgb_adj; + green = rgb_max; + blue = rgb_min; + break; + case 2: + red = rgb_min; + green = rgb_max; + blue = rgb_min + rgb_adj; + break; + case 3: + red = rgb_min; + green = rgb_max - rgb_adj; + blue = rgb_max; + break; + case 4: + red = rgb_min + rgb_adj; + green = rgb_min; + blue = rgb_max; + break; + default: + red = rgb_max; + green = rgb_min; + blue = rgb_max - rgb_adj; + break; + } + + return strip->set_pixel(strip, channel, index, red, green, blue); +} + +esp_err_t muxed_led_strip_set_pixel_rgbw(muxed_led_strip_handle_t strip, uint32_t channel, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + return strip->set_pixel_rgbw(strip, channel, index, red, green, blue, white); +} + +esp_err_t muxed_led_strip_refresh(muxed_led_strip_handle_t strip, uint32_t channel) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + return strip->refresh(strip, channel); +} + +esp_err_t muxed_led_strip_clear(muxed_led_strip_handle_t strip, uint32_t channel) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + return strip->clear(strip, channel); +} + +esp_err_t muxed_led_strip_del(muxed_led_strip_handle_t strip) +{ + ESP_RETURN_ON_FALSE(strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + return strip->del(strip); +} + diff --git a/components/MuxedLedStrip/src/muxed_led_strip_rmt_dev.c b/components/MuxedLedStrip/src/muxed_led_strip_rmt_dev.c new file mode 100644 index 0000000..7b5668f --- /dev/null +++ b/components/MuxedLedStrip/src/muxed_led_strip_rmt_dev.c @@ -0,0 +1,186 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "esp_log.h" +#include "esp_check.h" +#include "driver/rmt_tx.h" +#include "muxed_led_strip.h" +#include "muxed_led_strip_interface.h" +#include "led_strip_rmt_encoder.h" + +#define LED_STRIP_RMT_DEFAULT_RESOLUTION 10000000 // 10MHz resolution +#define LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE 4 +// the memory size of each RMT channel, in words (4 bytes) +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 +#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 64 +#else +#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 48 +#endif + +static const char *TAG = "led_strip_rmt"; + +typedef struct +{ + muxed_led_strip_t base; + rmt_channel_handle_t rmt_chan; + rmt_encoder_handle_t strip_encoder; + uint32_t strip_len; + uint8_t bytes_per_pixel; + uint8_t n_channels; + uint8_t pixel_buf[]; +} muxed_led_strip_rmt_obj; + +static esp_err_t muxed_led_strip_rmt_set_pixel(muxed_led_strip_t *strip, uint32_t channel, uint32_t index, uint32_t red, uint32_t green, uint32_t blue) +{ + muxed_led_strip_rmt_obj *rmt_strip = __containerof(strip, muxed_led_strip_rmt_obj, base); + ESP_RETURN_ON_FALSE(channel < rmt_strip->n_channels, ESP_ERR_INVALID_ARG, TAG, "channel greater than total channels"); + ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs"); + uint32_t start = (channel * rmt_strip->strip_len * rmt_strip->bytes_per_pixel) + (index * rmt_strip->bytes_per_pixel); + // In thr order of GRB, as LED strip like WS2812 sends out pixels in this order + rmt_strip->pixel_buf[start + 0] = green & 0xFF; + rmt_strip->pixel_buf[start + 1] = red & 0xFF; + rmt_strip->pixel_buf[start + 2] = blue & 0xFF; + if (rmt_strip->bytes_per_pixel > 3) + { + rmt_strip->pixel_buf[start + 3] = 0; + } + return ESP_OK; +} + +static esp_err_t muxed_led_strip_rmt_set_pixel_rgbw(muxed_led_strip_t *strip, uint32_t channel, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) +{ + muxed_led_strip_rmt_obj *rmt_strip = __containerof(strip, muxed_led_strip_rmt_obj, base); + ESP_RETURN_ON_FALSE(channel < rmt_strip->n_channels, ESP_ERR_INVALID_ARG, TAG, "channel greater than total channels"); + ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs"); + ESP_RETURN_ON_FALSE(rmt_strip->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "wrong LED pixel format, expected 4 bytes per pixel"); + uint8_t *buf_start = rmt_strip->pixel_buf + (channel * rmt_strip->strip_len * rmt_strip->bytes_per_pixel) + (index * 4); + // SK6812 component order is GRBW + *buf_start = green & 0xFF; + *++buf_start = red & 0xFF; + *++buf_start = blue & 0xFF; + *++buf_start = white & 0xFF; + return ESP_OK; +} + +static esp_err_t muxed_led_strip_rmt_refresh(muxed_led_strip_t *strip, uint32_t channel) +{ + muxed_led_strip_rmt_obj *rmt_strip = __containerof(strip, muxed_led_strip_rmt_obj, base); + rmt_transmit_config_t tx_conf = { + .loop_count = 0, + }; + ESP_RETURN_ON_FALSE(channel < rmt_strip->n_channels, ESP_ERR_INVALID_ARG, TAG, "channel greater than total channels"); + ESP_RETURN_ON_ERROR(rmt_enable(rmt_strip->rmt_chan), TAG, "enable RMT channel failed"); + ESP_RETURN_ON_ERROR(rmt_transmit(rmt_strip->rmt_chan, rmt_strip->strip_encoder, rmt_strip->pixel_buf + (channel * rmt_strip->strip_len * rmt_strip->bytes_per_pixel), + rmt_strip->strip_len * rmt_strip->bytes_per_pixel, &tx_conf), + TAG, "transmit pixels by RMT failed"); + ESP_RETURN_ON_ERROR(rmt_tx_wait_all_done(rmt_strip->rmt_chan, -1), TAG, "flush RMT channel failed"); + ESP_RETURN_ON_ERROR(rmt_disable(rmt_strip->rmt_chan), TAG, "disable RMT channel failed"); + return ESP_OK; +} + +static esp_err_t muxed_led_strip_rmt_clear(muxed_led_strip_t *strip, uint32_t channel) +{ + muxed_led_strip_rmt_obj *rmt_strip = __containerof(strip, muxed_led_strip_rmt_obj, base); + ESP_RETURN_ON_FALSE(channel < rmt_strip->n_channels, ESP_ERR_INVALID_ARG, TAG, "channel greater than total channels"); + // Write zero to turn off all leds + memset(rmt_strip->pixel_buf + (channel * rmt_strip->strip_len * rmt_strip->bytes_per_pixel), 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel); + return muxed_led_strip_rmt_refresh(strip, channel); +} + +static esp_err_t muxed_led_strip_rmt_del(muxed_led_strip_t *strip) +{ + muxed_led_strip_rmt_obj *rmt_strip = __containerof(strip, muxed_led_strip_rmt_obj, base); + ESP_RETURN_ON_ERROR(rmt_del_channel(rmt_strip->rmt_chan), TAG, "delete RMT channel failed"); + ESP_RETURN_ON_ERROR(rmt_del_encoder(rmt_strip->strip_encoder), TAG, "delete strip encoder failed"); + free(rmt_strip); + return ESP_OK; +} + +esp_err_t muxed_led_strip_new_rmt_device(const muxed_led_strip_config_t *led_config, + const led_strip_rmt_config_t *rmt_config, + const rmt_tx_event_callbacks_t *cbs, + muxed_led_strip_handle_t *ret_strip) +{ + muxed_led_strip_rmt_obj *rmt_strip = NULL; + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE(led_config && rmt_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format"); + uint8_t bytes_per_pixel = 3; + if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) + { + bytes_per_pixel = 4; + } + else if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRB) + { + bytes_per_pixel = 3; + } + else + { + assert(false); + } + uint8_t number_of_multiplexed_channels = led_config->channels; + rmt_strip = calloc(1, sizeof(muxed_led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel * number_of_multiplexed_channels); + ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt strip"); + uint32_t resolution = rmt_config->resolution_hz ? rmt_config->resolution_hz : LED_STRIP_RMT_DEFAULT_RESOLUTION; + + // for backward compatibility, if the user does not set the clk_src, use the default value + rmt_clock_source_t clk_src = RMT_CLK_SRC_DEFAULT; + if (rmt_config->clk_src) + { + clk_src = rmt_config->clk_src; + } + size_t mem_block_symbols = LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS; + // override the default value if the user sets it + if (rmt_config->mem_block_symbols) + { + mem_block_symbols = rmt_config->mem_block_symbols; + } + rmt_tx_channel_config_t rmt_chan_config = { + .clk_src = clk_src, + .gpio_num = led_config->strip_gpio_num, + .mem_block_symbols = mem_block_symbols, + .resolution_hz = resolution, + .trans_queue_depth = LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE, + .flags.with_dma = rmt_config->flags.with_dma, + .flags.invert_out = led_config->flags.invert_out, + }; + ESP_GOTO_ON_ERROR(rmt_new_tx_channel(&rmt_chan_config, &rmt_strip->rmt_chan), err, TAG, "create RMT TX channel failed"); + + led_strip_encoder_config_t strip_encoder_conf = { + .resolution = resolution, + .led_model = led_config->led_model}; + ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, "create LED strip encoder failed"); + + rmt_strip->bytes_per_pixel = bytes_per_pixel; + rmt_strip->strip_len = led_config->max_leds; + rmt_strip->n_channels = number_of_multiplexed_channels; + rmt_strip->base.set_pixel = muxed_led_strip_rmt_set_pixel; + rmt_strip->base.set_pixel_rgbw = muxed_led_strip_rmt_set_pixel_rgbw; + rmt_strip->base.refresh = muxed_led_strip_rmt_refresh; + rmt_strip->base.clear = muxed_led_strip_rmt_clear; + rmt_strip->base.del = muxed_led_strip_rmt_del; + + ESP_GOTO_ON_ERROR(rmt_tx_register_event_callbacks(rmt_strip->rmt_chan, cbs, (void *)0), err, TAG, "register RMT TX callbacks failed"); + + *ret_strip = &rmt_strip->base; + return ESP_OK; +err: + if (rmt_strip) + { + if (rmt_strip->rmt_chan) + { + rmt_del_channel(rmt_strip->rmt_chan); + } + if (rmt_strip->strip_encoder) + { + rmt_del_encoder(rmt_strip->strip_encoder); + } + free(rmt_strip); + } + return ret; +} diff --git a/components/NVM/CMakeLists.txt b/components/NVM/CMakeLists.txt new file mode 100644 index 0000000..bd0321e --- /dev/null +++ b/components/NVM/CMakeLists.txt @@ -0,0 +1,17 @@ +idf_component_register( + SRCS + "Key_Value.c" + "Settings.c" + "SPIFFS.c" + "USB.c" + + INCLUDE_DIRS + "." + REQUIRES + "SystemK" + "spiffs" + "driver" + "usb" + "usb_host_msc" + "esp_timer" +) diff --git a/components/NVM/Key_Value.c b/components/NVM/Key_Value.c new file mode 100644 index 0000000..2384b9e --- /dev/null +++ b/components/NVM/Key_Value.c @@ -0,0 +1,228 @@ +/* + * This program source code file is part of the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +#include +#include +#include +#include +#include + +#define MAX_LINE_LENGTH 140 +#define MAX_KEY_LENGTH 64 +#define MAX_VALUE_LENGTH 64 + +static const char *TAG = "NVM KV"; +static const char *TEMP_FILE = "/usb/esp/temp.txt"; + +// Trims the whitespace from both ends of a string. +static void KV_Trim(char *str) +{ + char *start = str; + char *end = str + strlen(str) - 1; + while (*start && (*start == ' ' || *start == '\t')) + start++; + while (end > start && (*end == ' ' || *end == '\t' || *end == '\n')) + end--; + *(end + 1) = '\0'; + memmove(str, start, end - start + 2); +} + +// Splits a line around the '=' into a key and value pair. +static int KV_Parse_Line(char *line, char *key, char *value) +{ + char *delimiter = strchr(line, '='); + if (delimiter == NULL) + return 0; + *delimiter = '\0'; + strncpy(key, line, MAX_KEY_LENGTH - 1); + strncpy(value, delimiter + 1, MAX_VALUE_LENGTH - 1); + key[MAX_KEY_LENGTH - 1] = '\0'; + value[MAX_VALUE_LENGTH - 1] = '\0'; + KV_Trim(key); + KV_Trim(value); + return 1; +} + +SystemKResult_T KV_Get_Value_string(const char *filename, const char *search_key, char *value) +{ + FILE *file = fopen(filename, "r"); + if (file == NULL) + { + KLOG_ERROR(TAG, "Couldn't open file %s for reading!", filename); + return SYSTEMK_RESULT_FILE_NOT_FOUND; + } + + char line[MAX_LINE_LENGTH]; + char key[MAX_KEY_LENGTH]; + + while (fgets(line, sizeof(line), file)) + { + if (KV_Parse_Line(line, key, value) && strcmp(key, search_key) == 0) + { + fclose(file); + return SYSTEMK_RESULT_SUCCESS; + } + } + + fclose(file); + KLOG_ERROR(TAG, "Couldn't find key %s in file %s!", search_key, filename); + return SYSTEMK_RESULT_KEY_NOT_FOUND; +} + +SystemKResult_T KV_Set_Value_string(const char *filename, const char *set_key, const char *set_value) +{ + FILE *file = fopen(filename, "r"); + if (file == NULL) + { + KLOG_ERROR(TAG, "Couldn't open file %s for reading!", filename); + return SYSTEMK_RESULT_FILE_NOT_FOUND; + } + + FILE *temp = fopen(TEMP_FILE, "w"); + if (temp == NULL) + { + fclose(file); + KLOG_ERROR(TAG, "Couldn't open file %s for writing!", TEMP_FILE); + return SYSTEMK_RESULT_WRITE_FAILED; + } + + char line[MAX_LINE_LENGTH]; + char line_copy[MAX_LINE_LENGTH]; + char key[MAX_KEY_LENGTH]; + char value[MAX_VALUE_LENGTH]; + int found = 0; + + while (fgets(line, sizeof(line), file)) + { + strncpy(line_copy, line, MAX_LINE_LENGTH); + line_copy[MAX_LINE_LENGTH - 1] = '\0'; // Ensure null-termination + + if (KV_Parse_Line(line, key, value) && strcmp(key, set_key) == 0) + { + fprintf(temp, "%s = %s\n", set_key, set_value); + found = 1; + } + else + { + fputs(line_copy, temp); + } + } + + if (!found) + { + fprintf(temp, "%s = %s\n", set_key, set_value); + } + + fclose(file); + fclose(temp); + + remove(filename); + rename(TEMP_FILE, filename); + + return SYSTEMK_RESULT_SUCCESS; +} + +SystemKResult_T KV_Get_Value_uint32(const char *filename, const char *search_key, uint32_t *value) +{ + char value_str[MAX_VALUE_LENGTH]; + + SystemKResult_T result = KV_Get_Value_string(filename, search_key, value_str); + if (result != SYSTEMK_RESULT_SUCCESS) + { + return result; + } + + char *endptr; + // Reset errno to check for conversion errors. + errno = 0; + *value = strtoul(value_str, &endptr, 10); + + // Check for conversion errors + if ((errno == ERANGE && *value == ULONG_MAX) || (errno != 0)) + { + KLOG_ERROR(TAG, "Error converting %s for key %s to uint32_t!", value_str, search_key); + return SYSTEMK_RESULT_WRONG_DATATYPE; + } + + if (endptr == value_str) + { + KLOG_ERROR(TAG, "No digits were found in %s (for key %s)!", value_str, search_key); + return SYSTEMK_RESULT_WRONG_DATATYPE; + } + + if (*value > UINT32_MAX) + { + KLOG_ERROR(TAG, "Value %s (for key %s) exceeds uint32_t range!", value_str, search_key); + return SYSTEMK_RESULT_OVERFLOW; + } + + return SYSTEMK_RESULT_SUCCESS; +} + +SystemKResult_T KV_Set_Value_uint32(const char *filename, const char *set_key, uint32_t *set_value) +{ + char value_str[MAX_VALUE_LENGTH]; + int written = snprintf(value_str, MAX_VALUE_LENGTH, "%lu", *set_value); + + if (written < 0 || written >= MAX_VALUE_LENGTH) + { + KLOG_ERROR(TAG, "Error converting uint32_t to string for key %s!", set_key); + return SYSTEMK_RESULT_WRONG_DATATYPE; + } + + return KV_Set_Value_string(filename, set_key, value_str); +} + +SystemKResult_T KV_Get_Value_uint8(const char *filename, const char *search_key, uint8_t *value) +{ + uint32_t value32 = 0; + + SystemKResult_T result = KV_Get_Value_uint32(filename, search_key, &value32); + if (result != SYSTEMK_RESULT_SUCCESS) + { + return result; + } + + // Check for conversion errors + if (value32 > UINT8_MAX) + { + KLOG_ERROR(TAG, "Value %lu (for key %s) exceeds uint32_t range!", value32, search_key); + return SYSTEMK_RESULT_OVERFLOW; + } + + *value = (uint8_t)value32; + + return SYSTEMK_RESULT_SUCCESS; +} + +SystemKResult_T KV_Set_Value_uint8(const char *filename, const char *set_key, uint8_t *set_value) +{ + char value_str[MAX_VALUE_LENGTH]; + int written = snprintf(value_str, MAX_VALUE_LENGTH, "%u", *set_value); + + if (written < 0 || written >= MAX_VALUE_LENGTH) + { + KLOG_ERROR(TAG, "Error converting uint8_t to string for key %s!", set_key); + return SYSTEMK_RESULT_WRONG_DATATYPE; + } + + return KV_Set_Value_string(filename, set_key, value_str); +} diff --git a/components/NVM/Key_Value.h b/components/NVM/Key_Value.h new file mode 100644 index 0000000..9331f1e --- /dev/null +++ b/components/NVM/Key_Value.h @@ -0,0 +1,29 @@ +/* + * This program source code file is part of the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +SystemKResult_T KV_Get_Value_string(const char *filename, const char *search_key, char *value); +SystemKResult_T KV_Set_Value_string(const char *filename, const char *set_key, const char *set_value); + +SystemKResult_T KV_Get_Value_uint32(const char *filename, const char *search_key, uint32_t *value); +SystemKResult_T KV_Set_Value_uint32(const char *filename, const char *set_key, uint32_t *set_value); + +SystemKResult_T KV_Get_Value_uint8(const char *filename, const char *search_key, uint8_t *value); +SystemKResult_T KV_Set_Value_uint8(const char *filename, const char *set_key, uint8_t *set_value); \ No newline at end of file diff --git a/components/NVM/NVM.h b/components/NVM/NVM.h new file mode 100644 index 0000000..01df907 --- /dev/null +++ b/components/NVM/NVM.h @@ -0,0 +1,26 @@ +/* + * This program source code file is part of the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +#pragma once + +#include "Key_Value.h" +#include "SPIFFS.h" +#include "USB.h" diff --git a/components/NVM/SPIFFS.c b/components/NVM/SPIFFS.c new file mode 100644 index 0000000..68f6ec0 --- /dev/null +++ b/components/NVM/SPIFFS.c @@ -0,0 +1,84 @@ +/* + * This program source code file is part of the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +#include +#include +#include "esp_spiffs.h" + +static const char *TAG = "SPIFFS"; +const char *DEFAULT_CONFIG_FILE = "/spiffs/default_config.txt"; + +void Initialize_SPIFFS(SemaphoreHandle_t init_complete) +{ + KLOG_INFO(TAG, "Initializing SPI flash file system (SPIFFS)..."); + + esp_vfs_spiffs_conf_t conf = { + .base_path = "/spiffs", // File path prefix associated with the filesystem. + .partition_label = NULL, // If set to NULL, first partition with subtype=spiffs will be used. + .max_files = 5, // Maximum files that could be open at the same time. + .format_if_mount_failed = false}; // If true, it will format the file system if it fails to mount. + + esp_err_t ret = esp_vfs_spiffs_register(&conf); + + if (ret != ESP_OK) + { + if (ret == ESP_FAIL) + { + KLOG_ERROR(TAG, "Failed to mount or format filesystem!"); + } + else if (ret == ESP_ERR_NOT_FOUND) + { + KLOG_ERROR(TAG, "Failed to find SPIFFS partition!"); + } + else + { + KLOG_ERROR(TAG, "Failed to initialize SPIFFS (%s)!", esp_err_to_name(ret)); + } + return; + } + + size_t total = 0; + size_t used = 0; + ret = esp_spiffs_info(NULL, &total, &used); + if (ret != ESP_OK) + { + KLOG_ERROR(TAG, "Failed to get SPIFFS partition information (%s)!", esp_err_to_name(ret)); + } + else + { + KLOG_INFO(TAG, "SPIFFS partition: %d bytes used out of %d total.", used, total); + } + + FILE *f = fopen("/spiffs/boot_message.txt", "r"); + if (f == NULL) + { + KLOG_ERROR(TAG, "Failed to open boot_message.txt!"); + return; + } + + char buf[64]; + memset(buf, 0, sizeof(buf)); + fread(buf, 1, sizeof(buf), f); + fclose(f); + + KLOG_INFO(TAG, ">>> %s <<<", buf); + xSemaphoreGive(init_complete); +} \ No newline at end of file diff --git a/components/NVM/SPIFFS.h b/components/NVM/SPIFFS.h new file mode 100644 index 0000000..6f83bd5 --- /dev/null +++ b/components/NVM/SPIFFS.h @@ -0,0 +1,26 @@ +/* + * This program source code file is part of the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +#pragma once + +void Initialize_SPIFFS(SemaphoreHandle_t init_complete); + +extern const char *DEFAULT_CONFIG_FILE; \ No newline at end of file diff --git a/components/NVM/Settings.c b/components/NVM/Settings.c new file mode 100644 index 0000000..0901514 --- /dev/null +++ b/components/NVM/Settings.c @@ -0,0 +1,209 @@ +/* + * This program source code file is part of the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +#include +#include + +static const uint8_t UNINTIALIZED_UINT8 = UINT8_MAX; + +static uint8_t Cached_Team_ID = UNINTIALIZED_UINT8; +static uint8_t Cached_Player_ID = UNINTIALIZED_UINT8; +static uint8_t Cached_Weapon_ID = UNINTIALIZED_UINT8; + +SystemKResult_T SETTINGS_get_uint8_t(SystemKSettingID_T id, uint8_t *value) +{ + SystemKResult_T result = SYSTEMK_RESULT_UNSPECIFIED_FAILURE; + char *key = ""; + uint8_t *cached_value = NULL; + + switch (id) + { + case SYSTEMK_SETTING_IS_RIGHT_HANDED: + key = "Is_Right_Handed"; + break; + + case SYSTEMK_SETTING_AUDIO_VOLUME: + key = "Audio_Volume"; + break; + + case SYSTEMK_SETTING_TEAMID: + if (Cached_Team_ID != UNINTIALIZED_UINT8) + { + *value = Cached_Team_ID; + result = SYSTEMK_RESULT_SUCCESS; + } + else + { + key = "Team_ID"; + cached_value = &Cached_Team_ID; + } + + break; + + case SYSTEMK_SETTING_PLAYERID: + if (Cached_Player_ID != UNINTIALIZED_UINT8) + { + *value = Cached_Player_ID; + result = SYSTEMK_RESULT_SUCCESS; + } + else + { + key = "Player_ID"; + cached_value = &Cached_Player_ID; + } + break; + + case SYSTEMK_SETTING_WEAPONID: + if (Cached_Weapon_ID != UNINTIALIZED_UINT8) + { + *value = Cached_Weapon_ID; + result = SYSTEMK_RESULT_SUCCESS; + } + else + { + key = "Weapon_ID"; + cached_value = &Cached_Weapon_ID; + } + break; + + default: + result = SYSTEMK_RESULT_WRONG_DATATYPE; + break; + } + + if (result != SYSTEMK_RESULT_SUCCESS) + { + result = KV_Get_Value_uint8(CONFIG_FILE, key, value); + + if (result != SYSTEMK_RESULT_SUCCESS) + { + result = KV_Get_Value_uint8(DEFAULT_CONFIG_FILE, key, value); + + if (result == SYSTEMK_RESULT_SUCCESS) + { + (void)KV_Set_Value_uint8(CONFIG_FILE, key, value); + } + } + + // Save the cached value, if necessary. + if ((cached_value != NULL) && (result == SYSTEMK_RESULT_SUCCESS)) + { + *cached_value = *value; + } + } + + return result; +} + +SystemKResult_T SETTINGS_set_uint8_t(SystemKSettingID_T id, uint8_t value) +{ + SystemKResult_T result = SYSTEMK_RESULT_SUCCESS; + + switch (id) + { + case SYSTEMK_SETTING_IS_RIGHT_HANDED: + result = KV_Set_Value_uint8(CONFIG_FILE, "Is_Right_Handed", &value); + break; + + case SYSTEMK_SETTING_AUDIO_VOLUME: + result = KV_Set_Value_uint8(CONFIG_FILE, "Audio_Volume", &value); + break; + + case SYSTEMK_SETTING_TEAMID: + Cached_Team_ID = value; + result = KV_Set_Value_uint8(CONFIG_FILE, "Team_ID", &value); + break; + + case SYSTEMK_SETTING_PLAYERID: + Cached_Player_ID = value; + result = KV_Set_Value_uint8(CONFIG_FILE, "Player_ID", &value); + break; + + case SYSTEMK_SETTING_WEAPONID: + Cached_Weapon_ID = value; + result = KV_Set_Value_uint8(CONFIG_FILE, "Weapon_ID", &value); + break; + + default: + result = SYSTEMK_RESULT_WRONG_DATATYPE; + break; + } + + return result; +} + +SystemKResult_T SETTINGS_get_uint32_t(SystemKSettingID_T id, uint32_t *value) +{ + SystemKResult_T result = SYSTEMK_RESULT_SUCCESS; + char *key = ""; + + switch (id) + { + case SYSTEMK_SETTING_T_START_GAME_in_ms: + key = "T_Start_Game_in_ms"; + break; + + default: + result = SYSTEMK_RESULT_WRONG_DATATYPE; + break; + } + + if (result == SYSTEMK_RESULT_SUCCESS) + { + result = KV_Get_Value_uint32(CONFIG_FILE, key, value); + + if (result != SYSTEMK_RESULT_SUCCESS) + { + result = KV_Get_Value_uint32(DEFAULT_CONFIG_FILE, key, value); + + if (result == SYSTEMK_RESULT_SUCCESS) + { + (void)KV_Set_Value_uint32(CONFIG_FILE, key, value); + } + } + } + + return result; +} + +SystemKResult_T SETTINGS_set_uint32_t(SystemKSettingID_T id, uint32_t value) +{ + SystemKResult_T result = SYSTEMK_RESULT_SUCCESS; + + switch (id) + { + case SYSTEMK_SETTING_T_START_GAME_in_ms: + result = KV_Set_Value_uint32(CONFIG_FILE, "T_Start_Game_in_ms", &value); + break; + + default: + result = SYSTEMK_RESULT_WRONG_DATATYPE; + break; + } + + return result; +} + +// Settings are saved on change in this implementation. +SystemKResult_T SETTINGS_Save(void) +{ + return SYSTEMK_RESULT_SUCCESS; +} diff --git a/components/NVM/USB.c b/components/NVM/USB.c new file mode 100644 index 0000000..5c746fc --- /dev/null +++ b/components/NVM/USB.c @@ -0,0 +1,449 @@ +/* + * This program source code file is part of the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +// From https://github.com/espressif/esp-idf/blob/master/examples/peripherals/usb/host/msc/main/msc_example_main.c + +#include +#include +#include +#include +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "usb/usb_host.h" +#include "usb/msc_host.h" +#include "usb/msc_host_vfs.h" +#include "esp_timer.h" +#include "esp_err.h" +#include "Key_Value.h" +#include "USB.h" + +#define STACK_SIZE 4096 +static StaticTask_t xTaskBuffer; +static StackType_t xStack[STACK_SIZE]; + +#define USB_HOST_TASK_PRIORITY 2 +#define MSC_HOST_TASK_PRIORITY 3 + +#define MNT_PATH "/usb" // Path in the Virtual File System, where the USB flash drive is going to be mounted +#define BUFFER_SIZE 4096 // The read/write performance can be improved with larger buffer for the cost of RAM; 4kB is enough for most use cases. + +static const char *TAG = "USB"; + +static const char *OTA_FILE = "/usb/esp/OTA_URL.txt"; +const char *CONFIG_FILE = "/usb/esp/config.txt"; + +typedef enum +{ + USB_STATE_UNINITIALIZED, + USB_STATE_IDLE, + USB_STATE_DEVICE_CONNECTED, + USB_STATE_VFS_REGISTERED, + USB_STATE_PROCESSING_DISCONNECTION +} USB_State_T; + +static QueueHandle_t usb_queue; +typedef struct +{ + enum + { + USB_HOST_INITIALIZED, + USB_DEVICE_CONNECTED, // USB device connect event + USB_DEVICE_DISCONNECTED, // USB device disconnect event + } id; + union + { + uint8_t new_dev_address; // Address of new USB device for APP_DEVICE_CONNECTED event + } data; +} usb_message_t; + +/** + * @brief MSC driver callback + * + * Signal device connection/disconnection to the main task + * + * @param[in] event MSC event + * @param[in] arg MSC event data + */ +static void MSC_Event_Callback(const msc_host_event_t *event, void *arg) +{ + if (event->event == MSC_DEVICE_CONNECTED) + { + usb_message_t message = { + .id = USB_DEVICE_CONNECTED, + .data.new_dev_address = event->device.address, + }; + xQueueSend(usb_queue, &message, portMAX_DELAY); + } + else if (event->event == MSC_DEVICE_DISCONNECTED) + { + usb_message_t message = { + .id = USB_DEVICE_DISCONNECTED, + }; + xQueueSend(usb_queue, &message, portMAX_DELAY); + } + else + { + KLOG_INFO(TAG, "Event: %d", event->event); + } +} + +__attribute__((unused)) static void print_device_info(msc_host_device_info_t *info) +{ + const size_t megabyte = 1024 * 1024; + uint64_t capacity = ((uint64_t)info->sector_size * info->sector_count) / megabyte; + + printf("Device info:\n"); + printf("\t Capacity: %llu MB\n", capacity); + printf("\t Sector size: %" PRIu32 "\n", info->sector_size); + printf("\t Sector count: %" PRIu32 "\n", info->sector_count); + printf("\t PID: 0x%04X \n", info->idProduct); + printf("\t VID: 0x%04X \n", info->idVendor); + wprintf(L"\t iProduct: %S \n", info->iProduct); + wprintf(L"\t iManufacturer: %S \n", info->iManufacturer); + wprintf(L"\t iSerialNumber: %S \n", info->iSerialNumber); +} + +__attribute__((unused)) static void file_operations(void) +{ + const char *directory = "/usb/esp"; + const char *file_path = "/usb/esp/test.txt"; + + // Create /usb/esp directory + struct stat s = {0}; + bool directory_exists = stat(directory, &s) == 0; + if (!directory_exists) + { + if (mkdir(directory, 0775) != 0) + { + KLOG_ERROR(TAG, "mkdir failed with errno: %s", strerror(errno)); + } + } + + // Create /usb/esp/test.txt file, if it doesn't exist + if (stat(file_path, &s) != 0) + { + KLOG_INFO(TAG, "Creating file"); + FILE *f = fopen(file_path, "w"); + if (f == NULL) + { + KLOG_ERROR(TAG, "Failed to open file for writing"); + return; + } + fprintf(f, "Hello World!\n"); + fclose(f); + } + + // Read back the file + FILE *f; + KLOG_INFO(TAG, "Reading file"); + f = fopen(file_path, "r"); + if (f == NULL) + { + KLOG_ERROR(TAG, "Failed to open file for reading"); + return; + } + char line[64]; + fgets(line, sizeof(line), f); + fclose(f); + // strip newline + char *pos = strchr(line, '\n'); + if (pos) + { + *pos = '\0'; + } + KLOG_INFO(TAG, "Read from file '%s': '%s'", file_path, line); +} + +__attribute__((unused)) void speed_test(void) +{ +#define TEST_FILE "/usb/esp/dummy" +#define ITERATIONS 256 // 256 * 4kb = 1MB + int64_t test_start, test_end; + + FILE *f = fopen(TEST_FILE, "wb+"); + if (f == NULL) + { + KLOG_ERROR(TAG, "Failed to open file for writing"); + return; + } + // Set larger buffer for this file. It results in larger and more effective USB transfers + setvbuf(f, NULL, _IOFBF, BUFFER_SIZE); + + // Allocate application buffer used for read/write + uint8_t *data = malloc(BUFFER_SIZE); + assert(data); + + KLOG_INFO(TAG, "Writing to file %s", TEST_FILE); + test_start = esp_timer_get_time(); + for (int i = 0; i < ITERATIONS; i++) + { + if (fwrite(data, BUFFER_SIZE, 1, f) == 0) + { + return; + } + } + test_end = esp_timer_get_time(); + KLOG_INFO(TAG, "Write speed %1.2f MiB/s", (BUFFER_SIZE * ITERATIONS) / (float)(test_end - test_start)); + rewind(f); + + KLOG_INFO(TAG, "Reading from file %s", TEST_FILE); + test_start = esp_timer_get_time(); + for (int i = 0; i < ITERATIONS; i++) + { + if (0 == fread(data, BUFFER_SIZE, 1, f)) + { + return; + } + } + test_end = esp_timer_get_time(); + KLOG_INFO(TAG, "Read speed %1.2f MiB/s", (BUFFER_SIZE * ITERATIONS) / (float)(test_end - test_start)); + + fclose(f); + free(data); +} + +static void usb_host_task(void *args) +{ + usb_host_config_t host_config = { + .skip_phy_setup = false, + .intr_flags = ESP_INTR_FLAG_LEVEL1, + }; + ESP_ERROR_CHECK(usb_host_install(&host_config)); + + const msc_host_driver_config_t msc_config = { + .create_backround_task = true, + .task_priority = MSC_HOST_TASK_PRIORITY, + .stack_size = 4096, + .callback = MSC_Event_Callback, + }; + ESP_ERROR_CHECK(msc_host_install(&msc_config)); + + vTaskDelay(10); // Short delay to let MSC client task spin up. + + usb_message_t message = { + .id = USB_HOST_INITIALIZED}; + xQueueSend(usb_queue, &message, portMAX_DELAY); + + while (true) + { + uint32_t event_flags; + + // This function handles all of the USB Host Library's processing and should be called repeatedly in a loop. + ESP_ERROR_CHECK(usb_host_lib_handle_events(portMAX_DELAY, &event_flags)); + + // Release devices once all clients have deregistered. + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) + { + if (usb_host_device_free_all() == ESP_OK) + { + KLOG_INFO(TAG, "USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS"); + // break; + }; + } + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) + { + KLOG_INFO(TAG, "USB_HOST_LIB_EVENT_FLAGS_ALL_FREE"); + // break; + } + } +} + +static void app_usb_task(void *args) +{ + SemaphoreHandle_t init_complete = args; + + static USB_State_T Current_State = USB_STATE_UNINITIALIZED; + static msc_host_device_handle_t msc_device = NULL; + static msc_host_vfs_handle_t vfs_handle = NULL; + static uint8_t device_address = 1; + usb_message_t msg; + + while (true) + { + switch (Current_State) + { + case USB_STATE_UNINITIALIZED: + { + if (xQueueReceive(usb_queue, &msg, portMAX_DELAY) == pdTRUE) + { + if (msg.id == USB_HOST_INITIALIZED) + { + KLOG_INFO(TAG, "Host initialized."); + Current_State = USB_STATE_IDLE; + } + } + } + break; + + case USB_STATE_IDLE: + { + KLOG_TRACE(TAG, "USB_STATE_IDLE"); + + if (xQueueReceive(usb_queue, &msg, pdMS_TO_TICKS(1000)) == pdTRUE) + { + if (msg.id == USB_DEVICE_CONNECTED) + { + device_address = msg.data.new_dev_address; + Current_State = USB_STATE_DEVICE_CONNECTED; + KLOG_INFO(TAG, "Device connected."); + } + } + else + { + KLOG_ERROR(TAG, "No flash drive detected--rebooting."); + vTaskDelay(pdMS_TO_TICKS(100)); + esp_restart(); + } + } + break; + + case USB_STATE_DEVICE_CONNECTED: + { + KLOG_TRACE(TAG, "USB_STATE_DEVICE_CONNECTED"); + + // USB device connected. Open it and attempt to map it to Virtual File System. + if (msc_host_install_device(device_address, &msc_device) != ESP_OK) + { + ESP_LOGW(TAG, "Problem connecting to flash drive."); + Current_State = USB_STATE_PROCESSING_DISCONNECTION; + } + else + { + const esp_vfs_fat_mount_config_t mount_config = { + .format_if_mount_failed = false, + .max_files = 3, + .allocation_unit_size = 8192, + }; + if (msc_host_vfs_register(msc_device, MNT_PATH, &mount_config, &vfs_handle) != ESP_OK) + { + ESP_LOGW(TAG, "Problem mounting filesystem."); + Current_State = USB_STATE_PROCESSING_DISCONNECTION; + } + else + { + Current_State = USB_STATE_VFS_REGISTERED; + xSemaphoreGive(init_complete); + } + } + } + break; + + case USB_STATE_VFS_REGISTERED: + { + KLOG_TRACE(TAG, "USB_STATE_VFS_REGISTERED"); + + if (xQueueReceive(usb_queue, &msg, pdMS_TO_TICKS(1000)) == pdTRUE) + { + if (msg.id == USB_DEVICE_DISCONNECTED) + { + Current_State = USB_STATE_PROCESSING_DISCONNECTION; + } + } + vTaskDelay(pdMS_TO_TICKS(1000)); + } + break; + + case USB_STATE_PROCESSING_DISCONNECTION: + { + KLOG_TRACE(TAG, "USB_STATE_PROCESSING_DISCONNECTION"); + + if (vfs_handle) + { + ESP_ERROR_CHECK(msc_host_vfs_unregister(vfs_handle)); + vfs_handle = NULL; + } + if (msc_device) + { + ESP_ERROR_CHECK(msc_host_uninstall_device(msc_device)); + msc_device = NULL; + device_address = 0; + } + + Current_State = USB_STATE_IDLE; + } + break; + } + } +} + +void Initialize_USB(SemaphoreHandle_t init_complete) +{ + KLOG_INFO(TAG, "Initializing USB file system..."); + + // Create FreeRTOS primitives + usb_queue = xQueueCreate(5, sizeof(usb_message_t)); + assert(usb_queue); + + BaseType_t usb_host_task_created = xTaskCreatePinnedToCore(usb_host_task, "USB Host", 4096, NULL, USB_HOST_TASK_PRIORITY, NULL, 1); + assert(usb_host_task_created); + + TaskHandle_t xHandle = xTaskCreateStaticPinnedToCore( + app_usb_task, // Function that implements the task. + "USB NVM", // Text name for the task. + STACK_SIZE, // Stack size in bytes, not words. + (void *)init_complete, // Parameter passed into the task. + tskIDLE_PRIORITY + 2, // Priority at which the task is created. + xStack, // Array to use as the task's stack. + &xTaskBuffer, // Variable to hold the task's data structure. + APP_CPU_NUM); // Specify the task's core affinity + assert(xHandle); +} + +bool OTA_File_Exists(void) +{ + struct stat s = {0}; + return (stat(OTA_FILE, &s) == 0); +} + +char *Get_OTA_Image_URL(void) +{ + static char url[64] = ""; + FILE *f; + f = fopen(OTA_FILE, "r"); + if (f == NULL) + { + KLOG_ERROR(TAG, "The OTA file is missing!"); + return url; + } + + fgets(url, sizeof(url), f); + fclose(f); + // Strip the newline + char *pos = strchr(url, '\n'); + if (pos) + { + *pos = '\0'; + } + return url; +} + +void Erase_OTA_File(void) +{ + if (remove(OTA_FILE) != 0) + { + KLOG_ERROR(TAG, "Error erasing the OTA file: %s", strerror(errno)); + } +} \ No newline at end of file diff --git a/components/NVM/USB.h b/components/NVM/USB.h new file mode 100644 index 0000000..f56e9fa --- /dev/null +++ b/components/NVM/USB.h @@ -0,0 +1,31 @@ +/* + * This program source code file is part of the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +#pragma once + +void Initialize_USB(SemaphoreHandle_t init_complete); + +extern const char *CONFIG_FILE; + +// OTA Reprogramming Helpers +bool OTA_File_Exists(void); +char * Get_OTA_Image_URL(void); +void Erase_OTA_File(void); diff --git a/components/Reprogramming/CMakeLists.txt b/components/Reprogramming/CMakeLists.txt new file mode 100644 index 0000000..6c2ced5 --- /dev/null +++ b/components/Reprogramming/CMakeLists.txt @@ -0,0 +1,14 @@ +idf_component_register( + SRCS + "Reprogramming.c" + INCLUDE_DIRS + "." + REQUIRES + "SystemK" + "driver" + "usb" + "usb_host_msc" + "esp_https_ota" + "app_update" + "NVM" +) \ No newline at end of file diff --git a/components/Reprogramming/Reprogramming.c b/components/Reprogramming/Reprogramming.c new file mode 100644 index 0000000..55f2342 --- /dev/null +++ b/components/Reprogramming/Reprogramming.c @@ -0,0 +1,311 @@ +/* + * This program source code file is part of the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include "esp_log.h" +#include "esp_ota_ops.h" +#include "esp_spiffs.h" +#include "esp_partition.h" + +static const char *TAG = "Reprogramming"; +static const char *FIRMWARE_DIR = "/usb/esp/firmware"; +static const char *APP_IMAGE_PREFIX = "APP"; +static const char *SPIFFS_IMAGE_PREFIX = "SPIFFS"; + +#define REPROGRAMMING_TASK_PRIORITY 1 +static TaskHandle_t xReprogrammingTask = NULL; +static StaticTask_t xReprogrammingTaskBuffer; +static StackType_t xReprogrammingTaskStack[4096]; + +#define BUFFER_SIZE 1024 + +typedef struct +{ + unsigned long total_size; + unsigned long remaining_size; + void *data; +} data_manager_t; + +typedef enum { + IMAGE_TYPE_APP, + IMAGE_TYPE_SPIFFS +} image_type_t; + +static char *find_image_filename(const char *prefix) +{ + DIR *dir = opendir(FIRMWARE_DIR); + if (dir == NULL) + { + KLOG_ERROR(TAG, "Failed to open directory '%s': %s!", FIRMWARE_DIR, strerror(errno)); + return NULL; + } + + struct dirent *entry; + char *filename = NULL; + + while ((entry = readdir(dir)) != NULL) + { + if (entry->d_type == DT_REG && strncmp(entry->d_name, prefix, strlen(prefix)) == 0) + { + filename = strdup(entry->d_name); + if (filename == NULL) + { + KLOG_ERROR(TAG, "Memory allocation failed!"); + } + else + { + KLOG_DEBUG(TAG, "Found image: %s", filename); + } + break; + } + } + + closedir(dir); + + if (filename == NULL) + { + KLOG_WARN(TAG, "Couldn't find an image with prefix '%s' in directory '%s'!", prefix, FIRMWARE_DIR); + return NULL; + } + + size_t needed = snprintf(NULL, 0, "%s/%s", FIRMWARE_DIR, filename) + 1; + char *full_path = malloc(needed); + if (full_path != NULL) + { + snprintf(full_path, needed, "%s/%s", FIRMWARE_DIR, filename); + } + + free(filename); + return full_path; +} + +static SystemKResult_T program_image(const char *filename, image_type_t image_type) +{ + esp_err_t err; + FILE *file = fopen(filename, "rb"); + if (file == NULL) + { + KLOG_ERROR(TAG, "Failed to open file %s", filename); + return SYSTEMK_RESULT_FILE_NOT_FOUND; + } + + fseek(file, 0, SEEK_END); + long file_size = ftell(file); + fseek(file, 0, SEEK_SET); + + KLOG_INFO(TAG, "File size: %ld bytes", file_size); + + data_manager_t data_manager = { + .total_size = file_size, + .remaining_size = file_size, + .data = malloc(BUFFER_SIZE) + }; + + if (data_manager.data == NULL) + { + KLOG_ERROR(TAG, "Failed to allocate memory"); + fclose(file); + return SYSTEMK_RESULT_NOT_ENOUGH_MEMORY; + } + + if (image_type == IMAGE_TYPE_APP) + { + esp_ota_handle_t update_handle = 0; + const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL); + KLOG_INFO(TAG, "Writing to partition subtype %d at offset 0x%" PRIx32, update_partition->subtype, update_partition->address); + err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle); + if (err != ESP_OK) + { + KLOG_ERROR(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err)); + free(data_manager.data); + fclose(file); + return SYSTEMK_RESULT_UNSPECIFIED_FAILURE; + } + + while (data_manager.remaining_size > 0) + { + size_t size = (data_manager.remaining_size <= BUFFER_SIZE) ? data_manager.remaining_size : BUFFER_SIZE; + if (fread(data_manager.data, 1, size, file) != size) + { + KLOG_ERROR(TAG, "fread failed"); + err = ESP_FAIL; + break; + } + + err = esp_ota_write(update_handle, data_manager.data, size); + if (err != ESP_OK) + { + KLOG_ERROR(TAG, "esp_ota_write failed (%s)", esp_err_to_name(err)); + break; + } + + data_manager.remaining_size -= size; + } + + if (err == ESP_OK) + { + err = esp_ota_end(update_handle); + if (err != ESP_OK) + { + KLOG_ERROR(TAG, "esp_ota_end failed (%s)", esp_err_to_name(err)); + } + else + { + err = esp_ota_set_boot_partition(update_partition); + if (err != ESP_OK) + { + KLOG_ERROR(TAG, "esp_ota_set_boot_partition failed (%s)", esp_err_to_name(err)); + } + } + } + } + else if (image_type == IMAGE_TYPE_SPIFFS) + { + const esp_partition_t *spiffs_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL); + if (spiffs_partition == NULL) + { + KLOG_ERROR(TAG, "SPIFFS partition not found"); + free(data_manager.data); + fclose(file); + return SYSTEMK_RESULT_UNSPECIFIED_FAILURE; + } + + err = esp_partition_erase_range(spiffs_partition, 0, spiffs_partition->size); + if (err != ESP_OK) + { + KLOG_ERROR(TAG, "Failed to erase SPIFFS partition (%s)", esp_err_to_name(err)); + free(data_manager.data); + fclose(file); + return SYSTEMK_RESULT_UNSPECIFIED_FAILURE; + } + + while (data_manager.remaining_size > 0) + { + size_t size = (data_manager.remaining_size <= BUFFER_SIZE) ? data_manager.remaining_size : BUFFER_SIZE; + if (fread(data_manager.data, 1, size, file) != size) + { + KLOG_ERROR(TAG, "fread failed"); + err = ESP_FAIL; + break; + } + + err = esp_partition_write(spiffs_partition, spiffs_partition->size - data_manager.remaining_size, data_manager.data, size); + if (err != ESP_OK) + { + KLOG_ERROR(TAG, "esp_partition_write failed (%s)", esp_err_to_name(err)); + break; + } + + data_manager.remaining_size -= size; + } + } + + free(data_manager.data); + fclose(file); + + return (err == ESP_OK) ? SYSTEMK_RESULT_SUCCESS : SYSTEMK_RESULT_UNSPECIFIED_FAILURE; +} + +SystemKResult_T Maybe_Reprogram_From_USB(void) +{ + SystemKResult_T result = SYSTEMK_RESULT_SUCCESS; + char *app_image_filename = find_image_filename(APP_IMAGE_PREFIX); + char *spiffs_image_filename = find_image_filename(SPIFFS_IMAGE_PREFIX); + + if (app_image_filename) + { + KLOG_INFO(TAG, "Application image found: %s", app_image_filename); + result = program_image(app_image_filename, IMAGE_TYPE_APP); + free(app_image_filename); + if (result != SYSTEMK_RESULT_SUCCESS) + { + return result; + } + } + + if (spiffs_image_filename) + { + KLOG_INFO(TAG, "SPIFFS image found: %s", spiffs_image_filename); + result = program_image(spiffs_image_filename, IMAGE_TYPE_SPIFFS); + free(spiffs_image_filename); + } + + if ((app_image_filename == NULL) && (spiffs_image_filename == NULL)) + { + KLOG_ERROR(TAG, "Reprogramming failed--there's nothing to reprogram!"); + result = SYSTEMK_RESULT_FILE_NOT_FOUND; + } + + return result; +} + +static void Reprogramming_Task(void *pvParameters) +{ + SystemKResult_T result = Maybe_Reprogram_From_USB(); + static All_On_Data_T data; + + if (result == SYSTEMK_RESULT_SUCCESS) + { + KLOG_INFO(TAG, "Reprogramming succeeded--rebooting..."); + data.color = ApplyMask(COLOR_GREEN, 0x70); + data.style = DISPLAY_STYLE_SOLID; + } + else + { + KLOG_ERROR(TAG, "Reprogramming failed--rebooting..."); + data.color = ApplyMask(COLOR_RED, 0x70); + data.style = DISPLAY_STYLE_SOLID; + } + + NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_ALL_ON, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)&data}; + xQueueSend(xQueueNeoPixels, &neopixels_action, 0); + vTaskDelay(5000 / portTICK_PERIOD_MS); + esp_restart(); + + vTaskDelete(NULL); +} + +void Request_Reprogramming_From_USB(void) +{ + if (xReprogrammingTask == NULL) + { + KLOG_INFO(TAG, "Attempting USB reprogramming..."); + + xReprogrammingTask = xTaskCreateStaticPinnedToCore( + Reprogramming_Task, + "Reprogramming", + sizeof(xReprogrammingTaskStack) / sizeof(StackType_t), + NULL, + REPROGRAMMING_TASK_PRIORITY, + xReprogrammingTaskStack, + &xReprogrammingTaskBuffer, + APP_CPU_NUM); + } + else + { + KLOG_WARN(TAG, "Reprogramming already in progress."); + } +} \ No newline at end of file diff --git a/components/Reprogramming/Reprogramming.h b/components/Reprogramming/Reprogramming.h new file mode 100644 index 0000000..16c1a09 --- /dev/null +++ b/components/Reprogramming/Reprogramming.h @@ -0,0 +1,22 @@ +/* + * This program source code file is part of the KTag project. + * + * 🛡️ 🃞 + * + * Copyright © 2024-2025 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +void Request_Reprogramming_From_USB(void); \ No newline at end of file diff --git a/components/Switches/CMakeLists.txt b/components/Switches/CMakeLists.txt new file mode 100644 index 0000000..79cfb03 --- /dev/null +++ b/components/Switches/CMakeLists.txt @@ -0,0 +1,10 @@ +idf_component_register( + SRCS + "Switches.c" + INCLUDE_DIRS + "." + REQUIRES + "SystemK" + "driver" + "button" +) diff --git a/components/Switches/Switches.c b/components/Switches/Switches.c new file mode 100644 index 0000000..7450ed7 --- /dev/null +++ b/components/Switches/Switches.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include + +static const char *TAG = "Switches"; + +// GPIO assignments +#define TRIGGER_GPIO GPIO_NUM_1 +#define ACCESSORY_GPIO GPIO_NUM_4 + +static button_handle_t Trigger_Button; +static button_config_t Trigger_Button_Config = { + .type = BUTTON_TYPE_GPIO, + .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS, + .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS, + .gpio_button_config = { + .gpio_num = TRIGGER_GPIO, + .active_level = 0, + }, +}; + +static button_handle_t Accessory_Button; +static button_config_t Accessory_Button_Config = { + .type = BUTTON_TYPE_GPIO, + .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS, + .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS, + .gpio_button_config = { + .gpio_num = ACCESSORY_GPIO, + .active_level = 0, + }, +}; + +static TickType_t TicksAtTriggerPress = 0; +static TickType_t TicksAtAccessoryPress = 0; +static TickType_t TicksAtAccessoryRelease = 0; + +static void trigger_press_cb(void *arg, void *usr_data) +{ + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + TicksAtTriggerPress = xTaskGetTickCountFromISR(); + KEvent_T switch_event = {.ID = KEVENT_TRIGGER_SWITCH_PRESSED, .Data = NULL}; + Post_KEvent_From_ISR(&switch_event, &xHigherPriorityTaskWoken); +} + +static void trigger_release_cb(void *arg, void *usr_data) +{ + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + uint32_t triggerPressDurationInms = pdTICKS_TO_MS(xTaskGetTickCountFromISR() - TicksAtTriggerPress); + KEvent_T switch_event = {.ID = KEVENT_TRIGGER_SWITCH_RELEASED, .Data = (void *) triggerPressDurationInms}; + Post_KEvent_From_ISR(&switch_event, &xHigherPriorityTaskWoken); +} + +static void accessory_press_cb(void *arg, void *usr_data) +{ + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + TicksAtAccessoryPress = xTaskGetTickCountFromISR(); + uint32_t accessoryTimeReleasedInms = pdTICKS_TO_MS(xTaskGetTickCountFromISR() - TicksAtAccessoryRelease); + KEvent_T switch_event = {.ID = KEVENT_ACCESSORY_SWITCH_PRESSED, .Data = (void *) accessoryTimeReleasedInms}; + Post_KEvent_From_ISR(&switch_event, &xHigherPriorityTaskWoken); +} + +static void accessory_release_cb(void *arg, void *usr_data) +{ + portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + TicksAtAccessoryRelease = xTaskGetTickCountFromISR(); + uint32_t accessoryPressDurationInms = pdTICKS_TO_MS(xTaskGetTickCountFromISR() - TicksAtAccessoryPress); + KEvent_T switch_event = {.ID = KEVENT_ACCESSORY_SWITCH_RELEASED, .Data = (void *) accessoryPressDurationInms}; + Post_KEvent_From_ISR(&switch_event, &xHigherPriorityTaskWoken); +} + +void Initialize_Switches(void) +{ + KLOG_INFO(TAG, "Initializing Switches..."); + + Trigger_Button = iot_button_create(&Trigger_Button_Config); + assert(Trigger_Button); + + Accessory_Button = iot_button_create(&Accessory_Button_Config); + assert(Accessory_Button); + + iot_button_register_cb(Trigger_Button, BUTTON_PRESS_DOWN, trigger_press_cb, NULL); + iot_button_register_cb(Trigger_Button, BUTTON_PRESS_UP, trigger_release_cb, NULL); + + iot_button_register_cb(Accessory_Button, BUTTON_PRESS_DOWN, accessory_press_cb, NULL); + iot_button_register_cb(Accessory_Button, BUTTON_PRESS_UP, accessory_release_cb, NULL); +} diff --git a/components/Switches/Switches.h b/components/Switches/Switches.h new file mode 100644 index 0000000..6d1bc5b --- /dev/null +++ b/components/Switches/Switches.h @@ -0,0 +1,2 @@ + +void Initialize_Switches(void); diff --git a/components/SystemK b/components/SystemK new file mode 160000 index 0000000..6f51f5b --- /dev/null +++ b/components/SystemK @@ -0,0 +1 @@ +Subproject commit 6f51f5b006db81d75dd752456be264bc50ce1b9b diff --git a/components/WiFi/CMakeLists.txt b/components/WiFi/CMakeLists.txt new file mode 100644 index 0000000..5f0e679 --- /dev/null +++ b/components/WiFi/CMakeLists.txt @@ -0,0 +1,20 @@ +idf_component_register( + SRCS + "WiFi.c" + INCLUDE_DIRS + "." + REQUIRES + "SystemK" + "esp_wifi" + "nvs_flash" + "esp_netif" + "esp_http_client" + "esp_event" + "esp_system" + "freertos" + "esp-tls" + "wifi_provisioning" + "esp_https_ota" + "app_update" + "NVM" +) diff --git a/components/WiFi/WiFi.c b/components/WiFi/WiFi.c new file mode 100644 index 0000000..bbb09aa --- /dev/null +++ b/components/WiFi/WiFi.c @@ -0,0 +1,253 @@ +#include +#include +#include "esp_log.h" +#include "nvs_flash.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_event.h" + +#include +#include "esp_wifi.h" +#include "esp_http_client.h" +#include "esp_tls.h" +#include "esp_https_ota.h" +#include "esp_ota_ops.h" +#include "esp_crt_bundle.h" + +#include "USB.h" +#include "Key_Value.h" + +static const char *TAG = "WiFi"; + +static EventGroupHandle_t s_wifi_event_group; +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +#define KTAG_WIFI_TASK_PRIORITY 2 +static TaskHandle_t xWiFiTask = NULL; +static StaticTask_t xWiFiTaskBuffer; +static StackType_t xWiFiTaskStack[4096]; + +static void event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + KLOG_INFO(TAG, "Connecting to the WiFi Access Point..."); + esp_wifi_connect(); + } + else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) + { + KLOG_INFO(TAG, "Connected to the WiFi Access Point!"); + } + else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + KLOG_WARN(TAG, "Failed to connect to the WiFi Access Point!"); + xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); + } + else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; + KLOG_INFO(TAG, "Got an IP address:" IPSTR, IP2STR(&event->ip_info.ip)); + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + } + else + { + KLOG_WARN(TAG, "Unhandled event: %s %ld", event_base, event_id); + } +} + +esp_err_t _http_event_handler(esp_http_client_event_t *evt) +{ + switch (evt->event_id) + { + case HTTP_EVENT_ERROR: + KLOG_DEBUG(TAG, "HTTP_EVENT_ERROR"); + break; + case HTTP_EVENT_ON_CONNECTED: + KLOG_DEBUG(TAG, "HTTP_EVENT_ON_CONNECTED"); + break; + case HTTP_EVENT_HEADER_SENT: + KLOG_DEBUG(TAG, "HTTP_EVENT_HEADER_SENT"); + break; + case HTTP_EVENT_ON_HEADER: + KLOG_DEBUG(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value); + break; + case HTTP_EVENT_ON_DATA: + KLOG_DEBUG(TAG, "HTTP_EVENT_ON_DATA, %.*s", evt->data_len, (char *)evt->data); + break; + case HTTP_EVENT_ON_FINISH: + KLOG_DEBUG(TAG, "HTTP_EVENT_ON_FINISH"); + break; + case HTTP_EVENT_DISCONNECTED: + KLOG_DEBUG(TAG, "HTTP_EVENT_DISCONNECTED"); + break; + case HTTP_EVENT_REDIRECT: + KLOG_DEBUG(TAG, "HTTP_EVENT_REDIRECT"); + break; + } + return ESP_OK; +} + +bool wifi_init_sta(void) +{ + s_wifi_event_group = xEventGroupCreate(); + + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_create_default_wifi_sta(); + + esp_event_handler_instance_t instance_any_id; + esp_event_handler_instance_t instance_got_ip; + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + ESP_EVENT_ANY_ID, + &event_handler, + NULL, + &instance_any_id)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, + IP_EVENT_STA_GOT_IP, + &event_handler, + NULL, + &instance_got_ip)); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + wifi_config_t wifi_config = { + .sta = { + .failure_retry_cnt = 3, + }, + }; + + char STA_SSID[32]; + char STA_Password[64]; + + KV_Get_Value_string(CONFIG_FILE, "STA_SSID", STA_SSID); + KV_Get_Value_string(CONFIG_FILE, "STA_Password", STA_Password); + + strlcpy((char *)wifi_config.sta.ssid, STA_SSID, sizeof(wifi_config.sta.ssid)); + strlcpy((char *)wifi_config.sta.password, STA_Password, sizeof(wifi_config.sta.password)); + + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + + // Wait until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum + // number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above). + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, + WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + if (bits & WIFI_CONNECTED_BIT) + { + KLOG_INFO(TAG, "Connected to AP with SSID: %s", wifi_config.sta.ssid); + return true; + } + else if (bits & WIFI_FAIL_BIT) + { + KLOG_WARN(TAG, "Failed to connect to SSID \"%s\"!", wifi_config.sta.ssid); + return false; + } + else + { + KLOG_ERROR(TAG, "Unexpected event!"); + return false; + } +} + +void download_test_file(void) +{ + esp_http_client_config_t config = { + .url = "https://ktag.clubk.club/2024A.txt", + .crt_bundle_attach = esp_crt_bundle_attach, + .event_handler = _http_event_handler}; + esp_http_client_handle_t client = esp_http_client_init(&config); + esp_err_t err = esp_http_client_perform(client); + + if (err == ESP_OK) + { + KLOG_INFO(TAG, "HTTPS Status = %d, content_length = %lld", + esp_http_client_get_status_code(client), + esp_http_client_get_content_length(client)); + } + else + { + KLOG_ERROR(TAG, "Error perform http request %s", esp_err_to_name(err)); + } + esp_http_client_cleanup(client); +} + +esp_http_client_config_t ota_http_config = { + .crt_bundle_attach = esp_crt_bundle_attach, + .event_handler = _http_event_handler, + .buffer_size = 8192, + .keep_alive_enable = true, + .timeout_ms = 30 * 1000}; + +esp_https_ota_config_t ota_config = { + .http_config = &ota_http_config, + .bulk_flash_erase = false, +}; + +static void WiFi_Task(void *pvParameters) +{ + if (wifi_init_sta()) + { + download_test_file(); + + vTaskDelay(5000 / portTICK_PERIOD_MS); + + const esp_partition_t *running = esp_ota_get_running_partition(); + esp_app_desc_t running_app_info; + if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) + { + KLOG_INFO(TAG, "Running firmware version: %s", running_app_info.version); + } + + ota_http_config.url = Get_OTA_Image_URL(); + + KLOG_INFO(TAG, "Attempting OTA reprogramming from %s", ota_http_config.url); + esp_log_level_set("wifi", ESP_LOG_VERBOSE); + + esp_err_t err = esp_https_ota(&ota_config); + if (err == ESP_OK) + { + Erase_OTA_File(); + KLOG_INFO(TAG, "OTA Succeed, Rebooting...\n"); + vTaskDelay(5000 / portTICK_PERIOD_MS); + esp_restart(); + } + else + { + KLOG_ERROR(TAG, "OTA Failed!\n"); + } + } + + vTaskDelete(NULL); +} + +void Initialize_WiFi(void) +{ + if (xWiFiTask == NULL) + { + KLOG_INFO(TAG, "Initializing WiFi..."); + + xWiFiTask = xTaskCreateStaticPinnedToCore( + WiFi_Task, + "KTag WiFI", + sizeof(xWiFiTaskStack) / sizeof(StackType_t), + NULL, + KTAG_WIFI_TASK_PRIORITY, + xWiFiTaskStack, + &xWiFiTaskBuffer, + APP_CPU_NUM); + } + else + { + KLOG_WARN(TAG, "WiFi already running."); + } +} diff --git a/components/WiFi/WiFi.h b/components/WiFi/WiFi.h new file mode 100644 index 0000000..5ba4f59 --- /dev/null +++ b/components/WiFi/WiFi.h @@ -0,0 +1 @@ +void Initialize_WiFi(void); diff --git a/dependencies.lock b/dependencies.lock new file mode 100644 index 0000000..03b4e56 --- /dev/null +++ b/dependencies.lock @@ -0,0 +1,87 @@ +dependencies: + chmorgan/esp-audio-player: + component_hash: c8ac1998e9af863bc41b57e592f88d1a5791a0f891485122336ddabbf7a65033 + dependencies: + - name: idf + require: private + version: '>=5.0' + - name: chmorgan/esp-libhelix-mp3 + registry_url: https://components.espressif.com + require: private + version: '>=1.0.0,<2.0.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.0.7 + chmorgan/esp-libhelix-mp3: + component_hash: cbb76089dc2c5749f7b470e2e70aedc44c9da519e04eb9a67d4c7ec275229e53 + dependencies: + - name: idf + require: private + version: '>=4.1.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.0.3 + espressif/button: + component_hash: 30a3f495c3862d505ce6e41adbbd218b2750e9723ab2151feff00e9fe685b326 + dependencies: + - name: espressif/cmake_utilities + registry_url: https://components.espressif.com + require: private + version: 0.* + - name: idf + require: private + version: '>=4.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 3.5.0 + espressif/cmake_utilities: + component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f + dependencies: + - name: idf + require: private + version: '>=4.1' + source: + registry_url: https://components.espressif.com + type: service + version: 0.5.3 + espressif/mdns: + component_hash: d36b265164be5139f92de993f08f5ecaa0de0c0acbf84deee1f10bb5902d04ff + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 1.4.3 + espressif/usb_host_msc: + component_hash: efbf44743b0f1f1f808697a671064531ae4661ccbce84632637261f8f670b375 + dependencies: + - name: idf + require: private + version: '>=4.4.1' + source: + registry_url: https://components.espressif.com/ + type: service + targets: + - esp32s2 + - esp32s3 + - esp32p4 + version: 1.1.3 + idf: + source: + type: idf + version: 5.4.0 +direct_dependencies: +- chmorgan/esp-audio-player +- chmorgan/esp-libhelix-mp3 +- espressif/button +- espressif/mdns +- espressif/usb_host_msc +- idf +manifest_hash: 49abffad73ef20c1e9924d5aece4befeab0cbad25b99f353334b089de1f63639 +target: esp32s3 +version: 2.0.0 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..9306f0b --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,14 @@ +idf_component_register( + SRCS + "HW_NeoPixels.c" + "main.c" + INCLUDE_DIRS + "." +) + +# Create a SPIFFS image from the contents of the 'spiffs_image' directory +# that fits the partition named 'spiffs'. FLASH_IN_PROJECT indicates that +# the generated image should be flashed when the entire project is flashed to +# the target with 'idf.py -p PORT flash'. +#spiffs_create_partition_image(spiffs ../spiffs_image FLASH_IN_PROJECT) +spiffs_create_partition_image(spiffs ../spiffs_image) diff --git a/main/HW_NeoPixels.c b/main/HW_NeoPixels.c new file mode 100644 index 0000000..3d7c584 --- /dev/null +++ b/main/HW_NeoPixels.c @@ -0,0 +1,230 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "HW_NeoPixels.h" + +#define NEOPIXELS_STACK_SIZE (100 * 1024) +#define NEOPIXELS_TASK_PRIORITY (tskIDLE_PRIORITY + 1) +static StaticTask_t xTaskBuffer; +StackType_t *xStack; +static TaskHandle_t xTaskHandle; + +static muxed_led_strip_handle_t NeoPixel_Out; + +// GPIO assignments +#define NEOPIXEL_OUT_GPIO GPIO_NUM_48 +#define BARREL_ENABLE_GPIO GPIO_NUM_18 +#define RECEIVER_ENABLE_GPIO GPIO_NUM_45 +#define DISPLAY_ENABLE_GPIO GPIO_NUM_10 +#define EFFECTS_ENABLE_GPIO GPIO_NUM_17 + +// 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) +#define LED_STRIP_RMT_RES_HZ (10 * 1000 * 1000) + +static const char *TAG = "NeoPixels"; + +static inline void Enable_Channel(NeoPixelsChannel_T channel) +{ + // The Enable lines are active low. + if (channel == NEOPIXEL_CHANNEL_ALL) + { + gpio_set_level(BARREL_ENABLE_GPIO, 0); + gpio_set_level(RECEIVER_ENABLE_GPIO, 0); + gpio_set_level(DISPLAY_ENABLE_GPIO, 0); + gpio_set_level(EFFECTS_ENABLE_GPIO, 0); + } + else if (channel < CONFIG_KTAG_N_NEOPIXEL_CHANNELS) + { + gpio_set_level(BARREL_ENABLE_GPIO, channel == NEOPIXEL_CHANNEL_BARREL ? 0 : 1); + gpio_set_level(RECEIVER_ENABLE_GPIO, channel == NEOPIXEL_CHANNEL_RECEIVER ? 0 : 1); + gpio_set_level(DISPLAY_ENABLE_GPIO, channel == NEOPIXEL_CHANNEL_DISPLAY ? 0 : 1); + gpio_set_level(EFFECTS_ENABLE_GPIO, channel == NEOPIXEL_CHANNEL_EFFECTS ? 0 : 1); + } + else + { + // Select none. + gpio_set_level(BARREL_ENABLE_GPIO, 1); + gpio_set_level(RECEIVER_ENABLE_GPIO, 1); + gpio_set_level(DISPLAY_ENABLE_GPIO, 1); + gpio_set_level(EFFECTS_ENABLE_GPIO, 1); + } +} + +static bool IRAM_ATTR rmt_tx_done_callback(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *edata, void *user_data) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + // Send a notification to the task that the current channel is complete. + xTaskNotifyIndexedFromISR(xTaskHandle, + 0, + 0, + eSetBits, + &xHigherPriorityTaskWoken); + + return xHigherPriorityTaskWoken; +} + +static rmt_tx_event_callbacks_t cbs = { + .on_trans_done = rmt_tx_done_callback, +}; + +static gpio_config_t barrel_enable_gpio_config = { + .pin_bit_mask = (1ULL << BARREL_ENABLE_GPIO), + .mode = GPIO_MODE_OUTPUT, // Set mode to output + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE}; + +static gpio_config_t receiver_enable_gpio_config = { + .pin_bit_mask = (1ULL << RECEIVER_ENABLE_GPIO), + .mode = GPIO_MODE_OUTPUT, // Set mode to output + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE}; + +static gpio_config_t display_enable_gpio_config = { + .pin_bit_mask = (1ULL << DISPLAY_ENABLE_GPIO), + .mode = GPIO_MODE_OUTPUT, // Set mode to output + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE}; + +static gpio_config_t effects_enable_gpio_config = { + .pin_bit_mask = (1ULL << EFFECTS_ENABLE_GPIO), + .mode = GPIO_MODE_OUTPUT, // Set mode to output + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE}; + +static muxed_led_strip_config_t neopixel_out_config = { + .strip_gpio_num = NEOPIXEL_OUT_GPIO, // The GPIO that connected to the LED strip's data line + .channels = CONFIG_KTAG_N_NEOPIXEL_CHANNELS, // The number of multiplexed channels + .max_leds = CONFIG_KTAG_MAX_NEOPIXELS_PER_CHANNEL, // The number of LEDs in the strip + .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip + .led_model = LED_MODEL_WS2812, // LED strip model + .flags.invert_out = false, // whether to invert the output signal +}; + +// From : +// +// The RMT module has eight channels, numbered from zero to seven. Each channel is able to independently +// transmit or receive signals. +// • Channel 0 ~ 3 (TX channel) are dedicated to sending signals. +// • Channel 4 ~ 7 (RX channel) are dedicated to receiving signals. +// Each TX/RX channel is controlled by a dedicated set of registers with the same functionality. Channel 3 and +// channel 7 support DMA access, so the two channels also have a set of DMA-related control and status registers + +static led_strip_rmt_config_t rmt_config_noDMA = { + .clk_src = RMT_CLK_SRC_XTAL, // different clock source can lead to different power consumption + .resolution_hz = LED_STRIP_RMT_RES_HZ, // RMT counter clock frequency + .flags.with_dma = false, // Only the last channel has the DMA capability +}; + +static led_strip_spi_config_t spi_config_withDMA __attribute__((unused)) = { + .clk_src = RMT_CLK_SRC_XTAL, // different clock source can lead to different power consumption + .flags.with_dma = true, // Using DMA can improve performance and help drive more LEDs + .spi_bus = SPI2_HOST, // SPI bus ID +}; + +void Initialize_SystemK_NeoPixels(SemaphoreHandle_t init_complete) +{ + xStack = (uint8_t *)heap_caps_calloc(1, NEOPIXELS_STACK_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT | MALLOC_CAP_32BIT); + + // Create the task without using any dynamic memory allocation. + xTaskHandle = xTaskCreateStaticPinnedToCore( + NeoPixels_Task, // Function that implements the task (this is part of SystemK). + "NeoPixels", // Text name for the task. + NEOPIXELS_STACK_SIZE, // Number of indexes in the xStack array. + NULL, // Parameter passed into the task. + NEOPIXELS_TASK_PRIORITY, // Priority at which the task is created. + xStack, // Array to use as the task's stack. + &xTaskBuffer, // Variable to hold the task's data structure. + APP_CPU_NUM); // Specify the task's core affinity. + + KLOG_INFO(TAG, "Initialization complete."); + + xSemaphoreGive(init_complete); +} + +SystemKResult_T HW_NeoPixels_Init(void) +{ + if (CONFIG_KTAG_N_NEOPIXEL_CHANNELS > 0) + { + // Initialize the NeoPixel Out and the Barrel Enable. + ESP_ERROR_CHECK(muxed_led_strip_new_rmt_device(&neopixel_out_config, &rmt_config_noDMA, &cbs, &NeoPixel_Out)); + KLOG_INFO(TAG, "Initialized NeoPixel Out as GPIO[%d].", NEOPIXEL_OUT_GPIO); + + ESP_ERROR_CHECK(gpio_config(&barrel_enable_gpio_config)); + KLOG_INFO(TAG, "Initialized barrel NeoPixel enable as GPIO[%d].", BARREL_ENABLE_GPIO); + } + if (CONFIG_KTAG_N_NEOPIXEL_CHANNELS > 1) + { + ESP_ERROR_CHECK(gpio_config(&receiver_enable_gpio_config)); + KLOG_INFO(TAG, "Initialized receiver NeoPixel enable as GPIO[%d].", RECEIVER_ENABLE_GPIO); + } + if (CONFIG_KTAG_N_NEOPIXEL_CHANNELS > 2) + { + ESP_ERROR_CHECK(gpio_config(&display_enable_gpio_config)); + KLOG_INFO(TAG, "Initialized display NeoPixel enable as GPIO[%d].", DISPLAY_ENABLE_GPIO); + } + if (CONFIG_KTAG_N_NEOPIXEL_CHANNELS > 3) + { + ESP_ERROR_CHECK(gpio_config(&effects_enable_gpio_config)); + KLOG_INFO(TAG, "Initialized effects NeoPixel enable as GPIO[%d].", EFFECTS_ENABLE_GPIO); + } + + return SYSTEMK_RESULT_SUCCESS; +} + +SystemKResult_T HW_NeoPixels_Set_RGB(NeoPixelsChannel_T channel, uint8_t position, uint8_t red, uint8_t green, uint8_t blue) +{ + if (channel < CONFIG_KTAG_N_NEOPIXEL_CHANNELS) + { + // TODO: Add code to account for RGB order in each channel. + ESP_ERROR_CHECK(muxed_led_strip_set_pixel(NeoPixel_Out, channel, position, red, green, blue)); + } + + return SYSTEMK_RESULT_SUCCESS; +} + +SystemKResult_T HW_NeoPixels_Publish(void) +{ + for (uint_fast8_t channel = 0; channel < CONFIG_KTAG_N_NEOPIXEL_CHANNELS; channel++) + { + uint32_t channel_complete; + Enable_Channel(channel); + ESP_ERROR_CHECK_WITHOUT_ABORT(muxed_led_strip_refresh(NeoPixel_Out, channel)); + xTaskNotifyWaitIndexed(0, /* Wait for 0th Notification */ + 0x00, /* Don't clear any bits on entry. */ + UINT32_MAX, /* Clear all bits on exit. */ + &channel_complete, /* Receives the notification value. */ + portMAX_DELAY); /* Block indefinitely. */ + // KLOG_INFO(TAG, "Published %lu.", channel_complete); + } + Enable_Channel(NEOPIXEL_CHANNEL_NONE); + + return SYSTEMK_RESULT_SUCCESS; +} + +color_t HW_NeoPixels_Get_My_Color(void) +{ + color_t result = COLOR_ORANGE; + + uint8_t Team_ID; + uint8_t Player_ID; + uint8_t Weapon_ID; + + (void) SETTINGS_get_uint8_t(SYSTEMK_SETTING_TEAMID, &Team_ID); + (void) SETTINGS_get_uint8_t(SYSTEMK_SETTING_PLAYERID, &Player_ID); + (void) SETTINGS_get_uint8_t(SYSTEMK_SETTING_WEAPONID, &Weapon_ID); + + result = PROTOCOLS_GetColor(GetWeaponFromID(Weapon_ID).Protocol, Team_ID, Player_ID); + + return result; +} diff --git a/main/HW_NeoPixels.h b/main/HW_NeoPixels.h new file mode 100644 index 0000000..33cadfd --- /dev/null +++ b/main/HW_NeoPixels.h @@ -0,0 +1,6 @@ +#ifndef HW_NEOPIXELS_H +#define HW_NEOPIXELS_H + +void Initialize_SystemK_NeoPixels(SemaphoreHandle_t init_complete); + +#endif // HW_NEOPIXELS_H \ No newline at end of file diff --git a/main/Version.h b/main/Version.h new file mode 100644 index 0000000..840d979 --- /dev/null +++ b/main/Version.h @@ -0,0 +1,11 @@ +#ifndef VERSION_H +#define VERSION_H + +#define VERSION_MAJOR 00 +#define VERSION_MINOR 38 + +#define STRINGIFY(number) #number +#define VERSION_STRING(major, minor) STRINGIFY(major) "." STRINGIFY(minor) +#define VERSION_AS_STR() "Version " VERSION_STRING(VERSION_MAJOR, VERSION_MINOR) " " __DATE__ " " __TIME__ + +#endif // VERSION_H \ No newline at end of file diff --git a/main/idf_component.yml b/main/idf_component.yml new file mode 100644 index 0000000..7df02e9 --- /dev/null +++ b/main/idf_component.yml @@ -0,0 +1,24 @@ +## IDF Component Manager Manifest File +dependencies: + chmorgan/esp-libhelix-mp3: "^1.0.3" + chmorgan/esp-audio-player: "^1.0.7" + espressif/button: "^3.3.1" + espressif/mdns: "^1.3.2" + espressif/usb_host_msc: "^1.1.2" + + ## Required IDF version (>=5.1 is required for the SPI backend of the led-strip component.) + ## We tested with 5.4.0. + idf: + version: ">=5.4.0" + + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: "~1.0.0" + # # For 3rd party components: + # username/component: ">=1.0.0,<2.0.0" + # username2/component2: + # version: "~1.0.0" + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect dependencies of the `main` component. + # # All dependencies of `main` are public by default. + # public: true diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..efe47bf --- /dev/null +++ b/main/main.c @@ -0,0 +1,140 @@ +// KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKKKKKKKKKKKky+.`/ykKKKKKKKKKKKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKKKKKKKds/. -+o:` ./sdNKKKKKKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKNds+-` `-+hNKKKKNho:` `-+shNKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKNkhyo+:. `-/sdNKKKKKKKKKKKKKky+:` .-/oyhdNKKKKKKKKKK +// KKys++:-.````.-:+oykNKKKKKKKKKKKKKKKKKKKKKKNkhs+/-.````.-:/+syKK +// KK -/+osydkNNNKKKkkkkkkkNKKKKKKKKKKKkkkkkkkkNKKKKNNkdhyso/: KK +// KK sKKKKKKKKKKKKK```````/KKKKKKKKKd-```````:kKKKKKKKKKKKKKd `KK +// KK- oKKKKKKKKKKKKK :KKKKKKKKo` `oNKKKKKKKKKKKKKKh :KK +// KK/ +KKKKKKKKKKKKK :KKKKKKd- -dKKKKKKKKKKKKKKKKy /KK +// KK+ /KKKKKKKKKKKKK :KKKKKs` +NKKKKKKKKKKKKKKKKKs +KK +// KKo :KKKKKKKKKKKKK :KKKk: .hKKKKKKKKKKKKKKKKKKKo oKK +// KKy -KKKKKKKKKKKKK :KKy` +NKKKKKKKKKKKKKKKKKKKK/ yKK +// KKd `KKKKKKKKKKKKK :k/ .hKKKKKKKKKKKKKKKKKKKKKK: dKK +// KKN NKKKKKKKKKKKK .. /kKKKKKKKKKKKKKKKKKKKKKKK. NKK +// KKK. dKKKKKKKKKKKK .yKKKKKKKKKKKKKKKKKKKKKKKKN .KKK +// KKK+ oKKKKKKKKKKKK -kKKKKKKKKKKKKKKKKKKKKKKKKKh +KKK +// KKKd .KKKKKKKKKKKK `sNKKKKKKKKKKKKKKKKKKKKKKKK/ dKKK +// KKKK: hKKKKKKKKKKK :kKKKKKKKKKKKKKKKKKKKKKKk :KKKK +// KKKKh -KKKKKKKKKKK `` .yKKKKKKKKKKKKKKKKKKKKK+ hKKKK +// KKKKK/ yKKKKKKKKKK T :d: /kKKKKKKKKKKKKKKKKKKk`:KKKKK +// KKKKKk`.NKKKKKKKKK :KNo` .hKKKKKKKKKKKKKKKKK:`kKKKKK +// KKKKKKy /KKKKKKKKK A :KKKd- +NKKKKKKKKKKKKKKo yKKKKKK +// KKKKKKK+ oKKKKKKKK :KKKKN+` -hKKKKKKKKKKKKy`+KKKKKKK +// KKKKKKKN/ sKKKKKKK G :KKKKKKh. `oNKKKKKKKKKh`/KKKKKKKK +// KKKKKKKKN/`sKKKKKK :KKKKKKKN/ -dKKKKKKKh`/NKKKKKKKK +// KKKKKKKKKK+ +NKKKK :KKKKKKKKKy. `sNKKKKs`+KKKKKKKKKK +// KKKKKKKKKKKs`:kKKK-------+KKKKKKKKKKk/--------oKKN+`sKKKKKKKKKKK +// KKKKKKKKKKKKh..yKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKd--dKKKKKKKKKKKK +// KKKKKKKKKKKKKN+`/kKKKKKKKKKKKKKKKKKKKKKKKKKKKKNo`+NKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKh-`sNKKKKKKKKKKKKKKKKKKKKKKKKNy.-hKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKs..sNKKKKKKKKKKKKKKKKKKKKNy-.yKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKNs..okKKKKKKKKKKKKKKKKNs-.sNKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKKKKy-`/hKKKKKKKKKKKKd+`-yKKKKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKKKKKKd/`.odKKKKKKks-`/dKKKKKKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKKKKKKKKNs: .+yy+-`:sNKKKKKKKKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKKKKKKKKKKKNy/..+yNKKKKKKKKKKKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK +// KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nvs_flash.h" +#include "HW_NeoPixels.h" +#include "Version.h" +#include "Reprogramming.h" + +static const char *TAG = "KTag 2024A"; +static SemaphoreHandle_t init_complete_semaphore; +static const uint16_t INITIALIZATION_TIMEOUT_IN_ms = 10 * 1000; + +void app_main(void) +{ + KLOG_INFO(TAG, VERSION_AS_STR()); + + KLOG_INFO(TAG, "Initializing app..."); + init_complete_semaphore = xSemaphoreCreateBinary(); + + // Initialize NVS — it is used by both the BLE and WiFi drivers. + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + Initialize_SPIFFS(init_complete_semaphore); + if (xSemaphoreTake(init_complete_semaphore, pdMS_TO_TICKS(INITIALIZATION_TIMEOUT_IN_ms)) != pdTRUE) + { + KLOG_ERROR(TAG, "Timeout initializing SPIFFS!"); + } + + Initialize_USB(init_complete_semaphore); + if (xSemaphoreTake(init_complete_semaphore, pdMS_TO_TICKS(INITIALIZATION_TIMEOUT_IN_ms)) != pdTRUE) + { + KLOG_ERROR(TAG, "Timeout initializing USB!"); + } + + if (OTA_File_Exists() == true) + { + KLOG_INFO(TAG, "Attempting OTA reprogramming from %s.", Get_OTA_Image_URL()); + KLOG_WARN(TAG, "This does not work reliably...use USB."); + Initialize_WiFi(); + } + else + { + Initialize_Audio(); + + Initialize_SystemK_NeoPixels(init_complete_semaphore); + if (xSemaphoreTake(init_complete_semaphore, pdMS_TO_TICKS(INITIALIZATION_TIMEOUT_IN_ms)) != pdTRUE) + { + KLOG_ERROR(TAG, "Timeout initializing NeoPixels!"); + } + + Initialize_BLE(); + + Initialize_IR(init_complete_semaphore); + if (xSemaphoreTake(init_complete_semaphore, pdMS_TO_TICKS(INITIALIZATION_TIMEOUT_IN_ms)) != pdTRUE) + { + KLOG_ERROR(TAG, "Timeout initializing IR!"); + } + if (Initialize_SystemK() != SYSTEMK_RESULT_SUCCESS) + { + KLOG_ERROR(TAG, "Error initializing SystemK!"); + } + + // Initialize the switches after SystemK, so xQueueEvents will have already been created. + Initialize_Switches(); + + vSemaphoreDelete(init_complete_semaphore); + KLOG_INFO(TAG, "Initialization complete."); + } + + while (true) + { + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +SystemKResult_T HW_Execute_Console_Command(const uint8_t *const command) +{ + SystemKResult_T result = SYSTEMK_RESULT_NOT_IMPLEMENTED; + + if (strncmp((const char *)command, "reprogram", 9) == 0) + { + Request_Reprogramming_From_USB(); + result = SYSTEMK_RESULT_SUCCESS; + } + + return result; +} diff --git a/managed_components/chmorgan__esp-audio-player/.component_hash b/managed_components/chmorgan__esp-audio-player/.component_hash new file mode 100644 index 0000000..fcf65be --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/.component_hash @@ -0,0 +1 @@ +c8ac1998e9af863bc41b57e592f88d1a5791a0f891485122336ddabbf7a65033 \ No newline at end of file diff --git a/managed_components/chmorgan__esp-audio-player/CMakeLists.txt b/managed_components/chmorgan__esp-audio-player/CMakeLists.txt new file mode 100644 index 0000000..e9c414e --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/CMakeLists.txt @@ -0,0 +1,27 @@ + +set(srcs + "audio_player.cpp" +) + +set(includes + "include" +) + +set(requires "") + +if(CONFIG_AUDIO_PLAYER_ENABLE_MP3) + list(APPEND srcs "audio_mp3.cpp") +endif() + +# TODO: move inside of the 'if(CONFIG_AUDIO_PLAYER_ENABLE_MP3)' when everything builds correctly +list(APPEND requires "esp-libhelix-mp3") + +if(CONFIG_AUDIO_PLAYER_ENABLE_WAV) + list(APPEND srcs "audio_wav.cpp") +endif() + +idf_component_register(SRCS "${srcs}" + REQUIRES "${requires}" + INCLUDE_DIRS "${includes}" + REQUIRES driver +) diff --git a/managed_components/chmorgan__esp-audio-player/Kconfig b/managed_components/chmorgan__esp-audio-player/Kconfig new file mode 100644 index 0000000..906d81c --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/Kconfig @@ -0,0 +1,20 @@ +menu "Audio playback" + + config AUDIO_PLAYER_ENABLE_MP3 + bool "Enable mp3 decoding." + default y + help + The audio player can play mp3 files using libhelix-mp3. + config AUDIO_PLAYER_ENABLE_WAV + bool "Enable wav file playback" + default y + help + Audio player can decode wave files. + + config AUDIO_PLAYER_LOG_LEVEL + int "Audio Player log level (0 none - 3 highest)" + default 0 + range 0 3 + help + Specify the verbosity of Audio Player log output. +endmenu \ No newline at end of file diff --git a/managed_components/chmorgan__esp-audio-player/LICENSE b/managed_components/chmorgan__esp-audio-player/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/LICENSE @@ -0,0 +1,201 @@ + 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 [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 + + 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. diff --git a/managed_components/chmorgan__esp-audio-player/README.md b/managed_components/chmorgan__esp-audio-player/README.md new file mode 100644 index 0000000..3740ca2 --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/README.md @@ -0,0 +1,80 @@ +# Audio player component for esp32 + + +[![cppcheck-action](https://github.com/chmorgan/esp-audio-player/actions/workflows/cppcheck.yml/badge.svg)](https://github.com/chmorgan/esp-audio-player/actions/workflows/cppcheck.yml) + +## Capabilities + +* MP3 decoding (via libhelix-mp3) +* Wav/wave file decoding + +## Who is this for? + +Decode only audio playback on esp32 series of chips, where the features and footprint of esp-adf are not +necessary. + +## What about esp-adf? + +This component is not intended to compete with esp-adf, a much more fully developed +audio framework. + +It does however have a number of advantages at the moment including: + +* Fully open source (esp-adf has a number of binary modules at the moment) +* Minimal size (it's less capable, but also simpler, than esp-adf) + +## Getting started + +### Examples + +* [esp-box mp3_demo](https://github.com/espressif/esp-box/tree/master/examples/mp3_demo) uses esp-audio-player. +* The [test example](https://github.com/chmorgan/esp-audio-player/tree/main/test) is a simpler example than mp3_demo that also uses the esp-box hardware. + +### How to use this? +[esp-audio-player is a component](https://components.espressif.com/components/chmorgan/esp-audio-player) on the [Espressif component registry](https://components.espressif.com). + +In your project run: +``` +idf.py add-dependency chmorgan/esp-audio-player +``` + +to add the component dependency to the project's manifest file. + + +## Dependencies + +For MP3 support you'll need the [esp-libhelix-mp3](https://github.com/chmorgan/esp-libhelix-mp3) component. + +## Tests + +Unity tests are implemented in the [test/](../test) folder. + +## States + +```mermaid +stateDiagram-v2 + [*] --> Idle : new(), cb(IDLE) + Idle --> Playing : play(), cb(PLAYING) + Playing --> Paused : pause(), cb(PAUSE) + Paused --> Playing : resume(), cb(PLAYING) + Playing --> Playing : play(), cb(COMPLETED_PLAYING_NEXT) + Paused --> Idle : stop(), cb(IDLE) + Playing --> Idle : song complete, cb(IDLE) + [*] --> Shutdown : delete(), cb(SHUTDOWN) + Shutdown --> Idle : new(), cb(IDLE) +``` + +Note: Diagram shortens callbacks from AUDIO_PLAYER_EVENT_xxx to xxx, and functions from audio_player_xxx() to xxx(), for clarity. + + +## Release process - Pushing component to the IDF Component Registry + +The github workflow, .github/workflows/esp_upload_component.yml, pushes data to the espressif +[IDF component registry](https://components.espressif.com). + +To push a new version: + +* Apply a git tag via 'git tag vA.B.C' +* Push tags via 'git push --tags' + +The github workflow *should* run and automatically push to the IDF component registry. diff --git a/managed_components/chmorgan__esp-audio-player/audio_decode_types.h b/managed_components/chmorgan__esp-audio-player/audio_decode_types.h new file mode 100644 index 0000000..1e6509f --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/audio_decode_types.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +typedef enum { + DECODE_STATUS_CONTINUE, /*< data remaining, call decode again */ + DECODE_STATUS_NO_DATA_CONTINUE, /*< data remaining but none in this call */ + DECODE_STATUS_DONE, /*< no data remaining to decode */ + DECODE_STATUS_ERROR /*< unrecoverable error */ +} DECODE_STATUS; + +typedef struct { + int sample_rate; + uint32_t bits_per_sample; + uint32_t channels; +} format; + +/** + * Decoded audio data ready for playback + * + * Fields in this structure are expected to be updated + * upon each cycle of the decoder, as the decoder stores + * audio data to be played back. + */ +typedef struct { + /** + * NOTE: output_samples is flushed each decode cycle + * + * NOTE: the decode format determines how to convert samples to frames, ie. + * whether these samples are stero or mono samples and what the bits per sample are + */ + uint8_t *samples; + + /** capacity of samples */ + size_t samples_capacity; + + /** + * 2x samples_capacity to allow for in-place conversion of + * mono to stereo + */ + size_t samples_capacity_max; + + /** + * Number of frames in samples, + * Note that each frame consists of 'fmt.channels' number of samples, + * for example for stereo output the number of samples is 2x the + * frame count. + */ + size_t frame_count; + + format fmt; +} decode_data; + + +#define BYTES_IN_WORD 2 +#define BITS_PER_BYTE 8 diff --git a/managed_components/chmorgan__esp-audio-player/audio_log.h b/managed_components/chmorgan__esp-audio-player/audio_log.h new file mode 100644 index 0000000..81da67c --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/audio_log.h @@ -0,0 +1,26 @@ +#pragma once + +#include "esp_log.h" + +#if CONFIG_AUDIO_PLAYER_LOG_LEVEL >= 1 +#define LOGI_1(FMT, ...) \ + ESP_LOGI(TAG, "[1] " FMT, ##__VA_ARGS__) +#else +#define LOGI_1(FMT, ...) { (void)TAG; } +#endif + +#if CONFIG_AUDIO_PLAYER_LOG_LEVEL >= 2 +#define LOGI_2(FMT, ...) \ + ESP_LOGI(TAG, "[2] " FMT, ##__VA_ARGS__) +#else +#define LOGI_2(FMT, ...) { (void)TAG;} +#endif + +#if CONFIG_AUDIO_PLAYER_LOG_LEVEL >= 3 +#define LOGI_3(FMT, ...) \ + ESP_LOGI(TAG, "[3] " FMT, ##__VA_ARGS__) +#define COMPILE_3(x) x +#else +#define LOGI_3(FMT, ...) { (void)TAG; } +#define COMPILE_3(x) {} +#endif diff --git a/managed_components/chmorgan__esp-audio-player/audio_mp3.cpp b/managed_components/chmorgan__esp-audio-player/audio_mp3.cpp new file mode 100644 index 0000000..1858bd0 --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/audio_mp3.cpp @@ -0,0 +1,169 @@ +#include +#include "audio_log.h" +#include "audio_mp3.h" + +static const char *TAG = "mp3"; + +bool is_mp3(FILE *fp) { + bool is_mp3_file = false; + + fseek(fp, 0, SEEK_SET); + + // see https://en.wikipedia.org/wiki/List_of_file_signatures + uint8_t magic[3]; + if(sizeof(magic) == fread(magic, 1, sizeof(magic), fp)) { + if((magic[0] == 0xFF) && + (magic[1] == 0xFB)) + { + is_mp3_file = true; + } else if((magic[0] == 0xFF) && + (magic[1] == 0xF3)) + { + is_mp3_file = true; + } else if((magic[0] == 0xFF) && + (magic[1] == 0xF2)) + { + is_mp3_file = true; + } else if((magic[0] == 0x49) && + (magic[1] == 0x44) && + (magic[2] == 0x33)) /* 'ID3' */ + { + fseek(fp, 0, SEEK_SET); + + /* Get ID3 head */ + mp3_id3_header_v2_t tag; + if (sizeof(mp3_id3_header_v2_t) == fread(&tag, 1, sizeof(mp3_id3_header_v2_t), fp)) { + if (memcmp("ID3", (const void *) &tag, sizeof(tag.header)) == 0) { + is_mp3_file = true; + } + } + } + } + + // seek back to the start of the file to avoid + // missing frames upon decode + fseek(fp, 0, SEEK_SET); + + return is_mp3_file; +} + +/** + * @return true if data remains, false on error or end of file + */ +DECODE_STATUS decode_mp3(HMP3Decoder mp3_decoder, FILE *fp, decode_data *pData, mp3_instance *pInstance) { + MP3FrameInfo frame_info; + + size_t unread_bytes = pInstance->bytes_in_data_buf - (pInstance->read_ptr - pInstance->data_buf); + + /* somewhat arbitrary trigger to refill buffer - should always be enough for a full frame */ + if (unread_bytes < 1.25 * MAINBUF_SIZE && !pInstance->eof_reached) { + uint8_t *write_ptr = pInstance->data_buf + unread_bytes; + size_t free_space = pInstance->data_buf_size - unread_bytes; + + /* move last, small chunk from end of buffer to start, + then fill with new data */ + memmove(pInstance->data_buf, pInstance->read_ptr, unread_bytes); + + size_t nRead = fread(write_ptr, 1, free_space, fp); + + pInstance->bytes_in_data_buf = unread_bytes + nRead; + pInstance->read_ptr = pInstance->data_buf; + + if ((nRead == 0) || feof(fp)) { + pInstance->eof_reached = true; + } + + LOGI_2("pos %ld, nRead %d, eof %d", ftell(fp), nRead, pInstance->eof_reached); + + unread_bytes = pInstance->bytes_in_data_buf; + } + + LOGI_3("data_buf 0x%p, read 0x%p", pInstance->data_buf, pInstance->read_ptr); + + if(unread_bytes == 0) { + LOGI_1("unread_bytes == 0, status done"); + return DECODE_STATUS_DONE; + } + + /* Find MP3 sync word from read buffer */ + int offset = MP3FindSyncWord(pInstance->read_ptr, unread_bytes); + + LOGI_2("unread %d, total %d, offset 0x%x(%d)", + unread_bytes, pInstance->bytes_in_data_buf, offset, offset); + + if (offset >= 0) { + COMPILE_3(int starting_unread_bytes = unread_bytes); + uint8_t *read_ptr = pInstance->read_ptr + offset; /*!< Data start point */ + unread_bytes -= offset; + LOGI_3("read 0x%p, unread %d", read_ptr, unread_bytes); + int mp3_dec_err = MP3Decode(mp3_decoder, &read_ptr, (int*)&unread_bytes, reinterpret_cast(pData->samples), +0); + + pInstance->read_ptr = read_ptr; + + if(mp3_dec_err == ERR_MP3_NONE) { + /* Get MP3 frame info */ + MP3GetLastFrameInfo(mp3_decoder, &frame_info); + + pData->fmt.sample_rate = frame_info.samprate; + pData->fmt.bits_per_sample = frame_info.bitsPerSample; + pData->fmt.channels = frame_info.nChans; + + pData->frame_count = (frame_info.outputSamps / frame_info.nChans); + + LOGI_3("mp3: channels %d, sr %d, bps %d, frame_count %d, processed %d", + pData->fmt.channels, + pData->fmt.sample_rate, + pData->fmt.bits_per_sample, + frame_info.outputSamps, + starting_unread_bytes - unread_bytes); + } else { + if (pInstance->eof_reached) { + ESP_LOGE(TAG, "status error %d, but EOF", mp3_dec_err); + return DECODE_STATUS_DONE; + } else if (mp3_dec_err == ERR_MP3_MAINDATA_UNDERFLOW) { + // underflow indicates MP3Decode should be called again + LOGI_1("underflow read ptr is 0x%p", read_ptr); + return DECODE_STATUS_NO_DATA_CONTINUE; + } else { + // NOTE: some mp3 files result in misdetection of mp3 frame headers + // and during decode these misdetected frames cannot be + // decoded + // + // Rather than give up on the file by returning + // DECODE_STATUS_ERROR, we ask the caller + // to continue to call us, by returning DECODE_STATUS_NO_DATA_CONTINUE. + // + // The invalid frame data is skipped over as a search for the next frame + // on the subsequent call to this function will start searching + // AFTER the misdetected frmame header, dropping the invalid data. + // + // We may want to consider a more sophisticated approach here at a later time. + ESP_LOGE(TAG, "status error %d", mp3_dec_err); + return DECODE_STATUS_NO_DATA_CONTINUE; + } + } + } else { + // if we are dropping data there were no frames decoded + pData->frame_count = 0; + + // drop an even count of words + size_t words_to_drop = unread_bytes / BYTES_IN_WORD; + size_t bytes_to_drop = words_to_drop * BYTES_IN_WORD; + + // if the unread bytes is less than BYTES_IN_WORD, we should drop any unread bytes + // to avoid the situation where the file could have a few extra bytes at the end + // of the file that isn't at least BYTES_IN_WORD and decoding would get stuck + if(unread_bytes < BYTES_IN_WORD) { + bytes_to_drop = unread_bytes; + } + + // shift the read_ptr to drop the bytes in the buffer + pInstance->read_ptr += bytes_to_drop; + + /* Sync word not found in frame. Drop data that was read until a word boundary */ + ESP_LOGE(TAG, "MP3 sync word not found, dropping %d bytes", bytes_to_drop); + } + + return DECODE_STATUS_CONTINUE; +} diff --git a/managed_components/chmorgan__esp-audio-player/audio_mp3.h b/managed_components/chmorgan__esp-audio-player/audio_mp3.h new file mode 100644 index 0000000..e1a247c --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/audio_mp3.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include "audio_decode_types.h" +#include "mp3dec.h" + +typedef struct { + char header[3]; /*!< Always "TAG" */ + char title[30]; /*!< Audio title */ + char artist[30]; /*!< Audio artist */ + char album[30]; /*!< Album name */ + char year[4]; /*!< Char array of year */ + char comment[30]; /*!< Extra comment */ + char genre; /*!< See "https://en.wikipedia.org/wiki/ID3" */ +} __attribute__((packed)) mp3_id3_header_v1_t; + +typedef struct { + char header[3]; /*!< Always "ID3" */ + char ver; /*!< Version, equals to3 if ID3V2.3 */ + char revision; /*!< Revision, should be 0 */ + char flag; /*!< Flag byte, use Bit[7..5] only */ + char size[4]; /*!< TAG size */ +} __attribute__((packed)) mp3_id3_header_v2_t; + +typedef struct { + // Constants below + uint8_t *data_buf; + + /** number of bytes in data_buf */ + size_t data_buf_size; + + // Values that change at runtime are below + + /** + * Total bytes in data_buf, + * not the number of bytes remaining after the read_ptr + */ + size_t bytes_in_data_buf; + + /** Pointer to read location in data_buf */ + uint8_t *read_ptr; + + // set to true if the end of file has been reached + bool eof_reached; +} mp3_instance; + +bool is_mp3(FILE *fp); +DECODE_STATUS decode_mp3(HMP3Decoder mp3_decoder, FILE *fp, decode_data *pData, mp3_instance *pInstance); diff --git a/managed_components/chmorgan__esp-audio-player/audio_player.cpp b/managed_components/chmorgan__esp-audio-player/audio_player.cpp new file mode 100644 index 0000000..731f813 --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/audio_player.cpp @@ -0,0 +1,608 @@ +/** + * @file + * @version 0.1 + * + * @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd. + * @copyright Copyright 2022 Chris Morgan + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "esp_check.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +#include "sdkconfig.h" + +#include "audio_player.h" + +#include "audio_wav.h" +#include "audio_mp3.h" + +static const char *TAG = "audio"; + +typedef enum { + AUDIO_PLAYER_REQUEST_NONE = 0, + AUDIO_PLAYER_REQUEST_PAUSE, /**< pause playback */ + AUDIO_PLAYER_REQUEST_RESUME, /**< resumed paused playback */ + AUDIO_PLAYER_REQUEST_PLAY, /**< initiate playing a new file */ + AUDIO_PLAYER_REQUEST_STOP, /**< stop playback */ + AUDIO_PLAYER_REQUEST_SHUTDOWN_THREAD, /**< shutdown audio playback thread */ + AUDIO_PLAYER_REQUEST_MAX +} audio_player_event_type_t; + +typedef struct { + audio_player_event_type_t type; + + // valid if type == AUDIO_PLAYER_EVENT_TYPE_PLAY + FILE* fp; +} audio_player_event_t; + +typedef enum { + FILE_TYPE_UNKNOWN, +#if defined(CONFIG_AUDIO_PLAYER_ENABLE_MP3) + FILE_TYPE_MP3, +#endif +#if defined(CONFIG_AUDIO_PLAYER_ENABLE_WAV) + FILE_TYPE_WAV +#endif +} FILE_TYPE; + +typedef struct audio_instance { + /** + * Set to true before task is created, false immediately before the + * task is deleted. + */ + bool running; + + decode_data output; + + QueueHandle_t event_queue; + + /* **************** AUDIO CALLBACK **************** */ + audio_player_cb_t s_audio_cb; + void *audio_cb_usrt_ctx; + audio_player_state_t state; + + audio_player_config_t config; + +#if defined(CONFIG_AUDIO_PLAYER_ENABLE_WAV) + wav_instance wav_data; +#endif + +#if defined(CONFIG_AUDIO_PLAYER_ENABLE_MP3) + HMP3Decoder mp3_decoder; + mp3_instance mp3_data; +#endif +} audio_instance_t; + +static audio_instance_t instance; + +audio_player_state_t audio_player_get_state() { + return instance.state; +} + +esp_err_t audio_player_callback_register(audio_player_cb_t call_back, void *user_ctx) +{ +#if CONFIG_IDF_TARGET_ARCH_XTENSA + ESP_RETURN_ON_FALSE(esp_ptr_executable(reinterpret_cast(call_back)), ESP_ERR_INVALID_ARG, + TAG, "Not a valid call back"); +#else + ESP_RETURN_ON_FALSE(reinterpret_cast(call_back), ESP_ERR_INVALID_ARG, + TAG, "Not a valid call back"); +#endif + instance.s_audio_cb = call_back; + instance.audio_cb_usrt_ctx = user_ctx; + + return ESP_OK; +} + +// This function is used in some optional logging functions so we don't want to +// have a cppcheck warning here +// cppcheck-suppress unusedFunction +const char* event_to_string(audio_player_callback_event_t event) { + switch(event) { + case AUDIO_PLAYER_CALLBACK_EVENT_IDLE: + return "AUDIO_PLAYER_CALLBACK_EVENT_IDLE"; + case AUDIO_PLAYER_CALLBACK_EVENT_COMPLETED_PLAYING_NEXT: + return "AUDIO_PLAYER_CALLBACK_EVENT_COMPLETED_PLAYING_NEXT"; + case AUDIO_PLAYER_CALLBACK_EVENT_PLAYING: + return "AUDIO_PLAYER_CALLBACK_EVENT_PLAYING"; + case AUDIO_PLAYER_CALLBACK_EVENT_PAUSE: + return "AUDIO_PLAYER_CALLBACK_EVENT_PAUSE"; + case AUDIO_PLAYER_CALLBACK_EVENT_SHUTDOWN: + return "AUDIO_PLAYER_CALLBACK_EVENT_SHUTDOWN"; + case AUDIO_PLAYER_CALLBACK_EVENT_UNKNOWN_FILE_TYPE: + return "AUDIO_PLAYER_CALLBACK_EVENT_UNKNOWN_FILE_TYPE"; + case AUDIO_PLAYER_CALLBACK_EVENT_UNKNOWN: + return "AUDIO_PLAYER_CALLBACK_EVENT_UNKNOWN"; + } + + return "unknown event"; +} + +static audio_player_callback_event_t state_to_event(audio_player_state_t state) { + audio_player_callback_event_t event = AUDIO_PLAYER_CALLBACK_EVENT_UNKNOWN; + + switch(state) { + case AUDIO_PLAYER_STATE_IDLE: + event = AUDIO_PLAYER_CALLBACK_EVENT_IDLE; + break; + case AUDIO_PLAYER_STATE_PAUSE: + event = AUDIO_PLAYER_CALLBACK_EVENT_PAUSE; + break; + case AUDIO_PLAYER_STATE_PLAYING: + event = AUDIO_PLAYER_CALLBACK_EVENT_PLAYING; + break; + case AUDIO_PLAYER_STATE_SHUTDOWN: + event = AUDIO_PLAYER_CALLBACK_EVENT_SHUTDOWN; + break; + }; + + return event; +} + +static void dispatch_callback(audio_instance_t *i, audio_player_callback_event_t event) { + LOGI_1("event '%s'", event_to_string(event)); + +#if CONFIG_IDF_TARGET_ARCH_XTENSA + if (esp_ptr_executable(reinterpret_cast(i->s_audio_cb))) { +#else + if (reinterpret_cast(i->s_audio_cb)) { +#endif + audio_player_cb_ctx_t ctx = { + .audio_event = event, + .user_ctx = i->audio_cb_usrt_ctx, + }; + i->s_audio_cb(&ctx); + } +} + +static void set_state(audio_instance_t *i, audio_player_state_t new_state) { + if(i->state != new_state) { + i->state = new_state; + audio_player_callback_event_t event = state_to_event(new_state); + dispatch_callback(i, event); + } +} + +static void audio_instance_init(audio_instance_t &i) { + i.event_queue = NULL; + i.s_audio_cb = NULL; + i.audio_cb_usrt_ctx = NULL; + i.state = AUDIO_PLAYER_STATE_IDLE; +} + +static esp_err_t mono_to_stereo(uint32_t output_bits_per_sample, decode_data &adata) +{ + size_t data = adata.frame_count * (output_bits_per_sample / BITS_PER_BYTE); + data *= 2; + + // do we have enough space in the output buffer to convert mono to stereo? + if(data > adata.samples_capacity_max) { + ESP_LOGE(TAG, "insufficient space in output.samples to convert mono to stereo, need %d, have %d", data, adata.samples_capacity_max); + return ESP_ERR_NO_MEM; + } + + size_t new_sample_count = adata.frame_count * 2; + + // convert from back to front to allow conversion in-place + // + // NOTE: -1 is because we want to shift to the sample at position X + // but if we do (ptr + X) we end up at the sample at index X instead + // which is one further + int16_t *out = reinterpret_cast(adata.samples) + (new_sample_count - 1); + int16_t *in = reinterpret_cast(adata.samples) + (adata.frame_count - 1); + size_t samples = adata.frame_count; + while(samples) { + // write right channel + *out = *in; + out--; + + // write left channel + *out = *in; + out--; + + // move input buffer back and decrement samples + in--; + samples--; + } + + // adjust channels to 2 + adata.fmt.channels = 2; + + return ESP_OK; +} + +static esp_err_t aplay_file(audio_instance_t *i, FILE *fp) +{ + LOGI_1("start to decode"); + + format i2s_format; + memset(&i2s_format, 0, sizeof(i2s_format)); + + esp_err_t ret = ESP_OK; + audio_player_event_t audio_event = { .type = AUDIO_PLAYER_REQUEST_NONE, .fp = NULL }; + + FILE_TYPE file_type = FILE_TYPE_UNKNOWN; + +#if defined(CONFIG_AUDIO_PLAYER_ENABLE_MP3) + if(is_mp3(fp)) { + file_type = FILE_TYPE_MP3; + LOGI_1("file is mp3"); + + // initialize mp3_instance + i->mp3_data.bytes_in_data_buf = 0; + i->mp3_data.read_ptr = i->mp3_data.data_buf; + i->mp3_data.eof_reached = false; + } +#endif + +#if defined(CONFIG_AUDIO_PLAYER_ENABLE_WAV) + // This can be a pointless condition depending on the build options, no reason to warn about it + // cppcheck-suppress knownConditionTrueFalse + if(file_type == FILE_TYPE_UNKNOWN) + { + if(is_wav(fp, &i->wav_data)) { + file_type = FILE_TYPE_WAV; + LOGI_1("file is wav"); + } + } +#endif + + // cppcheck-suppress knownConditionTrueFalse + if(file_type == FILE_TYPE_UNKNOWN) { + ESP_LOGE(TAG, "unknown file type, cleaning up"); + dispatch_callback(i, AUDIO_PLAYER_CALLBACK_EVENT_UNKNOWN_FILE_TYPE); + goto clean_up; + } + + do { + /* Process audio event sent from other task */ + if (pdPASS == xQueuePeek(i->event_queue, &audio_event, 0)) { + LOGI_2("event in queue"); + if (AUDIO_PLAYER_REQUEST_PAUSE == audio_event.type) { + // receive the pause event to take it off of the queue + xQueueReceive(i->event_queue, &audio_event, 0); + + set_state(i, AUDIO_PLAYER_STATE_PAUSE); + + // wait until an event is received that will cause playback to resume, + // stop, or change file + while(1) { + xQueuePeek(i->event_queue, &audio_event, portMAX_DELAY); + + if((AUDIO_PLAYER_REQUEST_PLAY != audio_event.type) && + (AUDIO_PLAYER_REQUEST_STOP != audio_event.type) && + (AUDIO_PLAYER_REQUEST_RESUME != audio_event.type)) + { + // receive to discard the event + xQueueReceive(i->event_queue, &audio_event, 0); + } else { + break; + } + } + + if(AUDIO_PLAYER_REQUEST_RESUME == audio_event.type) { + // receive to discard the event + xQueueReceive(i->event_queue, &audio_event, 0); + continue; + } + + // else fall out of this condition and let the below logic + // handle the other event types + } + + if ((AUDIO_PLAYER_REQUEST_STOP == audio_event.type) || + (AUDIO_PLAYER_REQUEST_PLAY == audio_event.type)) { + ret = ESP_OK; + goto clean_up; + } else { + // receive to discard the event, this event has no + // impact on the state of playback + xQueueReceive(i->event_queue, &audio_event, 0); + continue; + } + } + + set_state(i, AUDIO_PLAYER_STATE_PLAYING); + + DECODE_STATUS decode_status = DECODE_STATUS_ERROR; + + switch(file_type) { +#if defined(CONFIG_AUDIO_PLAYER_ENABLE_MP3) + case FILE_TYPE_MP3: + decode_status = decode_mp3(i->mp3_decoder, fp, &i->output, &i->mp3_data); + break; +#endif +#if defined(CONFIG_AUDIO_PLAYER_ENABLE_WAV) + case FILE_TYPE_WAV: + decode_status = decode_wav(fp, &i->output, &i->wav_data); + break; +#endif + case FILE_TYPE_UNKNOWN: + ESP_LOGE(TAG, "unexpected unknown file type when decoding"); + break; + } + + // break out and exit if we aren't supposed to continue decoding + if(decode_status == DECODE_STATUS_CONTINUE) + { + // if mono, convert to stereo as es8311 requires stereo input + // even though it is mono output + if(i->output.fmt.channels == 1) { + LOGI_3("c == 1, mono -> stereo"); + ret = mono_to_stereo(i->output.fmt.bits_per_sample, i->output); + if(ret != ESP_OK) { + goto clean_up; + } + } + + /* Configure I2S clock if the output format changed */ + if ((i2s_format.sample_rate != i->output.fmt.sample_rate) || + (i2s_format.channels != i->output.fmt.channels) || + (i2s_format.bits_per_sample != i->output.fmt.bits_per_sample)) { + i2s_format = i->output.fmt; + LOGI_1("format change: sr=%d, bit=%d, ch=%d", + i2s_format.sample_rate, + i2s_format.bits_per_sample, + i2s_format.channels); + i2s_slot_mode_t channel_setting = (i2s_format.channels == 1) ? I2S_SLOT_MODE_MONO : I2S_SLOT_MODE_STEREO; + ret = i->config.clk_set_fn(i2s_format.sample_rate, + i2s_format.bits_per_sample, + channel_setting); + ESP_GOTO_ON_ERROR(ret, clean_up, TAG, "i2s_set_clk"); + } + + /** + * Block until all data has been accepted into the i2s driver, however + * the i2s driver has been configured with a buffer to allow for the next round of + * audio decoding to occur while the previous set of samples is finishing playback, in order + * to ensure playback without interruption. + */ + size_t i2s_bytes_written = 0; + size_t bytes_to_write = i->output.frame_count * i->output.fmt.channels * (i2s_format.bits_per_sample / 8); + LOGI_2("c %d, bps %d, bytes %d, frame_count %d", + i->output.fmt.channels, + i2s_format.bits_per_sample, + bytes_to_write, + i->output.frame_count); + + i->config.write_fn(i->output.samples, bytes_to_write, &i2s_bytes_written, portMAX_DELAY); + if(bytes_to_write != i2s_bytes_written) { + ESP_LOGE(TAG, "to write %d != written %d", bytes_to_write, i2s_bytes_written); + } + } else if(decode_status == DECODE_STATUS_NO_DATA_CONTINUE) + { + LOGI_2("no data"); + } else { // DECODE_STATUS_DONE || DECODE_STATUS_ERROR + LOGI_1("breaking out of playback"); + break; + } + } while (true); + +clean_up: + return ret; +} + +static void audio_task(void *pvParam) +{ + audio_instance_t *i = static_cast(pvParam); + audio_player_event_t audio_event; + + while (true) { + // pull items off of the queue until we run into a PLAY request + while(true) { + // zero delay in the case where we are playing as we want to + // send an event indicating either + // PLAYING -> IDLE (IDLE) or PLAYING -> PLAYING (COMPLETED PLAYING NEXT) + // and thus don't want to block until the next request comes in + // in the case when there are no further requests pending + int delay = (i->state == AUDIO_PLAYER_STATE_PLAYING) ? 0 : portMAX_DELAY; + + int retval = xQueuePeek(i->event_queue, &audio_event, delay); + if (pdPASS == retval) { // item on the queue, process it + xQueueReceive(i->event_queue, &audio_event, 0); + + // if the item is a play request, process it + if(AUDIO_PLAYER_REQUEST_PLAY == audio_event.type) { + if(i->state == AUDIO_PLAYER_STATE_PLAYING) { + dispatch_callback(i, AUDIO_PLAYER_CALLBACK_EVENT_COMPLETED_PLAYING_NEXT); + } else { + set_state(i, AUDIO_PLAYER_STATE_PLAYING); + } + + break; + } else if(AUDIO_PLAYER_REQUEST_SHUTDOWN_THREAD == audio_event.type) { + set_state(i, AUDIO_PLAYER_STATE_SHUTDOWN); + i->running = false; + + // should never return + vTaskDelete(NULL); + break; + } else { + // ignore other events when not playing + } + } else { // no items on the queue + // if we are playing transition to idle and indicate the transition via callback + if(i->state == AUDIO_PLAYER_STATE_PLAYING) { + set_state(i, AUDIO_PLAYER_STATE_IDLE); + } + } + } + + i->config.mute_fn(AUDIO_PLAYER_UNMUTE); + esp_err_t ret_val = aplay_file(i, audio_event.fp); + if(ret_val != ESP_OK) + { + ESP_LOGE(TAG, "aplay_file() %d", ret_val); + } + i->config.mute_fn(AUDIO_PLAYER_MUTE); + + if(audio_event.fp) fclose(audio_event.fp); + } +} + +/* **************** AUDIO PLAY CONTROL **************** */ +static esp_err_t audio_send_event(audio_instance_t *i, audio_player_event_t event) { + ESP_RETURN_ON_FALSE(NULL != i->event_queue, ESP_ERR_INVALID_STATE, + TAG, "Audio task not started yet"); + + BaseType_t ret_val = xQueueSend(i->event_queue, &event, 0); + + ESP_RETURN_ON_FALSE(pdPASS == ret_val, ESP_ERR_INVALID_STATE, + TAG, "The last event has not been processed yet"); + + return ESP_OK; +} + +esp_err_t audio_player_play(FILE *fp) +{ + LOGI_1("%s", __FUNCTION__); + audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_PLAY, .fp = fp }; + return audio_send_event(&instance, event); +} + +esp_err_t audio_player_pause(void) +{ + LOGI_1("%s", __FUNCTION__); + audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_PAUSE, .fp = NULL }; + return audio_send_event(&instance, event); +} + +esp_err_t audio_player_resume(void) +{ + LOGI_1("%s", __FUNCTION__); + audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_RESUME, .fp = NULL }; + return audio_send_event(&instance, event); +} + +esp_err_t audio_player_stop(void) +{ + LOGI_1("%s", __FUNCTION__); + audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_STOP, .fp = NULL }; + return audio_send_event(&instance, event); +} + +/** + * Can only shut down the playback thread if the thread is not presently playing audio. + * Call audio_player_stop() + */ +static esp_err_t _internal_audio_player_shutdown_thread(void) +{ + LOGI_1("%s", __FUNCTION__); + audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_SHUTDOWN_THREAD, .fp = NULL }; + return audio_send_event(&instance, event); +} + +static void cleanup_memory(audio_instance_t &i) +{ +#if defined(CONFIG_AUDIO_PLAYER_ENABLE_MP3) + if(i.mp3_decoder) MP3FreeDecoder(i.mp3_decoder); + if(i.mp3_data.data_buf) free(i.mp3_data.data_buf); +#endif + if(i.output.samples) free(i.output.samples); + + vQueueDelete(i.event_queue); +} + +esp_err_t audio_player_new(audio_player_config_t config) +{ + BaseType_t task_val; + + audio_instance_init(instance); + + instance.config = config; + + /* Audio control event queue */ + instance.event_queue = xQueueCreate(4, sizeof(audio_player_event_t)); + ESP_RETURN_ON_FALSE(NULL != instance.event_queue, -1, TAG, "xQueueCreate"); + + /** See https://github.com/ultraembedded/libhelix-mp3/blob/0a0e0673f82bc6804e5a3ddb15fb6efdcde747cd/testwrap/main.c#L74 */ + instance.output.samples_capacity = MAX_NCHAN * MAX_NGRAN * MAX_NSAMP; + instance.output.samples_capacity_max = instance.output.samples_capacity * 2; + instance.output.samples = static_cast(malloc(instance.output.samples_capacity_max)); + LOGI_1("samples_capacity %d bytes", instance.output.samples_capacity_max); + int ret = ESP_OK; + ESP_GOTO_ON_FALSE(NULL != instance.output.samples, ESP_ERR_NO_MEM, cleanup, + TAG, "Failed allocate output buffer"); + +#if defined(CONFIG_AUDIO_PLAYER_ENABLE_MP3) + instance.mp3_data.data_buf_size = MAINBUF_SIZE * 3; + instance.mp3_data.data_buf = static_cast(malloc(instance.mp3_data.data_buf_size)); + ESP_GOTO_ON_FALSE(NULL != instance.mp3_data.data_buf, ESP_ERR_NO_MEM, cleanup, + TAG, "Failed allocate mp3 data buffer"); + + instance.mp3_decoder = MP3InitDecoder(); + ESP_GOTO_ON_FALSE(NULL != instance.mp3_decoder, ESP_ERR_NO_MEM, cleanup, + TAG, "Failed create MP3 decoder"); +#endif + + instance.running = true; + task_val = xTaskCreatePinnedToCore( + (TaskFunction_t) audio_task, + "Audio Task", + 4 * 1024, + &instance, + (UBaseType_t) instance.config.priority, + (TaskHandle_t * const) NULL, + (BaseType_t) instance.config.coreID); + + ESP_GOTO_ON_FALSE(pdPASS == task_val, ESP_ERR_NO_MEM, cleanup, + TAG, "Failed create audio task"); + + // start muted + instance.config.mute_fn(AUDIO_PLAYER_MUTE); + + return ret; + +// At the moment when we run cppcheck there is a lack of esp-idf header files this +// means cppcheck doesn't know that ESP_GOTO_ON_FALSE() etc are making use of this label +// cppcheck-suppress unusedLabelConfiguration +cleanup: + cleanup_memory(instance); + + return ret; +} + +esp_err_t audio_player_delete() { + const int MAX_RETRIES = 5; + int retries = MAX_RETRIES; + while(instance.running && retries) { + // stop any playback and shutdown the thread + audio_player_stop(); + _internal_audio_player_shutdown_thread(); + + vTaskDelay(pdMS_TO_TICKS(100)); + retries--; + } + + cleanup_memory(instance); + + // if we ran out of retries, return fail code + if(retries == 0) { + return ESP_FAIL; + } + + return ESP_OK; +} diff --git a/managed_components/chmorgan__esp-audio-player/audio_wav.cpp b/managed_components/chmorgan__esp-audio-player/audio_wav.cpp new file mode 100644 index 0000000..530b3b0 --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/audio_wav.cpp @@ -0,0 +1,81 @@ +#include +#include +#include "audio_wav.h" + +static const char *TAG = "wav"; + +/** + * @param fp + * @param pInstance - Values can be considered valid if true is returned + * @return true if file is a wav file + */ +bool is_wav(FILE *fp, wav_instance *pInstance) { + fseek(fp, 0, SEEK_SET); + + size_t bytes_read = fread(&pInstance->header, 1, sizeof(wav_header_t), fp); + if(bytes_read != sizeof(wav_header_t)) { + return false; + } + + wav_header_t *wav_head = &pInstance->header; + if((NULL == strstr(reinterpret_cast(wav_head->ChunkID), "RIFF")) || + (NULL == strstr(reinterpret_cast(wav_head->Format), "WAVE")) + ) + { + return false; + } + + // decode chunks until we find the 'data' one + wav_subchunk_header_t subchunk; + while(true) { + bytes_read = fread(&subchunk, 1, sizeof(wav_subchunk_header_t), fp); + if(bytes_read != sizeof(wav_subchunk_header_t)) { + return false; + } + + if(memcmp(subchunk.SubchunkID, "data", 4) == 0) + { + break; + } else { + // advance beyond this subchunk, it could be a 'LIST' chunk with file info or some other unhandled subchunk + fseek(fp, subchunk.SubchunkSize, SEEK_CUR); + } + } + + LOGI_2("sample_rate=%d, channels=%d, bps=%d", + wav_head->SampleRate, + wav_head->NumChannels, + wav_head->BitsPerSample); + + return true; +} + +/** + * @return true if data remains, false on error or end of file + */ +DECODE_STATUS decode_wav(FILE *fp, decode_data *pData, wav_instance *pInstance) { + // read an even multiple of frames that can fit into output_samples buffer, otherwise + // we would have to manage what happens with partial frames in the output buffer + size_t bytes_per_frame = (pInstance->header.BitsPerSample / BITS_PER_BYTE) * pInstance->header.NumChannels; + size_t frames_to_read = pData->samples_capacity / bytes_per_frame; + size_t bytes_to_read = frames_to_read * bytes_per_frame; + + size_t bytes_read = fread(pData->samples, 1, bytes_to_read, fp); + + pData->fmt.channels = pInstance->header.NumChannels; + pData->fmt.bits_per_sample = pInstance->header.BitsPerSample; + pData->fmt.sample_rate = pInstance->header.SampleRate; + + if(bytes_read != 0) + { + pData->frame_count = (bytes_read / (pInstance->header.BitsPerSample / BITS_PER_BYTE)) / pInstance->header.NumChannels; + } else { + pData->frame_count = 0; + } + + LOGI_2("bytes_per_frame %d, bytes_to_read %d, bytes_read %d, frame_count %d", + bytes_per_frame, bytes_to_read, bytes_read, + pData->frame_count); + + return (bytes_read == 0) ? DECODE_STATUS_DONE : DECODE_STATUS_CONTINUE; +} diff --git a/managed_components/chmorgan__esp-audio-player/audio_wav.h b/managed_components/chmorgan__esp-audio-player/audio_wav.h new file mode 100644 index 0000000..a7d9b2d --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/audio_wav.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include "audio_log.h" +#include "audio_decode_types.h" + +typedef struct { + // The "RIFF" chunk descriptor + uint8_t ChunkID[4]; + int32_t ChunkSize; + uint8_t Format[4]; + // The "fmt" sub-chunk + uint8_t Subchunk1ID[4]; + int32_t Subchunk1Size; + int16_t AudioFormat; + int16_t NumChannels; + int32_t SampleRate; + int32_t ByteRate; + int16_t BlockAlign; + int16_t BitsPerSample; +} wav_header_t; + +typedef struct { + // The "data" sub-chunk + uint8_t SubchunkID[4]; + int32_t SubchunkSize; +} wav_subchunk_header_t; + +typedef struct { + wav_header_t header; +} wav_instance; + +bool is_wav(FILE *fp, wav_instance *pInstance); +DECODE_STATUS decode_wav(FILE *fp, decode_data *pData, wav_instance *pInstance); diff --git a/managed_components/chmorgan__esp-audio-player/idf_component.yml b/managed_components/chmorgan__esp-audio-player/idf_component.yml new file mode 100644 index 0000000..c5501a9 --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/idf_component.yml @@ -0,0 +1,8 @@ +dependencies: + chmorgan/esp-libhelix-mp3: + version: '>=1.0.0,<2.0.0' + idf: + version: '>=5.0' +description: Lightweight audio decoding component for esp processors +url: https://github.com/chmorgan/esp-audio-player +version: 1.0.7 diff --git a/managed_components/chmorgan__esp-audio-player/include/audio_player.h b/managed_components/chmorgan__esp-audio-player/include/audio_player.h new file mode 100644 index 0000000..fd849f0 --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/include/audio_player.h @@ -0,0 +1,182 @@ +/** + * @file + * @version 0.1 + * + * @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd. + * @copyright Copyright 2022 Chris Morgan + * + * 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. + */ + +/** + * Design notes + * + * - There is a distinct event for playing -> playing state transitions. + * COMPLETED_PLAYING_NEXT is helpful for users of the audio player to know + * the difference between playing and transitioning to another audio file + * vs. detecting that the audio file transitioned by looking at + * events indicating IDLE and then PLAYING within a short period of time. + * + * State machine diagram + * + * cb is the callback function registered with audio_player_callback_register() + * + * cb(PLAYING) cb(PLAYING) + * _______________________________ ____________________________________ + * | | | | + * | | | | + * | cb(IDLE) V V cb(PAUSE) | + * Idle <------------------------ Playing ----------------------------> Pause + * ^ |_____^ | + * | cb(COMPLETED_PLAYING_NEXT) | + * | | + * |______________________________________________________________________| + * cb(IDLE) + * + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "driver/i2s_std.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + AUDIO_PLAYER_STATE_IDLE, + AUDIO_PLAYER_STATE_PLAYING, + AUDIO_PLAYER_STATE_PAUSE, + AUDIO_PLAYER_STATE_SHUTDOWN +} audio_player_state_t; + +/** + * @brief Get the audio player state + * + * @return the present audio_player_state_t + */ +audio_player_state_t audio_player_get_state(); + +typedef enum { + AUDIO_PLAYER_CALLBACK_EVENT_IDLE, /**< Player is idle, not playing audio */ + AUDIO_PLAYER_CALLBACK_EVENT_COMPLETED_PLAYING_NEXT, /**< Player is playing and playing a new audio file */ + AUDIO_PLAYER_CALLBACK_EVENT_PLAYING, /**< Player is playing */ + AUDIO_PLAYER_CALLBACK_EVENT_PAUSE, /**< Player is pausing */ + AUDIO_PLAYER_CALLBACK_EVENT_SHUTDOWN, /**< Player is shutting down */ + AUDIO_PLAYER_CALLBACK_EVENT_UNKNOWN_FILE_TYPE, /**< File type is unknown */ + AUDIO_PLAYER_CALLBACK_EVENT_UNKNOWN /**< Unknown event */ +} audio_player_callback_event_t; + +typedef struct { + audio_player_callback_event_t audio_event; + void *user_ctx; +} audio_player_cb_ctx_t; + +/** Audio callback function type */ +typedef void (*audio_player_cb_t)(audio_player_cb_ctx_t *); + +/** + * @brief Play mp3 audio file. + * + * Will interrupt a present playback and start the new playback + * as soon as possible. + * + * @param fp - If ESP_OK is returned, will be fclose()ed by the audio system + * when the playback has completed or in the event of a playback error. + * If not ESP_OK returned then should be fclose()d by the caller. + * @return + * - ESP_OK: Success in queuing play request + * - Others: Fail + */ +esp_err_t audio_player_play(FILE *fp); + +/** + * @brief Pause playback + * + * @return + * - ESP_OK: Success in queuing pause request + * - Others: Fail + */ +esp_err_t audio_player_pause(void); + +/** + * @brief Resume playback + * + * Has no effect if playback is not in progress + * @return esp_err_t + * - ESP_OK: Success in queuing resume request + * - Others: Fail + */ +esp_err_t audio_player_resume(void); + +/** + * @brief Stop playback + * + * Has no effect if playback is already stopped + * @return esp_err_t + * - ESP_OK: Success in queuing resume request + * - Others: Fail + */ +esp_err_t audio_player_stop(void); + +/** + * @brief Register callback for audio event + * + * @param call_back Call back function + * @param user_ctx User context + * @return + * - ESP_OK: Success + * - Others: Fail + */ +esp_err_t audio_player_callback_register(audio_player_cb_t call_back, void *user_ctx); + +typedef enum { + AUDIO_PLAYER_MUTE, + AUDIO_PLAYER_UNMUTE +} AUDIO_PLAYER_MUTE_SETTING; + +typedef esp_err_t (*audio_player_mute_fn)(AUDIO_PLAYER_MUTE_SETTING setting); +typedef esp_err_t (*audio_reconfig_std_clock)(uint32_t rate, uint32_t bits_cfg, i2s_slot_mode_t ch); +typedef esp_err_t (*audio_player_write_fn)(void *audio_buffer, size_t len, size_t *bytes_written, uint32_t timeout_ms); + +typedef struct { + audio_player_mute_fn mute_fn; + audio_reconfig_std_clock clk_set_fn; + audio_player_write_fn write_fn; + UBaseType_t priority; /*< FreeRTOS task priority */ + BaseType_t coreID; /*< ESP32 core ID */ +} audio_player_config_t; + +/** + * @brief Initialize hardware, allocate memory, create and start audio task. + * Call before any other 'audio' functions. + * + * @param port - The i2s port for output + * @return esp_err_t + */ +esp_err_t audio_player_new(audio_player_config_t config); + +/** + * @brief Shut down audio task, free allocated memory. + * + * @return esp_err_t ESP_OK upon success, ESP_FAIL if unable to shutdown due to retries exhausted + */ +esp_err_t audio_player_delete(); + +#ifdef __cplusplus +} +#endif diff --git a/managed_components/chmorgan__esp-audio-player/test/CMakeLists.txt b/managed_components/chmorgan__esp-audio-player/test/CMakeLists.txt new file mode 100644 index 0000000..640d071 --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/test/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRC_DIRS "." + PRIV_INCLUDE_DIRS "." + PRIV_REQUIRES unity test_utils audio_player + EMBED_TXTFILES gs-16b-1c-44100hz.mp3) diff --git a/managed_components/chmorgan__esp-audio-player/test/audio_player_test.c b/managed_components/chmorgan__esp-audio-player/test/audio_player_test.c new file mode 100644 index 0000000..77928b7 --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/test/audio_player_test.c @@ -0,0 +1,282 @@ +// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp_log.h" +#include "esp_check.h" +#include "unity.h" +#include "audio_player.h" +#include "driver/gpio.h" +#include "test_utils.h" +#include "freertos/semphr.h" + +static const char *TAG = "AUDIO PLAYER TEST"; + +#define CONFIG_BSP_I2S_NUM 1 + +/* Audio */ +#define BSP_I2S_SCLK (GPIO_NUM_17) +#define BSP_I2S_MCLK (GPIO_NUM_2) +#define BSP_I2S_LCLK (GPIO_NUM_47) +#define BSP_I2S_DOUT (GPIO_NUM_15) // To Codec ES8311 +#define BSP_I2S_DSIN (GPIO_NUM_16) // From ADC ES7210 +#define BSP_POWER_AMP_IO (GPIO_NUM_46) +#define BSP_MUTE_STATUS (GPIO_NUM_1) + +/** + * @brief ESP-BOX I2S pinout + * + * Can be used for i2s_std_gpio_config_t and/or i2s_std_config_t initialization + */ +#define BSP_I2S_GPIO_CFG \ + { \ + .mclk = BSP_I2S_MCLK, \ + .bclk = BSP_I2S_SCLK, \ + .ws = BSP_I2S_LCLK, \ + .dout = BSP_I2S_DOUT, \ + .din = BSP_I2S_DSIN, \ + .invert_flags = { \ + .mclk_inv = false, \ + .bclk_inv = false, \ + .ws_inv = false, \ + }, \ + } + +/** + * @brief Mono Duplex I2S configuration structure + * + * This configuration is used by default in bsp_audio_init() + */ +#define BSP_I2S_DUPLEX_MONO_CFG(_sample_rate) \ + { \ + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(_sample_rate), \ + .slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), \ + .gpio_cfg = BSP_I2S_GPIO_CFG, \ + } + +static i2s_chan_handle_t i2s_tx_chan; +static i2s_chan_handle_t i2s_rx_chan; + +static esp_err_t bsp_i2s_write(void * audio_buffer, size_t len, size_t *bytes_written, uint32_t timeout_ms) +{ + esp_err_t ret = ESP_OK; + ret = i2s_channel_write(i2s_tx_chan, (char *)audio_buffer, len, bytes_written, timeout_ms); + return ret; +} + +static esp_err_t bsp_i2s_reconfig_clk(uint32_t rate, uint32_t bits_cfg, i2s_slot_mode_t ch) +{ + esp_err_t ret = ESP_OK; + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(rate), + .slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t)bits_cfg, (i2s_slot_mode_t)ch), + .gpio_cfg = BSP_I2S_GPIO_CFG, + }; + + ret |= i2s_channel_disable(i2s_tx_chan); + ret |= i2s_channel_reconfig_std_clock(i2s_tx_chan, &std_cfg.clk_cfg); + ret |= i2s_channel_reconfig_std_slot(i2s_tx_chan, &std_cfg.slot_cfg); + ret |= i2s_channel_enable(i2s_tx_chan); + return ret; +} + +static esp_err_t audio_mute_function(AUDIO_PLAYER_MUTE_SETTING setting) { + ESP_LOGI(TAG, "mute setting %d", setting); + return ESP_OK; +} + +TEST_CASE("audio player can be newed and deleted", "[audio player]") +{ + audio_player_config_t config = { .mute_fn = audio_mute_function, + .write_fn = bsp_i2s_write, + .clk_set_fn = bsp_i2s_reconfig_clk, + .priority = 0, + .coreID = 0 }; + esp_err_t ret = audio_player_new(config); + TEST_ASSERT_EQUAL(ret, ESP_OK); + + ret = audio_player_delete(); + TEST_ASSERT_EQUAL(ret, ESP_OK); + + audio_player_state_t state = audio_player_get_state(); + TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_SHUTDOWN); +} + +static esp_err_t bsp_audio_init(const i2s_std_config_t *i2s_config, i2s_chan_handle_t *tx_channel, i2s_chan_handle_t *rx_channel) +{ + /* Setup I2S peripheral */ + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(CONFIG_BSP_I2S_NUM, I2S_ROLE_MASTER); + chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer + ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, tx_channel, rx_channel)); + + /* Setup I2S channels */ + const i2s_std_config_t std_cfg_default = BSP_I2S_DUPLEX_MONO_CFG(22050); + const i2s_std_config_t *p_i2s_cfg = &std_cfg_default; + if (i2s_config != NULL) { + p_i2s_cfg = i2s_config; + } + + if (tx_channel != NULL) { + ESP_ERROR_CHECK(i2s_channel_init_std_mode(*tx_channel, p_i2s_cfg)); + ESP_ERROR_CHECK(i2s_channel_enable(*tx_channel)); + } + if (rx_channel != NULL) { + ESP_ERROR_CHECK(i2s_channel_init_std_mode(*rx_channel, p_i2s_cfg)); + ESP_ERROR_CHECK(i2s_channel_enable(*rx_channel)); + } + + /* Setup power amplifier pin */ + const gpio_config_t io_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = BIT64(BSP_POWER_AMP_IO), + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .pull_up_en = GPIO_PULLDOWN_DISABLE, + }; + ESP_ERROR_CHECK(gpio_config(&io_conf)); + + return ESP_OK; +} + +static audio_player_callback_event_t expected_event; +static QueueHandle_t event_queue; + +static void audio_player_callback(audio_player_cb_ctx_t *ctx) +{ + TEST_ASSERT_EQUAL(ctx->audio_event, expected_event); + + // wake up the test so it can continue to the next step + TEST_ASSERT_EQUAL(xQueueSend(event_queue, &(ctx->audio_event), 0), pdPASS); +} + +TEST_CASE("audio player states and callbacks are correct", "[audio player]") +{ + audio_player_callback_event_t event; + + /* Configure I2S peripheral and Power Amplifier */ + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(44100), + .slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), + .gpio_cfg = BSP_I2S_GPIO_CFG, + }; + esp_err_t ret = bsp_audio_init(&std_cfg, &i2s_tx_chan, &i2s_rx_chan); + TEST_ASSERT_EQUAL(ret, ESP_OK); + + audio_player_config_t config = { .mute_fn = audio_mute_function, + .write_fn = bsp_i2s_write, + .clk_set_fn = bsp_i2s_reconfig_clk, + .priority = 0, + .coreID = 0 }; + ret = audio_player_new(config); + TEST_ASSERT_EQUAL(ret, ESP_OK); + + event_queue = xQueueCreate(1, sizeof(audio_player_callback_event_t)); + TEST_ASSERT_NOT_NULL(event_queue); + + ret = audio_player_callback_register(audio_player_callback, NULL); + TEST_ASSERT_EQUAL(ret, ESP_OK); + + audio_player_state_t state = audio_player_get_state(); + TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_IDLE); + + extern const char mp3_start[] asm("_binary_gs_16b_1c_44100hz_mp3_start"); + extern const char mp3_end[] asm("_binary_gs_16b_1c_44100hz_mp3_end"); + + // -1 due to the size being 1 byte too large, I think because end is the byte + // immediately after the last byte in the memory but I'm not sure - cmm 2022-08-20 + // + // Suppression as these are linker symbols and cppcheck doesn't know how to ensure + // they are the same object + // cppcheck-suppress comparePointers + size_t mp3_size = (mp3_end - mp3_start) - 1; + ESP_LOGI(TAG, "mp3_size %zu bytes", mp3_size); + + FILE *fp = fmemopen((void*)mp3_start, mp3_size, "rb"); + TEST_ASSERT_NOT_NULL(fp); + + + + /////////////// + expected_event = AUDIO_PLAYER_CALLBACK_EVENT_PLAYING; + ret = audio_player_play(fp); + TEST_ASSERT_EQUAL(ret, ESP_OK); + + // wait for playing event to arrive + TEST_ASSERT_EQUAL(xQueueReceive(event_queue, &event, pdMS_TO_TICKS(100)), pdPASS); + + // confirm state is playing + state = audio_player_get_state(); + TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_PLAYING); + + + + /////////////// + expected_event = AUDIO_PLAYER_CALLBACK_EVENT_PAUSE; + ret = audio_player_pause(); + TEST_ASSERT_EQUAL(ret, ESP_OK); + + // wait for paused event to arrive + TEST_ASSERT_EQUAL(xQueueReceive(event_queue, &event, pdMS_TO_TICKS(100)), pdPASS); + + state = audio_player_get_state(); + TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_PAUSE); + + + + //////////////// + expected_event = AUDIO_PLAYER_CALLBACK_EVENT_PLAYING; + ret = audio_player_resume(); + TEST_ASSERT_EQUAL(ret, ESP_OK); + + // wait for paused event to arrive + TEST_ASSERT_EQUAL(xQueueReceive(event_queue, &event, pdMS_TO_TICKS(100)), pdPASS); + + + + /////////////// + expected_event = AUDIO_PLAYER_CALLBACK_EVENT_IDLE; + + // the track is 16 seconds long so lets wait a bit here + int sleep_seconds = 16; + ESP_LOGI(TAG, "sleeping for %d seconds for playback to complete", sleep_seconds); + vTaskDelay(pdMS_TO_TICKS(sleep_seconds * 1000)); + + // wait for idle event to arrive + TEST_ASSERT_EQUAL(xQueueReceive(event_queue, &event, pdMS_TO_TICKS(100)), pdPASS); + + state = audio_player_get_state(); + TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_IDLE); + + + + /////////////// + expected_event = AUDIO_PLAYER_CALLBACK_EVENT_SHUTDOWN; + ret = audio_player_delete(); + TEST_ASSERT_EQUAL(ret, ESP_OK); + + // wait for idle event to arrive + TEST_ASSERT_EQUAL(xQueueReceive(event_queue, &event, pdMS_TO_TICKS(100)), pdPASS); + + state = audio_player_get_state(); + TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_SHUTDOWN); + + vQueueDelete(event_queue); + + TEST_ESP_OK(i2s_channel_disable(i2s_tx_chan)); + TEST_ESP_OK(i2s_channel_disable(i2s_rx_chan)); + TEST_ESP_OK(i2s_del_channel(i2s_tx_chan)); + TEST_ESP_OK(i2s_del_channel(i2s_rx_chan)); + + ESP_LOGI(TAG, "NOTE: a memory leak will be reported the first time this test runs.\n"); + ESP_LOGI(TAG, "esp-idf v4.4.1 and v4.4.2 both leak memory between i2s_driver_install() and i2s_driver_uninstall()\n"); +} diff --git a/managed_components/chmorgan__esp-audio-player/test/component.mk b/managed_components/chmorgan__esp-audio-player/test/component.mk new file mode 100644 index 0000000..8653b82 --- /dev/null +++ b/managed_components/chmorgan__esp-audio-player/test/component.mk @@ -0,0 +1,6 @@ +# +#Component Makefile +# + +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive +COMPONENT_EMBED_TXTFILES += gs-16b-1c-44100hz.mp3 diff --git a/managed_components/chmorgan__esp-audio-player/test/gs-16b-1c-44100hz.mp3 b/managed_components/chmorgan__esp-audio-player/test/gs-16b-1c-44100hz.mp3 new file mode 100644 index 0000000..e9915d8 Binary files /dev/null and b/managed_components/chmorgan__esp-audio-player/test/gs-16b-1c-44100hz.mp3 differ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/.component_hash b/managed_components/chmorgan__esp-libhelix-mp3/.component_hash new file mode 100644 index 0000000..5e4d083 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/.component_hash @@ -0,0 +1 @@ +cbb76089dc2c5749f7b470e2e70aedc44c9da519e04eb9a67d4c7ec275229e53 \ No newline at end of file diff --git a/managed_components/chmorgan__esp-libhelix-mp3/.gitmodules b/managed_components/chmorgan__esp-libhelix-mp3/.gitmodules new file mode 100644 index 0000000..2c852f3 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libhelix-mp3"] + path = libhelix-mp3 + url = https://github.com/chmorgan/libhelix-mp3.git diff --git a/managed_components/chmorgan__esp-libhelix-mp3/CMakeLists.txt b/managed_components/chmorgan__esp-libhelix-mp3/CMakeLists.txt new file mode 100644 index 0000000..1109ffe --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/CMakeLists.txt @@ -0,0 +1,11 @@ +idf_component_register( + SRC_DIRS + "libhelix-mp3/." + "libhelix-mp3/real" + INCLUDE_DIRS + "libhelix-mp3/pub" + PRIV_INCLUDE_DIRS + "libhelix-mp3/real") + +# Some of warinings, block them. +target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-but-set-variable) diff --git a/managed_components/chmorgan__esp-libhelix-mp3/LICENSE b/managed_components/chmorgan__esp-libhelix-mp3/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/LICENSE @@ -0,0 +1,201 @@ + 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 [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 + + 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. diff --git a/managed_components/chmorgan__esp-libhelix-mp3/README.md b/managed_components/chmorgan__esp-libhelix-mp3/README.md new file mode 100644 index 0000000..2799cb4 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/README.md @@ -0,0 +1,3 @@ +# esp-libhelix-mp3 + +ESP32 (and others) component for the libhelix-mp3 mp3 decoding library. diff --git a/managed_components/chmorgan__esp-libhelix-mp3/idf_component.yml b/managed_components/chmorgan__esp-libhelix-mp3/idf_component.yml new file mode 100644 index 0000000..7177964 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/idf_component.yml @@ -0,0 +1,6 @@ +dependencies: + idf: + version: '>=4.1.0' +description: libhelix-mp3 (mp3 decoder) component +url: https://github.com/chmorgan/esp-libhelix-mp3 +version: 1.0.3 diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/LICENSE.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/LICENSE.txt new file mode 100644 index 0000000..12e5372 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/LICENSE.txt @@ -0,0 +1,30 @@ + Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. + + The contents of this directory, and (except where otherwise + indicated) the directories included within this directory, are + subject to the current version of the RealNetworks Public Source + License (the "RPSL") available at RPSL.txt in this directory, unless + you have licensed the directory under the current version of the + RealNetworks Community Source License (the "RCSL") available at + RCSL.txt in this directory, in which case the RCSL will apply. You + may also obtain the license terms directly from RealNetworks. You + may not use the files in this directory except in compliance with the + RPSL or, if you have a valid RCSL with RealNetworks applicable to + this directory, the RCSL. Please see the applicable RPSL or RCSL for + the rights, obligations and limitations governing use of the contents + of the directory. + + This directory is part of the Helix DNA Technology. RealNetworks is + the developer of the Original Code and owns the copyrights in the + portions it created. + + This directory, and the directories included with this directory, are + distributed and made available on an 'AS IS' basis, WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY + DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + QUIET ENJOYMENT OR NON-INFRINGEMENT. + + Technology Compatibility Kit Test Suite(s) Location: + http://www.helixcommunity.org/content/tck + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/RCSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/RCSL.txt new file mode 100644 index 0000000..a809759 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/RCSL.txt @@ -0,0 +1,948 @@ +The RCSL is made up of a base agreement and a few Attachments. + +For Research and Development use, you agree to the terms of the +RCSL R&D License (base RCSL and Attachments A, B, and C) + +For Commercial Use (either distribution or internal commercial +deployment) of the Helix DNA with or without support for RealNetworks' +RealAudio and RealVideo Add-on Technology, you agree to the +terms of the same RCSL R&D license +and execute one or more additional Commercial Use License attachments +. + +------------------------------------------------------------------------ + + + REALNETWORKS COMMUNITY SOURCE LICENSE + +Version 1.2 (Rev. Date: January 22, 2003). + + + RECITALS + +Original Contributor has developed Specifications, Source Code +implementations and Executables of certain Technology; and + +Original Contributor desires to license the Technology to a large +community to facilitate research, innovation and product development +while maintaining compatibility of such products with the Technology as +delivered by Original Contributor; and + +Original Contributor desires to license certain Trademarks for the +purpose of branding products that are compatible with the relevant +Technology delivered by Original Contributor; and + +You desire to license the Technology and possibly certain Trademarks +from Original Contributor on the terms and conditions specified in this +License. + +In consideration for the mutual covenants contained herein, You and +Original Contributor agree as follows: + + + AGREEMENT + +*1. Introduction.* + +The RealNetworks Community Source License ("RCSL") and effective +attachments ("License") may include five distinct licenses: + +i) Research Use license -- License plus Attachments A, B and C only. + +ii) Commercial Use and Trademark License, which may be for Internal +Deployment Use or external distribution, or both -- License plus +Attachments A, B, C, and D. + +iii) Technology Compatibility Kit (TCK) license -- Attachment C. + +iv) Add-On Technology License (Executable) Commercial Use License +-Attachment F. + +v) Add-On Technology Source Code Porting and Optimization +License-Attachment G. + +The Research Use license is effective when You click and accept this +License. The TCK is effective when You click and accept this License, +unless otherwise specified in the TCK attachments. The Commercial Use +and Trademark, Add-On Technology License, and the Add-On Technology +Source Code Porting and Optimization licenses must each be signed by You +and Original Contributor to become effective. Once effective, these +licenses and the associated requirements and responsibilities are +cumulative. Capitalized terms used in this License are defined in the +Glossary. + +*2. License Grants.* + +2.1 Original Contributor Grant. + +Subject to Your compliance with Sections 3, 8.10 and Attachment A of +this License, Original Contributor grants to You a worldwide, +royalty-free, non-exclusive license, to the extent of Original +Contributor's Intellectual Property Rights covering the Original Code, +Upgraded Code and Specifications, to do the following: + +(a) Research Use License: + +(i) use, reproduce and modify the Original Code, Upgraded Code and +Specifications to create Modifications and Reformatted Specifications +for Research Use by You; + +(ii) publish and display Original Code, Upgraded Code and Specifications +with, or as part of Modifications, as permitted under Section 3.1(b) below; + +(iii) reproduce and distribute copies of Original Code and Upgraded Code +to Licensees and students for Research Use by You; + +(iv) compile, reproduce and distribute Original Code and Upgraded Code +in Executable form, and Reformatted Specifications to anyone for +Research Use by You. + +(b) Other than the licenses expressly granted in this License, Original +Contributor retains all right, title, and interest in Original Code and +Upgraded Code and Specifications. + +2.2 Your Grants. + +(a) To Other Licensees. You hereby grant to each Licensee a license to +Your Error Corrections and Shared Modifications, of the same scope and +extent as Original Contributor's licenses under Section 2.1 a) above +relative to Research Use and Attachment D relative to Commercial Use. + +(b) To Original Contributor. You hereby grant to Original Contributor a +worldwide, royalty-free, non-exclusive, perpetual and irrevocable +license, to the extent of Your Intellectual Property Rights covering +Your Error Corrections, Shared Modifications and Reformatted +Specifications, to use, reproduce, modify, display and distribute Your +Error Corrections, Shared Modifications and Reformatted Specifications, +in any form, including the right to sublicense such rights through +multiple tiers of distribution. + +(c) Other than the licenses expressly granted in Sections 2.2(a) and (b) +above, and the restrictions set forth in Section 3.1(d)(iv) below, You +retain all right, title, and interest in Your Error Corrections, Shared +Modifications and Reformatted Specifications. + +2.3 Contributor Modifications. + +You may use, reproduce, modify, display and distribute Contributor Error +Corrections, Shared Modifications and Reformatted Specifications, +obtained by You under this License, to the same scope and extent as with +Original Code, Upgraded Code and Specifications. + +2.4 Subcontracting. + +You may deliver the Source Code of Covered Code to other Licensees +having at least a Research Use license, for the sole purpose of +furnishing development services to You in connection with Your rights +granted in this License. All such Licensees must execute appropriate +documents with respect to such work consistent with the terms of this +License, and acknowledging their work-made-for-hire status or assigning +exclusive right to the work product and associated Intellectual Property +Rights to You. + +*3. Requirements and Responsibilities*. + +3.1 Research Use License. + +As a condition of exercising the rights granted under Section 2.1(a) +above, You agree to comply with the following: + +(a) Your Contribution to the Community. All Error Corrections and Shared +Modifications which You create or contribute to are automatically +subject to the licenses granted under Section 2.2 above. You are +encouraged to license all of Your other Modifications under Section 2.2 +as Shared Modifications, but are not required to do so. You agree to +notify Original Contributor of any errors in the Specification. + +(b) Source Code Availability. You agree to provide all Your Error +Corrections to Original Contributor as soon as reasonably practicable +and, in any event, prior to Internal Deployment Use or Commercial Use, +if applicable. Original Contributor may, at its discretion, post Source +Code for Your Error Corrections and Shared Modifications on the +Community Webserver. You may also post Error Corrections and Shared +Modifications on a web-server of Your choice; provided, that You must +take reasonable precautions to ensure that only Licensees have access to +such Error Corrections and Shared Modifications. Such precautions shall +include, without limitation, a password protection scheme limited to +Licensees and a click-on, download certification of Licensee status +required of those attempting to download from the server. An example of +an acceptable certification is attached as Attachment A-2. + +(c) Notices. All Error Corrections and Shared Modifications You create +or contribute to must include a file documenting the additions and +changes You made and the date of such additions and changes. You must +also include the notice set forth in Attachment A-1 in the file header. +If it is not possible to put the notice in a particular Source Code file +due to its structure, then You must include the notice in a location +(such as a relevant directory file), where a recipient would be most +likely to look for such a notice. + +(d) Redistribution. + +(i) Source. Covered Code may be distributed in Source Code form only to +another Licensee (except for students as provided below). You may not +offer or impose any terms on any Covered Code that alter the rights, +requirements, or responsibilities of such Licensee. You may distribute +Covered Code to students for use in connection with their course work +and research projects undertaken at accredited educational institutions. +Such students need not be Licensees, but must be given a copy of the +notice set forth in Attachment A-3 and such notice must also be included +in a file header or prominent location in the Source Code made available +to such students. + +(ii) Executable. You may distribute Executable version(s) of Covered +Code to Licensees and other third parties only for the purpose of +evaluation and comment in connection with Research Use by You and under +a license of Your choice, but which limits use of such Executable +version(s) of Covered Code only to that purpose. + +(iii) Modified Class, Interface and Package Naming. In connection with +Research Use by You only, You may use Original Contributor's class, +Interface and package names only to accurately reference or invoke the +Source Code files You modify. Original Contributor grants to You a +limited license to the extent necessary for such purposes. + +(iv) You expressly agree that any distribution, in whole or in part, of +Modifications developed by You shall only be done pursuant to the terms +and conditions of this License. + +(e) Extensions. + +(i) Covered Code. You may not include any Source Code of Community Code +in any Extensions. You may include the compiled Header Files of +Community Code in an Extension provided that Your use of the Covered +Code, including Heading Files, complies with the Commercial Use License, +the TCK and all other terms of this License. + +(ii) Publication. No later than the date on which You first distribute +such Extension for Commercial Use, You must publish to the industry, on +a non-confidential basis and free of all copyright restrictions with +respect to reproduction and use, an accurate and current specification +for any Extension. In addition, You must make available an appropriate +test suite, pursuant to the same rights as the specification, +sufficiently detailed to allow any third party reasonably skilled in the +technology to produce implementations of the Extension compatible with +the specification. Such test suites must be made available as soon as +reasonably practicable but, in no event, later than ninety (90) days +after Your first Commercial Use of the Extension. You must use +reasonable efforts to promptly clarify and correct the specification and +the test suite upon written request by Original Contributor. + +(iii) Open. You agree to refrain from enforcing any Intellectual +Property Rights You may have covering any interface(s) of Your +Extension, which would prevent the implementation of such interface(s) +by Original Contributor or any Licensee. This obligation does not +prevent You from enforcing any Intellectual Property Right You have that +would otherwise be infringed by an implementation of Your Extension. + +(iv) Interface Modifications and Naming. You may not modify or add to +the GUID space * * "xxxxxxxx-0901-11d1-8B06-00A024406D59" or any other +GUID space designated by Original Contributor. You may not modify any +Interface prefix provided with the Covered Code or any other prefix +designated by Original Contributor.* * + +* * + +(f) You agree that any Specifications provided to You by Original +Contributor are confidential and proprietary information of Original +Contributor. You must maintain the confidentiality of the Specifications +and may not disclose them to any third party without Original +Contributor's prior written consent. You may only use the Specifications +under the terms of this License and only for the purpose of implementing +the terms of this License with respect to Covered Code. You agree not +use, copy or distribute any such Specifications except as provided in +writing by Original Contributor. + +3.2 Commercial Use License. + +You may not make Commercial Use of any Covered Code unless You and +Original Contributor have executed a copy of the Commercial Use and +Trademark License attached as Attachment D. + +*4. Versions of the License.* + +4.1 License Versions. + +Original Contributor may publish revised versions of the License from +time to time. Each version will be given a distinguishing version number. + +4.2 Effect. + +Once a particular version of Covered Code has been provided under a +version of the License, You may always continue to use such Covered Code +under the terms of that version of the License. You may also choose to +use such Covered Code under the terms of any subsequent version of the +License. No one other than Original Contributor has the right to +promulgate License versions. + +4.3 Multiple-Licensed Code. + +Original Contributor may designate portions of the Covered Code as +"Multiple-Licensed." "Multiple-Licensed" means that the Original +Contributor permits You to utilize those designated portions of the +Covered Code under Your choice of this License or the alternative +license(s), if any, specified by the Original Contributor in an +Attachment to this License. + +*5. Disclaimer of Warranty.* + +5.1 COVERED CODE PROVIDED AS IS. + +COVERED CODE IS PROVIDED UNDER THIS LICENSE "AS IS," WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, +WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT +FOR A PARTICULAR PURPOSE OR NON-INFRINGING. YOU AGREE TO BEAR THE ENTIRE +RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF COVERED CODE UNDER +THIS LICENSE. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART +OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER +EXCEPT SUBJECT TO THIS DISCLAIMER. + +5.2 Not Designed for High Risk Activities. + +You acknowledge that Original Code, Upgraded Code and Specifications are +not designed or intended for use in high risk activities including, but +not limited to: (i) on-line control of aircraft, air traffic, aircraft +navigation or aircraft communications; or (ii) in the design, +construction, operation or maintenance of any nuclear facility. Original +Contributor disclaims any express or implied warranty of fitness for +such uses. + +*6. Termination.* + +6.1 By You. + +You may terminate this Research Use license at anytime by providing +written notice to Original Contributor. + +6.2 By Original Contributor. + +This License and the rights granted hereunder will terminate: + +(i) automatically if You fail to comply with the terms of this License +and fail to cure such breach within 30 days of receipt of written notice +of the breach; + +(ii) immediately in the event of circumstances specified in Sections 7.1 +and 8.4; or + +(iii) at Original Contributor's discretion upon any action initiated by +You (including by cross-claim or counter claim) alleging that use or +distribution by Original Contributor or any Licensee, of Original Code, +Upgraded Code, Error Corrections, Shared Modifications or Specifications +infringe a patent owned or controlled by You. + +6.3 Effective of Termination. + +Upon termination, You agree to discontinue use of and destroy all copies +of Covered Code in Your possession. All sublicenses to the Covered Code +which You have properly granted shall survive any termination of this +License. Provisions that, by their nature, should remain in effect +beyond the termination of this License shall survive including, without +limitation, Sections 2.2, 3, 5, 7 and 8. + +6.4 No Compensation. + +Each party waives and releases the other from any claim to compensation +or indemnity for permitted or lawful termination of the business +relationship established by this License. + +*7. Liability.* + +7.1 Infringement. Should any of the Original Code, Upgraded Code, TCK or +Specifications ("Materials") become the subject of a claim of +infringement, Original Contributor may, at its sole option, (i) attempt +to procure the rights necessary for You to continue using the Materials, +(ii) modify the Materials so that they are no longer infringing, or +(iii) terminate Your right to use the Materials, immediately upon +written notice, and refund to You the amount, if any, having then +actually been paid by You to Original Contributor for the Original Code, +Upgraded Code and TCK, depreciated on a straight line, five year basis. + +7.2 LIMITATION OF LIABILITY. TO THE FULL EXTENT ALLOWED BY APPLICABLE +LAW, ORIGINAL CONTRIBUTOR'S LIABILITY TO YOU FOR CLAIMS RELATING TO THIS +LICENSE, WHETHER FOR BREACH OR IN TORT, SHALL BE LIMITED TO ONE HUNDRED +PERCENT (100%) OF THE AMOUNT HAVING THEN ACTUALLY BEEN PAID BY YOU TO +ORIGINAL CONTRIBUTOR FOR ALL COPIES LICENSED HEREUNDER OF THE PARTICULAR +ITEMS GIVING RISE TO SUCH CLAIM, IF ANY, DURING THE TWELVE MONTHS +PRECEDING THE CLAIMED BREACH. IN NO EVENT WILL YOU (RELATIVE TO YOUR +SHARED MODIFICATIONS OR ERROR CORRECTIONS) OR ORIGINAL CONTRIBUTOR BE +LIABLE FOR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES IN CONNECTION WITH OR RISING OUT OF THIS LICENSE (INCLUDING, +WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR OTHER ECONOMIC +ADVANTAGE), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY, WHETHER IN +AN ACTION FOR CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE) +OR OTHERWISE, WHETHER OR NOT YOU OR ORIGINAL CONTRIBUTOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE AND NOTWITHSTANDING THE +FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. + +*8. Miscellaneous.* + +8.1 Trademark. + +You shall not use any Trademark unless You and Original Contributor +execute a copy of the Commercial Use and Trademark License Agreement +attached hereto as Attachment D. Except as expressly provided in the +License, You are granted no right, title or license to, or interest in, +any Trademarks. Whether or not You and Original Contributor enter into +the Trademark License, You agree not to (i) challenge Original +Contributor's ownership or use of Trademarks; (ii) attempt to register +any Trademarks, or any mark or logo substantially similar thereto; or +(iii) incorporate any Trademarks into Your own trademarks, product +names, service marks, company names, or domain names. + +8.2 Integration. + +This License represents the complete agreement concerning the subject +matter hereof. + +8.3 Assignment. + +Original Contributor may assign this License, and its rights and +obligations hereunder, in its sole discretion. You may assign the +Research Use portions of this License and the TCK license to a third +party upon prior written notice to Original Contributor (which may be +provided electronically via the Community Web-Server). You may not +assign the Commercial Use and Trademark license, the Add-On Technology +License, or the Add-On Technology Source Code Porting License, including +by way of merger (regardless of whether You are the surviving entity) or +acquisition, without Original Contributor's prior written consent. + +8.4 Severability. + +If any provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to make it +enforceable. Notwithstanding the foregoing, if You are prohibited by law +from fully and specifically complying with Sections 2.2 or 3, this +License will immediately terminate and You must immediately discontinue +any use of Covered Code. + +8.5 Governing Law. + +This License shall be governed by the laws of the United States and the +State of Washington, as applied to contracts entered into and to be +performed in Washington between Washington residents. The application of +the United Nations Convention on Contracts for the International Sale of +Goods is expressly excluded. You agree that the state and federal courts +located in Seattle, Washington have exclusive jurisdiction over any +claim relating to the License, including contract and tort claims. + +8.6 Dispute Resolution. + +a) Arbitration. Any dispute arising out of or relating to this License +shall be finally settled by arbitration as set out herein, except that +either party may bring any action, in a court of competent jurisdiction +(which jurisdiction shall be exclusive), with respect to any dispute +relating to such party's Intellectual Property Rights or with respect to +Your compliance with the TCK license. Arbitration shall be administered: +(i) by the American Arbitration Association (AAA), (ii) in accordance +with the rules of the United Nations Commission on International Trade +Law (UNCITRAL) (the "Rules") in effect at the time of arbitration as +modified herein; and (iii) the arbitrator will apply the substantive +laws of Washington and the United States. Judgment upon the award +rendered by the arbitrator may be entered in any court having +jurisdiction to enforce such award. + +b) Arbitration language, venue and damages. All arbitration proceedings +shall be conducted in English by a single arbitrator selected in +accordance with the Rules, who must be fluent in English and be either a +retired judge or practicing attorney having at least ten (10) years +litigation experience and be reasonably familiar with the technology +matters relative to the dispute. Unless otherwise agreed, arbitration +venue shall be in Seattle, Washington. The arbitrator may award monetary +damages only and nothing shall preclude either party from seeking +provisional or emergency relief from a court of competent jurisdiction. +The arbitrator shall have no authority to award damages in excess of +those permitted in this License and any such award in excess is void. +All awards will be payable in U.S. dollars and may include, for the +prevailing party (i) pre-judgment award interest, (ii) reasonable +attorneys' fees incurred in connection with the arbitration, and (iii) +reasonable costs and expenses incurred in enforcing the award. The +arbitrator will order each party to produce identified documents and +respond to no more than twenty-five single question interrogatories. + +8.7 Construction. + +Any law or regulation, which provides that the language of a contract +shall be construed against the drafter, shall not apply to this License. + +8.8 U.S. Government End Users. + +The Covered Code is a "commercial item," as that term is defined in 48 +C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" +and "commercial computer software documentation," as such terms are used +in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and +48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government +End Users acquire Covered Code with only those rights set forth herein. +You agree to pass this notice to our licensees. + +8.9 Marketing Activities. + +Licensee hereby grants Original Contributor a non-exclusive, +non-transferable, limited license to use the Licensee's company name and +logo ("Licensee Marks") in any presentations, press releases, or +marketing materials solely for the purpose of identifying Licensee as a +member of the Helix Community. Licensee shall provide samples of +Licensee Marks to Original Contributor upon request by Original +Contributor. Original Contributor acknowledges that the Licensee Marks +are the trademarks of Licensee. Original Contributor shall not use the +Licensee Marks in a way that may imply that Original Contributor is an +agency or branch of Licensee. Original Contributor understands and +agrees that the use of any Licensee Marks in connection with this +Agreement shall not create any right, title or interest, in, or to the +Licensee Marks or any Licensee trademarks and that all such use and +goodwill associated with any such trademarks will inure to the benefit +of Licensee. Further the Original Contributor will stop usage of the +Licensee Marks upon Licensee's request. + +8.10 Press Announcements. + +You may make press announcements or other public statements regarding +this License without the prior written consent of the Original +Contributor, if Your statement is limited to announcing the licensing of +the Covered Code or the availability of Your Product and its +compatibility with the Covered Code. All other public announcements +regarding this license require the prior written consent of the Original +Contributor. Consent requests are welcome at press@helixcommunity.org. + +8.11 International Use. + +a) Export/Import laws. Covered Code is subject to U.S. export control +laws and may be subject to export or import regulations in other +countries. Each party agrees to comply strictly with all such laws and +regulations and acknowledges their responsibility to obtain such +licenses to export, re-export, or import as may be required. You agree +to pass these obligations to Your licensees. + +b) Intellectual Property Protection. Due to limited intellectual +property protection and enforcement in certain countries, You agree not +to redistribute the Original Code, Upgraded Code, TCK and Specifications +to any country on the list of restricted countries on the Community Web +Server. + +8.12 Language. + +This License is in the English language only, which language shall be +controlling in all respects, and all versions of this License in any +other language shall be for accommodation only and shall not be binding +on the parties to this License. All communications and notices made or +given pursuant to this License, and all documentation and support to be +provided, unless otherwise noted, shall be in the English language. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH REALNETWORKS, INC. IF YOU ARE AGREEING +TO THIS LICENSE ON BEHALF OF A COMPANY, YOU REPRESENT THAT YOU ARE +AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. WHETHER YOU ARE ACTING +ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, YOU MUST BE OF MAJORITY +AGE AND BE OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. IF YOU DO NOT +MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY OF THE TERMS AND +CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON TO EXIT. + + + GLOSSARY + +1. *"Added Value"* means code which: + +(i) has a principal purpose which is substantially different from that +of the stand-alone Technology; + +(ii) represents a significant functional and value enhancement to the +Technology; + +(iii) operates in conjunction with the Technology; and + +(iv) is not marketed as a technology which replaces or substitutes for +the Technology + +2. "*Applicable Patent Rights*" mean: (a) in the case where Original +Contributor is the grantor of rights, claims of patents that (i) are now +or hereafter acquired, owned by or assigned to Original Contributor and +(ii) are necessarily infringed by using or making the Original Code or +Upgraded Code, including Modifications provided by Original Contributor, +alone and not in combination with other software or hardware; and (b) in +the case where Licensee is the grantor of rights, claims of patents that +(i) are now or hereafter acquired, owned by or assigned to Licensee and +(ii) are infringed (directly or indirectly) by using or making +Licensee's Modifications or Error Corrections, taken alone or in +combination with Covered Code. + +3. "*Application Programming Interfaces (APIs)"* means the interfaces, +associated header files, service provider interfaces, and protocols that +enable a device, application, Operating System, or other program to +obtain services from or make requests of (or provide services in +response to requests from) other programs, and to use, benefit from, or +rely on the resources, facilities, and capabilities of the relevant +programs using the APIs. APIs includes the technical documentation +describing the APIs, the Source Code constituting the API, and any +Header Files used with the APIs. + +4. "*Commercial Use*" means any use (internal or external), copying, +sublicensing or distribution (internal or external), directly or +indirectly of Covered Code by You other than Your Research Use of +Covered Code within Your business or organization or in conjunction with +other Licensees with equivalent Research Use rights. Commercial Use +includes any use of the Covered Code for direct or indirect commercial +or strategic gain, advantage or other business purpose. Any Commercial +Use requires execution of Attachment D by You and Original Contributor. + +5. "*Community Code*" means the Original Code, Upgraded Code, Error +Corrections, Shared Modifications, or any combination thereof. + +6. "*Community Webserver(s)"* means the webservers designated by +Original Contributor for access to the Original Code, Upgraded Code, TCK +and Specifications and for posting Error Corrections and Shared +Modifications. + +7. "*Compliant Covered Code*" means Covered Code that complies with the +requirements of the TCK. + +8. "*Contributor*" means each Licensee that creates or contributes to +the creation of any Error Correction or Shared Modification. + +9. "*Covered Code*" means the Original Code, Upgraded Code, +Modifications, or any combination thereof. + +10. "*Error Correction*" means any change made to Community Code which +conforms to the Specification and corrects the adverse effect of a +failure of Community Code to perform any function set forth in or +required by the Specifications. + +11. "*Executable*" means Covered Code that has been converted from +Source Code to the preferred form for execution by a computer or digital +processor (e.g. binary form). + +12. "*Extension(s)"* means any additional Interfaces developed by or for +You which: (i) are designed for use with the Technology; (ii) constitute +an API for a library of computing functions or services; and (iii) are +disclosed or otherwise made available to third party software developers +for the purpose of developing software which invokes such additional +Interfaces. The foregoing shall not apply to software developed by Your +subcontractors to be exclusively used by You. + +13. "*Header File(s)"* means that portion of the Source Code that +provides the names and types of member functions, data members, class +definitions, and interface definitions necessary to implement the APIs +for the Covered Code. Header Files include, files specifically +designated by Original Contributor as Header Files. Header Files do not +include the code necessary to implement the functionality underlying the +Interface. + +14. *"Helix DNA Server Technology"* means the program(s) that implement +the Helix Universal Server streaming engine for the Technology as +defined in the Specification. + +15. *"Helix DNA Client Technology"* means the Covered Code that +implements the RealOne Player engine as defined in the Specification. + +16. *"Helix DNA Producer Technology"* means the Covered Code that +implements the Helix Producer engine as defined in the Specification. + +17. *"Helix DNA Technology"* means the Helix DNA Server Technology, the +Helix DNA Client Technology, the Helix DNA Producer Technology and other +Helix technologies designated by Original Contributor. + +18. "*Intellectual Property Rights*" means worldwide statutory and +common law rights associated solely with (i) Applicable Patent Rights; +(ii) works of authorship including copyrights, copyright applications, +copyright registrations and "moral rights"; (iii) the protection of +trade and industrial secrets and confidential information; and (iv) +divisions, continuations, renewals, and re-issuances of the foregoing +now existing or acquired in the future. + +19. *"Interface*" means interfaces, functions, properties, class +definitions, APIs, Header Files, GUIDs, V-Tables, and/or protocols +allowing one piece of software, firmware or hardware to communicate or +interoperate with another piece of software, firmware or hardware. + +20. "*Internal Deployment Use*" means use of Compliant Covered Code +(excluding Research Use) within Your business or organization only by +Your employees and/or agents on behalf of Your business or organization, +but not to provide services, including content distribution, to third +parties, subject to execution of Attachment D by You and Original +Contributor, if required. + +21. "*Licensee*" means any party that has entered into and has in effect +a version of this License with Original Contributor. + +22. "*MIME type*" means a description of what type of media or other +content is in a file, including by way of example but not limited to +'audio/x-pn-realaudio-plugin.' + +23. "*Modification(s)"* means (i) any addition to, deletion from and/or +change to the substance and/or structure of the Covered Code, including +Interfaces; (ii) the combination of any Covered Code and any previous +Modifications; (iii) any new file or other representation of computer +program statements that contains any portion of Covered Code; and/or +(iv) any new Source Code implementing any portion of the Specifications. + +24. "*MP3 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Picture Experts Group known as MPEG-1 Audio Layer-3 or MP3, +including but not limited to all past and future versions, profiles, +extensions, parts and amendments relating to the MP3 specification. + +25. "*MPEG-4 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Pictures Experts Group known as MPEG-4, including but not +limited to all past and future versions, profiles, extensions, parts and +amendments relating to the MPEG-4 specification. + +26. "*Original Code*" means the initial Source Code for the Technology +as described on the Community Web Server. + +27. "*Original Contributor*" means RealNetworks, Inc., its affiliates +and its successors and assigns. + +28. "*Original Contributor MIME Type*" means the MIME registry, browser +preferences, or local file/protocol associations invoking any Helix DNA +Client-based application, including the RealOne Player, for playback of +RealAudio, RealVideo, other RealMedia MIME types or datatypes (e.g., +.ram, .rnx, .rpm, .ra, .rm, .rp, .rt, .rf, .prx, .mpe, .rmp, .rmj, .rav, +.rjs, .rmx, .rjt, .rms), and any other Original Contributor-specific or +proprietary MIME types that Original Contributor may introduce in the +future. + +29. "*Personal Use*" means use of Covered Code by an individual solely +for his or her personal, private and non-commercial purposes. An +individual's use of Covered Code in his or her capacity as an officer, +employee, member, independent contractor or agent of a corporation, +business or organization (commercial or non-commercial) does not qualify +as Personal Use. + +30. "*RealMedia File Format*" means the file format designed and +developed by RealNetworks for storing multimedia data and used to store +RealAudio and RealVideo encoded streams. Valid RealMedia File Format +extensions include: .rm, .rmj, .rmc, .rmvb, .rms. + +31. "*RCSL Webpage*" means the RealNetworks Community Source License +webpage located at https://www.helixcommunity.org/content/rcsl or such +other URL that Original Contributor may designate from time to time. + +32. "*Reformatted Specifications*" means any revision to the +Specifications which translates or reformats the Specifications (as for +example in connection with Your documentation) but which does not alter, +subset or superset * *the functional or operational aspects of the +Specifications. + +33. "*Research Use*" means use and distribution of Covered Code only for +Your Personal Use, research or development use and expressly excludes +Internal Deployment Use and Commercial Use. Research Use also includes +use of Covered Code to teach individuals how to use Covered Code. + +34. "*Shared Modifications*" means Modifications that You distribute or +use for a Commercial Use, in addition to any Modifications provided by +You, at Your option, pursuant to Section 2.2, or received by You from a +Contributor pursuant to Section 2.3. + +35. "*Source Code*" means the preferred form of the Covered Code for +making modifications to it, including all modules it contains, plus any +associated interface definition files, scripts used to control +compilation and installation of an Executable, or source code +differential comparisons against either the Original Code or another +well known, available Covered Code of the Contributor's choice. The +Source Code can be in a compressed or archival form, provided the +appropriate decompression or de-archiving software is widely available +for no charge. + +36. "*Specifications*" means the specifications for the Technology and +other documentation, as designated on the Community Web Server, as may +be revised by Original Contributor from time to time. + +37. "*Trademarks*" means Original Contributor's trademarks and logos, +including, but not limited to, RealNetworks, RealAudio, RealVideo, +RealOne, RealSystem, SureStream, Helix, Helix DNA and other trademarks +whether now used or adopted in the future. + +38. "*Technology*" means the technology described in Attachment B, and +Upgrades. + +39. "*Technology Compatibility Kit"* or *"TCK*" means the test programs, +procedures, acceptance criteria and/or other requirements, designated by +Original Contributor for use in verifying compliance of Covered Code +with the Specifications, in conjunction with the Original Code and +Upgraded Code. Original Contributor may, in its sole discretion and from +time to time, revise a TCK to correct errors and/or omissions and in +connection with Upgrades. + +40. "*Upgrade(s)"* means new versions of Technology designated +exclusively by Original Contributor as an "Upgrade" and released by +Original Contributor from time to time under the terms of the License. + +41. "*Upgraded Code*" means the Source Code and/or Executables for +Upgrades, possibly including Modifications made by Contributors. + +42. *"User's Guide"* means the users guide for the TCK which Original +Contributor makes available to You to provide direction in how to run +the TCK and properly interpret the results, as may be revised by +Original Contributor from time to time. + +43. "*You(r)*" means an individual, or a legal entity acting by and +through an individual or individuals, exercising rights either under +this License or under a future version of this License issued pursuant +to Section 4.1. For legal entities, "You(r)" includes any entity that by +majority voting interest controls, is controlled by, or is under common +control with You. + +44. "*Your Products*" means any (i) hardware products You distribute +integrating the Covered Code; (ii) any software products You distribute +with the Covered Code that utilize the APIs of the Covered Code; or +(iii) any services You provide using the Covered Code. + + + ATTACHMENT A + +REQUIRED NOTICES + + + ATTACHMENT A-1 + +REQUIRED IN ALL CASES + +Notice to be included in header file of all Error Corrections and Shared +Modifications: + +Portions Copyright 1994-2003 RealNetworks, Inc. All rights reserved. + +The contents of this file, and the files included with this file, are +subject to the current version of RealNetworks Community Source License +Version 1.1 (the "License"). You may not use this file except in +compliance with the License executed by both You and RealNetworks. You +may obtain a copy of the License at * +https://www.helixcommunity.org/content/rcsl.* You may also obtain a copy +of the License by contacting RealNetworks directly. Please see the +License for the rights, obligations and limitations governing use of the +contents of the file. + +This file is part of the Helix DNA technology. RealNetworks, Inc., is +the developer of the Original code and owns the copyrights in the +portions it created. + +This file, and the files included with this file, are distributed on an +'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, +AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): + +_______________________________________________ + +Technology Compatibility Kit Test Suite(s) Location: + +________________________________ + + + ATTACHMENT A-2 + +SAMPLE LICENSEE CERTIFICATION + +"By clicking the `Agree' button below, You certify that You are a +Licensee in good standing under the RealNetworks Community Source +License, ("License") and that Your access, use and distribution of code +and information You may obtain at this site is subject to the License. +If You are not a Licensee under the RealNetworks Community Source +License You agree not to download, copy or use the Helix DNA technology. + + + ATTACHMENT A-3 + +REQUIRED STUDENT NOTIFICATION + +"This software and related documentation has been obtained by Your +educational institution subject to the RealNetworks Community Source +License. You have been provided access to the software and related +documentation for use only in connection with your course work and +research activities as a matriculated student of Your educational +institution. Any other use is expressly prohibited. + +THIS SOFTWARE AND RELATED DOCUMENTATION CONTAINS PROPRIETARY MATERIAL OF +REALNETWORKS, INC, WHICH ARE PROTECTED BY VARIOUS INTELLECTUAL PROPERTY +RIGHTS. + +You may not use this file except in compliance with the License. You may +obtain a copy of the License on the web at +https://www.helixcommunity.org/content/rcsl. + +* +* + + + ATTACHMENT B + +Description of Technology + +Helix DNA, which consists of Helix DNA Client, Helix DNA Server and +Helix DNA Producer. + +Description of "Technology" + +Helix DNA Technology v1.0 as described on the Community Web Server. + + + ATTACHMENT C + +TECHNOLOGY COMPATIBILITY KIT LICENSE + +The following license is effective for the *Helix DNA* Technology +Compatibility Kit - as described on the Community Web Server. The +Technology Compatibility Kit(s) for the Technology specified in +Attachment B may be accessed at the Community Web Server. + +1. TCK License. + +1.1 Grants to use TCK + +Subject to the terms and restrictions set forth below and the +RealNetworks Community Source License, and the Research Use license, +Original Contributor grants to You a worldwide, non-exclusive, +non-transferable license, to the extent of Original Contributor's +Intellectual Property Rights in the TCK (without the right to +sublicense), to use the TCK to develop and test Covered Code. + +1.2 TCK Use Restrictions. + +You are not authorized to create derivative works of the TCK or use the +TCK to test any implementation of the Specification that is not Covered +Code. You may not publish Your test results or make claims of +comparative compatibility with respect to other implementations of the +Specification. In consideration for the license grant in Section 1.1 +above You agree not to develop Your own tests that are intended to +validate conformation with the Specification. + +2. Test Results. + +You agree to provide to Original Contributor or the third party test +facility if applicable, Your test results that demonstrate that Covered +Code is Compliant Covered Code and that Original Contributor may publish +or otherwise distribute such test results. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH THE ORIGINAL CONTRIBUTOR, REALNETWORKS, +INC. IF YOU ARE AGREEING TO THIS LICENSE ON BEHALF OF A COMPANY, YOU +REPRESENT THAT YOU ARE AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. +WHETHER YOU ARE ACTING ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, +YOU MUST BE OF MAJORITY AGE AND BE OTHERWISE COMPETENT TO ENTER INTO +CONTRACTS. IF YOU DO NOT MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY +OF THE TERMS AND CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON +TO EXIT. + +*ACCEPT / REJECT +* + +* +* + +*To agree to the R&D/academic terms of this license, please register + on the site -- +you will then be given a chance to agree to the clickwrap RCSL + +R&D License + +and gain access to the RCSL-licensed source code. To build or deploy +commercial applications based on the RCSL, you will need to agree to the +Commercial Use license attachments +* + + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/RPSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/RPSL.txt new file mode 100644 index 0000000..d040a45 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/RPSL.txt @@ -0,0 +1,518 @@ +RealNetworks Public Source License Version 1.0 +(Rev. Date October 28, 2002) + +1. General Definitions. This License applies to any program or other work which +RealNetworks, Inc., or any other entity that elects to use this license, +("Licensor") makes publicly available and which contains a notice placed by +Licensor identifying such program or work as "Original Code" and stating that it +is subject to the terms of this RealNetworks Public Source License version 1.0 +(or subsequent version thereof) ("License"). You are not required to accept this +License. However, nothing else grants You permission to use, copy, modify or +distribute the software or its derivative works. These actions are prohibited by +law if You do not accept this License. Therefore, by modifying, copying or +distributing the software (or any work based on the software), You indicate your +acceptance of this License to do so, and all its terms and conditions. In +addition, you agree to the terms of this License by clicking the Accept button +or downloading the software. As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Licensor is the +grantor of rights, claims of patents that (i) are now or hereafter acquired, +owned by or assigned to Licensor and (ii) are necessarily infringed by using or +making the Original Code alone and not in combination with other software or +hardware; and (b) in the case where You are the grantor of rights, claims of +patents that (i) are now or hereafter acquired, owned by or assigned to You and +(ii) are infringed (directly or indirectly) by using or making Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Compatible Source License" means any one of the licenses listed on Exhibit +B or at https://www.helixcommunity.org/content/complicense or other licenses +specifically identified by Licensor in writing. Notwithstanding any term to the +contrary in any Compatible Source License, any code covered by any Compatible +Source License that is used with Covered Code must be made readily available in +Source Code format for royalty-free use under the terms of the Compatible Source +License or this License. + +1.3 "Contributor" means any person or entity that creates or contributes to the +creation of Modifications. + +1.4 "Covered Code" means the Original Code, Modifications, the combination of +Original Code and any Modifications, and/or any respective portions thereof. + +1.5 "Deploy" means to use, sublicense or distribute Covered Code other than for +Your internal research and development (R&D) and/or Personal Use, and includes +without limitation, any and all internal use or distribution of Covered Code +within Your business or organization except for R&D use and/or Personal Use, as +well as direct or indirect sublicensing or distribution of Covered Code by You +to any third party in any form or manner. + +1.6 "Derivative Work" means either the Covered Code or any derivative work under +United States copyright law, and including any work containing or including any +portion of the Covered Code or Modifications, either verbatim or with +modifications and/or translated into another language. Derivative Work also +includes any work which combines any portion of Covered Code or Modifications +with code not otherwise governed by the terms of this License. + +1.7 "Externally Deploy" means to Deploy the Covered Code in any way that may be +accessed or used by anyone other than You, used to provide any services to +anyone other than You, or used in any way to deliver any content to anyone other +than You, whether the Covered Code is distributed to those parties, made +available as an application intended for use over a computer network, or used to +provide services or otherwise deliver content to anyone other than You. + +1.8. "Interface" means interfaces, functions, properties, class definitions, +APIs, header files, GUIDs, V-Tables, and/or protocols allowing one piece of +software, firmware or hardware to communicate or interoperate with another piece +of software, firmware or hardware. + +1.9 "Modifications" mean any addition to, deletion from, and/or change to, the +substance and/or structure of the Original Code, any previous Modifications, the +combination of Original Code and any previous Modifications, and/or any +respective portions thereof. When code is released as a series of files, a +Modification is: (a) any addition to or deletion from the contents of a file +containing Covered Code; and/or (b) any new file or other representation of +computer program statements that contains any part of Covered Code. + +1.10 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Licensor under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Licensor under this License, and that has been expressly identified by Licensor +as such in the header file(s) of such work; and (b) the object code compiled +from such Source Code and originally made available by Licensor under this +License. + +1.11 "Personal Use" means use of Covered Code by an individual solely for his or +her personal, private and non-commercial purposes. An individual's use of +Covered Code in his or her capacity as an officer, employee, member, independent +contractor or agent of a corporation, business or organization (commercial or +non-commercial) does not qualify as Personal Use. + +1.12 "Source Code" means the human readable form of a program or other work that +is suitable for making modifications to it, including all modules it contains, +plus any associated interface definition files, scripts used to control +compilation and installation of an executable (object code). + +1.13 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership of +fifty percent (50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Licensor hereby grants You, effective on the date +You accept this License (via downloading or using Covered Code or otherwise +indicating your acceptance of this License), a worldwide, royalty-free, +non-exclusive copyright license, to the extent of Licensor's copyrights cover +the Original Code, to do the following: + +2.1 You may reproduce, display, perform, modify and Deploy Covered Code, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the copyright +and other proprietary notices and disclaimers of Licensor as they appear in the +Original Code, and keep intact all notices in the Original Code that refer to +this License; + +(b) You must include a copy of this License with every copy of Source Code of +Covered Code and documentation You distribute, and You may not offer or impose +any terms on such Source Code that alter or restrict this License or the +recipients' rights hereunder, except as permitted under Section 6; + +(c) You must duplicate, to the extent it does not already exist, the notice in +Exhibit A in each file of the Source Code of all Your Modifications, and cause +the modified files to carry prominent notices stating that You changed the files +and the date of any change; + +(d) You must make Source Code of all Your Externally Deployed Modifications +publicly available under the terms of this License, including the license grants +set forth in Section 3 below, for as long as you Deploy the Covered Code or +twelve (12) months from the date of initial Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Deployed Modifications +electronically (e.g. download from a web site); and + +(e) if You Deploy Covered Code in object code, executable form only, You must +include a prominent notice, in the code itself as well as in related +documentation, stating that Source Code of the Covered Code is available under +the terms of this License with information on how and where to obtain such +Source Code. You must also include the Object Code Notice set forth in Exhibit A +in the "about" box or other appropriate place where other copyright notices are +placed, including any packaging materials. + +2.2 You expressly acknowledge and agree that although Licensor and each +Contributor grants the licenses to their respective portions of the Covered Code +set forth herein, no assurances are provided by Licensor or any Contributor that +the Covered Code does not infringe the patent or other intellectual property +rights of any other entity. Licensor and each Contributor disclaim any liability +to You for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, You hereby assume sole responsibility to +secure any other intellectual property rights needed, if any. For example, if a +third party patent license is required to allow You to make, use, sell, import +or offer for sale the Covered Code, it is Your responsibility to acquire such +license(s). + +2.3 Subject to the terms and conditions of this License, Licensor hereby grants +You, effective on the date You accept this License (via downloading or using +Covered Code or otherwise indicating your acceptance of this License), a +worldwide, royalty-free, perpetual, non-exclusive patent license under +Licensor's Applicable Patent Rights to make, use, sell, offer for sale and +import the Covered Code, provided that in each instance you comply with the +terms of this License. + +3. Your Grants. In consideration of, and as a condition to, the licenses granted +to You under this License: + +(a) You grant to Licensor and all third parties a non-exclusive, perpetual, +irrevocable, royalty free license under Your Applicable Patent Rights and other +intellectual property rights owned or controlled by You, to make, sell, offer +for sale, use, import, reproduce, display, perform, modify, distribute and +Deploy Your Modifications of the same scope and extent as Licensor's licenses +under Sections 2.1 and 2.2; and + +(b) You grant to Licensor and its subsidiaries a non-exclusive, worldwide, +royalty-free, perpetual and irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights owned or controlled by You, to +make, use, sell, offer for sale, import, reproduce, display, perform, +distribute, modify or have modified (for Licensor and/or its subsidiaries), +sublicense and distribute Your Modifications, in any form and for any purpose, +through multiple tiers of distribution. + +(c) You agree not use any information derived from Your use and review of the +Covered Code, including but not limited to any algorithms or inventions that may +be contained in the Covered Code, for the purpose of asserting any of Your +patent rights, or assisting a third party to assert any of its patent rights, +against Licensor or any Contributor. + +4. Derivative Works. You may create a Derivative Work by combining Covered Code +with other code not otherwise governed by the terms of this License and +distribute the Derivative Work as an integrated product. In each such instance, +You must make sure the requirements of this License are fulfilled for the +Covered Code or any portion thereof, including all Modifications. + +4.1 You must cause any Derivative Work that you distribute, publish or +Externally Deploy, that in whole or in part contains or is derived from the +Covered Code or any part thereof, to be licensed as a whole at no charge to all +third parties under the terms of this License and no other license except as +provided in Section 4.2. You also must make Source Code available for the +Derivative Work under the same terms as Modifications, described in Sections 2 +and 3, above. + +4.2 Compatible Source Licenses. Software modules that have been independently +developed without any use of Covered Code and which contain no portion of the +Covered Code, Modifications or other Derivative Works, but are used or combined +in any way wtih the Covered Code or any Derivative Work to form a larger +Derivative Work, are exempt from the conditions described in Section 4.1 but +only to the extent that: the software module, including any software that is +linked to, integrated with, or part of the same applications as, the software +module by any method must be wholly subject to one of the Compatible Source +Licenses. Notwithstanding the foregoing, all Covered Code must be subject to the +terms of this License. Thus, the entire Derivative Work must be licensed under a +combination of the RPSL (for Covered Code) and a Compatible Source License for +any independently developed software modules within the Derivative Work. The +foregoing requirement applies even if the Compatible Source License would +ordinarily allow the software module to link with, or form larger works with, +other software that is not subject to the Compatible Source License. For +example, although the Mozilla Public License v1.1 allows Mozilla code to be +combined with proprietary software that is not subject to the MPL, if +MPL-licensed code is used with Covered Code the MPL-licensed code could not be +combined or linked with any code not governed by the MPL. The general intent of +this section 4.2 is to enable use of Covered Code with applications that are +wholly subject to an acceptable open source license. You are responsible for +determining whether your use of software with Covered Code is allowed under Your +license to such software. + +4.3 Mere aggregation of another work not based on the Covered Code with the +Covered Code (or with a work based on the Covered Code) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. If You deliver the Covered Code for combination and/or integration with +an application previously provided by You (for example, via automatic updating +technology), such combination and/or integration constitutes a Derivative Work +subject to the terms of this License. + +5. Exclusions From License Grant. Nothing in this License shall be deemed to +grant any rights to trademarks, copyrights, patents, trade secrets or any other +intellectual property of Licensor or any Contributor except as expressly stated +herein. No right is granted to the trademarks of Licensor or any Contributor +even if such marks are included in the Covered Code. Nothing in this License +shall be interpreted to prohibit Licensor from licensing under different terms +from this License any code that Licensor otherwise would have a right to +license. Modifications, Derivative Works and/or any use or combination of +Covered Code with other technology provided by Licensor or third parties may +require additional patent licenses from Licensor which Licensor may grant in its +sole discretion. No patent license is granted separate from the Original Code or +combinations of the Original Code with other software or hardware. + +5.1. Trademarks. This License does not grant any rights to use the trademarks or +trade names owned by Licensor ("Licensor Marks" defined in Exhibit C) or to any +trademark or trade name belonging to any Contributor. No Licensor Marks may be +used to endorse or promote products derived from the Original Code other than as +permitted by the Licensor Trademark Policy defined in Exhibit C. + +6. Additional Terms. You may choose to offer, and to charge a fee for, warranty, +support, indemnity or liability obligations and/or other rights consistent with +the scope of the license granted herein ("Additional Terms") to one or more +recipients of Covered Code. However, You may do so only on Your own behalf and +as Your sole responsibility, and not on behalf of Licensor or any Contributor. +You must obtain the recipient's agreement that any such Additional Terms are +offered by You alone, and You hereby agree to indemnify, defend and hold +Licensor and every Contributor harmless for any liability incurred by or claims +asserted against Licensor or such Contributor by reason of any such Additional +Terms. + +7. Versions of the License. Licensor may publish revised and/or new versions of +this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular version +of this License, You may continue to use it under the terms of that version. You +may also choose to use such Original Code under the terms of any subsequent +version of this License published by Licensor. No one other than Licensor has +the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in part +pre-release, untested, or not fully tested works. The Covered Code may contain +errors that could cause failures or loss of data, and may be incomplete or +contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND LICENSOR AND LICENSOR'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS +"LICENSOR" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY +DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET +ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. LICENSOR AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN DOCUMENTATION, INFORMATION OR ADVICE GIVEN BY LICENSOR, A LICENSOR +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You +acknowledge that the Covered Code is not intended for use in high risk +activities, including, but not limited to, the design, construction, operation +or maintenance of nuclear facilities, aircraft navigation, aircraft +communication systems, or air traffic control machines in which case the failure +of the Covered Code could lead to death, personal injury, or severe physical or +environmental damage. Licensor disclaims any express or implied warranty of +fitness for such uses. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT +SHALL LICENSOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR STRICT +LIABILITY), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF LICENSOR OR SUCH +CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND +NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. SOME +JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF INCIDENTAL OR +CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event +shall Licensor's total liability to You for all damages (other than as may be +required by applicable law) under this License exceed the amount of ten dollars +($10.00). + +10. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Licensor retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Licensor +("Licensor Modifications"), and such Licensor Modifications will not be +automatically subject to this License. Licensor may, at its sole discretion, +choose to license such Licensor Modifications under this License, or on +different terms from those contained in this License or may choose not to +license them at all. + +11. Termination. + +11.1 Term and Termination. The term of this License is perpetual unless +terminated as provided below. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Licensor if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; + +(b) immediately in the event of the circumstances described in Section 12.5(b); +or + +(c) automatically without notice from Licensor if You, at any time during the +term of this License, commence an action for patent infringement against +Licensor (including by cross-claim or counter claim in a lawsuit); + +(d) upon written notice from Licensor if You, at any time during the term of +this License, commence an action for patent infringement against any third party +alleging that the Covered Code itself (excluding combinations with other +software or hardware) infringes any patent (including by cross-claim or counter +claim in a lawsuit). + +11.2 Effect of Termination. Upon termination, You agree to immediately stop any +further use, reproduction, modification, sublicensing and distribution of the +Covered Code and to destroy all copies of the Covered Code that are in your +possession or control. All sublicenses to the Covered Code which have been +properly granted prior to termination shall survive any termination of this +License. Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to Sections +3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other for +compensation, indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this License will +be without prejudice to any other right or remedy of any party. + +12. Miscellaneous. + +12.1 Government End Users. The Covered Code is a "commercial item" as defined in +FAR 2.101. Government software and technical data rights in the Covered Code +include only those rights customarily provided to the public as defined in this +License. This customary commercial license in technical data and software is +provided in accordance with FAR 12.211 (Technical Data) and 12.212 (Computer +Software) and, for Department of Defense purchases, DFAR 252.227-7015 (Technical +Data -- Commercial Items) and 227.7202-3 (Rights in Commercial Computer Software +or Computer Software Documentation). Accordingly, all U.S. Government End Users +acquire Covered Code with only those rights set forth herein. + +12.2 Relationship of Parties. This License will not be construed as creating an +agency, partnership, joint venture or any other form of legal association +between or among You, Licensor or any Contributor, and You will not represent to +the contrary, whether expressly, by implication, appearance or otherwise. + +12.3 Independent Development. Nothing in this License will impair Licensor's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions as, +or otherwise compete with, Modifications, Derivative Works, technology or +products that You may develop, produce, market or distribute. + +12.4 Waiver; Construction. Failure by Licensor or any Contributor to enforce any +provision of this License will not be deemed a waiver of future enforcement of +that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +12.5 Severability. (a) If for any reason a court of competent jurisdiction finds +any provision of this License, or portion thereof, to be unenforceable, that +provision of the License will be enforced to the maximum extent permissible so +as to effect the economic benefits and intent of the parties, and the remainder +of this License will continue in full force and effect. (b) Notwithstanding the +foregoing, if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the enforceability +of either of those Sections, this License will immediately terminate and You +must immediately discontinue any use of the Covered Code and destroy all copies +of it that are in your possession or control. + +12.6 Dispute Resolution. Any litigation or other dispute resolution between You +and Licensor relating to this License shall take place in the Seattle, +Washington, and You and Licensor hereby consent to the personal jurisdiction of, +and venue in, the state and federal courts within that District with respect to +this License. The application of the United Nations Convention on Contracts for +the International Sale of Goods is expressly excluded. + +12.7 Export/Import Laws. This software is subject to all export and import laws +and restrictions and regulations of the country in which you receive the Covered +Code and You are solely responsible for ensuring that You do not export, +re-export or import the Covered Code or any direct product thereof in violation +of any such restrictions, laws or regulations, or without all necessary +authorizations. + +12.8 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +Washington. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé +que le présent contrat et tous les documents connexes soient +rédigés en anglais. + + EXHIBIT A. + +"Copyright © 1995-2002 +RealNetworks, Inc. and/or its licensors. All Rights Reserved. + +The contents of this file, and the files included with this file, are subject to +the current version of the RealNetworks Public Source License Version 1.0 (the +"RPSL") available at https://www.helixcommunity.org/content/rpsl unless you have +licensed the file under the RealNetworks Community Source License Version 1.0 +(the "RCSL") available at https://www.helixcommunity.org/content/rcsl, in which +case the RCSL will apply. You may also obtain the license terms directly from +RealNetworks. You may not use this file except in compliance with the RPSL or, +if you have a valid RCSL with RealNetworks applicable to this file, the RCSL. +Please see the applicable RPSL or RCSL for the rights, obligations and +limitations governing use of the contents of the file. + +This file is part of the Helix DNA Technology. RealNetworks is the developer of +the Original code and owns the copyrights in the portions it created. + +This file, and the files included with this file, is distributed and made +available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR +IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING +WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): ____________________________________ + +Technology Compatibility Kit Test +Suite(s) Location (if licensed under the RCSL): ______________________________ + +Object Code Notice: Helix DNA Client technology included. Copyright (c) +RealNetworks, Inc., 1995-2002. All rights reserved. + + + EXHIBIT B + +Compatible Source Licenses for the RealNetworks Public Source License. The +following list applies to the most recent version of the license as of October +25, 2002, unless otherwise indicated. + +* Academic Free License +* Apache Software License +* Apple Public Source License +* Artistic license +* Attribution Assurance Licenses +* BSD license +* Common Public License (1) +* Eiffel Forum License +* GNU General Public License (GPL) (1) +* GNU Library or "Lesser" General Public License (LGPL) (1) +* IBM Public License +* Intel Open Source License +* Jabber Open Source License +* MIT license +* MITRE Collaborative Virtual Workspace License (CVW License) +* Motosoto License +* Mozilla Public License 1.0 (MPL) +* Mozilla Public License 1.1 (MPL) +* Nokia Open Source License +* Open Group Test Suite License +* Python Software Foundation License +* Ricoh Source Code Public License +* Sun Industry Standards Source License (SISSL) +* Sun Public License +* University of Illinois/NCSA Open Source License +* Vovida Software License v. 1.0 +* W3C License +* X.Net License +* Zope Public License +* zlib/libpng license + +(1) Note: because this license contains certain reciprocal licensing terms that +purport to extend to independently developed code, You may be prohibited under +the terms of this otherwise compatible license from using code licensed under +its terms with Covered Code because Covered Code may only be licensed under the +RealNetworks Public Source License. Any attempt to apply non RPSL license terms, +including without limitation the GPL, to Covered Code is expressly forbidden. +You are responsible for ensuring that Your use of Compatible Source Licensed +code does not violate either the RPSL or the Compatible Source License. + +The latest version of this list can be found at: +https://www.helixcommunity.org/content/complicense + + EXHIBIT C + +RealNetworks' Trademark policy. + +RealNetworks defines the following trademarks collectively as "Licensor +Trademarks": "RealNetworks", "RealPlayer", "RealJukebox", "RealSystem", +"RealAudio", "RealVideo", "RealOne Player", "RealMedia", "Helix" or any other +trademarks or trade names belonging to RealNetworks. + +RealNetworks "Licensor Trademark Policy" forbids any use of Licensor Trademarks +except as permitted by and in strict compliance at all times with RealNetworks' +third party trademark usage guidelines which are posted at +http://www.realnetworks.com/info/helixlogo.html. + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/Umakefil b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/Umakefil new file mode 100644 index 0000000..93e2570 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/Umakefil @@ -0,0 +1,80 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: RCSL 1.0/RPSL 1.0 +# +# Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. +# +# The contents of this file, and the files included with this file, are +# subject to the current version of the RealNetworks Public Source License +# Version 1.0 (the "RPSL") available at +# http://www.helixcommunity.org/content/rpsl unless you have licensed +# the file under the RealNetworks Community Source License Version 1.0 +# (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, +# in which case the RCSL will apply. You may also obtain the license terms +# directly from RealNetworks. You may not use this file except in +# compliance with the RPSL or, if you have a valid RCSL with RealNetworks +# applicable to this file, the RCSL. Please see the applicable RPSL or +# RCSL for the rights, obligations and limitations governing use of the +# contents of the file. +# +# This file is part of the Helix DNA Technology. RealNetworks is the +# developer of the Original Code and owns the copyrights in the portions +# it created. +# +# This file, and the files included with this file, is distributed and made +# available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# +# Technology Compatibility Kit Test Suite(s) Location: +# http://www.helixcommunity.org/content/tck +# +# Contributor(s): +# +# ***** END LICENSE BLOCK ***** +# + +UmakefileVersion(2,1) + +# old C++ shim layer for backwards compatibility with Player +# if you don't want to use this, just use the public C api +# in mp3dec.c/.h +project.AddSources("mpadecobj.cpp") + +project.AddSources("mp3dec.c", "mp3tabs.c") + +if (sysinfo.arch == 'arm') and project.IsDefined('HELIX_FEATURE_USE_IPP4'): + project.AddDefines('USE_IPP_MP3') + +if ('USE_IPP_MP3' in project.defines): + project.AddSources("ipp/bitstream.c", "ipp/buffers.c", "ipp/dequant.c", + "ipp/huffman.c", "ipp/imdct.c", "ipp/subband.c") + if('_LINUX' in project.defines): + project.AddIncludes('%s/include/' % GetSDKPath("ipp_mp3_tools")) + else: + project.AddIncludes('\"%s\include\"' % GetSDKPath("ipp_mp3_tools")) + +else: + project.AddSources("real/bitstream.c", "real/buffers.c", "real/dct32.c", + "real/dequant.c", "real/dqchan.c", "real/huffman.c", "real/hufftabs.c", + "real/imdct.c", "real/scalfact.c", + "real/stproc.c", "real/subband.c", "real/trigtabs.c") + if ('ARM_ADS' in project.defines): + project.AddSources("real/arm/asmpoly.s") + elif ('_WINCE' in project.defines and '_ARM' in project.defines): + project.AddSources("real/arm/asmpoly.s", "real/arm/asmmisc.s") + elif (('_SYMBIAN' in project.defines or '_LINUX' in project.defines ) and + 'ARM' in project.defines): + project.AddSources("real/arm/asmpoly_gcc.s") + else: + project.AddSources("real/polyphase.c") + +project.AddIncludes("./pub") +project.AddModuleIncludes("common/include") +project.AddModuleIncludes("common/runtime/pub") + +LibraryTarget("mp3codecfixpt") + +DependTarget() + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/LICENSE.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/LICENSE.txt new file mode 100644 index 0000000..12e5372 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/LICENSE.txt @@ -0,0 +1,30 @@ + Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. + + The contents of this directory, and (except where otherwise + indicated) the directories included within this directory, are + subject to the current version of the RealNetworks Public Source + License (the "RPSL") available at RPSL.txt in this directory, unless + you have licensed the directory under the current version of the + RealNetworks Community Source License (the "RCSL") available at + RCSL.txt in this directory, in which case the RCSL will apply. You + may also obtain the license terms directly from RealNetworks. You + may not use the files in this directory except in compliance with the + RPSL or, if you have a valid RCSL with RealNetworks applicable to + this directory, the RCSL. Please see the applicable RPSL or RCSL for + the rights, obligations and limitations governing use of the contents + of the directory. + + This directory is part of the Helix DNA Technology. RealNetworks is + the developer of the Original Code and owns the copyrights in the + portions it created. + + This directory, and the directories included with this directory, are + distributed and made available on an 'AS IS' basis, WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY + DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + QUIET ENJOYMENT OR NON-INFRINGEMENT. + + Technology Compatibility Kit Test Suite(s) Location: + http://www.helixcommunity.org/content/tck + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/RCSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/RCSL.txt new file mode 100644 index 0000000..a809759 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/RCSL.txt @@ -0,0 +1,948 @@ +The RCSL is made up of a base agreement and a few Attachments. + +For Research and Development use, you agree to the terms of the +RCSL R&D License (base RCSL and Attachments A, B, and C) + +For Commercial Use (either distribution or internal commercial +deployment) of the Helix DNA with or without support for RealNetworks' +RealAudio and RealVideo Add-on Technology, you agree to the +terms of the same RCSL R&D license +and execute one or more additional Commercial Use License attachments +. + +------------------------------------------------------------------------ + + + REALNETWORKS COMMUNITY SOURCE LICENSE + +Version 1.2 (Rev. Date: January 22, 2003). + + + RECITALS + +Original Contributor has developed Specifications, Source Code +implementations and Executables of certain Technology; and + +Original Contributor desires to license the Technology to a large +community to facilitate research, innovation and product development +while maintaining compatibility of such products with the Technology as +delivered by Original Contributor; and + +Original Contributor desires to license certain Trademarks for the +purpose of branding products that are compatible with the relevant +Technology delivered by Original Contributor; and + +You desire to license the Technology and possibly certain Trademarks +from Original Contributor on the terms and conditions specified in this +License. + +In consideration for the mutual covenants contained herein, You and +Original Contributor agree as follows: + + + AGREEMENT + +*1. Introduction.* + +The RealNetworks Community Source License ("RCSL") and effective +attachments ("License") may include five distinct licenses: + +i) Research Use license -- License plus Attachments A, B and C only. + +ii) Commercial Use and Trademark License, which may be for Internal +Deployment Use or external distribution, or both -- License plus +Attachments A, B, C, and D. + +iii) Technology Compatibility Kit (TCK) license -- Attachment C. + +iv) Add-On Technology License (Executable) Commercial Use License +-Attachment F. + +v) Add-On Technology Source Code Porting and Optimization +License-Attachment G. + +The Research Use license is effective when You click and accept this +License. The TCK is effective when You click and accept this License, +unless otherwise specified in the TCK attachments. The Commercial Use +and Trademark, Add-On Technology License, and the Add-On Technology +Source Code Porting and Optimization licenses must each be signed by You +and Original Contributor to become effective. Once effective, these +licenses and the associated requirements and responsibilities are +cumulative. Capitalized terms used in this License are defined in the +Glossary. + +*2. License Grants.* + +2.1 Original Contributor Grant. + +Subject to Your compliance with Sections 3, 8.10 and Attachment A of +this License, Original Contributor grants to You a worldwide, +royalty-free, non-exclusive license, to the extent of Original +Contributor's Intellectual Property Rights covering the Original Code, +Upgraded Code and Specifications, to do the following: + +(a) Research Use License: + +(i) use, reproduce and modify the Original Code, Upgraded Code and +Specifications to create Modifications and Reformatted Specifications +for Research Use by You; + +(ii) publish and display Original Code, Upgraded Code and Specifications +with, or as part of Modifications, as permitted under Section 3.1(b) below; + +(iii) reproduce and distribute copies of Original Code and Upgraded Code +to Licensees and students for Research Use by You; + +(iv) compile, reproduce and distribute Original Code and Upgraded Code +in Executable form, and Reformatted Specifications to anyone for +Research Use by You. + +(b) Other than the licenses expressly granted in this License, Original +Contributor retains all right, title, and interest in Original Code and +Upgraded Code and Specifications. + +2.2 Your Grants. + +(a) To Other Licensees. You hereby grant to each Licensee a license to +Your Error Corrections and Shared Modifications, of the same scope and +extent as Original Contributor's licenses under Section 2.1 a) above +relative to Research Use and Attachment D relative to Commercial Use. + +(b) To Original Contributor. You hereby grant to Original Contributor a +worldwide, royalty-free, non-exclusive, perpetual and irrevocable +license, to the extent of Your Intellectual Property Rights covering +Your Error Corrections, Shared Modifications and Reformatted +Specifications, to use, reproduce, modify, display and distribute Your +Error Corrections, Shared Modifications and Reformatted Specifications, +in any form, including the right to sublicense such rights through +multiple tiers of distribution. + +(c) Other than the licenses expressly granted in Sections 2.2(a) and (b) +above, and the restrictions set forth in Section 3.1(d)(iv) below, You +retain all right, title, and interest in Your Error Corrections, Shared +Modifications and Reformatted Specifications. + +2.3 Contributor Modifications. + +You may use, reproduce, modify, display and distribute Contributor Error +Corrections, Shared Modifications and Reformatted Specifications, +obtained by You under this License, to the same scope and extent as with +Original Code, Upgraded Code and Specifications. + +2.4 Subcontracting. + +You may deliver the Source Code of Covered Code to other Licensees +having at least a Research Use license, for the sole purpose of +furnishing development services to You in connection with Your rights +granted in this License. All such Licensees must execute appropriate +documents with respect to such work consistent with the terms of this +License, and acknowledging their work-made-for-hire status or assigning +exclusive right to the work product and associated Intellectual Property +Rights to You. + +*3. Requirements and Responsibilities*. + +3.1 Research Use License. + +As a condition of exercising the rights granted under Section 2.1(a) +above, You agree to comply with the following: + +(a) Your Contribution to the Community. All Error Corrections and Shared +Modifications which You create or contribute to are automatically +subject to the licenses granted under Section 2.2 above. You are +encouraged to license all of Your other Modifications under Section 2.2 +as Shared Modifications, but are not required to do so. You agree to +notify Original Contributor of any errors in the Specification. + +(b) Source Code Availability. You agree to provide all Your Error +Corrections to Original Contributor as soon as reasonably practicable +and, in any event, prior to Internal Deployment Use or Commercial Use, +if applicable. Original Contributor may, at its discretion, post Source +Code for Your Error Corrections and Shared Modifications on the +Community Webserver. You may also post Error Corrections and Shared +Modifications on a web-server of Your choice; provided, that You must +take reasonable precautions to ensure that only Licensees have access to +such Error Corrections and Shared Modifications. Such precautions shall +include, without limitation, a password protection scheme limited to +Licensees and a click-on, download certification of Licensee status +required of those attempting to download from the server. An example of +an acceptable certification is attached as Attachment A-2. + +(c) Notices. All Error Corrections and Shared Modifications You create +or contribute to must include a file documenting the additions and +changes You made and the date of such additions and changes. You must +also include the notice set forth in Attachment A-1 in the file header. +If it is not possible to put the notice in a particular Source Code file +due to its structure, then You must include the notice in a location +(such as a relevant directory file), where a recipient would be most +likely to look for such a notice. + +(d) Redistribution. + +(i) Source. Covered Code may be distributed in Source Code form only to +another Licensee (except for students as provided below). You may not +offer or impose any terms on any Covered Code that alter the rights, +requirements, or responsibilities of such Licensee. You may distribute +Covered Code to students for use in connection with their course work +and research projects undertaken at accredited educational institutions. +Such students need not be Licensees, but must be given a copy of the +notice set forth in Attachment A-3 and such notice must also be included +in a file header or prominent location in the Source Code made available +to such students. + +(ii) Executable. You may distribute Executable version(s) of Covered +Code to Licensees and other third parties only for the purpose of +evaluation and comment in connection with Research Use by You and under +a license of Your choice, but which limits use of such Executable +version(s) of Covered Code only to that purpose. + +(iii) Modified Class, Interface and Package Naming. In connection with +Research Use by You only, You may use Original Contributor's class, +Interface and package names only to accurately reference or invoke the +Source Code files You modify. Original Contributor grants to You a +limited license to the extent necessary for such purposes. + +(iv) You expressly agree that any distribution, in whole or in part, of +Modifications developed by You shall only be done pursuant to the terms +and conditions of this License. + +(e) Extensions. + +(i) Covered Code. You may not include any Source Code of Community Code +in any Extensions. You may include the compiled Header Files of +Community Code in an Extension provided that Your use of the Covered +Code, including Heading Files, complies with the Commercial Use License, +the TCK and all other terms of this License. + +(ii) Publication. No later than the date on which You first distribute +such Extension for Commercial Use, You must publish to the industry, on +a non-confidential basis and free of all copyright restrictions with +respect to reproduction and use, an accurate and current specification +for any Extension. In addition, You must make available an appropriate +test suite, pursuant to the same rights as the specification, +sufficiently detailed to allow any third party reasonably skilled in the +technology to produce implementations of the Extension compatible with +the specification. Such test suites must be made available as soon as +reasonably practicable but, in no event, later than ninety (90) days +after Your first Commercial Use of the Extension. You must use +reasonable efforts to promptly clarify and correct the specification and +the test suite upon written request by Original Contributor. + +(iii) Open. You agree to refrain from enforcing any Intellectual +Property Rights You may have covering any interface(s) of Your +Extension, which would prevent the implementation of such interface(s) +by Original Contributor or any Licensee. This obligation does not +prevent You from enforcing any Intellectual Property Right You have that +would otherwise be infringed by an implementation of Your Extension. + +(iv) Interface Modifications and Naming. You may not modify or add to +the GUID space * * "xxxxxxxx-0901-11d1-8B06-00A024406D59" or any other +GUID space designated by Original Contributor. You may not modify any +Interface prefix provided with the Covered Code or any other prefix +designated by Original Contributor.* * + +* * + +(f) You agree that any Specifications provided to You by Original +Contributor are confidential and proprietary information of Original +Contributor. You must maintain the confidentiality of the Specifications +and may not disclose them to any third party without Original +Contributor's prior written consent. You may only use the Specifications +under the terms of this License and only for the purpose of implementing +the terms of this License with respect to Covered Code. You agree not +use, copy or distribute any such Specifications except as provided in +writing by Original Contributor. + +3.2 Commercial Use License. + +You may not make Commercial Use of any Covered Code unless You and +Original Contributor have executed a copy of the Commercial Use and +Trademark License attached as Attachment D. + +*4. Versions of the License.* + +4.1 License Versions. + +Original Contributor may publish revised versions of the License from +time to time. Each version will be given a distinguishing version number. + +4.2 Effect. + +Once a particular version of Covered Code has been provided under a +version of the License, You may always continue to use such Covered Code +under the terms of that version of the License. You may also choose to +use such Covered Code under the terms of any subsequent version of the +License. No one other than Original Contributor has the right to +promulgate License versions. + +4.3 Multiple-Licensed Code. + +Original Contributor may designate portions of the Covered Code as +"Multiple-Licensed." "Multiple-Licensed" means that the Original +Contributor permits You to utilize those designated portions of the +Covered Code under Your choice of this License or the alternative +license(s), if any, specified by the Original Contributor in an +Attachment to this License. + +*5. Disclaimer of Warranty.* + +5.1 COVERED CODE PROVIDED AS IS. + +COVERED CODE IS PROVIDED UNDER THIS LICENSE "AS IS," WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, +WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT +FOR A PARTICULAR PURPOSE OR NON-INFRINGING. YOU AGREE TO BEAR THE ENTIRE +RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF COVERED CODE UNDER +THIS LICENSE. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART +OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER +EXCEPT SUBJECT TO THIS DISCLAIMER. + +5.2 Not Designed for High Risk Activities. + +You acknowledge that Original Code, Upgraded Code and Specifications are +not designed or intended for use in high risk activities including, but +not limited to: (i) on-line control of aircraft, air traffic, aircraft +navigation or aircraft communications; or (ii) in the design, +construction, operation or maintenance of any nuclear facility. Original +Contributor disclaims any express or implied warranty of fitness for +such uses. + +*6. Termination.* + +6.1 By You. + +You may terminate this Research Use license at anytime by providing +written notice to Original Contributor. + +6.2 By Original Contributor. + +This License and the rights granted hereunder will terminate: + +(i) automatically if You fail to comply with the terms of this License +and fail to cure such breach within 30 days of receipt of written notice +of the breach; + +(ii) immediately in the event of circumstances specified in Sections 7.1 +and 8.4; or + +(iii) at Original Contributor's discretion upon any action initiated by +You (including by cross-claim or counter claim) alleging that use or +distribution by Original Contributor or any Licensee, of Original Code, +Upgraded Code, Error Corrections, Shared Modifications or Specifications +infringe a patent owned or controlled by You. + +6.3 Effective of Termination. + +Upon termination, You agree to discontinue use of and destroy all copies +of Covered Code in Your possession. All sublicenses to the Covered Code +which You have properly granted shall survive any termination of this +License. Provisions that, by their nature, should remain in effect +beyond the termination of this License shall survive including, without +limitation, Sections 2.2, 3, 5, 7 and 8. + +6.4 No Compensation. + +Each party waives and releases the other from any claim to compensation +or indemnity for permitted or lawful termination of the business +relationship established by this License. + +*7. Liability.* + +7.1 Infringement. Should any of the Original Code, Upgraded Code, TCK or +Specifications ("Materials") become the subject of a claim of +infringement, Original Contributor may, at its sole option, (i) attempt +to procure the rights necessary for You to continue using the Materials, +(ii) modify the Materials so that they are no longer infringing, or +(iii) terminate Your right to use the Materials, immediately upon +written notice, and refund to You the amount, if any, having then +actually been paid by You to Original Contributor for the Original Code, +Upgraded Code and TCK, depreciated on a straight line, five year basis. + +7.2 LIMITATION OF LIABILITY. TO THE FULL EXTENT ALLOWED BY APPLICABLE +LAW, ORIGINAL CONTRIBUTOR'S LIABILITY TO YOU FOR CLAIMS RELATING TO THIS +LICENSE, WHETHER FOR BREACH OR IN TORT, SHALL BE LIMITED TO ONE HUNDRED +PERCENT (100%) OF THE AMOUNT HAVING THEN ACTUALLY BEEN PAID BY YOU TO +ORIGINAL CONTRIBUTOR FOR ALL COPIES LICENSED HEREUNDER OF THE PARTICULAR +ITEMS GIVING RISE TO SUCH CLAIM, IF ANY, DURING THE TWELVE MONTHS +PRECEDING THE CLAIMED BREACH. IN NO EVENT WILL YOU (RELATIVE TO YOUR +SHARED MODIFICATIONS OR ERROR CORRECTIONS) OR ORIGINAL CONTRIBUTOR BE +LIABLE FOR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES IN CONNECTION WITH OR RISING OUT OF THIS LICENSE (INCLUDING, +WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR OTHER ECONOMIC +ADVANTAGE), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY, WHETHER IN +AN ACTION FOR CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE) +OR OTHERWISE, WHETHER OR NOT YOU OR ORIGINAL CONTRIBUTOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE AND NOTWITHSTANDING THE +FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. + +*8. Miscellaneous.* + +8.1 Trademark. + +You shall not use any Trademark unless You and Original Contributor +execute a copy of the Commercial Use and Trademark License Agreement +attached hereto as Attachment D. Except as expressly provided in the +License, You are granted no right, title or license to, or interest in, +any Trademarks. Whether or not You and Original Contributor enter into +the Trademark License, You agree not to (i) challenge Original +Contributor's ownership or use of Trademarks; (ii) attempt to register +any Trademarks, or any mark or logo substantially similar thereto; or +(iii) incorporate any Trademarks into Your own trademarks, product +names, service marks, company names, or domain names. + +8.2 Integration. + +This License represents the complete agreement concerning the subject +matter hereof. + +8.3 Assignment. + +Original Contributor may assign this License, and its rights and +obligations hereunder, in its sole discretion. You may assign the +Research Use portions of this License and the TCK license to a third +party upon prior written notice to Original Contributor (which may be +provided electronically via the Community Web-Server). You may not +assign the Commercial Use and Trademark license, the Add-On Technology +License, or the Add-On Technology Source Code Porting License, including +by way of merger (regardless of whether You are the surviving entity) or +acquisition, without Original Contributor's prior written consent. + +8.4 Severability. + +If any provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to make it +enforceable. Notwithstanding the foregoing, if You are prohibited by law +from fully and specifically complying with Sections 2.2 or 3, this +License will immediately terminate and You must immediately discontinue +any use of Covered Code. + +8.5 Governing Law. + +This License shall be governed by the laws of the United States and the +State of Washington, as applied to contracts entered into and to be +performed in Washington between Washington residents. The application of +the United Nations Convention on Contracts for the International Sale of +Goods is expressly excluded. You agree that the state and federal courts +located in Seattle, Washington have exclusive jurisdiction over any +claim relating to the License, including contract and tort claims. + +8.6 Dispute Resolution. + +a) Arbitration. Any dispute arising out of or relating to this License +shall be finally settled by arbitration as set out herein, except that +either party may bring any action, in a court of competent jurisdiction +(which jurisdiction shall be exclusive), with respect to any dispute +relating to such party's Intellectual Property Rights or with respect to +Your compliance with the TCK license. Arbitration shall be administered: +(i) by the American Arbitration Association (AAA), (ii) in accordance +with the rules of the United Nations Commission on International Trade +Law (UNCITRAL) (the "Rules") in effect at the time of arbitration as +modified herein; and (iii) the arbitrator will apply the substantive +laws of Washington and the United States. Judgment upon the award +rendered by the arbitrator may be entered in any court having +jurisdiction to enforce such award. + +b) Arbitration language, venue and damages. All arbitration proceedings +shall be conducted in English by a single arbitrator selected in +accordance with the Rules, who must be fluent in English and be either a +retired judge or practicing attorney having at least ten (10) years +litigation experience and be reasonably familiar with the technology +matters relative to the dispute. Unless otherwise agreed, arbitration +venue shall be in Seattle, Washington. The arbitrator may award monetary +damages only and nothing shall preclude either party from seeking +provisional or emergency relief from a court of competent jurisdiction. +The arbitrator shall have no authority to award damages in excess of +those permitted in this License and any such award in excess is void. +All awards will be payable in U.S. dollars and may include, for the +prevailing party (i) pre-judgment award interest, (ii) reasonable +attorneys' fees incurred in connection with the arbitration, and (iii) +reasonable costs and expenses incurred in enforcing the award. The +arbitrator will order each party to produce identified documents and +respond to no more than twenty-five single question interrogatories. + +8.7 Construction. + +Any law or regulation, which provides that the language of a contract +shall be construed against the drafter, shall not apply to this License. + +8.8 U.S. Government End Users. + +The Covered Code is a "commercial item," as that term is defined in 48 +C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" +and "commercial computer software documentation," as such terms are used +in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and +48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government +End Users acquire Covered Code with only those rights set forth herein. +You agree to pass this notice to our licensees. + +8.9 Marketing Activities. + +Licensee hereby grants Original Contributor a non-exclusive, +non-transferable, limited license to use the Licensee's company name and +logo ("Licensee Marks") in any presentations, press releases, or +marketing materials solely for the purpose of identifying Licensee as a +member of the Helix Community. Licensee shall provide samples of +Licensee Marks to Original Contributor upon request by Original +Contributor. Original Contributor acknowledges that the Licensee Marks +are the trademarks of Licensee. Original Contributor shall not use the +Licensee Marks in a way that may imply that Original Contributor is an +agency or branch of Licensee. Original Contributor understands and +agrees that the use of any Licensee Marks in connection with this +Agreement shall not create any right, title or interest, in, or to the +Licensee Marks or any Licensee trademarks and that all such use and +goodwill associated with any such trademarks will inure to the benefit +of Licensee. Further the Original Contributor will stop usage of the +Licensee Marks upon Licensee's request. + +8.10 Press Announcements. + +You may make press announcements or other public statements regarding +this License without the prior written consent of the Original +Contributor, if Your statement is limited to announcing the licensing of +the Covered Code or the availability of Your Product and its +compatibility with the Covered Code. All other public announcements +regarding this license require the prior written consent of the Original +Contributor. Consent requests are welcome at press@helixcommunity.org. + +8.11 International Use. + +a) Export/Import laws. Covered Code is subject to U.S. export control +laws and may be subject to export or import regulations in other +countries. Each party agrees to comply strictly with all such laws and +regulations and acknowledges their responsibility to obtain such +licenses to export, re-export, or import as may be required. You agree +to pass these obligations to Your licensees. + +b) Intellectual Property Protection. Due to limited intellectual +property protection and enforcement in certain countries, You agree not +to redistribute the Original Code, Upgraded Code, TCK and Specifications +to any country on the list of restricted countries on the Community Web +Server. + +8.12 Language. + +This License is in the English language only, which language shall be +controlling in all respects, and all versions of this License in any +other language shall be for accommodation only and shall not be binding +on the parties to this License. All communications and notices made or +given pursuant to this License, and all documentation and support to be +provided, unless otherwise noted, shall be in the English language. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH REALNETWORKS, INC. IF YOU ARE AGREEING +TO THIS LICENSE ON BEHALF OF A COMPANY, YOU REPRESENT THAT YOU ARE +AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. WHETHER YOU ARE ACTING +ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, YOU MUST BE OF MAJORITY +AGE AND BE OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. IF YOU DO NOT +MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY OF THE TERMS AND +CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON TO EXIT. + + + GLOSSARY + +1. *"Added Value"* means code which: + +(i) has a principal purpose which is substantially different from that +of the stand-alone Technology; + +(ii) represents a significant functional and value enhancement to the +Technology; + +(iii) operates in conjunction with the Technology; and + +(iv) is not marketed as a technology which replaces or substitutes for +the Technology + +2. "*Applicable Patent Rights*" mean: (a) in the case where Original +Contributor is the grantor of rights, claims of patents that (i) are now +or hereafter acquired, owned by or assigned to Original Contributor and +(ii) are necessarily infringed by using or making the Original Code or +Upgraded Code, including Modifications provided by Original Contributor, +alone and not in combination with other software or hardware; and (b) in +the case where Licensee is the grantor of rights, claims of patents that +(i) are now or hereafter acquired, owned by or assigned to Licensee and +(ii) are infringed (directly or indirectly) by using or making +Licensee's Modifications or Error Corrections, taken alone or in +combination with Covered Code. + +3. "*Application Programming Interfaces (APIs)"* means the interfaces, +associated header files, service provider interfaces, and protocols that +enable a device, application, Operating System, or other program to +obtain services from or make requests of (or provide services in +response to requests from) other programs, and to use, benefit from, or +rely on the resources, facilities, and capabilities of the relevant +programs using the APIs. APIs includes the technical documentation +describing the APIs, the Source Code constituting the API, and any +Header Files used with the APIs. + +4. "*Commercial Use*" means any use (internal or external), copying, +sublicensing or distribution (internal or external), directly or +indirectly of Covered Code by You other than Your Research Use of +Covered Code within Your business or organization or in conjunction with +other Licensees with equivalent Research Use rights. Commercial Use +includes any use of the Covered Code for direct or indirect commercial +or strategic gain, advantage or other business purpose. Any Commercial +Use requires execution of Attachment D by You and Original Contributor. + +5. "*Community Code*" means the Original Code, Upgraded Code, Error +Corrections, Shared Modifications, or any combination thereof. + +6. "*Community Webserver(s)"* means the webservers designated by +Original Contributor for access to the Original Code, Upgraded Code, TCK +and Specifications and for posting Error Corrections and Shared +Modifications. + +7. "*Compliant Covered Code*" means Covered Code that complies with the +requirements of the TCK. + +8. "*Contributor*" means each Licensee that creates or contributes to +the creation of any Error Correction or Shared Modification. + +9. "*Covered Code*" means the Original Code, Upgraded Code, +Modifications, or any combination thereof. + +10. "*Error Correction*" means any change made to Community Code which +conforms to the Specification and corrects the adverse effect of a +failure of Community Code to perform any function set forth in or +required by the Specifications. + +11. "*Executable*" means Covered Code that has been converted from +Source Code to the preferred form for execution by a computer or digital +processor (e.g. binary form). + +12. "*Extension(s)"* means any additional Interfaces developed by or for +You which: (i) are designed for use with the Technology; (ii) constitute +an API for a library of computing functions or services; and (iii) are +disclosed or otherwise made available to third party software developers +for the purpose of developing software which invokes such additional +Interfaces. The foregoing shall not apply to software developed by Your +subcontractors to be exclusively used by You. + +13. "*Header File(s)"* means that portion of the Source Code that +provides the names and types of member functions, data members, class +definitions, and interface definitions necessary to implement the APIs +for the Covered Code. Header Files include, files specifically +designated by Original Contributor as Header Files. Header Files do not +include the code necessary to implement the functionality underlying the +Interface. + +14. *"Helix DNA Server Technology"* means the program(s) that implement +the Helix Universal Server streaming engine for the Technology as +defined in the Specification. + +15. *"Helix DNA Client Technology"* means the Covered Code that +implements the RealOne Player engine as defined in the Specification. + +16. *"Helix DNA Producer Technology"* means the Covered Code that +implements the Helix Producer engine as defined in the Specification. + +17. *"Helix DNA Technology"* means the Helix DNA Server Technology, the +Helix DNA Client Technology, the Helix DNA Producer Technology and other +Helix technologies designated by Original Contributor. + +18. "*Intellectual Property Rights*" means worldwide statutory and +common law rights associated solely with (i) Applicable Patent Rights; +(ii) works of authorship including copyrights, copyright applications, +copyright registrations and "moral rights"; (iii) the protection of +trade and industrial secrets and confidential information; and (iv) +divisions, continuations, renewals, and re-issuances of the foregoing +now existing or acquired in the future. + +19. *"Interface*" means interfaces, functions, properties, class +definitions, APIs, Header Files, GUIDs, V-Tables, and/or protocols +allowing one piece of software, firmware or hardware to communicate or +interoperate with another piece of software, firmware or hardware. + +20. "*Internal Deployment Use*" means use of Compliant Covered Code +(excluding Research Use) within Your business or organization only by +Your employees and/or agents on behalf of Your business or organization, +but not to provide services, including content distribution, to third +parties, subject to execution of Attachment D by You and Original +Contributor, if required. + +21. "*Licensee*" means any party that has entered into and has in effect +a version of this License with Original Contributor. + +22. "*MIME type*" means a description of what type of media or other +content is in a file, including by way of example but not limited to +'audio/x-pn-realaudio-plugin.' + +23. "*Modification(s)"* means (i) any addition to, deletion from and/or +change to the substance and/or structure of the Covered Code, including +Interfaces; (ii) the combination of any Covered Code and any previous +Modifications; (iii) any new file or other representation of computer +program statements that contains any portion of Covered Code; and/or +(iv) any new Source Code implementing any portion of the Specifications. + +24. "*MP3 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Picture Experts Group known as MPEG-1 Audio Layer-3 or MP3, +including but not limited to all past and future versions, profiles, +extensions, parts and amendments relating to the MP3 specification. + +25. "*MPEG-4 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Pictures Experts Group known as MPEG-4, including but not +limited to all past and future versions, profiles, extensions, parts and +amendments relating to the MPEG-4 specification. + +26. "*Original Code*" means the initial Source Code for the Technology +as described on the Community Web Server. + +27. "*Original Contributor*" means RealNetworks, Inc., its affiliates +and its successors and assigns. + +28. "*Original Contributor MIME Type*" means the MIME registry, browser +preferences, or local file/protocol associations invoking any Helix DNA +Client-based application, including the RealOne Player, for playback of +RealAudio, RealVideo, other RealMedia MIME types or datatypes (e.g., +.ram, .rnx, .rpm, .ra, .rm, .rp, .rt, .rf, .prx, .mpe, .rmp, .rmj, .rav, +.rjs, .rmx, .rjt, .rms), and any other Original Contributor-specific or +proprietary MIME types that Original Contributor may introduce in the +future. + +29. "*Personal Use*" means use of Covered Code by an individual solely +for his or her personal, private and non-commercial purposes. An +individual's use of Covered Code in his or her capacity as an officer, +employee, member, independent contractor or agent of a corporation, +business or organization (commercial or non-commercial) does not qualify +as Personal Use. + +30. "*RealMedia File Format*" means the file format designed and +developed by RealNetworks for storing multimedia data and used to store +RealAudio and RealVideo encoded streams. Valid RealMedia File Format +extensions include: .rm, .rmj, .rmc, .rmvb, .rms. + +31. "*RCSL Webpage*" means the RealNetworks Community Source License +webpage located at https://www.helixcommunity.org/content/rcsl or such +other URL that Original Contributor may designate from time to time. + +32. "*Reformatted Specifications*" means any revision to the +Specifications which translates or reformats the Specifications (as for +example in connection with Your documentation) but which does not alter, +subset or superset * *the functional or operational aspects of the +Specifications. + +33. "*Research Use*" means use and distribution of Covered Code only for +Your Personal Use, research or development use and expressly excludes +Internal Deployment Use and Commercial Use. Research Use also includes +use of Covered Code to teach individuals how to use Covered Code. + +34. "*Shared Modifications*" means Modifications that You distribute or +use for a Commercial Use, in addition to any Modifications provided by +You, at Your option, pursuant to Section 2.2, or received by You from a +Contributor pursuant to Section 2.3. + +35. "*Source Code*" means the preferred form of the Covered Code for +making modifications to it, including all modules it contains, plus any +associated interface definition files, scripts used to control +compilation and installation of an Executable, or source code +differential comparisons against either the Original Code or another +well known, available Covered Code of the Contributor's choice. The +Source Code can be in a compressed or archival form, provided the +appropriate decompression or de-archiving software is widely available +for no charge. + +36. "*Specifications*" means the specifications for the Technology and +other documentation, as designated on the Community Web Server, as may +be revised by Original Contributor from time to time. + +37. "*Trademarks*" means Original Contributor's trademarks and logos, +including, but not limited to, RealNetworks, RealAudio, RealVideo, +RealOne, RealSystem, SureStream, Helix, Helix DNA and other trademarks +whether now used or adopted in the future. + +38. "*Technology*" means the technology described in Attachment B, and +Upgrades. + +39. "*Technology Compatibility Kit"* or *"TCK*" means the test programs, +procedures, acceptance criteria and/or other requirements, designated by +Original Contributor for use in verifying compliance of Covered Code +with the Specifications, in conjunction with the Original Code and +Upgraded Code. Original Contributor may, in its sole discretion and from +time to time, revise a TCK to correct errors and/or omissions and in +connection with Upgrades. + +40. "*Upgrade(s)"* means new versions of Technology designated +exclusively by Original Contributor as an "Upgrade" and released by +Original Contributor from time to time under the terms of the License. + +41. "*Upgraded Code*" means the Source Code and/or Executables for +Upgrades, possibly including Modifications made by Contributors. + +42. *"User's Guide"* means the users guide for the TCK which Original +Contributor makes available to You to provide direction in how to run +the TCK and properly interpret the results, as may be revised by +Original Contributor from time to time. + +43. "*You(r)*" means an individual, or a legal entity acting by and +through an individual or individuals, exercising rights either under +this License or under a future version of this License issued pursuant +to Section 4.1. For legal entities, "You(r)" includes any entity that by +majority voting interest controls, is controlled by, or is under common +control with You. + +44. "*Your Products*" means any (i) hardware products You distribute +integrating the Covered Code; (ii) any software products You distribute +with the Covered Code that utilize the APIs of the Covered Code; or +(iii) any services You provide using the Covered Code. + + + ATTACHMENT A + +REQUIRED NOTICES + + + ATTACHMENT A-1 + +REQUIRED IN ALL CASES + +Notice to be included in header file of all Error Corrections and Shared +Modifications: + +Portions Copyright 1994-2003 RealNetworks, Inc. All rights reserved. + +The contents of this file, and the files included with this file, are +subject to the current version of RealNetworks Community Source License +Version 1.1 (the "License"). You may not use this file except in +compliance with the License executed by both You and RealNetworks. You +may obtain a copy of the License at * +https://www.helixcommunity.org/content/rcsl.* You may also obtain a copy +of the License by contacting RealNetworks directly. Please see the +License for the rights, obligations and limitations governing use of the +contents of the file. + +This file is part of the Helix DNA technology. RealNetworks, Inc., is +the developer of the Original code and owns the copyrights in the +portions it created. + +This file, and the files included with this file, are distributed on an +'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, +AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): + +_______________________________________________ + +Technology Compatibility Kit Test Suite(s) Location: + +________________________________ + + + ATTACHMENT A-2 + +SAMPLE LICENSEE CERTIFICATION + +"By clicking the `Agree' button below, You certify that You are a +Licensee in good standing under the RealNetworks Community Source +License, ("License") and that Your access, use and distribution of code +and information You may obtain at this site is subject to the License. +If You are not a Licensee under the RealNetworks Community Source +License You agree not to download, copy or use the Helix DNA technology. + + + ATTACHMENT A-3 + +REQUIRED STUDENT NOTIFICATION + +"This software and related documentation has been obtained by Your +educational institution subject to the RealNetworks Community Source +License. You have been provided access to the software and related +documentation for use only in connection with your course work and +research activities as a matriculated student of Your educational +institution. Any other use is expressly prohibited. + +THIS SOFTWARE AND RELATED DOCUMENTATION CONTAINS PROPRIETARY MATERIAL OF +REALNETWORKS, INC, WHICH ARE PROTECTED BY VARIOUS INTELLECTUAL PROPERTY +RIGHTS. + +You may not use this file except in compliance with the License. You may +obtain a copy of the License on the web at +https://www.helixcommunity.org/content/rcsl. + +* +* + + + ATTACHMENT B + +Description of Technology + +Helix DNA, which consists of Helix DNA Client, Helix DNA Server and +Helix DNA Producer. + +Description of "Technology" + +Helix DNA Technology v1.0 as described on the Community Web Server. + + + ATTACHMENT C + +TECHNOLOGY COMPATIBILITY KIT LICENSE + +The following license is effective for the *Helix DNA* Technology +Compatibility Kit - as described on the Community Web Server. The +Technology Compatibility Kit(s) for the Technology specified in +Attachment B may be accessed at the Community Web Server. + +1. TCK License. + +1.1 Grants to use TCK + +Subject to the terms and restrictions set forth below and the +RealNetworks Community Source License, and the Research Use license, +Original Contributor grants to You a worldwide, non-exclusive, +non-transferable license, to the extent of Original Contributor's +Intellectual Property Rights in the TCK (without the right to +sublicense), to use the TCK to develop and test Covered Code. + +1.2 TCK Use Restrictions. + +You are not authorized to create derivative works of the TCK or use the +TCK to test any implementation of the Specification that is not Covered +Code. You may not publish Your test results or make claims of +comparative compatibility with respect to other implementations of the +Specification. In consideration for the license grant in Section 1.1 +above You agree not to develop Your own tests that are intended to +validate conformation with the Specification. + +2. Test Results. + +You agree to provide to Original Contributor or the third party test +facility if applicable, Your test results that demonstrate that Covered +Code is Compliant Covered Code and that Original Contributor may publish +or otherwise distribute such test results. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH THE ORIGINAL CONTRIBUTOR, REALNETWORKS, +INC. IF YOU ARE AGREEING TO THIS LICENSE ON BEHALF OF A COMPANY, YOU +REPRESENT THAT YOU ARE AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. +WHETHER YOU ARE ACTING ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, +YOU MUST BE OF MAJORITY AGE AND BE OTHERWISE COMPETENT TO ENTER INTO +CONTRACTS. IF YOU DO NOT MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY +OF THE TERMS AND CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON +TO EXIT. + +*ACCEPT / REJECT +* + +* +* + +*To agree to the R&D/academic terms of this license, please register + on the site -- +you will then be given a chance to agree to the clickwrap RCSL + +R&D License + +and gain access to the RCSL-licensed source code. To build or deploy +commercial applications based on the RCSL, you will need to agree to the +Commercial Use license attachments +* + + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/RPSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/RPSL.txt new file mode 100644 index 0000000..d040a45 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/RPSL.txt @@ -0,0 +1,518 @@ +RealNetworks Public Source License Version 1.0 +(Rev. Date October 28, 2002) + +1. General Definitions. This License applies to any program or other work which +RealNetworks, Inc., or any other entity that elects to use this license, +("Licensor") makes publicly available and which contains a notice placed by +Licensor identifying such program or work as "Original Code" and stating that it +is subject to the terms of this RealNetworks Public Source License version 1.0 +(or subsequent version thereof) ("License"). You are not required to accept this +License. However, nothing else grants You permission to use, copy, modify or +distribute the software or its derivative works. These actions are prohibited by +law if You do not accept this License. Therefore, by modifying, copying or +distributing the software (or any work based on the software), You indicate your +acceptance of this License to do so, and all its terms and conditions. In +addition, you agree to the terms of this License by clicking the Accept button +or downloading the software. As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Licensor is the +grantor of rights, claims of patents that (i) are now or hereafter acquired, +owned by or assigned to Licensor and (ii) are necessarily infringed by using or +making the Original Code alone and not in combination with other software or +hardware; and (b) in the case where You are the grantor of rights, claims of +patents that (i) are now or hereafter acquired, owned by or assigned to You and +(ii) are infringed (directly or indirectly) by using or making Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Compatible Source License" means any one of the licenses listed on Exhibit +B or at https://www.helixcommunity.org/content/complicense or other licenses +specifically identified by Licensor in writing. Notwithstanding any term to the +contrary in any Compatible Source License, any code covered by any Compatible +Source License that is used with Covered Code must be made readily available in +Source Code format for royalty-free use under the terms of the Compatible Source +License or this License. + +1.3 "Contributor" means any person or entity that creates or contributes to the +creation of Modifications. + +1.4 "Covered Code" means the Original Code, Modifications, the combination of +Original Code and any Modifications, and/or any respective portions thereof. + +1.5 "Deploy" means to use, sublicense or distribute Covered Code other than for +Your internal research and development (R&D) and/or Personal Use, and includes +without limitation, any and all internal use or distribution of Covered Code +within Your business or organization except for R&D use and/or Personal Use, as +well as direct or indirect sublicensing or distribution of Covered Code by You +to any third party in any form or manner. + +1.6 "Derivative Work" means either the Covered Code or any derivative work under +United States copyright law, and including any work containing or including any +portion of the Covered Code or Modifications, either verbatim or with +modifications and/or translated into another language. Derivative Work also +includes any work which combines any portion of Covered Code or Modifications +with code not otherwise governed by the terms of this License. + +1.7 "Externally Deploy" means to Deploy the Covered Code in any way that may be +accessed or used by anyone other than You, used to provide any services to +anyone other than You, or used in any way to deliver any content to anyone other +than You, whether the Covered Code is distributed to those parties, made +available as an application intended for use over a computer network, or used to +provide services or otherwise deliver content to anyone other than You. + +1.8. "Interface" means interfaces, functions, properties, class definitions, +APIs, header files, GUIDs, V-Tables, and/or protocols allowing one piece of +software, firmware or hardware to communicate or interoperate with another piece +of software, firmware or hardware. + +1.9 "Modifications" mean any addition to, deletion from, and/or change to, the +substance and/or structure of the Original Code, any previous Modifications, the +combination of Original Code and any previous Modifications, and/or any +respective portions thereof. When code is released as a series of files, a +Modification is: (a) any addition to or deletion from the contents of a file +containing Covered Code; and/or (b) any new file or other representation of +computer program statements that contains any part of Covered Code. + +1.10 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Licensor under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Licensor under this License, and that has been expressly identified by Licensor +as such in the header file(s) of such work; and (b) the object code compiled +from such Source Code and originally made available by Licensor under this +License. + +1.11 "Personal Use" means use of Covered Code by an individual solely for his or +her personal, private and non-commercial purposes. An individual's use of +Covered Code in his or her capacity as an officer, employee, member, independent +contractor or agent of a corporation, business or organization (commercial or +non-commercial) does not qualify as Personal Use. + +1.12 "Source Code" means the human readable form of a program or other work that +is suitable for making modifications to it, including all modules it contains, +plus any associated interface definition files, scripts used to control +compilation and installation of an executable (object code). + +1.13 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership of +fifty percent (50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Licensor hereby grants You, effective on the date +You accept this License (via downloading or using Covered Code or otherwise +indicating your acceptance of this License), a worldwide, royalty-free, +non-exclusive copyright license, to the extent of Licensor's copyrights cover +the Original Code, to do the following: + +2.1 You may reproduce, display, perform, modify and Deploy Covered Code, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the copyright +and other proprietary notices and disclaimers of Licensor as they appear in the +Original Code, and keep intact all notices in the Original Code that refer to +this License; + +(b) You must include a copy of this License with every copy of Source Code of +Covered Code and documentation You distribute, and You may not offer or impose +any terms on such Source Code that alter or restrict this License or the +recipients' rights hereunder, except as permitted under Section 6; + +(c) You must duplicate, to the extent it does not already exist, the notice in +Exhibit A in each file of the Source Code of all Your Modifications, and cause +the modified files to carry prominent notices stating that You changed the files +and the date of any change; + +(d) You must make Source Code of all Your Externally Deployed Modifications +publicly available under the terms of this License, including the license grants +set forth in Section 3 below, for as long as you Deploy the Covered Code or +twelve (12) months from the date of initial Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Deployed Modifications +electronically (e.g. download from a web site); and + +(e) if You Deploy Covered Code in object code, executable form only, You must +include a prominent notice, in the code itself as well as in related +documentation, stating that Source Code of the Covered Code is available under +the terms of this License with information on how and where to obtain such +Source Code. You must also include the Object Code Notice set forth in Exhibit A +in the "about" box or other appropriate place where other copyright notices are +placed, including any packaging materials. + +2.2 You expressly acknowledge and agree that although Licensor and each +Contributor grants the licenses to their respective portions of the Covered Code +set forth herein, no assurances are provided by Licensor or any Contributor that +the Covered Code does not infringe the patent or other intellectual property +rights of any other entity. Licensor and each Contributor disclaim any liability +to You for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, You hereby assume sole responsibility to +secure any other intellectual property rights needed, if any. For example, if a +third party patent license is required to allow You to make, use, sell, import +or offer for sale the Covered Code, it is Your responsibility to acquire such +license(s). + +2.3 Subject to the terms and conditions of this License, Licensor hereby grants +You, effective on the date You accept this License (via downloading or using +Covered Code or otherwise indicating your acceptance of this License), a +worldwide, royalty-free, perpetual, non-exclusive patent license under +Licensor's Applicable Patent Rights to make, use, sell, offer for sale and +import the Covered Code, provided that in each instance you comply with the +terms of this License. + +3. Your Grants. In consideration of, and as a condition to, the licenses granted +to You under this License: + +(a) You grant to Licensor and all third parties a non-exclusive, perpetual, +irrevocable, royalty free license under Your Applicable Patent Rights and other +intellectual property rights owned or controlled by You, to make, sell, offer +for sale, use, import, reproduce, display, perform, modify, distribute and +Deploy Your Modifications of the same scope and extent as Licensor's licenses +under Sections 2.1 and 2.2; and + +(b) You grant to Licensor and its subsidiaries a non-exclusive, worldwide, +royalty-free, perpetual and irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights owned or controlled by You, to +make, use, sell, offer for sale, import, reproduce, display, perform, +distribute, modify or have modified (for Licensor and/or its subsidiaries), +sublicense and distribute Your Modifications, in any form and for any purpose, +through multiple tiers of distribution. + +(c) You agree not use any information derived from Your use and review of the +Covered Code, including but not limited to any algorithms or inventions that may +be contained in the Covered Code, for the purpose of asserting any of Your +patent rights, or assisting a third party to assert any of its patent rights, +against Licensor or any Contributor. + +4. Derivative Works. You may create a Derivative Work by combining Covered Code +with other code not otherwise governed by the terms of this License and +distribute the Derivative Work as an integrated product. In each such instance, +You must make sure the requirements of this License are fulfilled for the +Covered Code or any portion thereof, including all Modifications. + +4.1 You must cause any Derivative Work that you distribute, publish or +Externally Deploy, that in whole or in part contains or is derived from the +Covered Code or any part thereof, to be licensed as a whole at no charge to all +third parties under the terms of this License and no other license except as +provided in Section 4.2. You also must make Source Code available for the +Derivative Work under the same terms as Modifications, described in Sections 2 +and 3, above. + +4.2 Compatible Source Licenses. Software modules that have been independently +developed without any use of Covered Code and which contain no portion of the +Covered Code, Modifications or other Derivative Works, but are used or combined +in any way wtih the Covered Code or any Derivative Work to form a larger +Derivative Work, are exempt from the conditions described in Section 4.1 but +only to the extent that: the software module, including any software that is +linked to, integrated with, or part of the same applications as, the software +module by any method must be wholly subject to one of the Compatible Source +Licenses. Notwithstanding the foregoing, all Covered Code must be subject to the +terms of this License. Thus, the entire Derivative Work must be licensed under a +combination of the RPSL (for Covered Code) and a Compatible Source License for +any independently developed software modules within the Derivative Work. The +foregoing requirement applies even if the Compatible Source License would +ordinarily allow the software module to link with, or form larger works with, +other software that is not subject to the Compatible Source License. For +example, although the Mozilla Public License v1.1 allows Mozilla code to be +combined with proprietary software that is not subject to the MPL, if +MPL-licensed code is used with Covered Code the MPL-licensed code could not be +combined or linked with any code not governed by the MPL. The general intent of +this section 4.2 is to enable use of Covered Code with applications that are +wholly subject to an acceptable open source license. You are responsible for +determining whether your use of software with Covered Code is allowed under Your +license to such software. + +4.3 Mere aggregation of another work not based on the Covered Code with the +Covered Code (or with a work based on the Covered Code) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. If You deliver the Covered Code for combination and/or integration with +an application previously provided by You (for example, via automatic updating +technology), such combination and/or integration constitutes a Derivative Work +subject to the terms of this License. + +5. Exclusions From License Grant. Nothing in this License shall be deemed to +grant any rights to trademarks, copyrights, patents, trade secrets or any other +intellectual property of Licensor or any Contributor except as expressly stated +herein. No right is granted to the trademarks of Licensor or any Contributor +even if such marks are included in the Covered Code. Nothing in this License +shall be interpreted to prohibit Licensor from licensing under different terms +from this License any code that Licensor otherwise would have a right to +license. Modifications, Derivative Works and/or any use or combination of +Covered Code with other technology provided by Licensor or third parties may +require additional patent licenses from Licensor which Licensor may grant in its +sole discretion. No patent license is granted separate from the Original Code or +combinations of the Original Code with other software or hardware. + +5.1. Trademarks. This License does not grant any rights to use the trademarks or +trade names owned by Licensor ("Licensor Marks" defined in Exhibit C) or to any +trademark or trade name belonging to any Contributor. No Licensor Marks may be +used to endorse or promote products derived from the Original Code other than as +permitted by the Licensor Trademark Policy defined in Exhibit C. + +6. Additional Terms. You may choose to offer, and to charge a fee for, warranty, +support, indemnity or liability obligations and/or other rights consistent with +the scope of the license granted herein ("Additional Terms") to one or more +recipients of Covered Code. However, You may do so only on Your own behalf and +as Your sole responsibility, and not on behalf of Licensor or any Contributor. +You must obtain the recipient's agreement that any such Additional Terms are +offered by You alone, and You hereby agree to indemnify, defend and hold +Licensor and every Contributor harmless for any liability incurred by or claims +asserted against Licensor or such Contributor by reason of any such Additional +Terms. + +7. Versions of the License. Licensor may publish revised and/or new versions of +this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular version +of this License, You may continue to use it under the terms of that version. You +may also choose to use such Original Code under the terms of any subsequent +version of this License published by Licensor. No one other than Licensor has +the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in part +pre-release, untested, or not fully tested works. The Covered Code may contain +errors that could cause failures or loss of data, and may be incomplete or +contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND LICENSOR AND LICENSOR'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS +"LICENSOR" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY +DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET +ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. LICENSOR AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN DOCUMENTATION, INFORMATION OR ADVICE GIVEN BY LICENSOR, A LICENSOR +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You +acknowledge that the Covered Code is not intended for use in high risk +activities, including, but not limited to, the design, construction, operation +or maintenance of nuclear facilities, aircraft navigation, aircraft +communication systems, or air traffic control machines in which case the failure +of the Covered Code could lead to death, personal injury, or severe physical or +environmental damage. Licensor disclaims any express or implied warranty of +fitness for such uses. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT +SHALL LICENSOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR STRICT +LIABILITY), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF LICENSOR OR SUCH +CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND +NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. SOME +JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF INCIDENTAL OR +CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event +shall Licensor's total liability to You for all damages (other than as may be +required by applicable law) under this License exceed the amount of ten dollars +($10.00). + +10. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Licensor retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Licensor +("Licensor Modifications"), and such Licensor Modifications will not be +automatically subject to this License. Licensor may, at its sole discretion, +choose to license such Licensor Modifications under this License, or on +different terms from those contained in this License or may choose not to +license them at all. + +11. Termination. + +11.1 Term and Termination. The term of this License is perpetual unless +terminated as provided below. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Licensor if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; + +(b) immediately in the event of the circumstances described in Section 12.5(b); +or + +(c) automatically without notice from Licensor if You, at any time during the +term of this License, commence an action for patent infringement against +Licensor (including by cross-claim or counter claim in a lawsuit); + +(d) upon written notice from Licensor if You, at any time during the term of +this License, commence an action for patent infringement against any third party +alleging that the Covered Code itself (excluding combinations with other +software or hardware) infringes any patent (including by cross-claim or counter +claim in a lawsuit). + +11.2 Effect of Termination. Upon termination, You agree to immediately stop any +further use, reproduction, modification, sublicensing and distribution of the +Covered Code and to destroy all copies of the Covered Code that are in your +possession or control. All sublicenses to the Covered Code which have been +properly granted prior to termination shall survive any termination of this +License. Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to Sections +3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other for +compensation, indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this License will +be without prejudice to any other right or remedy of any party. + +12. Miscellaneous. + +12.1 Government End Users. The Covered Code is a "commercial item" as defined in +FAR 2.101. Government software and technical data rights in the Covered Code +include only those rights customarily provided to the public as defined in this +License. This customary commercial license in technical data and software is +provided in accordance with FAR 12.211 (Technical Data) and 12.212 (Computer +Software) and, for Department of Defense purchases, DFAR 252.227-7015 (Technical +Data -- Commercial Items) and 227.7202-3 (Rights in Commercial Computer Software +or Computer Software Documentation). Accordingly, all U.S. Government End Users +acquire Covered Code with only those rights set forth herein. + +12.2 Relationship of Parties. This License will not be construed as creating an +agency, partnership, joint venture or any other form of legal association +between or among You, Licensor or any Contributor, and You will not represent to +the contrary, whether expressly, by implication, appearance or otherwise. + +12.3 Independent Development. Nothing in this License will impair Licensor's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions as, +or otherwise compete with, Modifications, Derivative Works, technology or +products that You may develop, produce, market or distribute. + +12.4 Waiver; Construction. Failure by Licensor or any Contributor to enforce any +provision of this License will not be deemed a waiver of future enforcement of +that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +12.5 Severability. (a) If for any reason a court of competent jurisdiction finds +any provision of this License, or portion thereof, to be unenforceable, that +provision of the License will be enforced to the maximum extent permissible so +as to effect the economic benefits and intent of the parties, and the remainder +of this License will continue in full force and effect. (b) Notwithstanding the +foregoing, if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the enforceability +of either of those Sections, this License will immediately terminate and You +must immediately discontinue any use of the Covered Code and destroy all copies +of it that are in your possession or control. + +12.6 Dispute Resolution. Any litigation or other dispute resolution between You +and Licensor relating to this License shall take place in the Seattle, +Washington, and You and Licensor hereby consent to the personal jurisdiction of, +and venue in, the state and federal courts within that District with respect to +this License. The application of the United Nations Convention on Contracts for +the International Sale of Goods is expressly excluded. + +12.7 Export/Import Laws. This software is subject to all export and import laws +and restrictions and regulations of the country in which you receive the Covered +Code and You are solely responsible for ensuring that You do not export, +re-export or import the Covered Code or any direct product thereof in violation +of any such restrictions, laws or regulations, or without all necessary +authorizations. + +12.8 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +Washington. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé +que le présent contrat et tous les documents connexes soient +rédigés en anglais. + + EXHIBIT A. + +"Copyright © 1995-2002 +RealNetworks, Inc. and/or its licensors. All Rights Reserved. + +The contents of this file, and the files included with this file, are subject to +the current version of the RealNetworks Public Source License Version 1.0 (the +"RPSL") available at https://www.helixcommunity.org/content/rpsl unless you have +licensed the file under the RealNetworks Community Source License Version 1.0 +(the "RCSL") available at https://www.helixcommunity.org/content/rcsl, in which +case the RCSL will apply. You may also obtain the license terms directly from +RealNetworks. You may not use this file except in compliance with the RPSL or, +if you have a valid RCSL with RealNetworks applicable to this file, the RCSL. +Please see the applicable RPSL or RCSL for the rights, obligations and +limitations governing use of the contents of the file. + +This file is part of the Helix DNA Technology. RealNetworks is the developer of +the Original code and owns the copyrights in the portions it created. + +This file, and the files included with this file, is distributed and made +available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR +IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING +WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): ____________________________________ + +Technology Compatibility Kit Test +Suite(s) Location (if licensed under the RCSL): ______________________________ + +Object Code Notice: Helix DNA Client technology included. Copyright (c) +RealNetworks, Inc., 1995-2002. All rights reserved. + + + EXHIBIT B + +Compatible Source Licenses for the RealNetworks Public Source License. The +following list applies to the most recent version of the license as of October +25, 2002, unless otherwise indicated. + +* Academic Free License +* Apache Software License +* Apple Public Source License +* Artistic license +* Attribution Assurance Licenses +* BSD license +* Common Public License (1) +* Eiffel Forum License +* GNU General Public License (GPL) (1) +* GNU Library or "Lesser" General Public License (LGPL) (1) +* IBM Public License +* Intel Open Source License +* Jabber Open Source License +* MIT license +* MITRE Collaborative Virtual Workspace License (CVW License) +* Motosoto License +* Mozilla Public License 1.0 (MPL) +* Mozilla Public License 1.1 (MPL) +* Nokia Open Source License +* Open Group Test Suite License +* Python Software Foundation License +* Ricoh Source Code Public License +* Sun Industry Standards Source License (SISSL) +* Sun Public License +* University of Illinois/NCSA Open Source License +* Vovida Software License v. 1.0 +* W3C License +* X.Net License +* Zope Public License +* zlib/libpng license + +(1) Note: because this license contains certain reciprocal licensing terms that +purport to extend to independently developed code, You may be prohibited under +the terms of this otherwise compatible license from using code licensed under +its terms with Covered Code because Covered Code may only be licensed under the +RealNetworks Public Source License. Any attempt to apply non RPSL license terms, +including without limitation the GPL, to Covered Code is expressly forbidden. +You are responsible for ensuring that Your use of Compatible Source Licensed +code does not violate either the RPSL or the Compatible Source License. + +The latest version of this list can be found at: +https://www.helixcommunity.org/content/complicense + + EXHIBIT C + +RealNetworks' Trademark policy. + +RealNetworks defines the following trademarks collectively as "Licensor +Trademarks": "RealNetworks", "RealPlayer", "RealJukebox", "RealSystem", +"RealAudio", "RealVideo", "RealOne Player", "RealMedia", "Helix" or any other +trademarks or trade names belonging to RealNetworks. + +RealNetworks "Licensor Trademark Policy" forbids any use of Licensor Trademarks +except as permitted by and in strict compliance at all times with RealNetworks' +third party trademark usage guidelines which are posted at +http://www.realnetworks.com/info/helixlogo.html. + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/cpuusage.xls b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/cpuusage.xls new file mode 100644 index 0000000..3bbf55c Binary files /dev/null and b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/cpuusage.xls differ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/memory.xls b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/memory.xls new file mode 100644 index 0000000..c023f9e Binary files /dev/null and b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/docs/memory.xls differ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/mp3dec.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/mp3dec.c new file mode 100644 index 0000000..5e68c7a --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/mp3dec.c @@ -0,0 +1,484 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * mp3dec.c - platform-independent top level MP3 decoder API + **************************************************************************************/ + +#include "string.h" +//#include "hlxclib/string.h" /* for memmove, memcpy (can replace with different implementations if desired) */ +#include "mp3common.h" /* includes mp3dec.h (public API) and internal, platform-independent API */ + + +//#define PROFILE +#ifdef PROFILE +#include "systime.h" +#endif + +/************************************************************************************** + * Function: MP3InitDecoder + * + * Description: allocate memory for platform-specific data + * clear all the user-accessible fields + * + * Inputs: none + * + * Outputs: none + * + * Return: handle to mp3 decoder instance, 0 if malloc fails + **************************************************************************************/ +HMP3Decoder MP3InitDecoder(void) +{ + MP3DecInfo *mp3DecInfo; + + mp3DecInfo = AllocateBuffers(); + + return (HMP3Decoder)mp3DecInfo; +} + +/************************************************************************************** + * Function: MP3FreeDecoder + * + * Description: free platform-specific data allocated by InitMP3Decoder + * zero out the contents of MP3DecInfo struct + * + * Inputs: valid MP3 decoder instance pointer (HMP3Decoder) + * + * Outputs: none + * + * Return: none + **************************************************************************************/ +void MP3FreeDecoder(HMP3Decoder hMP3Decoder) +{ + MP3DecInfo *mp3DecInfo = (MP3DecInfo *)hMP3Decoder; + + if (!mp3DecInfo) + return; + + FreeBuffers(mp3DecInfo); +} + +/************************************************************************************** + * Function: MP3FindSyncWord + * + * Description: locate the next byte-alinged sync word in the raw mp3 stream + * + * Inputs: buffer to search for sync word + * max number of bytes to search in buffer + * + * Outputs: none + * + * Return: offset to first sync word (bytes from start of buf) + * -1 if sync not found after searching nBytes + **************************************************************************************/ +int MP3FindSyncWord(unsigned char *buf, int nBytes) +{ + int i; + + /* find byte-aligned syncword - need 12 (MPEG 1,2) or 11 (MPEG 2.5) matching bits */ + for (i = 0; i < nBytes - 1; i++) { + if ( (buf[i+0] & SYNCWORDH) == SYNCWORDH && (buf[i+1] & SYNCWORDL) == SYNCWORDL ) + return i; + } + + return -1; +} + +/************************************************************************************** + * Function: MP3FindFreeSync + * + * Description: figure out number of bytes between adjacent sync words in "free" mode + * + * Inputs: buffer to search for next sync word + * the 4-byte frame header starting at the current sync word + * max number of bytes to search in buffer + * + * Outputs: none + * + * Return: offset to next sync word, minus any pad byte (i.e. nSlots) + * -1 if sync not found after searching nBytes + * + * Notes: this checks that the first 22 bits of the next frame header are the + * same as the current frame header, but it's still not foolproof + * (could accidentally find a sequence in the bitstream which + * appears to match but is not actually the next frame header) + * this could be made more error-resilient by checking several frames + * in a row and verifying that nSlots is the same in each case + * since free mode requires CBR (see spec) we generally only call + * this function once (first frame) then store the result (nSlots) + * and just use it from then on + **************************************************************************************/ +static int MP3FindFreeSync(unsigned char *buf, unsigned char firstFH[4], int nBytes) +{ + int offset = 0; + unsigned char *bufPtr = buf; + + /* loop until we either: + * - run out of nBytes (FindMP3SyncWord() returns -1) + * - find the next valid frame header (sync word, version, layer, CRC flag, bitrate, and sample rate + * in next header must match current header) + */ + while (1) { + offset = MP3FindSyncWord(bufPtr, nBytes); + bufPtr += offset; + if (offset < 0) { + return -1; + } else if ( (bufPtr[0] == firstFH[0]) && (bufPtr[1] == firstFH[1]) && ((bufPtr[2] & 0xfc) == (firstFH[2] & 0xfc)) ) { + /* want to return number of bytes per frame, NOT counting the padding byte, so subtract one if padFlag == 1 */ + if ((firstFH[2] >> 1) & 0x01) + bufPtr--; + return bufPtr - buf; + } + bufPtr += 3; + nBytes -= (offset + 3); + }; + + return -1; +} + +/************************************************************************************** + * Function: MP3GetLastFrameInfo + * + * Description: get info about last MP3 frame decoded (number of sampled decoded, + * sample rate, bitrate, etc.) + * + * Inputs: valid MP3 decoder instance pointer (HMP3Decoder) + * pointer to MP3FrameInfo struct + * + * Outputs: filled-in MP3FrameInfo struct + * + * Return: none + * + * Notes: call this right after calling MP3Decode + **************************************************************************************/ +void MP3GetLastFrameInfo(HMP3Decoder hMP3Decoder, MP3FrameInfo *mp3FrameInfo) +{ + MP3DecInfo *mp3DecInfo = (MP3DecInfo *)hMP3Decoder; + + if (!mp3DecInfo || mp3DecInfo->layer != 3) { + mp3FrameInfo->bitrate = 0; + mp3FrameInfo->nChans = 0; + mp3FrameInfo->samprate = 0; + mp3FrameInfo->bitsPerSample = 0; + mp3FrameInfo->outputSamps = 0; + mp3FrameInfo->layer = 0; + mp3FrameInfo->version = 0; + } else { + mp3FrameInfo->bitrate = mp3DecInfo->bitrate; + mp3FrameInfo->nChans = mp3DecInfo->nChans; + mp3FrameInfo->samprate = mp3DecInfo->samprate; + mp3FrameInfo->bitsPerSample = 16; + mp3FrameInfo->outputSamps = mp3DecInfo->nChans * (int)samplesPerFrameTab[mp3DecInfo->version][mp3DecInfo->layer - 1]; + mp3FrameInfo->layer = mp3DecInfo->layer; + mp3FrameInfo->version = mp3DecInfo->version; + } +} + +/************************************************************************************** + * Function: MP3GetNextFrameInfo + * + * Description: parse MP3 frame header + * + * Inputs: valid MP3 decoder instance pointer (HMP3Decoder) + * pointer to MP3FrameInfo struct + * pointer to buffer containing valid MP3 frame header (located using + * MP3FindSyncWord(), above) + * + * Outputs: filled-in MP3FrameInfo struct + * + * Return: error code, defined in mp3dec.h (0 means no error, < 0 means error) + **************************************************************************************/ +int MP3GetNextFrameInfo(HMP3Decoder hMP3Decoder, MP3FrameInfo *mp3FrameInfo, unsigned char *buf) +{ + MP3DecInfo *mp3DecInfo = (MP3DecInfo *)hMP3Decoder; + + if (!mp3DecInfo) + return ERR_MP3_NULL_POINTER; + + if (UnpackFrameHeader(mp3DecInfo, buf) == -1 || mp3DecInfo->layer != 3) + return ERR_MP3_INVALID_FRAMEHEADER; + + MP3GetLastFrameInfo(mp3DecInfo, mp3FrameInfo); + + return ERR_MP3_NONE; +} + +/************************************************************************************** + * Function: MP3ClearBadFrame + * + * Description: zero out pcm buffer if error decoding MP3 frame + * + * Inputs: mp3DecInfo struct with correct frame size parameters filled in + * pointer pcm output buffer + * + * Outputs: zeroed out pcm buffer + * + * Return: none + **************************************************************************************/ +static void MP3ClearBadFrame(MP3DecInfo *mp3DecInfo, short *outbuf) +{ + int i; + + if (!mp3DecInfo) + return; + + for (i = 0; i < mp3DecInfo->nGrans * mp3DecInfo->nGranSamps * mp3DecInfo->nChans; i++) + outbuf[i] = 0; +} + +/************************************************************************************** + * Function: MP3Decode + * + * Description: decode one frame of MP3 data + * + * Inputs: valid MP3 decoder instance pointer (HMP3Decoder) + * double pointer to buffer of MP3 data (containing headers + mainData) + * number of valid bytes remaining in inbuf + * pointer to outbuf, big enough to hold one frame of decoded PCM samples + * flag indicating whether MP3 data is normal MPEG format (useSize = 0) + * or reformatted as "self-contained" frames (useSize = 1) + * + * Outputs: PCM data in outbuf, interleaved LRLRLR... if stereo + * number of output samples = nGrans * nGranSamps * nChans + * updated inbuf pointer, updated bytesLeft + * + * Return: error code, defined in mp3dec.h (0 means no error, < 0 means error) + * + * Notes: switching useSize on and off between frames in the same stream + * is not supported (bit reservoir is not maintained if useSize on) + **************************************************************************************/ +int MP3Decode(HMP3Decoder hMP3Decoder, unsigned char **inbuf, int *bytesLeft, short *outbuf, int useSize) +{ + int offset, bitOffset, mainBits, gr, ch, fhBytes, siBytes, freeFrameBytes; + int prevBitOffset, sfBlockBits, huffBlockBits; + unsigned char *mainPtr; + MP3DecInfo *mp3DecInfo = (MP3DecInfo *)hMP3Decoder; + + #ifdef PROFILE + long time; + #endif + + if (!mp3DecInfo) + return ERR_MP3_NULL_POINTER; + + /* unpack frame header */ + fhBytes = UnpackFrameHeader(mp3DecInfo, *inbuf); + if (fhBytes < 0) + return ERR_MP3_INVALID_FRAMEHEADER; /* don't clear outbuf since we don't know size (failed to parse header) */ + *inbuf += fhBytes; + +#ifdef PROFILE + time = systime_get(); +#endif + /* unpack side info */ + siBytes = UnpackSideInfo(mp3DecInfo, *inbuf); + if (siBytes < 0) { + MP3ClearBadFrame(mp3DecInfo, outbuf); + return ERR_MP3_INVALID_SIDEINFO; + } + *inbuf += siBytes; + *bytesLeft -= (fhBytes + siBytes); +#ifdef PROFILE + time = systime_get() - time; + printf("UnpackSideInfo: %i ms\n", time); +#endif + + + /* if free mode, need to calculate bitrate and nSlots manually, based on frame size */ + if (mp3DecInfo->bitrate == 0 || mp3DecInfo->freeBitrateFlag) { + if (!mp3DecInfo->freeBitrateFlag) { + /* first time through, need to scan for next sync word and figure out frame size */ + mp3DecInfo->freeBitrateFlag = 1; + mp3DecInfo->freeBitrateSlots = MP3FindFreeSync(*inbuf, *inbuf - fhBytes - siBytes, *bytesLeft); + if (mp3DecInfo->freeBitrateSlots < 0) { + MP3ClearBadFrame(mp3DecInfo, outbuf); + return ERR_MP3_FREE_BITRATE_SYNC; + } + freeFrameBytes = mp3DecInfo->freeBitrateSlots + fhBytes + siBytes; + mp3DecInfo->bitrate = (freeFrameBytes * mp3DecInfo->samprate * 8) / (mp3DecInfo->nGrans * mp3DecInfo->nGranSamps); + } + mp3DecInfo->nSlots = mp3DecInfo->freeBitrateSlots + CheckPadBit(mp3DecInfo); /* add pad byte, if required */ + } + + /* useSize != 0 means we're getting reformatted (RTP) packets (see RFC 3119) + * - calling function assembles "self-contained" MP3 frames by shifting any main_data + * from the bit reservoir (in previous frames) to AFTER the sync word and side info + * - calling function should set mainDataBegin to 0, and tell us exactly how large this + * frame is (in bytesLeft) + */ + if (useSize) { + mp3DecInfo->nSlots = *bytesLeft; + if (mp3DecInfo->mainDataBegin != 0 || mp3DecInfo->nSlots <= 0) { + /* error - non self-contained frame, or missing frame (size <= 0), could do loss concealment here */ + MP3ClearBadFrame(mp3DecInfo, outbuf); + return ERR_MP3_INVALID_FRAMEHEADER; + } + + /* can operate in-place on reformatted frames */ + mp3DecInfo->mainDataBytes = mp3DecInfo->nSlots; + mainPtr = *inbuf; + *inbuf += mp3DecInfo->nSlots; + *bytesLeft -= (mp3DecInfo->nSlots); + } else { + /* out of data - assume last or truncated frame */ + if (mp3DecInfo->nSlots > *bytesLeft) { + MP3ClearBadFrame(mp3DecInfo, outbuf); + return ERR_MP3_INDATA_UNDERFLOW; + } + +#ifdef PROFILE + time = systime_get(); +#endif + /* fill main data buffer with enough new data for this frame */ + if (mp3DecInfo->mainDataBytes >= mp3DecInfo->mainDataBegin) { + /* adequate "old" main data available (i.e. bit reservoir) */ + memmove(mp3DecInfo->mainBuf, mp3DecInfo->mainBuf + mp3DecInfo->mainDataBytes - mp3DecInfo->mainDataBegin, mp3DecInfo->mainDataBegin); + memcpy(mp3DecInfo->mainBuf + mp3DecInfo->mainDataBegin, *inbuf, mp3DecInfo->nSlots); + + mp3DecInfo->mainDataBytes = mp3DecInfo->mainDataBegin + mp3DecInfo->nSlots; + *inbuf += mp3DecInfo->nSlots; + *bytesLeft -= (mp3DecInfo->nSlots); + mainPtr = mp3DecInfo->mainBuf; + } else { + /* not enough data in bit reservoir from previous frames (perhaps starting in middle of file) */ + memcpy(mp3DecInfo->mainBuf + mp3DecInfo->mainDataBytes, *inbuf, mp3DecInfo->nSlots); + mp3DecInfo->mainDataBytes += mp3DecInfo->nSlots; + *inbuf += mp3DecInfo->nSlots; + *bytesLeft -= (mp3DecInfo->nSlots); + MP3ClearBadFrame(mp3DecInfo, outbuf); + return ERR_MP3_MAINDATA_UNDERFLOW; + } +#ifdef PROFILE + time = systime_get() - time; + printf("data buffer filling: %i ms\n", time); +#endif + + } + bitOffset = 0; + mainBits = mp3DecInfo->mainDataBytes * 8; + + /* decode one complete frame */ + for (gr = 0; gr < mp3DecInfo->nGrans; gr++) { + for (ch = 0; ch < mp3DecInfo->nChans; ch++) { + + #ifdef PROFILE + time = systime_get(); + #endif + /* unpack scale factors and compute size of scale factor block */ + prevBitOffset = bitOffset; + offset = UnpackScaleFactors(mp3DecInfo, mainPtr, &bitOffset, mainBits, gr, ch); + #ifdef PROFILE + time = systime_get() - time; + printf("UnpackScaleFactors: %i ms\n", time); + #endif + + sfBlockBits = 8*offset - prevBitOffset + bitOffset; + huffBlockBits = mp3DecInfo->part23Length[gr][ch] - sfBlockBits; + mainPtr += offset; + mainBits -= sfBlockBits; + + if (offset < 0 || mainBits < huffBlockBits) { + MP3ClearBadFrame(mp3DecInfo, outbuf); + return ERR_MP3_INVALID_SCALEFACT; + } + + #ifdef PROFILE + time = systime_get(); + #endif + /* decode Huffman code words */ + prevBitOffset = bitOffset; + offset = DecodeHuffman(mp3DecInfo, mainPtr, &bitOffset, huffBlockBits, gr, ch); + if (offset < 0) { + MP3ClearBadFrame(mp3DecInfo, outbuf); + return ERR_MP3_INVALID_HUFFCODES; + } + #ifdef PROFILE + time = systime_get() - time; + printf("Huffman: %i ms\n", time); + #endif + + mainPtr += offset; + mainBits -= (8*offset - prevBitOffset + bitOffset); + } + + #ifdef PROFILE + time = systime_get(); + #endif + /* dequantize coefficients, decode stereo, reorder short blocks */ + if (Dequantize(mp3DecInfo, gr) < 0) { + MP3ClearBadFrame(mp3DecInfo, outbuf); + return ERR_MP3_INVALID_DEQUANTIZE; + } + #ifdef PROFILE + time = systime_get() - time; + printf("Dequantize: %i ms\n", time); + #endif + + /* alias reduction, inverse MDCT, overlap-add, frequency inversion */ + for (ch = 0; ch < mp3DecInfo->nChans; ch++) + { + #ifdef PROFILE + time = systime_get(); + #endif + if (IMDCT(mp3DecInfo, gr, ch) < 0) { + MP3ClearBadFrame(mp3DecInfo, outbuf); + return ERR_MP3_INVALID_IMDCT; + } + #ifdef PROFILE + time = systime_get() - time; + printf("IMDCT: %i ms\n", time); + #endif + } + + #ifdef PROFILE + time = systime_get(); + #endif + /* subband transform - if stereo, interleaves pcm LRLRLR */ + if (Subband(mp3DecInfo, outbuf + gr*mp3DecInfo->nGranSamps*mp3DecInfo->nChans) < 0) { + MP3ClearBadFrame(mp3DecInfo, outbuf); + return ERR_MP3_INVALID_SUBBAND; + } + #ifdef PROFILE + time = systime_get() - time; + printf("Subband: %i ms\n", time); + #endif + + } + return ERR_MP3_NONE; +} diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/mp3tabs.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/mp3tabs.c new file mode 100644 index 0000000..e4899c7 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/mp3tabs.c @@ -0,0 +1,181 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * mp3tabs.c - platform-independent tables for MP3 decoder (global, read-only) + **************************************************************************************/ + +#include "mp3common.h" + +/* indexing = [version][samplerate index] + * sample rate of frame (Hz) + */ +const int samplerateTab[3][3] = { + {44100, 48000, 32000}, /* MPEG-1 */ + {22050, 24000, 16000}, /* MPEG-2 */ + {11025, 12000, 8000}, /* MPEG-2.5 */ +}; + +/* indexing = [version][layer][bitrate index] + * bitrate (kbps) of frame + * - bitrate index == 0 is "free" mode (bitrate determined on the fly by + * counting bits between successive sync words) + */ +const short bitrateTab[3][3][15] = { + { + /* MPEG-1 */ + { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448}, /* Layer 1 */ + { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384}, /* Layer 2 */ + { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320}, /* Layer 3 */ + }, + { + /* MPEG-2 */ + { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256}, /* Layer 1 */ + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}, /* Layer 2 */ + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}, /* Layer 3 */ + }, + { + /* MPEG-2.5 */ + { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256}, /* Layer 1 */ + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}, /* Layer 2 */ + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}, /* Layer 3 */ + }, +}; + +/* indexing = [version][layer] + * number of samples in one frame (per channel) + */ +const short samplesPerFrameTab[3][3] = { + {384, 1152, 1152 }, /* MPEG1 */ + {384, 1152, 576 }, /* MPEG2 */ + {384, 1152, 576 }, /* MPEG2.5 */ +}; + +/* layers 1, 2, 3 */ +const short bitsPerSlotTab[3] = {32, 8, 8}; + +/* indexing = [version][mono/stereo] + * number of bytes in side info section of bitstream + */ +const short sideBytesTab[3][2] = { + {17, 32}, /* MPEG-1: mono, stereo */ + { 9, 17}, /* MPEG-2: mono, stereo */ + { 9, 17}, /* MPEG-2.5: mono, stereo */ +}; + +/* indexing = [version][sampleRate][bitRate] + * for layer3, nSlots = floor(samps/frame * bitRate / sampleRate / 8) + * - add one pad slot if necessary + */ +const short slotTab[3][3][15] = { + { + /* MPEG-1 */ + { 0, 104, 130, 156, 182, 208, 261, 313, 365, 417, 522, 626, 731, 835,1044 }, /* 44 kHz */ + { 0, 96, 120, 144, 168, 192, 240, 288, 336, 384, 480, 576, 672, 768, 960 }, /* 48 kHz */ + { 0, 144, 180, 216, 252, 288, 360, 432, 504, 576, 720, 864,1008,1152,1440 }, /* 32 kHz */ + }, + { + /* MPEG-2 */ + { 0, 26, 52, 78, 104, 130, 156, 182, 208, 261, 313, 365, 417, 470, 522 }, /* 22 kHz */ + { 0, 24, 48, 72, 96, 120, 144, 168, 192, 240, 288, 336, 384, 432, 480 }, /* 24 kHz */ + { 0, 36, 72, 108, 144, 180, 216, 252, 288, 360, 432, 504, 576, 648, 720 }, /* 16 kHz */ + }, + { + /* MPEG-2.5 */ + { 0, 52, 104, 156, 208, 261, 313, 365, 417, 522, 626, 731, 835, 940,1044 }, /* 11 kHz */ + { 0, 48, 96, 144, 192, 240, 288, 336, 384, 480, 576, 672, 768, 864, 960 }, /* 12 kHz */ + { 0, 72, 144, 216, 288, 360, 432, 504, 576, 720, 864,1008,1152,1296,1440 }, /* 8 kHz */ + }, +}; + +/* indexing = [version][sampleRate][long (.l) or short (.s) block] + * sfBandTable[v][s].l[cb] = index of first bin in critical band cb (long blocks) + * sfBandTable[v][s].s[cb] = index of first bin in critical band cb (short blocks) + */ +const SFBandTable sfBandTable[3][3] = { + { + /* MPEG-1 (44, 48, 32 kHz) */ + { + { 0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90,110,134,162,196,238,288,342,418,576 }, + { 0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84,106,136,192 } + }, + { + { 0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88,106,128,156,190,230,276,330,384,576 }, + { 0, 4, 8, 12, 16, 22, 28, 38, 50, 64, 80,100,126,192 } + }, + { + { 0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82,102,126,156,194,240,296,364,448,550,576 }, + { 0, 4, 8, 12, 16, 22, 30, 42, 58, 78,104,138,180,192 } + } + }, + + { + /* MPEG-2 (22, 24, 16 kHz) */ + { + { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96,116,140,168,200,238,284,336,396,464,522,576 }, + { 0, 4, 8, 12, 18, 24, 32, 42, 56, 74,100,132,174,192 } + }, + { + { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96,114,136,162,194,232,278,332,394,464,540,576 }, + { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80,104,136,180,192 } + }, + { + { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96,116,140,168,200,238,284,336,396,464,522,576 }, + { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80,104,134,174,192 } + }, + }, + + { + /* MPEG-2.5 (11, 12, 8 kHz) */ + { + { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96,116,140,168,200,238,284,336,396,464,522,576 }, + { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80,104,134,174,192 } + }, + { + { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96,116,140,168,200,238,284,336,396,464,522,576 }, + { 0, 4, 8, 12, 18, 26, 36, 48, 62, 80,104,134,174,192 } + }, + { + { 0, 12, 24, 36, 48, 60, 72, 88,108,132,160,192,232,280,336,400,476,566,568,570,572,574,576 }, + { 0, 8, 16, 24, 36, 52, 72, 96,124,160,162,164,166,192 } + }, + }, +}; + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/LICENSE.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/LICENSE.txt new file mode 100644 index 0000000..12e5372 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/LICENSE.txt @@ -0,0 +1,30 @@ + Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. + + The contents of this directory, and (except where otherwise + indicated) the directories included within this directory, are + subject to the current version of the RealNetworks Public Source + License (the "RPSL") available at RPSL.txt in this directory, unless + you have licensed the directory under the current version of the + RealNetworks Community Source License (the "RCSL") available at + RCSL.txt in this directory, in which case the RCSL will apply. You + may also obtain the license terms directly from RealNetworks. You + may not use the files in this directory except in compliance with the + RPSL or, if you have a valid RCSL with RealNetworks applicable to + this directory, the RCSL. Please see the applicable RPSL or RCSL for + the rights, obligations and limitations governing use of the contents + of the directory. + + This directory is part of the Helix DNA Technology. RealNetworks is + the developer of the Original Code and owns the copyrights in the + portions it created. + + This directory, and the directories included with this directory, are + distributed and made available on an 'AS IS' basis, WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY + DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + QUIET ENJOYMENT OR NON-INFRINGEMENT. + + Technology Compatibility Kit Test Suite(s) Location: + http://www.helixcommunity.org/content/tck + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/RCSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/RCSL.txt new file mode 100644 index 0000000..a809759 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/RCSL.txt @@ -0,0 +1,948 @@ +The RCSL is made up of a base agreement and a few Attachments. + +For Research and Development use, you agree to the terms of the +RCSL R&D License (base RCSL and Attachments A, B, and C) + +For Commercial Use (either distribution or internal commercial +deployment) of the Helix DNA with or without support for RealNetworks' +RealAudio and RealVideo Add-on Technology, you agree to the +terms of the same RCSL R&D license +and execute one or more additional Commercial Use License attachments +. + +------------------------------------------------------------------------ + + + REALNETWORKS COMMUNITY SOURCE LICENSE + +Version 1.2 (Rev. Date: January 22, 2003). + + + RECITALS + +Original Contributor has developed Specifications, Source Code +implementations and Executables of certain Technology; and + +Original Contributor desires to license the Technology to a large +community to facilitate research, innovation and product development +while maintaining compatibility of such products with the Technology as +delivered by Original Contributor; and + +Original Contributor desires to license certain Trademarks for the +purpose of branding products that are compatible with the relevant +Technology delivered by Original Contributor; and + +You desire to license the Technology and possibly certain Trademarks +from Original Contributor on the terms and conditions specified in this +License. + +In consideration for the mutual covenants contained herein, You and +Original Contributor agree as follows: + + + AGREEMENT + +*1. Introduction.* + +The RealNetworks Community Source License ("RCSL") and effective +attachments ("License") may include five distinct licenses: + +i) Research Use license -- License plus Attachments A, B and C only. + +ii) Commercial Use and Trademark License, which may be for Internal +Deployment Use or external distribution, or both -- License plus +Attachments A, B, C, and D. + +iii) Technology Compatibility Kit (TCK) license -- Attachment C. + +iv) Add-On Technology License (Executable) Commercial Use License +-Attachment F. + +v) Add-On Technology Source Code Porting and Optimization +License-Attachment G. + +The Research Use license is effective when You click and accept this +License. The TCK is effective when You click and accept this License, +unless otherwise specified in the TCK attachments. The Commercial Use +and Trademark, Add-On Technology License, and the Add-On Technology +Source Code Porting and Optimization licenses must each be signed by You +and Original Contributor to become effective. Once effective, these +licenses and the associated requirements and responsibilities are +cumulative. Capitalized terms used in this License are defined in the +Glossary. + +*2. License Grants.* + +2.1 Original Contributor Grant. + +Subject to Your compliance with Sections 3, 8.10 and Attachment A of +this License, Original Contributor grants to You a worldwide, +royalty-free, non-exclusive license, to the extent of Original +Contributor's Intellectual Property Rights covering the Original Code, +Upgraded Code and Specifications, to do the following: + +(a) Research Use License: + +(i) use, reproduce and modify the Original Code, Upgraded Code and +Specifications to create Modifications and Reformatted Specifications +for Research Use by You; + +(ii) publish and display Original Code, Upgraded Code and Specifications +with, or as part of Modifications, as permitted under Section 3.1(b) below; + +(iii) reproduce and distribute copies of Original Code and Upgraded Code +to Licensees and students for Research Use by You; + +(iv) compile, reproduce and distribute Original Code and Upgraded Code +in Executable form, and Reformatted Specifications to anyone for +Research Use by You. + +(b) Other than the licenses expressly granted in this License, Original +Contributor retains all right, title, and interest in Original Code and +Upgraded Code and Specifications. + +2.2 Your Grants. + +(a) To Other Licensees. You hereby grant to each Licensee a license to +Your Error Corrections and Shared Modifications, of the same scope and +extent as Original Contributor's licenses under Section 2.1 a) above +relative to Research Use and Attachment D relative to Commercial Use. + +(b) To Original Contributor. You hereby grant to Original Contributor a +worldwide, royalty-free, non-exclusive, perpetual and irrevocable +license, to the extent of Your Intellectual Property Rights covering +Your Error Corrections, Shared Modifications and Reformatted +Specifications, to use, reproduce, modify, display and distribute Your +Error Corrections, Shared Modifications and Reformatted Specifications, +in any form, including the right to sublicense such rights through +multiple tiers of distribution. + +(c) Other than the licenses expressly granted in Sections 2.2(a) and (b) +above, and the restrictions set forth in Section 3.1(d)(iv) below, You +retain all right, title, and interest in Your Error Corrections, Shared +Modifications and Reformatted Specifications. + +2.3 Contributor Modifications. + +You may use, reproduce, modify, display and distribute Contributor Error +Corrections, Shared Modifications and Reformatted Specifications, +obtained by You under this License, to the same scope and extent as with +Original Code, Upgraded Code and Specifications. + +2.4 Subcontracting. + +You may deliver the Source Code of Covered Code to other Licensees +having at least a Research Use license, for the sole purpose of +furnishing development services to You in connection with Your rights +granted in this License. All such Licensees must execute appropriate +documents with respect to such work consistent with the terms of this +License, and acknowledging their work-made-for-hire status or assigning +exclusive right to the work product and associated Intellectual Property +Rights to You. + +*3. Requirements and Responsibilities*. + +3.1 Research Use License. + +As a condition of exercising the rights granted under Section 2.1(a) +above, You agree to comply with the following: + +(a) Your Contribution to the Community. All Error Corrections and Shared +Modifications which You create or contribute to are automatically +subject to the licenses granted under Section 2.2 above. You are +encouraged to license all of Your other Modifications under Section 2.2 +as Shared Modifications, but are not required to do so. You agree to +notify Original Contributor of any errors in the Specification. + +(b) Source Code Availability. You agree to provide all Your Error +Corrections to Original Contributor as soon as reasonably practicable +and, in any event, prior to Internal Deployment Use or Commercial Use, +if applicable. Original Contributor may, at its discretion, post Source +Code for Your Error Corrections and Shared Modifications on the +Community Webserver. You may also post Error Corrections and Shared +Modifications on a web-server of Your choice; provided, that You must +take reasonable precautions to ensure that only Licensees have access to +such Error Corrections and Shared Modifications. Such precautions shall +include, without limitation, a password protection scheme limited to +Licensees and a click-on, download certification of Licensee status +required of those attempting to download from the server. An example of +an acceptable certification is attached as Attachment A-2. + +(c) Notices. All Error Corrections and Shared Modifications You create +or contribute to must include a file documenting the additions and +changes You made and the date of such additions and changes. You must +also include the notice set forth in Attachment A-1 in the file header. +If it is not possible to put the notice in a particular Source Code file +due to its structure, then You must include the notice in a location +(such as a relevant directory file), where a recipient would be most +likely to look for such a notice. + +(d) Redistribution. + +(i) Source. Covered Code may be distributed in Source Code form only to +another Licensee (except for students as provided below). You may not +offer or impose any terms on any Covered Code that alter the rights, +requirements, or responsibilities of such Licensee. You may distribute +Covered Code to students for use in connection with their course work +and research projects undertaken at accredited educational institutions. +Such students need not be Licensees, but must be given a copy of the +notice set forth in Attachment A-3 and such notice must also be included +in a file header or prominent location in the Source Code made available +to such students. + +(ii) Executable. You may distribute Executable version(s) of Covered +Code to Licensees and other third parties only for the purpose of +evaluation and comment in connection with Research Use by You and under +a license of Your choice, but which limits use of such Executable +version(s) of Covered Code only to that purpose. + +(iii) Modified Class, Interface and Package Naming. In connection with +Research Use by You only, You may use Original Contributor's class, +Interface and package names only to accurately reference or invoke the +Source Code files You modify. Original Contributor grants to You a +limited license to the extent necessary for such purposes. + +(iv) You expressly agree that any distribution, in whole or in part, of +Modifications developed by You shall only be done pursuant to the terms +and conditions of this License. + +(e) Extensions. + +(i) Covered Code. You may not include any Source Code of Community Code +in any Extensions. You may include the compiled Header Files of +Community Code in an Extension provided that Your use of the Covered +Code, including Heading Files, complies with the Commercial Use License, +the TCK and all other terms of this License. + +(ii) Publication. No later than the date on which You first distribute +such Extension for Commercial Use, You must publish to the industry, on +a non-confidential basis and free of all copyright restrictions with +respect to reproduction and use, an accurate and current specification +for any Extension. In addition, You must make available an appropriate +test suite, pursuant to the same rights as the specification, +sufficiently detailed to allow any third party reasonably skilled in the +technology to produce implementations of the Extension compatible with +the specification. Such test suites must be made available as soon as +reasonably practicable but, in no event, later than ninety (90) days +after Your first Commercial Use of the Extension. You must use +reasonable efforts to promptly clarify and correct the specification and +the test suite upon written request by Original Contributor. + +(iii) Open. You agree to refrain from enforcing any Intellectual +Property Rights You may have covering any interface(s) of Your +Extension, which would prevent the implementation of such interface(s) +by Original Contributor or any Licensee. This obligation does not +prevent You from enforcing any Intellectual Property Right You have that +would otherwise be infringed by an implementation of Your Extension. + +(iv) Interface Modifications and Naming. You may not modify or add to +the GUID space * * "xxxxxxxx-0901-11d1-8B06-00A024406D59" or any other +GUID space designated by Original Contributor. You may not modify any +Interface prefix provided with the Covered Code or any other prefix +designated by Original Contributor.* * + +* * + +(f) You agree that any Specifications provided to You by Original +Contributor are confidential and proprietary information of Original +Contributor. You must maintain the confidentiality of the Specifications +and may not disclose them to any third party without Original +Contributor's prior written consent. You may only use the Specifications +under the terms of this License and only for the purpose of implementing +the terms of this License with respect to Covered Code. You agree not +use, copy or distribute any such Specifications except as provided in +writing by Original Contributor. + +3.2 Commercial Use License. + +You may not make Commercial Use of any Covered Code unless You and +Original Contributor have executed a copy of the Commercial Use and +Trademark License attached as Attachment D. + +*4. Versions of the License.* + +4.1 License Versions. + +Original Contributor may publish revised versions of the License from +time to time. Each version will be given a distinguishing version number. + +4.2 Effect. + +Once a particular version of Covered Code has been provided under a +version of the License, You may always continue to use such Covered Code +under the terms of that version of the License. You may also choose to +use such Covered Code under the terms of any subsequent version of the +License. No one other than Original Contributor has the right to +promulgate License versions. + +4.3 Multiple-Licensed Code. + +Original Contributor may designate portions of the Covered Code as +"Multiple-Licensed." "Multiple-Licensed" means that the Original +Contributor permits You to utilize those designated portions of the +Covered Code under Your choice of this License or the alternative +license(s), if any, specified by the Original Contributor in an +Attachment to this License. + +*5. Disclaimer of Warranty.* + +5.1 COVERED CODE PROVIDED AS IS. + +COVERED CODE IS PROVIDED UNDER THIS LICENSE "AS IS," WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, +WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT +FOR A PARTICULAR PURPOSE OR NON-INFRINGING. YOU AGREE TO BEAR THE ENTIRE +RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF COVERED CODE UNDER +THIS LICENSE. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART +OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER +EXCEPT SUBJECT TO THIS DISCLAIMER. + +5.2 Not Designed for High Risk Activities. + +You acknowledge that Original Code, Upgraded Code and Specifications are +not designed or intended for use in high risk activities including, but +not limited to: (i) on-line control of aircraft, air traffic, aircraft +navigation or aircraft communications; or (ii) in the design, +construction, operation or maintenance of any nuclear facility. Original +Contributor disclaims any express or implied warranty of fitness for +such uses. + +*6. Termination.* + +6.1 By You. + +You may terminate this Research Use license at anytime by providing +written notice to Original Contributor. + +6.2 By Original Contributor. + +This License and the rights granted hereunder will terminate: + +(i) automatically if You fail to comply with the terms of this License +and fail to cure such breach within 30 days of receipt of written notice +of the breach; + +(ii) immediately in the event of circumstances specified in Sections 7.1 +and 8.4; or + +(iii) at Original Contributor's discretion upon any action initiated by +You (including by cross-claim or counter claim) alleging that use or +distribution by Original Contributor or any Licensee, of Original Code, +Upgraded Code, Error Corrections, Shared Modifications or Specifications +infringe a patent owned or controlled by You. + +6.3 Effective of Termination. + +Upon termination, You agree to discontinue use of and destroy all copies +of Covered Code in Your possession. All sublicenses to the Covered Code +which You have properly granted shall survive any termination of this +License. Provisions that, by their nature, should remain in effect +beyond the termination of this License shall survive including, without +limitation, Sections 2.2, 3, 5, 7 and 8. + +6.4 No Compensation. + +Each party waives and releases the other from any claim to compensation +or indemnity for permitted or lawful termination of the business +relationship established by this License. + +*7. Liability.* + +7.1 Infringement. Should any of the Original Code, Upgraded Code, TCK or +Specifications ("Materials") become the subject of a claim of +infringement, Original Contributor may, at its sole option, (i) attempt +to procure the rights necessary for You to continue using the Materials, +(ii) modify the Materials so that they are no longer infringing, or +(iii) terminate Your right to use the Materials, immediately upon +written notice, and refund to You the amount, if any, having then +actually been paid by You to Original Contributor for the Original Code, +Upgraded Code and TCK, depreciated on a straight line, five year basis. + +7.2 LIMITATION OF LIABILITY. TO THE FULL EXTENT ALLOWED BY APPLICABLE +LAW, ORIGINAL CONTRIBUTOR'S LIABILITY TO YOU FOR CLAIMS RELATING TO THIS +LICENSE, WHETHER FOR BREACH OR IN TORT, SHALL BE LIMITED TO ONE HUNDRED +PERCENT (100%) OF THE AMOUNT HAVING THEN ACTUALLY BEEN PAID BY YOU TO +ORIGINAL CONTRIBUTOR FOR ALL COPIES LICENSED HEREUNDER OF THE PARTICULAR +ITEMS GIVING RISE TO SUCH CLAIM, IF ANY, DURING THE TWELVE MONTHS +PRECEDING THE CLAIMED BREACH. IN NO EVENT WILL YOU (RELATIVE TO YOUR +SHARED MODIFICATIONS OR ERROR CORRECTIONS) OR ORIGINAL CONTRIBUTOR BE +LIABLE FOR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES IN CONNECTION WITH OR RISING OUT OF THIS LICENSE (INCLUDING, +WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR OTHER ECONOMIC +ADVANTAGE), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY, WHETHER IN +AN ACTION FOR CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE) +OR OTHERWISE, WHETHER OR NOT YOU OR ORIGINAL CONTRIBUTOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE AND NOTWITHSTANDING THE +FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. + +*8. Miscellaneous.* + +8.1 Trademark. + +You shall not use any Trademark unless You and Original Contributor +execute a copy of the Commercial Use and Trademark License Agreement +attached hereto as Attachment D. Except as expressly provided in the +License, You are granted no right, title or license to, or interest in, +any Trademarks. Whether or not You and Original Contributor enter into +the Trademark License, You agree not to (i) challenge Original +Contributor's ownership or use of Trademarks; (ii) attempt to register +any Trademarks, or any mark or logo substantially similar thereto; or +(iii) incorporate any Trademarks into Your own trademarks, product +names, service marks, company names, or domain names. + +8.2 Integration. + +This License represents the complete agreement concerning the subject +matter hereof. + +8.3 Assignment. + +Original Contributor may assign this License, and its rights and +obligations hereunder, in its sole discretion. You may assign the +Research Use portions of this License and the TCK license to a third +party upon prior written notice to Original Contributor (which may be +provided electronically via the Community Web-Server). You may not +assign the Commercial Use and Trademark license, the Add-On Technology +License, or the Add-On Technology Source Code Porting License, including +by way of merger (regardless of whether You are the surviving entity) or +acquisition, without Original Contributor's prior written consent. + +8.4 Severability. + +If any provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to make it +enforceable. Notwithstanding the foregoing, if You are prohibited by law +from fully and specifically complying with Sections 2.2 or 3, this +License will immediately terminate and You must immediately discontinue +any use of Covered Code. + +8.5 Governing Law. + +This License shall be governed by the laws of the United States and the +State of Washington, as applied to contracts entered into and to be +performed in Washington between Washington residents. The application of +the United Nations Convention on Contracts for the International Sale of +Goods is expressly excluded. You agree that the state and federal courts +located in Seattle, Washington have exclusive jurisdiction over any +claim relating to the License, including contract and tort claims. + +8.6 Dispute Resolution. + +a) Arbitration. Any dispute arising out of or relating to this License +shall be finally settled by arbitration as set out herein, except that +either party may bring any action, in a court of competent jurisdiction +(which jurisdiction shall be exclusive), with respect to any dispute +relating to such party's Intellectual Property Rights or with respect to +Your compliance with the TCK license. Arbitration shall be administered: +(i) by the American Arbitration Association (AAA), (ii) in accordance +with the rules of the United Nations Commission on International Trade +Law (UNCITRAL) (the "Rules") in effect at the time of arbitration as +modified herein; and (iii) the arbitrator will apply the substantive +laws of Washington and the United States. Judgment upon the award +rendered by the arbitrator may be entered in any court having +jurisdiction to enforce such award. + +b) Arbitration language, venue and damages. All arbitration proceedings +shall be conducted in English by a single arbitrator selected in +accordance with the Rules, who must be fluent in English and be either a +retired judge or practicing attorney having at least ten (10) years +litigation experience and be reasonably familiar with the technology +matters relative to the dispute. Unless otherwise agreed, arbitration +venue shall be in Seattle, Washington. The arbitrator may award monetary +damages only and nothing shall preclude either party from seeking +provisional or emergency relief from a court of competent jurisdiction. +The arbitrator shall have no authority to award damages in excess of +those permitted in this License and any such award in excess is void. +All awards will be payable in U.S. dollars and may include, for the +prevailing party (i) pre-judgment award interest, (ii) reasonable +attorneys' fees incurred in connection with the arbitration, and (iii) +reasonable costs and expenses incurred in enforcing the award. The +arbitrator will order each party to produce identified documents and +respond to no more than twenty-five single question interrogatories. + +8.7 Construction. + +Any law or regulation, which provides that the language of a contract +shall be construed against the drafter, shall not apply to this License. + +8.8 U.S. Government End Users. + +The Covered Code is a "commercial item," as that term is defined in 48 +C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" +and "commercial computer software documentation," as such terms are used +in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and +48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government +End Users acquire Covered Code with only those rights set forth herein. +You agree to pass this notice to our licensees. + +8.9 Marketing Activities. + +Licensee hereby grants Original Contributor a non-exclusive, +non-transferable, limited license to use the Licensee's company name and +logo ("Licensee Marks") in any presentations, press releases, or +marketing materials solely for the purpose of identifying Licensee as a +member of the Helix Community. Licensee shall provide samples of +Licensee Marks to Original Contributor upon request by Original +Contributor. Original Contributor acknowledges that the Licensee Marks +are the trademarks of Licensee. Original Contributor shall not use the +Licensee Marks in a way that may imply that Original Contributor is an +agency or branch of Licensee. Original Contributor understands and +agrees that the use of any Licensee Marks in connection with this +Agreement shall not create any right, title or interest, in, or to the +Licensee Marks or any Licensee trademarks and that all such use and +goodwill associated with any such trademarks will inure to the benefit +of Licensee. Further the Original Contributor will stop usage of the +Licensee Marks upon Licensee's request. + +8.10 Press Announcements. + +You may make press announcements or other public statements regarding +this License without the prior written consent of the Original +Contributor, if Your statement is limited to announcing the licensing of +the Covered Code or the availability of Your Product and its +compatibility with the Covered Code. All other public announcements +regarding this license require the prior written consent of the Original +Contributor. Consent requests are welcome at press@helixcommunity.org. + +8.11 International Use. + +a) Export/Import laws. Covered Code is subject to U.S. export control +laws and may be subject to export or import regulations in other +countries. Each party agrees to comply strictly with all such laws and +regulations and acknowledges their responsibility to obtain such +licenses to export, re-export, or import as may be required. You agree +to pass these obligations to Your licensees. + +b) Intellectual Property Protection. Due to limited intellectual +property protection and enforcement in certain countries, You agree not +to redistribute the Original Code, Upgraded Code, TCK and Specifications +to any country on the list of restricted countries on the Community Web +Server. + +8.12 Language. + +This License is in the English language only, which language shall be +controlling in all respects, and all versions of this License in any +other language shall be for accommodation only and shall not be binding +on the parties to this License. All communications and notices made or +given pursuant to this License, and all documentation and support to be +provided, unless otherwise noted, shall be in the English language. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH REALNETWORKS, INC. IF YOU ARE AGREEING +TO THIS LICENSE ON BEHALF OF A COMPANY, YOU REPRESENT THAT YOU ARE +AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. WHETHER YOU ARE ACTING +ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, YOU MUST BE OF MAJORITY +AGE AND BE OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. IF YOU DO NOT +MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY OF THE TERMS AND +CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON TO EXIT. + + + GLOSSARY + +1. *"Added Value"* means code which: + +(i) has a principal purpose which is substantially different from that +of the stand-alone Technology; + +(ii) represents a significant functional and value enhancement to the +Technology; + +(iii) operates in conjunction with the Technology; and + +(iv) is not marketed as a technology which replaces or substitutes for +the Technology + +2. "*Applicable Patent Rights*" mean: (a) in the case where Original +Contributor is the grantor of rights, claims of patents that (i) are now +or hereafter acquired, owned by or assigned to Original Contributor and +(ii) are necessarily infringed by using or making the Original Code or +Upgraded Code, including Modifications provided by Original Contributor, +alone and not in combination with other software or hardware; and (b) in +the case where Licensee is the grantor of rights, claims of patents that +(i) are now or hereafter acquired, owned by or assigned to Licensee and +(ii) are infringed (directly or indirectly) by using or making +Licensee's Modifications or Error Corrections, taken alone or in +combination with Covered Code. + +3. "*Application Programming Interfaces (APIs)"* means the interfaces, +associated header files, service provider interfaces, and protocols that +enable a device, application, Operating System, or other program to +obtain services from or make requests of (or provide services in +response to requests from) other programs, and to use, benefit from, or +rely on the resources, facilities, and capabilities of the relevant +programs using the APIs. APIs includes the technical documentation +describing the APIs, the Source Code constituting the API, and any +Header Files used with the APIs. + +4. "*Commercial Use*" means any use (internal or external), copying, +sublicensing or distribution (internal or external), directly or +indirectly of Covered Code by You other than Your Research Use of +Covered Code within Your business or organization or in conjunction with +other Licensees with equivalent Research Use rights. Commercial Use +includes any use of the Covered Code for direct or indirect commercial +or strategic gain, advantage or other business purpose. Any Commercial +Use requires execution of Attachment D by You and Original Contributor. + +5. "*Community Code*" means the Original Code, Upgraded Code, Error +Corrections, Shared Modifications, or any combination thereof. + +6. "*Community Webserver(s)"* means the webservers designated by +Original Contributor for access to the Original Code, Upgraded Code, TCK +and Specifications and for posting Error Corrections and Shared +Modifications. + +7. "*Compliant Covered Code*" means Covered Code that complies with the +requirements of the TCK. + +8. "*Contributor*" means each Licensee that creates or contributes to +the creation of any Error Correction or Shared Modification. + +9. "*Covered Code*" means the Original Code, Upgraded Code, +Modifications, or any combination thereof. + +10. "*Error Correction*" means any change made to Community Code which +conforms to the Specification and corrects the adverse effect of a +failure of Community Code to perform any function set forth in or +required by the Specifications. + +11. "*Executable*" means Covered Code that has been converted from +Source Code to the preferred form for execution by a computer or digital +processor (e.g. binary form). + +12. "*Extension(s)"* means any additional Interfaces developed by or for +You which: (i) are designed for use with the Technology; (ii) constitute +an API for a library of computing functions or services; and (iii) are +disclosed or otherwise made available to third party software developers +for the purpose of developing software which invokes such additional +Interfaces. The foregoing shall not apply to software developed by Your +subcontractors to be exclusively used by You. + +13. "*Header File(s)"* means that portion of the Source Code that +provides the names and types of member functions, data members, class +definitions, and interface definitions necessary to implement the APIs +for the Covered Code. Header Files include, files specifically +designated by Original Contributor as Header Files. Header Files do not +include the code necessary to implement the functionality underlying the +Interface. + +14. *"Helix DNA Server Technology"* means the program(s) that implement +the Helix Universal Server streaming engine for the Technology as +defined in the Specification. + +15. *"Helix DNA Client Technology"* means the Covered Code that +implements the RealOne Player engine as defined in the Specification. + +16. *"Helix DNA Producer Technology"* means the Covered Code that +implements the Helix Producer engine as defined in the Specification. + +17. *"Helix DNA Technology"* means the Helix DNA Server Technology, the +Helix DNA Client Technology, the Helix DNA Producer Technology and other +Helix technologies designated by Original Contributor. + +18. "*Intellectual Property Rights*" means worldwide statutory and +common law rights associated solely with (i) Applicable Patent Rights; +(ii) works of authorship including copyrights, copyright applications, +copyright registrations and "moral rights"; (iii) the protection of +trade and industrial secrets and confidential information; and (iv) +divisions, continuations, renewals, and re-issuances of the foregoing +now existing or acquired in the future. + +19. *"Interface*" means interfaces, functions, properties, class +definitions, APIs, Header Files, GUIDs, V-Tables, and/or protocols +allowing one piece of software, firmware or hardware to communicate or +interoperate with another piece of software, firmware or hardware. + +20. "*Internal Deployment Use*" means use of Compliant Covered Code +(excluding Research Use) within Your business or organization only by +Your employees and/or agents on behalf of Your business or organization, +but not to provide services, including content distribution, to third +parties, subject to execution of Attachment D by You and Original +Contributor, if required. + +21. "*Licensee*" means any party that has entered into and has in effect +a version of this License with Original Contributor. + +22. "*MIME type*" means a description of what type of media or other +content is in a file, including by way of example but not limited to +'audio/x-pn-realaudio-plugin.' + +23. "*Modification(s)"* means (i) any addition to, deletion from and/or +change to the substance and/or structure of the Covered Code, including +Interfaces; (ii) the combination of any Covered Code and any previous +Modifications; (iii) any new file or other representation of computer +program statements that contains any portion of Covered Code; and/or +(iv) any new Source Code implementing any portion of the Specifications. + +24. "*MP3 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Picture Experts Group known as MPEG-1 Audio Layer-3 or MP3, +including but not limited to all past and future versions, profiles, +extensions, parts and amendments relating to the MP3 specification. + +25. "*MPEG-4 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Pictures Experts Group known as MPEG-4, including but not +limited to all past and future versions, profiles, extensions, parts and +amendments relating to the MPEG-4 specification. + +26. "*Original Code*" means the initial Source Code for the Technology +as described on the Community Web Server. + +27. "*Original Contributor*" means RealNetworks, Inc., its affiliates +and its successors and assigns. + +28. "*Original Contributor MIME Type*" means the MIME registry, browser +preferences, or local file/protocol associations invoking any Helix DNA +Client-based application, including the RealOne Player, for playback of +RealAudio, RealVideo, other RealMedia MIME types or datatypes (e.g., +.ram, .rnx, .rpm, .ra, .rm, .rp, .rt, .rf, .prx, .mpe, .rmp, .rmj, .rav, +.rjs, .rmx, .rjt, .rms), and any other Original Contributor-specific or +proprietary MIME types that Original Contributor may introduce in the +future. + +29. "*Personal Use*" means use of Covered Code by an individual solely +for his or her personal, private and non-commercial purposes. An +individual's use of Covered Code in his or her capacity as an officer, +employee, member, independent contractor or agent of a corporation, +business or organization (commercial or non-commercial) does not qualify +as Personal Use. + +30. "*RealMedia File Format*" means the file format designed and +developed by RealNetworks for storing multimedia data and used to store +RealAudio and RealVideo encoded streams. Valid RealMedia File Format +extensions include: .rm, .rmj, .rmc, .rmvb, .rms. + +31. "*RCSL Webpage*" means the RealNetworks Community Source License +webpage located at https://www.helixcommunity.org/content/rcsl or such +other URL that Original Contributor may designate from time to time. + +32. "*Reformatted Specifications*" means any revision to the +Specifications which translates or reformats the Specifications (as for +example in connection with Your documentation) but which does not alter, +subset or superset * *the functional or operational aspects of the +Specifications. + +33. "*Research Use*" means use and distribution of Covered Code only for +Your Personal Use, research or development use and expressly excludes +Internal Deployment Use and Commercial Use. Research Use also includes +use of Covered Code to teach individuals how to use Covered Code. + +34. "*Shared Modifications*" means Modifications that You distribute or +use for a Commercial Use, in addition to any Modifications provided by +You, at Your option, pursuant to Section 2.2, or received by You from a +Contributor pursuant to Section 2.3. + +35. "*Source Code*" means the preferred form of the Covered Code for +making modifications to it, including all modules it contains, plus any +associated interface definition files, scripts used to control +compilation and installation of an Executable, or source code +differential comparisons against either the Original Code or another +well known, available Covered Code of the Contributor's choice. The +Source Code can be in a compressed or archival form, provided the +appropriate decompression or de-archiving software is widely available +for no charge. + +36. "*Specifications*" means the specifications for the Technology and +other documentation, as designated on the Community Web Server, as may +be revised by Original Contributor from time to time. + +37. "*Trademarks*" means Original Contributor's trademarks and logos, +including, but not limited to, RealNetworks, RealAudio, RealVideo, +RealOne, RealSystem, SureStream, Helix, Helix DNA and other trademarks +whether now used or adopted in the future. + +38. "*Technology*" means the technology described in Attachment B, and +Upgrades. + +39. "*Technology Compatibility Kit"* or *"TCK*" means the test programs, +procedures, acceptance criteria and/or other requirements, designated by +Original Contributor for use in verifying compliance of Covered Code +with the Specifications, in conjunction with the Original Code and +Upgraded Code. Original Contributor may, in its sole discretion and from +time to time, revise a TCK to correct errors and/or omissions and in +connection with Upgrades. + +40. "*Upgrade(s)"* means new versions of Technology designated +exclusively by Original Contributor as an "Upgrade" and released by +Original Contributor from time to time under the terms of the License. + +41. "*Upgraded Code*" means the Source Code and/or Executables for +Upgrades, possibly including Modifications made by Contributors. + +42. *"User's Guide"* means the users guide for the TCK which Original +Contributor makes available to You to provide direction in how to run +the TCK and properly interpret the results, as may be revised by +Original Contributor from time to time. + +43. "*You(r)*" means an individual, or a legal entity acting by and +through an individual or individuals, exercising rights either under +this License or under a future version of this License issued pursuant +to Section 4.1. For legal entities, "You(r)" includes any entity that by +majority voting interest controls, is controlled by, or is under common +control with You. + +44. "*Your Products*" means any (i) hardware products You distribute +integrating the Covered Code; (ii) any software products You distribute +with the Covered Code that utilize the APIs of the Covered Code; or +(iii) any services You provide using the Covered Code. + + + ATTACHMENT A + +REQUIRED NOTICES + + + ATTACHMENT A-1 + +REQUIRED IN ALL CASES + +Notice to be included in header file of all Error Corrections and Shared +Modifications: + +Portions Copyright 1994-2003 RealNetworks, Inc. All rights reserved. + +The contents of this file, and the files included with this file, are +subject to the current version of RealNetworks Community Source License +Version 1.1 (the "License"). You may not use this file except in +compliance with the License executed by both You and RealNetworks. You +may obtain a copy of the License at * +https://www.helixcommunity.org/content/rcsl.* You may also obtain a copy +of the License by contacting RealNetworks directly. Please see the +License for the rights, obligations and limitations governing use of the +contents of the file. + +This file is part of the Helix DNA technology. RealNetworks, Inc., is +the developer of the Original code and owns the copyrights in the +portions it created. + +This file, and the files included with this file, are distributed on an +'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, +AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): + +_______________________________________________ + +Technology Compatibility Kit Test Suite(s) Location: + +________________________________ + + + ATTACHMENT A-2 + +SAMPLE LICENSEE CERTIFICATION + +"By clicking the `Agree' button below, You certify that You are a +Licensee in good standing under the RealNetworks Community Source +License, ("License") and that Your access, use and distribution of code +and information You may obtain at this site is subject to the License. +If You are not a Licensee under the RealNetworks Community Source +License You agree not to download, copy or use the Helix DNA technology. + + + ATTACHMENT A-3 + +REQUIRED STUDENT NOTIFICATION + +"This software and related documentation has been obtained by Your +educational institution subject to the RealNetworks Community Source +License. You have been provided access to the software and related +documentation for use only in connection with your course work and +research activities as a matriculated student of Your educational +institution. Any other use is expressly prohibited. + +THIS SOFTWARE AND RELATED DOCUMENTATION CONTAINS PROPRIETARY MATERIAL OF +REALNETWORKS, INC, WHICH ARE PROTECTED BY VARIOUS INTELLECTUAL PROPERTY +RIGHTS. + +You may not use this file except in compliance with the License. You may +obtain a copy of the License on the web at +https://www.helixcommunity.org/content/rcsl. + +* +* + + + ATTACHMENT B + +Description of Technology + +Helix DNA, which consists of Helix DNA Client, Helix DNA Server and +Helix DNA Producer. + +Description of "Technology" + +Helix DNA Technology v1.0 as described on the Community Web Server. + + + ATTACHMENT C + +TECHNOLOGY COMPATIBILITY KIT LICENSE + +The following license is effective for the *Helix DNA* Technology +Compatibility Kit - as described on the Community Web Server. The +Technology Compatibility Kit(s) for the Technology specified in +Attachment B may be accessed at the Community Web Server. + +1. TCK License. + +1.1 Grants to use TCK + +Subject to the terms and restrictions set forth below and the +RealNetworks Community Source License, and the Research Use license, +Original Contributor grants to You a worldwide, non-exclusive, +non-transferable license, to the extent of Original Contributor's +Intellectual Property Rights in the TCK (without the right to +sublicense), to use the TCK to develop and test Covered Code. + +1.2 TCK Use Restrictions. + +You are not authorized to create derivative works of the TCK or use the +TCK to test any implementation of the Specification that is not Covered +Code. You may not publish Your test results or make claims of +comparative compatibility with respect to other implementations of the +Specification. In consideration for the license grant in Section 1.1 +above You agree not to develop Your own tests that are intended to +validate conformation with the Specification. + +2. Test Results. + +You agree to provide to Original Contributor or the third party test +facility if applicable, Your test results that demonstrate that Covered +Code is Compliant Covered Code and that Original Contributor may publish +or otherwise distribute such test results. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH THE ORIGINAL CONTRIBUTOR, REALNETWORKS, +INC. IF YOU ARE AGREEING TO THIS LICENSE ON BEHALF OF A COMPANY, YOU +REPRESENT THAT YOU ARE AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. +WHETHER YOU ARE ACTING ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, +YOU MUST BE OF MAJORITY AGE AND BE OTHERWISE COMPETENT TO ENTER INTO +CONTRACTS. IF YOU DO NOT MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY +OF THE TERMS AND CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON +TO EXIT. + +*ACCEPT / REJECT +* + +* +* + +*To agree to the R&D/academic terms of this license, please register + on the site -- +you will then be given a chance to agree to the clickwrap RCSL + +R&D License + +and gain access to the RCSL-licensed source code. To build or deploy +commercial applications based on the RCSL, you will need to agree to the +Commercial Use license attachments +* + + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/RPSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/RPSL.txt new file mode 100644 index 0000000..d040a45 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/RPSL.txt @@ -0,0 +1,518 @@ +RealNetworks Public Source License Version 1.0 +(Rev. Date October 28, 2002) + +1. General Definitions. This License applies to any program or other work which +RealNetworks, Inc., or any other entity that elects to use this license, +("Licensor") makes publicly available and which contains a notice placed by +Licensor identifying such program or work as "Original Code" and stating that it +is subject to the terms of this RealNetworks Public Source License version 1.0 +(or subsequent version thereof) ("License"). You are not required to accept this +License. However, nothing else grants You permission to use, copy, modify or +distribute the software or its derivative works. These actions are prohibited by +law if You do not accept this License. Therefore, by modifying, copying or +distributing the software (or any work based on the software), You indicate your +acceptance of this License to do so, and all its terms and conditions. In +addition, you agree to the terms of this License by clicking the Accept button +or downloading the software. As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Licensor is the +grantor of rights, claims of patents that (i) are now or hereafter acquired, +owned by or assigned to Licensor and (ii) are necessarily infringed by using or +making the Original Code alone and not in combination with other software or +hardware; and (b) in the case where You are the grantor of rights, claims of +patents that (i) are now or hereafter acquired, owned by or assigned to You and +(ii) are infringed (directly or indirectly) by using or making Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Compatible Source License" means any one of the licenses listed on Exhibit +B or at https://www.helixcommunity.org/content/complicense or other licenses +specifically identified by Licensor in writing. Notwithstanding any term to the +contrary in any Compatible Source License, any code covered by any Compatible +Source License that is used with Covered Code must be made readily available in +Source Code format for royalty-free use under the terms of the Compatible Source +License or this License. + +1.3 "Contributor" means any person or entity that creates or contributes to the +creation of Modifications. + +1.4 "Covered Code" means the Original Code, Modifications, the combination of +Original Code and any Modifications, and/or any respective portions thereof. + +1.5 "Deploy" means to use, sublicense or distribute Covered Code other than for +Your internal research and development (R&D) and/or Personal Use, and includes +without limitation, any and all internal use or distribution of Covered Code +within Your business or organization except for R&D use and/or Personal Use, as +well as direct or indirect sublicensing or distribution of Covered Code by You +to any third party in any form or manner. + +1.6 "Derivative Work" means either the Covered Code or any derivative work under +United States copyright law, and including any work containing or including any +portion of the Covered Code or Modifications, either verbatim or with +modifications and/or translated into another language. Derivative Work also +includes any work which combines any portion of Covered Code or Modifications +with code not otherwise governed by the terms of this License. + +1.7 "Externally Deploy" means to Deploy the Covered Code in any way that may be +accessed or used by anyone other than You, used to provide any services to +anyone other than You, or used in any way to deliver any content to anyone other +than You, whether the Covered Code is distributed to those parties, made +available as an application intended for use over a computer network, or used to +provide services or otherwise deliver content to anyone other than You. + +1.8. "Interface" means interfaces, functions, properties, class definitions, +APIs, header files, GUIDs, V-Tables, and/or protocols allowing one piece of +software, firmware or hardware to communicate or interoperate with another piece +of software, firmware or hardware. + +1.9 "Modifications" mean any addition to, deletion from, and/or change to, the +substance and/or structure of the Original Code, any previous Modifications, the +combination of Original Code and any previous Modifications, and/or any +respective portions thereof. When code is released as a series of files, a +Modification is: (a) any addition to or deletion from the contents of a file +containing Covered Code; and/or (b) any new file or other representation of +computer program statements that contains any part of Covered Code. + +1.10 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Licensor under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Licensor under this License, and that has been expressly identified by Licensor +as such in the header file(s) of such work; and (b) the object code compiled +from such Source Code and originally made available by Licensor under this +License. + +1.11 "Personal Use" means use of Covered Code by an individual solely for his or +her personal, private and non-commercial purposes. An individual's use of +Covered Code in his or her capacity as an officer, employee, member, independent +contractor or agent of a corporation, business or organization (commercial or +non-commercial) does not qualify as Personal Use. + +1.12 "Source Code" means the human readable form of a program or other work that +is suitable for making modifications to it, including all modules it contains, +plus any associated interface definition files, scripts used to control +compilation and installation of an executable (object code). + +1.13 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership of +fifty percent (50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Licensor hereby grants You, effective on the date +You accept this License (via downloading or using Covered Code or otherwise +indicating your acceptance of this License), a worldwide, royalty-free, +non-exclusive copyright license, to the extent of Licensor's copyrights cover +the Original Code, to do the following: + +2.1 You may reproduce, display, perform, modify and Deploy Covered Code, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the copyright +and other proprietary notices and disclaimers of Licensor as they appear in the +Original Code, and keep intact all notices in the Original Code that refer to +this License; + +(b) You must include a copy of this License with every copy of Source Code of +Covered Code and documentation You distribute, and You may not offer or impose +any terms on such Source Code that alter or restrict this License or the +recipients' rights hereunder, except as permitted under Section 6; + +(c) You must duplicate, to the extent it does not already exist, the notice in +Exhibit A in each file of the Source Code of all Your Modifications, and cause +the modified files to carry prominent notices stating that You changed the files +and the date of any change; + +(d) You must make Source Code of all Your Externally Deployed Modifications +publicly available under the terms of this License, including the license grants +set forth in Section 3 below, for as long as you Deploy the Covered Code or +twelve (12) months from the date of initial Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Deployed Modifications +electronically (e.g. download from a web site); and + +(e) if You Deploy Covered Code in object code, executable form only, You must +include a prominent notice, in the code itself as well as in related +documentation, stating that Source Code of the Covered Code is available under +the terms of this License with information on how and where to obtain such +Source Code. You must also include the Object Code Notice set forth in Exhibit A +in the "about" box or other appropriate place where other copyright notices are +placed, including any packaging materials. + +2.2 You expressly acknowledge and agree that although Licensor and each +Contributor grants the licenses to their respective portions of the Covered Code +set forth herein, no assurances are provided by Licensor or any Contributor that +the Covered Code does not infringe the patent or other intellectual property +rights of any other entity. Licensor and each Contributor disclaim any liability +to You for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, You hereby assume sole responsibility to +secure any other intellectual property rights needed, if any. For example, if a +third party patent license is required to allow You to make, use, sell, import +or offer for sale the Covered Code, it is Your responsibility to acquire such +license(s). + +2.3 Subject to the terms and conditions of this License, Licensor hereby grants +You, effective on the date You accept this License (via downloading or using +Covered Code or otherwise indicating your acceptance of this License), a +worldwide, royalty-free, perpetual, non-exclusive patent license under +Licensor's Applicable Patent Rights to make, use, sell, offer for sale and +import the Covered Code, provided that in each instance you comply with the +terms of this License. + +3. Your Grants. In consideration of, and as a condition to, the licenses granted +to You under this License: + +(a) You grant to Licensor and all third parties a non-exclusive, perpetual, +irrevocable, royalty free license under Your Applicable Patent Rights and other +intellectual property rights owned or controlled by You, to make, sell, offer +for sale, use, import, reproduce, display, perform, modify, distribute and +Deploy Your Modifications of the same scope and extent as Licensor's licenses +under Sections 2.1 and 2.2; and + +(b) You grant to Licensor and its subsidiaries a non-exclusive, worldwide, +royalty-free, perpetual and irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights owned or controlled by You, to +make, use, sell, offer for sale, import, reproduce, display, perform, +distribute, modify or have modified (for Licensor and/or its subsidiaries), +sublicense and distribute Your Modifications, in any form and for any purpose, +through multiple tiers of distribution. + +(c) You agree not use any information derived from Your use and review of the +Covered Code, including but not limited to any algorithms or inventions that may +be contained in the Covered Code, for the purpose of asserting any of Your +patent rights, or assisting a third party to assert any of its patent rights, +against Licensor or any Contributor. + +4. Derivative Works. You may create a Derivative Work by combining Covered Code +with other code not otherwise governed by the terms of this License and +distribute the Derivative Work as an integrated product. In each such instance, +You must make sure the requirements of this License are fulfilled for the +Covered Code or any portion thereof, including all Modifications. + +4.1 You must cause any Derivative Work that you distribute, publish or +Externally Deploy, that in whole or in part contains or is derived from the +Covered Code or any part thereof, to be licensed as a whole at no charge to all +third parties under the terms of this License and no other license except as +provided in Section 4.2. You also must make Source Code available for the +Derivative Work under the same terms as Modifications, described in Sections 2 +and 3, above. + +4.2 Compatible Source Licenses. Software modules that have been independently +developed without any use of Covered Code and which contain no portion of the +Covered Code, Modifications or other Derivative Works, but are used or combined +in any way wtih the Covered Code or any Derivative Work to form a larger +Derivative Work, are exempt from the conditions described in Section 4.1 but +only to the extent that: the software module, including any software that is +linked to, integrated with, or part of the same applications as, the software +module by any method must be wholly subject to one of the Compatible Source +Licenses. Notwithstanding the foregoing, all Covered Code must be subject to the +terms of this License. Thus, the entire Derivative Work must be licensed under a +combination of the RPSL (for Covered Code) and a Compatible Source License for +any independently developed software modules within the Derivative Work. The +foregoing requirement applies even if the Compatible Source License would +ordinarily allow the software module to link with, or form larger works with, +other software that is not subject to the Compatible Source License. For +example, although the Mozilla Public License v1.1 allows Mozilla code to be +combined with proprietary software that is not subject to the MPL, if +MPL-licensed code is used with Covered Code the MPL-licensed code could not be +combined or linked with any code not governed by the MPL. The general intent of +this section 4.2 is to enable use of Covered Code with applications that are +wholly subject to an acceptable open source license. You are responsible for +determining whether your use of software with Covered Code is allowed under Your +license to such software. + +4.3 Mere aggregation of another work not based on the Covered Code with the +Covered Code (or with a work based on the Covered Code) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. If You deliver the Covered Code for combination and/or integration with +an application previously provided by You (for example, via automatic updating +technology), such combination and/or integration constitutes a Derivative Work +subject to the terms of this License. + +5. Exclusions From License Grant. Nothing in this License shall be deemed to +grant any rights to trademarks, copyrights, patents, trade secrets or any other +intellectual property of Licensor or any Contributor except as expressly stated +herein. No right is granted to the trademarks of Licensor or any Contributor +even if such marks are included in the Covered Code. Nothing in this License +shall be interpreted to prohibit Licensor from licensing under different terms +from this License any code that Licensor otherwise would have a right to +license. Modifications, Derivative Works and/or any use or combination of +Covered Code with other technology provided by Licensor or third parties may +require additional patent licenses from Licensor which Licensor may grant in its +sole discretion. No patent license is granted separate from the Original Code or +combinations of the Original Code with other software or hardware. + +5.1. Trademarks. This License does not grant any rights to use the trademarks or +trade names owned by Licensor ("Licensor Marks" defined in Exhibit C) or to any +trademark or trade name belonging to any Contributor. No Licensor Marks may be +used to endorse or promote products derived from the Original Code other than as +permitted by the Licensor Trademark Policy defined in Exhibit C. + +6. Additional Terms. You may choose to offer, and to charge a fee for, warranty, +support, indemnity or liability obligations and/or other rights consistent with +the scope of the license granted herein ("Additional Terms") to one or more +recipients of Covered Code. However, You may do so only on Your own behalf and +as Your sole responsibility, and not on behalf of Licensor or any Contributor. +You must obtain the recipient's agreement that any such Additional Terms are +offered by You alone, and You hereby agree to indemnify, defend and hold +Licensor and every Contributor harmless for any liability incurred by or claims +asserted against Licensor or such Contributor by reason of any such Additional +Terms. + +7. Versions of the License. Licensor may publish revised and/or new versions of +this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular version +of this License, You may continue to use it under the terms of that version. You +may also choose to use such Original Code under the terms of any subsequent +version of this License published by Licensor. No one other than Licensor has +the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in part +pre-release, untested, or not fully tested works. The Covered Code may contain +errors that could cause failures or loss of data, and may be incomplete or +contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND LICENSOR AND LICENSOR'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS +"LICENSOR" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY +DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET +ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. LICENSOR AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN DOCUMENTATION, INFORMATION OR ADVICE GIVEN BY LICENSOR, A LICENSOR +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You +acknowledge that the Covered Code is not intended for use in high risk +activities, including, but not limited to, the design, construction, operation +or maintenance of nuclear facilities, aircraft navigation, aircraft +communication systems, or air traffic control machines in which case the failure +of the Covered Code could lead to death, personal injury, or severe physical or +environmental damage. Licensor disclaims any express or implied warranty of +fitness for such uses. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT +SHALL LICENSOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR STRICT +LIABILITY), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF LICENSOR OR SUCH +CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND +NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. SOME +JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF INCIDENTAL OR +CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event +shall Licensor's total liability to You for all damages (other than as may be +required by applicable law) under this License exceed the amount of ten dollars +($10.00). + +10. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Licensor retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Licensor +("Licensor Modifications"), and such Licensor Modifications will not be +automatically subject to this License. Licensor may, at its sole discretion, +choose to license such Licensor Modifications under this License, or on +different terms from those contained in this License or may choose not to +license them at all. + +11. Termination. + +11.1 Term and Termination. The term of this License is perpetual unless +terminated as provided below. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Licensor if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; + +(b) immediately in the event of the circumstances described in Section 12.5(b); +or + +(c) automatically without notice from Licensor if You, at any time during the +term of this License, commence an action for patent infringement against +Licensor (including by cross-claim or counter claim in a lawsuit); + +(d) upon written notice from Licensor if You, at any time during the term of +this License, commence an action for patent infringement against any third party +alleging that the Covered Code itself (excluding combinations with other +software or hardware) infringes any patent (including by cross-claim or counter +claim in a lawsuit). + +11.2 Effect of Termination. Upon termination, You agree to immediately stop any +further use, reproduction, modification, sublicensing and distribution of the +Covered Code and to destroy all copies of the Covered Code that are in your +possession or control. All sublicenses to the Covered Code which have been +properly granted prior to termination shall survive any termination of this +License. Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to Sections +3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other for +compensation, indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this License will +be without prejudice to any other right or remedy of any party. + +12. Miscellaneous. + +12.1 Government End Users. The Covered Code is a "commercial item" as defined in +FAR 2.101. Government software and technical data rights in the Covered Code +include only those rights customarily provided to the public as defined in this +License. This customary commercial license in technical data and software is +provided in accordance with FAR 12.211 (Technical Data) and 12.212 (Computer +Software) and, for Department of Defense purchases, DFAR 252.227-7015 (Technical +Data -- Commercial Items) and 227.7202-3 (Rights in Commercial Computer Software +or Computer Software Documentation). Accordingly, all U.S. Government End Users +acquire Covered Code with only those rights set forth herein. + +12.2 Relationship of Parties. This License will not be construed as creating an +agency, partnership, joint venture or any other form of legal association +between or among You, Licensor or any Contributor, and You will not represent to +the contrary, whether expressly, by implication, appearance or otherwise. + +12.3 Independent Development. Nothing in this License will impair Licensor's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions as, +or otherwise compete with, Modifications, Derivative Works, technology or +products that You may develop, produce, market or distribute. + +12.4 Waiver; Construction. Failure by Licensor or any Contributor to enforce any +provision of this License will not be deemed a waiver of future enforcement of +that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +12.5 Severability. (a) If for any reason a court of competent jurisdiction finds +any provision of this License, or portion thereof, to be unenforceable, that +provision of the License will be enforced to the maximum extent permissible so +as to effect the economic benefits and intent of the parties, and the remainder +of this License will continue in full force and effect. (b) Notwithstanding the +foregoing, if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the enforceability +of either of those Sections, this License will immediately terminate and You +must immediately discontinue any use of the Covered Code and destroy all copies +of it that are in your possession or control. + +12.6 Dispute Resolution. Any litigation or other dispute resolution between You +and Licensor relating to this License shall take place in the Seattle, +Washington, and You and Licensor hereby consent to the personal jurisdiction of, +and venue in, the state and federal courts within that District with respect to +this License. The application of the United Nations Convention on Contracts for +the International Sale of Goods is expressly excluded. + +12.7 Export/Import Laws. This software is subject to all export and import laws +and restrictions and regulations of the country in which you receive the Covered +Code and You are solely responsible for ensuring that You do not export, +re-export or import the Covered Code or any direct product thereof in violation +of any such restrictions, laws or regulations, or without all necessary +authorizations. + +12.8 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +Washington. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé +que le présent contrat et tous les documents connexes soient +rédigés en anglais. + + EXHIBIT A. + +"Copyright © 1995-2002 +RealNetworks, Inc. and/or its licensors. All Rights Reserved. + +The contents of this file, and the files included with this file, are subject to +the current version of the RealNetworks Public Source License Version 1.0 (the +"RPSL") available at https://www.helixcommunity.org/content/rpsl unless you have +licensed the file under the RealNetworks Community Source License Version 1.0 +(the "RCSL") available at https://www.helixcommunity.org/content/rcsl, in which +case the RCSL will apply. You may also obtain the license terms directly from +RealNetworks. You may not use this file except in compliance with the RPSL or, +if you have a valid RCSL with RealNetworks applicable to this file, the RCSL. +Please see the applicable RPSL or RCSL for the rights, obligations and +limitations governing use of the contents of the file. + +This file is part of the Helix DNA Technology. RealNetworks is the developer of +the Original code and owns the copyrights in the portions it created. + +This file, and the files included with this file, is distributed and made +available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR +IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING +WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): ____________________________________ + +Technology Compatibility Kit Test +Suite(s) Location (if licensed under the RCSL): ______________________________ + +Object Code Notice: Helix DNA Client technology included. Copyright (c) +RealNetworks, Inc., 1995-2002. All rights reserved. + + + EXHIBIT B + +Compatible Source Licenses for the RealNetworks Public Source License. The +following list applies to the most recent version of the license as of October +25, 2002, unless otherwise indicated. + +* Academic Free License +* Apache Software License +* Apple Public Source License +* Artistic license +* Attribution Assurance Licenses +* BSD license +* Common Public License (1) +* Eiffel Forum License +* GNU General Public License (GPL) (1) +* GNU Library or "Lesser" General Public License (LGPL) (1) +* IBM Public License +* Intel Open Source License +* Jabber Open Source License +* MIT license +* MITRE Collaborative Virtual Workspace License (CVW License) +* Motosoto License +* Mozilla Public License 1.0 (MPL) +* Mozilla Public License 1.1 (MPL) +* Nokia Open Source License +* Open Group Test Suite License +* Python Software Foundation License +* Ricoh Source Code Public License +* Sun Industry Standards Source License (SISSL) +* Sun Public License +* University of Illinois/NCSA Open Source License +* Vovida Software License v. 1.0 +* W3C License +* X.Net License +* Zope Public License +* zlib/libpng license + +(1) Note: because this license contains certain reciprocal licensing terms that +purport to extend to independently developed code, You may be prohibited under +the terms of this otherwise compatible license from using code licensed under +its terms with Covered Code because Covered Code may only be licensed under the +RealNetworks Public Source License. Any attempt to apply non RPSL license terms, +including without limitation the GPL, to Covered Code is expressly forbidden. +You are responsible for ensuring that Your use of Compatible Source Licensed +code does not violate either the RPSL or the Compatible Source License. + +The latest version of this list can be found at: +https://www.helixcommunity.org/content/complicense + + EXHIBIT C + +RealNetworks' Trademark policy. + +RealNetworks defines the following trademarks collectively as "Licensor +Trademarks": "RealNetworks", "RealPlayer", "RealJukebox", "RealSystem", +"RealAudio", "RealVideo", "RealOne Player", "RealMedia", "Helix" or any other +trademarks or trade names belonging to RealNetworks. + +RealNetworks "Licensor Trademark Policy" forbids any use of Licensor Trademarks +except as permitted by and in strict compliance at all times with RealNetworks' +third party trademark usage guidelines which are posted at +http://www.realnetworks.com/info/helixlogo.html. + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/mp3common.h b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/mp3common.h new file mode 100644 index 0000000..0cd3172 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/mp3common.h @@ -0,0 +1,124 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * mp3common.h - implementation-independent API's, datatypes, and definitions + **************************************************************************************/ + +#ifndef _MP3COMMON_H +#define _MP3COMMON_H + +#include "mp3dec.h" +#include "statname.h" /* do name-mangling for static linking */ + +#define MAX_SCFBD 4 /* max scalefactor bands per channel */ +#define NGRANS_MPEG1 2 +#define NGRANS_MPEG2 1 + +/* 11-bit syncword if MPEG 2.5 extensions are enabled */ +/* +#define SYNCWORDH 0xff +#define SYNCWORDL 0xe0 +*/ + +/* 12-bit syncword if MPEG 1,2 only are supported */ +#define SYNCWORDH 0xff +#define SYNCWORDL 0xf0 + +typedef struct _MP3DecInfo { + /* pointers to platform-specific data structures */ + void *FrameHeaderPS; + void *SideInfoPS; + void *ScaleFactorInfoPS; + void *HuffmanInfoPS; + void *DequantInfoPS; + void *IMDCTInfoPS; + void *SubbandInfoPS; + + /* buffer which must be large enough to hold largest possible main_data section */ + unsigned char mainBuf[MAINBUF_SIZE]; + + /* special info for "free" bitrate files */ + int freeBitrateFlag; + int freeBitrateSlots; + + /* user-accessible info */ + int bitrate; + int nChans; + int samprate; + int nGrans; /* granules per frame */ + int nGranSamps; /* samples per granule */ + int nSlots; + int layer; + MPEGVersion version; + + int mainDataBegin; + int mainDataBytes; + + int part23Length[MAX_NGRAN][MAX_NCHAN]; + +} MP3DecInfo; + +typedef struct _SFBandTable { + short l[23]; + short s[14]; +} SFBandTable; + +/* decoder functions which must be implemented for each platform */ +MP3DecInfo *AllocateBuffers(void); +void FreeBuffers(MP3DecInfo *mp3DecInfo); +int CheckPadBit(MP3DecInfo *mp3DecInfo); +int UnpackFrameHeader(MP3DecInfo *mp3DecInfo, unsigned char *buf); +int UnpackSideInfo(MP3DecInfo *mp3DecInfo, unsigned char *buf); +int DecodeHuffman(MP3DecInfo *mp3DecInfo, unsigned char *buf, int *bitOffset, int huffBlockBits, int gr, int ch); +int Dequantize(MP3DecInfo *mp3DecInfo, int gr); +int IMDCT(MP3DecInfo *mp3DecInfo, int gr, int ch); +int UnpackScaleFactors(MP3DecInfo *mp3DecInfo, unsigned char *buf, int *bitOffset, int bitsAvail, int gr, int ch); +int Subband(MP3DecInfo *mp3DecInfo, short *pcmBuf); + +/* mp3tabs.c - global ROM tables */ +extern const int samplerateTab[3][3]; +extern const short bitrateTab[3][3][15]; +extern const short samplesPerFrameTab[3][3]; +extern const short bitsPerSlotTab[3]; +extern const short sideBytesTab[3][2]; +extern const short slotTab[3][3][15]; +extern const SFBandTable sfBandTable[3][3]; + +#endif /* _MP3COMMON_H */ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/mp3dec.h b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/mp3dec.h new file mode 100644 index 0000000..cd6c2da --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/mp3dec.h @@ -0,0 +1,132 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * mp3dec.h - public C API for MP3 decoder + **************************************************************************************/ + +#ifndef _MP3DEC_H +#define _MP3DEC_H + +#if defined(_WIN32) && !defined(_WIN32_WCE) +# +#elif defined(_WIN32) && defined(_WIN32_WCE) && defined(ARM) +# +#elif defined(_WIN32) && defined(WINCE_EMULATOR) +# +#elif defined(ARM_ADS) +# +#elif defined(_SYMBIAN) && defined(__WINS__) /* Symbian emulator for Ix86 */ +# +#elif defined(__GNUC__) && defined(ARM) +# +#elif defined(__GNUC__) && defined(__i386__) +# +#elif defined(_OPENWAVE_SIMULATOR) || defined(_OPENWAVE_ARMULATOR) +# +#else +//#error No platform defined. See valid options in mp3dec.h +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* determining MAINBUF_SIZE: + * max mainDataBegin = (2^9 - 1) bytes (since 9-bit offset) = 511 + * max nSlots (concatenated with mainDataBegin bytes from before) = 1440 - 9 - 4 + 1 = 1428 + * 511 + 1428 = 1939, round up to 1940 (4-byte align) + */ +#define MAINBUF_SIZE 1940 + +#define MAX_NGRAN 2 /* max granules */ +#define MAX_NCHAN 2 /* max channels */ +#define MAX_NSAMP 576 /* max samples per channel, per granule */ + +/* map to 0,1,2 to make table indexing easier */ +typedef enum { + MPEG1 = 0, + MPEG2 = 1, + MPEG25 = 2 +} MPEGVersion; + +typedef void *HMP3Decoder; + +enum { + ERR_MP3_NONE = 0, + ERR_MP3_INDATA_UNDERFLOW = -1, + ERR_MP3_MAINDATA_UNDERFLOW = -2, + ERR_MP3_FREE_BITRATE_SYNC = -3, + ERR_MP3_OUT_OF_MEMORY = -4, + ERR_MP3_NULL_POINTER = -5, + ERR_MP3_INVALID_FRAMEHEADER = -6, + ERR_MP3_INVALID_SIDEINFO = -7, + ERR_MP3_INVALID_SCALEFACT = -8, + ERR_MP3_INVALID_HUFFCODES = -9, + ERR_MP3_INVALID_DEQUANTIZE = -10, + ERR_MP3_INVALID_IMDCT = -11, + ERR_MP3_INVALID_SUBBAND = -12, + + ERR_UNKNOWN = -9999 +}; + +typedef struct _MP3FrameInfo { + int bitrate; + int nChans; + int samprate; + int bitsPerSample; + int outputSamps; + int layer; + int version; +} MP3FrameInfo; + +/* public API */ +HMP3Decoder MP3InitDecoder(void); +void MP3FreeDecoder(HMP3Decoder hMP3Decoder); +int MP3Decode(HMP3Decoder hMP3Decoder, unsigned char **inbuf, int *bytesLeft, short *outbuf, int useSize); + +void MP3GetLastFrameInfo(HMP3Decoder hMP3Decoder, MP3FrameInfo *mp3FrameInfo); +int MP3GetNextFrameInfo(HMP3Decoder hMP3Decoder, MP3FrameInfo *mp3FrameInfo, unsigned char *buf); +int MP3FindSyncWord(unsigned char *buf, int nBytes); + +#ifdef __cplusplus +} +#endif + +#endif /* _MP3DEC_H */ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/mpadecobjfixpt.h b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/mpadecobjfixpt.h new file mode 100644 index 0000000..a8a5c40 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/mpadecobjfixpt.h @@ -0,0 +1,108 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _MPADECOBJFIXPT_H_ +#define _MPADECOBJFIXPT_H_ + +#include "mp3dec.h" /* public C API for new MP3 decoder */ + +class CMpaDecObj +{ +public: + CMpaDecObj(); + ~CMpaDecObj(); + + /////////////////////////////////////////////////////////////////////////// + // Function: Init_n + // Purpose: Initialize the mp3 decoder. + // Parameters: pSync a pointer to a syncword + // ulSize the size of the buffer pSync points to + // bUseSize this tells the decoder to use the input frame + // size on the decode instead of calculating + // the frame size. This is necessary when + // our formatted mp3 data (main_data_begin always + // equal to 0). + // + // Returns: returns 1 on success, 0 on failure + /////////////////////////////////////////////////////////////////////////// + int Init_n(unsigned char *pSync, + unsigned long ulSize, + unsigned char bUseSize=0); + + /////////////////////////////////////////////////////////////////////////// + // Function: DecodeFrame_v + // Purpose: Decodes one mp3 frame + // Parameters: pSource pointer to an mp3 frame (at a syncword) + // pulSize size of the buffer pSource points to. It will + // contain the number of mp3 bytes decoded upon + // return. + // pPCM pointer to a buffer to decode into + // pulPCMSize size of the PCM buffer. It will contain the + // number of PCM bytes prodced upon return. + /////////////////////////////////////////////////////////////////////////// + void DecodeFrame_v(unsigned char *pSource, + unsigned long *pulSize, + unsigned char *pPCM, + unsigned long *pulPCMSize); + + // overloaded new version that returns error code in errCode + void DecodeFrame_v(unsigned char *pSource, + unsigned long *pulSize, + unsigned char *pPCM, + unsigned long *pulPCMSize, + int *errCode); + + void GetPCMInfo_v(unsigned long &ulSampRate, + int &nChannels, + int &nBitsPerSample); + + // return number of samples per frame, PER CHANNEL (renderer multiplies this result by nChannels) + int GetSamplesPerFrame_n(); + + void SetTrustPackets(unsigned char bTrust) { m_bTrustPackets = bTrust; } + +private: + void * m_pDec; // generic void ptr + + void * m_pDecL1; // not implemented (could use old Xing mpadecl1.cpp) + void * m_pDecL2; // not implemented (could use old Xing mpadecl2.cpp) + HMP3Decoder m_pDecL3; + + MP3FrameInfo m_lastMP3FrameInfo; + unsigned char m_bUseFrameSize; + unsigned char m_bTrustPackets; +}; + +#endif /* _MPADECOBJFIXPT_H_ */ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/statname.h b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/statname.h new file mode 100644 index 0000000..518e4c7 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/pub/statname.h @@ -0,0 +1,88 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * statname.h - name mangling macros for static linking + **************************************************************************************/ + +#ifndef _STATNAME_H +#define _STATNAME_H + +/* define STAT_PREFIX to a unique name for static linking + * all the C functions and global variables will be mangled by the preprocessor + * e.g. void FFT(int *fftbuf) becomes void cook_FFT(int *fftbuf) + */ +#define STAT_PREFIX xmp3 + +#define STATCC1(x,y,z) STATCC2(x,y,z) +#define STATCC2(x,y,z) x##y##z + +#ifdef STAT_PREFIX +#define STATNAME(func) STATCC1(STAT_PREFIX, _, func) +#else +#define STATNAME(func) func +#endif + +/* these symbols are common to all implementations */ +#define CheckPadBit STATNAME(CheckPadBit) +#define UnpackFrameHeader STATNAME(UnpackFrameHeader) +#define UnpackSideInfo STATNAME(UnpackSideInfo) +#define AllocateBuffers STATNAME(AllocateBuffers) +#define FreeBuffers STATNAME(FreeBuffers) +#define DecodeHuffman STATNAME(DecodeHuffman) +#define Dequantize STATNAME(Dequantize) +#define IMDCT STATNAME(IMDCT) +#define UnpackScaleFactors STATNAME(UnpackScaleFactors) +#define Subband STATNAME(Subband) + +#define samplerateTab STATNAME(samplerateTab) +#define bitrateTab STATNAME(bitrateTab) +#define samplesPerFrameTab STATNAME(samplesPerFrameTab) +#define bitsPerSlotTab STATNAME(bitsPerSlotTab) +#define sideBytesTab STATNAME(sideBytesTab) +#define slotTab STATNAME(slotTab) +#define sfBandTable STATNAME(sfBandTable) + +/* in your implementation's top-level include file (e.g. real\coder.h) you should + * add new #define sym STATNAME(sym) lines for all the + * additional global functions or variables which your + * implementation uses + */ + +#endif /* _STATNAME_H */ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/readme.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/readme.txt new file mode 100644 index 0000000..69e5d42 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/readme.txt @@ -0,0 +1,141 @@ +Fixed-point MP3 decoder +Developed by RealNetworks, 2003 +=============================== + +Overview +-------- +This module contains a high-performance MPEG layer 3 audio decoder for 32-bit fixed-point +processors. The following is a quick summary of what is and is not supported: + +Supported + - layer 3 + - MPEG1, MPEG2, and MPEG2.5 (low sampling frequency extensions) + - constant bitrate, variable bitrate, and free bitrate modes + - mono and all stereo modes (normal stereo, joint stereo, dual-mono) + +Not currently supported + - layers 1 and 2 + +Highlights +---------- + - highly optimized for ARM processors (details in docs/ subdirectory) + - reference x86 implementation + - C and assembly code only (C++ not required) + - reentrant, statically linkable + - low memory (details in docs/ subdirectory) + - option to use Intel Integrated Performance Primitives (details below) + +Supported platforms and toolchains +---------------------------------- +This codec should run on any 32-bit fixed-point processor which can perform a full 32x32-bit +multiply (providing a 64-bit result). The following processors and toolchains are supported: + - x86, Microsoft Visual C++ + - ARM, ARM Developer Suite (ADS) + - ARM, Microsoft Embedded Visual C++ + - ARM, GNU toolchain (gcc) + - RISC-V, GNU toolchain (gcc) + +ARM refers to any processor supporting ARM architecture v.4 or above. Thumb is not required. +Typically this means an ARM7TDMI or better (including ARM9, StrongARM, XScale, etc.) + +Generally ADS produces the fastest code. EVC 3.0 does not support inline assembly code for +ARM targets, so calls to MULSHIFT32 (smull on ARM) are left as function calls. For the +fastest code on targets which do not normally use ADS consider compiling with ADS, +using the -S option to output assembly code, and feeding this assembly code to the assembler +of your choice. This might require some syntax changes in the .S file. + +Adding support for a new processor is fairly simple. Simply add a new block to the file +real/assembly.h which implements the required inline assembly functions for your processor. +Something like + +... +#elif defined NEW_PROCESSOR + +/* you implement MULSHIFT32() and so forth */ + +#else +#error Unsupported platform in assembly.h +#endif + +Optionally you can rewrite or add assembly language files optimized for your platform. Note +that many of the algorithms are designed for an ARM-type processor, so performance of the +unmodified C code might be noticeably worse on other architectures. + +Adding support for a new toolchain should be straightforward. Use the sample projects or the +Umakefil as a template for which source files to include. + +Directory structure +------------------- +fixpt/ platform-independent code and tables, public API +fixpt/docs algorithm notes, memory and CPU usage figures, optimization suggestions +fixpt/ipp source code which uses IPP for decoding (see the "IPP" section below) +fixpt/pub public header files +fixpt/real source code for RealNetworks' MP3 decoder +fixpt/testwrap sample code to build a command-line test application + +Code organization +----------------- +fixpt/ + mpadecobj.cpp optional shim which exports API used by Helix clients (see mp3/renderer) + mp3dec.c main decode functions, exports C-only API + mp3tabs.c common tables used by all implementations (bitrates, frame sizes, etc.) +fixpt/pub/ + mp3common.h defines low-level codec API which mp3dec.c calls + mp3dec.h defines high-level codec API which applications call + mpadecobjfixpt.h optional C++ shim API (only necessary if mpadecobj.cpp is used) + statname.h symbols which get name-mangled by C preprocessor to allow static linking +fixpt/ipp source code for wrapper files which link in IPP libraries +fixpt/real full source code for RealNetworks MP3 decoder + +To build an MP3 decoder library, you'll need to compile the top-level files and EITHER +real/*.c OR ipp/*.c and the correct IPP library. + +Decoder using Real code: mp3dec.c + mp3tabs.c + real/*.c + real/arm/[files].s (if ARM) +Decoder using IPP code: mp3dec.c + mp3tabs.c + ipp/*.c + ippac*.lib + +Although the real/ and ipp/ source code follow the same top-level API (for Dequantize(), +Subband(), etc.) mixing and matching is not guaranteed to work. The outputs might +be ordered differently for optimization purposes, scaled differently, etc. + +IPP +--- +For certain platforms Intel has created highly-optimized object code libraries of DSP +routines. These are called the Intel Integrated Performance Primitives (IPP). If IPP +libraries are available for a platform, this MP3 decoder can link them in and use them +instead of the RealNetworks source code. To use IPP, you still need to build the top-level +files (mp3dec.c, mp3tabs.c). You also build the files in ipp/*.c. These are just thin +wrappers which provide the glue logic between the top-level decode functions in +mp3dec.c and the optimized DSP primitives in the IPP libraries. IPP libraries are not +included in this module. You must obtain them WITH A LICENSE directly from Intel. +Further info on the latest versions of IPP (as of the date of this readme) is available +from the URLs below + +Intel Integrated Performance Primitives for the +Intel PXA25x and PXA26x family of Processors, Version 3.0 +* http://www.intel.com/design/pca/applicationsprocessors/swsup/IPPv30.htm + +Intel Integrated Performance Primitives for +Intel Pentium Processors and Intel Itanium Architectures +* http://www.intel.com/software/products/ipp/ipp30/ + +These sites explain how to obtain IPP and the terms under which IPP libraries may be used. +The code in this module is merely wrapper code which calls IPP functions. You are fully +responsible for adhering to the license agreement under which you obtain the IPP +libraries from Intel. + +To-Do list and status +--------------------- +faster/lower-memory dequantizer (in progress) +tighter fixed-point scaling (in progress) +remove all run-time math calls (/, %) (in progress) +ARM assembly code for DCT32, IMDCT (if necessary) +add test scripts and compliance docs +write 32-bit C polyphase filter + (where 64-bit MACC not available) + +As these optimizations are completed, they will be added to the Helix codebase. Please +continue to check there for updates. Changes will be noted in this readme. + +readme.txt last updated 07/23/03 + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/LICENSE.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/LICENSE.txt new file mode 100644 index 0000000..12e5372 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/LICENSE.txt @@ -0,0 +1,30 @@ + Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. + + The contents of this directory, and (except where otherwise + indicated) the directories included within this directory, are + subject to the current version of the RealNetworks Public Source + License (the "RPSL") available at RPSL.txt in this directory, unless + you have licensed the directory under the current version of the + RealNetworks Community Source License (the "RCSL") available at + RCSL.txt in this directory, in which case the RCSL will apply. You + may also obtain the license terms directly from RealNetworks. You + may not use the files in this directory except in compliance with the + RPSL or, if you have a valid RCSL with RealNetworks applicable to + this directory, the RCSL. Please see the applicable RPSL or RCSL for + the rights, obligations and limitations governing use of the contents + of the directory. + + This directory is part of the Helix DNA Technology. RealNetworks is + the developer of the Original Code and owns the copyrights in the + portions it created. + + This directory, and the directories included with this directory, are + distributed and made available on an 'AS IS' basis, WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY + DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + QUIET ENJOYMENT OR NON-INFRINGEMENT. + + Technology Compatibility Kit Test Suite(s) Location: + http://www.helixcommunity.org/content/tck + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/RCSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/RCSL.txt new file mode 100644 index 0000000..a809759 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/RCSL.txt @@ -0,0 +1,948 @@ +The RCSL is made up of a base agreement and a few Attachments. + +For Research and Development use, you agree to the terms of the +RCSL R&D License (base RCSL and Attachments A, B, and C) + +For Commercial Use (either distribution or internal commercial +deployment) of the Helix DNA with or without support for RealNetworks' +RealAudio and RealVideo Add-on Technology, you agree to the +terms of the same RCSL R&D license +and execute one or more additional Commercial Use License attachments +. + +------------------------------------------------------------------------ + + + REALNETWORKS COMMUNITY SOURCE LICENSE + +Version 1.2 (Rev. Date: January 22, 2003). + + + RECITALS + +Original Contributor has developed Specifications, Source Code +implementations and Executables of certain Technology; and + +Original Contributor desires to license the Technology to a large +community to facilitate research, innovation and product development +while maintaining compatibility of such products with the Technology as +delivered by Original Contributor; and + +Original Contributor desires to license certain Trademarks for the +purpose of branding products that are compatible with the relevant +Technology delivered by Original Contributor; and + +You desire to license the Technology and possibly certain Trademarks +from Original Contributor on the terms and conditions specified in this +License. + +In consideration for the mutual covenants contained herein, You and +Original Contributor agree as follows: + + + AGREEMENT + +*1. Introduction.* + +The RealNetworks Community Source License ("RCSL") and effective +attachments ("License") may include five distinct licenses: + +i) Research Use license -- License plus Attachments A, B and C only. + +ii) Commercial Use and Trademark License, which may be for Internal +Deployment Use or external distribution, or both -- License plus +Attachments A, B, C, and D. + +iii) Technology Compatibility Kit (TCK) license -- Attachment C. + +iv) Add-On Technology License (Executable) Commercial Use License +-Attachment F. + +v) Add-On Technology Source Code Porting and Optimization +License-Attachment G. + +The Research Use license is effective when You click and accept this +License. The TCK is effective when You click and accept this License, +unless otherwise specified in the TCK attachments. The Commercial Use +and Trademark, Add-On Technology License, and the Add-On Technology +Source Code Porting and Optimization licenses must each be signed by You +and Original Contributor to become effective. Once effective, these +licenses and the associated requirements and responsibilities are +cumulative. Capitalized terms used in this License are defined in the +Glossary. + +*2. License Grants.* + +2.1 Original Contributor Grant. + +Subject to Your compliance with Sections 3, 8.10 and Attachment A of +this License, Original Contributor grants to You a worldwide, +royalty-free, non-exclusive license, to the extent of Original +Contributor's Intellectual Property Rights covering the Original Code, +Upgraded Code and Specifications, to do the following: + +(a) Research Use License: + +(i) use, reproduce and modify the Original Code, Upgraded Code and +Specifications to create Modifications and Reformatted Specifications +for Research Use by You; + +(ii) publish and display Original Code, Upgraded Code and Specifications +with, or as part of Modifications, as permitted under Section 3.1(b) below; + +(iii) reproduce and distribute copies of Original Code and Upgraded Code +to Licensees and students for Research Use by You; + +(iv) compile, reproduce and distribute Original Code and Upgraded Code +in Executable form, and Reformatted Specifications to anyone for +Research Use by You. + +(b) Other than the licenses expressly granted in this License, Original +Contributor retains all right, title, and interest in Original Code and +Upgraded Code and Specifications. + +2.2 Your Grants. + +(a) To Other Licensees. You hereby grant to each Licensee a license to +Your Error Corrections and Shared Modifications, of the same scope and +extent as Original Contributor's licenses under Section 2.1 a) above +relative to Research Use and Attachment D relative to Commercial Use. + +(b) To Original Contributor. You hereby grant to Original Contributor a +worldwide, royalty-free, non-exclusive, perpetual and irrevocable +license, to the extent of Your Intellectual Property Rights covering +Your Error Corrections, Shared Modifications and Reformatted +Specifications, to use, reproduce, modify, display and distribute Your +Error Corrections, Shared Modifications and Reformatted Specifications, +in any form, including the right to sublicense such rights through +multiple tiers of distribution. + +(c) Other than the licenses expressly granted in Sections 2.2(a) and (b) +above, and the restrictions set forth in Section 3.1(d)(iv) below, You +retain all right, title, and interest in Your Error Corrections, Shared +Modifications and Reformatted Specifications. + +2.3 Contributor Modifications. + +You may use, reproduce, modify, display and distribute Contributor Error +Corrections, Shared Modifications and Reformatted Specifications, +obtained by You under this License, to the same scope and extent as with +Original Code, Upgraded Code and Specifications. + +2.4 Subcontracting. + +You may deliver the Source Code of Covered Code to other Licensees +having at least a Research Use license, for the sole purpose of +furnishing development services to You in connection with Your rights +granted in this License. All such Licensees must execute appropriate +documents with respect to such work consistent with the terms of this +License, and acknowledging their work-made-for-hire status or assigning +exclusive right to the work product and associated Intellectual Property +Rights to You. + +*3. Requirements and Responsibilities*. + +3.1 Research Use License. + +As a condition of exercising the rights granted under Section 2.1(a) +above, You agree to comply with the following: + +(a) Your Contribution to the Community. All Error Corrections and Shared +Modifications which You create or contribute to are automatically +subject to the licenses granted under Section 2.2 above. You are +encouraged to license all of Your other Modifications under Section 2.2 +as Shared Modifications, but are not required to do so. You agree to +notify Original Contributor of any errors in the Specification. + +(b) Source Code Availability. You agree to provide all Your Error +Corrections to Original Contributor as soon as reasonably practicable +and, in any event, prior to Internal Deployment Use or Commercial Use, +if applicable. Original Contributor may, at its discretion, post Source +Code for Your Error Corrections and Shared Modifications on the +Community Webserver. You may also post Error Corrections and Shared +Modifications on a web-server of Your choice; provided, that You must +take reasonable precautions to ensure that only Licensees have access to +such Error Corrections and Shared Modifications. Such precautions shall +include, without limitation, a password protection scheme limited to +Licensees and a click-on, download certification of Licensee status +required of those attempting to download from the server. An example of +an acceptable certification is attached as Attachment A-2. + +(c) Notices. All Error Corrections and Shared Modifications You create +or contribute to must include a file documenting the additions and +changes You made and the date of such additions and changes. You must +also include the notice set forth in Attachment A-1 in the file header. +If it is not possible to put the notice in a particular Source Code file +due to its structure, then You must include the notice in a location +(such as a relevant directory file), where a recipient would be most +likely to look for such a notice. + +(d) Redistribution. + +(i) Source. Covered Code may be distributed in Source Code form only to +another Licensee (except for students as provided below). You may not +offer or impose any terms on any Covered Code that alter the rights, +requirements, or responsibilities of such Licensee. You may distribute +Covered Code to students for use in connection with their course work +and research projects undertaken at accredited educational institutions. +Such students need not be Licensees, but must be given a copy of the +notice set forth in Attachment A-3 and such notice must also be included +in a file header or prominent location in the Source Code made available +to such students. + +(ii) Executable. You may distribute Executable version(s) of Covered +Code to Licensees and other third parties only for the purpose of +evaluation and comment in connection with Research Use by You and under +a license of Your choice, but which limits use of such Executable +version(s) of Covered Code only to that purpose. + +(iii) Modified Class, Interface and Package Naming. In connection with +Research Use by You only, You may use Original Contributor's class, +Interface and package names only to accurately reference or invoke the +Source Code files You modify. Original Contributor grants to You a +limited license to the extent necessary for such purposes. + +(iv) You expressly agree that any distribution, in whole or in part, of +Modifications developed by You shall only be done pursuant to the terms +and conditions of this License. + +(e) Extensions. + +(i) Covered Code. You may not include any Source Code of Community Code +in any Extensions. You may include the compiled Header Files of +Community Code in an Extension provided that Your use of the Covered +Code, including Heading Files, complies with the Commercial Use License, +the TCK and all other terms of this License. + +(ii) Publication. No later than the date on which You first distribute +such Extension for Commercial Use, You must publish to the industry, on +a non-confidential basis and free of all copyright restrictions with +respect to reproduction and use, an accurate and current specification +for any Extension. In addition, You must make available an appropriate +test suite, pursuant to the same rights as the specification, +sufficiently detailed to allow any third party reasonably skilled in the +technology to produce implementations of the Extension compatible with +the specification. Such test suites must be made available as soon as +reasonably practicable but, in no event, later than ninety (90) days +after Your first Commercial Use of the Extension. You must use +reasonable efforts to promptly clarify and correct the specification and +the test suite upon written request by Original Contributor. + +(iii) Open. You agree to refrain from enforcing any Intellectual +Property Rights You may have covering any interface(s) of Your +Extension, which would prevent the implementation of such interface(s) +by Original Contributor or any Licensee. This obligation does not +prevent You from enforcing any Intellectual Property Right You have that +would otherwise be infringed by an implementation of Your Extension. + +(iv) Interface Modifications and Naming. You may not modify or add to +the GUID space * * "xxxxxxxx-0901-11d1-8B06-00A024406D59" or any other +GUID space designated by Original Contributor. You may not modify any +Interface prefix provided with the Covered Code or any other prefix +designated by Original Contributor.* * + +* * + +(f) You agree that any Specifications provided to You by Original +Contributor are confidential and proprietary information of Original +Contributor. You must maintain the confidentiality of the Specifications +and may not disclose them to any third party without Original +Contributor's prior written consent. You may only use the Specifications +under the terms of this License and only for the purpose of implementing +the terms of this License with respect to Covered Code. You agree not +use, copy or distribute any such Specifications except as provided in +writing by Original Contributor. + +3.2 Commercial Use License. + +You may not make Commercial Use of any Covered Code unless You and +Original Contributor have executed a copy of the Commercial Use and +Trademark License attached as Attachment D. + +*4. Versions of the License.* + +4.1 License Versions. + +Original Contributor may publish revised versions of the License from +time to time. Each version will be given a distinguishing version number. + +4.2 Effect. + +Once a particular version of Covered Code has been provided under a +version of the License, You may always continue to use such Covered Code +under the terms of that version of the License. You may also choose to +use such Covered Code under the terms of any subsequent version of the +License. No one other than Original Contributor has the right to +promulgate License versions. + +4.3 Multiple-Licensed Code. + +Original Contributor may designate portions of the Covered Code as +"Multiple-Licensed." "Multiple-Licensed" means that the Original +Contributor permits You to utilize those designated portions of the +Covered Code under Your choice of this License or the alternative +license(s), if any, specified by the Original Contributor in an +Attachment to this License. + +*5. Disclaimer of Warranty.* + +5.1 COVERED CODE PROVIDED AS IS. + +COVERED CODE IS PROVIDED UNDER THIS LICENSE "AS IS," WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, +WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT +FOR A PARTICULAR PURPOSE OR NON-INFRINGING. YOU AGREE TO BEAR THE ENTIRE +RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF COVERED CODE UNDER +THIS LICENSE. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART +OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER +EXCEPT SUBJECT TO THIS DISCLAIMER. + +5.2 Not Designed for High Risk Activities. + +You acknowledge that Original Code, Upgraded Code and Specifications are +not designed or intended for use in high risk activities including, but +not limited to: (i) on-line control of aircraft, air traffic, aircraft +navigation or aircraft communications; or (ii) in the design, +construction, operation or maintenance of any nuclear facility. Original +Contributor disclaims any express or implied warranty of fitness for +such uses. + +*6. Termination.* + +6.1 By You. + +You may terminate this Research Use license at anytime by providing +written notice to Original Contributor. + +6.2 By Original Contributor. + +This License and the rights granted hereunder will terminate: + +(i) automatically if You fail to comply with the terms of this License +and fail to cure such breach within 30 days of receipt of written notice +of the breach; + +(ii) immediately in the event of circumstances specified in Sections 7.1 +and 8.4; or + +(iii) at Original Contributor's discretion upon any action initiated by +You (including by cross-claim or counter claim) alleging that use or +distribution by Original Contributor or any Licensee, of Original Code, +Upgraded Code, Error Corrections, Shared Modifications or Specifications +infringe a patent owned or controlled by You. + +6.3 Effective of Termination. + +Upon termination, You agree to discontinue use of and destroy all copies +of Covered Code in Your possession. All sublicenses to the Covered Code +which You have properly granted shall survive any termination of this +License. Provisions that, by their nature, should remain in effect +beyond the termination of this License shall survive including, without +limitation, Sections 2.2, 3, 5, 7 and 8. + +6.4 No Compensation. + +Each party waives and releases the other from any claim to compensation +or indemnity for permitted or lawful termination of the business +relationship established by this License. + +*7. Liability.* + +7.1 Infringement. Should any of the Original Code, Upgraded Code, TCK or +Specifications ("Materials") become the subject of a claim of +infringement, Original Contributor may, at its sole option, (i) attempt +to procure the rights necessary for You to continue using the Materials, +(ii) modify the Materials so that they are no longer infringing, or +(iii) terminate Your right to use the Materials, immediately upon +written notice, and refund to You the amount, if any, having then +actually been paid by You to Original Contributor for the Original Code, +Upgraded Code and TCK, depreciated on a straight line, five year basis. + +7.2 LIMITATION OF LIABILITY. TO THE FULL EXTENT ALLOWED BY APPLICABLE +LAW, ORIGINAL CONTRIBUTOR'S LIABILITY TO YOU FOR CLAIMS RELATING TO THIS +LICENSE, WHETHER FOR BREACH OR IN TORT, SHALL BE LIMITED TO ONE HUNDRED +PERCENT (100%) OF THE AMOUNT HAVING THEN ACTUALLY BEEN PAID BY YOU TO +ORIGINAL CONTRIBUTOR FOR ALL COPIES LICENSED HEREUNDER OF THE PARTICULAR +ITEMS GIVING RISE TO SUCH CLAIM, IF ANY, DURING THE TWELVE MONTHS +PRECEDING THE CLAIMED BREACH. IN NO EVENT WILL YOU (RELATIVE TO YOUR +SHARED MODIFICATIONS OR ERROR CORRECTIONS) OR ORIGINAL CONTRIBUTOR BE +LIABLE FOR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES IN CONNECTION WITH OR RISING OUT OF THIS LICENSE (INCLUDING, +WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR OTHER ECONOMIC +ADVANTAGE), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY, WHETHER IN +AN ACTION FOR CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE) +OR OTHERWISE, WHETHER OR NOT YOU OR ORIGINAL CONTRIBUTOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE AND NOTWITHSTANDING THE +FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. + +*8. Miscellaneous.* + +8.1 Trademark. + +You shall not use any Trademark unless You and Original Contributor +execute a copy of the Commercial Use and Trademark License Agreement +attached hereto as Attachment D. Except as expressly provided in the +License, You are granted no right, title or license to, or interest in, +any Trademarks. Whether or not You and Original Contributor enter into +the Trademark License, You agree not to (i) challenge Original +Contributor's ownership or use of Trademarks; (ii) attempt to register +any Trademarks, or any mark or logo substantially similar thereto; or +(iii) incorporate any Trademarks into Your own trademarks, product +names, service marks, company names, or domain names. + +8.2 Integration. + +This License represents the complete agreement concerning the subject +matter hereof. + +8.3 Assignment. + +Original Contributor may assign this License, and its rights and +obligations hereunder, in its sole discretion. You may assign the +Research Use portions of this License and the TCK license to a third +party upon prior written notice to Original Contributor (which may be +provided electronically via the Community Web-Server). You may not +assign the Commercial Use and Trademark license, the Add-On Technology +License, or the Add-On Technology Source Code Porting License, including +by way of merger (regardless of whether You are the surviving entity) or +acquisition, without Original Contributor's prior written consent. + +8.4 Severability. + +If any provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to make it +enforceable. Notwithstanding the foregoing, if You are prohibited by law +from fully and specifically complying with Sections 2.2 or 3, this +License will immediately terminate and You must immediately discontinue +any use of Covered Code. + +8.5 Governing Law. + +This License shall be governed by the laws of the United States and the +State of Washington, as applied to contracts entered into and to be +performed in Washington between Washington residents. The application of +the United Nations Convention on Contracts for the International Sale of +Goods is expressly excluded. You agree that the state and federal courts +located in Seattle, Washington have exclusive jurisdiction over any +claim relating to the License, including contract and tort claims. + +8.6 Dispute Resolution. + +a) Arbitration. Any dispute arising out of or relating to this License +shall be finally settled by arbitration as set out herein, except that +either party may bring any action, in a court of competent jurisdiction +(which jurisdiction shall be exclusive), with respect to any dispute +relating to such party's Intellectual Property Rights or with respect to +Your compliance with the TCK license. Arbitration shall be administered: +(i) by the American Arbitration Association (AAA), (ii) in accordance +with the rules of the United Nations Commission on International Trade +Law (UNCITRAL) (the "Rules") in effect at the time of arbitration as +modified herein; and (iii) the arbitrator will apply the substantive +laws of Washington and the United States. Judgment upon the award +rendered by the arbitrator may be entered in any court having +jurisdiction to enforce such award. + +b) Arbitration language, venue and damages. All arbitration proceedings +shall be conducted in English by a single arbitrator selected in +accordance with the Rules, who must be fluent in English and be either a +retired judge or practicing attorney having at least ten (10) years +litigation experience and be reasonably familiar with the technology +matters relative to the dispute. Unless otherwise agreed, arbitration +venue shall be in Seattle, Washington. The arbitrator may award monetary +damages only and nothing shall preclude either party from seeking +provisional or emergency relief from a court of competent jurisdiction. +The arbitrator shall have no authority to award damages in excess of +those permitted in this License and any such award in excess is void. +All awards will be payable in U.S. dollars and may include, for the +prevailing party (i) pre-judgment award interest, (ii) reasonable +attorneys' fees incurred in connection with the arbitration, and (iii) +reasonable costs and expenses incurred in enforcing the award. The +arbitrator will order each party to produce identified documents and +respond to no more than twenty-five single question interrogatories. + +8.7 Construction. + +Any law or regulation, which provides that the language of a contract +shall be construed against the drafter, shall not apply to this License. + +8.8 U.S. Government End Users. + +The Covered Code is a "commercial item," as that term is defined in 48 +C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" +and "commercial computer software documentation," as such terms are used +in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and +48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government +End Users acquire Covered Code with only those rights set forth herein. +You agree to pass this notice to our licensees. + +8.9 Marketing Activities. + +Licensee hereby grants Original Contributor a non-exclusive, +non-transferable, limited license to use the Licensee's company name and +logo ("Licensee Marks") in any presentations, press releases, or +marketing materials solely for the purpose of identifying Licensee as a +member of the Helix Community. Licensee shall provide samples of +Licensee Marks to Original Contributor upon request by Original +Contributor. Original Contributor acknowledges that the Licensee Marks +are the trademarks of Licensee. Original Contributor shall not use the +Licensee Marks in a way that may imply that Original Contributor is an +agency or branch of Licensee. Original Contributor understands and +agrees that the use of any Licensee Marks in connection with this +Agreement shall not create any right, title or interest, in, or to the +Licensee Marks or any Licensee trademarks and that all such use and +goodwill associated with any such trademarks will inure to the benefit +of Licensee. Further the Original Contributor will stop usage of the +Licensee Marks upon Licensee's request. + +8.10 Press Announcements. + +You may make press announcements or other public statements regarding +this License without the prior written consent of the Original +Contributor, if Your statement is limited to announcing the licensing of +the Covered Code or the availability of Your Product and its +compatibility with the Covered Code. All other public announcements +regarding this license require the prior written consent of the Original +Contributor. Consent requests are welcome at press@helixcommunity.org. + +8.11 International Use. + +a) Export/Import laws. Covered Code is subject to U.S. export control +laws and may be subject to export or import regulations in other +countries. Each party agrees to comply strictly with all such laws and +regulations and acknowledges their responsibility to obtain such +licenses to export, re-export, or import as may be required. You agree +to pass these obligations to Your licensees. + +b) Intellectual Property Protection. Due to limited intellectual +property protection and enforcement in certain countries, You agree not +to redistribute the Original Code, Upgraded Code, TCK and Specifications +to any country on the list of restricted countries on the Community Web +Server. + +8.12 Language. + +This License is in the English language only, which language shall be +controlling in all respects, and all versions of this License in any +other language shall be for accommodation only and shall not be binding +on the parties to this License. All communications and notices made or +given pursuant to this License, and all documentation and support to be +provided, unless otherwise noted, shall be in the English language. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH REALNETWORKS, INC. IF YOU ARE AGREEING +TO THIS LICENSE ON BEHALF OF A COMPANY, YOU REPRESENT THAT YOU ARE +AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. WHETHER YOU ARE ACTING +ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, YOU MUST BE OF MAJORITY +AGE AND BE OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. IF YOU DO NOT +MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY OF THE TERMS AND +CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON TO EXIT. + + + GLOSSARY + +1. *"Added Value"* means code which: + +(i) has a principal purpose which is substantially different from that +of the stand-alone Technology; + +(ii) represents a significant functional and value enhancement to the +Technology; + +(iii) operates in conjunction with the Technology; and + +(iv) is not marketed as a technology which replaces or substitutes for +the Technology + +2. "*Applicable Patent Rights*" mean: (a) in the case where Original +Contributor is the grantor of rights, claims of patents that (i) are now +or hereafter acquired, owned by or assigned to Original Contributor and +(ii) are necessarily infringed by using or making the Original Code or +Upgraded Code, including Modifications provided by Original Contributor, +alone and not in combination with other software or hardware; and (b) in +the case where Licensee is the grantor of rights, claims of patents that +(i) are now or hereafter acquired, owned by or assigned to Licensee and +(ii) are infringed (directly or indirectly) by using or making +Licensee's Modifications or Error Corrections, taken alone or in +combination with Covered Code. + +3. "*Application Programming Interfaces (APIs)"* means the interfaces, +associated header files, service provider interfaces, and protocols that +enable a device, application, Operating System, or other program to +obtain services from or make requests of (or provide services in +response to requests from) other programs, and to use, benefit from, or +rely on the resources, facilities, and capabilities of the relevant +programs using the APIs. APIs includes the technical documentation +describing the APIs, the Source Code constituting the API, and any +Header Files used with the APIs. + +4. "*Commercial Use*" means any use (internal or external), copying, +sublicensing or distribution (internal or external), directly or +indirectly of Covered Code by You other than Your Research Use of +Covered Code within Your business or organization or in conjunction with +other Licensees with equivalent Research Use rights. Commercial Use +includes any use of the Covered Code for direct or indirect commercial +or strategic gain, advantage or other business purpose. Any Commercial +Use requires execution of Attachment D by You and Original Contributor. + +5. "*Community Code*" means the Original Code, Upgraded Code, Error +Corrections, Shared Modifications, or any combination thereof. + +6. "*Community Webserver(s)"* means the webservers designated by +Original Contributor for access to the Original Code, Upgraded Code, TCK +and Specifications and for posting Error Corrections and Shared +Modifications. + +7. "*Compliant Covered Code*" means Covered Code that complies with the +requirements of the TCK. + +8. "*Contributor*" means each Licensee that creates or contributes to +the creation of any Error Correction or Shared Modification. + +9. "*Covered Code*" means the Original Code, Upgraded Code, +Modifications, or any combination thereof. + +10. "*Error Correction*" means any change made to Community Code which +conforms to the Specification and corrects the adverse effect of a +failure of Community Code to perform any function set forth in or +required by the Specifications. + +11. "*Executable*" means Covered Code that has been converted from +Source Code to the preferred form for execution by a computer or digital +processor (e.g. binary form). + +12. "*Extension(s)"* means any additional Interfaces developed by or for +You which: (i) are designed for use with the Technology; (ii) constitute +an API for a library of computing functions or services; and (iii) are +disclosed or otherwise made available to third party software developers +for the purpose of developing software which invokes such additional +Interfaces. The foregoing shall not apply to software developed by Your +subcontractors to be exclusively used by You. + +13. "*Header File(s)"* means that portion of the Source Code that +provides the names and types of member functions, data members, class +definitions, and interface definitions necessary to implement the APIs +for the Covered Code. Header Files include, files specifically +designated by Original Contributor as Header Files. Header Files do not +include the code necessary to implement the functionality underlying the +Interface. + +14. *"Helix DNA Server Technology"* means the program(s) that implement +the Helix Universal Server streaming engine for the Technology as +defined in the Specification. + +15. *"Helix DNA Client Technology"* means the Covered Code that +implements the RealOne Player engine as defined in the Specification. + +16. *"Helix DNA Producer Technology"* means the Covered Code that +implements the Helix Producer engine as defined in the Specification. + +17. *"Helix DNA Technology"* means the Helix DNA Server Technology, the +Helix DNA Client Technology, the Helix DNA Producer Technology and other +Helix technologies designated by Original Contributor. + +18. "*Intellectual Property Rights*" means worldwide statutory and +common law rights associated solely with (i) Applicable Patent Rights; +(ii) works of authorship including copyrights, copyright applications, +copyright registrations and "moral rights"; (iii) the protection of +trade and industrial secrets and confidential information; and (iv) +divisions, continuations, renewals, and re-issuances of the foregoing +now existing or acquired in the future. + +19. *"Interface*" means interfaces, functions, properties, class +definitions, APIs, Header Files, GUIDs, V-Tables, and/or protocols +allowing one piece of software, firmware or hardware to communicate or +interoperate with another piece of software, firmware or hardware. + +20. "*Internal Deployment Use*" means use of Compliant Covered Code +(excluding Research Use) within Your business or organization only by +Your employees and/or agents on behalf of Your business or organization, +but not to provide services, including content distribution, to third +parties, subject to execution of Attachment D by You and Original +Contributor, if required. + +21. "*Licensee*" means any party that has entered into and has in effect +a version of this License with Original Contributor. + +22. "*MIME type*" means a description of what type of media or other +content is in a file, including by way of example but not limited to +'audio/x-pn-realaudio-plugin.' + +23. "*Modification(s)"* means (i) any addition to, deletion from and/or +change to the substance and/or structure of the Covered Code, including +Interfaces; (ii) the combination of any Covered Code and any previous +Modifications; (iii) any new file or other representation of computer +program statements that contains any portion of Covered Code; and/or +(iv) any new Source Code implementing any portion of the Specifications. + +24. "*MP3 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Picture Experts Group known as MPEG-1 Audio Layer-3 or MP3, +including but not limited to all past and future versions, profiles, +extensions, parts and amendments relating to the MP3 specification. + +25. "*MPEG-4 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Pictures Experts Group known as MPEG-4, including but not +limited to all past and future versions, profiles, extensions, parts and +amendments relating to the MPEG-4 specification. + +26. "*Original Code*" means the initial Source Code for the Technology +as described on the Community Web Server. + +27. "*Original Contributor*" means RealNetworks, Inc., its affiliates +and its successors and assigns. + +28. "*Original Contributor MIME Type*" means the MIME registry, browser +preferences, or local file/protocol associations invoking any Helix DNA +Client-based application, including the RealOne Player, for playback of +RealAudio, RealVideo, other RealMedia MIME types or datatypes (e.g., +.ram, .rnx, .rpm, .ra, .rm, .rp, .rt, .rf, .prx, .mpe, .rmp, .rmj, .rav, +.rjs, .rmx, .rjt, .rms), and any other Original Contributor-specific or +proprietary MIME types that Original Contributor may introduce in the +future. + +29. "*Personal Use*" means use of Covered Code by an individual solely +for his or her personal, private and non-commercial purposes. An +individual's use of Covered Code in his or her capacity as an officer, +employee, member, independent contractor or agent of a corporation, +business or organization (commercial or non-commercial) does not qualify +as Personal Use. + +30. "*RealMedia File Format*" means the file format designed and +developed by RealNetworks for storing multimedia data and used to store +RealAudio and RealVideo encoded streams. Valid RealMedia File Format +extensions include: .rm, .rmj, .rmc, .rmvb, .rms. + +31. "*RCSL Webpage*" means the RealNetworks Community Source License +webpage located at https://www.helixcommunity.org/content/rcsl or such +other URL that Original Contributor may designate from time to time. + +32. "*Reformatted Specifications*" means any revision to the +Specifications which translates or reformats the Specifications (as for +example in connection with Your documentation) but which does not alter, +subset or superset * *the functional or operational aspects of the +Specifications. + +33. "*Research Use*" means use and distribution of Covered Code only for +Your Personal Use, research or development use and expressly excludes +Internal Deployment Use and Commercial Use. Research Use also includes +use of Covered Code to teach individuals how to use Covered Code. + +34. "*Shared Modifications*" means Modifications that You distribute or +use for a Commercial Use, in addition to any Modifications provided by +You, at Your option, pursuant to Section 2.2, or received by You from a +Contributor pursuant to Section 2.3. + +35. "*Source Code*" means the preferred form of the Covered Code for +making modifications to it, including all modules it contains, plus any +associated interface definition files, scripts used to control +compilation and installation of an Executable, or source code +differential comparisons against either the Original Code or another +well known, available Covered Code of the Contributor's choice. The +Source Code can be in a compressed or archival form, provided the +appropriate decompression or de-archiving software is widely available +for no charge. + +36. "*Specifications*" means the specifications for the Technology and +other documentation, as designated on the Community Web Server, as may +be revised by Original Contributor from time to time. + +37. "*Trademarks*" means Original Contributor's trademarks and logos, +including, but not limited to, RealNetworks, RealAudio, RealVideo, +RealOne, RealSystem, SureStream, Helix, Helix DNA and other trademarks +whether now used or adopted in the future. + +38. "*Technology*" means the technology described in Attachment B, and +Upgrades. + +39. "*Technology Compatibility Kit"* or *"TCK*" means the test programs, +procedures, acceptance criteria and/or other requirements, designated by +Original Contributor for use in verifying compliance of Covered Code +with the Specifications, in conjunction with the Original Code and +Upgraded Code. Original Contributor may, in its sole discretion and from +time to time, revise a TCK to correct errors and/or omissions and in +connection with Upgrades. + +40. "*Upgrade(s)"* means new versions of Technology designated +exclusively by Original Contributor as an "Upgrade" and released by +Original Contributor from time to time under the terms of the License. + +41. "*Upgraded Code*" means the Source Code and/or Executables for +Upgrades, possibly including Modifications made by Contributors. + +42. *"User's Guide"* means the users guide for the TCK which Original +Contributor makes available to You to provide direction in how to run +the TCK and properly interpret the results, as may be revised by +Original Contributor from time to time. + +43. "*You(r)*" means an individual, or a legal entity acting by and +through an individual or individuals, exercising rights either under +this License or under a future version of this License issued pursuant +to Section 4.1. For legal entities, "You(r)" includes any entity that by +majority voting interest controls, is controlled by, or is under common +control with You. + +44. "*Your Products*" means any (i) hardware products You distribute +integrating the Covered Code; (ii) any software products You distribute +with the Covered Code that utilize the APIs of the Covered Code; or +(iii) any services You provide using the Covered Code. + + + ATTACHMENT A + +REQUIRED NOTICES + + + ATTACHMENT A-1 + +REQUIRED IN ALL CASES + +Notice to be included in header file of all Error Corrections and Shared +Modifications: + +Portions Copyright 1994-2003 RealNetworks, Inc. All rights reserved. + +The contents of this file, and the files included with this file, are +subject to the current version of RealNetworks Community Source License +Version 1.1 (the "License"). You may not use this file except in +compliance with the License executed by both You and RealNetworks. You +may obtain a copy of the License at * +https://www.helixcommunity.org/content/rcsl.* You may also obtain a copy +of the License by contacting RealNetworks directly. Please see the +License for the rights, obligations and limitations governing use of the +contents of the file. + +This file is part of the Helix DNA technology. RealNetworks, Inc., is +the developer of the Original code and owns the copyrights in the +portions it created. + +This file, and the files included with this file, are distributed on an +'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, +AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): + +_______________________________________________ + +Technology Compatibility Kit Test Suite(s) Location: + +________________________________ + + + ATTACHMENT A-2 + +SAMPLE LICENSEE CERTIFICATION + +"By clicking the `Agree' button below, You certify that You are a +Licensee in good standing under the RealNetworks Community Source +License, ("License") and that Your access, use and distribution of code +and information You may obtain at this site is subject to the License. +If You are not a Licensee under the RealNetworks Community Source +License You agree not to download, copy or use the Helix DNA technology. + + + ATTACHMENT A-3 + +REQUIRED STUDENT NOTIFICATION + +"This software and related documentation has been obtained by Your +educational institution subject to the RealNetworks Community Source +License. You have been provided access to the software and related +documentation for use only in connection with your course work and +research activities as a matriculated student of Your educational +institution. Any other use is expressly prohibited. + +THIS SOFTWARE AND RELATED DOCUMENTATION CONTAINS PROPRIETARY MATERIAL OF +REALNETWORKS, INC, WHICH ARE PROTECTED BY VARIOUS INTELLECTUAL PROPERTY +RIGHTS. + +You may not use this file except in compliance with the License. You may +obtain a copy of the License on the web at +https://www.helixcommunity.org/content/rcsl. + +* +* + + + ATTACHMENT B + +Description of Technology + +Helix DNA, which consists of Helix DNA Client, Helix DNA Server and +Helix DNA Producer. + +Description of "Technology" + +Helix DNA Technology v1.0 as described on the Community Web Server. + + + ATTACHMENT C + +TECHNOLOGY COMPATIBILITY KIT LICENSE + +The following license is effective for the *Helix DNA* Technology +Compatibility Kit - as described on the Community Web Server. The +Technology Compatibility Kit(s) for the Technology specified in +Attachment B may be accessed at the Community Web Server. + +1. TCK License. + +1.1 Grants to use TCK + +Subject to the terms and restrictions set forth below and the +RealNetworks Community Source License, and the Research Use license, +Original Contributor grants to You a worldwide, non-exclusive, +non-transferable license, to the extent of Original Contributor's +Intellectual Property Rights in the TCK (without the right to +sublicense), to use the TCK to develop and test Covered Code. + +1.2 TCK Use Restrictions. + +You are not authorized to create derivative works of the TCK or use the +TCK to test any implementation of the Specification that is not Covered +Code. You may not publish Your test results or make claims of +comparative compatibility with respect to other implementations of the +Specification. In consideration for the license grant in Section 1.1 +above You agree not to develop Your own tests that are intended to +validate conformation with the Specification. + +2. Test Results. + +You agree to provide to Original Contributor or the third party test +facility if applicable, Your test results that demonstrate that Covered +Code is Compliant Covered Code and that Original Contributor may publish +or otherwise distribute such test results. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH THE ORIGINAL CONTRIBUTOR, REALNETWORKS, +INC. IF YOU ARE AGREEING TO THIS LICENSE ON BEHALF OF A COMPANY, YOU +REPRESENT THAT YOU ARE AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. +WHETHER YOU ARE ACTING ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, +YOU MUST BE OF MAJORITY AGE AND BE OTHERWISE COMPETENT TO ENTER INTO +CONTRACTS. IF YOU DO NOT MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY +OF THE TERMS AND CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON +TO EXIT. + +*ACCEPT / REJECT +* + +* +* + +*To agree to the R&D/academic terms of this license, please register + on the site -- +you will then be given a chance to agree to the clickwrap RCSL + +R&D License + +and gain access to the RCSL-licensed source code. To build or deploy +commercial applications based on the RCSL, you will need to agree to the +Commercial Use license attachments +* + + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/RPSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/RPSL.txt new file mode 100644 index 0000000..d040a45 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/RPSL.txt @@ -0,0 +1,518 @@ +RealNetworks Public Source License Version 1.0 +(Rev. Date October 28, 2002) + +1. General Definitions. This License applies to any program or other work which +RealNetworks, Inc., or any other entity that elects to use this license, +("Licensor") makes publicly available and which contains a notice placed by +Licensor identifying such program or work as "Original Code" and stating that it +is subject to the terms of this RealNetworks Public Source License version 1.0 +(or subsequent version thereof) ("License"). You are not required to accept this +License. However, nothing else grants You permission to use, copy, modify or +distribute the software or its derivative works. These actions are prohibited by +law if You do not accept this License. Therefore, by modifying, copying or +distributing the software (or any work based on the software), You indicate your +acceptance of this License to do so, and all its terms and conditions. In +addition, you agree to the terms of this License by clicking the Accept button +or downloading the software. As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Licensor is the +grantor of rights, claims of patents that (i) are now or hereafter acquired, +owned by or assigned to Licensor and (ii) are necessarily infringed by using or +making the Original Code alone and not in combination with other software or +hardware; and (b) in the case where You are the grantor of rights, claims of +patents that (i) are now or hereafter acquired, owned by or assigned to You and +(ii) are infringed (directly or indirectly) by using or making Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Compatible Source License" means any one of the licenses listed on Exhibit +B or at https://www.helixcommunity.org/content/complicense or other licenses +specifically identified by Licensor in writing. Notwithstanding any term to the +contrary in any Compatible Source License, any code covered by any Compatible +Source License that is used with Covered Code must be made readily available in +Source Code format for royalty-free use under the terms of the Compatible Source +License or this License. + +1.3 "Contributor" means any person or entity that creates or contributes to the +creation of Modifications. + +1.4 "Covered Code" means the Original Code, Modifications, the combination of +Original Code and any Modifications, and/or any respective portions thereof. + +1.5 "Deploy" means to use, sublicense or distribute Covered Code other than for +Your internal research and development (R&D) and/or Personal Use, and includes +without limitation, any and all internal use or distribution of Covered Code +within Your business or organization except for R&D use and/or Personal Use, as +well as direct or indirect sublicensing or distribution of Covered Code by You +to any third party in any form or manner. + +1.6 "Derivative Work" means either the Covered Code or any derivative work under +United States copyright law, and including any work containing or including any +portion of the Covered Code or Modifications, either verbatim or with +modifications and/or translated into another language. Derivative Work also +includes any work which combines any portion of Covered Code or Modifications +with code not otherwise governed by the terms of this License. + +1.7 "Externally Deploy" means to Deploy the Covered Code in any way that may be +accessed or used by anyone other than You, used to provide any services to +anyone other than You, or used in any way to deliver any content to anyone other +than You, whether the Covered Code is distributed to those parties, made +available as an application intended for use over a computer network, or used to +provide services or otherwise deliver content to anyone other than You. + +1.8. "Interface" means interfaces, functions, properties, class definitions, +APIs, header files, GUIDs, V-Tables, and/or protocols allowing one piece of +software, firmware or hardware to communicate or interoperate with another piece +of software, firmware or hardware. + +1.9 "Modifications" mean any addition to, deletion from, and/or change to, the +substance and/or structure of the Original Code, any previous Modifications, the +combination of Original Code and any previous Modifications, and/or any +respective portions thereof. When code is released as a series of files, a +Modification is: (a) any addition to or deletion from the contents of a file +containing Covered Code; and/or (b) any new file or other representation of +computer program statements that contains any part of Covered Code. + +1.10 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Licensor under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Licensor under this License, and that has been expressly identified by Licensor +as such in the header file(s) of such work; and (b) the object code compiled +from such Source Code and originally made available by Licensor under this +License. + +1.11 "Personal Use" means use of Covered Code by an individual solely for his or +her personal, private and non-commercial purposes. An individual's use of +Covered Code in his or her capacity as an officer, employee, member, independent +contractor or agent of a corporation, business or organization (commercial or +non-commercial) does not qualify as Personal Use. + +1.12 "Source Code" means the human readable form of a program or other work that +is suitable for making modifications to it, including all modules it contains, +plus any associated interface definition files, scripts used to control +compilation and installation of an executable (object code). + +1.13 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership of +fifty percent (50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Licensor hereby grants You, effective on the date +You accept this License (via downloading or using Covered Code or otherwise +indicating your acceptance of this License), a worldwide, royalty-free, +non-exclusive copyright license, to the extent of Licensor's copyrights cover +the Original Code, to do the following: + +2.1 You may reproduce, display, perform, modify and Deploy Covered Code, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the copyright +and other proprietary notices and disclaimers of Licensor as they appear in the +Original Code, and keep intact all notices in the Original Code that refer to +this License; + +(b) You must include a copy of this License with every copy of Source Code of +Covered Code and documentation You distribute, and You may not offer or impose +any terms on such Source Code that alter or restrict this License or the +recipients' rights hereunder, except as permitted under Section 6; + +(c) You must duplicate, to the extent it does not already exist, the notice in +Exhibit A in each file of the Source Code of all Your Modifications, and cause +the modified files to carry prominent notices stating that You changed the files +and the date of any change; + +(d) You must make Source Code of all Your Externally Deployed Modifications +publicly available under the terms of this License, including the license grants +set forth in Section 3 below, for as long as you Deploy the Covered Code or +twelve (12) months from the date of initial Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Deployed Modifications +electronically (e.g. download from a web site); and + +(e) if You Deploy Covered Code in object code, executable form only, You must +include a prominent notice, in the code itself as well as in related +documentation, stating that Source Code of the Covered Code is available under +the terms of this License with information on how and where to obtain such +Source Code. You must also include the Object Code Notice set forth in Exhibit A +in the "about" box or other appropriate place where other copyright notices are +placed, including any packaging materials. + +2.2 You expressly acknowledge and agree that although Licensor and each +Contributor grants the licenses to their respective portions of the Covered Code +set forth herein, no assurances are provided by Licensor or any Contributor that +the Covered Code does not infringe the patent or other intellectual property +rights of any other entity. Licensor and each Contributor disclaim any liability +to You for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, You hereby assume sole responsibility to +secure any other intellectual property rights needed, if any. For example, if a +third party patent license is required to allow You to make, use, sell, import +or offer for sale the Covered Code, it is Your responsibility to acquire such +license(s). + +2.3 Subject to the terms and conditions of this License, Licensor hereby grants +You, effective on the date You accept this License (via downloading or using +Covered Code or otherwise indicating your acceptance of this License), a +worldwide, royalty-free, perpetual, non-exclusive patent license under +Licensor's Applicable Patent Rights to make, use, sell, offer for sale and +import the Covered Code, provided that in each instance you comply with the +terms of this License. + +3. Your Grants. In consideration of, and as a condition to, the licenses granted +to You under this License: + +(a) You grant to Licensor and all third parties a non-exclusive, perpetual, +irrevocable, royalty free license under Your Applicable Patent Rights and other +intellectual property rights owned or controlled by You, to make, sell, offer +for sale, use, import, reproduce, display, perform, modify, distribute and +Deploy Your Modifications of the same scope and extent as Licensor's licenses +under Sections 2.1 and 2.2; and + +(b) You grant to Licensor and its subsidiaries a non-exclusive, worldwide, +royalty-free, perpetual and irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights owned or controlled by You, to +make, use, sell, offer for sale, import, reproduce, display, perform, +distribute, modify or have modified (for Licensor and/or its subsidiaries), +sublicense and distribute Your Modifications, in any form and for any purpose, +through multiple tiers of distribution. + +(c) You agree not use any information derived from Your use and review of the +Covered Code, including but not limited to any algorithms or inventions that may +be contained in the Covered Code, for the purpose of asserting any of Your +patent rights, or assisting a third party to assert any of its patent rights, +against Licensor or any Contributor. + +4. Derivative Works. You may create a Derivative Work by combining Covered Code +with other code not otherwise governed by the terms of this License and +distribute the Derivative Work as an integrated product. In each such instance, +You must make sure the requirements of this License are fulfilled for the +Covered Code or any portion thereof, including all Modifications. + +4.1 You must cause any Derivative Work that you distribute, publish or +Externally Deploy, that in whole or in part contains or is derived from the +Covered Code or any part thereof, to be licensed as a whole at no charge to all +third parties under the terms of this License and no other license except as +provided in Section 4.2. You also must make Source Code available for the +Derivative Work under the same terms as Modifications, described in Sections 2 +and 3, above. + +4.2 Compatible Source Licenses. Software modules that have been independently +developed without any use of Covered Code and which contain no portion of the +Covered Code, Modifications or other Derivative Works, but are used or combined +in any way wtih the Covered Code or any Derivative Work to form a larger +Derivative Work, are exempt from the conditions described in Section 4.1 but +only to the extent that: the software module, including any software that is +linked to, integrated with, or part of the same applications as, the software +module by any method must be wholly subject to one of the Compatible Source +Licenses. Notwithstanding the foregoing, all Covered Code must be subject to the +terms of this License. Thus, the entire Derivative Work must be licensed under a +combination of the RPSL (for Covered Code) and a Compatible Source License for +any independently developed software modules within the Derivative Work. The +foregoing requirement applies even if the Compatible Source License would +ordinarily allow the software module to link with, or form larger works with, +other software that is not subject to the Compatible Source License. For +example, although the Mozilla Public License v1.1 allows Mozilla code to be +combined with proprietary software that is not subject to the MPL, if +MPL-licensed code is used with Covered Code the MPL-licensed code could not be +combined or linked with any code not governed by the MPL. The general intent of +this section 4.2 is to enable use of Covered Code with applications that are +wholly subject to an acceptable open source license. You are responsible for +determining whether your use of software with Covered Code is allowed under Your +license to such software. + +4.3 Mere aggregation of another work not based on the Covered Code with the +Covered Code (or with a work based on the Covered Code) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. If You deliver the Covered Code for combination and/or integration with +an application previously provided by You (for example, via automatic updating +technology), such combination and/or integration constitutes a Derivative Work +subject to the terms of this License. + +5. Exclusions From License Grant. Nothing in this License shall be deemed to +grant any rights to trademarks, copyrights, patents, trade secrets or any other +intellectual property of Licensor or any Contributor except as expressly stated +herein. No right is granted to the trademarks of Licensor or any Contributor +even if such marks are included in the Covered Code. Nothing in this License +shall be interpreted to prohibit Licensor from licensing under different terms +from this License any code that Licensor otherwise would have a right to +license. Modifications, Derivative Works and/or any use or combination of +Covered Code with other technology provided by Licensor or third parties may +require additional patent licenses from Licensor which Licensor may grant in its +sole discretion. No patent license is granted separate from the Original Code or +combinations of the Original Code with other software or hardware. + +5.1. Trademarks. This License does not grant any rights to use the trademarks or +trade names owned by Licensor ("Licensor Marks" defined in Exhibit C) or to any +trademark or trade name belonging to any Contributor. No Licensor Marks may be +used to endorse or promote products derived from the Original Code other than as +permitted by the Licensor Trademark Policy defined in Exhibit C. + +6. Additional Terms. You may choose to offer, and to charge a fee for, warranty, +support, indemnity or liability obligations and/or other rights consistent with +the scope of the license granted herein ("Additional Terms") to one or more +recipients of Covered Code. However, You may do so only on Your own behalf and +as Your sole responsibility, and not on behalf of Licensor or any Contributor. +You must obtain the recipient's agreement that any such Additional Terms are +offered by You alone, and You hereby agree to indemnify, defend and hold +Licensor and every Contributor harmless for any liability incurred by or claims +asserted against Licensor or such Contributor by reason of any such Additional +Terms. + +7. Versions of the License. Licensor may publish revised and/or new versions of +this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular version +of this License, You may continue to use it under the terms of that version. You +may also choose to use such Original Code under the terms of any subsequent +version of this License published by Licensor. No one other than Licensor has +the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in part +pre-release, untested, or not fully tested works. The Covered Code may contain +errors that could cause failures or loss of data, and may be incomplete or +contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND LICENSOR AND LICENSOR'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS +"LICENSOR" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY +DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET +ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. LICENSOR AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN DOCUMENTATION, INFORMATION OR ADVICE GIVEN BY LICENSOR, A LICENSOR +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You +acknowledge that the Covered Code is not intended for use in high risk +activities, including, but not limited to, the design, construction, operation +or maintenance of nuclear facilities, aircraft navigation, aircraft +communication systems, or air traffic control machines in which case the failure +of the Covered Code could lead to death, personal injury, or severe physical or +environmental damage. Licensor disclaims any express or implied warranty of +fitness for such uses. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT +SHALL LICENSOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR STRICT +LIABILITY), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF LICENSOR OR SUCH +CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND +NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. SOME +JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF INCIDENTAL OR +CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event +shall Licensor's total liability to You for all damages (other than as may be +required by applicable law) under this License exceed the amount of ten dollars +($10.00). + +10. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Licensor retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Licensor +("Licensor Modifications"), and such Licensor Modifications will not be +automatically subject to this License. Licensor may, at its sole discretion, +choose to license such Licensor Modifications under this License, or on +different terms from those contained in this License or may choose not to +license them at all. + +11. Termination. + +11.1 Term and Termination. The term of this License is perpetual unless +terminated as provided below. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Licensor if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; + +(b) immediately in the event of the circumstances described in Section 12.5(b); +or + +(c) automatically without notice from Licensor if You, at any time during the +term of this License, commence an action for patent infringement against +Licensor (including by cross-claim or counter claim in a lawsuit); + +(d) upon written notice from Licensor if You, at any time during the term of +this License, commence an action for patent infringement against any third party +alleging that the Covered Code itself (excluding combinations with other +software or hardware) infringes any patent (including by cross-claim or counter +claim in a lawsuit). + +11.2 Effect of Termination. Upon termination, You agree to immediately stop any +further use, reproduction, modification, sublicensing and distribution of the +Covered Code and to destroy all copies of the Covered Code that are in your +possession or control. All sublicenses to the Covered Code which have been +properly granted prior to termination shall survive any termination of this +License. Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to Sections +3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other for +compensation, indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this License will +be without prejudice to any other right or remedy of any party. + +12. Miscellaneous. + +12.1 Government End Users. The Covered Code is a "commercial item" as defined in +FAR 2.101. Government software and technical data rights in the Covered Code +include only those rights customarily provided to the public as defined in this +License. This customary commercial license in technical data and software is +provided in accordance with FAR 12.211 (Technical Data) and 12.212 (Computer +Software) and, for Department of Defense purchases, DFAR 252.227-7015 (Technical +Data -- Commercial Items) and 227.7202-3 (Rights in Commercial Computer Software +or Computer Software Documentation). Accordingly, all U.S. Government End Users +acquire Covered Code with only those rights set forth herein. + +12.2 Relationship of Parties. This License will not be construed as creating an +agency, partnership, joint venture or any other form of legal association +between or among You, Licensor or any Contributor, and You will not represent to +the contrary, whether expressly, by implication, appearance or otherwise. + +12.3 Independent Development. Nothing in this License will impair Licensor's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions as, +or otherwise compete with, Modifications, Derivative Works, technology or +products that You may develop, produce, market or distribute. + +12.4 Waiver; Construction. Failure by Licensor or any Contributor to enforce any +provision of this License will not be deemed a waiver of future enforcement of +that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +12.5 Severability. (a) If for any reason a court of competent jurisdiction finds +any provision of this License, or portion thereof, to be unenforceable, that +provision of the License will be enforced to the maximum extent permissible so +as to effect the economic benefits and intent of the parties, and the remainder +of this License will continue in full force and effect. (b) Notwithstanding the +foregoing, if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the enforceability +of either of those Sections, this License will immediately terminate and You +must immediately discontinue any use of the Covered Code and destroy all copies +of it that are in your possession or control. + +12.6 Dispute Resolution. Any litigation or other dispute resolution between You +and Licensor relating to this License shall take place in the Seattle, +Washington, and You and Licensor hereby consent to the personal jurisdiction of, +and venue in, the state and federal courts within that District with respect to +this License. The application of the United Nations Convention on Contracts for +the International Sale of Goods is expressly excluded. + +12.7 Export/Import Laws. This software is subject to all export and import laws +and restrictions and regulations of the country in which you receive the Covered +Code and You are solely responsible for ensuring that You do not export, +re-export or import the Covered Code or any direct product thereof in violation +of any such restrictions, laws or regulations, or without all necessary +authorizations. + +12.8 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +Washington. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé +que le présent contrat et tous les documents connexes soient +rédigés en anglais. + + EXHIBIT A. + +"Copyright © 1995-2002 +RealNetworks, Inc. and/or its licensors. All Rights Reserved. + +The contents of this file, and the files included with this file, are subject to +the current version of the RealNetworks Public Source License Version 1.0 (the +"RPSL") available at https://www.helixcommunity.org/content/rpsl unless you have +licensed the file under the RealNetworks Community Source License Version 1.0 +(the "RCSL") available at https://www.helixcommunity.org/content/rcsl, in which +case the RCSL will apply. You may also obtain the license terms directly from +RealNetworks. You may not use this file except in compliance with the RPSL or, +if you have a valid RCSL with RealNetworks applicable to this file, the RCSL. +Please see the applicable RPSL or RCSL for the rights, obligations and +limitations governing use of the contents of the file. + +This file is part of the Helix DNA Technology. RealNetworks is the developer of +the Original code and owns the copyrights in the portions it created. + +This file, and the files included with this file, is distributed and made +available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR +IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING +WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): ____________________________________ + +Technology Compatibility Kit Test +Suite(s) Location (if licensed under the RCSL): ______________________________ + +Object Code Notice: Helix DNA Client technology included. Copyright (c) +RealNetworks, Inc., 1995-2002. All rights reserved. + + + EXHIBIT B + +Compatible Source Licenses for the RealNetworks Public Source License. The +following list applies to the most recent version of the license as of October +25, 2002, unless otherwise indicated. + +* Academic Free License +* Apache Software License +* Apple Public Source License +* Artistic license +* Attribution Assurance Licenses +* BSD license +* Common Public License (1) +* Eiffel Forum License +* GNU General Public License (GPL) (1) +* GNU Library or "Lesser" General Public License (LGPL) (1) +* IBM Public License +* Intel Open Source License +* Jabber Open Source License +* MIT license +* MITRE Collaborative Virtual Workspace License (CVW License) +* Motosoto License +* Mozilla Public License 1.0 (MPL) +* Mozilla Public License 1.1 (MPL) +* Nokia Open Source License +* Open Group Test Suite License +* Python Software Foundation License +* Ricoh Source Code Public License +* Sun Industry Standards Source License (SISSL) +* Sun Public License +* University of Illinois/NCSA Open Source License +* Vovida Software License v. 1.0 +* W3C License +* X.Net License +* Zope Public License +* zlib/libpng license + +(1) Note: because this license contains certain reciprocal licensing terms that +purport to extend to independently developed code, You may be prohibited under +the terms of this otherwise compatible license from using code licensed under +its terms with Covered Code because Covered Code may only be licensed under the +RealNetworks Public Source License. Any attempt to apply non RPSL license terms, +including without limitation the GPL, to Covered Code is expressly forbidden. +You are responsible for ensuring that Your use of Compatible Source Licensed +code does not violate either the RPSL or the Compatible Source License. + +The latest version of this list can be found at: +https://www.helixcommunity.org/content/complicense + + EXHIBIT C + +RealNetworks' Trademark policy. + +RealNetworks defines the following trademarks collectively as "Licensor +Trademarks": "RealNetworks", "RealPlayer", "RealJukebox", "RealSystem", +"RealAudio", "RealVideo", "RealOne Player", "RealMedia", "Helix" or any other +trademarks or trade names belonging to RealNetworks. + +RealNetworks "Licensor Trademark Policy" forbids any use of Licensor Trademarks +except as permitted by and in strict compliance at all times with RealNetworks' +third party trademark usage guidelines which are posted at +http://www.realnetworks.com/info/helixlogo.html. + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/LICENSE.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/LICENSE.txt new file mode 100644 index 0000000..12e5372 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/LICENSE.txt @@ -0,0 +1,30 @@ + Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. + + The contents of this directory, and (except where otherwise + indicated) the directories included within this directory, are + subject to the current version of the RealNetworks Public Source + License (the "RPSL") available at RPSL.txt in this directory, unless + you have licensed the directory under the current version of the + RealNetworks Community Source License (the "RCSL") available at + RCSL.txt in this directory, in which case the RCSL will apply. You + may also obtain the license terms directly from RealNetworks. You + may not use the files in this directory except in compliance with the + RPSL or, if you have a valid RCSL with RealNetworks applicable to + this directory, the RCSL. Please see the applicable RPSL or RCSL for + the rights, obligations and limitations governing use of the contents + of the directory. + + This directory is part of the Helix DNA Technology. RealNetworks is + the developer of the Original Code and owns the copyrights in the + portions it created. + + This directory, and the directories included with this directory, are + distributed and made available on an 'AS IS' basis, WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY + DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + QUIET ENJOYMENT OR NON-INFRINGEMENT. + + Technology Compatibility Kit Test Suite(s) Location: + http://www.helixcommunity.org/content/tck + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/RCSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/RCSL.txt new file mode 100644 index 0000000..a809759 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/RCSL.txt @@ -0,0 +1,948 @@ +The RCSL is made up of a base agreement and a few Attachments. + +For Research and Development use, you agree to the terms of the +RCSL R&D License (base RCSL and Attachments A, B, and C) + +For Commercial Use (either distribution or internal commercial +deployment) of the Helix DNA with or without support for RealNetworks' +RealAudio and RealVideo Add-on Technology, you agree to the +terms of the same RCSL R&D license +and execute one or more additional Commercial Use License attachments +. + +------------------------------------------------------------------------ + + + REALNETWORKS COMMUNITY SOURCE LICENSE + +Version 1.2 (Rev. Date: January 22, 2003). + + + RECITALS + +Original Contributor has developed Specifications, Source Code +implementations and Executables of certain Technology; and + +Original Contributor desires to license the Technology to a large +community to facilitate research, innovation and product development +while maintaining compatibility of such products with the Technology as +delivered by Original Contributor; and + +Original Contributor desires to license certain Trademarks for the +purpose of branding products that are compatible with the relevant +Technology delivered by Original Contributor; and + +You desire to license the Technology and possibly certain Trademarks +from Original Contributor on the terms and conditions specified in this +License. + +In consideration for the mutual covenants contained herein, You and +Original Contributor agree as follows: + + + AGREEMENT + +*1. Introduction.* + +The RealNetworks Community Source License ("RCSL") and effective +attachments ("License") may include five distinct licenses: + +i) Research Use license -- License plus Attachments A, B and C only. + +ii) Commercial Use and Trademark License, which may be for Internal +Deployment Use or external distribution, or both -- License plus +Attachments A, B, C, and D. + +iii) Technology Compatibility Kit (TCK) license -- Attachment C. + +iv) Add-On Technology License (Executable) Commercial Use License +-Attachment F. + +v) Add-On Technology Source Code Porting and Optimization +License-Attachment G. + +The Research Use license is effective when You click and accept this +License. The TCK is effective when You click and accept this License, +unless otherwise specified in the TCK attachments. The Commercial Use +and Trademark, Add-On Technology License, and the Add-On Technology +Source Code Porting and Optimization licenses must each be signed by You +and Original Contributor to become effective. Once effective, these +licenses and the associated requirements and responsibilities are +cumulative. Capitalized terms used in this License are defined in the +Glossary. + +*2. License Grants.* + +2.1 Original Contributor Grant. + +Subject to Your compliance with Sections 3, 8.10 and Attachment A of +this License, Original Contributor grants to You a worldwide, +royalty-free, non-exclusive license, to the extent of Original +Contributor's Intellectual Property Rights covering the Original Code, +Upgraded Code and Specifications, to do the following: + +(a) Research Use License: + +(i) use, reproduce and modify the Original Code, Upgraded Code and +Specifications to create Modifications and Reformatted Specifications +for Research Use by You; + +(ii) publish and display Original Code, Upgraded Code and Specifications +with, or as part of Modifications, as permitted under Section 3.1(b) below; + +(iii) reproduce and distribute copies of Original Code and Upgraded Code +to Licensees and students for Research Use by You; + +(iv) compile, reproduce and distribute Original Code and Upgraded Code +in Executable form, and Reformatted Specifications to anyone for +Research Use by You. + +(b) Other than the licenses expressly granted in this License, Original +Contributor retains all right, title, and interest in Original Code and +Upgraded Code and Specifications. + +2.2 Your Grants. + +(a) To Other Licensees. You hereby grant to each Licensee a license to +Your Error Corrections and Shared Modifications, of the same scope and +extent as Original Contributor's licenses under Section 2.1 a) above +relative to Research Use and Attachment D relative to Commercial Use. + +(b) To Original Contributor. You hereby grant to Original Contributor a +worldwide, royalty-free, non-exclusive, perpetual and irrevocable +license, to the extent of Your Intellectual Property Rights covering +Your Error Corrections, Shared Modifications and Reformatted +Specifications, to use, reproduce, modify, display and distribute Your +Error Corrections, Shared Modifications and Reformatted Specifications, +in any form, including the right to sublicense such rights through +multiple tiers of distribution. + +(c) Other than the licenses expressly granted in Sections 2.2(a) and (b) +above, and the restrictions set forth in Section 3.1(d)(iv) below, You +retain all right, title, and interest in Your Error Corrections, Shared +Modifications and Reformatted Specifications. + +2.3 Contributor Modifications. + +You may use, reproduce, modify, display and distribute Contributor Error +Corrections, Shared Modifications and Reformatted Specifications, +obtained by You under this License, to the same scope and extent as with +Original Code, Upgraded Code and Specifications. + +2.4 Subcontracting. + +You may deliver the Source Code of Covered Code to other Licensees +having at least a Research Use license, for the sole purpose of +furnishing development services to You in connection with Your rights +granted in this License. All such Licensees must execute appropriate +documents with respect to such work consistent with the terms of this +License, and acknowledging their work-made-for-hire status or assigning +exclusive right to the work product and associated Intellectual Property +Rights to You. + +*3. Requirements and Responsibilities*. + +3.1 Research Use License. + +As a condition of exercising the rights granted under Section 2.1(a) +above, You agree to comply with the following: + +(a) Your Contribution to the Community. All Error Corrections and Shared +Modifications which You create or contribute to are automatically +subject to the licenses granted under Section 2.2 above. You are +encouraged to license all of Your other Modifications under Section 2.2 +as Shared Modifications, but are not required to do so. You agree to +notify Original Contributor of any errors in the Specification. + +(b) Source Code Availability. You agree to provide all Your Error +Corrections to Original Contributor as soon as reasonably practicable +and, in any event, prior to Internal Deployment Use or Commercial Use, +if applicable. Original Contributor may, at its discretion, post Source +Code for Your Error Corrections and Shared Modifications on the +Community Webserver. You may also post Error Corrections and Shared +Modifications on a web-server of Your choice; provided, that You must +take reasonable precautions to ensure that only Licensees have access to +such Error Corrections and Shared Modifications. Such precautions shall +include, without limitation, a password protection scheme limited to +Licensees and a click-on, download certification of Licensee status +required of those attempting to download from the server. An example of +an acceptable certification is attached as Attachment A-2. + +(c) Notices. All Error Corrections and Shared Modifications You create +or contribute to must include a file documenting the additions and +changes You made and the date of such additions and changes. You must +also include the notice set forth in Attachment A-1 in the file header. +If it is not possible to put the notice in a particular Source Code file +due to its structure, then You must include the notice in a location +(such as a relevant directory file), where a recipient would be most +likely to look for such a notice. + +(d) Redistribution. + +(i) Source. Covered Code may be distributed in Source Code form only to +another Licensee (except for students as provided below). You may not +offer or impose any terms on any Covered Code that alter the rights, +requirements, or responsibilities of such Licensee. You may distribute +Covered Code to students for use in connection with their course work +and research projects undertaken at accredited educational institutions. +Such students need not be Licensees, but must be given a copy of the +notice set forth in Attachment A-3 and such notice must also be included +in a file header or prominent location in the Source Code made available +to such students. + +(ii) Executable. You may distribute Executable version(s) of Covered +Code to Licensees and other third parties only for the purpose of +evaluation and comment in connection with Research Use by You and under +a license of Your choice, but which limits use of such Executable +version(s) of Covered Code only to that purpose. + +(iii) Modified Class, Interface and Package Naming. In connection with +Research Use by You only, You may use Original Contributor's class, +Interface and package names only to accurately reference or invoke the +Source Code files You modify. Original Contributor grants to You a +limited license to the extent necessary for such purposes. + +(iv) You expressly agree that any distribution, in whole or in part, of +Modifications developed by You shall only be done pursuant to the terms +and conditions of this License. + +(e) Extensions. + +(i) Covered Code. You may not include any Source Code of Community Code +in any Extensions. You may include the compiled Header Files of +Community Code in an Extension provided that Your use of the Covered +Code, including Heading Files, complies with the Commercial Use License, +the TCK and all other terms of this License. + +(ii) Publication. No later than the date on which You first distribute +such Extension for Commercial Use, You must publish to the industry, on +a non-confidential basis and free of all copyright restrictions with +respect to reproduction and use, an accurate and current specification +for any Extension. In addition, You must make available an appropriate +test suite, pursuant to the same rights as the specification, +sufficiently detailed to allow any third party reasonably skilled in the +technology to produce implementations of the Extension compatible with +the specification. Such test suites must be made available as soon as +reasonably practicable but, in no event, later than ninety (90) days +after Your first Commercial Use of the Extension. You must use +reasonable efforts to promptly clarify and correct the specification and +the test suite upon written request by Original Contributor. + +(iii) Open. You agree to refrain from enforcing any Intellectual +Property Rights You may have covering any interface(s) of Your +Extension, which would prevent the implementation of such interface(s) +by Original Contributor or any Licensee. This obligation does not +prevent You from enforcing any Intellectual Property Right You have that +would otherwise be infringed by an implementation of Your Extension. + +(iv) Interface Modifications and Naming. You may not modify or add to +the GUID space * * "xxxxxxxx-0901-11d1-8B06-00A024406D59" or any other +GUID space designated by Original Contributor. You may not modify any +Interface prefix provided with the Covered Code or any other prefix +designated by Original Contributor.* * + +* * + +(f) You agree that any Specifications provided to You by Original +Contributor are confidential and proprietary information of Original +Contributor. You must maintain the confidentiality of the Specifications +and may not disclose them to any third party without Original +Contributor's prior written consent. You may only use the Specifications +under the terms of this License and only for the purpose of implementing +the terms of this License with respect to Covered Code. You agree not +use, copy or distribute any such Specifications except as provided in +writing by Original Contributor. + +3.2 Commercial Use License. + +You may not make Commercial Use of any Covered Code unless You and +Original Contributor have executed a copy of the Commercial Use and +Trademark License attached as Attachment D. + +*4. Versions of the License.* + +4.1 License Versions. + +Original Contributor may publish revised versions of the License from +time to time. Each version will be given a distinguishing version number. + +4.2 Effect. + +Once a particular version of Covered Code has been provided under a +version of the License, You may always continue to use such Covered Code +under the terms of that version of the License. You may also choose to +use such Covered Code under the terms of any subsequent version of the +License. No one other than Original Contributor has the right to +promulgate License versions. + +4.3 Multiple-Licensed Code. + +Original Contributor may designate portions of the Covered Code as +"Multiple-Licensed." "Multiple-Licensed" means that the Original +Contributor permits You to utilize those designated portions of the +Covered Code under Your choice of this License or the alternative +license(s), if any, specified by the Original Contributor in an +Attachment to this License. + +*5. Disclaimer of Warranty.* + +5.1 COVERED CODE PROVIDED AS IS. + +COVERED CODE IS PROVIDED UNDER THIS LICENSE "AS IS," WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, +WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT +FOR A PARTICULAR PURPOSE OR NON-INFRINGING. YOU AGREE TO BEAR THE ENTIRE +RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF COVERED CODE UNDER +THIS LICENSE. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART +OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER +EXCEPT SUBJECT TO THIS DISCLAIMER. + +5.2 Not Designed for High Risk Activities. + +You acknowledge that Original Code, Upgraded Code and Specifications are +not designed or intended for use in high risk activities including, but +not limited to: (i) on-line control of aircraft, air traffic, aircraft +navigation or aircraft communications; or (ii) in the design, +construction, operation or maintenance of any nuclear facility. Original +Contributor disclaims any express or implied warranty of fitness for +such uses. + +*6. Termination.* + +6.1 By You. + +You may terminate this Research Use license at anytime by providing +written notice to Original Contributor. + +6.2 By Original Contributor. + +This License and the rights granted hereunder will terminate: + +(i) automatically if You fail to comply with the terms of this License +and fail to cure such breach within 30 days of receipt of written notice +of the breach; + +(ii) immediately in the event of circumstances specified in Sections 7.1 +and 8.4; or + +(iii) at Original Contributor's discretion upon any action initiated by +You (including by cross-claim or counter claim) alleging that use or +distribution by Original Contributor or any Licensee, of Original Code, +Upgraded Code, Error Corrections, Shared Modifications or Specifications +infringe a patent owned or controlled by You. + +6.3 Effective of Termination. + +Upon termination, You agree to discontinue use of and destroy all copies +of Covered Code in Your possession. All sublicenses to the Covered Code +which You have properly granted shall survive any termination of this +License. Provisions that, by their nature, should remain in effect +beyond the termination of this License shall survive including, without +limitation, Sections 2.2, 3, 5, 7 and 8. + +6.4 No Compensation. + +Each party waives and releases the other from any claim to compensation +or indemnity for permitted or lawful termination of the business +relationship established by this License. + +*7. Liability.* + +7.1 Infringement. Should any of the Original Code, Upgraded Code, TCK or +Specifications ("Materials") become the subject of a claim of +infringement, Original Contributor may, at its sole option, (i) attempt +to procure the rights necessary for You to continue using the Materials, +(ii) modify the Materials so that they are no longer infringing, or +(iii) terminate Your right to use the Materials, immediately upon +written notice, and refund to You the amount, if any, having then +actually been paid by You to Original Contributor for the Original Code, +Upgraded Code and TCK, depreciated on a straight line, five year basis. + +7.2 LIMITATION OF LIABILITY. TO THE FULL EXTENT ALLOWED BY APPLICABLE +LAW, ORIGINAL CONTRIBUTOR'S LIABILITY TO YOU FOR CLAIMS RELATING TO THIS +LICENSE, WHETHER FOR BREACH OR IN TORT, SHALL BE LIMITED TO ONE HUNDRED +PERCENT (100%) OF THE AMOUNT HAVING THEN ACTUALLY BEEN PAID BY YOU TO +ORIGINAL CONTRIBUTOR FOR ALL COPIES LICENSED HEREUNDER OF THE PARTICULAR +ITEMS GIVING RISE TO SUCH CLAIM, IF ANY, DURING THE TWELVE MONTHS +PRECEDING THE CLAIMED BREACH. IN NO EVENT WILL YOU (RELATIVE TO YOUR +SHARED MODIFICATIONS OR ERROR CORRECTIONS) OR ORIGINAL CONTRIBUTOR BE +LIABLE FOR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES IN CONNECTION WITH OR RISING OUT OF THIS LICENSE (INCLUDING, +WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR OTHER ECONOMIC +ADVANTAGE), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY, WHETHER IN +AN ACTION FOR CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE) +OR OTHERWISE, WHETHER OR NOT YOU OR ORIGINAL CONTRIBUTOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE AND NOTWITHSTANDING THE +FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. + +*8. Miscellaneous.* + +8.1 Trademark. + +You shall not use any Trademark unless You and Original Contributor +execute a copy of the Commercial Use and Trademark License Agreement +attached hereto as Attachment D. Except as expressly provided in the +License, You are granted no right, title or license to, or interest in, +any Trademarks. Whether or not You and Original Contributor enter into +the Trademark License, You agree not to (i) challenge Original +Contributor's ownership or use of Trademarks; (ii) attempt to register +any Trademarks, or any mark or logo substantially similar thereto; or +(iii) incorporate any Trademarks into Your own trademarks, product +names, service marks, company names, or domain names. + +8.2 Integration. + +This License represents the complete agreement concerning the subject +matter hereof. + +8.3 Assignment. + +Original Contributor may assign this License, and its rights and +obligations hereunder, in its sole discretion. You may assign the +Research Use portions of this License and the TCK license to a third +party upon prior written notice to Original Contributor (which may be +provided electronically via the Community Web-Server). You may not +assign the Commercial Use and Trademark license, the Add-On Technology +License, or the Add-On Technology Source Code Porting License, including +by way of merger (regardless of whether You are the surviving entity) or +acquisition, without Original Contributor's prior written consent. + +8.4 Severability. + +If any provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to make it +enforceable. Notwithstanding the foregoing, if You are prohibited by law +from fully and specifically complying with Sections 2.2 or 3, this +License will immediately terminate and You must immediately discontinue +any use of Covered Code. + +8.5 Governing Law. + +This License shall be governed by the laws of the United States and the +State of Washington, as applied to contracts entered into and to be +performed in Washington between Washington residents. The application of +the United Nations Convention on Contracts for the International Sale of +Goods is expressly excluded. You agree that the state and federal courts +located in Seattle, Washington have exclusive jurisdiction over any +claim relating to the License, including contract and tort claims. + +8.6 Dispute Resolution. + +a) Arbitration. Any dispute arising out of or relating to this License +shall be finally settled by arbitration as set out herein, except that +either party may bring any action, in a court of competent jurisdiction +(which jurisdiction shall be exclusive), with respect to any dispute +relating to such party's Intellectual Property Rights or with respect to +Your compliance with the TCK license. Arbitration shall be administered: +(i) by the American Arbitration Association (AAA), (ii) in accordance +with the rules of the United Nations Commission on International Trade +Law (UNCITRAL) (the "Rules") in effect at the time of arbitration as +modified herein; and (iii) the arbitrator will apply the substantive +laws of Washington and the United States. Judgment upon the award +rendered by the arbitrator may be entered in any court having +jurisdiction to enforce such award. + +b) Arbitration language, venue and damages. All arbitration proceedings +shall be conducted in English by a single arbitrator selected in +accordance with the Rules, who must be fluent in English and be either a +retired judge or practicing attorney having at least ten (10) years +litigation experience and be reasonably familiar with the technology +matters relative to the dispute. Unless otherwise agreed, arbitration +venue shall be in Seattle, Washington. The arbitrator may award monetary +damages only and nothing shall preclude either party from seeking +provisional or emergency relief from a court of competent jurisdiction. +The arbitrator shall have no authority to award damages in excess of +those permitted in this License and any such award in excess is void. +All awards will be payable in U.S. dollars and may include, for the +prevailing party (i) pre-judgment award interest, (ii) reasonable +attorneys' fees incurred in connection with the arbitration, and (iii) +reasonable costs and expenses incurred in enforcing the award. The +arbitrator will order each party to produce identified documents and +respond to no more than twenty-five single question interrogatories. + +8.7 Construction. + +Any law or regulation, which provides that the language of a contract +shall be construed against the drafter, shall not apply to this License. + +8.8 U.S. Government End Users. + +The Covered Code is a "commercial item," as that term is defined in 48 +C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" +and "commercial computer software documentation," as such terms are used +in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and +48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government +End Users acquire Covered Code with only those rights set forth herein. +You agree to pass this notice to our licensees. + +8.9 Marketing Activities. + +Licensee hereby grants Original Contributor a non-exclusive, +non-transferable, limited license to use the Licensee's company name and +logo ("Licensee Marks") in any presentations, press releases, or +marketing materials solely for the purpose of identifying Licensee as a +member of the Helix Community. Licensee shall provide samples of +Licensee Marks to Original Contributor upon request by Original +Contributor. Original Contributor acknowledges that the Licensee Marks +are the trademarks of Licensee. Original Contributor shall not use the +Licensee Marks in a way that may imply that Original Contributor is an +agency or branch of Licensee. Original Contributor understands and +agrees that the use of any Licensee Marks in connection with this +Agreement shall not create any right, title or interest, in, or to the +Licensee Marks or any Licensee trademarks and that all such use and +goodwill associated with any such trademarks will inure to the benefit +of Licensee. Further the Original Contributor will stop usage of the +Licensee Marks upon Licensee's request. + +8.10 Press Announcements. + +You may make press announcements or other public statements regarding +this License without the prior written consent of the Original +Contributor, if Your statement is limited to announcing the licensing of +the Covered Code or the availability of Your Product and its +compatibility with the Covered Code. All other public announcements +regarding this license require the prior written consent of the Original +Contributor. Consent requests are welcome at press@helixcommunity.org. + +8.11 International Use. + +a) Export/Import laws. Covered Code is subject to U.S. export control +laws and may be subject to export or import regulations in other +countries. Each party agrees to comply strictly with all such laws and +regulations and acknowledges their responsibility to obtain such +licenses to export, re-export, or import as may be required. You agree +to pass these obligations to Your licensees. + +b) Intellectual Property Protection. Due to limited intellectual +property protection and enforcement in certain countries, You agree not +to redistribute the Original Code, Upgraded Code, TCK and Specifications +to any country on the list of restricted countries on the Community Web +Server. + +8.12 Language. + +This License is in the English language only, which language shall be +controlling in all respects, and all versions of this License in any +other language shall be for accommodation only and shall not be binding +on the parties to this License. All communications and notices made or +given pursuant to this License, and all documentation and support to be +provided, unless otherwise noted, shall be in the English language. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH REALNETWORKS, INC. IF YOU ARE AGREEING +TO THIS LICENSE ON BEHALF OF A COMPANY, YOU REPRESENT THAT YOU ARE +AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. WHETHER YOU ARE ACTING +ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, YOU MUST BE OF MAJORITY +AGE AND BE OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. IF YOU DO NOT +MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY OF THE TERMS AND +CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON TO EXIT. + + + GLOSSARY + +1. *"Added Value"* means code which: + +(i) has a principal purpose which is substantially different from that +of the stand-alone Technology; + +(ii) represents a significant functional and value enhancement to the +Technology; + +(iii) operates in conjunction with the Technology; and + +(iv) is not marketed as a technology which replaces or substitutes for +the Technology + +2. "*Applicable Patent Rights*" mean: (a) in the case where Original +Contributor is the grantor of rights, claims of patents that (i) are now +or hereafter acquired, owned by or assigned to Original Contributor and +(ii) are necessarily infringed by using or making the Original Code or +Upgraded Code, including Modifications provided by Original Contributor, +alone and not in combination with other software or hardware; and (b) in +the case where Licensee is the grantor of rights, claims of patents that +(i) are now or hereafter acquired, owned by or assigned to Licensee and +(ii) are infringed (directly or indirectly) by using or making +Licensee's Modifications or Error Corrections, taken alone or in +combination with Covered Code. + +3. "*Application Programming Interfaces (APIs)"* means the interfaces, +associated header files, service provider interfaces, and protocols that +enable a device, application, Operating System, or other program to +obtain services from or make requests of (or provide services in +response to requests from) other programs, and to use, benefit from, or +rely on the resources, facilities, and capabilities of the relevant +programs using the APIs. APIs includes the technical documentation +describing the APIs, the Source Code constituting the API, and any +Header Files used with the APIs. + +4. "*Commercial Use*" means any use (internal or external), copying, +sublicensing or distribution (internal or external), directly or +indirectly of Covered Code by You other than Your Research Use of +Covered Code within Your business or organization or in conjunction with +other Licensees with equivalent Research Use rights. Commercial Use +includes any use of the Covered Code for direct or indirect commercial +or strategic gain, advantage or other business purpose. Any Commercial +Use requires execution of Attachment D by You and Original Contributor. + +5. "*Community Code*" means the Original Code, Upgraded Code, Error +Corrections, Shared Modifications, or any combination thereof. + +6. "*Community Webserver(s)"* means the webservers designated by +Original Contributor for access to the Original Code, Upgraded Code, TCK +and Specifications and for posting Error Corrections and Shared +Modifications. + +7. "*Compliant Covered Code*" means Covered Code that complies with the +requirements of the TCK. + +8. "*Contributor*" means each Licensee that creates or contributes to +the creation of any Error Correction or Shared Modification. + +9. "*Covered Code*" means the Original Code, Upgraded Code, +Modifications, or any combination thereof. + +10. "*Error Correction*" means any change made to Community Code which +conforms to the Specification and corrects the adverse effect of a +failure of Community Code to perform any function set forth in or +required by the Specifications. + +11. "*Executable*" means Covered Code that has been converted from +Source Code to the preferred form for execution by a computer or digital +processor (e.g. binary form). + +12. "*Extension(s)"* means any additional Interfaces developed by or for +You which: (i) are designed for use with the Technology; (ii) constitute +an API for a library of computing functions or services; and (iii) are +disclosed or otherwise made available to third party software developers +for the purpose of developing software which invokes such additional +Interfaces. The foregoing shall not apply to software developed by Your +subcontractors to be exclusively used by You. + +13. "*Header File(s)"* means that portion of the Source Code that +provides the names and types of member functions, data members, class +definitions, and interface definitions necessary to implement the APIs +for the Covered Code. Header Files include, files specifically +designated by Original Contributor as Header Files. Header Files do not +include the code necessary to implement the functionality underlying the +Interface. + +14. *"Helix DNA Server Technology"* means the program(s) that implement +the Helix Universal Server streaming engine for the Technology as +defined in the Specification. + +15. *"Helix DNA Client Technology"* means the Covered Code that +implements the RealOne Player engine as defined in the Specification. + +16. *"Helix DNA Producer Technology"* means the Covered Code that +implements the Helix Producer engine as defined in the Specification. + +17. *"Helix DNA Technology"* means the Helix DNA Server Technology, the +Helix DNA Client Technology, the Helix DNA Producer Technology and other +Helix technologies designated by Original Contributor. + +18. "*Intellectual Property Rights*" means worldwide statutory and +common law rights associated solely with (i) Applicable Patent Rights; +(ii) works of authorship including copyrights, copyright applications, +copyright registrations and "moral rights"; (iii) the protection of +trade and industrial secrets and confidential information; and (iv) +divisions, continuations, renewals, and re-issuances of the foregoing +now existing or acquired in the future. + +19. *"Interface*" means interfaces, functions, properties, class +definitions, APIs, Header Files, GUIDs, V-Tables, and/or protocols +allowing one piece of software, firmware or hardware to communicate or +interoperate with another piece of software, firmware or hardware. + +20. "*Internal Deployment Use*" means use of Compliant Covered Code +(excluding Research Use) within Your business or organization only by +Your employees and/or agents on behalf of Your business or organization, +but not to provide services, including content distribution, to third +parties, subject to execution of Attachment D by You and Original +Contributor, if required. + +21. "*Licensee*" means any party that has entered into and has in effect +a version of this License with Original Contributor. + +22. "*MIME type*" means a description of what type of media or other +content is in a file, including by way of example but not limited to +'audio/x-pn-realaudio-plugin.' + +23. "*Modification(s)"* means (i) any addition to, deletion from and/or +change to the substance and/or structure of the Covered Code, including +Interfaces; (ii) the combination of any Covered Code and any previous +Modifications; (iii) any new file or other representation of computer +program statements that contains any portion of Covered Code; and/or +(iv) any new Source Code implementing any portion of the Specifications. + +24. "*MP3 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Picture Experts Group known as MPEG-1 Audio Layer-3 or MP3, +including but not limited to all past and future versions, profiles, +extensions, parts and amendments relating to the MP3 specification. + +25. "*MPEG-4 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Pictures Experts Group known as MPEG-4, including but not +limited to all past and future versions, profiles, extensions, parts and +amendments relating to the MPEG-4 specification. + +26. "*Original Code*" means the initial Source Code for the Technology +as described on the Community Web Server. + +27. "*Original Contributor*" means RealNetworks, Inc., its affiliates +and its successors and assigns. + +28. "*Original Contributor MIME Type*" means the MIME registry, browser +preferences, or local file/protocol associations invoking any Helix DNA +Client-based application, including the RealOne Player, for playback of +RealAudio, RealVideo, other RealMedia MIME types or datatypes (e.g., +.ram, .rnx, .rpm, .ra, .rm, .rp, .rt, .rf, .prx, .mpe, .rmp, .rmj, .rav, +.rjs, .rmx, .rjt, .rms), and any other Original Contributor-specific or +proprietary MIME types that Original Contributor may introduce in the +future. + +29. "*Personal Use*" means use of Covered Code by an individual solely +for his or her personal, private and non-commercial purposes. An +individual's use of Covered Code in his or her capacity as an officer, +employee, member, independent contractor or agent of a corporation, +business or organization (commercial or non-commercial) does not qualify +as Personal Use. + +30. "*RealMedia File Format*" means the file format designed and +developed by RealNetworks for storing multimedia data and used to store +RealAudio and RealVideo encoded streams. Valid RealMedia File Format +extensions include: .rm, .rmj, .rmc, .rmvb, .rms. + +31. "*RCSL Webpage*" means the RealNetworks Community Source License +webpage located at https://www.helixcommunity.org/content/rcsl or such +other URL that Original Contributor may designate from time to time. + +32. "*Reformatted Specifications*" means any revision to the +Specifications which translates or reformats the Specifications (as for +example in connection with Your documentation) but which does not alter, +subset or superset * *the functional or operational aspects of the +Specifications. + +33. "*Research Use*" means use and distribution of Covered Code only for +Your Personal Use, research or development use and expressly excludes +Internal Deployment Use and Commercial Use. Research Use also includes +use of Covered Code to teach individuals how to use Covered Code. + +34. "*Shared Modifications*" means Modifications that You distribute or +use for a Commercial Use, in addition to any Modifications provided by +You, at Your option, pursuant to Section 2.2, or received by You from a +Contributor pursuant to Section 2.3. + +35. "*Source Code*" means the preferred form of the Covered Code for +making modifications to it, including all modules it contains, plus any +associated interface definition files, scripts used to control +compilation and installation of an Executable, or source code +differential comparisons against either the Original Code or another +well known, available Covered Code of the Contributor's choice. The +Source Code can be in a compressed or archival form, provided the +appropriate decompression or de-archiving software is widely available +for no charge. + +36. "*Specifications*" means the specifications for the Technology and +other documentation, as designated on the Community Web Server, as may +be revised by Original Contributor from time to time. + +37. "*Trademarks*" means Original Contributor's trademarks and logos, +including, but not limited to, RealNetworks, RealAudio, RealVideo, +RealOne, RealSystem, SureStream, Helix, Helix DNA and other trademarks +whether now used or adopted in the future. + +38. "*Technology*" means the technology described in Attachment B, and +Upgrades. + +39. "*Technology Compatibility Kit"* or *"TCK*" means the test programs, +procedures, acceptance criteria and/or other requirements, designated by +Original Contributor for use in verifying compliance of Covered Code +with the Specifications, in conjunction with the Original Code and +Upgraded Code. Original Contributor may, in its sole discretion and from +time to time, revise a TCK to correct errors and/or omissions and in +connection with Upgrades. + +40. "*Upgrade(s)"* means new versions of Technology designated +exclusively by Original Contributor as an "Upgrade" and released by +Original Contributor from time to time under the terms of the License. + +41. "*Upgraded Code*" means the Source Code and/or Executables for +Upgrades, possibly including Modifications made by Contributors. + +42. *"User's Guide"* means the users guide for the TCK which Original +Contributor makes available to You to provide direction in how to run +the TCK and properly interpret the results, as may be revised by +Original Contributor from time to time. + +43. "*You(r)*" means an individual, or a legal entity acting by and +through an individual or individuals, exercising rights either under +this License or under a future version of this License issued pursuant +to Section 4.1. For legal entities, "You(r)" includes any entity that by +majority voting interest controls, is controlled by, or is under common +control with You. + +44. "*Your Products*" means any (i) hardware products You distribute +integrating the Covered Code; (ii) any software products You distribute +with the Covered Code that utilize the APIs of the Covered Code; or +(iii) any services You provide using the Covered Code. + + + ATTACHMENT A + +REQUIRED NOTICES + + + ATTACHMENT A-1 + +REQUIRED IN ALL CASES + +Notice to be included in header file of all Error Corrections and Shared +Modifications: + +Portions Copyright 1994-2003 RealNetworks, Inc. All rights reserved. + +The contents of this file, and the files included with this file, are +subject to the current version of RealNetworks Community Source License +Version 1.1 (the "License"). You may not use this file except in +compliance with the License executed by both You and RealNetworks. You +may obtain a copy of the License at * +https://www.helixcommunity.org/content/rcsl.* You may also obtain a copy +of the License by contacting RealNetworks directly. Please see the +License for the rights, obligations and limitations governing use of the +contents of the file. + +This file is part of the Helix DNA technology. RealNetworks, Inc., is +the developer of the Original code and owns the copyrights in the +portions it created. + +This file, and the files included with this file, are distributed on an +'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, +AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): + +_______________________________________________ + +Technology Compatibility Kit Test Suite(s) Location: + +________________________________ + + + ATTACHMENT A-2 + +SAMPLE LICENSEE CERTIFICATION + +"By clicking the `Agree' button below, You certify that You are a +Licensee in good standing under the RealNetworks Community Source +License, ("License") and that Your access, use and distribution of code +and information You may obtain at this site is subject to the License. +If You are not a Licensee under the RealNetworks Community Source +License You agree not to download, copy or use the Helix DNA technology. + + + ATTACHMENT A-3 + +REQUIRED STUDENT NOTIFICATION + +"This software and related documentation has been obtained by Your +educational institution subject to the RealNetworks Community Source +License. You have been provided access to the software and related +documentation for use only in connection with your course work and +research activities as a matriculated student of Your educational +institution. Any other use is expressly prohibited. + +THIS SOFTWARE AND RELATED DOCUMENTATION CONTAINS PROPRIETARY MATERIAL OF +REALNETWORKS, INC, WHICH ARE PROTECTED BY VARIOUS INTELLECTUAL PROPERTY +RIGHTS. + +You may not use this file except in compliance with the License. You may +obtain a copy of the License on the web at +https://www.helixcommunity.org/content/rcsl. + +* +* + + + ATTACHMENT B + +Description of Technology + +Helix DNA, which consists of Helix DNA Client, Helix DNA Server and +Helix DNA Producer. + +Description of "Technology" + +Helix DNA Technology v1.0 as described on the Community Web Server. + + + ATTACHMENT C + +TECHNOLOGY COMPATIBILITY KIT LICENSE + +The following license is effective for the *Helix DNA* Technology +Compatibility Kit - as described on the Community Web Server. The +Technology Compatibility Kit(s) for the Technology specified in +Attachment B may be accessed at the Community Web Server. + +1. TCK License. + +1.1 Grants to use TCK + +Subject to the terms and restrictions set forth below and the +RealNetworks Community Source License, and the Research Use license, +Original Contributor grants to You a worldwide, non-exclusive, +non-transferable license, to the extent of Original Contributor's +Intellectual Property Rights in the TCK (without the right to +sublicense), to use the TCK to develop and test Covered Code. + +1.2 TCK Use Restrictions. + +You are not authorized to create derivative works of the TCK or use the +TCK to test any implementation of the Specification that is not Covered +Code. You may not publish Your test results or make claims of +comparative compatibility with respect to other implementations of the +Specification. In consideration for the license grant in Section 1.1 +above You agree not to develop Your own tests that are intended to +validate conformation with the Specification. + +2. Test Results. + +You agree to provide to Original Contributor or the third party test +facility if applicable, Your test results that demonstrate that Covered +Code is Compliant Covered Code and that Original Contributor may publish +or otherwise distribute such test results. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH THE ORIGINAL CONTRIBUTOR, REALNETWORKS, +INC. IF YOU ARE AGREEING TO THIS LICENSE ON BEHALF OF A COMPANY, YOU +REPRESENT THAT YOU ARE AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. +WHETHER YOU ARE ACTING ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, +YOU MUST BE OF MAJORITY AGE AND BE OTHERWISE COMPETENT TO ENTER INTO +CONTRACTS. IF YOU DO NOT MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY +OF THE TERMS AND CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON +TO EXIT. + +*ACCEPT / REJECT +* + +* +* + +*To agree to the R&D/academic terms of this license, please register + on the site -- +you will then be given a chance to agree to the clickwrap RCSL + +R&D License + +and gain access to the RCSL-licensed source code. To build or deploy +commercial applications based on the RCSL, you will need to agree to the +Commercial Use license attachments +* + + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/RPSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/RPSL.txt new file mode 100644 index 0000000..d040a45 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/RPSL.txt @@ -0,0 +1,518 @@ +RealNetworks Public Source License Version 1.0 +(Rev. Date October 28, 2002) + +1. General Definitions. This License applies to any program or other work which +RealNetworks, Inc., or any other entity that elects to use this license, +("Licensor") makes publicly available and which contains a notice placed by +Licensor identifying such program or work as "Original Code" and stating that it +is subject to the terms of this RealNetworks Public Source License version 1.0 +(or subsequent version thereof) ("License"). You are not required to accept this +License. However, nothing else grants You permission to use, copy, modify or +distribute the software or its derivative works. These actions are prohibited by +law if You do not accept this License. Therefore, by modifying, copying or +distributing the software (or any work based on the software), You indicate your +acceptance of this License to do so, and all its terms and conditions. In +addition, you agree to the terms of this License by clicking the Accept button +or downloading the software. As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Licensor is the +grantor of rights, claims of patents that (i) are now or hereafter acquired, +owned by or assigned to Licensor and (ii) are necessarily infringed by using or +making the Original Code alone and not in combination with other software or +hardware; and (b) in the case where You are the grantor of rights, claims of +patents that (i) are now or hereafter acquired, owned by or assigned to You and +(ii) are infringed (directly or indirectly) by using or making Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Compatible Source License" means any one of the licenses listed on Exhibit +B or at https://www.helixcommunity.org/content/complicense or other licenses +specifically identified by Licensor in writing. Notwithstanding any term to the +contrary in any Compatible Source License, any code covered by any Compatible +Source License that is used with Covered Code must be made readily available in +Source Code format for royalty-free use under the terms of the Compatible Source +License or this License. + +1.3 "Contributor" means any person or entity that creates or contributes to the +creation of Modifications. + +1.4 "Covered Code" means the Original Code, Modifications, the combination of +Original Code and any Modifications, and/or any respective portions thereof. + +1.5 "Deploy" means to use, sublicense or distribute Covered Code other than for +Your internal research and development (R&D) and/or Personal Use, and includes +without limitation, any and all internal use or distribution of Covered Code +within Your business or organization except for R&D use and/or Personal Use, as +well as direct or indirect sublicensing or distribution of Covered Code by You +to any third party in any form or manner. + +1.6 "Derivative Work" means either the Covered Code or any derivative work under +United States copyright law, and including any work containing or including any +portion of the Covered Code or Modifications, either verbatim or with +modifications and/or translated into another language. Derivative Work also +includes any work which combines any portion of Covered Code or Modifications +with code not otherwise governed by the terms of this License. + +1.7 "Externally Deploy" means to Deploy the Covered Code in any way that may be +accessed or used by anyone other than You, used to provide any services to +anyone other than You, or used in any way to deliver any content to anyone other +than You, whether the Covered Code is distributed to those parties, made +available as an application intended for use over a computer network, or used to +provide services or otherwise deliver content to anyone other than You. + +1.8. "Interface" means interfaces, functions, properties, class definitions, +APIs, header files, GUIDs, V-Tables, and/or protocols allowing one piece of +software, firmware or hardware to communicate or interoperate with another piece +of software, firmware or hardware. + +1.9 "Modifications" mean any addition to, deletion from, and/or change to, the +substance and/or structure of the Original Code, any previous Modifications, the +combination of Original Code and any previous Modifications, and/or any +respective portions thereof. When code is released as a series of files, a +Modification is: (a) any addition to or deletion from the contents of a file +containing Covered Code; and/or (b) any new file or other representation of +computer program statements that contains any part of Covered Code. + +1.10 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Licensor under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Licensor under this License, and that has been expressly identified by Licensor +as such in the header file(s) of such work; and (b) the object code compiled +from such Source Code and originally made available by Licensor under this +License. + +1.11 "Personal Use" means use of Covered Code by an individual solely for his or +her personal, private and non-commercial purposes. An individual's use of +Covered Code in his or her capacity as an officer, employee, member, independent +contractor or agent of a corporation, business or organization (commercial or +non-commercial) does not qualify as Personal Use. + +1.12 "Source Code" means the human readable form of a program or other work that +is suitable for making modifications to it, including all modules it contains, +plus any associated interface definition files, scripts used to control +compilation and installation of an executable (object code). + +1.13 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership of +fifty percent (50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Licensor hereby grants You, effective on the date +You accept this License (via downloading or using Covered Code or otherwise +indicating your acceptance of this License), a worldwide, royalty-free, +non-exclusive copyright license, to the extent of Licensor's copyrights cover +the Original Code, to do the following: + +2.1 You may reproduce, display, perform, modify and Deploy Covered Code, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the copyright +and other proprietary notices and disclaimers of Licensor as they appear in the +Original Code, and keep intact all notices in the Original Code that refer to +this License; + +(b) You must include a copy of this License with every copy of Source Code of +Covered Code and documentation You distribute, and You may not offer or impose +any terms on such Source Code that alter or restrict this License or the +recipients' rights hereunder, except as permitted under Section 6; + +(c) You must duplicate, to the extent it does not already exist, the notice in +Exhibit A in each file of the Source Code of all Your Modifications, and cause +the modified files to carry prominent notices stating that You changed the files +and the date of any change; + +(d) You must make Source Code of all Your Externally Deployed Modifications +publicly available under the terms of this License, including the license grants +set forth in Section 3 below, for as long as you Deploy the Covered Code or +twelve (12) months from the date of initial Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Deployed Modifications +electronically (e.g. download from a web site); and + +(e) if You Deploy Covered Code in object code, executable form only, You must +include a prominent notice, in the code itself as well as in related +documentation, stating that Source Code of the Covered Code is available under +the terms of this License with information on how and where to obtain such +Source Code. You must also include the Object Code Notice set forth in Exhibit A +in the "about" box or other appropriate place where other copyright notices are +placed, including any packaging materials. + +2.2 You expressly acknowledge and agree that although Licensor and each +Contributor grants the licenses to their respective portions of the Covered Code +set forth herein, no assurances are provided by Licensor or any Contributor that +the Covered Code does not infringe the patent or other intellectual property +rights of any other entity. Licensor and each Contributor disclaim any liability +to You for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, You hereby assume sole responsibility to +secure any other intellectual property rights needed, if any. For example, if a +third party patent license is required to allow You to make, use, sell, import +or offer for sale the Covered Code, it is Your responsibility to acquire such +license(s). + +2.3 Subject to the terms and conditions of this License, Licensor hereby grants +You, effective on the date You accept this License (via downloading or using +Covered Code or otherwise indicating your acceptance of this License), a +worldwide, royalty-free, perpetual, non-exclusive patent license under +Licensor's Applicable Patent Rights to make, use, sell, offer for sale and +import the Covered Code, provided that in each instance you comply with the +terms of this License. + +3. Your Grants. In consideration of, and as a condition to, the licenses granted +to You under this License: + +(a) You grant to Licensor and all third parties a non-exclusive, perpetual, +irrevocable, royalty free license under Your Applicable Patent Rights and other +intellectual property rights owned or controlled by You, to make, sell, offer +for sale, use, import, reproduce, display, perform, modify, distribute and +Deploy Your Modifications of the same scope and extent as Licensor's licenses +under Sections 2.1 and 2.2; and + +(b) You grant to Licensor and its subsidiaries a non-exclusive, worldwide, +royalty-free, perpetual and irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights owned or controlled by You, to +make, use, sell, offer for sale, import, reproduce, display, perform, +distribute, modify or have modified (for Licensor and/or its subsidiaries), +sublicense and distribute Your Modifications, in any form and for any purpose, +through multiple tiers of distribution. + +(c) You agree not use any information derived from Your use and review of the +Covered Code, including but not limited to any algorithms or inventions that may +be contained in the Covered Code, for the purpose of asserting any of Your +patent rights, or assisting a third party to assert any of its patent rights, +against Licensor or any Contributor. + +4. Derivative Works. You may create a Derivative Work by combining Covered Code +with other code not otherwise governed by the terms of this License and +distribute the Derivative Work as an integrated product. In each such instance, +You must make sure the requirements of this License are fulfilled for the +Covered Code or any portion thereof, including all Modifications. + +4.1 You must cause any Derivative Work that you distribute, publish or +Externally Deploy, that in whole or in part contains or is derived from the +Covered Code or any part thereof, to be licensed as a whole at no charge to all +third parties under the terms of this License and no other license except as +provided in Section 4.2. You also must make Source Code available for the +Derivative Work under the same terms as Modifications, described in Sections 2 +and 3, above. + +4.2 Compatible Source Licenses. Software modules that have been independently +developed without any use of Covered Code and which contain no portion of the +Covered Code, Modifications or other Derivative Works, but are used or combined +in any way wtih the Covered Code or any Derivative Work to form a larger +Derivative Work, are exempt from the conditions described in Section 4.1 but +only to the extent that: the software module, including any software that is +linked to, integrated with, or part of the same applications as, the software +module by any method must be wholly subject to one of the Compatible Source +Licenses. Notwithstanding the foregoing, all Covered Code must be subject to the +terms of this License. Thus, the entire Derivative Work must be licensed under a +combination of the RPSL (for Covered Code) and a Compatible Source License for +any independently developed software modules within the Derivative Work. The +foregoing requirement applies even if the Compatible Source License would +ordinarily allow the software module to link with, or form larger works with, +other software that is not subject to the Compatible Source License. For +example, although the Mozilla Public License v1.1 allows Mozilla code to be +combined with proprietary software that is not subject to the MPL, if +MPL-licensed code is used with Covered Code the MPL-licensed code could not be +combined or linked with any code not governed by the MPL. The general intent of +this section 4.2 is to enable use of Covered Code with applications that are +wholly subject to an acceptable open source license. You are responsible for +determining whether your use of software with Covered Code is allowed under Your +license to such software. + +4.3 Mere aggregation of another work not based on the Covered Code with the +Covered Code (or with a work based on the Covered Code) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. If You deliver the Covered Code for combination and/or integration with +an application previously provided by You (for example, via automatic updating +technology), such combination and/or integration constitutes a Derivative Work +subject to the terms of this License. + +5. Exclusions From License Grant. Nothing in this License shall be deemed to +grant any rights to trademarks, copyrights, patents, trade secrets or any other +intellectual property of Licensor or any Contributor except as expressly stated +herein. No right is granted to the trademarks of Licensor or any Contributor +even if such marks are included in the Covered Code. Nothing in this License +shall be interpreted to prohibit Licensor from licensing under different terms +from this License any code that Licensor otherwise would have a right to +license. Modifications, Derivative Works and/or any use or combination of +Covered Code with other technology provided by Licensor or third parties may +require additional patent licenses from Licensor which Licensor may grant in its +sole discretion. No patent license is granted separate from the Original Code or +combinations of the Original Code with other software or hardware. + +5.1. Trademarks. This License does not grant any rights to use the trademarks or +trade names owned by Licensor ("Licensor Marks" defined in Exhibit C) or to any +trademark or trade name belonging to any Contributor. No Licensor Marks may be +used to endorse or promote products derived from the Original Code other than as +permitted by the Licensor Trademark Policy defined in Exhibit C. + +6. Additional Terms. You may choose to offer, and to charge a fee for, warranty, +support, indemnity or liability obligations and/or other rights consistent with +the scope of the license granted herein ("Additional Terms") to one or more +recipients of Covered Code. However, You may do so only on Your own behalf and +as Your sole responsibility, and not on behalf of Licensor or any Contributor. +You must obtain the recipient's agreement that any such Additional Terms are +offered by You alone, and You hereby agree to indemnify, defend and hold +Licensor and every Contributor harmless for any liability incurred by or claims +asserted against Licensor or such Contributor by reason of any such Additional +Terms. + +7. Versions of the License. Licensor may publish revised and/or new versions of +this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular version +of this License, You may continue to use it under the terms of that version. You +may also choose to use such Original Code under the terms of any subsequent +version of this License published by Licensor. No one other than Licensor has +the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in part +pre-release, untested, or not fully tested works. The Covered Code may contain +errors that could cause failures or loss of data, and may be incomplete or +contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND LICENSOR AND LICENSOR'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS +"LICENSOR" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY +DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET +ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. LICENSOR AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN DOCUMENTATION, INFORMATION OR ADVICE GIVEN BY LICENSOR, A LICENSOR +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You +acknowledge that the Covered Code is not intended for use in high risk +activities, including, but not limited to, the design, construction, operation +or maintenance of nuclear facilities, aircraft navigation, aircraft +communication systems, or air traffic control machines in which case the failure +of the Covered Code could lead to death, personal injury, or severe physical or +environmental damage. Licensor disclaims any express or implied warranty of +fitness for such uses. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT +SHALL LICENSOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR STRICT +LIABILITY), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF LICENSOR OR SUCH +CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND +NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. SOME +JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF INCIDENTAL OR +CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event +shall Licensor's total liability to You for all damages (other than as may be +required by applicable law) under this License exceed the amount of ten dollars +($10.00). + +10. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Licensor retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Licensor +("Licensor Modifications"), and such Licensor Modifications will not be +automatically subject to this License. Licensor may, at its sole discretion, +choose to license such Licensor Modifications under this License, or on +different terms from those contained in this License or may choose not to +license them at all. + +11. Termination. + +11.1 Term and Termination. The term of this License is perpetual unless +terminated as provided below. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Licensor if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; + +(b) immediately in the event of the circumstances described in Section 12.5(b); +or + +(c) automatically without notice from Licensor if You, at any time during the +term of this License, commence an action for patent infringement against +Licensor (including by cross-claim or counter claim in a lawsuit); + +(d) upon written notice from Licensor if You, at any time during the term of +this License, commence an action for patent infringement against any third party +alleging that the Covered Code itself (excluding combinations with other +software or hardware) infringes any patent (including by cross-claim or counter +claim in a lawsuit). + +11.2 Effect of Termination. Upon termination, You agree to immediately stop any +further use, reproduction, modification, sublicensing and distribution of the +Covered Code and to destroy all copies of the Covered Code that are in your +possession or control. All sublicenses to the Covered Code which have been +properly granted prior to termination shall survive any termination of this +License. Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to Sections +3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other for +compensation, indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this License will +be without prejudice to any other right or remedy of any party. + +12. Miscellaneous. + +12.1 Government End Users. The Covered Code is a "commercial item" as defined in +FAR 2.101. Government software and technical data rights in the Covered Code +include only those rights customarily provided to the public as defined in this +License. This customary commercial license in technical data and software is +provided in accordance with FAR 12.211 (Technical Data) and 12.212 (Computer +Software) and, for Department of Defense purchases, DFAR 252.227-7015 (Technical +Data -- Commercial Items) and 227.7202-3 (Rights in Commercial Computer Software +or Computer Software Documentation). Accordingly, all U.S. Government End Users +acquire Covered Code with only those rights set forth herein. + +12.2 Relationship of Parties. This License will not be construed as creating an +agency, partnership, joint venture or any other form of legal association +between or among You, Licensor or any Contributor, and You will not represent to +the contrary, whether expressly, by implication, appearance or otherwise. + +12.3 Independent Development. Nothing in this License will impair Licensor's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions as, +or otherwise compete with, Modifications, Derivative Works, technology or +products that You may develop, produce, market or distribute. + +12.4 Waiver; Construction. Failure by Licensor or any Contributor to enforce any +provision of this License will not be deemed a waiver of future enforcement of +that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +12.5 Severability. (a) If for any reason a court of competent jurisdiction finds +any provision of this License, or portion thereof, to be unenforceable, that +provision of the License will be enforced to the maximum extent permissible so +as to effect the economic benefits and intent of the parties, and the remainder +of this License will continue in full force and effect. (b) Notwithstanding the +foregoing, if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the enforceability +of either of those Sections, this License will immediately terminate and You +must immediately discontinue any use of the Covered Code and destroy all copies +of it that are in your possession or control. + +12.6 Dispute Resolution. Any litigation or other dispute resolution between You +and Licensor relating to this License shall take place in the Seattle, +Washington, and You and Licensor hereby consent to the personal jurisdiction of, +and venue in, the state and federal courts within that District with respect to +this License. The application of the United Nations Convention on Contracts for +the International Sale of Goods is expressly excluded. + +12.7 Export/Import Laws. This software is subject to all export and import laws +and restrictions and regulations of the country in which you receive the Covered +Code and You are solely responsible for ensuring that You do not export, +re-export or import the Covered Code or any direct product thereof in violation +of any such restrictions, laws or regulations, or without all necessary +authorizations. + +12.8 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +Washington. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé +que le présent contrat et tous les documents connexes soient +rédigés en anglais. + + EXHIBIT A. + +"Copyright © 1995-2002 +RealNetworks, Inc. and/or its licensors. All Rights Reserved. + +The contents of this file, and the files included with this file, are subject to +the current version of the RealNetworks Public Source License Version 1.0 (the +"RPSL") available at https://www.helixcommunity.org/content/rpsl unless you have +licensed the file under the RealNetworks Community Source License Version 1.0 +(the "RCSL") available at https://www.helixcommunity.org/content/rcsl, in which +case the RCSL will apply. You may also obtain the license terms directly from +RealNetworks. You may not use this file except in compliance with the RPSL or, +if you have a valid RCSL with RealNetworks applicable to this file, the RCSL. +Please see the applicable RPSL or RCSL for the rights, obligations and +limitations governing use of the contents of the file. + +This file is part of the Helix DNA Technology. RealNetworks is the developer of +the Original code and owns the copyrights in the portions it created. + +This file, and the files included with this file, is distributed and made +available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR +IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING +WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): ____________________________________ + +Technology Compatibility Kit Test +Suite(s) Location (if licensed under the RCSL): ______________________________ + +Object Code Notice: Helix DNA Client technology included. Copyright (c) +RealNetworks, Inc., 1995-2002. All rights reserved. + + + EXHIBIT B + +Compatible Source Licenses for the RealNetworks Public Source License. The +following list applies to the most recent version of the license as of October +25, 2002, unless otherwise indicated. + +* Academic Free License +* Apache Software License +* Apple Public Source License +* Artistic license +* Attribution Assurance Licenses +* BSD license +* Common Public License (1) +* Eiffel Forum License +* GNU General Public License (GPL) (1) +* GNU Library or "Lesser" General Public License (LGPL) (1) +* IBM Public License +* Intel Open Source License +* Jabber Open Source License +* MIT license +* MITRE Collaborative Virtual Workspace License (CVW License) +* Motosoto License +* Mozilla Public License 1.0 (MPL) +* Mozilla Public License 1.1 (MPL) +* Nokia Open Source License +* Open Group Test Suite License +* Python Software Foundation License +* Ricoh Source Code Public License +* Sun Industry Standards Source License (SISSL) +* Sun Public License +* University of Illinois/NCSA Open Source License +* Vovida Software License v. 1.0 +* W3C License +* X.Net License +* Zope Public License +* zlib/libpng license + +(1) Note: because this license contains certain reciprocal licensing terms that +purport to extend to independently developed code, You may be prohibited under +the terms of this otherwise compatible license from using code licensed under +its terms with Covered Code because Covered Code may only be licensed under the +RealNetworks Public Source License. Any attempt to apply non RPSL license terms, +including without limitation the GPL, to Covered Code is expressly forbidden. +You are responsible for ensuring that Your use of Compatible Source Licensed +code does not violate either the RPSL or the Compatible Source License. + +The latest version of this list can be found at: +https://www.helixcommunity.org/content/complicense + + EXHIBIT C + +RealNetworks' Trademark policy. + +RealNetworks defines the following trademarks collectively as "Licensor +Trademarks": "RealNetworks", "RealPlayer", "RealJukebox", "RealSystem", +"RealAudio", "RealVideo", "RealOne Player", "RealMedia", "Helix" or any other +trademarks or trade names belonging to RealNetworks. + +RealNetworks "Licensor Trademark Policy" forbids any use of Licensor Trademarks +except as permitted by and in strict compliance at all times with RealNetworks' +third party trademark usage guidelines which are posted at +http://www.realnetworks.com/info/helixlogo.html. + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/asmmisc.s b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/asmmisc.s new file mode 100644 index 0000000..a9dff45 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/asmmisc.s @@ -0,0 +1,47 @@ +;/* ***** BEGIN LICENSE BLOCK ***** +; * Version: RCSL 1.0/RPSL 1.0 +; * +; * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. +; * +; * The contents of this file, and the files included with this file, are +; * subject to the current version of the RealNetworks Public Source License +; * Version 1.0 (the "RPSL") available at +; * http://www.helixcommunity.org/content/rpsl unless you have licensed +; * the file under the RealNetworks Community Source License Version 1.0 +; * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, +; * in which case the RCSL will apply. You may also obtain the license terms +; * directly from RealNetworks. You may not use this file except in +; * compliance with the RPSL or, if you have a valid RCSL with RealNetworks +; * applicable to this file, the RCSL. Please see the applicable RPSL or +; * RCSL for the rights, obligations and limitations governing use of the +; * contents of the file. +; * +; * This file is part of the Helix DNA Technology. RealNetworks is the +; * developer of the Original Code and owns the copyrights in the portions +; * it created. +; * +; * This file, and the files included with this file, is distributed and made +; * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +; * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, +; * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS +; * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +; * +; * Technology Compatibility Kit Test Suite(s) Location: +; * http://www.helixcommunity.org/content/tck +; * +; * Contributor(s): +; * +; * ***** END LICENSE BLOCK ***** */ + + AREA |.text|, CODE, READONLY + +; int xmp3_MULSHIFT32(int x, int y); + + EXPORT xmp3_MULSHIFT32 + +xmp3_MULSHIFT32 + + smull r2, r0, r1, r0 + mov pc, lr + + END \ No newline at end of file diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/asmpoly.s b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/asmpoly.s new file mode 100644 index 0000000..c051cea --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/asmpoly.s @@ -0,0 +1,415 @@ +;/* ***** BEGIN LICENSE BLOCK ***** +; * Version: RCSL 1.0/RPSL 1.0 +; * +; * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. +; * +; * The contents of this file, and the files included with this file, are +; * subject to the current version of the RealNetworks Public Source License +; * Version 1.0 (the "RPSL") available at +; * http://www.helixcommunity.org/content/rpsl unless you have licensed +; * the file under the RealNetworks Community Source License Version 1.0 +; * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, +; * in which case the RCSL will apply. You may also obtain the license terms +; * directly from RealNetworks. You may not use this file except in +; * compliance with the RPSL or, if you have a valid RCSL with RealNetworks +; * applicable to this file, the RCSL. Please see the applicable RPSL or +; * RCSL for the rights, obligations and limitations governing use of the +; * contents of the file. +; * +; * This file is part of the Helix DNA Technology. RealNetworks is the +; * developer of the Original Code and owns the copyrights in the portions +; * it created. +; * +; * This file, and the files included with this file, is distributed and made +; * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +; * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, +; * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS +; * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +; * +; * Technology Compatibility Kit Test Suite(s) Location: +; * http://www.helixcommunity.org/content/tck +; * +; * Contributor(s): +; * +; * ***** END LICENSE BLOCK ***** */ + + AREA |.text|, CODE, READONLY + +PCM RN r0 +VB1 RN r1 +COEF RN r2 + +VLO RN r0 ; must push PCM ptr to stack during inner looop +VHI RN r3 ; temp variable + +SUM1LL RN r4 +SUM1LH RN r5 +SUM2LL RN r6 +SUM2LH RN r7 +SUM1RL RN r8 +SUM1RH RN r9 +SUM2RL RN r10 +SUM2RH RN r11 + +CF1 RN r12 +CF2 RN r14 + +SIGN RN r12 ; used for clipping - after discarding CF1 +MAXPOS RN r14 ; used for clipping - after discarding CF2 + +I RN r12 ; overlay loop counter with CF1, SIGN + + GBLA RNDVAL +RNDVAL SETA (1 << ((32 - 12) + (6 - 1))) + + ; C64TOS - clip 64-bit accumulator to short (no rounding) + ; xl, xh = value (lo 32, hi 32) + ; input assumed to have 6 fraction bits + ; sign = temp variable to use for sign + ; maxPos = 0x00007fff (takes 2 instr. to generate - calculating + ; once and using repeatedly saves if you do several CTOS in a row) + MACRO + C64TOS $xl, $xh, $sign, $maxPos + + mov $xl, $xl, lsr #(20+6) + orr $xl, $xl, $xh, lsl #(12-6) + mov $sign, $xl, ASR #31 + cmp $sign, $xl, ASR #15 + eorne $xl, $sign, $maxPos + + MEND ; C64TOS + + ; MC0S - process 2 taps, 1 sample per channel (sample 0) + ; x = vb1 offset + MACRO + MC0S $x + + ldr CF1, [COEF], #4 + ldr CF2, [COEF], #4 + ldr VLO, [VB1, #(4*($x))] + ldr VHI, [VB1, #(4*(23 - $x))] + + smlal SUM1LL, SUM1LH, VLO, CF1 + ldr VLO, [VB1, #(4*(32 + $x))] + rsb CF2, CF2, #0 + smlal SUM1LL, SUM1LH, VHI, CF2 + ldr VHI, [VB1, #(4*(32 + 23 - $x))] + + smlal SUM1RL, SUM1RH, VLO, CF1 + smlal SUM1RL, SUM1RH, VHI, CF2 + + MEND ; MC0S + + ; MC1S - process 2 taps, 1 sample per channel (sample 16) + ; x = vb1 offset + MACRO + MC1S $x + + ldr CF1, [COEF], #4 + ldr VLO, [VB1, #(4*($x))] + ldr VHI, [VB1, #(4*(32 + $x))] + smlal SUM1LL, SUM1LH, VLO, CF1 + smlal SUM1RL, SUM1RH, VHI, CF1 + + MEND ; MC1S + + ; MC2S - process 2 taps, 2 samples per channel + ; x = vb1 offset + MACRO + MC2S $x + + ; load data as far as possible in advance of using it + ldr CF1, [COEF], #4 + ldr CF2, [COEF], #4 + ldr VLO, [VB1, #(4*($x))] + ldr VHI, [VB1, #(4*(23 - $x))] + + smlal SUM1LL, SUM1LH, VLO, CF1 + smlal SUM2LL, SUM2LH, VLO, CF2 + rsb CF2, CF2, #0 + smlal SUM2LL, SUM2LH, VHI, CF1 + smlal SUM1LL, SUM1LH, VHI, CF2 + + ldr VHI, [VB1, #(4*(32 + 23 - $x))] + ldr VLO, [VB1, #(4*(32 + $x))] + + smlal SUM1RL, SUM1RH, VHI, CF2 + smlal SUM2RL, SUM2RH, VHI, CF1 + rsb CF2, CF2, #0 + smlal SUM1RL, SUM1RH, VLO, CF1 + smlal SUM2RL, SUM2RH, VLO, CF2 + + MEND ; MC2S + +; void PolyphaseStereo(short *pcm, int *vbuf, const int *coefBase) + +xmp3_PolyphaseStereo FUNCTION + EXPORT xmp3_PolyphaseStereo + + stmfd sp!, {r4-r11, r14} + + ; clear out stack space for 2 local variables (4 bytes each) + sub sp, sp, #8 + str PCM, [sp, #4] ; sp[1] = pcm pointer + + ; special case, output sample 0 + mov SUM1LL, #RNDVAL ; load rndVal (low 32) + mov SUM1RL, #RNDVAL ; load rndVal (low 32) + mov SUM1LH, #0 + mov SUM1RH, #0 + + MC0S 0 + MC0S 1 + MC0S 2 + MC0S 3 + MC0S 4 + MC0S 5 + MC0S 6 + MC0S 7 + + ldr PCM, [sp, #4] ; load pcm pointer + mov MAXPOS, #0x7f00 + orr MAXPOS, MAXPOS, #0xff + + C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS + C64TOS SUM1RL, SUM1RH, SIGN, MAXPOS + + strh SUM1LL, [PCM, #(2*0)] + strh SUM1RL, [PCM, #(2*1)] + + ; special case, output sample 16 + add COEF, COEF, #(4*(256-16)) ; coef = coefBase + 256 (was coefBase + 16 after MC0S block) + add VB1, VB1, #(4*1024) ; vb1 = vbuf + 64*16 + + mov SUM1LL, #RNDVAL ; load rndVal (low 32) + mov SUM1RL, #RNDVAL ; load rndVal (low 32) + mov SUM1LH, #0 + mov SUM1RH, #0 + + MC1S 0 + MC1S 1 + MC1S 2 + MC1S 3 + MC1S 4 + MC1S 5 + MC1S 6 + MC1S 7 + + ldr PCM, [sp, #4] ; load pcm pointer + mov MAXPOS, #0x7f00 + orr MAXPOS, MAXPOS, #0xff + + C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS + C64TOS SUM1RL, SUM1RH, SIGN, MAXPOS + + strh SUM1LL, [PCM, #(2*(2*16+0))] + strh SUM1RL, [PCM, #(2*(2*16+1))] + + ; main convolution loop: sum1L = samples 1, 2, 3, ... 15 sum2L = samples 31, 30, ... 17 + sub COEF, COEF, #(4*(264-16)) ; coef = coefBase + 16 (was coefBase + 264 after MC1S block) + sub VB1, VB1, #(4*(1024-64)) ; vb1 = vbuf + 64 (was vbuf + 64*16 after MC1S block) + mov I, #15 ; loop counter, count down + add PCM, PCM, #(2*2) ; pcm+=2 + +LoopPS + str I, [sp, #0] ; sp[0] = i (loop counter) + str PCM, [sp, #4] ; sp[1] = pcm (pointer to pcm buffer) + + mov SUM1LL, #RNDVAL ; load rndVal (low 32) + mov SUM1RL, #RNDVAL ; load rndVal (low 32) + mov SUM2LL, #RNDVAL ; load rndVal (low 32) + mov SUM2RL, #RNDVAL ; load rndVal (low 32) + + mov SUM1LH, #0 + mov SUM1RH, #0 + mov SUM2LH, #0 + mov SUM2RH, #0 + + MC2S 0 + MC2S 1 + MC2S 2 + MC2S 3 + MC2S 4 + MC2S 5 + MC2S 6 + MC2S 7 + + add VB1, VB1, #(4*64) ; vb1 += 64 + + ldr PCM, [sp, #4] ; load pcm pointer + mov MAXPOS, #0x7f00 + orr MAXPOS, MAXPOS, #0xff + + C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS + C64TOS SUM1RL, SUM1RH, SIGN, MAXPOS + C64TOS SUM2LL, SUM2LH, SIGN, MAXPOS + C64TOS SUM2RL, SUM2RH, SIGN, MAXPOS + + ldr I, [sp, #0] ; load loop counter + add CF2, PCM, I, lsl #3 ; CF2 = PCM + 4*i (short offset) + strh SUM2LL, [CF2], #2 ; *(pcm + 2*2*i + 0) + strh SUM2RL, [CF2], #2 ; *(pcm + 2*2*i + 1) + + strh SUM1LL, [PCM], #2 ; *(pcm + 0) + strh SUM1RL, [PCM], #2 ; *(pcm + 1) + + subs I, I, #1 + bne LoopPS + + ; restore stack pointer + add sp, sp, #8 + + ldmfd sp!, {r4-r11, pc} + ENDFUNC + +;; MONO PROCESSING + + ; MC0M - process 2 taps, 1 sample (sample 0) + ; x = vb1 offset + MACRO + MC0M $x + + ldr CF1, [COEF], #4 + ldr CF2, [COEF], #4 + ldr VLO, [VB1, #(4*($x))] + ldr VHI, [VB1, #(4*(23 - $x))] + + rsb CF2, CF2, #0 + smlal SUM1LL, SUM1LH, VLO, CF1 + smlal SUM1LL, SUM1LH, VHI, CF2 + + MEND ; MC0M + + ; MC1M - process 2 taps, 1 sample (sample 16) + ; x = vb1 offset + MACRO + MC1M $x + + ldr CF1, [COEF], #4 + ldr VLO, [VB1, #(4*($x))] + smlal SUM1LL, SUM1LH, VLO, CF1 + + MEND ; MC1M + + ; MC2M - process 2 taps, 2 samples + ; x = vb1 offset + MACRO + MC2M $x + + ; load data as far as possible in advance of using it + ldr CF1, [COEF], #4 + ldr CF2, [COEF], #4 + ldr VLO, [VB1, #(4*($x))] + ldr VHI, [VB1, #(4*(23 - $x))] + + smlal SUM1LL, SUM1LH, VLO, CF1 + smlal SUM2LL, SUM2LH, VLO, CF2 + rsb CF2, CF2, #0 + smlal SUM1LL, SUM1LH, VHI, CF2 + smlal SUM2LL, SUM2LH, VHI, CF1 + + MEND ; MC2M + +; void PolyphaseMono(short *pcm, int *vbuf, const int *coefBase) + +xmp3_PolyphaseMono FUNCTION + EXPORT xmp3_PolyphaseMono + + stmfd sp!, {r4-r11, r14} + + ; clear out stack space for 4 local variables (4 bytes each) + sub sp, sp, #8 + str PCM, [sp, #4] ; sp[1] = pcm pointer + + ; special case, output sample 0 + mov SUM1LL, #RNDVAL ; load rndVal (low 32) + mov SUM1LH, #0 + + MC0M 0 + MC0M 1 + MC0M 2 + MC0M 3 + MC0M 4 + MC0M 5 + MC0M 6 + MC0M 7 + + ldr PCM, [sp, #4] ; load pcm pointer + mov MAXPOS, #0x7f00 + orr MAXPOS, MAXPOS, #0xff + + C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS + strh SUM1LL, [PCM, #(2*0)] + + ; special case, output sample 16 + add COEF, COEF, #(4*(256-16)) ; coef = coefBase + 256 (was coefBase + 16 after MC0M block) + add VB1, VB1, #(4*1024) ; vb1 = vbuf + 64*16 + + mov SUM1LL, #RNDVAL ; load rndVal (low 32) + mov SUM1LH, #0 + + MC1M 0 + MC1M 1 + MC1M 2 + MC1M 3 + MC1M 4 + MC1M 5 + MC1M 6 + MC1M 7 + + ldr PCM, [sp, #4] ; load pcm pointer + mov MAXPOS, #0x7f00 + orr MAXPOS, MAXPOS, #0xff + + C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS + + strh SUM1LL, [PCM, #(2*16)] + + ; main convolution loop: sum1L = samples 1, 2, 3, ... 15 sum2L = samples 31, 30, ... 17 + sub COEF, COEF, #(4*(264-16)) ; coef = coefBase + 16 (was coefBase + 264 after MC1M block) + sub VB1, VB1, #(4*(1024-64)) ; vb1 = vbuf + 64 (was vbuf + 64*16 after MC1M block) + mov I, #15 ; loop counter, count down + add PCM, PCM, #(2) ; pcm++ + +LoopPM + str I, [sp, #0] ; sp[0] = i (loop counter) + str PCM, [sp, #4] ; sp[1] = pcm (pointer to pcm buffer) + + mov SUM1LL, #RNDVAL ; load rndVal (low 32) + mov SUM2LL, #RNDVAL ; load rndVal (low 32) + mov SUM1LH, #0 + mov SUM2LH, #0 + + MC2M 0 + MC2M 1 + MC2M 2 + MC2M 3 + MC2M 4 + MC2M 5 + MC2M 6 + MC2M 7 + + add VB1, VB1, #(4*64) ; vb1 += 64 + + ldr PCM, [sp, #4] ; load pcm pointer + mov MAXPOS, #0x7f00 + orr MAXPOS, MAXPOS, #0xff + + C64TOS SUM1LL, SUM1LH, SIGN, MAXPOS + C64TOS SUM2LL, SUM2LH, SIGN, MAXPOS + + ldr I, [sp, #0] ; load loop counter + add CF2, PCM, I, lsl #2 ; CF2 = PCM + 2*i (short offset) + strh SUM2LL, [CF2], #2 ; *(pcm + 2*i + 0) + strh SUM1LL, [PCM], #2 ; *(pcm + 0) ; pcm++ + + subs I, I, #1 + bne LoopPM + + ; restore stack pointer + add sp, sp, #8 + + ldmfd sp!, {r4-r11, pc} + ENDFUNC + + END \ No newline at end of file diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/asmpoly_gcc.S b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/asmpoly_gcc.S new file mode 100644 index 0000000..d02281c --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/arm/asmpoly_gcc.S @@ -0,0 +1,605 @@ +@/* ***** BEGIN LICENSE BLOCK ***** +@ * Version: RCSL 1.0/RPSL 1.0 +@ * +@ * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. +@ * +@ * The contents of this file, and the files included with this file, are +@ * subject to the current version of the RealNetworks Public Source License +@ * Version 1.0 (the "RPSL") available at +@ * http://www.helixcommunity.org/content/rpsl unless you have licensed +@ * the file under the RealNetworks Community Source License Version 1.0 +@ * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, +@ * in which case the RCSL will apply. You may also obtain the license terms +@ * directly from RealNetworks. You may not use this file except in +@ * compliance with the RPSL or, if you have a valid RCSL with RealNetworks +@ * applicable to this file, the RCSL. Please see the applicable RPSL or +@ * RCSL for the rights, obligations and limitations governing use of the +@ * contents of the file. +@ * +@ * This file is part of the Helix DNA Technology. RealNetworks is the +@ * developer of the Original Code and owns the copyrights in the portions +@ * it created. +@ * +@ * This file, and the files included with this file, is distributed and made +@ * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +@ * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, +@ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS +@ * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +@ * +@ * Technology Compatibility Kit Test Suite(s) Location: +@ * http://www.helixcommunity.org/content/tck +@ * +@ * Contributor(s): +@ * +@ * ***** END LICENSE BLOCK ***** */ + +# a lot faster in RAM (1-2 ms per frame) +.data + + .GLOBAL xmp3_PolyphaseStereo +xmp3_PolyphaseStereo: + STMFD r13!,{r4-r11,r14} + SUB r13,r13,#8 + STR r0,[r13,#4] + MOV r4,#0x2000000 + MOV r8,#0x2000000 + MOV r5,#0 + MOV r9,#0 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0] + LDR r3,[r1,#0x5c] + SMLAL r4,r5,r0,r12 + LDR r0,[r1,#0x80] + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xdc] + SMLAL r8,r9,r0,r12 + SMLAL r8,r9,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#4] + LDR r3,[r1,#0x58] + SMLAL r4,r5,r0,r12 + LDR r0,[r1,#0x84] + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xd8] + SMLAL r8,r9,r0,r12 + SMLAL r8,r9,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#8] + LDR r3,[r1,#0x54] + SMLAL r4,r5,r0,r12 + LDR r0,[r1,#0x88] + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xd4] + SMLAL r8,r9,r0,r12 + SMLAL r8,r9,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0xc] + LDR r3,[r1,#0x50] + SMLAL r4,r5,r0,r12 + LDR r0,[r1,#0x8c] + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xd0] + SMLAL r8,r9,r0,r12 + SMLAL r8,r9,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x10] + LDR r3,[r1,#0x4c] + SMLAL r4,r5,r0,r12 + LDR r0,[r1,#0x90] + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xcc] + SMLAL r8,r9,r0,r12 + SMLAL r8,r9,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x14] + LDR r3,[r1,#0x48] + SMLAL r4,r5,r0,r12 + LDR r0,[r1,#0x94] + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xc8] + SMLAL r8,r9,r0,r12 + SMLAL r8,r9,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x18] + LDR r3,[r1,#0x44] + SMLAL r4,r5,r0,r12 + LDR r0,[r1,#0x98] + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xc4] + SMLAL r8,r9,r0,r12 + SMLAL r8,r9,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x1c] + LDR r3,[r1,#0x40] + SMLAL r4,r5,r0,r12 + LDR r0,[r1,#0x9c] + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xc0] + SMLAL r8,r9,r0,r12 + SMLAL r8,r9,r3,r14 + LDR r0,[r13,#4] + MOV r14,#0x7f00 + ORR r14,r14,#0xff + MOV r4,r4,LSR #26 + ORR r4,r4,r5,LSL #6 + MOV r12,r4,ASR #31 + CMP r12,r4,ASR #15 + EORNE r4,r12,r14 + MOV r8,r8,LSR #26 + ORR r8,r8,r9,LSL #6 + MOV r12,r8,ASR #31 + CMP r12,r8,ASR #15 + EORNE r8,r12,r14 + STRH r4,[r0,#0] + STRH r8,[r0,#2] + ADD r2,r2,#0x3c0 + ADD r1,r1,#0x1000 + MOV r4,#0x2000000 + MOV r8,#0x2000000 + MOV r5,#0 + MOV r9,#0 + LDR r12,[r2],#4 + LDR r0,[r1,#0] + LDR r3,[r1,#0x80] + SMLAL r4,r5,r0,r12 + SMLAL r8,r9,r3,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#4] + LDR r3,[r1,#0x84] + SMLAL r4,r5,r0,r12 + SMLAL r8,r9,r3,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#8] + LDR r3,[r1,#0x88] + SMLAL r4,r5,r0,r12 + SMLAL r8,r9,r3,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#0xc] + LDR r3,[r1,#0x8c] + SMLAL r4,r5,r0,r12 + SMLAL r8,r9,r3,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#0x10] + LDR r3,[r1,#0x90] + SMLAL r4,r5,r0,r12 + SMLAL r8,r9,r3,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#0x14] + LDR r3,[r1,#0x94] + SMLAL r4,r5,r0,r12 + SMLAL r8,r9,r3,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#0x18] + LDR r3,[r1,#0x98] + SMLAL r4,r5,r0,r12 + SMLAL r8,r9,r3,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#0x1c] + LDR r3,[r1,#0x9c] + SMLAL r4,r5,r0,r12 + SMLAL r8,r9,r3,r12 + LDR r0,[r13,#4] + MOV r14,#0x7f00 + ORR r14,r14,#0xff + MOV r4,r4,LSR #26 + ORR r4,r4,r5,LSL #6 + MOV r12,r4,ASR #31 + CMP r12,r4,ASR #15 + EORNE r4,r12,r14 + MOV r8,r8,LSR #26 + ORR r8,r8,r9,LSL #6 + MOV r12,r8,ASR #31 + CMP r12,r8,ASR #15 + EORNE r8,r12,r14 + STRH r4,[r0,#0x40] + STRH r8,[r0,#0x42] + SUB r2,r2,#0x3e0 + SUB r1,r1,#0xf00 + MOV r12,#0xf + ADD r0,r0,#4 +LoopPS: + STR r12,[r13,#0] + STR r0,[r13,#4] + MOV r4,#0x2000000 + MOV r8,#0x2000000 + MOV r6,#0x2000000 + MOV r10,#0x2000000 + MOV r5,#0 + MOV r9,#0 + MOV r7,#0 + MOV r11,#0 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0] + LDR r3,[r1,#0x5c] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r6,r7,r3,r12 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xdc] + LDR r0,[r1,#0x80] + SMLAL r8,r9,r3,r14 + SMLAL r10,r11,r3,r12 + RSB r14,r14,#0 + SMLAL r8,r9,r0,r12 + SMLAL r10,r11,r0,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#4] + LDR r3,[r1,#0x58] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r6,r7,r3,r12 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xd8] + LDR r0,[r1,#0x84] + SMLAL r8,r9,r3,r14 + SMLAL r10,r11,r3,r12 + RSB r14,r14,#0 + SMLAL r8,r9,r0,r12 + SMLAL r10,r11,r0,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#8] + LDR r3,[r1,#0x54] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r6,r7,r3,r12 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xd4] + LDR r0,[r1,#0x88] + SMLAL r8,r9,r3,r14 + SMLAL r10,r11,r3,r12 + RSB r14,r14,#0 + SMLAL r8,r9,r0,r12 + SMLAL r10,r11,r0,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0xc] + LDR r3,[r1,#0x50] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r6,r7,r3,r12 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xd0] + LDR r0,[r1,#0x8c] + SMLAL r8,r9,r3,r14 + SMLAL r10,r11,r3,r12 + RSB r14,r14,#0 + SMLAL r8,r9,r0,r12 + SMLAL r10,r11,r0,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x10] + LDR r3,[r1,#0x4c] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r6,r7,r3,r12 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xcc] + LDR r0,[r1,#0x90] + SMLAL r8,r9,r3,r14 + SMLAL r10,r11,r3,r12 + RSB r14,r14,#0 + SMLAL r8,r9,r0,r12 + SMLAL r10,r11,r0,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x14] + LDR r3,[r1,#0x48] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r6,r7,r3,r12 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xc8] + LDR r0,[r1,#0x94] + SMLAL r8,r9,r3,r14 + SMLAL r10,r11,r3,r12 + RSB r14,r14,#0 + SMLAL r8,r9,r0,r12 + SMLAL r10,r11,r0,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x18] + LDR r3,[r1,#0x44] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r6,r7,r3,r12 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xc4] + LDR r0,[r1,#0x98] + SMLAL r8,r9,r3,r14 + SMLAL r10,r11,r3,r12 + RSB r14,r14,#0 + SMLAL r8,r9,r0,r12 + SMLAL r10,r11,r0,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x1c] + LDR r3,[r1,#0x40] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r6,r7,r3,r12 + SMLAL r4,r5,r3,r14 + LDR r3,[r1,#0xc0] + LDR r0,[r1,#0x9c] + SMLAL r8,r9,r3,r14 + SMLAL r10,r11,r3,r12 + RSB r14,r14,#0 + SMLAL r8,r9,r0,r12 + SMLAL r10,r11,r0,r14 + ADD r1,r1,#0x100 + LDR r0,[r13,#4] + MOV r14,#0x7f00 + ORR r14,r14,#0xff + MOV r4,r4,LSR #26 + ORR r4,r4,r5,LSL #6 + MOV r12,r4,ASR #31 + CMP r12,r4,ASR #15 + EORNE r4,r12,r14 + MOV r8,r8,LSR #26 + ORR r8,r8,r9,LSL #6 + MOV r12,r8,ASR #31 + CMP r12,r8,ASR #15 + EORNE r8,r12,r14 + MOV r6,r6,LSR #26 + ORR r6,r6,r7,LSL #6 + MOV r12,r6,ASR #31 + CMP r12,r6,ASR #15 + EORNE r6,r12,r14 + MOV r10,r10,LSR #26 + ORR r10,r10,r11,LSL #6 + MOV r12,r10,ASR #31 + CMP r12,r10,ASR #15 + EORNE r10,r12,r14 + LDR r12,[r13,#0] + ADD r14,r0,r12,LSL #3 + STRH r6,[r14],#2 + STRH r10,[r14],#2 + STRH r4,[r0],#2 + STRH r8,[r0],#2 + SUBS r12,r12,#1 + BNE LoopPS + ADD r13,r13,#8 + LDMFD r13!,{r4-r11,pc} + + .GLOBAL xmp3_PolyphaseMono +xmp3_PolyphaseMono: + STMFD r13!,{r4-r11,r14} + SUB r13,r13,#8 + STR r0,[r13,#4] + MOV r4,#0x2000000 + MOV r5,#0 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0] + LDR r3,[r1,#0x5c] + RSB r14,r14,#0 + SMLAL r4,r5,r0,r12 + SMLAL r4,r5,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#4] + LDR r3,[r1,#0x58] + RSB r14,r14,#0 + SMLAL r4,r5,r0,r12 + SMLAL r4,r5,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#8] + LDR r3,[r1,#0x54] + RSB r14,r14,#0 + SMLAL r4,r5,r0,r12 + SMLAL r4,r5,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0xc] + LDR r3,[r1,#0x50] + RSB r14,r14,#0 + SMLAL r4,r5,r0,r12 + SMLAL r4,r5,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x10] + LDR r3,[r1,#0x4c] + RSB r14,r14,#0 + SMLAL r4,r5,r0,r12 + SMLAL r4,r5,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x14] + LDR r3,[r1,#0x48] + RSB r14,r14,#0 + SMLAL r4,r5,r0,r12 + SMLAL r4,r5,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x18] + LDR r3,[r1,#0x44] + RSB r14,r14,#0 + SMLAL r4,r5,r0,r12 + SMLAL r4,r5,r3,r14 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x1c] + LDR r3,[r1,#0x40] + RSB r14,r14,#0 + SMLAL r4,r5,r0,r12 + SMLAL r4,r5,r3,r14 + LDR r0,[r13,#4] + MOV r14,#0x7f00 + ORR r14,r14,#0xff + MOV r4,r4,LSR #26 + ORR r4,r4,r5,LSL #6 + MOV r12,r4,ASR #31 + CMP r12,r4,ASR #15 + EORNE r4,r12,r14 + STRH r4,[r0,#0] + ADD r2,r2,#0x3c0 + ADD r1,r1,#0x1000 + MOV r4,#0x2000000 + MOV r5,#0 + LDR r12,[r2],#4 + LDR r0,[r1,#0] + SMLAL r4,r5,r0,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#4] + SMLAL r4,r5,r0,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#8] + SMLAL r4,r5,r0,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#0xc] + SMLAL r4,r5,r0,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#0x10] + SMLAL r4,r5,r0,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#0x14] + SMLAL r4,r5,r0,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#0x18] + SMLAL r4,r5,r0,r12 + LDR r12,[r2],#4 + LDR r0,[r1,#0x1c] + SMLAL r4,r5,r0,r12 + LDR r0,[r13,#4] + MOV r14,#0x7f00 + ORR r14,r14,#0xff + MOV r4,r4,LSR #26 + ORR r4,r4,r5,LSL #6 + MOV r12,r4,ASR #31 + CMP r12,r4,ASR #15 + EORNE r4,r12,r14 + STRH r4,[r0,#0x20] + SUB r2,r2,#0x3e0 + SUB r1,r1,#0xf00 + MOV r12,#0xf + ADD r0,r0,#2 +LoopPM: + STR r12,[r13,#0] + STR r0,[r13,#4] + MOV r4,#0x2000000 + MOV r6,#0x2000000 + MOV r5,#0 + MOV r7,#0 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0] + LDR r3,[r1,#0x5c] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + SMLAL r6,r7,r3,r12 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#4] + LDR r3,[r1,#0x58] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + SMLAL r6,r7,r3,r12 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#8] + LDR r3,[r1,#0x54] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + SMLAL r6,r7,r3,r12 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0xc] + LDR r3,[r1,#0x50] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + SMLAL r6,r7,r3,r12 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x10] + LDR r3,[r1,#0x4c] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + SMLAL r6,r7,r3,r12 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x14] + LDR r3,[r1,#0x48] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + SMLAL r6,r7,r3,r12 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x18] + LDR r3,[r1,#0x44] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + SMLAL r6,r7,r3,r12 + LDR r12,[r2],#4 + LDR r14,[r2],#4 + LDR r0,[r1,#0x1c] + LDR r3,[r1,#0x40] + SMLAL r4,r5,r0,r12 + SMLAL r6,r7,r0,r14 + RSB r14,r14,#0 + SMLAL r4,r5,r3,r14 + SMLAL r6,r7,r3,r12 + ADD r1,r1,#0x100 + LDR r0,[r13,#4] + MOV r14,#0x7f00 + ORR r14,r14,#0xff + MOV r4,r4,LSR #26 + ORR r4,r4,r5,LSL #6 + MOV r12,r4,ASR #31 + CMP r12,r4,ASR #15 + EORNE r4,r12,r14 + MOV r6,r6,LSR #26 + ORR r6,r6,r7,LSL #6 + MOV r12,r6,ASR #31 + CMP r12,r6,ASR #15 + EORNE r6,r12,r14 + LDR r12,[r13,#0] + ADD r14,r0,r12,LSL #2 + STRH r6,[r14],#2 + STRH r4,[r0],#2 + SUBS r12,r12,#1 + BNE LoopPM + ADD r13,r13,#8 + LDMFD r13!,{r4-r11,pc} + + .END diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/assembly.h b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/assembly.h new file mode 100644 index 0000000..1f17ef1 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/assembly.h @@ -0,0 +1,486 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * assembly.h - assembly language functions and prototypes for supported platforms + * + * - inline rountines with access to 64-bit multiply results + * - x86 (_WIN32) and ARM (ARM_ADS, _WIN32_WCE) versions included + * - some inline functions are mix of asm and C for speed + * - some functions are in native asm files, so only the prototype is given here + * + * MULSHIFT32(x, y) signed multiply of two 32-bit integers (x and y), returns top 32 bits of 64-bit result + * FASTABS(x) branchless absolute value of signed integer x + * CLZ(x) count leading zeros in x + * MADD64(sum, x, y) (Windows only) sum [64-bit] += x [32-bit] * y [32-bit] + * SHL64(sum, x, y) (Windows only) 64-bit left shift using __int64 + * SAR64(sum, x, y) (Windows only) 64-bit right shift using __int64 + */ + +#ifndef _ASSEMBLY_H +#define _ASSEMBLY_H + +#if (defined _WIN32 && !defined _WIN32_WCE) || (defined __WINS__ && defined _SYMBIAN) || defined(_OPENWAVE_SIMULATOR) || defined(WINCE_EMULATOR) /* Symbian emulator for Ix86 */ + +#pragma warning( disable : 4035 ) /* complains about inline asm not returning a value */ + +static __inline int MULSHIFT32(int x, int y) +{ + __asm { + mov eax, x + imul y + mov eax, edx + } +} + +static __inline int FASTABS(int x) +{ + int sign; + + sign = x >> (sizeof(int) * 8 - 1); + x ^= sign; + x -= sign; + + return x; +} + +static __inline int CLZ(int x) +{ + int numZeros; + + if (!x) + return (sizeof(int) * 8); + + numZeros = 0; + while (!(x & 0x80000000)) { + numZeros++; + x <<= 1; + } + + return numZeros; +} + +/* MADD64, SHL64, SAR64: + * write in assembly to avoid dependency on run-time lib for 64-bit shifts, muls + * (sometimes compiler thunks to function calls instead of code generating) + * required for Symbian emulator + */ +#ifdef __CW32__ +typedef long long Word64; +#else +typedef __int64 Word64; +#endif + +static __inline Word64 MADD64(Word64 sum, int x, int y) +{ + unsigned int sumLo = ((unsigned int *)&sum)[0]; + int sumHi = ((int *)&sum)[1]; + + __asm { + mov eax, x + imul y + add eax, sumLo + adc edx, sumHi + } + + /* equivalent to return (sum + ((__int64)x * y)); */ +} + +static __inline Word64 SHL64(Word64 x, int n) +{ + unsigned int xLo = ((unsigned int *)&x)[0]; + int xHi = ((int *)&x)[1]; + unsigned char nb = (unsigned char)n; + + if (n < 32) { + __asm { + mov edx, xHi + mov eax, xLo + mov cl, nb + shld edx, eax, cl + shl eax, cl + } + } else if (n < 64) { + /* shl masks cl to 0x1f */ + __asm { + mov edx, xLo + mov cl, nb + xor eax, eax + shl edx, cl + } + } else { + __asm { + xor edx, edx + xor eax, eax + } + } +} + +static __inline Word64 SAR64(Word64 x, int n) +{ + unsigned int xLo = ((unsigned int *)&x)[0]; + int xHi = ((int *)&x)[1]; + unsigned char nb = (unsigned char)n; + + if (n < 32) { + __asm { + mov edx, xHi + mov eax, xLo + mov cl, nb + shrd eax, edx, cl + sar edx, cl + } + } else if (n < 64) { + /* sar masks cl to 0x1f */ + __asm { + mov edx, xHi + mov eax, xHi + mov cl, nb + sar edx, 31 + sar eax, cl + } + } else { + __asm { + sar xHi, 31 + mov eax, xHi + mov edx, xHi + } + } +} + +#elif (defined _WIN32) && (defined _WIN32_WCE) + +/* use asm function for now (EVC++ 3.0 does horrible job compiling __int64 version) */ +#define MULSHIFT32 xmp3_MULSHIFT32 +int MULSHIFT32(int x, int y); + +static __inline int FASTABS(int x) +{ + int sign; + + sign = x >> (sizeof(int) * 8 - 1); + x ^= sign; + x -= sign; + + return x; +} + +static __inline int CLZ(int x) +{ + int numZeros; + + if (!x) + return (sizeof(int) * 8); + + numZeros = 0; + while (!(x & 0x80000000)) { + numZeros++; + x <<= 1; + } + + return numZeros; +} + +#elif defined ARM_ADS + +static __inline int MULSHIFT32(int x, int y) +{ + /* important rules for smull RdLo, RdHi, Rm, Rs: + * RdHi and Rm can't be the same register + * RdLo and Rm can't be the same register + * RdHi and RdLo can't be the same register + * Note: Rs determines early termination (leading sign bits) so if you want to specify + * which operand is Rs, put it in the SECOND argument (y) + * For inline assembly, x and y are not assumed to be R0, R1 so it shouldn't matter + * which one is returned. (If this were a function call, returning y (R1) would + * require an extra "mov r0, r1") + */ + int zlow; + __asm { + smull zlow,y,x,y + } + + return y; +} + +static __inline int FASTABS(int x) +{ + int t=0; /*Really is not necessary to initialiaze only to avoid warning*/ + + __asm { + eor t, x, x, asr #31 + sub t, t, x, asr #31 + } + + return t; +} + +static __inline int CLZ(int x) +{ + int numZeros; + + if (!x) + return (sizeof(int) * 8); + + numZeros = 0; + while (!(x & 0x80000000)) { + numZeros++; + x <<= 1; + } + + return numZeros; +} + +#elif defined(__GNUC__) && defined(ARM) + +#if defined(ARM7DI) + +typedef long long Word64; + +static __inline int MULSHIFT32(int x, int y) { + return x * y; +} + +static __inline Word64 SAR64(Word64 x, int n) { + return x >>= n; +} + + +typedef union _U64 { + Word64 w64; + struct { + /* x86 = little endian */ + unsigned int lo32; + signed int hi32; + } r; +} U64; + +static __inline Word64 MADD64(Word64 sum64, int x, int y) +{ + sum64 += (Word64)x * (Word64)y; + + return sum64; +} + +#else + +static __inline int MULSHIFT32(int x, int y) +{ + /* important rules for smull RdLo, RdHi, Rm, Rs: + * RdHi and Rm can't be the same register + * RdLo and Rm can't be the same register + * RdHi and RdLo can't be the same register + * Note: Rs determines early termination (leading sign bits) so if you want to specify + * which operand is Rs, put it in the SECOND argument (y) + * For inline assembly, x and y are not assumed to be R0, R1 so it shouldn't matter + * which one is returned. (If this were a function call, returning y (R1) would + * require an extra "mov r0, r1") + */ + int zlow; + __asm__ volatile ("smull %0,%1,%2,%3" : "=&r" (zlow), "=r" (y) : "r" (x), "1" (y)) ; + + return y; +} + +#endif + +static __inline int FASTABS(int x) +{ + int t=0; /*Really is not necessary to initialiaze only to avoid warning*/ + + __asm__ volatile ( + "eor %0,%2,%2, asr #31;" + "sub %0,%1,%2, asr #31;" + : "=&r" (t) + : "0" (t), "r" (x) + ); + + return t; +} + +static __inline int CLZ(int x) +{ + int numZeros; + + if (!x) + return (sizeof(int) * 8); + + numZeros = 0; + while (!(x & 0x80000000)) { + numZeros++; + x <<= 1; + } + + return numZeros; +} + +#else + +#ifdef __riscv + +typedef long long Word64; + +static __inline int MULSHIFT32(int x, int y) +{ + unsigned int result = 0; + asm volatile ("mulh %0, %1, %2" : "=r"(result): "r"(x), "r"(y)); + return result; +} + +static __inline int FASTABS(int x) +{ + int sign; + + sign = x >> (sizeof(int) * 8 - 1); + x ^= sign; + x -= sign; + + return x; +} + +static __inline int CLZ(int x) +{ + int numZeros; + + if (!x) + return (sizeof(int) * 8); + + numZeros = 0; + while (!(x & 0x80000000)) { + numZeros++; + x <<= 1; + } + + return numZeros; +} + +static __inline Word64 MADD64(Word64 sum, int a, int b) +{ + unsigned int result_hi = 0; + unsigned int result_lo = 0; + asm volatile ("mulh %0, %1, %2" : "=r"(result_hi): "r"(a), "r"(b)); + asm volatile ("mul %0, %1, %2" : "=r"(result_lo): "r"(a), "r"(b)); + + Word64 result = result_hi; + result <<= 32; + result += result_lo; + result += sum; + return result; +} + +static __inline Word64 SHL64(Word64 x, int n) +{ + return (x<> n); +} + +#elif defined(__xtensa__) + +#include "xtensa/config/core-isa.h" + +typedef long long Word64; + +static __inline Word64 MADD64(Word64 sum64, int x, int y) +{ + return (sum64 + ((long long)x * y)); +} + +#if XCHAL_HAVE_MUL32_HIGH + +static __inline int MULSHIFT32(int x, int y) +{ + /* important rules for smull RdLo, RdHi, Rm, Rs: + * RdHi and Rm can't be the same register + * RdLo and Rm can't be the same register + * RdHi and RdLo can't be the same register + * Note: Rs determines early termination (leading sign bits) so if you want to specify + * which operand is Rs, put it in the SECOND argument (y) + * For inline assembly, x and y are not assumed to be R0, R1 so it shouldn't matter + * which one is returned. (If this were a function call, returning y (R1) would + * require an extra "mov r0, r1") + */ + int ret; + asm volatile ("mulsh %0, %1, %2" : "=r" (ret) : "r" (x), "r" (y)); + return ret; +} + +#else + +#error Missing definition of MULSHIFT32 + +#endif + +#if XCHAL_HAVE_ABS + +static __inline int FASTABS(int x) +{ + int ret; + asm volatile ("abs %0, %1" : "=r" (ret) : "r" (x)); + return ret; +} + +#else + +#error Missing definition of FASTABS + +#endif + +static __inline Word64 SAR64(Word64 x, int n) +{ + return x >> n; +} + +static __inline int CLZ(int x) +{ + return __builtin_clz(x); +} + +#else + +#error Unsupported platform in assembly.h + +#endif + +#endif /* platforms */ + +#endif /* _ASSEMBLY_H */ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/bitstream.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/bitstream.c new file mode 100644 index 0000000..608c39c --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/bitstream.c @@ -0,0 +1,389 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * bitstream.c - bitstream unpacking, frame header parsing, side info parsing + **************************************************************************************/ + +#include "coder.h" +#include "assembly.h" + +/************************************************************************************** + * Function: SetBitstreamPointer + * + * Description: initialize bitstream reader + * + * Inputs: pointer to BitStreamInfo struct + * number of bytes in bitstream + * pointer to byte-aligned buffer of data to read from + * + * Outputs: filled bitstream info struct + * + * Return: none + **************************************************************************************/ +void SetBitstreamPointer(BitStreamInfo *bsi, int nBytes, unsigned char *buf) +{ + /* init bitstream */ + bsi->bytePtr = buf; + bsi->iCache = 0; /* 4-byte unsigned int */ + bsi->cachedBits = 0; /* i.e. zero bits in cache */ + bsi->nBytes = nBytes; +} + +/************************************************************************************** + * Function: RefillBitstreamCache + * + * Description: read new data from bitstream buffer into bsi cache + * + * Inputs: pointer to initialized BitStreamInfo struct + * + * Outputs: updated bitstream info struct + * + * Return: none + * + * Notes: only call when iCache is completely drained (resets bitOffset to 0) + * always loads 4 new bytes except when bsi->nBytes < 4 (end of buffer) + * stores data as big-endian in cache, regardless of machine endian-ness + * + * TODO: optimize for ARM + * possibly add little/big-endian modes for doing 32-bit loads + **************************************************************************************/ +static __inline void RefillBitstreamCache(BitStreamInfo *bsi) +{ + int nBytes = bsi->nBytes; + + /* optimize for common case, independent of machine endian-ness */ + if (nBytes >= 4) { + bsi->iCache = (*bsi->bytePtr++) << 24; + bsi->iCache |= (*bsi->bytePtr++) << 16; + bsi->iCache |= (*bsi->bytePtr++) << 8; + bsi->iCache |= (*bsi->bytePtr++); + bsi->cachedBits = 32; + bsi->nBytes -= 4; + } else { + bsi->iCache = 0; + while (nBytes--) { + bsi->iCache |= (*bsi->bytePtr++); + bsi->iCache <<= 8; + } + bsi->iCache <<= ((3 - bsi->nBytes)*8); + bsi->cachedBits = 8*bsi->nBytes; + bsi->nBytes = 0; + } +} + +/************************************************************************************** + * Function: GetBits + * + * Description: get bits from bitstream, advance bitstream pointer + * + * Inputs: pointer to initialized BitStreamInfo struct + * number of bits to get from bitstream + * + * Outputs: updated bitstream info struct + * + * Return: the next nBits bits of data from bitstream buffer + * + * Notes: nBits must be in range [0, 31], nBits outside this range masked by 0x1f + * for speed, does not indicate error if you overrun bit buffer + * if nBits = 0, returns 0 (useful for scalefactor unpacking) + * + * TODO: optimize for ARM + **************************************************************************************/ +unsigned int GetBits(BitStreamInfo *bsi, int nBits) +{ + unsigned int data, lowBits; + + nBits &= 0x1f; /* nBits mod 32 to avoid unpredictable results like >> by negative amount */ + data = bsi->iCache >> (31 - nBits); /* unsigned >> so zero-extend */ + data >>= 1; /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */ + bsi->iCache <<= nBits; /* left-justify cache */ + bsi->cachedBits -= nBits; /* how many bits have we drawn from the cache so far */ + + /* if we cross an int boundary, refill the cache */ + if (bsi->cachedBits < 0) { + lowBits = -bsi->cachedBits; + RefillBitstreamCache(bsi); + data |= bsi->iCache >> (32 - lowBits); /* get the low-order bits */ + + bsi->cachedBits -= lowBits; /* how many bits have we drawn from the cache so far */ + bsi->iCache <<= lowBits; /* left-justify cache */ + } + + return data; +} + +/************************************************************************************** + * Function: CalcBitsUsed + * + * Description: calculate how many bits have been read from bitstream + * + * Inputs: pointer to initialized BitStreamInfo struct + * pointer to start of bitstream buffer + * bit offset into first byte of startBuf (0-7) + * + * Outputs: none + * + * Return: number of bits read from bitstream, as offset from startBuf:startOffset + **************************************************************************************/ +int CalcBitsUsed(BitStreamInfo *bsi, unsigned char *startBuf, int startOffset) +{ + int bitsUsed; + + bitsUsed = (bsi->bytePtr - startBuf) * 8; + bitsUsed -= bsi->cachedBits; + bitsUsed -= startOffset; + + return bitsUsed; +} + +/************************************************************************************** + * Function: CheckPadBit + * + * Description: check whether padding byte is present in an MP3 frame + * + * Inputs: MP3DecInfo struct with valid FrameHeader struct + * (filled by UnpackFrameHeader()) + * + * Outputs: none + * + * Return: 1 if pad bit is set, 0 if not, -1 if null input pointer + **************************************************************************************/ +int CheckPadBit(MP3DecInfo *mp3DecInfo) +{ + FrameHeader *fh; + + /* validate pointers */ + if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS) + return -1; + + fh = ((FrameHeader *)(mp3DecInfo->FrameHeaderPS)); + + return (fh->paddingBit ? 1 : 0); +} + +/************************************************************************************** + * Function: UnpackFrameHeader + * + * Description: parse the fields of the MP3 frame header + * + * Inputs: buffer pointing to a complete MP3 frame header (4 bytes, plus 2 if CRC) + * + * Outputs: filled frame header info in the MP3DecInfo structure + * updated platform-specific FrameHeader struct + * + * Return: length (in bytes) of frame header (for caller to calculate offset to + * first byte following frame header) + * -1 if null frameHeader or invalid header + * + * TODO: check for valid modes, depending on capabilities of decoder + * test CRC on actual stream (verify no endian problems) + **************************************************************************************/ +int UnpackFrameHeader(MP3DecInfo *mp3DecInfo, unsigned char *buf) +{ + + int verIdx; + FrameHeader *fh; + + /* validate pointers and sync word */ + if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS || (buf[0] & SYNCWORDH) != SYNCWORDH || (buf[1] & SYNCWORDL) != SYNCWORDL) + return -1; + + fh = ((FrameHeader *)(mp3DecInfo->FrameHeaderPS)); + + /* read header fields - use bitmasks instead of GetBits() for speed, since format never varies */ + verIdx = (buf[1] >> 3) & 0x03; + fh->ver = (MPEGVersion)( verIdx == 0 ? MPEG25 : ((verIdx & 0x01) ? MPEG1 : MPEG2) ); + fh->layer = 4 - ((buf[1] >> 1) & 0x03); /* easy mapping of index to layer number, 4 = error */ + fh->crc = 1 - ((buf[1] >> 0) & 0x01); + fh->brIdx = (buf[2] >> 4) & 0x0f; + fh->srIdx = (buf[2] >> 2) & 0x03; + fh->paddingBit = (buf[2] >> 1) & 0x01; + fh->privateBit = (buf[2] >> 0) & 0x01; + fh->sMode = (StereoMode)((buf[3] >> 6) & 0x03); /* maps to correct enum (see definition) */ + fh->modeExt = (buf[3] >> 4) & 0x03; + fh->copyFlag = (buf[3] >> 3) & 0x01; + fh->origFlag = (buf[3] >> 2) & 0x01; + fh->emphasis = (buf[3] >> 0) & 0x03; + + /* check parameters to avoid indexing tables with bad values */ + if (fh->srIdx == 3 || fh->layer == 4 || fh->brIdx == 15) + return -1; + + fh->sfBand = &sfBandTable[fh->ver][fh->srIdx]; /* for readability (we reference sfBandTable many times in decoder) */ + if (fh->sMode != Joint) /* just to be safe (dequant, stproc check fh->modeExt) */ + fh->modeExt = 0; + + /* init user-accessible data */ + mp3DecInfo->nChans = (fh->sMode == Mono ? 1 : 2); + mp3DecInfo->samprate = samplerateTab[fh->ver][fh->srIdx]; + mp3DecInfo->nGrans = (fh->ver == MPEG1 ? NGRANS_MPEG1 : NGRANS_MPEG2); + mp3DecInfo->nGranSamps = ((int)samplesPerFrameTab[fh->ver][fh->layer - 1]) / mp3DecInfo->nGrans; + mp3DecInfo->layer = fh->layer; + mp3DecInfo->version = fh->ver; + + /* get bitrate and nSlots from table, unless brIdx == 0 (free mode) in which case caller must figure it out himself + * question - do we want to overwrite mp3DecInfo->bitrate with 0 each time if it's free mode, and + * copy the pre-calculated actual free bitrate into it in mp3dec.c (according to the spec, + * this shouldn't be necessary, since it should be either all frames free or none free) + */ + if (fh->brIdx) { + mp3DecInfo->bitrate = ((int)bitrateTab[fh->ver][fh->layer - 1][fh->brIdx]) * 1000; + + /* nSlots = total frame bytes (from table) - sideInfo bytes - header - CRC (if present) + pad (if present) */ + mp3DecInfo->nSlots = (int)slotTab[fh->ver][fh->srIdx][fh->brIdx] - + (int)sideBytesTab[fh->ver][(fh->sMode == Mono ? 0 : 1)] - + 4 - (fh->crc ? 2 : 0) + (fh->paddingBit ? 1 : 0); + } + + /* load crc word, if enabled, and return length of frame header (in bytes) */ + if (fh->crc) { + fh->CRCWord = ((int)buf[4] << 8 | (int)buf[5] << 0); + return 6; + } else { + fh->CRCWord = 0; + return 4; + } +} + +/************************************************************************************** + * Function: UnpackSideInfo + * + * Description: parse the fields of the MP3 side info header + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader() + * buffer pointing to the MP3 side info data + * + * Outputs: updated mainDataBegin in MP3DecInfo struct + * updated private (platform-specific) SideInfo struct + * + * Return: length (in bytes) of side info data + * -1 if null input pointers + **************************************************************************************/ +int UnpackSideInfo(MP3DecInfo *mp3DecInfo, unsigned char *buf) +{ + int gr, ch, bd, nBytes; + BitStreamInfo bitStreamInfo, *bsi; + FrameHeader *fh; + SideInfo *si; + SideInfoSub *sis; + + /* validate pointers and sync word */ + if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS || !mp3DecInfo->SideInfoPS) + return -1; + + fh = ((FrameHeader *)(mp3DecInfo->FrameHeaderPS)); + si = ((SideInfo *)(mp3DecInfo->SideInfoPS)); + + bsi = &bitStreamInfo; + if (fh->ver == MPEG1) { + /* MPEG 1 */ + nBytes = (fh->sMode == Mono ? SIBYTES_MPEG1_MONO : SIBYTES_MPEG1_STEREO); + SetBitstreamPointer(bsi, nBytes, buf); + si->mainDataBegin = GetBits(bsi, 9); + si->privateBits = GetBits(bsi, (fh->sMode == Mono ? 5 : 3)); + + for (ch = 0; ch < mp3DecInfo->nChans; ch++) + for (bd = 0; bd < MAX_SCFBD; bd++) + si->scfsi[ch][bd] = GetBits(bsi, 1); + } else { + /* MPEG 2, MPEG 2.5 */ + nBytes = (fh->sMode == Mono ? SIBYTES_MPEG2_MONO : SIBYTES_MPEG2_STEREO); + SetBitstreamPointer(bsi, nBytes, buf); + si->mainDataBegin = GetBits(bsi, 8); + si->privateBits = GetBits(bsi, (fh->sMode == Mono ? 1 : 2)); + } + + for(gr =0; gr < mp3DecInfo->nGrans; gr++) { + for (ch = 0; ch < mp3DecInfo->nChans; ch++) { + sis = &si->sis[gr][ch]; /* side info subblock for this granule, channel */ + + sis->part23Length = GetBits(bsi, 12); + sis->nBigvals = GetBits(bsi, 9); + sis->globalGain = GetBits(bsi, 8); + sis->sfCompress = GetBits(bsi, (fh->ver == MPEG1 ? 4 : 9)); + sis->winSwitchFlag = GetBits(bsi, 1); + + if(sis->winSwitchFlag) { + /* this is a start, stop, short, or mixed block */ + sis->blockType = GetBits(bsi, 2); /* 0 = normal, 1 = start, 2 = short, 3 = stop */ + sis->mixedBlock = GetBits(bsi, 1); /* 0 = not mixed, 1 = mixed */ + sis->tableSelect[0] = GetBits(bsi, 5); + sis->tableSelect[1] = GetBits(bsi, 5); + sis->tableSelect[2] = 0; /* unused */ + sis->subBlockGain[0] = GetBits(bsi, 3); + sis->subBlockGain[1] = GetBits(bsi, 3); + sis->subBlockGain[2] = GetBits(bsi, 3); + + /* TODO - check logic */ + if (sis->blockType == 0) { + /* this should not be allowed, according to spec */ + sis->nBigvals = 0; + sis->part23Length = 0; + sis->sfCompress = 0; + } else if (sis->blockType == 2 && sis->mixedBlock == 0) { + /* short block, not mixed */ + sis->region0Count = 8; + } else { + /* start, stop, or short-mixed */ + sis->region0Count = 7; + } + sis->region1Count = 20 - sis->region0Count; + } else { + /* this is a normal block */ + sis->blockType = 0; + sis->mixedBlock = 0; + sis->tableSelect[0] = GetBits(bsi, 5); + sis->tableSelect[1] = GetBits(bsi, 5); + sis->tableSelect[2] = GetBits(bsi, 5); + sis->region0Count = GetBits(bsi, 4); + sis->region1Count = GetBits(bsi, 3); + } + sis->preFlag = (fh->ver == MPEG1 ? GetBits(bsi, 1) : 0); + sis->sfactScale = GetBits(bsi, 1); + sis->count1TableSelect = GetBits(bsi, 1); + } + } + mp3DecInfo->mainDataBegin = si->mainDataBegin; /* needed by main decode loop */ + + ASSERT(nBytes == CalcBitsUsed(bsi, buf, 0) >> 3); + + return nBytes; +} + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/buffers.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/buffers.c new file mode 100644 index 0000000..25ad7ad --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/buffers.c @@ -0,0 +1,172 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * buffers.c - allocation and freeing of internal MP3 decoder buffers + * + * All memory allocation for the codec is done in this file, so if you don't want + * to use other the default system malloc() and free() for heap management this is + * the only file you'll need to change. + **************************************************************************************/ + +//#include "hlxclib/stdlib.h" /* for malloc, free */ +#include +#include +#include "coder.h" + +/************************************************************************************** + * Function: ClearBuffer + * + * Description: fill buffer with 0's + * + * Inputs: pointer to buffer + * number of bytes to fill with 0 + * + * Outputs: cleared buffer + * + * Return: none + * + * Notes: slow, platform-independent equivalent to memset(buf, 0, nBytes) + **************************************************************************************/ +static void ClearBuffer(void *buf, int nBytes) +{ + int i; + unsigned char *cbuf = (unsigned char *)buf; + + for (i = 0; i < nBytes; i++) + cbuf[i] = 0; + + return; +} + +/************************************************************************************** + * Function: AllocateBuffers + * + * Description: allocate all the memory needed for the MP3 decoder + * + * Inputs: none + * + * Outputs: none + * + * Return: pointer to MP3DecInfo structure (initialized with pointers to all + * the internal buffers needed for decoding, all other members of + * MP3DecInfo structure set to 0) + * + * Notes: if one or more mallocs fail, function frees any buffers already + * allocated before returning + **************************************************************************************/ +MP3DecInfo *AllocateBuffers(void) +{ + MP3DecInfo *mp3DecInfo; + FrameHeader *fh; + SideInfo *si; + ScaleFactorInfo *sfi; + HuffmanInfo *hi; + DequantInfo *di; + IMDCTInfo *mi; + SubbandInfo *sbi; + + mp3DecInfo = (MP3DecInfo *)malloc(sizeof(MP3DecInfo)); + if (!mp3DecInfo) + return 0; + ClearBuffer(mp3DecInfo, sizeof(MP3DecInfo)); + + fh = (FrameHeader *) malloc(sizeof(FrameHeader)); + si = (SideInfo *) malloc(sizeof(SideInfo)); + sfi = (ScaleFactorInfo *) malloc(sizeof(ScaleFactorInfo)); + hi = (HuffmanInfo *) malloc(sizeof(HuffmanInfo)); + di = (DequantInfo *) malloc(sizeof(DequantInfo)); + mi = (IMDCTInfo *) malloc(sizeof(IMDCTInfo)); + sbi = (SubbandInfo *) malloc(sizeof(SubbandInfo)); + + mp3DecInfo->FrameHeaderPS = (void *)fh; + mp3DecInfo->SideInfoPS = (void *)si; + mp3DecInfo->ScaleFactorInfoPS = (void *)sfi; + mp3DecInfo->HuffmanInfoPS = (void *)hi; + mp3DecInfo->DequantInfoPS = (void *)di; + mp3DecInfo->IMDCTInfoPS = (void *)mi; + mp3DecInfo->SubbandInfoPS = (void *)sbi; + + if (!fh || !si || !sfi || !hi || !di || !mi || !sbi) { + FreeBuffers(mp3DecInfo); /* safe to call - only frees memory that was successfully allocated */ + return 0; + } + + /* important to do this - DSP primitives assume a bunch of state variables are 0 on first use */ + ClearBuffer(fh, sizeof(FrameHeader)); + ClearBuffer(si, sizeof(SideInfo)); + ClearBuffer(sfi, sizeof(ScaleFactorInfo)); + ClearBuffer(hi, sizeof(HuffmanInfo)); + ClearBuffer(di, sizeof(DequantInfo)); + ClearBuffer(mi, sizeof(IMDCTInfo)); + ClearBuffer(sbi, sizeof(SubbandInfo)); + + return mp3DecInfo; +} + +#define SAFE_FREE(x) {if (x) free(x); (x) = 0;} /* helper macro */ + +/************************************************************************************** + * Function: FreeBuffers + * + * Description: frees all the memory used by the MP3 decoder + * + * Inputs: pointer to initialized MP3DecInfo structure + * + * Outputs: none + * + * Return: none + * + * Notes: safe to call even if some buffers were not allocated (uses SAFE_FREE) + **************************************************************************************/ +void FreeBuffers(MP3DecInfo *mp3DecInfo) +{ + if (!mp3DecInfo) + return; + + SAFE_FREE(mp3DecInfo->FrameHeaderPS); + SAFE_FREE(mp3DecInfo->SideInfoPS); + SAFE_FREE(mp3DecInfo->ScaleFactorInfoPS); + SAFE_FREE(mp3DecInfo->HuffmanInfoPS); + SAFE_FREE(mp3DecInfo->DequantInfoPS); + SAFE_FREE(mp3DecInfo->IMDCTInfoPS); + SAFE_FREE(mp3DecInfo->SubbandInfoPS); + + SAFE_FREE(mp3DecInfo); +} diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/coder.h b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/coder.h new file mode 100644 index 0000000..59ef671 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/coder.h @@ -0,0 +1,307 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * coder.h - private, implementation-specific header file + **************************************************************************************/ + +#ifndef _CODER_H +#define _CODER_H + +#include "mp3common.h" + +#if defined(ASSERT) +#undef ASSERT +#endif +#if defined(_WIN32) && defined(_M_IX86) && (defined (_DEBUG) || defined (REL_ENABLE_ASSERTS)) +#define ASSERT(x) if (!(x)) __asm int 3; +#else +#define ASSERT(x) /* do nothing */ +#endif + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* clip to range [-2^n, 2^n - 1] */ +#define CLIP_2N(y, n) { \ + int sign = (y) >> 31; \ + if (sign != (y) >> (n)) { \ + (y) = sign ^ ((1 << (n)) - 1); \ + } \ +} + +#define SIBYTES_MPEG1_MONO 17 +#define SIBYTES_MPEG1_STEREO 32 +#define SIBYTES_MPEG2_MONO 9 +#define SIBYTES_MPEG2_STEREO 17 + +/* number of fraction bits for pow43Tab (see comments there) */ +#define POW43_FRACBITS_LOW 22 +#define POW43_FRACBITS_HIGH 12 + +#define DQ_FRACBITS_OUT 25 /* number of fraction bits in output of dequant */ +#define IMDCT_SCALE 2 /* additional scaling (by sqrt(2)) for fast IMDCT36 */ + +#define HUFF_PAIRTABS 32 +#define BLOCK_SIZE 18 +#define NBANDS 32 +#define MAX_REORDER_SAMPS ((192-126)*3) /* largest critical band for short blocks (see sfBandTable) */ +#define VBUF_LENGTH (17 * 2 * NBANDS) /* for double-sized vbuf FIFO */ + +/* additional external symbols to name-mangle for static linking */ +#define SetBitstreamPointer STATNAME(SetBitstreamPointer) +#define GetBits STATNAME(GetBits) +#define CalcBitsUsed STATNAME(CalcBitsUsed) +#define DequantChannel STATNAME(DequantChannel) +#define MidSideProc STATNAME(MidSideProc) +#define IntensityProcMPEG1 STATNAME(IntensityProcMPEG1) +#define IntensityProcMPEG2 STATNAME(IntensityProcMPEG2) +#define PolyphaseMono STATNAME(PolyphaseMono) +#define PolyphaseStereo STATNAME(PolyphaseStereo) +#define FDCT32 STATNAME(FDCT32) + +#define ISFMpeg1 STATNAME(ISFMpeg1) +#define ISFMpeg2 STATNAME(ISFMpeg2) +#define ISFIIP STATNAME(ISFIIP) +#define uniqueIDTab STATNAME(uniqueIDTab) +#define coef32 STATNAME(coef32) +#define polyCoef STATNAME(polyCoef) +#define csa STATNAME(csa) +#define imdctWin STATNAME(imdctWin) + +#define huffTable STATNAME(huffTable) +#define huffTabOffset STATNAME(huffTabOffset) +#define huffTabLookup STATNAME(huffTabLookup) +#define quadTable STATNAME(quadTable) +#define quadTabOffset STATNAME(quadTabOffset) +#define quadTabMaxBits STATNAME(quadTabMaxBits) + +/* map these to the corresponding 2-bit values in the frame header */ +typedef enum { + Stereo = 0x00, /* two independent channels, but L and R frames might have different # of bits */ + Joint = 0x01, /* coupled channels - layer III: mix of M-S and intensity, Layers I/II: intensity and direct coding only */ + Dual = 0x02, /* two independent channels, L and R always have exactly 1/2 the total bitrate */ + Mono = 0x03 /* one channel */ +} StereoMode; + +typedef struct _BitStreamInfo { + unsigned char *bytePtr; + unsigned int iCache; + int cachedBits; + int nBytes; +} BitStreamInfo; + +typedef struct _FrameHeader { + MPEGVersion ver; /* version ID */ + int layer; /* layer index (1, 2, or 3) */ + int crc; /* CRC flag: 0 = disabled, 1 = enabled */ + int brIdx; /* bitrate index (0 - 15) */ + int srIdx; /* sample rate index (0 - 2) */ + int paddingBit; /* padding flag: 0 = no padding, 1 = single pad byte */ + int privateBit; /* unused */ + StereoMode sMode; /* mono/stereo mode */ + int modeExt; /* used to decipher joint stereo mode */ + int copyFlag; /* copyright flag: 0 = no, 1 = yes */ + int origFlag; /* original flag: 0 = copy, 1 = original */ + int emphasis; /* deemphasis mode */ + int CRCWord; /* CRC word (16 bits, 0 if crc not enabled) */ + + const SFBandTable *sfBand; +} FrameHeader; + +typedef struct _SideInfoSub { + int part23Length; /* number of bits in main data */ + int nBigvals; /* 2x this = first set of Huffman cw's (maximum amplitude can be > 1) */ + int globalGain; /* overall gain for dequantizer */ + int sfCompress; /* unpacked to figure out number of bits in scale factors */ + int winSwitchFlag; /* window switching flag */ + int blockType; /* block type */ + int mixedBlock; /* 0 = regular block (all short or long), 1 = mixed block */ + int tableSelect[3]; /* index of Huffman tables for the big values regions */ + int subBlockGain[3]; /* subblock gain offset, relative to global gain */ + int region0Count; /* 1+region0Count = num scale factor bands in first region of bigvals */ + int region1Count; /* 1+region1Count = num scale factor bands in second region of bigvals */ + int preFlag; /* for optional high frequency boost */ + int sfactScale; /* scaling of the scalefactors */ + int count1TableSelect; /* index of Huffman table for quad codewords */ +} SideInfoSub; + +typedef struct _SideInfo { + int mainDataBegin; + int privateBits; + int scfsi[MAX_NCHAN][MAX_SCFBD]; /* 4 scalefactor bands per channel */ + + SideInfoSub sis[MAX_NGRAN][MAX_NCHAN]; +} SideInfo; + +typedef struct { + int cbType; /* pure long = 0, pure short = 1, mixed = 2 */ + int cbEndS[3]; /* number nonzero short cb's, per subbblock */ + int cbEndSMax; /* max of cbEndS[] */ + int cbEndL; /* number nonzero long cb's */ +} CriticalBandInfo; + +typedef struct _DequantInfo { + int workBuf[MAX_REORDER_SAMPS]; /* workbuf for reordering short blocks */ + CriticalBandInfo cbi[MAX_NCHAN]; /* filled in dequantizer, used in joint stereo reconstruction */ +} DequantInfo; + +typedef struct _HuffmanInfo { + int huffDecBuf[MAX_NCHAN][MAX_NSAMP]; /* used both for decoded Huffman values and dequantized coefficients */ + int nonZeroBound[MAX_NCHAN]; /* number of coeffs in huffDecBuf[ch] which can be > 0 */ + int gb[MAX_NCHAN]; /* minimum number of guard bits in huffDecBuf[ch] */ +} HuffmanInfo; + +typedef enum _HuffTabType { + noBits, + oneShot, + loopNoLinbits, + loopLinbits, + quadA, + quadB, + invalidTab +} HuffTabType; + +typedef struct _HuffTabLookup { + int linBits; + HuffTabType tabType; +} HuffTabLookup; + +typedef struct _IMDCTInfo { + int outBuf[MAX_NCHAN][BLOCK_SIZE][NBANDS]; /* output of IMDCT */ + int overBuf[MAX_NCHAN][MAX_NSAMP / 2]; /* overlap-add buffer (by symmetry, only need 1/2 size) */ + int numPrevIMDCT[MAX_NCHAN]; /* how many IMDCT's calculated in this channel on prev. granule */ + int prevType[MAX_NCHAN]; + int prevWinSwitch[MAX_NCHAN]; + int gb[MAX_NCHAN]; +} IMDCTInfo; + +typedef struct _BlockCount { + int nBlocksLong; + int nBlocksTotal; + int nBlocksPrev; + int prevType; + int prevWinSwitch; + int currWinSwitch; + int gbIn; + int gbOut; +} BlockCount; + +/* max bits in scalefactors = 5, so use char's to save space */ +typedef struct _ScaleFactorInfoSub { + char l[23]; /* [band] */ + char s[13][3]; /* [band][window] */ +} ScaleFactorInfoSub; + +/* used in MPEG 2, 2.5 intensity (joint) stereo only */ +typedef struct _ScaleFactorJS { + int intensityScale; + int slen[4]; + int nr[4]; +} ScaleFactorJS; + +typedef struct _ScaleFactorInfo { + ScaleFactorInfoSub sfis[MAX_NGRAN][MAX_NCHAN]; + ScaleFactorJS sfjs; +} ScaleFactorInfo; + +/* NOTE - could get by with smaller vbuf if memory is more important than speed + * (in Subband, instead of replicating each block in FDCT32 you would do a memmove on the + * last 15 blocks to shift them down one, a hardware style FIFO) + */ +typedef struct _SubbandInfo { + int vbuf[MAX_NCHAN * VBUF_LENGTH]; /* vbuf for fast DCT-based synthesis PQMF - double size for speed (no modulo indexing) */ + int vindex; /* internal index for tracking position in vbuf */ +} SubbandInfo; + +/* bitstream.c */ +void SetBitstreamPointer(BitStreamInfo *bsi, int nBytes, unsigned char *buf); +unsigned int GetBits(BitStreamInfo *bsi, int nBits); +int CalcBitsUsed(BitStreamInfo *bsi, unsigned char *startBuf, int startOffset); + +/* dequant.c, dqchan.c, stproc.c */ +int DequantChannel(int *sampleBuf, int *workBuf, int *nonZeroBound, FrameHeader *fh, SideInfoSub *sis, + ScaleFactorInfoSub *sfis, CriticalBandInfo *cbi); +void MidSideProc(int x[MAX_NCHAN][MAX_NSAMP], int nSamps, int mOut[2]); +void IntensityProcMPEG1(int x[MAX_NCHAN][MAX_NSAMP], int nSamps, FrameHeader *fh, ScaleFactorInfoSub *sfis, + CriticalBandInfo *cbi, int midSideFlag, int mixFlag, int mOut[2]); +void IntensityProcMPEG2(int x[MAX_NCHAN][MAX_NSAMP], int nSamps, FrameHeader *fh, ScaleFactorInfoSub *sfis, + CriticalBandInfo *cbi, ScaleFactorJS *sfjs, int midSideFlag, int mixFlag, int mOut[2]); + +/* dct32.c */ +// about 1 ms faster in RAM, but very large +void FDCT32(int *x, int *d, int offset, int oddBlock, int gb);// __attribute__ ((section (".data"))); + +/* hufftabs.c */ +extern const HuffTabLookup huffTabLookup[HUFF_PAIRTABS]; +extern const int huffTabOffset[HUFF_PAIRTABS]; +extern const unsigned short huffTable[]; +extern const unsigned char quadTable[64+16]; +extern const int quadTabOffset[2]; +extern const int quadTabMaxBits[2]; + +/* polyphase.c (or asmpoly.s) + * some platforms require a C++ compile of all source files, + * so if we're compiling C as C++ and using native assembly + * for these functions we need to prevent C++ name mangling. + */ +#ifdef __cplusplus +extern "C" { +#endif +void PolyphaseMono(short *pcm, int *vbuf, const int *coefBase); +void PolyphaseStereo(short *pcm, int *vbuf, const int *coefBase); +#ifdef __cplusplus +} +#endif + +/* trigtabs.c */ +extern const int imdctWin[4][36]; +extern const int ISFMpeg1[2][7]; +extern const int ISFMpeg2[2][2][16]; +extern const int ISFIIP[2][2]; +extern const int csa[8][2]; +extern const int coef32[31]; +extern const int polyCoef[264]; + +#endif /* _CODER_H */ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/dct32.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/dct32.c new file mode 100644 index 0000000..990c733 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/dct32.c @@ -0,0 +1,280 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * dct32.c - optimized implementations of 32-point DCT for matrixing stage of + * polyphase filter + **************************************************************************************/ + +#include "coder.h" +#include "assembly.h" + +#define COS0_0 0x4013c251 /* Q31 */ +#define COS0_1 0x40b345bd /* Q31 */ +#define COS0_2 0x41fa2d6d /* Q31 */ +#define COS0_3 0x43f93421 /* Q31 */ +#define COS0_4 0x46cc1bc4 /* Q31 */ +#define COS0_5 0x4a9d9cf0 /* Q31 */ +#define COS0_6 0x4fae3711 /* Q31 */ +#define COS0_7 0x56601ea7 /* Q31 */ +#define COS0_8 0x5f4cf6eb /* Q31 */ +#define COS0_9 0x6b6fcf26 /* Q31 */ +#define COS0_10 0x7c7d1db3 /* Q31 */ +#define COS0_11 0x4ad81a97 /* Q30 */ +#define COS0_12 0x5efc8d96 /* Q30 */ +#define COS0_13 0x41d95790 /* Q29 */ +#define COS0_14 0x6d0b20cf /* Q29 */ +#define COS0_15 0x518522fb /* Q27 */ + +#define COS1_0 0x404f4672 /* Q31 */ +#define COS1_1 0x42e13c10 /* Q31 */ +#define COS1_2 0x48919f44 /* Q31 */ +#define COS1_3 0x52cb0e63 /* Q31 */ +#define COS1_4 0x64e2402e /* Q31 */ +#define COS1_5 0x43e224a9 /* Q30 */ +#define COS1_6 0x6e3c92c1 /* Q30 */ +#define COS1_7 0x519e4e04 /* Q28 */ + +#define COS2_0 0x4140fb46 /* Q31 */ +#define COS2_1 0x4cf8de88 /* Q31 */ +#define COS2_2 0x73326bbf /* Q31 */ +#define COS2_3 0x52036742 /* Q29 */ + +#define COS3_0 0x4545e9ef /* Q31 */ +#define COS3_1 0x539eba45 /* Q30 */ + +#define COS4_0 0x5a82799a /* Q31 */ + +// faster in ROM +static const int dcttab[48] = { + /* first pass */ + COS0_0, COS0_15, COS1_0, /* 31, 27, 31 */ + COS0_1, COS0_14, COS1_1, /* 31, 29, 31 */ + COS0_2, COS0_13, COS1_2, /* 31, 29, 31 */ + COS0_3, COS0_12, COS1_3, /* 31, 30, 31 */ + COS0_4, COS0_11, COS1_4, /* 31, 30, 31 */ + COS0_5, COS0_10, COS1_5, /* 31, 31, 30 */ + COS0_6, COS0_9, COS1_6, /* 31, 31, 30 */ + COS0_7, COS0_8, COS1_7, /* 31, 31, 28 */ + /* second pass */ + COS2_0, COS2_3, COS3_0, /* 31, 29, 31 */ + COS2_1, COS2_2, COS3_1, /* 31, 31, 30 */ + -COS2_0, -COS2_3, COS3_0, /* 31, 29, 31 */ + -COS2_1, -COS2_2, COS3_1, /* 31, 31, 30 */ + COS2_0, COS2_3, COS3_0, /* 31, 29, 31 */ + COS2_1, COS2_2, COS3_1, /* 31, 31, 30 */ + -COS2_0, -COS2_3, COS3_0, /* 31, 29, 31 */ + -COS2_1, -COS2_2, COS3_1, /* 31, 31, 30 */ +}; + +#define D32FP(i, s0, s1, s2) { \ + a0 = buf[i]; a3 = buf[31-i]; \ + a1 = buf[15-i]; a2 = buf[16+i]; \ + b0 = a0 + a3; b3 = MULSHIFT32(*cptr++, a0 - a3) << (s0); \ + b1 = a1 + a2; b2 = MULSHIFT32(*cptr++, a1 - a2) << (s1); \ + buf[i] = b0 + b1; buf[15-i] = MULSHIFT32(*cptr, b0 - b1) << (s2); \ + buf[16+i] = b2 + b3; buf[31-i] = MULSHIFT32(*cptr++, b3 - b2) << (s2); \ +} + +/************************************************************************************** + * Function: FDCT32 + * + * Description: Ken's highly-optimized 32-point DCT (radix-4 + radix-8) + * + * Inputs: input buffer, length = 32 samples + * require at least 6 guard bits in input vector x to avoid possibility + * of overflow in internal calculations (see bbtest_imdct test app) + * buffer offset and oddblock flag for polyphase filter input buffer + * number of guard bits in input + * + * Outputs: output buffer, data copied and interleaved for polyphase filter + * no guarantees about number of guard bits in output + * + * Return: none + * + * Notes: number of muls = 4*8 + 12*4 = 80 + * final stage of DCT is hardcoded to shuffle data into the proper order + * for the polyphase filterbank + * fully unrolled stage 1, for max precision (scale the 1/cos() factors + * differently, depending on magnitude) + * guard bit analysis verified by exhaustive testing of all 2^32 + * combinations of max pos/max neg values in x[] + * + * TODO: code organization and optimization for ARM + * possibly interleave stereo (cut # of coef loads in half - may not have + * enough registers) + **************************************************************************************/ +// about 1ms faster in RAM +void FDCT32(int *buf, int *dest, int offset, int oddBlock, int gb) +{ + int i, s, tmp, es; + const int *cptr = dcttab; + int a0, a1, a2, a3, a4, a5, a6, a7; + int b0, b1, b2, b3, b4, b5, b6, b7; + int *d; + + /* scaling - ensure at least 6 guard bits for DCT + * (in practice this is already true 99% of time, so this code is + * almost never triggered) + */ + es = 0; + if (gb < 6) { + es = 6 - gb; + for (i = 0; i < 32; i++) + buf[i] >>= es; + } + + /* first pass */ + D32FP(0, 1, 5, 1); + D32FP(1, 1, 3, 1); + D32FP(2, 1, 3, 1); + D32FP(3, 1, 2, 1); + D32FP(4, 1, 2, 1); + D32FP(5, 1, 1, 2); + D32FP(6, 1, 1, 2); + D32FP(7, 1, 1, 4); + + /* second pass */ + for (i = 4; i > 0; i--) { + a0 = buf[0]; a7 = buf[7]; a3 = buf[3]; a4 = buf[4]; + b0 = a0 + a7; b7 = MULSHIFT32(*cptr++, a0 - a7) << 1; + b3 = a3 + a4; b4 = MULSHIFT32(*cptr++, a3 - a4) << 3; + a0 = b0 + b3; a3 = MULSHIFT32(*cptr, b0 - b3) << 1; + a4 = b4 + b7; a7 = MULSHIFT32(*cptr++, b7 - b4) << 1; + + a1 = buf[1]; a6 = buf[6]; a2 = buf[2]; a5 = buf[5]; + b1 = a1 + a6; b6 = MULSHIFT32(*cptr++, a1 - a6) << 1; + b2 = a2 + a5; b5 = MULSHIFT32(*cptr++, a2 - a5) << 1; + a1 = b1 + b2; a2 = MULSHIFT32(*cptr, b1 - b2) << 2; + a5 = b5 + b6; a6 = MULSHIFT32(*cptr++, b6 - b5) << 2; + + b0 = a0 + a1; b1 = MULSHIFT32(COS4_0, a0 - a1) << 1; + b2 = a2 + a3; b3 = MULSHIFT32(COS4_0, a3 - a2) << 1; + buf[0] = b0; buf[1] = b1; + buf[2] = b2 + b3; buf[3] = b3; + + b4 = a4 + a5; b5 = MULSHIFT32(COS4_0, a4 - a5) << 1; + b6 = a6 + a7; b7 = MULSHIFT32(COS4_0, a7 - a6) << 1; + b6 += b7; + buf[4] = b4 + b6; buf[5] = b5 + b7; + buf[6] = b5 + b6; buf[7] = b7; + + buf += 8; + } + buf -= 32; /* reset */ + + /* sample 0 - always delayed one block */ + d = dest + 64*16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : VBUF_LENGTH); + s = buf[ 0]; d[0] = d[8] = s; + + /* samples 16 to 31 */ + d = dest + offset + (oddBlock ? VBUF_LENGTH : 0); + + s = buf[ 1]; d[0] = d[8] = s; d += 64; + + tmp = buf[25] + buf[29]; + s = buf[17] + tmp; d[0] = d[8] = s; d += 64; + s = buf[ 9] + buf[13]; d[0] = d[8] = s; d += 64; + s = buf[21] + tmp; d[0] = d[8] = s; d += 64; + + tmp = buf[29] + buf[27]; + s = buf[ 5]; d[0] = d[8] = s; d += 64; + s = buf[21] + tmp; d[0] = d[8] = s; d += 64; + s = buf[13] + buf[11]; d[0] = d[8] = s; d += 64; + s = buf[19] + tmp; d[0] = d[8] = s; d += 64; + + tmp = buf[27] + buf[31]; + s = buf[ 3]; d[0] = d[8] = s; d += 64; + s = buf[19] + tmp; d[0] = d[8] = s; d += 64; + s = buf[11] + buf[15]; d[0] = d[8] = s; d += 64; + s = buf[23] + tmp; d[0] = d[8] = s; d += 64; + + tmp = buf[31]; + s = buf[ 7]; d[0] = d[8] = s; d += 64; + s = buf[23] + tmp; d[0] = d[8] = s; d += 64; + s = buf[15]; d[0] = d[8] = s; d += 64; + s = tmp; d[0] = d[8] = s; + + /* samples 16 to 1 (sample 16 used again) */ + d = dest + 16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : VBUF_LENGTH); + + s = buf[ 1]; d[0] = d[8] = s; d += 64; + + tmp = buf[30] + buf[25]; + s = buf[17] + tmp; d[0] = d[8] = s; d += 64; + s = buf[14] + buf[ 9]; d[0] = d[8] = s; d += 64; + s = buf[22] + tmp; d[0] = d[8] = s; d += 64; + s = buf[ 6]; d[0] = d[8] = s; d += 64; + + tmp = buf[26] + buf[30]; + s = buf[22] + tmp; d[0] = d[8] = s; d += 64; + s = buf[10] + buf[14]; d[0] = d[8] = s; d += 64; + s = buf[18] + tmp; d[0] = d[8] = s; d += 64; + s = buf[ 2]; d[0] = d[8] = s; d += 64; + + tmp = buf[28] + buf[26]; + s = buf[18] + tmp; d[0] = d[8] = s; d += 64; + s = buf[12] + buf[10]; d[0] = d[8] = s; d += 64; + s = buf[20] + tmp; d[0] = d[8] = s; d += 64; + s = buf[ 4]; d[0] = d[8] = s; d += 64; + + tmp = buf[24] + buf[28]; + s = buf[20] + tmp; d[0] = d[8] = s; d += 64; + s = buf[ 8] + buf[12]; d[0] = d[8] = s; d += 64; + s = buf[16] + tmp; d[0] = d[8] = s; + + /* this is so rarely invoked that it's not worth making two versions of the output + * shuffle code (one for no shift, one for clip + variable shift) like in IMDCT + * here we just load, clip, shift, and store on the rare instances that es != 0 + */ + if (es) { + d = dest + 64*16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : VBUF_LENGTH); + s = d[0]; CLIP_2N(s, 31 - es); d[0] = d[8] = (s << es); + + d = dest + offset + (oddBlock ? VBUF_LENGTH : 0); + for (i = 16; i <= 31; i++) { + s = d[0]; CLIP_2N(s, 31 - es); d[0] = d[8] = (s << es); d += 64; + } + + d = dest + 16 + ((offset - oddBlock) & 7) + (oddBlock ? 0 : VBUF_LENGTH); + for (i = 15; i >= 0; i--) { + s = d[0]; CLIP_2N(s, 31 - es); d[0] = d[8] = (s << es); d += 64; + } + } +} diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/dequant.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/dequant.c new file mode 100644 index 0000000..b989b7d --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/dequant.c @@ -0,0 +1,158 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * dequant.c - dequantization, stereo processing (intensity, mid-side), short-block + * coefficient reordering + **************************************************************************************/ + +#include "coder.h" +#include "assembly.h" + +/************************************************************************************** + * Function: Dequantize + * + * Description: dequantize coefficients, decode stereo, reorder short blocks + * (one granule-worth) + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader(), UnpackSideInfo(), + * UnpackScaleFactors(), and DecodeHuffman() (for this granule) + * index of current granule + * + * Outputs: dequantized and reordered coefficients in hi->huffDecBuf + * (one granule-worth, all channels), format = Q26 + * operates in-place on huffDecBuf but also needs di->workBuf + * updated hi->nonZeroBound index for both channels + * + * Return: 0 on success, -1 if null input pointers + * + * Notes: In calling output Q(DQ_FRACBITS_OUT), we assume an implicit bias + * of 2^15. Some (floating-point) reference implementations factor this + * into the 2^(0.25 * gain) scaling explicitly. But to avoid precision + * loss, we don't do that. Instead take it into account in the final + * round to PCM (>> by 15 less than we otherwise would have). + * Equivalently, we can think of the dequantized coefficients as + * Q(DQ_FRACBITS_OUT - 15) with no implicit bias. + **************************************************************************************/ +int Dequantize(MP3DecInfo *mp3DecInfo, int gr) +{ + int i, ch, nSamps, mOut[2]; + FrameHeader *fh; + SideInfo *si; + ScaleFactorInfo *sfi; + HuffmanInfo *hi; + DequantInfo *di; + CriticalBandInfo *cbi; + + /* validate pointers */ + if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS || !mp3DecInfo->SideInfoPS || !mp3DecInfo->ScaleFactorInfoPS || + !mp3DecInfo->HuffmanInfoPS || !mp3DecInfo->DequantInfoPS) + return -1; + + fh = (FrameHeader *)(mp3DecInfo->FrameHeaderPS); + + /* si is an array of up to 4 structs, stored as gr0ch0, gr0ch1, gr1ch0, gr1ch1 */ + si = (SideInfo *)(mp3DecInfo->SideInfoPS); + sfi = (ScaleFactorInfo *)(mp3DecInfo->ScaleFactorInfoPS); + hi = (HuffmanInfo *)mp3DecInfo->HuffmanInfoPS; + di = (DequantInfo *)mp3DecInfo->DequantInfoPS; + cbi = di->cbi; + mOut[0] = mOut[1] = 0; + + /* dequantize all the samples in each channel */ + for (ch = 0; ch < mp3DecInfo->nChans; ch++) { + hi->gb[ch] = DequantChannel(hi->huffDecBuf[ch], di->workBuf, &hi->nonZeroBound[ch], fh, + &si->sis[gr][ch], &sfi->sfis[gr][ch], &cbi[ch]); + } + + /* joint stereo processing assumes one guard bit in input samples + * it's extremely rare not to have at least one gb, so if this is the case + * just make a pass over the data and clip to [-2^30+1, 2^30-1] + * in practice this may never happen + */ + if (fh->modeExt && (hi->gb[0] < 1 || hi->gb[1] < 1)) { + for (i = 0; i < hi->nonZeroBound[0]; i++) { + if (hi->huffDecBuf[0][i] < -0x3fffffff) hi->huffDecBuf[0][i] = -0x3fffffff; + if (hi->huffDecBuf[0][i] > 0x3fffffff) hi->huffDecBuf[0][i] = 0x3fffffff; + } + for (i = 0; i < hi->nonZeroBound[1]; i++) { + if (hi->huffDecBuf[1][i] < -0x3fffffff) hi->huffDecBuf[1][i] = -0x3fffffff; + if (hi->huffDecBuf[1][i] > 0x3fffffff) hi->huffDecBuf[1][i] = 0x3fffffff; + } + } + + /* do mid-side stereo processing, if enabled */ + if (fh->modeExt >> 1) { + if (fh->modeExt & 0x01) { + /* intensity stereo enabled - run mid-side up to start of right zero region */ + if (cbi[1].cbType == 0) + nSamps = fh->sfBand->l[cbi[1].cbEndL + 1]; + else + nSamps = 3 * fh->sfBand->s[cbi[1].cbEndSMax + 1]; + } else { + /* intensity stereo disabled - run mid-side on whole spectrum */ + nSamps = MAX(hi->nonZeroBound[0], hi->nonZeroBound[1]); + } + MidSideProc(hi->huffDecBuf, nSamps, mOut); + } + + /* do intensity stereo processing, if enabled */ + if (fh->modeExt & 0x01) { + nSamps = hi->nonZeroBound[0]; + if (fh->ver == MPEG1) { + IntensityProcMPEG1(hi->huffDecBuf, nSamps, fh, &sfi->sfis[gr][1], di->cbi, + fh->modeExt >> 1, si->sis[gr][1].mixedBlock, mOut); + } else { + IntensityProcMPEG2(hi->huffDecBuf, nSamps, fh, &sfi->sfis[gr][1], di->cbi, &sfi->sfjs, + fh->modeExt >> 1, si->sis[gr][1].mixedBlock, mOut); + } + } + + /* adjust guard bit count and nonZeroBound if we did any stereo processing */ + if (fh->modeExt) { + hi->gb[0] = CLZ(mOut[0]) - 1; + hi->gb[1] = CLZ(mOut[1]) - 1; + nSamps = MAX(hi->nonZeroBound[0], hi->nonZeroBound[1]); + hi->nonZeroBound[0] = nSamps; + hi->nonZeroBound[1] = nSamps; + } + + /* output format Q(DQ_FRACBITS_OUT) */ + return 0; +} diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/dqchan.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/dqchan.c new file mode 100644 index 0000000..d73ac60 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/dqchan.c @@ -0,0 +1,375 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * August 2003 + * + * dqchan.c - dequantization of transform coefficients + **************************************************************************************/ + +#include "coder.h" +#include "assembly.h" + +typedef int ARRAY3[3]; /* for short-block reordering */ + +/* optional pre-emphasis for high-frequency scale factor bands */ +static const char preTab[22] = { 0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,2,0 }; + +/* pow(2,-i/4) for i=0..3, Q31 format */ +int pow14[4] = { + 0x7fffffff, 0x6ba27e65, 0x5a82799a, 0x4c1bf829 +}; + +/* pow(2,-i/4) * pow(j,4/3) for i=0..3 j=0..15, Q25 format */ +int pow43_14[4][16] = { +{ 0x00000000, 0x10000000, 0x285145f3, 0x453a5cdb, /* Q28 */ + 0x0cb2ff53, 0x111989d6, 0x15ce31c8, 0x1ac7f203, + 0x20000000, 0x257106b9, 0x2b16b4a3, 0x30ed74b4, + 0x36f23fa5, 0x3d227bd3, 0x437be656, 0x49fc823c, }, + +{ 0x00000000, 0x0d744fcd, 0x21e71f26, 0x3a36abd9, + 0x0aadc084, 0x0e610e6e, 0x12560c1d, 0x168523cf, + 0x1ae89f99, 0x1f7c03a4, 0x243bae49, 0x29249c67, + 0x2e34420f, 0x33686f85, 0x38bf3dff, 0x3e370182, }, + +{ 0x00000000, 0x0b504f33, 0x1c823e07, 0x30f39a55, + 0x08facd62, 0x0c176319, 0x0f6b3522, 0x12efe2ad, + 0x16a09e66, 0x1a79a317, 0x1e77e301, 0x2298d5b4, + 0x26da56fc, 0x2b3a902a, 0x2fb7e7e7, 0x3450f650, }, + +{ 0x00000000, 0x09837f05, 0x17f910d7, 0x2929c7a9, + 0x078d0dfa, 0x0a2ae661, 0x0cf73154, 0x0fec91cb, + 0x1306fe0a, 0x16434a6c, 0x199ee595, 0x1d17ae3d, + 0x20abd76a, 0x2459d551, 0x28204fbb, 0x2bfe1808, }, +}; + +/* pow(j,4/3) for j=16..63, Q23 format */ +int pow43[] = { + 0x1428a2fa, 0x15db1bd6, 0x1796302c, 0x19598d85, + 0x1b24e8bb, 0x1cf7fcfa, 0x1ed28af2, 0x20b4582a, + 0x229d2e6e, 0x248cdb55, 0x26832fda, 0x28800000, + 0x2a832287, 0x2c8c70a8, 0x2e9bc5d8, 0x30b0ff99, + 0x32cbfd4a, 0x34eca001, 0x3712ca62, 0x393e6088, + 0x3b6f47e0, 0x3da56717, 0x3fe0a5fc, 0x4220ed72, + 0x44662758, 0x46b03e7c, 0x48ff1e87, 0x4b52b3f3, + 0x4daaebfd, 0x5007b497, 0x5268fc62, 0x54ceb29c, + 0x5738c721, 0x59a72a59, 0x5c19cd35, 0x5e90a129, + 0x610b9821, 0x638aa47f, 0x660db90f, 0x6894c90b, + 0x6b1fc80c, 0x6daeaa0d, 0x70416360, 0x72d7e8b0, + 0x75722ef9, 0x78102b85, 0x7ab1d3ec, 0x7d571e09, +}; + +/* sqrt(0.5) in Q31 format */ +#define SQRTHALF 0x5a82799a + +/* + * Minimax polynomial approximation to pow(x, 4/3), over the range + * poly43lo: x = [0.5, 0.7071] + * poly43hi: x = [0.7071, 1.0] + * + * Relative error < 1E-7 + * Coefs are scaled by 4, 2, 1, 0.5, 0.25 + */ +int poly43lo[5] = { 0x29a0bda9, 0xb02e4828, 0x5957aa1b, 0x236c498d, 0xff581859 }; +int poly43hi[5] = { 0x10852163, 0xd333f6a4, 0x46e9408b, 0x27c2cef0, 0xfef577b4 }; + +/* pow(2, i*4/3) as exp and frac */ +int pow2exp[8] = { 14, 13, 11, 10, 9, 7, 6, 5 }; + +int pow2frac[8] = { + 0x6597fa94, 0x50a28be6, 0x7fffffff, 0x6597fa94, + 0x50a28be6, 0x7fffffff, 0x6597fa94, 0x50a28be6 +}; + +/************************************************************************************** + * Function: DequantBlock + * + * Description: Ken's highly-optimized, low memory dequantizer performing the operation + * y = pow(x, 4.0/3.0) * pow(2, 25 - scale/4.0) + * + * Inputs: input buffer of decode Huffman codewords (signed-magnitude) + * output buffer of same length (in-place (outbuf = inbuf) is allowed) + * number of samples + * + * Outputs: dequantized samples in Q25 format + * + * Return: bitwise-OR of the unsigned outputs (for guard bit calculations) + **************************************************************************************/ +static int DequantBlock(int *inbuf, int *outbuf, int num, int scale) +{ + int tab4[4]; + int scalef, scalei, shift; + int sx, x, y; + int mask = 0; + const int *tab16, *coef; + + tab16 = pow43_14[scale & 0x3]; + scalef = pow14[scale & 0x3]; + scalei = MIN(scale >> 2, 31); /* smallest input scale = -47, so smallest scalei = -12 */ + + /* cache first 4 values */ + shift = MIN(scalei + 3, 31); + shift = MAX(shift, 0); + tab4[0] = 0; + tab4[1] = tab16[1] >> shift; + tab4[2] = tab16[2] >> shift; + tab4[3] = tab16[3] >> shift; + + do { + + sx = *inbuf++; + x = sx & 0x7fffffff; /* sx = sign|mag */ + + if (x < 4) { + + y = tab4[x]; + + } else if (x < 16) { + + y = tab16[x]; + y = (scalei < 0) ? y << -scalei : y >> scalei; + + } else { + + if (x < 64) { + + y = pow43[x-16]; + + /* fractional scale */ + y = MULSHIFT32(y, scalef); + shift = scalei - 3; + + } else { + + /* normalize to [0x40000000, 0x7fffffff] */ + x <<= 17; + shift = 0; + if (x < 0x08000000) + x <<= 4, shift += 4; + if (x < 0x20000000) + x <<= 2, shift += 2; + if (x < 0x40000000) + x <<= 1, shift += 1; + + coef = (x < SQRTHALF) ? poly43lo : poly43hi; + + /* polynomial */ + y = coef[0]; + y = MULSHIFT32(y, x) + coef[1]; + y = MULSHIFT32(y, x) + coef[2]; + y = MULSHIFT32(y, x) + coef[3]; + y = MULSHIFT32(y, x) + coef[4]; + y = MULSHIFT32(y, pow2frac[shift]) << 3; + + /* fractional scale */ + y = MULSHIFT32(y, scalef); + shift = scalei - pow2exp[shift]; + } + + /* integer scale */ + if (shift < 0) { + shift = -shift; + if (y > (0x7fffffff >> shift)) + y = 0x7fffffff; /* clip */ + else + y <<= shift; + } else { + y >>= shift; + } + } + + /* sign and store */ + mask |= y; + *outbuf++ = (sx < 0) ? -y : y; + + } while (--num); + + return mask; +} + +/************************************************************************************** + * Function: DequantChannel + * + * Description: dequantize one granule, one channel worth of decoded Huffman codewords + * + * Inputs: sample buffer (decoded Huffman codewords), length = MAX_NSAMP samples + * work buffer for reordering short-block, length = MAX_REORDER_SAMPS + * samples (3 * width of largest short-block critical band) + * non-zero bound for this channel/granule + * valid FrameHeader, SideInfoSub, ScaleFactorInfoSub, and CriticalBandInfo + * structures for this channel/granule + * + * Outputs: MAX_NSAMP dequantized samples in sampleBuf + * updated non-zero bound (indicating which samples are != 0 after DQ) + * filled-in cbi structure indicating start and end critical bands + * + * Return: minimum number of guard bits in dequantized sampleBuf + * + * Notes: dequantized samples in Q(DQ_FRACBITS_OUT) format + **************************************************************************************/ +int DequantChannel(int *sampleBuf, int *workBuf, int *nonZeroBound, FrameHeader *fh, SideInfoSub *sis, + ScaleFactorInfoSub *sfis, CriticalBandInfo *cbi) +{ + int i, j, w, cb; + int cbStartL, cbEndL, cbStartS, cbEndS; + int nSamps, nonZero, sfactMultiplier, gbMask; + int globalGain, gainI; + int cbMax[3]; + ARRAY3 *buf; /* short block reorder */ + + /* set default start/end points for short/long blocks - will update with non-zero cb info */ + if (sis->blockType == 2) { + cbStartL = 0; + if (sis->mixedBlock) { + cbEndL = (fh->ver == MPEG1 ? 8 : 6); + cbStartS = 3; + } else { + cbEndL = 0; + cbStartS = 0; + } + cbEndS = 13; + } else { + /* long block */ + cbStartL = 0; + cbEndL = 22; + cbStartS = 13; + cbEndS = 13; + } + cbMax[2] = cbMax[1] = cbMax[0] = 0; + gbMask = 0; + i = 0; + + /* sfactScale = 0 --> quantizer step size = 2 + * sfactScale = 1 --> quantizer step size = sqrt(2) + * so sfactMultiplier = 2 or 4 (jump through globalGain by powers of 2 or sqrt(2)) + */ + sfactMultiplier = 2 * (sis->sfactScale + 1); + + /* offset globalGain by -2 if midSide enabled, for 1/sqrt(2) used in MidSideProc() + * (DequantBlock() does 0.25 * gainI so knocking it down by two is the same as + * dividing every sample by sqrt(2) = multiplying by 2^-.5) + */ + globalGain = sis->globalGain; + if (fh->modeExt >> 1) + globalGain -= 2; + globalGain += IMDCT_SCALE; /* scale everything by sqrt(2), for fast IMDCT36 */ + + /* long blocks */ + for (cb = 0; cb < cbEndL; cb++) { + + nonZero = 0; + nSamps = fh->sfBand->l[cb + 1] - fh->sfBand->l[cb]; + gainI = 210 - globalGain + sfactMultiplier * (sfis->l[cb] + (sis->preFlag ? (int)preTab[cb] : 0)); + + nonZero |= DequantBlock(sampleBuf + i, sampleBuf + i, nSamps, gainI); + i += nSamps; + + /* update highest non-zero critical band */ + if (nonZero) + cbMax[0] = cb; + gbMask |= nonZero; + + if (i >= *nonZeroBound) + break; + } + + /* set cbi (Type, EndS[], EndSMax will be overwritten if we proceed to do short blocks) */ + cbi->cbType = 0; /* long only */ + cbi->cbEndL = cbMax[0]; + cbi->cbEndS[0] = cbi->cbEndS[1] = cbi->cbEndS[2] = 0; + cbi->cbEndSMax = 0; + + /* early exit if no short blocks */ + if (cbStartS >= 12) + return CLZ(gbMask) - 1; + + /* short blocks */ + cbMax[2] = cbMax[1] = cbMax[0] = cbStartS; + for (cb = cbStartS; cb < cbEndS; cb++) { + + nSamps = fh->sfBand->s[cb + 1] - fh->sfBand->s[cb]; + for (w = 0; w < 3; w++) { + nonZero = 0; + gainI = 210 - globalGain + 8*sis->subBlockGain[w] + sfactMultiplier*(sfis->s[cb][w]); + + nonZero |= DequantBlock(sampleBuf + i + nSamps*w, workBuf + nSamps*w, nSamps, gainI); + + /* update highest non-zero critical band */ + if (nonZero) + cbMax[w] = cb; + gbMask |= nonZero; + } + + /* reorder blocks */ + buf = (ARRAY3 *)(sampleBuf + i); + i += 3*nSamps; + for (j = 0; j < nSamps; j++) { + buf[j][0] = workBuf[0*nSamps + j]; + buf[j][1] = workBuf[1*nSamps + j]; + buf[j][2] = workBuf[2*nSamps + j]; + } + + ASSERT(3*nSamps <= MAX_REORDER_SAMPS); + + if (i >= *nonZeroBound) + break; + } + + /* i = last non-zero INPUT sample processed, which corresponds to highest possible non-zero + * OUTPUT sample (after reorder) + * however, the original nzb is no longer necessarily true + * for each cb, buf[][] is updated with 3*nSamps samples (i increases 3*nSamps each time) + * (buf[j + 1][0] = 3 (input) samples ahead of buf[j][0]) + * so update nonZeroBound to i + */ + *nonZeroBound = i; + + ASSERT(*nonZeroBound <= MAX_NSAMP); + + cbi->cbType = (sis->mixedBlock ? 2 : 1); /* 2 = mixed short/long, 1 = short only */ + + cbi->cbEndS[0] = cbMax[0]; + cbi->cbEndS[1] = cbMax[1]; + cbi->cbEndS[2] = cbMax[2]; + + cbi->cbEndSMax = cbMax[0]; + cbi->cbEndSMax = MAX(cbi->cbEndSMax, cbMax[1]); + cbi->cbEndSMax = MAX(cbi->cbEndSMax, cbMax[2]); + + return CLZ(gbMask) - 1; +} + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/huffman.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/huffman.c new file mode 100644 index 0000000..192f188 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/huffman.c @@ -0,0 +1,461 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * July 2003 + * + * huffman.c - Huffman decoding of transform coefficients + **************************************************************************************/ + +#include "coder.h" + +/* helper macros - see comments in hufftabs.c about the format of the huffman tables */ +#define GetMaxbits(x) ((int)( (((unsigned short)(x)) >> 0) & 0x000f)) +#define GetHLen(x) ((int)( (((unsigned short)(x)) >> 12) & 0x000f)) +#define GetCWY(x) ((int)( (((unsigned short)(x)) >> 8) & 0x000f)) +#define GetCWX(x) ((int)( (((unsigned short)(x)) >> 4) & 0x000f)) +#define GetSignBits(x) ((int)( (((unsigned short)(x)) >> 0) & 0x000f)) + +#define GetHLenQ(x) ((int)( (((unsigned char)(x)) >> 4) & 0x0f)) +#define GetCWVQ(x) ((int)( (((unsigned char)(x)) >> 3) & 0x01)) +#define GetCWWQ(x) ((int)( (((unsigned char)(x)) >> 2) & 0x01)) +#define GetCWXQ(x) ((int)( (((unsigned char)(x)) >> 1) & 0x01)) +#define GetCWYQ(x) ((int)( (((unsigned char)(x)) >> 0) & 0x01)) + +/* apply sign of s to the positive number x (save in MSB, will do two's complement in dequant) */ +#define ApplySign(x, s) { (x) |= ((s) & 0x80000000); } + +/************************************************************************************** + * Function: DecodeHuffmanPairs + * + * Description: decode 2-way vector Huffman codes in the "bigValues" region of spectrum + * + * Inputs: valid BitStreamInfo struct, pointing to start of pair-wise codes + * pointer to xy buffer to received decoded values + * number of codewords to decode + * index of Huffman table to use + * number of bits remaining in bitstream + * + * Outputs: pairs of decoded coefficients in vwxy + * updated BitStreamInfo struct + * + * Return: number of bits used, or -1 if out of bits + * + * Notes: assumes that nVals is an even number + * si_huff.bit tests every Huffman codeword in every table (though not + * necessarily all linBits outputs for x,y > 15) + **************************************************************************************/ +// no improvement with section=data +static int DecodeHuffmanPairs(int *xy, int nVals, int tabIdx, int bitsLeft, unsigned char *buf, int bitOffset) +{ + int i, x, y; + int cachedBits, padBits, len, startBits, linBits, maxBits, minBits; + HuffTabType tabType; + unsigned short cw, *tBase, *tCurr; + unsigned int cache; + + if(nVals <= 0) + return 0; + + if (bitsLeft < 0) + return -1; + startBits = bitsLeft; + + tBase = (unsigned short *)(huffTable + huffTabOffset[tabIdx]); + linBits = huffTabLookup[tabIdx].linBits; + tabType = huffTabLookup[tabIdx].tabType; + + ASSERT(!(nVals & 0x01)); + ASSERT(tabIdx < HUFF_PAIRTABS); + ASSERT(tabIdx >= 0); + ASSERT(tabType != invalidTab); + + /* initially fill cache with any partial byte */ + cache = 0; + cachedBits = (8 - bitOffset) & 0x07; + if (cachedBits) + cache = (unsigned int)(*buf++) << (32 - cachedBits); + bitsLeft -= cachedBits; + + if (tabType == noBits) { + /* table 0, no data, x = y = 0 */ + for (i = 0; i < nVals; i+=2) { + xy[i+0] = 0; + xy[i+1] = 0; + } + return 0; + } else if (tabType == oneShot) { + /* single lookup, no escapes */ + maxBits = GetMaxbits(tBase[0]); + tBase++; + padBits = 0; + while (nVals > 0) { + /* refill cache - assumes cachedBits <= 16 */ + if (bitsLeft >= 16) { + /* load 2 new bytes into left-justified cache */ + cache |= (unsigned int)(*buf++) << (24 - cachedBits); + cache |= (unsigned int)(*buf++) << (16 - cachedBits); + cachedBits += 16; + bitsLeft -= 16; + } else { + /* last time through, pad cache with zeros and drain cache */ + if (cachedBits + bitsLeft <= 0) return -1; + if (bitsLeft > 0) cache |= (unsigned int)(*buf++) << (24 - cachedBits); + if (bitsLeft > 8) cache |= (unsigned int)(*buf++) << (16 - cachedBits); + cachedBits += bitsLeft; + bitsLeft = 0; + + cache &= (signed int)0x80000000 >> (cachedBits - 1); + padBits = 11; + cachedBits += padBits; /* okay if this is > 32 (0's automatically shifted in from right) */ + } + + /* largest maxBits = 9, plus 2 for sign bits, so make sure cache has at least 11 bits */ + while (nVals > 0 && cachedBits >= 11 ) { + cw = tBase[cache >> (32 - maxBits)]; + len = GetHLen(cw); + cachedBits -= len; + cache <<= len; + + x = GetCWX(cw); if (x) {ApplySign(x, cache); cache <<= 1; cachedBits--;} + y = GetCWY(cw); if (y) {ApplySign(y, cache); cache <<= 1; cachedBits--;} + + /* ran out of bits - should never have consumed padBits */ + if (cachedBits < padBits) + return -1; + + *xy++ = x; + *xy++ = y; + nVals -= 2; + } + } + bitsLeft += (cachedBits - padBits); + return (startBits - bitsLeft); + } else if (tabType == loopLinbits || tabType == loopNoLinbits) { + tCurr = tBase; + padBits = 0; + while (nVals > 0) { + /* refill cache - assumes cachedBits <= 16 */ + if (bitsLeft >= 16) { + /* load 2 new bytes into left-justified cache */ + cache |= (unsigned int)(*buf++) << (24 - cachedBits); + cache |= (unsigned int)(*buf++) << (16 - cachedBits); + cachedBits += 16; + bitsLeft -= 16; + } else { + /* last time through, pad cache with zeros and drain cache */ + if (cachedBits + bitsLeft <= 0) return -1; + if (bitsLeft > 0) cache |= (unsigned int)(*buf++) << (24 - cachedBits); + if (bitsLeft > 8) cache |= (unsigned int)(*buf++) << (16 - cachedBits); + cachedBits += bitsLeft; + bitsLeft = 0; + + cache &= (signed int)0x80000000 >> (cachedBits - 1); + padBits = 11; + cachedBits += padBits; /* okay if this is > 32 (0's automatically shifted in from right) */ + } + + /* largest maxBits = 9, plus 2 for sign bits, so make sure cache has at least 11 bits */ + while (nVals > 0 && cachedBits >= 11 ) { + maxBits = GetMaxbits(tCurr[0]); + cw = tCurr[(cache >> (32 - maxBits)) + 1]; + len = GetHLen(cw); + if (!len) { + cachedBits -= maxBits; + cache <<= maxBits; + tCurr += cw; + continue; + } + cachedBits -= len; + cache <<= len; + + x = GetCWX(cw); + y = GetCWY(cw); + + if (x == 15 && tabType == loopLinbits) { + minBits = linBits + 1 + (y ? 1 : 0); + if (cachedBits + bitsLeft < minBits) + return -1; + while (cachedBits < minBits) { + cache |= (unsigned int)(*buf++) << (24 - cachedBits); + cachedBits += 8; + bitsLeft -= 8; + } + if (bitsLeft < 0) { + cachedBits += bitsLeft; + bitsLeft = 0; + cache &= (signed int)0x80000000 >> (cachedBits - 1); + } + x += (int)(cache >> (32 - linBits)); + cachedBits -= linBits; + cache <<= linBits; + } + if (x) {ApplySign(x, cache); cache <<= 1; cachedBits--;} + + if (y == 15 && tabType == loopLinbits) { + minBits = linBits + 1; + if (cachedBits + bitsLeft < minBits) + return -1; + while (cachedBits < minBits) { + cache |= (unsigned int)(*buf++) << (24 - cachedBits); + cachedBits += 8; + bitsLeft -= 8; + } + if (bitsLeft < 0) { + cachedBits += bitsLeft; + bitsLeft = 0; + cache &= (signed int)0x80000000 >> (cachedBits - 1); + } + y += (int)(cache >> (32 - linBits)); + cachedBits -= linBits; + cache <<= linBits; + } + if (y) {ApplySign(y, cache); cache <<= 1; cachedBits--;} + + /* ran out of bits - should never have consumed padBits */ + if (cachedBits < padBits) + return -1; + + *xy++ = x; + *xy++ = y; + nVals -= 2; + tCurr = tBase; + } + } + bitsLeft += (cachedBits - padBits); + return (startBits - bitsLeft); + } + + /* error in bitstream - trying to access unused Huffman table */ + return -1; +} + +/************************************************************************************** + * Function: DecodeHuffmanQuads + * + * Description: decode 4-way vector Huffman codes in the "count1" region of spectrum + * + * Inputs: valid BitStreamInfo struct, pointing to start of quadword codes + * pointer to vwxy buffer to received decoded values + * maximum number of codewords to decode + * index of quadword table (0 = table A, 1 = table B) + * number of bits remaining in bitstream + * + * Outputs: quadruples of decoded coefficients in vwxy + * updated BitStreamInfo struct + * + * Return: index of the first "zero_part" value (index of the first sample + * of the quad word after which all samples are 0) + * + * Notes: si_huff.bit tests every vwxy output in both quad tables + **************************************************************************************/ +// no improvement with section=data +static int DecodeHuffmanQuads(int *vwxy, int nVals, int tabIdx, int bitsLeft, unsigned char *buf, int bitOffset) +{ + int i, v, w, x, y; + int len, maxBits, cachedBits, padBits; + unsigned int cache; + unsigned char cw, *tBase; + + if (bitsLeft <= 0) + return 0; + + tBase = (unsigned char *)quadTable + quadTabOffset[tabIdx]; + maxBits = quadTabMaxBits[tabIdx]; + + /* initially fill cache with any partial byte */ + cache = 0; + cachedBits = (8 - bitOffset) & 0x07; + if (cachedBits) + cache = (unsigned int)(*buf++) << (32 - cachedBits); + bitsLeft -= cachedBits; + + i = padBits = 0; + while (i < (nVals - 3)) { + /* refill cache - assumes cachedBits <= 16 */ + if (bitsLeft >= 16) { + /* load 2 new bytes into left-justified cache */ + cache |= (unsigned int)(*buf++) << (24 - cachedBits); + cache |= (unsigned int)(*buf++) << (16 - cachedBits); + cachedBits += 16; + bitsLeft -= 16; + } else { + /* last time through, pad cache with zeros and drain cache */ + if (cachedBits + bitsLeft <= 0) return i; + if (bitsLeft > 0) cache |= (unsigned int)(*buf++) << (24 - cachedBits); + if (bitsLeft > 8) cache |= (unsigned int)(*buf++) << (16 - cachedBits); + cachedBits += bitsLeft; + bitsLeft = 0; + + cache &= (signed int)0x80000000 >> (cachedBits - 1); + padBits = 10; + cachedBits += padBits; /* okay if this is > 32 (0's automatically shifted in from right) */ + } + + /* largest maxBits = 6, plus 4 for sign bits, so make sure cache has at least 10 bits */ + while (i < (nVals - 3) && cachedBits >= 10 ) { + cw = tBase[cache >> (32 - maxBits)]; + len = GetHLenQ(cw); + cachedBits -= len; + cache <<= len; + + v = GetCWVQ(cw); if(v) {ApplySign(v, cache); cache <<= 1; cachedBits--;} + w = GetCWWQ(cw); if(w) {ApplySign(w, cache); cache <<= 1; cachedBits--;} + x = GetCWXQ(cw); if(x) {ApplySign(x, cache); cache <<= 1; cachedBits--;} + y = GetCWYQ(cw); if(y) {ApplySign(y, cache); cache <<= 1; cachedBits--;} + + /* ran out of bits - okay (means we're done) */ + if (cachedBits < padBits) + return i; + + *vwxy++ = v; + *vwxy++ = w; + *vwxy++ = x; + *vwxy++ = y; + i += 4; + } + } + + /* decoded max number of quad values */ + return i; +} + +/************************************************************************************** + * Function: DecodeHuffman + * + * Description: decode one granule, one channel worth of Huffman codes + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader(), UnpackSideInfo(), + * and UnpackScaleFactors() (for this granule) + * buffer pointing to start of Huffman data in MP3 frame + * pointer to bit offset (0-7) indicating starting bit in buf[0] + * number of bits in the Huffman data section of the frame + * (could include padding bits) + * index of current granule and channel + * + * Outputs: decoded coefficients in hi->huffDecBuf[ch] (hi pointer in mp3DecInfo) + * updated bitOffset + * + * Return: length (in bytes) of Huffman codes + * bitOffset also returned in parameter (0 = MSB, 7 = LSB of + * byte located at buf + offset) + * -1 if null input pointers, huffBlockBits < 0, or decoder runs + * out of bits prematurely (invalid bitstream) + **************************************************************************************/ +// .data about 1ms faster per frame +int DecodeHuffman(MP3DecInfo *mp3DecInfo, unsigned char *buf, int *bitOffset, int huffBlockBits, int gr, int ch) +{ + int r1Start, r2Start, rEnd[4]; /* region boundaries */ + int i, w, bitsUsed, bitsLeft; + unsigned char *startBuf = buf; + + FrameHeader *fh; + SideInfo *si; + SideInfoSub *sis; + ScaleFactorInfo *sfi; + HuffmanInfo *hi; + + /* validate pointers */ + if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS || !mp3DecInfo->SideInfoPS || !mp3DecInfo->ScaleFactorInfoPS || !mp3DecInfo->HuffmanInfoPS) + return -1; + + fh = ((FrameHeader *)(mp3DecInfo->FrameHeaderPS)); + si = ((SideInfo *)(mp3DecInfo->SideInfoPS)); + sis = &si->sis[gr][ch]; + sfi = ((ScaleFactorInfo *)(mp3DecInfo->ScaleFactorInfoPS)); + hi = (HuffmanInfo*)(mp3DecInfo->HuffmanInfoPS); + + if (huffBlockBits < 0) + return -1; + + /* figure out region boundaries (the first 2*bigVals coefficients divided into 3 regions) */ + if (sis->winSwitchFlag && sis->blockType == 2) { + if (sis->mixedBlock == 0) { + r1Start = fh->sfBand->s[(sis->region0Count + 1)/3] * 3; + } else { + if (fh->ver == MPEG1) { + r1Start = fh->sfBand->l[sis->region0Count + 1]; + } else { + /* see MPEG2 spec for explanation */ + w = fh->sfBand->s[4] - fh->sfBand->s[3]; + r1Start = fh->sfBand->l[6] + 2*w; + } + } + r2Start = MAX_NSAMP; /* short blocks don't have region 2 */ + } else { + r1Start = fh->sfBand->l[sis->region0Count + 1]; + r2Start = fh->sfBand->l[sis->region0Count + 1 + sis->region1Count + 1]; + } + + /* offset rEnd index by 1 so first region = rEnd[1] - rEnd[0], etc. */ + rEnd[3] = MIN(MAX_NSAMP, 2 * sis->nBigvals); + rEnd[2] = MIN(r2Start, rEnd[3]); + rEnd[1] = MIN(r1Start, rEnd[3]); + rEnd[0] = 0; + + /* rounds up to first all-zero pair (we don't check last pair for (x,y) == (non-zero, zero)) */ + hi->nonZeroBound[ch] = rEnd[3]; + + /* decode Huffman pairs (rEnd[i] are always even numbers) */ + bitsLeft = huffBlockBits; + for (i = 0; i < 3; i++) { + bitsUsed = DecodeHuffmanPairs(hi->huffDecBuf[ch] + rEnd[i], rEnd[i+1] - rEnd[i], sis->tableSelect[i], bitsLeft, buf, *bitOffset); + if (bitsUsed < 0 || bitsUsed > bitsLeft) /* error - overran end of bitstream */ + return -1; + + /* update bitstream position */ + buf += (bitsUsed + *bitOffset) >> 3; + *bitOffset = (bitsUsed + *bitOffset) & 0x07; + bitsLeft -= bitsUsed; + } + + /* decode Huffman quads (if any) */ + hi->nonZeroBound[ch] += DecodeHuffmanQuads(hi->huffDecBuf[ch] + rEnd[3], MAX_NSAMP - rEnd[3], sis->count1TableSelect, bitsLeft, buf, *bitOffset); + + ASSERT(hi->nonZeroBound[ch] <= MAX_NSAMP); + for (i = hi->nonZeroBound[ch]; i < MAX_NSAMP; i++) + hi->huffDecBuf[ch][i] = 0; + + /* If bits used for 576 samples < huffBlockBits, then the extras are considered + * to be stuffing bits (throw away, but need to return correct bitstream position) + */ + buf += (bitsLeft + *bitOffset) >> 3; + *bitOffset = (bitsLeft + *bitOffset) & 0x07; + + return (buf - startBuf); +} + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/hufftabs.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/hufftabs.c new file mode 100644 index 0000000..916e114 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/hufftabs.c @@ -0,0 +1,755 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * hufftabs.c - compressed Huffman code tables + **************************************************************************************/ + +#include "coder.h" + +/* NOTE - regenerated tables to use shorts instead of ints + * (all needed data can fit in 16 bits - see below) + * + * format 0xABCD + * A = length of codeword + * B = y value + * C = x value + * D = number of sign bits (0, 1, or 2) + * + * to read a CW, the code reads maxbits from the stream (dep. on + * table index), but doesn't remove them from the bitstream reader + * then it gets the correct CW by direct lookup into the table + * of length (2^maxbits) (more complicated for non-oneShot...) + * for CW's with hlen < maxbits, there are multiple entries in the + * table (extra bits are don't cares) + * the bitstream reader then "purges" (or removes) only the correct + * number of bits for the chosen CW + * + * entries starting with F are special: D (signbits) is maxbits, + * so the decoder always checks huffTableXX[0] first, gets the + * signbits, and reads that many bits from the bitstream + * (sometimes it takes > 1 read to get the value, so maxbits is + * can get updated by jumping to another value starting with 0xF) + * entries starting with 0 are also special: A = hlen = 0, rest of + * value is an offset to jump higher in the table (for tables of + * type loopNoLinbits or loopLinbits) + */ + +/* store Huffman codes as one big table plus table of offsets, since some platforms + * don't properly support table-of-tables (table of pointers to other const tables) + */ +const unsigned short huffTable[] = { + /* huffTable01[9] */ + 0xf003, 0x3112, 0x3101, 0x2011, 0x2011, 0x1000, 0x1000, 0x1000, + 0x1000, + + /* huffTable02[65] */ + 0xf006, 0x6222, 0x6201, 0x5212, 0x5212, 0x5122, 0x5122, 0x5021, + 0x5021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, + + /* huffTable03[65] */ + 0xf006, 0x6222, 0x6201, 0x5212, 0x5212, 0x5122, 0x5122, 0x5021, + 0x5021, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, + 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, 0x2101, + 0x2101, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, + + /* huffTable05[257] */ + 0xf008, 0x8332, 0x8322, 0x7232, 0x7232, 0x6132, 0x6132, 0x6132, + 0x6132, 0x7312, 0x7312, 0x7301, 0x7301, 0x7031, 0x7031, 0x7222, + 0x7222, 0x6212, 0x6212, 0x6212, 0x6212, 0x6122, 0x6122, 0x6122, + 0x6122, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, + 0x6021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, + + /* huffTable06[129] */ + 0xf007, 0x7332, 0x7301, 0x6322, 0x6322, 0x6232, 0x6232, 0x6031, + 0x6031, 0x5312, 0x5312, 0x5312, 0x5312, 0x5132, 0x5132, 0x5132, + 0x5132, 0x5222, 0x5222, 0x5222, 0x5222, 0x5201, 0x5201, 0x5201, + 0x5201, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, + 0x4122, 0x4021, 0x4021, 0x4021, 0x4021, 0x4021, 0x4021, 0x4021, + 0x4021, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, + + /* huffTable07[110] */ + 0xf006, 0x0041, 0x0052, 0x005b, 0x0060, 0x0063, 0x0068, 0x006b, + 0x6212, 0x5122, 0x5122, 0x6201, 0x6021, 0x4112, 0x4112, 0x4112, + 0x4112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0xf004, 0x4552, 0x4542, 0x4452, 0x4352, 0x3532, 0x3532, + 0x3442, 0x3442, 0x3522, 0x3522, 0x3252, 0x3252, 0x2512, 0x2512, + 0x2512, 0x2512, 0xf003, 0x2152, 0x2152, 0x3501, 0x3432, 0x2051, + 0x2051, 0x3342, 0x3332, 0xf002, 0x2422, 0x2242, 0x1412, 0x1412, + 0xf001, 0x1142, 0x1041, 0xf002, 0x2401, 0x2322, 0x2232, 0x2301, + 0xf001, 0x1312, 0x1132, 0xf001, 0x1031, 0x1222, + + /* huffTable08[280] */ + 0xf008, 0x0101, 0x010a, 0x010f, 0x8512, 0x8152, 0x0112, 0x0115, + 0x8422, 0x8242, 0x8412, 0x7142, 0x7142, 0x8401, 0x8041, 0x8322, + 0x8232, 0x8312, 0x8132, 0x8301, 0x8031, 0x6222, 0x6222, 0x6222, + 0x6222, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, + 0x6021, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, + 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, + 0x4122, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, 0x2112, + 0x2112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0xf003, 0x3552, 0x3452, 0x2542, 0x2542, 0x1352, 0x1352, + 0x1352, 0x1352, 0xf002, 0x2532, 0x2442, 0x1522, 0x1522, 0xf001, + 0x1252, 0x1501, 0xf001, 0x1432, 0x1342, 0xf001, 0x1051, 0x1332, + + /* huffTable09[93] */ + 0xf006, 0x0041, 0x004a, 0x004f, 0x0052, 0x0057, 0x005a, 0x6412, + 0x6142, 0x6322, 0x6232, 0x5312, 0x5312, 0x5132, 0x5132, 0x6301, + 0x6031, 0x5222, 0x5222, 0x5201, 0x5201, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4122, 0x4122, 0x4122, 0x4122, 0x4021, 0x4021, 0x4021, + 0x4021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, 0xf003, 0x3552, 0x3542, 0x2532, 0x2532, 0x2352, 0x2352, + 0x3452, 0x3501, 0xf002, 0x2442, 0x2522, 0x2252, 0x2512, 0xf001, + 0x1152, 0x1432, 0xf002, 0x1342, 0x1342, 0x2051, 0x2401, 0xf001, + 0x1422, 0x1242, 0xf001, 0x1332, 0x1041, + + /* huffTable10[320] */ + 0xf008, 0x0101, 0x010a, 0x010f, 0x0118, 0x011b, 0x0120, 0x0125, + 0x8712, 0x8172, 0x012a, 0x012d, 0x0132, 0x8612, 0x8162, 0x8061, + 0x0137, 0x013a, 0x013d, 0x8412, 0x8142, 0x8041, 0x8322, 0x8232, + 0x8301, 0x7312, 0x7312, 0x7132, 0x7132, 0x7031, 0x7031, 0x7222, + 0x7222, 0x6212, 0x6212, 0x6212, 0x6212, 0x6122, 0x6122, 0x6122, + 0x6122, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, + 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0xf003, 0x3772, 0x3762, 0x3672, 0x3752, 0x3572, 0x3662, + 0x2742, 0x2742, 0xf002, 0x2472, 0x2652, 0x2562, 0x2732, 0xf003, + 0x2372, 0x2372, 0x2642, 0x2642, 0x3552, 0x3452, 0x2362, 0x2362, + 0xf001, 0x1722, 0x1272, 0xf002, 0x2462, 0x2701, 0x1071, 0x1071, + 0xf002, 0x1262, 0x1262, 0x2542, 0x2532, 0xf002, 0x1601, 0x1601, + 0x2352, 0x2442, 0xf001, 0x1632, 0x1622, 0xf002, 0x2522, 0x2252, + 0x1512, 0x1512, 0xf002, 0x1152, 0x1152, 0x2432, 0x2342, 0xf001, + 0x1501, 0x1051, 0xf001, 0x1422, 0x1242, 0xf001, 0x1332, 0x1401, + + /* huffTable11[296] */ + 0xf008, 0x0101, 0x0106, 0x010f, 0x0114, 0x0117, 0x8722, 0x8272, + 0x011c, 0x7172, 0x7172, 0x8712, 0x8071, 0x8632, 0x8362, 0x8061, + 0x011f, 0x0122, 0x8512, 0x7262, 0x7262, 0x8622, 0x8601, 0x7612, + 0x7612, 0x7162, 0x7162, 0x8152, 0x8432, 0x8051, 0x0125, 0x8422, + 0x8242, 0x8412, 0x8142, 0x8401, 0x8041, 0x7322, 0x7322, 0x7232, + 0x7232, 0x6312, 0x6312, 0x6312, 0x6312, 0x6132, 0x6132, 0x6132, + 0x6132, 0x7301, 0x7301, 0x7031, 0x7031, 0x6222, 0x6222, 0x6222, + 0x6222, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, + 0x5122, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, + 0x4212, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, + 0x5201, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, + 0x5021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, + 0x2000, 0xf002, 0x2772, 0x2762, 0x2672, 0x2572, 0xf003, 0x2662, + 0x2662, 0x2742, 0x2742, 0x2472, 0x2472, 0x3752, 0x3552, 0xf002, + 0x2652, 0x2562, 0x1732, 0x1732, 0xf001, 0x1372, 0x1642, 0xf002, + 0x2542, 0x2452, 0x2532, 0x2352, 0xf001, 0x1462, 0x1701, 0xf001, + 0x1442, 0x1522, 0xf001, 0x1252, 0x1501, 0xf001, 0x1342, 0x1332, + + /* huffTable12[185] */ + 0xf007, 0x0081, 0x008a, 0x008f, 0x0092, 0x0097, 0x009a, 0x009d, + 0x00a2, 0x00a5, 0x00a8, 0x7622, 0x7262, 0x7162, 0x00ad, 0x00b0, + 0x00b3, 0x7512, 0x7152, 0x7432, 0x7342, 0x00b6, 0x7422, 0x7242, + 0x7412, 0x6332, 0x6332, 0x6142, 0x6142, 0x6322, 0x6322, 0x6232, + 0x6232, 0x7041, 0x7301, 0x6031, 0x6031, 0x5312, 0x5312, 0x5312, + 0x5312, 0x5132, 0x5132, 0x5132, 0x5132, 0x5222, 0x5222, 0x5222, + 0x5222, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, 0x4212, + 0x4212, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, 0x4122, + 0x4122, 0x5201, 0x5201, 0x5201, 0x5201, 0x5021, 0x5021, 0x5021, + 0x5021, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, + 0x4000, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, 0x3101, + 0x3101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0xf003, 0x3772, 0x3762, 0x2672, 0x2672, 0x2752, 0x2752, + 0x2572, 0x2572, 0xf002, 0x2662, 0x2742, 0x2472, 0x2562, 0xf001, + 0x1652, 0x1732, 0xf002, 0x2372, 0x2552, 0x1722, 0x1722, 0xf001, + 0x1272, 0x1642, 0xf001, 0x1462, 0x1712, 0xf002, 0x1172, 0x1172, + 0x2701, 0x2071, 0xf001, 0x1632, 0x1362, 0xf001, 0x1542, 0x1452, + 0xf002, 0x1442, 0x1442, 0x2601, 0x2501, 0xf001, 0x1612, 0x1061, + 0xf001, 0x1532, 0x1352, 0xf001, 0x1522, 0x1252, 0xf001, 0x1051, + 0x1401, + + /* huffTable13[497] */ + 0xf006, 0x0041, 0x0082, 0x00c3, 0x00e4, 0x0105, 0x0116, 0x011f, + 0x0130, 0x0139, 0x013e, 0x0143, 0x0146, 0x6212, 0x6122, 0x6201, + 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4101, 0x4101, 0x4101, + 0x4101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0xf006, 0x0108, 0x0111, 0x011a, 0x0123, 0x012c, 0x0131, + 0x0136, 0x013f, 0x0144, 0x0147, 0x014c, 0x0151, 0x0156, 0x015b, + 0x6f12, 0x61f2, 0x60f1, 0x0160, 0x0163, 0x0166, 0x62e2, 0x0169, + 0x6e12, 0x61e2, 0x016c, 0x016f, 0x0172, 0x0175, 0x0178, 0x017b, + 0x66c2, 0x6d32, 0x017e, 0x6d22, 0x62d2, 0x6d12, 0x67b2, 0x0181, + 0x0184, 0x63c2, 0x0187, 0x6b42, 0x51d2, 0x51d2, 0x6d01, 0x60d1, + 0x6a82, 0x68a2, 0x6c42, 0x64c2, 0x6b62, 0x66b2, 0x5c32, 0x5c32, + 0x5c22, 0x5c22, 0x52c2, 0x52c2, 0x5b52, 0x5b52, 0x65b2, 0x6982, + 0x5c12, 0x5c12, 0xf006, 0x51c2, 0x51c2, 0x6892, 0x6c01, 0x50c1, + 0x50c1, 0x64b2, 0x6a62, 0x66a2, 0x6972, 0x5b32, 0x5b32, 0x53b2, + 0x53b2, 0x6882, 0x6a52, 0x5b22, 0x5b22, 0x65a2, 0x6962, 0x54a2, + 0x54a2, 0x6872, 0x6782, 0x5492, 0x5492, 0x6772, 0x6672, 0x42b2, + 0x42b2, 0x42b2, 0x42b2, 0x4b12, 0x4b12, 0x4b12, 0x4b12, 0x41b2, + 0x41b2, 0x41b2, 0x41b2, 0x5b01, 0x5b01, 0x50b1, 0x50b1, 0x5692, + 0x5692, 0x5a42, 0x5a42, 0x5a32, 0x5a32, 0x53a2, 0x53a2, 0x5952, + 0x5952, 0x5592, 0x5592, 0x4a22, 0x4a22, 0x4a22, 0x4a22, 0x42a2, + 0x42a2, 0x42a2, 0x42a2, 0xf005, 0x4a12, 0x4a12, 0x41a2, 0x41a2, + 0x5a01, 0x5862, 0x40a1, 0x40a1, 0x5682, 0x5942, 0x4392, 0x4392, + 0x5932, 0x5852, 0x5582, 0x5762, 0x4922, 0x4922, 0x4292, 0x4292, + 0x5752, 0x5572, 0x4832, 0x4832, 0x4382, 0x4382, 0x5662, 0x5742, + 0x5472, 0x5652, 0x5562, 0x5372, 0xf005, 0x3912, 0x3912, 0x3912, + 0x3912, 0x3192, 0x3192, 0x3192, 0x3192, 0x4901, 0x4901, 0x4091, + 0x4091, 0x4842, 0x4842, 0x4482, 0x4482, 0x4272, 0x4272, 0x5642, + 0x5462, 0x3822, 0x3822, 0x3822, 0x3822, 0x3282, 0x3282, 0x3282, + 0x3282, 0x3812, 0x3812, 0x3812, 0x3812, 0xf004, 0x4732, 0x4722, + 0x3712, 0x3712, 0x3172, 0x3172, 0x4552, 0x4701, 0x4071, 0x4632, + 0x4362, 0x4542, 0x4452, 0x4622, 0x4262, 0x4532, 0xf003, 0x2182, + 0x2182, 0x3801, 0x3081, 0x3612, 0x3162, 0x3601, 0x3061, 0xf004, + 0x4352, 0x4442, 0x3522, 0x3522, 0x3252, 0x3252, 0x3501, 0x3501, + 0x2512, 0x2512, 0x2512, 0x2512, 0x2152, 0x2152, 0x2152, 0x2152, + 0xf003, 0x3432, 0x3342, 0x3051, 0x3422, 0x3242, 0x3332, 0x2412, + 0x2412, 0xf002, 0x1142, 0x1142, 0x2401, 0x2041, 0xf002, 0x2322, + 0x2232, 0x1312, 0x1312, 0xf001, 0x1132, 0x1301, 0xf001, 0x1031, + 0x1222, 0xf003, 0x0082, 0x008b, 0x008e, 0x0091, 0x0094, 0x0097, + 0x3ce2, 0x3dd2, 0xf003, 0x0093, 0x3eb2, 0x3be2, 0x3f92, 0x39f2, + 0x3ae2, 0x3db2, 0x3bd2, 0xf003, 0x3f82, 0x38f2, 0x3cc2, 0x008d, + 0x3e82, 0x0090, 0x27f2, 0x27f2, 0xf003, 0x2ad2, 0x2ad2, 0x3da2, + 0x3cb2, 0x3bc2, 0x36f2, 0x2f62, 0x2f62, 0xf002, 0x28e2, 0x2f52, + 0x2d92, 0x29d2, 0xf002, 0x25f2, 0x27e2, 0x2ca2, 0x2bb2, 0xf003, + 0x2f42, 0x2f42, 0x24f2, 0x24f2, 0x3ac2, 0x36e2, 0x23f2, 0x23f2, + 0xf002, 0x1f32, 0x1f32, 0x2d82, 0x28d2, 0xf001, 0x1f22, 0x12f2, + 0xf002, 0x2e62, 0x2c92, 0x1f01, 0x1f01, 0xf002, 0x29c2, 0x2e52, + 0x1ba2, 0x1ba2, 0xf002, 0x2d72, 0x27d2, 0x1e42, 0x1e42, 0xf002, + 0x28c2, 0x26d2, 0x1e32, 0x1e32, 0xf002, 0x19b2, 0x19b2, 0x2b92, + 0x2aa2, 0xf001, 0x1ab2, 0x15e2, 0xf001, 0x14e2, 0x1c82, 0xf001, + 0x1d62, 0x13e2, 0xf001, 0x1e22, 0x1e01, 0xf001, 0x10e1, 0x1d52, + 0xf001, 0x15d2, 0x1c72, 0xf001, 0x17c2, 0x1d42, 0xf001, 0x1b82, + 0x18b2, 0xf001, 0x14d2, 0x1a92, 0xf001, 0x19a2, 0x1c62, 0xf001, + 0x13d2, 0x1b72, 0xf001, 0x1c52, 0x15c2, 0xf001, 0x1992, 0x1a72, + 0xf001, 0x17a2, 0x1792, 0xf003, 0x0023, 0x3df2, 0x2de2, 0x2de2, + 0x1ff2, 0x1ff2, 0x1ff2, 0x1ff2, 0xf001, 0x1fe2, 0x1fd2, 0xf001, + 0x1ee2, 0x1fc2, 0xf001, 0x1ed2, 0x1fb2, 0xf001, 0x1bf2, 0x1ec2, + 0xf002, 0x1cd2, 0x1cd2, 0x2fa2, 0x29e2, 0xf001, 0x1af2, 0x1dc2, + 0xf001, 0x1ea2, 0x1e92, 0xf001, 0x1f72, 0x1e72, 0xf001, 0x1ef2, + 0x1cf2, + + /* huffTable15[580] */ + 0xf008, 0x0101, 0x0122, 0x0143, 0x0154, 0x0165, 0x0176, 0x017f, + 0x0188, 0x0199, 0x01a2, 0x01ab, 0x01b4, 0x01bd, 0x01c2, 0x01cb, + 0x01d4, 0x01d9, 0x01de, 0x01e3, 0x01e8, 0x01ed, 0x01f2, 0x01f7, + 0x01fc, 0x0201, 0x0204, 0x0207, 0x020a, 0x020f, 0x0212, 0x0215, + 0x021a, 0x021d, 0x0220, 0x8192, 0x0223, 0x0226, 0x0229, 0x022c, + 0x022f, 0x8822, 0x8282, 0x8812, 0x8182, 0x0232, 0x0235, 0x0238, + 0x023b, 0x8722, 0x8272, 0x8462, 0x8712, 0x8552, 0x8172, 0x023e, + 0x8632, 0x8362, 0x8542, 0x8452, 0x8622, 0x8262, 0x8612, 0x0241, + 0x8532, 0x7162, 0x7162, 0x8352, 0x8442, 0x7522, 0x7522, 0x7252, + 0x7252, 0x7512, 0x7512, 0x7152, 0x7152, 0x8501, 0x8051, 0x7432, + 0x7432, 0x7342, 0x7342, 0x7422, 0x7422, 0x7242, 0x7242, 0x7332, + 0x7332, 0x6142, 0x6142, 0x6142, 0x6142, 0x7412, 0x7412, 0x7401, + 0x7401, 0x6322, 0x6322, 0x6322, 0x6322, 0x6232, 0x6232, 0x6232, + 0x6232, 0x7041, 0x7041, 0x7301, 0x7301, 0x6312, 0x6312, 0x6312, + 0x6312, 0x6132, 0x6132, 0x6132, 0x6132, 0x6031, 0x6031, 0x6031, + 0x6031, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, 0x5222, + 0x5222, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, + 0x5212, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, + 0x5122, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, 0x5201, + 0x5201, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, 0x5021, + 0x5021, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, 0x3112, + 0x3112, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, + 0x3000, 0xf005, 0x5ff2, 0x5fe2, 0x5ef2, 0x5fd2, 0x4ee2, 0x4ee2, + 0x5df2, 0x5fc2, 0x5cf2, 0x5ed2, 0x5de2, 0x5fb2, 0x4bf2, 0x4bf2, + 0x5ec2, 0x5ce2, 0x4dd2, 0x4dd2, 0x4fa2, 0x4fa2, 0x4af2, 0x4af2, + 0x4eb2, 0x4eb2, 0x4be2, 0x4be2, 0x4dc2, 0x4dc2, 0x4cd2, 0x4cd2, + 0x4f92, 0x4f92, 0xf005, 0x49f2, 0x49f2, 0x4ae2, 0x4ae2, 0x4db2, + 0x4db2, 0x4bd2, 0x4bd2, 0x4f82, 0x4f82, 0x48f2, 0x48f2, 0x4cc2, + 0x4cc2, 0x4e92, 0x4e92, 0x49e2, 0x49e2, 0x4f72, 0x4f72, 0x47f2, + 0x47f2, 0x4da2, 0x4da2, 0x4ad2, 0x4ad2, 0x4cb2, 0x4cb2, 0x4f62, + 0x4f62, 0x5ea2, 0x5f01, 0xf004, 0x3bc2, 0x3bc2, 0x36f2, 0x36f2, + 0x4e82, 0x48e2, 0x4f52, 0x4d92, 0x35f2, 0x35f2, 0x3e72, 0x3e72, + 0x37e2, 0x37e2, 0x3ca2, 0x3ca2, 0xf004, 0x3ac2, 0x3ac2, 0x3bb2, + 0x3bb2, 0x49d2, 0x4d82, 0x3f42, 0x3f42, 0x34f2, 0x34f2, 0x3f32, + 0x3f32, 0x33f2, 0x33f2, 0x38d2, 0x38d2, 0xf004, 0x36e2, 0x36e2, + 0x3f22, 0x3f22, 0x32f2, 0x32f2, 0x4e62, 0x40f1, 0x3f12, 0x3f12, + 0x31f2, 0x31f2, 0x3c92, 0x3c92, 0x39c2, 0x39c2, 0xf003, 0x3e52, + 0x3ba2, 0x3ab2, 0x35e2, 0x3d72, 0x37d2, 0x3e42, 0x34e2, 0xf003, + 0x3c82, 0x38c2, 0x3e32, 0x3d62, 0x36d2, 0x33e2, 0x3b92, 0x39b2, + 0xf004, 0x3e22, 0x3e22, 0x3aa2, 0x3aa2, 0x32e2, 0x32e2, 0x3e12, + 0x3e12, 0x31e2, 0x31e2, 0x4e01, 0x40e1, 0x3d52, 0x3d52, 0x35d2, + 0x35d2, 0xf003, 0x3c72, 0x37c2, 0x3d42, 0x3b82, 0x24d2, 0x24d2, + 0x38b2, 0x3a92, 0xf003, 0x39a2, 0x3c62, 0x36c2, 0x3d32, 0x23d2, + 0x23d2, 0x22d2, 0x22d2, 0xf003, 0x3d22, 0x3d01, 0x2d12, 0x2d12, + 0x2b72, 0x2b72, 0x27b2, 0x27b2, 0xf003, 0x21d2, 0x21d2, 0x3c52, + 0x30d1, 0x25c2, 0x25c2, 0x2a82, 0x2a82, 0xf002, 0x28a2, 0x2c42, + 0x24c2, 0x2b62, 0xf003, 0x26b2, 0x26b2, 0x3992, 0x3c01, 0x2c32, + 0x2c32, 0x23c2, 0x23c2, 0xf003, 0x2a72, 0x2a72, 0x27a2, 0x27a2, + 0x26a2, 0x26a2, 0x30c1, 0x3b01, 0xf002, 0x12c2, 0x12c2, 0x2c22, + 0x2b52, 0xf002, 0x25b2, 0x2c12, 0x2982, 0x2892, 0xf002, 0x21c2, + 0x2b42, 0x24b2, 0x2a62, 0xf002, 0x2b32, 0x2972, 0x13b2, 0x13b2, + 0xf002, 0x2792, 0x2882, 0x2b22, 0x2a52, 0xf002, 0x12b2, 0x12b2, + 0x25a2, 0x2b12, 0xf002, 0x11b2, 0x11b2, 0x20b1, 0x2962, 0xf002, + 0x2692, 0x2a42, 0x24a2, 0x2872, 0xf002, 0x2782, 0x2a32, 0x13a2, + 0x13a2, 0xf001, 0x1952, 0x1592, 0xf001, 0x1a22, 0x12a2, 0xf001, + 0x1a12, 0x11a2, 0xf002, 0x2a01, 0x20a1, 0x1862, 0x1862, 0xf001, + 0x1682, 0x1942, 0xf001, 0x1492, 0x1932, 0xf002, 0x1392, 0x1392, + 0x2772, 0x2901, 0xf001, 0x1852, 0x1582, 0xf001, 0x1922, 0x1762, + 0xf001, 0x1672, 0x1292, 0xf001, 0x1912, 0x1091, 0xf001, 0x1842, + 0x1482, 0xf001, 0x1752, 0x1572, 0xf001, 0x1832, 0x1382, 0xf001, + 0x1662, 0x1742, 0xf001, 0x1472, 0x1801, 0xf001, 0x1081, 0x1652, + 0xf001, 0x1562, 0x1732, 0xf001, 0x1372, 0x1642, 0xf001, 0x1701, + 0x1071, 0xf001, 0x1601, 0x1061, + + /* huffTable16[651] */ + 0xf008, 0x0101, 0x010a, 0x0113, 0x8ff2, 0x0118, 0x011d, 0x0120, + 0x82f2, 0x0131, 0x8f12, 0x81f2, 0x0134, 0x0145, 0x0156, 0x0167, + 0x0178, 0x0189, 0x019a, 0x01a3, 0x01ac, 0x01b5, 0x01be, 0x01c7, + 0x01d0, 0x01d9, 0x01de, 0x01e3, 0x01e6, 0x01eb, 0x01f0, 0x8152, + 0x01f3, 0x01f6, 0x01f9, 0x01fc, 0x8412, 0x8142, 0x01ff, 0x8322, + 0x8232, 0x7312, 0x7312, 0x7132, 0x7132, 0x8301, 0x8031, 0x7222, + 0x7222, 0x6212, 0x6212, 0x6212, 0x6212, 0x6122, 0x6122, 0x6122, + 0x6122, 0x6201, 0x6201, 0x6201, 0x6201, 0x6021, 0x6021, 0x6021, + 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, 0x3011, + 0x3011, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, + 0x1000, 0xf003, 0x3fe2, 0x3ef2, 0x3fd2, 0x3df2, 0x3fc2, 0x3cf2, + 0x3fb2, 0x3bf2, 0xf003, 0x2fa2, 0x2fa2, 0x3af2, 0x3f92, 0x39f2, + 0x38f2, 0x2f82, 0x2f82, 0xf002, 0x2f72, 0x27f2, 0x2f62, 0x26f2, + 0xf002, 0x2f52, 0x25f2, 0x1f42, 0x1f42, 0xf001, 0x14f2, 0x13f2, + 0xf004, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, 0x10f1, + 0x10f1, 0x2f32, 0x2f32, 0x2f32, 0x2f32, 0x00e2, 0x00f3, 0x00fc, + 0x0105, 0xf001, 0x1f22, 0x1f01, 0xf004, 0x00fa, 0x00ff, 0x0104, + 0x0109, 0x010c, 0x0111, 0x0116, 0x0119, 0x011e, 0x0123, 0x0128, + 0x43e2, 0x012d, 0x0130, 0x0133, 0x0136, 0xf004, 0x0128, 0x012b, + 0x012e, 0x4d01, 0x0131, 0x0134, 0x0137, 0x4c32, 0x013a, 0x4c12, + 0x40c1, 0x013d, 0x32e2, 0x32e2, 0x4e22, 0x4e12, 0xf004, 0x43d2, + 0x4d22, 0x42d2, 0x41d2, 0x4b32, 0x012f, 0x3d12, 0x3d12, 0x44c2, + 0x4b62, 0x43c2, 0x47a2, 0x3c22, 0x3c22, 0x42c2, 0x45b2, 0xf004, + 0x41c2, 0x4c01, 0x4b42, 0x44b2, 0x4a62, 0x46a2, 0x33b2, 0x33b2, + 0x4a52, 0x45a2, 0x3b22, 0x3b22, 0x32b2, 0x32b2, 0x3b12, 0x3b12, + 0xf004, 0x31b2, 0x31b2, 0x4b01, 0x40b1, 0x4962, 0x4692, 0x4a42, + 0x44a2, 0x4872, 0x4782, 0x33a2, 0x33a2, 0x4a32, 0x4952, 0x3a22, + 0x3a22, 0xf004, 0x4592, 0x4862, 0x31a2, 0x31a2, 0x4682, 0x4772, + 0x3492, 0x3492, 0x4942, 0x4752, 0x3762, 0x3762, 0x22a2, 0x22a2, + 0x22a2, 0x22a2, 0xf003, 0x2a12, 0x2a12, 0x3a01, 0x30a1, 0x3932, + 0x3392, 0x3852, 0x3582, 0xf003, 0x2922, 0x2922, 0x2292, 0x2292, + 0x3672, 0x3901, 0x2912, 0x2912, 0xf003, 0x2192, 0x2192, 0x3091, + 0x3842, 0x3482, 0x3572, 0x3832, 0x3382, 0xf003, 0x3662, 0x3822, + 0x2282, 0x2282, 0x3742, 0x3472, 0x2812, 0x2812, 0xf003, 0x2182, + 0x2182, 0x2081, 0x2081, 0x3801, 0x3652, 0x2732, 0x2732, 0xf003, + 0x2372, 0x2372, 0x3562, 0x3642, 0x2722, 0x2722, 0x2272, 0x2272, + 0xf003, 0x3462, 0x3552, 0x2701, 0x2701, 0x1712, 0x1712, 0x1712, + 0x1712, 0xf002, 0x1172, 0x1172, 0x2071, 0x2632, 0xf002, 0x2362, + 0x2542, 0x2452, 0x2622, 0xf001, 0x1262, 0x1612, 0xf002, 0x1162, + 0x1162, 0x2601, 0x2061, 0xf002, 0x1352, 0x1352, 0x2532, 0x2442, + 0xf001, 0x1522, 0x1252, 0xf001, 0x1512, 0x1501, 0xf001, 0x1432, + 0x1342, 0xf001, 0x1051, 0x1422, 0xf001, 0x1242, 0x1332, 0xf001, + 0x1401, 0x1041, 0xf004, 0x4ec2, 0x0086, 0x3ed2, 0x3ed2, 0x39e2, + 0x39e2, 0x4ae2, 0x49d2, 0x2ee2, 0x2ee2, 0x2ee2, 0x2ee2, 0x3de2, + 0x3de2, 0x3be2, 0x3be2, 0xf003, 0x2eb2, 0x2eb2, 0x2dc2, 0x2dc2, + 0x3cd2, 0x3bd2, 0x2ea2, 0x2ea2, 0xf003, 0x2cc2, 0x2cc2, 0x3da2, + 0x3ad2, 0x3e72, 0x3ca2, 0x2ac2, 0x2ac2, 0xf003, 0x39c2, 0x3d72, + 0x2e52, 0x2e52, 0x1db2, 0x1db2, 0x1db2, 0x1db2, 0xf002, 0x1e92, + 0x1e92, 0x2cb2, 0x2bc2, 0xf002, 0x2e82, 0x28e2, 0x2d92, 0x27e2, + 0xf002, 0x2bb2, 0x2d82, 0x28d2, 0x2e62, 0xf001, 0x16e2, 0x1c92, + 0xf002, 0x2ba2, 0x2ab2, 0x25e2, 0x27d2, 0xf002, 0x1e42, 0x1e42, + 0x24e2, 0x2c82, 0xf001, 0x18c2, 0x1e32, 0xf002, 0x1d62, 0x1d62, + 0x26d2, 0x2b92, 0xf002, 0x29b2, 0x2aa2, 0x11e2, 0x11e2, 0xf002, + 0x14d2, 0x14d2, 0x28b2, 0x29a2, 0xf002, 0x1b72, 0x1b72, 0x27b2, + 0x20d1, 0xf001, 0x1e01, 0x10e1, 0xf001, 0x1d52, 0x15d2, 0xf001, + 0x1c72, 0x17c2, 0xf001, 0x1d42, 0x1b82, 0xf001, 0x1a92, 0x1c62, + 0xf001, 0x16c2, 0x1d32, 0xf001, 0x1c52, 0x15c2, 0xf001, 0x1a82, + 0x18a2, 0xf001, 0x1992, 0x1c42, 0xf001, 0x16b2, 0x1a72, 0xf001, + 0x1b52, 0x1982, 0xf001, 0x1892, 0x1972, 0xf001, 0x1792, 0x1882, + 0xf001, 0x1ce2, 0x1dd2, + + /* huffTable24[705] */ + 0xf009, 0x8fe2, 0x8fe2, 0x8ef2, 0x8ef2, 0x8fd2, 0x8fd2, 0x8df2, + 0x8df2, 0x8fc2, 0x8fc2, 0x8cf2, 0x8cf2, 0x8fb2, 0x8fb2, 0x8bf2, + 0x8bf2, 0x7af2, 0x7af2, 0x7af2, 0x7af2, 0x8fa2, 0x8fa2, 0x8f92, + 0x8f92, 0x79f2, 0x79f2, 0x79f2, 0x79f2, 0x78f2, 0x78f2, 0x78f2, + 0x78f2, 0x8f82, 0x8f82, 0x8f72, 0x8f72, 0x77f2, 0x77f2, 0x77f2, + 0x77f2, 0x7f62, 0x7f62, 0x7f62, 0x7f62, 0x76f2, 0x76f2, 0x76f2, + 0x76f2, 0x7f52, 0x7f52, 0x7f52, 0x7f52, 0x75f2, 0x75f2, 0x75f2, + 0x75f2, 0x7f42, 0x7f42, 0x7f42, 0x7f42, 0x74f2, 0x74f2, 0x74f2, + 0x74f2, 0x7f32, 0x7f32, 0x7f32, 0x7f32, 0x73f2, 0x73f2, 0x73f2, + 0x73f2, 0x7f22, 0x7f22, 0x7f22, 0x7f22, 0x72f2, 0x72f2, 0x72f2, + 0x72f2, 0x71f2, 0x71f2, 0x71f2, 0x71f2, 0x8f12, 0x8f12, 0x80f1, + 0x80f1, 0x9f01, 0x0201, 0x0206, 0x020b, 0x0210, 0x0215, 0x021a, + 0x021f, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, + 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, + 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, + 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, 0x4ff2, + 0x4ff2, 0x0224, 0x0229, 0x0232, 0x0237, 0x023a, 0x023f, 0x0242, + 0x0245, 0x024a, 0x024d, 0x0250, 0x0253, 0x0256, 0x0259, 0x025c, + 0x025f, 0x0262, 0x0265, 0x0268, 0x026b, 0x026e, 0x0271, 0x0274, + 0x0277, 0x027a, 0x027d, 0x0280, 0x0283, 0x0288, 0x028b, 0x028e, + 0x0291, 0x0294, 0x0297, 0x029a, 0x029f, 0x94b2, 0x02a4, 0x02a7, + 0x02aa, 0x93b2, 0x9882, 0x02af, 0x92b2, 0x02b2, 0x02b5, 0x9692, + 0x94a2, 0x02b8, 0x9782, 0x9a32, 0x93a2, 0x9952, 0x9592, 0x9a22, + 0x92a2, 0x91a2, 0x9862, 0x9682, 0x9772, 0x9942, 0x9492, 0x9932, + 0x9392, 0x9852, 0x9582, 0x9922, 0x9762, 0x9672, 0x9292, 0x9912, + 0x9192, 0x9842, 0x9482, 0x9752, 0x9572, 0x9832, 0x9382, 0x9662, + 0x9822, 0x9282, 0x9812, 0x9742, 0x9472, 0x9182, 0x02bb, 0x9652, + 0x9562, 0x9712, 0x02be, 0x8372, 0x8372, 0x9732, 0x9722, 0x8272, + 0x8272, 0x8642, 0x8642, 0x8462, 0x8462, 0x8552, 0x8552, 0x8172, + 0x8172, 0x8632, 0x8632, 0x8362, 0x8362, 0x8542, 0x8542, 0x8452, + 0x8452, 0x8622, 0x8622, 0x8262, 0x8262, 0x8612, 0x8612, 0x8162, + 0x8162, 0x9601, 0x9061, 0x8532, 0x8532, 0x8352, 0x8352, 0x8442, + 0x8442, 0x8522, 0x8522, 0x8252, 0x8252, 0x8512, 0x8512, 0x9501, + 0x9051, 0x7152, 0x7152, 0x7152, 0x7152, 0x8432, 0x8432, 0x8342, + 0x8342, 0x7422, 0x7422, 0x7422, 0x7422, 0x7242, 0x7242, 0x7242, + 0x7242, 0x7332, 0x7332, 0x7332, 0x7332, 0x7412, 0x7412, 0x7412, + 0x7412, 0x7142, 0x7142, 0x7142, 0x7142, 0x8401, 0x8401, 0x8041, + 0x8041, 0x7322, 0x7322, 0x7322, 0x7322, 0x7232, 0x7232, 0x7232, + 0x7232, 0x6312, 0x6312, 0x6312, 0x6312, 0x6312, 0x6312, 0x6312, + 0x6312, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, 0x6132, + 0x6132, 0x7301, 0x7301, 0x7301, 0x7301, 0x7031, 0x7031, 0x7031, + 0x7031, 0x6222, 0x6222, 0x6222, 0x6222, 0x6222, 0x6222, 0x6222, + 0x6222, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, + 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, 0x5212, + 0x5212, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, + 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, 0x5122, + 0x5122, 0x6201, 0x6201, 0x6201, 0x6201, 0x6201, 0x6201, 0x6201, + 0x6201, 0x6021, 0x6021, 0x6021, 0x6021, 0x6021, 0x6021, 0x6021, + 0x6021, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, 0x4112, + 0x4112, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, 0x4101, + 0x4101, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, 0x4011, + 0x4011, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, + 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, + 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, + 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, + 0x4000, 0xf002, 0x2ee2, 0x2ed2, 0x2de2, 0x2ec2, 0xf002, 0x2ce2, + 0x2dd2, 0x2eb2, 0x2be2, 0xf002, 0x2dc2, 0x2cd2, 0x2ea2, 0x2ae2, + 0xf002, 0x2db2, 0x2bd2, 0x2cc2, 0x2e92, 0xf002, 0x29e2, 0x2da2, + 0x2ad2, 0x2cb2, 0xf002, 0x2bc2, 0x2e82, 0x28e2, 0x2d92, 0xf002, + 0x29d2, 0x2e72, 0x27e2, 0x2ca2, 0xf002, 0x2ac2, 0x2bb2, 0x2d82, + 0x28d2, 0xf003, 0x3e01, 0x30e1, 0x2d01, 0x2d01, 0x16e2, 0x16e2, + 0x16e2, 0x16e2, 0xf002, 0x2e62, 0x2c92, 0x19c2, 0x19c2, 0xf001, + 0x1e52, 0x1ab2, 0xf002, 0x15e2, 0x15e2, 0x2ba2, 0x2d72, 0xf001, + 0x17d2, 0x14e2, 0xf001, 0x1c82, 0x18c2, 0xf002, 0x2e42, 0x2e22, + 0x1e32, 0x1e32, 0xf001, 0x1d62, 0x16d2, 0xf001, 0x13e2, 0x1b92, + 0xf001, 0x19b2, 0x1aa2, 0xf001, 0x12e2, 0x1e12, 0xf001, 0x11e2, + 0x1d52, 0xf001, 0x15d2, 0x1c72, 0xf001, 0x17c2, 0x1d42, 0xf001, + 0x1b82, 0x18b2, 0xf001, 0x14d2, 0x1a92, 0xf001, 0x19a2, 0x1c62, + 0xf001, 0x16c2, 0x1d32, 0xf001, 0x13d2, 0x1d22, 0xf001, 0x12d2, + 0x1d12, 0xf001, 0x1b72, 0x17b2, 0xf001, 0x11d2, 0x1c52, 0xf001, + 0x15c2, 0x1a82, 0xf001, 0x18a2, 0x1992, 0xf001, 0x1c42, 0x14c2, + 0xf001, 0x1b62, 0x16b2, 0xf002, 0x20d1, 0x2c01, 0x1c32, 0x1c32, + 0xf001, 0x13c2, 0x1a72, 0xf001, 0x17a2, 0x1c22, 0xf001, 0x12c2, + 0x1b52, 0xf001, 0x15b2, 0x1c12, 0xf001, 0x1982, 0x1892, 0xf001, + 0x11c2, 0x1b42, 0xf002, 0x20c1, 0x2b01, 0x1b32, 0x1b32, 0xf002, + 0x20b1, 0x2a01, 0x1a12, 0x1a12, 0xf001, 0x1a62, 0x16a2, 0xf001, + 0x1972, 0x1792, 0xf002, 0x20a1, 0x2901, 0x1091, 0x1091, 0xf001, + 0x1b22, 0x1a52, 0xf001, 0x15a2, 0x1b12, 0xf001, 0x11b2, 0x1962, + 0xf001, 0x1a42, 0x1872, 0xf001, 0x1801, 0x1081, 0xf001, 0x1701, + 0x1071, +}; + +#define HUFF_OFFSET_01 0 +#define HUFF_OFFSET_02 ( 9 + HUFF_OFFSET_01) +#define HUFF_OFFSET_03 ( 65 + HUFF_OFFSET_02) +#define HUFF_OFFSET_05 ( 65 + HUFF_OFFSET_03) +#define HUFF_OFFSET_06 (257 + HUFF_OFFSET_05) +#define HUFF_OFFSET_07 (129 + HUFF_OFFSET_06) +#define HUFF_OFFSET_08 (110 + HUFF_OFFSET_07) +#define HUFF_OFFSET_09 (280 + HUFF_OFFSET_08) +#define HUFF_OFFSET_10 ( 93 + HUFF_OFFSET_09) +#define HUFF_OFFSET_11 (320 + HUFF_OFFSET_10) +#define HUFF_OFFSET_12 (296 + HUFF_OFFSET_11) +#define HUFF_OFFSET_13 (185 + HUFF_OFFSET_12) +#define HUFF_OFFSET_15 (497 + HUFF_OFFSET_13) +#define HUFF_OFFSET_16 (580 + HUFF_OFFSET_15) +#define HUFF_OFFSET_24 (651 + HUFF_OFFSET_16) + +const int huffTabOffset[HUFF_PAIRTABS] = { + 0, + HUFF_OFFSET_01, + HUFF_OFFSET_02, + HUFF_OFFSET_03, + 0, + HUFF_OFFSET_05, + HUFF_OFFSET_06, + HUFF_OFFSET_07, + HUFF_OFFSET_08, + HUFF_OFFSET_09, + HUFF_OFFSET_10, + HUFF_OFFSET_11, + HUFF_OFFSET_12, + HUFF_OFFSET_13, + 0, + HUFF_OFFSET_15, + HUFF_OFFSET_16, + HUFF_OFFSET_16, + HUFF_OFFSET_16, + HUFF_OFFSET_16, + HUFF_OFFSET_16, + HUFF_OFFSET_16, + HUFF_OFFSET_16, + HUFF_OFFSET_16, + HUFF_OFFSET_24, + HUFF_OFFSET_24, + HUFF_OFFSET_24, + HUFF_OFFSET_24, + HUFF_OFFSET_24, + HUFF_OFFSET_24, + HUFF_OFFSET_24, + HUFF_OFFSET_24, +}; + +const HuffTabLookup huffTabLookup[HUFF_PAIRTABS] = { + { 0, noBits }, + { 0, oneShot }, + { 0, oneShot }, + { 0, oneShot }, + { 0, invalidTab }, + { 0, oneShot }, + { 0, oneShot }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, loopNoLinbits }, + { 0, invalidTab }, + { 0, loopNoLinbits }, + { 1, loopLinbits }, + { 2, loopLinbits }, + { 3, loopLinbits }, + { 4, loopLinbits }, + { 6, loopLinbits }, + { 8, loopLinbits }, + { 10, loopLinbits }, + { 13, loopLinbits }, + { 4, loopLinbits }, + { 5, loopLinbits }, + { 6, loopLinbits }, + { 7, loopLinbits }, + { 8, loopLinbits }, + { 9, loopLinbits }, + { 11, loopLinbits }, + { 13, loopLinbits }, +}; + +/* tables for quadruples + * format 0xAB + * A = length of codeword + * B = codeword + */ +const unsigned char quadTable[64+16] = { + /* table A */ + 0x6b, 0x6f, 0x6d, 0x6e, 0x67, 0x65, 0x59, 0x59, + 0x56, 0x56, 0x53, 0x53, 0x5a, 0x5a, 0x5c, 0x5c, + 0x42, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x41, + 0x44, 0x44, 0x44, 0x44, 0x48, 0x48, 0x48, 0x48, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + /* table B */ + 0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48, + 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, +}; + +const int quadTabOffset[2] = {0, 64}; +const int quadTabMaxBits[2] = {6, 4}; \ No newline at end of file diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/imdct.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/imdct.c new file mode 100644 index 0000000..b5c0f78 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/imdct.c @@ -0,0 +1,784 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * imdct.c - antialias, inverse transform (short/long/mixed), windowing, + * overlap-add, frequency inversion + **************************************************************************************/ + +#include "coder.h" +#include "assembly.h" + +/************************************************************************************** + * Function: AntiAlias + * + * Description: smooth transition across DCT block boundaries (every 18 coefficients) + * + * Inputs: vector of dequantized coefficients, length = (nBfly+1) * 18 + * number of "butterflies" to perform (one butterfly means one + * inter-block smoothing operation) + * + * Outputs: updated coefficient vector x + * + * Return: none + * + * Notes: weighted average of opposite bands (pairwise) from the 8 samples + * before and after each block boundary + * nBlocks = (nonZeroBound + 7) / 18, since nZB is the first ZERO sample + * above which all other samples are also zero + * max gain per sample = 1.372 + * MAX(i) (abs(csa[i][0]) + abs(csa[i][1])) + * bits gained = 0 + * assume at least 1 guard bit in x[] to avoid overflow + * (should be guaranteed from dequant, and max gain from stproc * max + * gain from AntiAlias < 2.0) + **************************************************************************************/ +// a little bit faster in RAM (< 1 ms per block) +static void AntiAlias(int *x, int nBfly) +{ + int k, a0, b0, c0, c1; + const int *c; + + /* csa = Q31 */ + for (k = nBfly; k > 0; k--) { + c = csa[0]; + x += 18; + + a0 = x[-1]; c0 = *c; c++; b0 = x[0]; c1 = *c; c++; + x[-1] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[0] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-2]; c0 = *c; c++; b0 = x[1]; c1 = *c; c++; + x[-2] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[1] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-3]; c0 = *c; c++; b0 = x[2]; c1 = *c; c++; + x[-3] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[2] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-4]; c0 = *c; c++; b0 = x[3]; c1 = *c; c++; + x[-4] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[3] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-5]; c0 = *c; c++; b0 = x[4]; c1 = *c; c++; + x[-5] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[4] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-6]; c0 = *c; c++; b0 = x[5]; c1 = *c; c++; + x[-6] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[5] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-7]; c0 = *c; c++; b0 = x[6]; c1 = *c; c++; + x[-7] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[6] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + + a0 = x[-8]; c0 = *c; c++; b0 = x[7]; c1 = *c; c++; + x[-8] = (MULSHIFT32(c0, a0) - MULSHIFT32(c1, b0)) << 1; + x[7] = (MULSHIFT32(c0, b0) + MULSHIFT32(c1, a0)) << 1; + } +} + +/************************************************************************************** + * Function: WinPrevious + * + * Description: apply specified window to second half of previous IMDCT (overlap part) + * + * Inputs: vector of 9 coefficients (xPrev) + * + * Outputs: 18 windowed output coefficients (gain 1 integer bit) + * window type (0, 1, 2, 3) + * + * Return: none + * + * Notes: produces 9 output samples from 18 input samples via symmetry + * all blocks gain at least 1 guard bit via window (long blocks get extra + * sign bit, short blocks can have one addition but max gain < 1.0) + **************************************************************************************/ +static void WinPrevious(int *xPrev, int *xPrevWin, int btPrev) +{ + int i, x, *xp, *xpwLo, *xpwHi, wLo, wHi; + const int *wpLo, *wpHi; + + xp = xPrev; + /* mapping (see IMDCT12x3): xPrev[0-2] = sum[6-8], xPrev[3-8] = sum[12-17] */ + if (btPrev == 2) { + /* this could be reordered for minimum loads/stores */ + wpLo = imdctWin[btPrev]; + xPrevWin[ 0] = MULSHIFT32(wpLo[ 6], xPrev[2]) + MULSHIFT32(wpLo[0], xPrev[6]); + xPrevWin[ 1] = MULSHIFT32(wpLo[ 7], xPrev[1]) + MULSHIFT32(wpLo[1], xPrev[7]); + xPrevWin[ 2] = MULSHIFT32(wpLo[ 8], xPrev[0]) + MULSHIFT32(wpLo[2], xPrev[8]); + xPrevWin[ 3] = MULSHIFT32(wpLo[ 9], xPrev[0]) + MULSHIFT32(wpLo[3], xPrev[8]); + xPrevWin[ 4] = MULSHIFT32(wpLo[10], xPrev[1]) + MULSHIFT32(wpLo[4], xPrev[7]); + xPrevWin[ 5] = MULSHIFT32(wpLo[11], xPrev[2]) + MULSHIFT32(wpLo[5], xPrev[6]); + xPrevWin[ 6] = MULSHIFT32(wpLo[ 6], xPrev[5]); + xPrevWin[ 7] = MULSHIFT32(wpLo[ 7], xPrev[4]); + xPrevWin[ 8] = MULSHIFT32(wpLo[ 8], xPrev[3]); + xPrevWin[ 9] = MULSHIFT32(wpLo[ 9], xPrev[3]); + xPrevWin[10] = MULSHIFT32(wpLo[10], xPrev[4]); + xPrevWin[11] = MULSHIFT32(wpLo[11], xPrev[5]); + xPrevWin[12] = xPrevWin[13] = xPrevWin[14] = xPrevWin[15] = xPrevWin[16] = xPrevWin[17] = 0; + } else { + /* use ARM-style pointers (*ptr++) so that ADS compiles well */ + wpLo = imdctWin[btPrev] + 18; + wpHi = wpLo + 17; + xpwLo = xPrevWin; + xpwHi = xPrevWin + 17; + for (i = 9; i > 0; i--) { + x = *xp++; wLo = *wpLo++; wHi = *wpHi--; + *xpwLo++ = MULSHIFT32(wLo, x); + *xpwHi-- = MULSHIFT32(wHi, x); + } + } +} + +/************************************************************************************** + * Function: FreqInvertRescale + * + * Description: do frequency inversion (odd samples of odd blocks) and rescale + * if necessary (extra guard bits added before IMDCT) + * + * Inputs: output vector y (18 new samples, spaced NBANDS apart) + * previous sample vector xPrev (9 samples) + * index of current block + * number of extra shifts added before IMDCT (usually 0) + * + * Outputs: inverted and rescaled (as necessary) outputs + * rescaled (as necessary) previous samples + * + * Return: updated mOut (from new outputs y) + **************************************************************************************/ +static int FreqInvertRescale(int *y, int *xPrev, int blockIdx, int es) +{ + int i, d, mOut; + int y0, y1, y2, y3, y4, y5, y6, y7, y8; + + if (es == 0) { + /* fast case - frequency invert only (no rescaling) - can fuse into overlap-add for speed, if desired */ + if (blockIdx & 0x01) { + y += NBANDS; + y0 = *y; y += 2*NBANDS; + y1 = *y; y += 2*NBANDS; + y2 = *y; y += 2*NBANDS; + y3 = *y; y += 2*NBANDS; + y4 = *y; y += 2*NBANDS; + y5 = *y; y += 2*NBANDS; + y6 = *y; y += 2*NBANDS; + y7 = *y; y += 2*NBANDS; + y8 = *y; y += 2*NBANDS; + + y -= 18*NBANDS; + *y = -y0; y += 2*NBANDS; + *y = -y1; y += 2*NBANDS; + *y = -y2; y += 2*NBANDS; + *y = -y3; y += 2*NBANDS; + *y = -y4; y += 2*NBANDS; + *y = -y5; y += 2*NBANDS; + *y = -y6; y += 2*NBANDS; + *y = -y7; y += 2*NBANDS; + *y = -y8; y += 2*NBANDS; + } + return 0; + } else { + /* undo pre-IMDCT scaling, clipping if necessary */ + mOut = 0; + if (blockIdx & 0x01) { + /* frequency invert */ + for (i = 0; i < 18; i+=2) { + d = *y; CLIP_2N(d, 31 - es); *y = d << es; mOut |= FASTABS(*y); y += NBANDS; + d = -*y; CLIP_2N(d, 31 - es); *y = d << es; mOut |= FASTABS(*y); y += NBANDS; + d = *xPrev; CLIP_2N(d, 31 - es); *xPrev++ = d << es; + } + } else { + for (i = 0; i < 18; i+=2) { + d = *y; CLIP_2N(d, 31 - es); *y = d << es; mOut |= FASTABS(*y); y += NBANDS; + d = *y; CLIP_2N(d, 31 - es); *y = d << es; mOut |= FASTABS(*y); y += NBANDS; + d = *xPrev; CLIP_2N(d, 31 - es); *xPrev++ = d << es; + } + } + return mOut; + } +} + +/* format = Q31 + * #define M_PI 3.14159265358979323846 + * double u = 2.0 * M_PI / 9.0; + * float c0 = sqrt(3.0) / 2.0; + * float c1 = cos(u); + * float c2 = cos(2*u); + * float c3 = sin(u); + * float c4 = sin(2*u); + */ + +static const int c9_0 = 0x6ed9eba1; +static const int c9_1 = 0x620dbe8b; +static const int c9_2 = 0x163a1a7e; +static const int c9_3 = 0x5246dd49; +static const int c9_4 = 0x7e0e2e32; + +/* format = Q31 + * cos(((0:8) + 0.5) * (pi/18)) + */ +static const int c18[9] = { + 0x7f834ed0, 0x7ba3751d, 0x7401e4c1, 0x68d9f964, 0x5a82799a, 0x496af3e2, 0x36185aee, 0x2120fb83, 0x0b27eb5c, +}; + +/* require at least 3 guard bits in x[] to ensure no overflow */ +static __inline void idct9(int *x) +{ + int a1, a2, a3, a4, a5, a6, a7, a8, a9; + int a10, a11, a12, a13, a14, a15, a16, a17, a18; + int a19, a20, a21, a22, a23, a24, a25, a26, a27; + int m1, m3, m5, m6, m7, m8, m9, m10, m11, m12; + int x0, x1, x2, x3, x4, x5, x6, x7, x8; + + x0 = x[0]; x1 = x[1]; x2 = x[2]; x3 = x[3]; x4 = x[4]; + x5 = x[5]; x6 = x[6]; x7 = x[7]; x8 = x[8]; + + a1 = x0 - x6; + a2 = x1 - x5; + a3 = x1 + x5; + a4 = x2 - x4; + a5 = x2 + x4; + a6 = x2 + x8; + a7 = x1 + x7; + + a8 = a6 - a5; /* ie x[8] - x[4] */ + a9 = a3 - a7; /* ie x[5] - x[7] */ + a10 = a2 - x7; /* ie x[1] - x[5] - x[7] */ + a11 = a4 - x8; /* ie x[2] - x[4] - x[8] */ + + /* do the << 1 as constant shifts where mX is actually used (free, no stall or extra inst.) */ + m1 = MULSHIFT32(c9_0, x3); + m3 = MULSHIFT32(c9_0, a10); + m5 = MULSHIFT32(c9_1, a5); + m6 = MULSHIFT32(c9_2, a6); + m7 = MULSHIFT32(c9_1, a8); + m8 = MULSHIFT32(c9_2, a5); + m9 = MULSHIFT32(c9_3, a9); + m10 = MULSHIFT32(c9_4, a7); + m11 = MULSHIFT32(c9_3, a3); + m12 = MULSHIFT32(c9_4, a9); + + a12 = x[0] + (x[6] >> 1); + a13 = a12 + ( m1 << 1); + a14 = a12 - ( m1 << 1); + a15 = a1 + ( a11 >> 1); + a16 = ( m5 << 1) + (m6 << 1); + a17 = ( m7 << 1) - (m8 << 1); + a18 = a16 + a17; + a19 = ( m9 << 1) + (m10 << 1); + a20 = (m11 << 1) - (m12 << 1); + + a21 = a20 - a19; + a22 = a13 + a16; + a23 = a14 + a16; + a24 = a14 + a17; + a25 = a13 + a17; + a26 = a14 - a18; + a27 = a13 - a18; + + x0 = a22 + a19; x[0] = x0; + x1 = a15 + (m3 << 1); x[1] = x1; + x2 = a24 + a20; x[2] = x2; + x3 = a26 - a21; x[3] = x3; + x4 = a1 - a11; x[4] = x4; + x5 = a27 + a21; x[5] = x5; + x6 = a25 - a20; x[6] = x6; + x7 = a15 - (m3 << 1); x[7] = x7; + x8 = a23 - a19; x[8] = x8; +} + +/* let c(j) = cos(M_PI/36 * ((j)+0.5)), s(j) = sin(M_PI/36 * ((j)+0.5)) + * then fastWin[2*j+0] = c(j)*(s(j) + c(j)), j = [0, 8] + * fastWin[2*j+1] = c(j)*(s(j) - c(j)) + * format = Q30 + */ +int fastWin36[18] = { + 0x42aace8b, 0xc2e92724, 0x47311c28, 0xc95f619a, 0x4a868feb, 0xd0859d8c, + 0x4c913b51, 0xd8243ea0, 0x4d413ccc, 0xe0000000, 0x4c913b51, 0xe7dbc161, + 0x4a868feb, 0xef7a6275, 0x47311c28, 0xf6a09e67, 0x42aace8b, 0xfd16d8dd, +}; + +/************************************************************************************** + * Function: IMDCT36 + * + * Description: 36-point modified DCT, with windowing and overlap-add (50% overlap) + * + * Inputs: vector of 18 coefficients (N/2 inputs produces N outputs, by symmetry) + * overlap part of last IMDCT (9 samples - see output comments) + * window type (0,1,2,3) of current and previous block + * current block index (for deciding whether to do frequency inversion) + * number of guard bits in input vector + * + * Outputs: 18 output samples, after windowing and overlap-add with last frame + * second half of (unwindowed) 36-point IMDCT - save for next time + * only save 9 xPrev samples, using symmetry (see WinPrevious()) + * + * Notes: this is Ken's hyper-fast algorithm, including symmetric sin window + * optimization, if applicable + * total number of multiplies, general case: + * 2*10 (idct9) + 9 (last stage imdct) + 36 (for windowing) = 65 + * total number of multiplies, btCurr == 0 && btPrev == 0: + * 2*10 (idct9) + 9 (last stage imdct) + 18 (for windowing) = 47 + * + * blockType == 0 is by far the most common case, so it should be + * possible to use the fast path most of the time + * this is the fastest known algorithm for performing + * long IMDCT + windowing + overlap-add in MP3 + * + * Return: mOut (OR of abs(y) for all y calculated here) + * + * TODO: optimize for ARM (reorder window coefs, ARM-style pointers in C, + * inline asm may or may not be helpful) + **************************************************************************************/ +// barely faster in RAM +static int IMDCT36(int *xCurr, int *xPrev, int *y, int btCurr, int btPrev, int blockIdx, int gb) +{ + int i, es, xBuf[18], xPrevWin[18]; + int acc1, acc2, s, d, t, mOut; + int xo, xe, c, *xp, yLo, yHi; + const int *cp, *wp; + + acc1 = acc2 = 0; + xCurr += 17; + + /* 7 gb is always adequate for antialias + accumulator loop + idct9 */ + if (gb < 7) { + /* rarely triggered - 5% to 10% of the time on normal clips (with Q25 input) */ + es = 7 - gb; + for (i = 8; i >= 0; i--) { + acc1 = ((*xCurr--) >> es) - acc1; + acc2 = acc1 - acc2; + acc1 = ((*xCurr--) >> es) - acc1; + xBuf[i+9] = acc2; /* odd */ + xBuf[i+0] = acc1; /* even */ + xPrev[i] >>= es; + } + } else { + es = 0; + /* max gain = 18, assume adequate guard bits */ + for (i = 8; i >= 0; i--) { + acc1 = (*xCurr--) - acc1; + acc2 = acc1 - acc2; + acc1 = (*xCurr--) - acc1; + xBuf[i+9] = acc2; /* odd */ + xBuf[i+0] = acc1; /* even */ + } + } + /* xEven[0] and xOdd[0] scaled by 0.5 */ + xBuf[9] >>= 1; + xBuf[0] >>= 1; + + /* do 9-point IDCT on even and odd */ + idct9(xBuf+0); /* even */ + idct9(xBuf+9); /* odd */ + + xp = xBuf + 8; + cp = c18 + 8; + mOut = 0; + if (btPrev == 0 && btCurr == 0) { + /* fast path - use symmetry of sin window to reduce windowing multiplies to 18 (N/2) */ + wp = fastWin36; + for (i = 0; i < 9; i++) { + /* do ARM-style pointer arithmetic (i still needed for y[] indexing - compiler spills if 2 y pointers) */ + c = *cp--; xo = *(xp + 9); xe = *xp--; + /* gain 2 int bits here */ + xo = MULSHIFT32(c, xo); /* 2*c18*xOdd (mul by 2 implicit in scaling) */ + xe >>= 2; + + s = -(*xPrev); /* sum from last block (always at least 2 guard bits) */ + d = -(xe - xo); /* gain 2 int bits, don't shift xo (effective << 1 to eat sign bit, << 1 for mul by 2) */ + (*xPrev++) = xe + xo; /* symmetry - xPrev[i] = xPrev[17-i] for long blocks */ + t = s - d; + + yLo = (d + (MULSHIFT32(t, *wp++) << 2)); + yHi = (s + (MULSHIFT32(t, *wp++) << 2)); + y[(i)*NBANDS] = yLo; + y[(17-i)*NBANDS] = yHi; + mOut |= FASTABS(yLo); + mOut |= FASTABS(yHi); + } + } else { + /* slower method - either prev or curr is using window type != 0 so do full 36-point window + * output xPrevWin has at least 3 guard bits (xPrev has 2, gain 1 in WinPrevious) + */ + WinPrevious(xPrev, xPrevWin, btPrev); + + wp = imdctWin[btCurr]; + for (i = 0; i < 9; i++) { + c = *cp--; xo = *(xp + 9); xe = *xp--; + /* gain 2 int bits here */ + xo = MULSHIFT32(c, xo); /* 2*c18*xOdd (mul by 2 implicit in scaling) */ + xe >>= 2; + + d = xe - xo; + (*xPrev++) = xe + xo; /* symmetry - xPrev[i] = xPrev[17-i] for long blocks */ + + yLo = (xPrevWin[i] + MULSHIFT32(d, wp[i])) << 2; + yHi = (xPrevWin[17-i] + MULSHIFT32(d, wp[17-i])) << 2; + y[(i)*NBANDS] = yLo; + y[(17-i)*NBANDS] = yHi; + mOut |= FASTABS(yLo); + mOut |= FASTABS(yHi); + } + } + + xPrev -= 9; + mOut |= FreqInvertRescale(y, xPrev, blockIdx, es); + + return mOut; +} + +static int c3_0 = 0x6ed9eba1; /* format = Q31, cos(pi/6) */ +static int c6[3] = { 0x7ba3751d, 0x5a82799a, 0x2120fb83 }; /* format = Q31, cos(((0:2) + 0.5) * (pi/6)) */ + +/* 12-point inverse DCT, used in IMDCT12x3() + * 4 input guard bits will ensure no overflow + */ +static __inline void imdct12 (int *x, int *out) +{ + int a0, a1, a2; + int x0, x1, x2, x3, x4, x5; + + x0 = *x; x+=3; x1 = *x; x+=3; + x2 = *x; x+=3; x3 = *x; x+=3; + x4 = *x; x+=3; x5 = *x; x+=3; + + x4 -= x5; + x3 -= x4; + x2 -= x3; + x3 -= x5; + x1 -= x2; + x0 -= x1; + x1 -= x3; + + x0 >>= 1; + x1 >>= 1; + + a0 = MULSHIFT32(c3_0, x2) << 1; + a1 = x0 + (x4 >> 1); + a2 = x0 - x4; + x0 = a1 + a0; + x2 = a2; + x4 = a1 - a0; + + a0 = MULSHIFT32(c3_0, x3) << 1; + a1 = x1 + (x5 >> 1); + a2 = x1 - x5; + + /* cos window odd samples, mul by 2, eat sign bit */ + x1 = MULSHIFT32(c6[0], a1 + a0) << 2; + x3 = MULSHIFT32(c6[1], a2) << 2; + x5 = MULSHIFT32(c6[2], a1 - a0) << 2; + + *out = x0 + x1; out++; + *out = x2 + x3; out++; + *out = x4 + x5; out++; + *out = x4 - x5; out++; + *out = x2 - x3; out++; + *out = x0 - x1; +} + +/************************************************************************************** + * Function: IMDCT12x3 + * + * Description: three 12-point modified DCT's for short blocks, with windowing, + * short block concatenation, and overlap-add + * + * Inputs: 3 interleaved vectors of 6 samples each + * (block0[0], block1[0], block2[0], block0[1], block1[1]....) + * overlap part of last IMDCT (9 samples - see output comments) + * window type (0,1,2,3) of previous block + * current block index (for deciding whether to do frequency inversion) + * number of guard bits in input vector + * + * Outputs: updated sample vector x, net gain of 1 integer bit + * second half of (unwindowed) IMDCT's - save for next time + * only save 9 xPrev samples, using symmetry (see WinPrevious()) + * + * Return: mOut (OR of abs(y) for all y calculated here) + * + * TODO: optimize for ARM + **************************************************************************************/ + // barely faster in RAM +static int IMDCT12x3(int *xCurr, int *xPrev, int *y, int btPrev, int blockIdx, int gb) +{ + int i, es, mOut, yLo, xBuf[18], xPrevWin[18]; /* need temp buffer for reordering short blocks */ + const int *wp; + + es = 0; + /* 7 gb is always adequate for accumulator loop + idct12 + window + overlap */ + if (gb < 7) { + es = 7 - gb; + for (i = 0; i < 18; i+=2) { + xCurr[i+0] >>= es; + xCurr[i+1] >>= es; + *xPrev++ >>= es; + } + xPrev -= 9; + } + + /* requires 4 input guard bits for each imdct12 */ + imdct12(xCurr + 0, xBuf + 0); + imdct12(xCurr + 1, xBuf + 6); + imdct12(xCurr + 2, xBuf + 12); + + /* window previous from last time */ + WinPrevious(xPrev, xPrevWin, btPrev); + + /* could unroll this for speed, minimum loads (short blocks usually rare, so doesn't make much overall difference) + * xPrevWin[i] << 2 still has 1 gb always, max gain of windowed xBuf stuff also < 1.0 and gain the sign bit + * so y calculations won't overflow + */ + wp = imdctWin[2]; + mOut = 0; + for (i = 0; i < 3; i++) { + yLo = (xPrevWin[ 0+i] << 2); + mOut |= FASTABS(yLo); y[( 0+i)*NBANDS] = yLo; + yLo = (xPrevWin[ 3+i] << 2); + mOut |= FASTABS(yLo); y[( 3+i)*NBANDS] = yLo; + yLo = (xPrevWin[ 6+i] << 2) + (MULSHIFT32(wp[0+i], xBuf[3+i])); + mOut |= FASTABS(yLo); y[( 6+i)*NBANDS] = yLo; + yLo = (xPrevWin[ 9+i] << 2) + (MULSHIFT32(wp[3+i], xBuf[5-i])); + mOut |= FASTABS(yLo); y[( 9+i)*NBANDS] = yLo; + yLo = (xPrevWin[12+i] << 2) + (MULSHIFT32(wp[6+i], xBuf[2-i]) + MULSHIFT32(wp[0+i], xBuf[(6+3)+i])); + mOut |= FASTABS(yLo); y[(12+i)*NBANDS] = yLo; + yLo = (xPrevWin[15+i] << 2) + (MULSHIFT32(wp[9+i], xBuf[0+i]) + MULSHIFT32(wp[3+i], xBuf[(6+5)-i])); + mOut |= FASTABS(yLo); y[(15+i)*NBANDS] = yLo; + } + + /* save previous (unwindowed) for overlap - only need samples 6-8, 12-17 */ + for (i = 6; i < 9; i++) + *xPrev++ = xBuf[i] >> 2; + for (i = 12; i < 18; i++) + *xPrev++ = xBuf[i] >> 2; + + xPrev -= 9; + mOut |= FreqInvertRescale(y, xPrev, blockIdx, es); + + return mOut; +} + +/************************************************************************************** + * Function: HybridTransform + * + * Description: IMDCT's, windowing, and overlap-add on long/short/mixed blocks + * + * Inputs: vector of input coefficients, length = nBlocksTotal * 18) + * vector of overlap samples from last time, length = nBlocksPrev * 9) + * buffer for output samples, length = MAXNSAMP + * SideInfoSub struct for this granule/channel + * BlockCount struct with necessary info + * number of non-zero input and overlap blocks + * number of long blocks in input vector (rest assumed to be short blocks) + * number of blocks which use long window (type) 0 in case of mixed block + * (bc->currWinSwitch, 0 for non-mixed blocks) + * + * Outputs: transformed, windowed, and overlapped sample buffer + * does frequency inversion on odd blocks + * updated buffer of samples for overlap + * + * Return: number of non-zero IMDCT blocks calculated in this call + * (including overlap-add) + * + * TODO: examine mixedBlock/winSwitch logic carefully (test he_mode.bit) + **************************************************************************************/ +static int HybridTransform(int *xCurr, int *xPrev, int y[BLOCK_SIZE][NBANDS], SideInfoSub *sis, BlockCount *bc) +{ + int xPrevWin[18], currWinIdx, prevWinIdx; + int i, j, nBlocksOut, nonZero, mOut; + int fiBit, xp; + + ASSERT(bc->nBlocksLong <= NBANDS); + ASSERT(bc->nBlocksTotal <= NBANDS); + ASSERT(bc->nBlocksPrev <= NBANDS); + + mOut = 0; + + /* do long blocks, if any */ + for(i = 0; i < bc->nBlocksLong; i++) { + /* currWinIdx picks the right window for long blocks (if mixed, long blocks use window type 0) */ + currWinIdx = sis->blockType; + if (sis->mixedBlock && i < bc->currWinSwitch) + currWinIdx = 0; + + prevWinIdx = bc->prevType; + if (i < bc->prevWinSwitch) + prevWinIdx = 0; + + /* do 36-point IMDCT, including windowing and overlap-add */ + mOut |= IMDCT36(xCurr, xPrev, &(y[0][i]), currWinIdx, prevWinIdx, i, bc->gbIn); + xCurr += 18; + xPrev += 9; + } + + /* do short blocks (if any) */ + for ( ; i < bc->nBlocksTotal; i++) { + ASSERT(sis->blockType == 2); + + prevWinIdx = bc->prevType; + if (i < bc->prevWinSwitch) + prevWinIdx = 0; + + mOut |= IMDCT12x3(xCurr, xPrev, &(y[0][i]), prevWinIdx, i, bc->gbIn); + xCurr += 18; + xPrev += 9; + } + nBlocksOut = i; + + /* window and overlap prev if prev longer that current */ + for ( ; i < bc->nBlocksPrev; i++) { + prevWinIdx = bc->prevType; + if (i < bc->prevWinSwitch) + prevWinIdx = 0; + WinPrevious(xPrev, xPrevWin, prevWinIdx); + + nonZero = 0; + fiBit = i << 31; + for (j = 0; j < 9; j++) { + xp = xPrevWin[2*j+0] << 2; /* << 2 temp for scaling */ + nonZero |= xp; + y[2*j+0][i] = xp; + mOut |= FASTABS(xp); + + /* frequency inversion on odd blocks/odd samples (flip sign if i odd, j odd) */ + xp = xPrevWin[2*j+1] << 2; + xp = (xp ^ (fiBit >> 31)) + (i & 0x01); + nonZero |= xp; + y[2*j+1][i] = xp; + mOut |= FASTABS(xp); + + xPrev[j] = 0; + } + xPrev += 9; + if (nonZero) + nBlocksOut = i; + } + + /* clear rest of blocks */ + for ( ; i < 32; i++) { + for (j = 0; j < 18; j++) + y[j][i] = 0; + } + + bc->gbOut = CLZ(mOut) - 1; + + return nBlocksOut; +} + +/************************************************************************************** + * Function: IMDCT + * + * Description: do alias reduction, inverse MDCT, overlap-add, and frequency inversion + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader(), UnpackSideInfo(), + * UnpackScaleFactors(), and DecodeHuffman() (for this granule, channel) + * includes PCM samples in overBuf (from last call to IMDCT) for OLA + * index of current granule and channel + * + * Outputs: PCM samples in outBuf, for input to subband transform + * PCM samples in overBuf, for OLA next time + * updated hi->nonZeroBound index for this channel + * + * Return: 0 on success, -1 if null input pointers + **************************************************************************************/ + // a bit faster in RAM +int IMDCT(MP3DecInfo *mp3DecInfo, int gr, int ch) +{ + int nBfly, blockCutoff; + FrameHeader *fh; + SideInfo *si; + HuffmanInfo *hi; + IMDCTInfo *mi; + BlockCount bc; + + /* validate pointers */ + if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS || !mp3DecInfo->SideInfoPS || + !mp3DecInfo->HuffmanInfoPS || !mp3DecInfo->IMDCTInfoPS) + return -1; + + /* si is an array of up to 4 structs, stored as gr0ch0, gr0ch1, gr1ch0, gr1ch1 */ + fh = (FrameHeader *)(mp3DecInfo->FrameHeaderPS); + si = (SideInfo *)(mp3DecInfo->SideInfoPS); + hi = (HuffmanInfo*)(mp3DecInfo->HuffmanInfoPS); + mi = (IMDCTInfo *)(mp3DecInfo->IMDCTInfoPS); + + /* anti-aliasing done on whole long blocks only + * for mixed blocks, nBfly always 1, except 3 for 8 kHz MPEG 2.5 (see sfBandTab) + * nLongBlocks = number of blocks with (possibly) non-zero power + * nBfly = number of butterflies to do (nLongBlocks - 1, unless no long blocks) + */ + blockCutoff = fh->sfBand->l[(fh->ver == MPEG1 ? 8 : 6)] / 18; /* same as 3* num short sfb's in spec */ + if (si->sis[gr][ch].blockType != 2) { + /* all long transforms */ + bc.nBlocksLong = MIN((hi->nonZeroBound[ch] + 7) / 18 + 1, 32); + nBfly = bc.nBlocksLong - 1; + } else if (si->sis[gr][ch].blockType == 2 && si->sis[gr][ch].mixedBlock) { + /* mixed block - long transforms until cutoff, then short transforms */ + bc.nBlocksLong = blockCutoff; + nBfly = bc.nBlocksLong - 1; + } else { + /* all short transforms */ + bc.nBlocksLong = 0; + nBfly = 0; + } + + AntiAlias(hi->huffDecBuf[ch], nBfly); + hi->nonZeroBound[ch] = MAX(hi->nonZeroBound[ch], (nBfly * 18) + 8); + + ASSERT(hi->nonZeroBound[ch] <= MAX_NSAMP); + + /* for readability, use a struct instead of passing a million parameters to HybridTransform() */ + bc.nBlocksTotal = (hi->nonZeroBound[ch] + 17) / 18; + bc.nBlocksPrev = mi->numPrevIMDCT[ch]; + bc.prevType = mi->prevType[ch]; + bc.prevWinSwitch = mi->prevWinSwitch[ch]; + bc.currWinSwitch = (si->sis[gr][ch].mixedBlock ? blockCutoff : 0); /* where WINDOW switches (not nec. transform) */ + bc.gbIn = hi->gb[ch]; + + mi->numPrevIMDCT[ch] = HybridTransform(hi->huffDecBuf[ch], mi->overBuf[ch], mi->outBuf[ch], &si->sis[gr][ch], &bc); + mi->prevType[ch] = si->sis[gr][ch].blockType; + mi->prevWinSwitch[ch] = bc.currWinSwitch; /* 0 means not a mixed block (either all short or all long) */ + mi->gb[ch] = bc.gbOut; + + ASSERT(mi->numPrevIMDCT[ch] <= NBANDS); + + /* output has gained 2 int bits */ + return 0; +} diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/polyphase.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/polyphase.c new file mode 100644 index 0000000..bd331df --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/polyphase.c @@ -0,0 +1,295 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * polyphase.c - final stage of subband transform (polyphase synthesis filter) + * + * This is the C reference version using __int64 + * Look in the appropriate subdirectories for optimized asm implementations + * (e.g. arm/asmpoly.s) + **************************************************************************************/ + +#include "coder.h" +#include "assembly.h" + +/* input to Polyphase = Q(DQ_FRACBITS_OUT-2), gain 2 bits in convolution + * we also have the implicit bias of 2^15 to add back, so net fraction bits = + * DQ_FRACBITS_OUT - 2 - 2 - 15 + * (see comment on Dequantize() for more info) + */ +#define DEF_NFRACBITS (DQ_FRACBITS_OUT - 2 - 2 - 15) +#define CSHIFT 12 /* coefficients have 12 leading sign bits for early-terminating mulitplies */ + +static __inline short ClipToShort(int x, int fracBits) +{ + int sign; + + /* assumes you've already rounded (x += (1 << (fracBits-1))) */ + x >>= fracBits; + + /* Ken's trick: clips to [-32768, 32767] */ + sign = x >> 31; + if (sign != (x >> 15)) + x = sign ^ ((1 << 15) - 1); + + return (short)x; +} + +#define MC0M(x) { \ + c1 = *coef; coef++; c2 = *coef; coef++; \ + vLo = *(vb1+(x)); vHi = *(vb1+(23-(x))); \ + sum1L = MADD64(sum1L, vLo, c1); sum1L = MADD64(sum1L, vHi, -c2); \ +} + +#define MC1M(x) { \ + c1 = *coef; coef++; \ + vLo = *(vb1+(x)); \ + sum1L = MADD64(sum1L, vLo, c1); \ +} + +#define MC2M(x) { \ + c1 = *coef; coef++; c2 = *coef; coef++; \ + vLo = *(vb1+(x)); vHi = *(vb1+(23-(x))); \ + sum1L = MADD64(sum1L, vLo, c1); sum2L = MADD64(sum2L, vLo, c2); \ + sum1L = MADD64(sum1L, vHi, -c2); sum2L = MADD64(sum2L, vHi, c1); \ +} + +/************************************************************************************** + * Function: PolyphaseMono + * + * Description: filter one subband and produce 32 output PCM samples for one channel + * + * Inputs: pointer to PCM output buffer + * number of "extra shifts" (vbuf format = Q(DQ_FRACBITS_OUT-2)) + * pointer to start of vbuf (preserved from last call) + * start of filter coefficient table (in proper, shuffled order) + * no minimum number of guard bits is required for input vbuf + * (see additional scaling comments below) + * + * Outputs: 32 samples of one channel of decoded PCM data, (i.e. Q16.0) + * + * Return: none + * + * TODO: add 32-bit version for platforms where 64-bit mul-acc is not supported + * (note max filter gain - see polyCoef[] comments) + **************************************************************************************/ +void PolyphaseMono(short *pcm, int *vbuf, const int *coefBase) +{ + int i; + const int *coef; + int *vb1; + int vLo, vHi, c1, c2; + Word64 sum1L, sum2L, rndVal; + + rndVal = (Word64)( 1 << (DEF_NFRACBITS - 1 + (32 - CSHIFT)) ); + + /* special case, output sample 0 */ + coef = coefBase; + vb1 = vbuf; + sum1L = rndVal; + + MC0M(0) + MC0M(1) + MC0M(2) + MC0M(3) + MC0M(4) + MC0M(5) + MC0M(6) + MC0M(7) + + *(pcm + 0) = ClipToShort((int)SAR64(sum1L, (32-CSHIFT)), DEF_NFRACBITS); + + /* special case, output sample 16 */ + coef = coefBase + 256; + vb1 = vbuf + 64*16; + sum1L = rndVal; + + MC1M(0) + MC1M(1) + MC1M(2) + MC1M(3) + MC1M(4) + MC1M(5) + MC1M(6) + MC1M(7) + + *(pcm + 16) = ClipToShort((int)SAR64(sum1L, (32-CSHIFT)), DEF_NFRACBITS); + + /* main convolution loop: sum1L = samples 1, 2, 3, ... 15 sum2L = samples 31, 30, ... 17 */ + coef = coefBase + 16; + vb1 = vbuf + 64; + pcm++; + + /* right now, the compiler creates bad asm from this... */ + for (i = 15; i > 0; i--) { + sum1L = sum2L = rndVal; + + MC2M(0) + MC2M(1) + MC2M(2) + MC2M(3) + MC2M(4) + MC2M(5) + MC2M(6) + MC2M(7) + + vb1 += 64; + *(pcm) = ClipToShort((int)SAR64(sum1L, (32-CSHIFT)), DEF_NFRACBITS); + *(pcm + 2*i) = ClipToShort((int)SAR64(sum2L, (32-CSHIFT)), DEF_NFRACBITS); + pcm++; + } +} + +#define MC0S(x) { \ + c1 = *coef; coef++; c2 = *coef; coef++; \ + vLo = *(vb1+(x)); vHi = *(vb1+(23-(x))); \ + sum1L = MADD64(sum1L, vLo, c1); sum1L = MADD64(sum1L, vHi, -c2); \ + vLo = *(vb1+32+(x)); vHi = *(vb1+32+(23-(x))); \ + sum1R = MADD64(sum1R, vLo, c1); sum1R = MADD64(sum1R, vHi, -c2); \ +} + +#define MC1S(x) { \ + c1 = *coef; coef++; \ + vLo = *(vb1+(x)); \ + sum1L = MADD64(sum1L, vLo, c1); \ + vLo = *(vb1+32+(x)); \ + sum1R = MADD64(sum1R, vLo, c1); \ +} + +#define MC2S(x) { \ + c1 = *coef; coef++; c2 = *coef; coef++; \ + vLo = *(vb1+(x)); vHi = *(vb1+(23-(x))); \ + sum1L = MADD64(sum1L, vLo, c1); sum2L = MADD64(sum2L, vLo, c2); \ + sum1L = MADD64(sum1L, vHi, -c2); sum2L = MADD64(sum2L, vHi, c1); \ + vLo = *(vb1+32+(x)); vHi = *(vb1+32+(23-(x))); \ + sum1R = MADD64(sum1R, vLo, c1); sum2R = MADD64(sum2R, vLo, c2); \ + sum1R = MADD64(sum1R, vHi, -c2); sum2R = MADD64(sum2R, vHi, c1); \ +} + +/************************************************************************************** + * Function: PolyphaseStereo + * + * Description: filter one subband and produce 32 output PCM samples for each channel + * + * Inputs: pointer to PCM output buffer + * number of "extra shifts" (vbuf format = Q(DQ_FRACBITS_OUT-2)) + * pointer to start of vbuf (preserved from last call) + * start of filter coefficient table (in proper, shuffled order) + * no minimum number of guard bits is required for input vbuf + * (see additional scaling comments below) + * + * Outputs: 32 samples of two channels of decoded PCM data, (i.e. Q16.0) + * + * Return: none + * + * Notes: interleaves PCM samples LRLRLR... + * + * TODO: add 32-bit version for platforms where 64-bit mul-acc is not supported + **************************************************************************************/ +void PolyphaseStereo(short *pcm, int *vbuf, const int *coefBase) +{ + int i; + const int *coef; + int *vb1; + int vLo, vHi, c1, c2; + Word64 sum1L, sum2L, sum1R, sum2R, rndVal; + + rndVal = (Word64)( 1 << (DEF_NFRACBITS - 1 + (32 - CSHIFT)) ); + + /* special case, output sample 0 */ + coef = coefBase; + vb1 = vbuf; + sum1L = sum1R = rndVal; + + MC0S(0) + MC0S(1) + MC0S(2) + MC0S(3) + MC0S(4) + MC0S(5) + MC0S(6) + MC0S(7) + + *(pcm + 0) = ClipToShort((int)SAR64(sum1L, (32-CSHIFT)), DEF_NFRACBITS); + *(pcm + 1) = ClipToShort((int)SAR64(sum1R, (32-CSHIFT)), DEF_NFRACBITS); + + /* special case, output sample 16 */ + coef = coefBase + 256; + vb1 = vbuf + 64*16; + sum1L = sum1R = rndVal; + + MC1S(0) + MC1S(1) + MC1S(2) + MC1S(3) + MC1S(4) + MC1S(5) + MC1S(6) + MC1S(7) + + *(pcm + 2*16 + 0) = ClipToShort((int)SAR64(sum1L, (32-CSHIFT)), DEF_NFRACBITS); + *(pcm + 2*16 + 1) = ClipToShort((int)SAR64(sum1R, (32-CSHIFT)), DEF_NFRACBITS); + + /* main convolution loop: sum1L = samples 1, 2, 3, ... 15 sum2L = samples 31, 30, ... 17 */ + coef = coefBase + 16; + vb1 = vbuf + 64; + pcm += 2; + + /* right now, the compiler creates bad asm from this... */ + for (i = 15; i > 0; i--) { + sum1L = sum2L = rndVal; + sum1R = sum2R = rndVal; + + MC2S(0) + MC2S(1) + MC2S(2) + MC2S(3) + MC2S(4) + MC2S(5) + MC2S(6) + MC2S(7) + + vb1 += 64; + *(pcm + 0) = ClipToShort((int)SAR64(sum1L, (32-CSHIFT)), DEF_NFRACBITS); + *(pcm + 1) = ClipToShort((int)SAR64(sum1R, (32-CSHIFT)), DEF_NFRACBITS); + *(pcm + 2*2*i + 0) = ClipToShort((int)SAR64(sum2L, (32-CSHIFT)), DEF_NFRACBITS); + *(pcm + 2*2*i + 1) = ClipToShort((int)SAR64(sum2R, (32-CSHIFT)), DEF_NFRACBITS); + pcm += 2; + } +} diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/LICENSE.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/LICENSE.txt new file mode 100644 index 0000000..12e5372 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/LICENSE.txt @@ -0,0 +1,30 @@ + Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. + + The contents of this directory, and (except where otherwise + indicated) the directories included within this directory, are + subject to the current version of the RealNetworks Public Source + License (the "RPSL") available at RPSL.txt in this directory, unless + you have licensed the directory under the current version of the + RealNetworks Community Source License (the "RCSL") available at + RCSL.txt in this directory, in which case the RCSL will apply. You + may also obtain the license terms directly from RealNetworks. You + may not use the files in this directory except in compliance with the + RPSL or, if you have a valid RCSL with RealNetworks applicable to + this directory, the RCSL. Please see the applicable RPSL or RCSL for + the rights, obligations and limitations governing use of the contents + of the directory. + + This directory is part of the Helix DNA Technology. RealNetworks is + the developer of the Original Code and owns the copyrights in the + portions it created. + + This directory, and the directories included with this directory, are + distributed and made available on an 'AS IS' basis, WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY + DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + QUIET ENJOYMENT OR NON-INFRINGEMENT. + + Technology Compatibility Kit Test Suite(s) Location: + http://www.helixcommunity.org/content/tck + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/RCSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/RCSL.txt new file mode 100644 index 0000000..a809759 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/RCSL.txt @@ -0,0 +1,948 @@ +The RCSL is made up of a base agreement and a few Attachments. + +For Research and Development use, you agree to the terms of the +RCSL R&D License (base RCSL and Attachments A, B, and C) + +For Commercial Use (either distribution or internal commercial +deployment) of the Helix DNA with or without support for RealNetworks' +RealAudio and RealVideo Add-on Technology, you agree to the +terms of the same RCSL R&D license +and execute one or more additional Commercial Use License attachments +. + +------------------------------------------------------------------------ + + + REALNETWORKS COMMUNITY SOURCE LICENSE + +Version 1.2 (Rev. Date: January 22, 2003). + + + RECITALS + +Original Contributor has developed Specifications, Source Code +implementations and Executables of certain Technology; and + +Original Contributor desires to license the Technology to a large +community to facilitate research, innovation and product development +while maintaining compatibility of such products with the Technology as +delivered by Original Contributor; and + +Original Contributor desires to license certain Trademarks for the +purpose of branding products that are compatible with the relevant +Technology delivered by Original Contributor; and + +You desire to license the Technology and possibly certain Trademarks +from Original Contributor on the terms and conditions specified in this +License. + +In consideration for the mutual covenants contained herein, You and +Original Contributor agree as follows: + + + AGREEMENT + +*1. Introduction.* + +The RealNetworks Community Source License ("RCSL") and effective +attachments ("License") may include five distinct licenses: + +i) Research Use license -- License plus Attachments A, B and C only. + +ii) Commercial Use and Trademark License, which may be for Internal +Deployment Use or external distribution, or both -- License plus +Attachments A, B, C, and D. + +iii) Technology Compatibility Kit (TCK) license -- Attachment C. + +iv) Add-On Technology License (Executable) Commercial Use License +-Attachment F. + +v) Add-On Technology Source Code Porting and Optimization +License-Attachment G. + +The Research Use license is effective when You click and accept this +License. The TCK is effective when You click and accept this License, +unless otherwise specified in the TCK attachments. The Commercial Use +and Trademark, Add-On Technology License, and the Add-On Technology +Source Code Porting and Optimization licenses must each be signed by You +and Original Contributor to become effective. Once effective, these +licenses and the associated requirements and responsibilities are +cumulative. Capitalized terms used in this License are defined in the +Glossary. + +*2. License Grants.* + +2.1 Original Contributor Grant. + +Subject to Your compliance with Sections 3, 8.10 and Attachment A of +this License, Original Contributor grants to You a worldwide, +royalty-free, non-exclusive license, to the extent of Original +Contributor's Intellectual Property Rights covering the Original Code, +Upgraded Code and Specifications, to do the following: + +(a) Research Use License: + +(i) use, reproduce and modify the Original Code, Upgraded Code and +Specifications to create Modifications and Reformatted Specifications +for Research Use by You; + +(ii) publish and display Original Code, Upgraded Code and Specifications +with, or as part of Modifications, as permitted under Section 3.1(b) below; + +(iii) reproduce and distribute copies of Original Code and Upgraded Code +to Licensees and students for Research Use by You; + +(iv) compile, reproduce and distribute Original Code and Upgraded Code +in Executable form, and Reformatted Specifications to anyone for +Research Use by You. + +(b) Other than the licenses expressly granted in this License, Original +Contributor retains all right, title, and interest in Original Code and +Upgraded Code and Specifications. + +2.2 Your Grants. + +(a) To Other Licensees. You hereby grant to each Licensee a license to +Your Error Corrections and Shared Modifications, of the same scope and +extent as Original Contributor's licenses under Section 2.1 a) above +relative to Research Use and Attachment D relative to Commercial Use. + +(b) To Original Contributor. You hereby grant to Original Contributor a +worldwide, royalty-free, non-exclusive, perpetual and irrevocable +license, to the extent of Your Intellectual Property Rights covering +Your Error Corrections, Shared Modifications and Reformatted +Specifications, to use, reproduce, modify, display and distribute Your +Error Corrections, Shared Modifications and Reformatted Specifications, +in any form, including the right to sublicense such rights through +multiple tiers of distribution. + +(c) Other than the licenses expressly granted in Sections 2.2(a) and (b) +above, and the restrictions set forth in Section 3.1(d)(iv) below, You +retain all right, title, and interest in Your Error Corrections, Shared +Modifications and Reformatted Specifications. + +2.3 Contributor Modifications. + +You may use, reproduce, modify, display and distribute Contributor Error +Corrections, Shared Modifications and Reformatted Specifications, +obtained by You under this License, to the same scope and extent as with +Original Code, Upgraded Code and Specifications. + +2.4 Subcontracting. + +You may deliver the Source Code of Covered Code to other Licensees +having at least a Research Use license, for the sole purpose of +furnishing development services to You in connection with Your rights +granted in this License. All such Licensees must execute appropriate +documents with respect to such work consistent with the terms of this +License, and acknowledging their work-made-for-hire status or assigning +exclusive right to the work product and associated Intellectual Property +Rights to You. + +*3. Requirements and Responsibilities*. + +3.1 Research Use License. + +As a condition of exercising the rights granted under Section 2.1(a) +above, You agree to comply with the following: + +(a) Your Contribution to the Community. All Error Corrections and Shared +Modifications which You create or contribute to are automatically +subject to the licenses granted under Section 2.2 above. You are +encouraged to license all of Your other Modifications under Section 2.2 +as Shared Modifications, but are not required to do so. You agree to +notify Original Contributor of any errors in the Specification. + +(b) Source Code Availability. You agree to provide all Your Error +Corrections to Original Contributor as soon as reasonably practicable +and, in any event, prior to Internal Deployment Use or Commercial Use, +if applicable. Original Contributor may, at its discretion, post Source +Code for Your Error Corrections and Shared Modifications on the +Community Webserver. You may also post Error Corrections and Shared +Modifications on a web-server of Your choice; provided, that You must +take reasonable precautions to ensure that only Licensees have access to +such Error Corrections and Shared Modifications. Such precautions shall +include, without limitation, a password protection scheme limited to +Licensees and a click-on, download certification of Licensee status +required of those attempting to download from the server. An example of +an acceptable certification is attached as Attachment A-2. + +(c) Notices. All Error Corrections and Shared Modifications You create +or contribute to must include a file documenting the additions and +changes You made and the date of such additions and changes. You must +also include the notice set forth in Attachment A-1 in the file header. +If it is not possible to put the notice in a particular Source Code file +due to its structure, then You must include the notice in a location +(such as a relevant directory file), where a recipient would be most +likely to look for such a notice. + +(d) Redistribution. + +(i) Source. Covered Code may be distributed in Source Code form only to +another Licensee (except for students as provided below). You may not +offer or impose any terms on any Covered Code that alter the rights, +requirements, or responsibilities of such Licensee. You may distribute +Covered Code to students for use in connection with their course work +and research projects undertaken at accredited educational institutions. +Such students need not be Licensees, but must be given a copy of the +notice set forth in Attachment A-3 and such notice must also be included +in a file header or prominent location in the Source Code made available +to such students. + +(ii) Executable. You may distribute Executable version(s) of Covered +Code to Licensees and other third parties only for the purpose of +evaluation and comment in connection with Research Use by You and under +a license of Your choice, but which limits use of such Executable +version(s) of Covered Code only to that purpose. + +(iii) Modified Class, Interface and Package Naming. In connection with +Research Use by You only, You may use Original Contributor's class, +Interface and package names only to accurately reference or invoke the +Source Code files You modify. Original Contributor grants to You a +limited license to the extent necessary for such purposes. + +(iv) You expressly agree that any distribution, in whole or in part, of +Modifications developed by You shall only be done pursuant to the terms +and conditions of this License. + +(e) Extensions. + +(i) Covered Code. You may not include any Source Code of Community Code +in any Extensions. You may include the compiled Header Files of +Community Code in an Extension provided that Your use of the Covered +Code, including Heading Files, complies with the Commercial Use License, +the TCK and all other terms of this License. + +(ii) Publication. No later than the date on which You first distribute +such Extension for Commercial Use, You must publish to the industry, on +a non-confidential basis and free of all copyright restrictions with +respect to reproduction and use, an accurate and current specification +for any Extension. In addition, You must make available an appropriate +test suite, pursuant to the same rights as the specification, +sufficiently detailed to allow any third party reasonably skilled in the +technology to produce implementations of the Extension compatible with +the specification. Such test suites must be made available as soon as +reasonably practicable but, in no event, later than ninety (90) days +after Your first Commercial Use of the Extension. You must use +reasonable efforts to promptly clarify and correct the specification and +the test suite upon written request by Original Contributor. + +(iii) Open. You agree to refrain from enforcing any Intellectual +Property Rights You may have covering any interface(s) of Your +Extension, which would prevent the implementation of such interface(s) +by Original Contributor or any Licensee. This obligation does not +prevent You from enforcing any Intellectual Property Right You have that +would otherwise be infringed by an implementation of Your Extension. + +(iv) Interface Modifications and Naming. You may not modify or add to +the GUID space * * "xxxxxxxx-0901-11d1-8B06-00A024406D59" or any other +GUID space designated by Original Contributor. You may not modify any +Interface prefix provided with the Covered Code or any other prefix +designated by Original Contributor.* * + +* * + +(f) You agree that any Specifications provided to You by Original +Contributor are confidential and proprietary information of Original +Contributor. You must maintain the confidentiality of the Specifications +and may not disclose them to any third party without Original +Contributor's prior written consent. You may only use the Specifications +under the terms of this License and only for the purpose of implementing +the terms of this License with respect to Covered Code. You agree not +use, copy or distribute any such Specifications except as provided in +writing by Original Contributor. + +3.2 Commercial Use License. + +You may not make Commercial Use of any Covered Code unless You and +Original Contributor have executed a copy of the Commercial Use and +Trademark License attached as Attachment D. + +*4. Versions of the License.* + +4.1 License Versions. + +Original Contributor may publish revised versions of the License from +time to time. Each version will be given a distinguishing version number. + +4.2 Effect. + +Once a particular version of Covered Code has been provided under a +version of the License, You may always continue to use such Covered Code +under the terms of that version of the License. You may also choose to +use such Covered Code under the terms of any subsequent version of the +License. No one other than Original Contributor has the right to +promulgate License versions. + +4.3 Multiple-Licensed Code. + +Original Contributor may designate portions of the Covered Code as +"Multiple-Licensed." "Multiple-Licensed" means that the Original +Contributor permits You to utilize those designated portions of the +Covered Code under Your choice of this License or the alternative +license(s), if any, specified by the Original Contributor in an +Attachment to this License. + +*5. Disclaimer of Warranty.* + +5.1 COVERED CODE PROVIDED AS IS. + +COVERED CODE IS PROVIDED UNDER THIS LICENSE "AS IS," WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, +WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT +FOR A PARTICULAR PURPOSE OR NON-INFRINGING. YOU AGREE TO BEAR THE ENTIRE +RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF COVERED CODE UNDER +THIS LICENSE. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART +OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER +EXCEPT SUBJECT TO THIS DISCLAIMER. + +5.2 Not Designed for High Risk Activities. + +You acknowledge that Original Code, Upgraded Code and Specifications are +not designed or intended for use in high risk activities including, but +not limited to: (i) on-line control of aircraft, air traffic, aircraft +navigation or aircraft communications; or (ii) in the design, +construction, operation or maintenance of any nuclear facility. Original +Contributor disclaims any express or implied warranty of fitness for +such uses. + +*6. Termination.* + +6.1 By You. + +You may terminate this Research Use license at anytime by providing +written notice to Original Contributor. + +6.2 By Original Contributor. + +This License and the rights granted hereunder will terminate: + +(i) automatically if You fail to comply with the terms of this License +and fail to cure such breach within 30 days of receipt of written notice +of the breach; + +(ii) immediately in the event of circumstances specified in Sections 7.1 +and 8.4; or + +(iii) at Original Contributor's discretion upon any action initiated by +You (including by cross-claim or counter claim) alleging that use or +distribution by Original Contributor or any Licensee, of Original Code, +Upgraded Code, Error Corrections, Shared Modifications or Specifications +infringe a patent owned or controlled by You. + +6.3 Effective of Termination. + +Upon termination, You agree to discontinue use of and destroy all copies +of Covered Code in Your possession. All sublicenses to the Covered Code +which You have properly granted shall survive any termination of this +License. Provisions that, by their nature, should remain in effect +beyond the termination of this License shall survive including, without +limitation, Sections 2.2, 3, 5, 7 and 8. + +6.4 No Compensation. + +Each party waives and releases the other from any claim to compensation +or indemnity for permitted or lawful termination of the business +relationship established by this License. + +*7. Liability.* + +7.1 Infringement. Should any of the Original Code, Upgraded Code, TCK or +Specifications ("Materials") become the subject of a claim of +infringement, Original Contributor may, at its sole option, (i) attempt +to procure the rights necessary for You to continue using the Materials, +(ii) modify the Materials so that they are no longer infringing, or +(iii) terminate Your right to use the Materials, immediately upon +written notice, and refund to You the amount, if any, having then +actually been paid by You to Original Contributor for the Original Code, +Upgraded Code and TCK, depreciated on a straight line, five year basis. + +7.2 LIMITATION OF LIABILITY. TO THE FULL EXTENT ALLOWED BY APPLICABLE +LAW, ORIGINAL CONTRIBUTOR'S LIABILITY TO YOU FOR CLAIMS RELATING TO THIS +LICENSE, WHETHER FOR BREACH OR IN TORT, SHALL BE LIMITED TO ONE HUNDRED +PERCENT (100%) OF THE AMOUNT HAVING THEN ACTUALLY BEEN PAID BY YOU TO +ORIGINAL CONTRIBUTOR FOR ALL COPIES LICENSED HEREUNDER OF THE PARTICULAR +ITEMS GIVING RISE TO SUCH CLAIM, IF ANY, DURING THE TWELVE MONTHS +PRECEDING THE CLAIMED BREACH. IN NO EVENT WILL YOU (RELATIVE TO YOUR +SHARED MODIFICATIONS OR ERROR CORRECTIONS) OR ORIGINAL CONTRIBUTOR BE +LIABLE FOR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES IN CONNECTION WITH OR RISING OUT OF THIS LICENSE (INCLUDING, +WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR OTHER ECONOMIC +ADVANTAGE), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY, WHETHER IN +AN ACTION FOR CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE) +OR OTHERWISE, WHETHER OR NOT YOU OR ORIGINAL CONTRIBUTOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE AND NOTWITHSTANDING THE +FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. + +*8. Miscellaneous.* + +8.1 Trademark. + +You shall not use any Trademark unless You and Original Contributor +execute a copy of the Commercial Use and Trademark License Agreement +attached hereto as Attachment D. Except as expressly provided in the +License, You are granted no right, title or license to, or interest in, +any Trademarks. Whether or not You and Original Contributor enter into +the Trademark License, You agree not to (i) challenge Original +Contributor's ownership or use of Trademarks; (ii) attempt to register +any Trademarks, or any mark or logo substantially similar thereto; or +(iii) incorporate any Trademarks into Your own trademarks, product +names, service marks, company names, or domain names. + +8.2 Integration. + +This License represents the complete agreement concerning the subject +matter hereof. + +8.3 Assignment. + +Original Contributor may assign this License, and its rights and +obligations hereunder, in its sole discretion. You may assign the +Research Use portions of this License and the TCK license to a third +party upon prior written notice to Original Contributor (which may be +provided electronically via the Community Web-Server). You may not +assign the Commercial Use and Trademark license, the Add-On Technology +License, or the Add-On Technology Source Code Porting License, including +by way of merger (regardless of whether You are the surviving entity) or +acquisition, without Original Contributor's prior written consent. + +8.4 Severability. + +If any provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to make it +enforceable. Notwithstanding the foregoing, if You are prohibited by law +from fully and specifically complying with Sections 2.2 or 3, this +License will immediately terminate and You must immediately discontinue +any use of Covered Code. + +8.5 Governing Law. + +This License shall be governed by the laws of the United States and the +State of Washington, as applied to contracts entered into and to be +performed in Washington between Washington residents. The application of +the United Nations Convention on Contracts for the International Sale of +Goods is expressly excluded. You agree that the state and federal courts +located in Seattle, Washington have exclusive jurisdiction over any +claim relating to the License, including contract and tort claims. + +8.6 Dispute Resolution. + +a) Arbitration. Any dispute arising out of or relating to this License +shall be finally settled by arbitration as set out herein, except that +either party may bring any action, in a court of competent jurisdiction +(which jurisdiction shall be exclusive), with respect to any dispute +relating to such party's Intellectual Property Rights or with respect to +Your compliance with the TCK license. Arbitration shall be administered: +(i) by the American Arbitration Association (AAA), (ii) in accordance +with the rules of the United Nations Commission on International Trade +Law (UNCITRAL) (the "Rules") in effect at the time of arbitration as +modified herein; and (iii) the arbitrator will apply the substantive +laws of Washington and the United States. Judgment upon the award +rendered by the arbitrator may be entered in any court having +jurisdiction to enforce such award. + +b) Arbitration language, venue and damages. All arbitration proceedings +shall be conducted in English by a single arbitrator selected in +accordance with the Rules, who must be fluent in English and be either a +retired judge or practicing attorney having at least ten (10) years +litigation experience and be reasonably familiar with the technology +matters relative to the dispute. Unless otherwise agreed, arbitration +venue shall be in Seattle, Washington. The arbitrator may award monetary +damages only and nothing shall preclude either party from seeking +provisional or emergency relief from a court of competent jurisdiction. +The arbitrator shall have no authority to award damages in excess of +those permitted in this License and any such award in excess is void. +All awards will be payable in U.S. dollars and may include, for the +prevailing party (i) pre-judgment award interest, (ii) reasonable +attorneys' fees incurred in connection with the arbitration, and (iii) +reasonable costs and expenses incurred in enforcing the award. The +arbitrator will order each party to produce identified documents and +respond to no more than twenty-five single question interrogatories. + +8.7 Construction. + +Any law or regulation, which provides that the language of a contract +shall be construed against the drafter, shall not apply to this License. + +8.8 U.S. Government End Users. + +The Covered Code is a "commercial item," as that term is defined in 48 +C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" +and "commercial computer software documentation," as such terms are used +in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and +48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government +End Users acquire Covered Code with only those rights set forth herein. +You agree to pass this notice to our licensees. + +8.9 Marketing Activities. + +Licensee hereby grants Original Contributor a non-exclusive, +non-transferable, limited license to use the Licensee's company name and +logo ("Licensee Marks") in any presentations, press releases, or +marketing materials solely for the purpose of identifying Licensee as a +member of the Helix Community. Licensee shall provide samples of +Licensee Marks to Original Contributor upon request by Original +Contributor. Original Contributor acknowledges that the Licensee Marks +are the trademarks of Licensee. Original Contributor shall not use the +Licensee Marks in a way that may imply that Original Contributor is an +agency or branch of Licensee. Original Contributor understands and +agrees that the use of any Licensee Marks in connection with this +Agreement shall not create any right, title or interest, in, or to the +Licensee Marks or any Licensee trademarks and that all such use and +goodwill associated with any such trademarks will inure to the benefit +of Licensee. Further the Original Contributor will stop usage of the +Licensee Marks upon Licensee's request. + +8.10 Press Announcements. + +You may make press announcements or other public statements regarding +this License without the prior written consent of the Original +Contributor, if Your statement is limited to announcing the licensing of +the Covered Code or the availability of Your Product and its +compatibility with the Covered Code. All other public announcements +regarding this license require the prior written consent of the Original +Contributor. Consent requests are welcome at press@helixcommunity.org. + +8.11 International Use. + +a) Export/Import laws. Covered Code is subject to U.S. export control +laws and may be subject to export or import regulations in other +countries. Each party agrees to comply strictly with all such laws and +regulations and acknowledges their responsibility to obtain such +licenses to export, re-export, or import as may be required. You agree +to pass these obligations to Your licensees. + +b) Intellectual Property Protection. Due to limited intellectual +property protection and enforcement in certain countries, You agree not +to redistribute the Original Code, Upgraded Code, TCK and Specifications +to any country on the list of restricted countries on the Community Web +Server. + +8.12 Language. + +This License is in the English language only, which language shall be +controlling in all respects, and all versions of this License in any +other language shall be for accommodation only and shall not be binding +on the parties to this License. All communications and notices made or +given pursuant to this License, and all documentation and support to be +provided, unless otherwise noted, shall be in the English language. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH REALNETWORKS, INC. IF YOU ARE AGREEING +TO THIS LICENSE ON BEHALF OF A COMPANY, YOU REPRESENT THAT YOU ARE +AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. WHETHER YOU ARE ACTING +ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, YOU MUST BE OF MAJORITY +AGE AND BE OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. IF YOU DO NOT +MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY OF THE TERMS AND +CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON TO EXIT. + + + GLOSSARY + +1. *"Added Value"* means code which: + +(i) has a principal purpose which is substantially different from that +of the stand-alone Technology; + +(ii) represents a significant functional and value enhancement to the +Technology; + +(iii) operates in conjunction with the Technology; and + +(iv) is not marketed as a technology which replaces or substitutes for +the Technology + +2. "*Applicable Patent Rights*" mean: (a) in the case where Original +Contributor is the grantor of rights, claims of patents that (i) are now +or hereafter acquired, owned by or assigned to Original Contributor and +(ii) are necessarily infringed by using or making the Original Code or +Upgraded Code, including Modifications provided by Original Contributor, +alone and not in combination with other software or hardware; and (b) in +the case where Licensee is the grantor of rights, claims of patents that +(i) are now or hereafter acquired, owned by or assigned to Licensee and +(ii) are infringed (directly or indirectly) by using or making +Licensee's Modifications or Error Corrections, taken alone or in +combination with Covered Code. + +3. "*Application Programming Interfaces (APIs)"* means the interfaces, +associated header files, service provider interfaces, and protocols that +enable a device, application, Operating System, or other program to +obtain services from or make requests of (or provide services in +response to requests from) other programs, and to use, benefit from, or +rely on the resources, facilities, and capabilities of the relevant +programs using the APIs. APIs includes the technical documentation +describing the APIs, the Source Code constituting the API, and any +Header Files used with the APIs. + +4. "*Commercial Use*" means any use (internal or external), copying, +sublicensing or distribution (internal or external), directly or +indirectly of Covered Code by You other than Your Research Use of +Covered Code within Your business or organization or in conjunction with +other Licensees with equivalent Research Use rights. Commercial Use +includes any use of the Covered Code for direct or indirect commercial +or strategic gain, advantage or other business purpose. Any Commercial +Use requires execution of Attachment D by You and Original Contributor. + +5. "*Community Code*" means the Original Code, Upgraded Code, Error +Corrections, Shared Modifications, or any combination thereof. + +6. "*Community Webserver(s)"* means the webservers designated by +Original Contributor for access to the Original Code, Upgraded Code, TCK +and Specifications and for posting Error Corrections and Shared +Modifications. + +7. "*Compliant Covered Code*" means Covered Code that complies with the +requirements of the TCK. + +8. "*Contributor*" means each Licensee that creates or contributes to +the creation of any Error Correction or Shared Modification. + +9. "*Covered Code*" means the Original Code, Upgraded Code, +Modifications, or any combination thereof. + +10. "*Error Correction*" means any change made to Community Code which +conforms to the Specification and corrects the adverse effect of a +failure of Community Code to perform any function set forth in or +required by the Specifications. + +11. "*Executable*" means Covered Code that has been converted from +Source Code to the preferred form for execution by a computer or digital +processor (e.g. binary form). + +12. "*Extension(s)"* means any additional Interfaces developed by or for +You which: (i) are designed for use with the Technology; (ii) constitute +an API for a library of computing functions or services; and (iii) are +disclosed or otherwise made available to third party software developers +for the purpose of developing software which invokes such additional +Interfaces. The foregoing shall not apply to software developed by Your +subcontractors to be exclusively used by You. + +13. "*Header File(s)"* means that portion of the Source Code that +provides the names and types of member functions, data members, class +definitions, and interface definitions necessary to implement the APIs +for the Covered Code. Header Files include, files specifically +designated by Original Contributor as Header Files. Header Files do not +include the code necessary to implement the functionality underlying the +Interface. + +14. *"Helix DNA Server Technology"* means the program(s) that implement +the Helix Universal Server streaming engine for the Technology as +defined in the Specification. + +15. *"Helix DNA Client Technology"* means the Covered Code that +implements the RealOne Player engine as defined in the Specification. + +16. *"Helix DNA Producer Technology"* means the Covered Code that +implements the Helix Producer engine as defined in the Specification. + +17. *"Helix DNA Technology"* means the Helix DNA Server Technology, the +Helix DNA Client Technology, the Helix DNA Producer Technology and other +Helix technologies designated by Original Contributor. + +18. "*Intellectual Property Rights*" means worldwide statutory and +common law rights associated solely with (i) Applicable Patent Rights; +(ii) works of authorship including copyrights, copyright applications, +copyright registrations and "moral rights"; (iii) the protection of +trade and industrial secrets and confidential information; and (iv) +divisions, continuations, renewals, and re-issuances of the foregoing +now existing or acquired in the future. + +19. *"Interface*" means interfaces, functions, properties, class +definitions, APIs, Header Files, GUIDs, V-Tables, and/or protocols +allowing one piece of software, firmware or hardware to communicate or +interoperate with another piece of software, firmware or hardware. + +20. "*Internal Deployment Use*" means use of Compliant Covered Code +(excluding Research Use) within Your business or organization only by +Your employees and/or agents on behalf of Your business or organization, +but not to provide services, including content distribution, to third +parties, subject to execution of Attachment D by You and Original +Contributor, if required. + +21. "*Licensee*" means any party that has entered into and has in effect +a version of this License with Original Contributor. + +22. "*MIME type*" means a description of what type of media or other +content is in a file, including by way of example but not limited to +'audio/x-pn-realaudio-plugin.' + +23. "*Modification(s)"* means (i) any addition to, deletion from and/or +change to the substance and/or structure of the Covered Code, including +Interfaces; (ii) the combination of any Covered Code and any previous +Modifications; (iii) any new file or other representation of computer +program statements that contains any portion of Covered Code; and/or +(iv) any new Source Code implementing any portion of the Specifications. + +24. "*MP3 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Picture Experts Group known as MPEG-1 Audio Layer-3 or MP3, +including but not limited to all past and future versions, profiles, +extensions, parts and amendments relating to the MP3 specification. + +25. "*MPEG-4 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Pictures Experts Group known as MPEG-4, including but not +limited to all past and future versions, profiles, extensions, parts and +amendments relating to the MPEG-4 specification. + +26. "*Original Code*" means the initial Source Code for the Technology +as described on the Community Web Server. + +27. "*Original Contributor*" means RealNetworks, Inc., its affiliates +and its successors and assigns. + +28. "*Original Contributor MIME Type*" means the MIME registry, browser +preferences, or local file/protocol associations invoking any Helix DNA +Client-based application, including the RealOne Player, for playback of +RealAudio, RealVideo, other RealMedia MIME types or datatypes (e.g., +.ram, .rnx, .rpm, .ra, .rm, .rp, .rt, .rf, .prx, .mpe, .rmp, .rmj, .rav, +.rjs, .rmx, .rjt, .rms), and any other Original Contributor-specific or +proprietary MIME types that Original Contributor may introduce in the +future. + +29. "*Personal Use*" means use of Covered Code by an individual solely +for his or her personal, private and non-commercial purposes. An +individual's use of Covered Code in his or her capacity as an officer, +employee, member, independent contractor or agent of a corporation, +business or organization (commercial or non-commercial) does not qualify +as Personal Use. + +30. "*RealMedia File Format*" means the file format designed and +developed by RealNetworks for storing multimedia data and used to store +RealAudio and RealVideo encoded streams. Valid RealMedia File Format +extensions include: .rm, .rmj, .rmc, .rmvb, .rms. + +31. "*RCSL Webpage*" means the RealNetworks Community Source License +webpage located at https://www.helixcommunity.org/content/rcsl or such +other URL that Original Contributor may designate from time to time. + +32. "*Reformatted Specifications*" means any revision to the +Specifications which translates or reformats the Specifications (as for +example in connection with Your documentation) but which does not alter, +subset or superset * *the functional or operational aspects of the +Specifications. + +33. "*Research Use*" means use and distribution of Covered Code only for +Your Personal Use, research or development use and expressly excludes +Internal Deployment Use and Commercial Use. Research Use also includes +use of Covered Code to teach individuals how to use Covered Code. + +34. "*Shared Modifications*" means Modifications that You distribute or +use for a Commercial Use, in addition to any Modifications provided by +You, at Your option, pursuant to Section 2.2, or received by You from a +Contributor pursuant to Section 2.3. + +35. "*Source Code*" means the preferred form of the Covered Code for +making modifications to it, including all modules it contains, plus any +associated interface definition files, scripts used to control +compilation and installation of an Executable, or source code +differential comparisons against either the Original Code or another +well known, available Covered Code of the Contributor's choice. The +Source Code can be in a compressed or archival form, provided the +appropriate decompression or de-archiving software is widely available +for no charge. + +36. "*Specifications*" means the specifications for the Technology and +other documentation, as designated on the Community Web Server, as may +be revised by Original Contributor from time to time. + +37. "*Trademarks*" means Original Contributor's trademarks and logos, +including, but not limited to, RealNetworks, RealAudio, RealVideo, +RealOne, RealSystem, SureStream, Helix, Helix DNA and other trademarks +whether now used or adopted in the future. + +38. "*Technology*" means the technology described in Attachment B, and +Upgrades. + +39. "*Technology Compatibility Kit"* or *"TCK*" means the test programs, +procedures, acceptance criteria and/or other requirements, designated by +Original Contributor for use in verifying compliance of Covered Code +with the Specifications, in conjunction with the Original Code and +Upgraded Code. Original Contributor may, in its sole discretion and from +time to time, revise a TCK to correct errors and/or omissions and in +connection with Upgrades. + +40. "*Upgrade(s)"* means new versions of Technology designated +exclusively by Original Contributor as an "Upgrade" and released by +Original Contributor from time to time under the terms of the License. + +41. "*Upgraded Code*" means the Source Code and/or Executables for +Upgrades, possibly including Modifications made by Contributors. + +42. *"User's Guide"* means the users guide for the TCK which Original +Contributor makes available to You to provide direction in how to run +the TCK and properly interpret the results, as may be revised by +Original Contributor from time to time. + +43. "*You(r)*" means an individual, or a legal entity acting by and +through an individual or individuals, exercising rights either under +this License or under a future version of this License issued pursuant +to Section 4.1. For legal entities, "You(r)" includes any entity that by +majority voting interest controls, is controlled by, or is under common +control with You. + +44. "*Your Products*" means any (i) hardware products You distribute +integrating the Covered Code; (ii) any software products You distribute +with the Covered Code that utilize the APIs of the Covered Code; or +(iii) any services You provide using the Covered Code. + + + ATTACHMENT A + +REQUIRED NOTICES + + + ATTACHMENT A-1 + +REQUIRED IN ALL CASES + +Notice to be included in header file of all Error Corrections and Shared +Modifications: + +Portions Copyright 1994-2003 RealNetworks, Inc. All rights reserved. + +The contents of this file, and the files included with this file, are +subject to the current version of RealNetworks Community Source License +Version 1.1 (the "License"). You may not use this file except in +compliance with the License executed by both You and RealNetworks. You +may obtain a copy of the License at * +https://www.helixcommunity.org/content/rcsl.* You may also obtain a copy +of the License by contacting RealNetworks directly. Please see the +License for the rights, obligations and limitations governing use of the +contents of the file. + +This file is part of the Helix DNA technology. RealNetworks, Inc., is +the developer of the Original code and owns the copyrights in the +portions it created. + +This file, and the files included with this file, are distributed on an +'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, +AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): + +_______________________________________________ + +Technology Compatibility Kit Test Suite(s) Location: + +________________________________ + + + ATTACHMENT A-2 + +SAMPLE LICENSEE CERTIFICATION + +"By clicking the `Agree' button below, You certify that You are a +Licensee in good standing under the RealNetworks Community Source +License, ("License") and that Your access, use and distribution of code +and information You may obtain at this site is subject to the License. +If You are not a Licensee under the RealNetworks Community Source +License You agree not to download, copy or use the Helix DNA technology. + + + ATTACHMENT A-3 + +REQUIRED STUDENT NOTIFICATION + +"This software and related documentation has been obtained by Your +educational institution subject to the RealNetworks Community Source +License. You have been provided access to the software and related +documentation for use only in connection with your course work and +research activities as a matriculated student of Your educational +institution. Any other use is expressly prohibited. + +THIS SOFTWARE AND RELATED DOCUMENTATION CONTAINS PROPRIETARY MATERIAL OF +REALNETWORKS, INC, WHICH ARE PROTECTED BY VARIOUS INTELLECTUAL PROPERTY +RIGHTS. + +You may not use this file except in compliance with the License. You may +obtain a copy of the License on the web at +https://www.helixcommunity.org/content/rcsl. + +* +* + + + ATTACHMENT B + +Description of Technology + +Helix DNA, which consists of Helix DNA Client, Helix DNA Server and +Helix DNA Producer. + +Description of "Technology" + +Helix DNA Technology v1.0 as described on the Community Web Server. + + + ATTACHMENT C + +TECHNOLOGY COMPATIBILITY KIT LICENSE + +The following license is effective for the *Helix DNA* Technology +Compatibility Kit - as described on the Community Web Server. The +Technology Compatibility Kit(s) for the Technology specified in +Attachment B may be accessed at the Community Web Server. + +1. TCK License. + +1.1 Grants to use TCK + +Subject to the terms and restrictions set forth below and the +RealNetworks Community Source License, and the Research Use license, +Original Contributor grants to You a worldwide, non-exclusive, +non-transferable license, to the extent of Original Contributor's +Intellectual Property Rights in the TCK (without the right to +sublicense), to use the TCK to develop and test Covered Code. + +1.2 TCK Use Restrictions. + +You are not authorized to create derivative works of the TCK or use the +TCK to test any implementation of the Specification that is not Covered +Code. You may not publish Your test results or make claims of +comparative compatibility with respect to other implementations of the +Specification. In consideration for the license grant in Section 1.1 +above You agree not to develop Your own tests that are intended to +validate conformation with the Specification. + +2. Test Results. + +You agree to provide to Original Contributor or the third party test +facility if applicable, Your test results that demonstrate that Covered +Code is Compliant Covered Code and that Original Contributor may publish +or otherwise distribute such test results. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH THE ORIGINAL CONTRIBUTOR, REALNETWORKS, +INC. IF YOU ARE AGREEING TO THIS LICENSE ON BEHALF OF A COMPANY, YOU +REPRESENT THAT YOU ARE AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. +WHETHER YOU ARE ACTING ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, +YOU MUST BE OF MAJORITY AGE AND BE OTHERWISE COMPETENT TO ENTER INTO +CONTRACTS. IF YOU DO NOT MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY +OF THE TERMS AND CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON +TO EXIT. + +*ACCEPT / REJECT +* + +* +* + +*To agree to the R&D/academic terms of this license, please register + on the site -- +you will then be given a chance to agree to the clickwrap RCSL + +R&D License + +and gain access to the RCSL-licensed source code. To build or deploy +commercial applications based on the RCSL, you will need to agree to the +Commercial Use license attachments +* + + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/RPSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/RPSL.txt new file mode 100644 index 0000000..d040a45 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/RPSL.txt @@ -0,0 +1,518 @@ +RealNetworks Public Source License Version 1.0 +(Rev. Date October 28, 2002) + +1. General Definitions. This License applies to any program or other work which +RealNetworks, Inc., or any other entity that elects to use this license, +("Licensor") makes publicly available and which contains a notice placed by +Licensor identifying such program or work as "Original Code" and stating that it +is subject to the terms of this RealNetworks Public Source License version 1.0 +(or subsequent version thereof) ("License"). You are not required to accept this +License. However, nothing else grants You permission to use, copy, modify or +distribute the software or its derivative works. These actions are prohibited by +law if You do not accept this License. Therefore, by modifying, copying or +distributing the software (or any work based on the software), You indicate your +acceptance of this License to do so, and all its terms and conditions. In +addition, you agree to the terms of this License by clicking the Accept button +or downloading the software. As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Licensor is the +grantor of rights, claims of patents that (i) are now or hereafter acquired, +owned by or assigned to Licensor and (ii) are necessarily infringed by using or +making the Original Code alone and not in combination with other software or +hardware; and (b) in the case where You are the grantor of rights, claims of +patents that (i) are now or hereafter acquired, owned by or assigned to You and +(ii) are infringed (directly or indirectly) by using or making Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Compatible Source License" means any one of the licenses listed on Exhibit +B or at https://www.helixcommunity.org/content/complicense or other licenses +specifically identified by Licensor in writing. Notwithstanding any term to the +contrary in any Compatible Source License, any code covered by any Compatible +Source License that is used with Covered Code must be made readily available in +Source Code format for royalty-free use under the terms of the Compatible Source +License or this License. + +1.3 "Contributor" means any person or entity that creates or contributes to the +creation of Modifications. + +1.4 "Covered Code" means the Original Code, Modifications, the combination of +Original Code and any Modifications, and/or any respective portions thereof. + +1.5 "Deploy" means to use, sublicense or distribute Covered Code other than for +Your internal research and development (R&D) and/or Personal Use, and includes +without limitation, any and all internal use or distribution of Covered Code +within Your business or organization except for R&D use and/or Personal Use, as +well as direct or indirect sublicensing or distribution of Covered Code by You +to any third party in any form or manner. + +1.6 "Derivative Work" means either the Covered Code or any derivative work under +United States copyright law, and including any work containing or including any +portion of the Covered Code or Modifications, either verbatim or with +modifications and/or translated into another language. Derivative Work also +includes any work which combines any portion of Covered Code or Modifications +with code not otherwise governed by the terms of this License. + +1.7 "Externally Deploy" means to Deploy the Covered Code in any way that may be +accessed or used by anyone other than You, used to provide any services to +anyone other than You, or used in any way to deliver any content to anyone other +than You, whether the Covered Code is distributed to those parties, made +available as an application intended for use over a computer network, or used to +provide services or otherwise deliver content to anyone other than You. + +1.8. "Interface" means interfaces, functions, properties, class definitions, +APIs, header files, GUIDs, V-Tables, and/or protocols allowing one piece of +software, firmware or hardware to communicate or interoperate with another piece +of software, firmware or hardware. + +1.9 "Modifications" mean any addition to, deletion from, and/or change to, the +substance and/or structure of the Original Code, any previous Modifications, the +combination of Original Code and any previous Modifications, and/or any +respective portions thereof. When code is released as a series of files, a +Modification is: (a) any addition to or deletion from the contents of a file +containing Covered Code; and/or (b) any new file or other representation of +computer program statements that contains any part of Covered Code. + +1.10 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Licensor under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Licensor under this License, and that has been expressly identified by Licensor +as such in the header file(s) of such work; and (b) the object code compiled +from such Source Code and originally made available by Licensor under this +License. + +1.11 "Personal Use" means use of Covered Code by an individual solely for his or +her personal, private and non-commercial purposes. An individual's use of +Covered Code in his or her capacity as an officer, employee, member, independent +contractor or agent of a corporation, business or organization (commercial or +non-commercial) does not qualify as Personal Use. + +1.12 "Source Code" means the human readable form of a program or other work that +is suitable for making modifications to it, including all modules it contains, +plus any associated interface definition files, scripts used to control +compilation and installation of an executable (object code). + +1.13 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership of +fifty percent (50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Licensor hereby grants You, effective on the date +You accept this License (via downloading or using Covered Code or otherwise +indicating your acceptance of this License), a worldwide, royalty-free, +non-exclusive copyright license, to the extent of Licensor's copyrights cover +the Original Code, to do the following: + +2.1 You may reproduce, display, perform, modify and Deploy Covered Code, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the copyright +and other proprietary notices and disclaimers of Licensor as they appear in the +Original Code, and keep intact all notices in the Original Code that refer to +this License; + +(b) You must include a copy of this License with every copy of Source Code of +Covered Code and documentation You distribute, and You may not offer or impose +any terms on such Source Code that alter or restrict this License or the +recipients' rights hereunder, except as permitted under Section 6; + +(c) You must duplicate, to the extent it does not already exist, the notice in +Exhibit A in each file of the Source Code of all Your Modifications, and cause +the modified files to carry prominent notices stating that You changed the files +and the date of any change; + +(d) You must make Source Code of all Your Externally Deployed Modifications +publicly available under the terms of this License, including the license grants +set forth in Section 3 below, for as long as you Deploy the Covered Code or +twelve (12) months from the date of initial Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Deployed Modifications +electronically (e.g. download from a web site); and + +(e) if You Deploy Covered Code in object code, executable form only, You must +include a prominent notice, in the code itself as well as in related +documentation, stating that Source Code of the Covered Code is available under +the terms of this License with information on how and where to obtain such +Source Code. You must also include the Object Code Notice set forth in Exhibit A +in the "about" box or other appropriate place where other copyright notices are +placed, including any packaging materials. + +2.2 You expressly acknowledge and agree that although Licensor and each +Contributor grants the licenses to their respective portions of the Covered Code +set forth herein, no assurances are provided by Licensor or any Contributor that +the Covered Code does not infringe the patent or other intellectual property +rights of any other entity. Licensor and each Contributor disclaim any liability +to You for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, You hereby assume sole responsibility to +secure any other intellectual property rights needed, if any. For example, if a +third party patent license is required to allow You to make, use, sell, import +or offer for sale the Covered Code, it is Your responsibility to acquire such +license(s). + +2.3 Subject to the terms and conditions of this License, Licensor hereby grants +You, effective on the date You accept this License (via downloading or using +Covered Code or otherwise indicating your acceptance of this License), a +worldwide, royalty-free, perpetual, non-exclusive patent license under +Licensor's Applicable Patent Rights to make, use, sell, offer for sale and +import the Covered Code, provided that in each instance you comply with the +terms of this License. + +3. Your Grants. In consideration of, and as a condition to, the licenses granted +to You under this License: + +(a) You grant to Licensor and all third parties a non-exclusive, perpetual, +irrevocable, royalty free license under Your Applicable Patent Rights and other +intellectual property rights owned or controlled by You, to make, sell, offer +for sale, use, import, reproduce, display, perform, modify, distribute and +Deploy Your Modifications of the same scope and extent as Licensor's licenses +under Sections 2.1 and 2.2; and + +(b) You grant to Licensor and its subsidiaries a non-exclusive, worldwide, +royalty-free, perpetual and irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights owned or controlled by You, to +make, use, sell, offer for sale, import, reproduce, display, perform, +distribute, modify or have modified (for Licensor and/or its subsidiaries), +sublicense and distribute Your Modifications, in any form and for any purpose, +through multiple tiers of distribution. + +(c) You agree not use any information derived from Your use and review of the +Covered Code, including but not limited to any algorithms or inventions that may +be contained in the Covered Code, for the purpose of asserting any of Your +patent rights, or assisting a third party to assert any of its patent rights, +against Licensor or any Contributor. + +4. Derivative Works. You may create a Derivative Work by combining Covered Code +with other code not otherwise governed by the terms of this License and +distribute the Derivative Work as an integrated product. In each such instance, +You must make sure the requirements of this License are fulfilled for the +Covered Code or any portion thereof, including all Modifications. + +4.1 You must cause any Derivative Work that you distribute, publish or +Externally Deploy, that in whole or in part contains or is derived from the +Covered Code or any part thereof, to be licensed as a whole at no charge to all +third parties under the terms of this License and no other license except as +provided in Section 4.2. You also must make Source Code available for the +Derivative Work under the same terms as Modifications, described in Sections 2 +and 3, above. + +4.2 Compatible Source Licenses. Software modules that have been independently +developed without any use of Covered Code and which contain no portion of the +Covered Code, Modifications or other Derivative Works, but are used or combined +in any way wtih the Covered Code or any Derivative Work to form a larger +Derivative Work, are exempt from the conditions described in Section 4.1 but +only to the extent that: the software module, including any software that is +linked to, integrated with, or part of the same applications as, the software +module by any method must be wholly subject to one of the Compatible Source +Licenses. Notwithstanding the foregoing, all Covered Code must be subject to the +terms of this License. Thus, the entire Derivative Work must be licensed under a +combination of the RPSL (for Covered Code) and a Compatible Source License for +any independently developed software modules within the Derivative Work. The +foregoing requirement applies even if the Compatible Source License would +ordinarily allow the software module to link with, or form larger works with, +other software that is not subject to the Compatible Source License. For +example, although the Mozilla Public License v1.1 allows Mozilla code to be +combined with proprietary software that is not subject to the MPL, if +MPL-licensed code is used with Covered Code the MPL-licensed code could not be +combined or linked with any code not governed by the MPL. The general intent of +this section 4.2 is to enable use of Covered Code with applications that are +wholly subject to an acceptable open source license. You are responsible for +determining whether your use of software with Covered Code is allowed under Your +license to such software. + +4.3 Mere aggregation of another work not based on the Covered Code with the +Covered Code (or with a work based on the Covered Code) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. If You deliver the Covered Code for combination and/or integration with +an application previously provided by You (for example, via automatic updating +technology), such combination and/or integration constitutes a Derivative Work +subject to the terms of this License. + +5. Exclusions From License Grant. Nothing in this License shall be deemed to +grant any rights to trademarks, copyrights, patents, trade secrets or any other +intellectual property of Licensor or any Contributor except as expressly stated +herein. No right is granted to the trademarks of Licensor or any Contributor +even if such marks are included in the Covered Code. Nothing in this License +shall be interpreted to prohibit Licensor from licensing under different terms +from this License any code that Licensor otherwise would have a right to +license. Modifications, Derivative Works and/or any use or combination of +Covered Code with other technology provided by Licensor or third parties may +require additional patent licenses from Licensor which Licensor may grant in its +sole discretion. No patent license is granted separate from the Original Code or +combinations of the Original Code with other software or hardware. + +5.1. Trademarks. This License does not grant any rights to use the trademarks or +trade names owned by Licensor ("Licensor Marks" defined in Exhibit C) or to any +trademark or trade name belonging to any Contributor. No Licensor Marks may be +used to endorse or promote products derived from the Original Code other than as +permitted by the Licensor Trademark Policy defined in Exhibit C. + +6. Additional Terms. You may choose to offer, and to charge a fee for, warranty, +support, indemnity or liability obligations and/or other rights consistent with +the scope of the license granted herein ("Additional Terms") to one or more +recipients of Covered Code. However, You may do so only on Your own behalf and +as Your sole responsibility, and not on behalf of Licensor or any Contributor. +You must obtain the recipient's agreement that any such Additional Terms are +offered by You alone, and You hereby agree to indemnify, defend and hold +Licensor and every Contributor harmless for any liability incurred by or claims +asserted against Licensor or such Contributor by reason of any such Additional +Terms. + +7. Versions of the License. Licensor may publish revised and/or new versions of +this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular version +of this License, You may continue to use it under the terms of that version. You +may also choose to use such Original Code under the terms of any subsequent +version of this License published by Licensor. No one other than Licensor has +the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in part +pre-release, untested, or not fully tested works. The Covered Code may contain +errors that could cause failures or loss of data, and may be incomplete or +contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND LICENSOR AND LICENSOR'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS +"LICENSOR" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY +DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET +ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. LICENSOR AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN DOCUMENTATION, INFORMATION OR ADVICE GIVEN BY LICENSOR, A LICENSOR +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You +acknowledge that the Covered Code is not intended for use in high risk +activities, including, but not limited to, the design, construction, operation +or maintenance of nuclear facilities, aircraft navigation, aircraft +communication systems, or air traffic control machines in which case the failure +of the Covered Code could lead to death, personal injury, or severe physical or +environmental damage. Licensor disclaims any express or implied warranty of +fitness for such uses. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT +SHALL LICENSOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR STRICT +LIABILITY), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF LICENSOR OR SUCH +CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND +NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. SOME +JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF INCIDENTAL OR +CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event +shall Licensor's total liability to You for all damages (other than as may be +required by applicable law) under this License exceed the amount of ten dollars +($10.00). + +10. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Licensor retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Licensor +("Licensor Modifications"), and such Licensor Modifications will not be +automatically subject to this License. Licensor may, at its sole discretion, +choose to license such Licensor Modifications under this License, or on +different terms from those contained in this License or may choose not to +license them at all. + +11. Termination. + +11.1 Term and Termination. The term of this License is perpetual unless +terminated as provided below. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Licensor if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; + +(b) immediately in the event of the circumstances described in Section 12.5(b); +or + +(c) automatically without notice from Licensor if You, at any time during the +term of this License, commence an action for patent infringement against +Licensor (including by cross-claim or counter claim in a lawsuit); + +(d) upon written notice from Licensor if You, at any time during the term of +this License, commence an action for patent infringement against any third party +alleging that the Covered Code itself (excluding combinations with other +software or hardware) infringes any patent (including by cross-claim or counter +claim in a lawsuit). + +11.2 Effect of Termination. Upon termination, You agree to immediately stop any +further use, reproduction, modification, sublicensing and distribution of the +Covered Code and to destroy all copies of the Covered Code that are in your +possession or control. All sublicenses to the Covered Code which have been +properly granted prior to termination shall survive any termination of this +License. Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to Sections +3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other for +compensation, indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this License will +be without prejudice to any other right or remedy of any party. + +12. Miscellaneous. + +12.1 Government End Users. The Covered Code is a "commercial item" as defined in +FAR 2.101. Government software and technical data rights in the Covered Code +include only those rights customarily provided to the public as defined in this +License. This customary commercial license in technical data and software is +provided in accordance with FAR 12.211 (Technical Data) and 12.212 (Computer +Software) and, for Department of Defense purchases, DFAR 252.227-7015 (Technical +Data -- Commercial Items) and 227.7202-3 (Rights in Commercial Computer Software +or Computer Software Documentation). Accordingly, all U.S. Government End Users +acquire Covered Code with only those rights set forth herein. + +12.2 Relationship of Parties. This License will not be construed as creating an +agency, partnership, joint venture or any other form of legal association +between or among You, Licensor or any Contributor, and You will not represent to +the contrary, whether expressly, by implication, appearance or otherwise. + +12.3 Independent Development. Nothing in this License will impair Licensor's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions as, +or otherwise compete with, Modifications, Derivative Works, technology or +products that You may develop, produce, market or distribute. + +12.4 Waiver; Construction. Failure by Licensor or any Contributor to enforce any +provision of this License will not be deemed a waiver of future enforcement of +that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +12.5 Severability. (a) If for any reason a court of competent jurisdiction finds +any provision of this License, or portion thereof, to be unenforceable, that +provision of the License will be enforced to the maximum extent permissible so +as to effect the economic benefits and intent of the parties, and the remainder +of this License will continue in full force and effect. (b) Notwithstanding the +foregoing, if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the enforceability +of either of those Sections, this License will immediately terminate and You +must immediately discontinue any use of the Covered Code and destroy all copies +of it that are in your possession or control. + +12.6 Dispute Resolution. Any litigation or other dispute resolution between You +and Licensor relating to this License shall take place in the Seattle, +Washington, and You and Licensor hereby consent to the personal jurisdiction of, +and venue in, the state and federal courts within that District with respect to +this License. The application of the United Nations Convention on Contracts for +the International Sale of Goods is expressly excluded. + +12.7 Export/Import Laws. This software is subject to all export and import laws +and restrictions and regulations of the country in which you receive the Covered +Code and You are solely responsible for ensuring that You do not export, +re-export or import the Covered Code or any direct product thereof in violation +of any such restrictions, laws or regulations, or without all necessary +authorizations. + +12.8 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +Washington. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé +que le présent contrat et tous les documents connexes soient +rédigés en anglais. + + EXHIBIT A. + +"Copyright © 1995-2002 +RealNetworks, Inc. and/or its licensors. All Rights Reserved. + +The contents of this file, and the files included with this file, are subject to +the current version of the RealNetworks Public Source License Version 1.0 (the +"RPSL") available at https://www.helixcommunity.org/content/rpsl unless you have +licensed the file under the RealNetworks Community Source License Version 1.0 +(the "RCSL") available at https://www.helixcommunity.org/content/rcsl, in which +case the RCSL will apply. You may also obtain the license terms directly from +RealNetworks. You may not use this file except in compliance with the RPSL or, +if you have a valid RCSL with RealNetworks applicable to this file, the RCSL. +Please see the applicable RPSL or RCSL for the rights, obligations and +limitations governing use of the contents of the file. + +This file is part of the Helix DNA Technology. RealNetworks is the developer of +the Original code and owns the copyrights in the portions it created. + +This file, and the files included with this file, is distributed and made +available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR +IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING +WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): ____________________________________ + +Technology Compatibility Kit Test +Suite(s) Location (if licensed under the RCSL): ______________________________ + +Object Code Notice: Helix DNA Client technology included. Copyright (c) +RealNetworks, Inc., 1995-2002. All rights reserved. + + + EXHIBIT B + +Compatible Source Licenses for the RealNetworks Public Source License. The +following list applies to the most recent version of the license as of October +25, 2002, unless otherwise indicated. + +* Academic Free License +* Apache Software License +* Apple Public Source License +* Artistic license +* Attribution Assurance Licenses +* BSD license +* Common Public License (1) +* Eiffel Forum License +* GNU General Public License (GPL) (1) +* GNU Library or "Lesser" General Public License (LGPL) (1) +* IBM Public License +* Intel Open Source License +* Jabber Open Source License +* MIT license +* MITRE Collaborative Virtual Workspace License (CVW License) +* Motosoto License +* Mozilla Public License 1.0 (MPL) +* Mozilla Public License 1.1 (MPL) +* Nokia Open Source License +* Open Group Test Suite License +* Python Software Foundation License +* Ricoh Source Code Public License +* Sun Industry Standards Source License (SISSL) +* Sun Public License +* University of Illinois/NCSA Open Source License +* Vovida Software License v. 1.0 +* W3C License +* X.Net License +* Zope Public License +* zlib/libpng license + +(1) Note: because this license contains certain reciprocal licensing terms that +purport to extend to independently developed code, You may be prohibited under +the terms of this otherwise compatible license from using code licensed under +its terms with Covered Code because Covered Code may only be licensed under the +RealNetworks Public Source License. Any attempt to apply non RPSL license terms, +including without limitation the GPL, to Covered Code is expressly forbidden. +You are responsible for ensuring that Your use of Compatible Source Licensed +code does not violate either the RPSL or the Compatible Source License. + +The latest version of this list can be found at: +https://www.helixcommunity.org/content/complicense + + EXHIBIT C + +RealNetworks' Trademark policy. + +RealNetworks defines the following trademarks collectively as "Licensor +Trademarks": "RealNetworks", "RealPlayer", "RealJukebox", "RealSystem", +"RealAudio", "RealVideo", "RealOne Player", "RealMedia", "Helix" or any other +trademarks or trade names belonging to RealNetworks. + +RealNetworks "Licensor Trademark Policy" forbids any use of Licensor Trademarks +except as permitted by and in strict compliance at all times with RealNetworks' +third party trademark usage guidelines which are posted at +http://www.realnetworks.com/info/helixlogo.html. + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/mp3dec.mcp b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/mp3dec.mcp new file mode 100644 index 0000000..3651bdd Binary files /dev/null and b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/mp3dec.mcp differ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/testwrap.mcp b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/testwrap.mcp new file mode 100644 index 0000000..a2be24b Binary files /dev/null and b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armads/testwrap.mcp differ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/LICENSE.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/LICENSE.txt new file mode 100644 index 0000000..12e5372 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/LICENSE.txt @@ -0,0 +1,30 @@ + Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. + + The contents of this directory, and (except where otherwise + indicated) the directories included within this directory, are + subject to the current version of the RealNetworks Public Source + License (the "RPSL") available at RPSL.txt in this directory, unless + you have licensed the directory under the current version of the + RealNetworks Community Source License (the "RCSL") available at + RCSL.txt in this directory, in which case the RCSL will apply. You + may also obtain the license terms directly from RealNetworks. You + may not use the files in this directory except in compliance with the + RPSL or, if you have a valid RCSL with RealNetworks applicable to + this directory, the RCSL. Please see the applicable RPSL or RCSL for + the rights, obligations and limitations governing use of the contents + of the directory. + + This directory is part of the Helix DNA Technology. RealNetworks is + the developer of the Original Code and owns the copyrights in the + portions it created. + + This directory, and the directories included with this directory, are + distributed and made available on an 'AS IS' basis, WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY + DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + QUIET ENJOYMENT OR NON-INFRINGEMENT. + + Technology Compatibility Kit Test Suite(s) Location: + http://www.helixcommunity.org/content/tck + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/RCSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/RCSL.txt new file mode 100644 index 0000000..a809759 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/RCSL.txt @@ -0,0 +1,948 @@ +The RCSL is made up of a base agreement and a few Attachments. + +For Research and Development use, you agree to the terms of the +RCSL R&D License (base RCSL and Attachments A, B, and C) + +For Commercial Use (either distribution or internal commercial +deployment) of the Helix DNA with or without support for RealNetworks' +RealAudio and RealVideo Add-on Technology, you agree to the +terms of the same RCSL R&D license +and execute one or more additional Commercial Use License attachments +. + +------------------------------------------------------------------------ + + + REALNETWORKS COMMUNITY SOURCE LICENSE + +Version 1.2 (Rev. Date: January 22, 2003). + + + RECITALS + +Original Contributor has developed Specifications, Source Code +implementations and Executables of certain Technology; and + +Original Contributor desires to license the Technology to a large +community to facilitate research, innovation and product development +while maintaining compatibility of such products with the Technology as +delivered by Original Contributor; and + +Original Contributor desires to license certain Trademarks for the +purpose of branding products that are compatible with the relevant +Technology delivered by Original Contributor; and + +You desire to license the Technology and possibly certain Trademarks +from Original Contributor on the terms and conditions specified in this +License. + +In consideration for the mutual covenants contained herein, You and +Original Contributor agree as follows: + + + AGREEMENT + +*1. Introduction.* + +The RealNetworks Community Source License ("RCSL") and effective +attachments ("License") may include five distinct licenses: + +i) Research Use license -- License plus Attachments A, B and C only. + +ii) Commercial Use and Trademark License, which may be for Internal +Deployment Use or external distribution, or both -- License plus +Attachments A, B, C, and D. + +iii) Technology Compatibility Kit (TCK) license -- Attachment C. + +iv) Add-On Technology License (Executable) Commercial Use License +-Attachment F. + +v) Add-On Technology Source Code Porting and Optimization +License-Attachment G. + +The Research Use license is effective when You click and accept this +License. The TCK is effective when You click and accept this License, +unless otherwise specified in the TCK attachments. The Commercial Use +and Trademark, Add-On Technology License, and the Add-On Technology +Source Code Porting and Optimization licenses must each be signed by You +and Original Contributor to become effective. Once effective, these +licenses and the associated requirements and responsibilities are +cumulative. Capitalized terms used in this License are defined in the +Glossary. + +*2. License Grants.* + +2.1 Original Contributor Grant. + +Subject to Your compliance with Sections 3, 8.10 and Attachment A of +this License, Original Contributor grants to You a worldwide, +royalty-free, non-exclusive license, to the extent of Original +Contributor's Intellectual Property Rights covering the Original Code, +Upgraded Code and Specifications, to do the following: + +(a) Research Use License: + +(i) use, reproduce and modify the Original Code, Upgraded Code and +Specifications to create Modifications and Reformatted Specifications +for Research Use by You; + +(ii) publish and display Original Code, Upgraded Code and Specifications +with, or as part of Modifications, as permitted under Section 3.1(b) below; + +(iii) reproduce and distribute copies of Original Code and Upgraded Code +to Licensees and students for Research Use by You; + +(iv) compile, reproduce and distribute Original Code and Upgraded Code +in Executable form, and Reformatted Specifications to anyone for +Research Use by You. + +(b) Other than the licenses expressly granted in this License, Original +Contributor retains all right, title, and interest in Original Code and +Upgraded Code and Specifications. + +2.2 Your Grants. + +(a) To Other Licensees. You hereby grant to each Licensee a license to +Your Error Corrections and Shared Modifications, of the same scope and +extent as Original Contributor's licenses under Section 2.1 a) above +relative to Research Use and Attachment D relative to Commercial Use. + +(b) To Original Contributor. You hereby grant to Original Contributor a +worldwide, royalty-free, non-exclusive, perpetual and irrevocable +license, to the extent of Your Intellectual Property Rights covering +Your Error Corrections, Shared Modifications and Reformatted +Specifications, to use, reproduce, modify, display and distribute Your +Error Corrections, Shared Modifications and Reformatted Specifications, +in any form, including the right to sublicense such rights through +multiple tiers of distribution. + +(c) Other than the licenses expressly granted in Sections 2.2(a) and (b) +above, and the restrictions set forth in Section 3.1(d)(iv) below, You +retain all right, title, and interest in Your Error Corrections, Shared +Modifications and Reformatted Specifications. + +2.3 Contributor Modifications. + +You may use, reproduce, modify, display and distribute Contributor Error +Corrections, Shared Modifications and Reformatted Specifications, +obtained by You under this License, to the same scope and extent as with +Original Code, Upgraded Code and Specifications. + +2.4 Subcontracting. + +You may deliver the Source Code of Covered Code to other Licensees +having at least a Research Use license, for the sole purpose of +furnishing development services to You in connection with Your rights +granted in this License. All such Licensees must execute appropriate +documents with respect to such work consistent with the terms of this +License, and acknowledging their work-made-for-hire status or assigning +exclusive right to the work product and associated Intellectual Property +Rights to You. + +*3. Requirements and Responsibilities*. + +3.1 Research Use License. + +As a condition of exercising the rights granted under Section 2.1(a) +above, You agree to comply with the following: + +(a) Your Contribution to the Community. All Error Corrections and Shared +Modifications which You create or contribute to are automatically +subject to the licenses granted under Section 2.2 above. You are +encouraged to license all of Your other Modifications under Section 2.2 +as Shared Modifications, but are not required to do so. You agree to +notify Original Contributor of any errors in the Specification. + +(b) Source Code Availability. You agree to provide all Your Error +Corrections to Original Contributor as soon as reasonably practicable +and, in any event, prior to Internal Deployment Use or Commercial Use, +if applicable. Original Contributor may, at its discretion, post Source +Code for Your Error Corrections and Shared Modifications on the +Community Webserver. You may also post Error Corrections and Shared +Modifications on a web-server of Your choice; provided, that You must +take reasonable precautions to ensure that only Licensees have access to +such Error Corrections and Shared Modifications. Such precautions shall +include, without limitation, a password protection scheme limited to +Licensees and a click-on, download certification of Licensee status +required of those attempting to download from the server. An example of +an acceptable certification is attached as Attachment A-2. + +(c) Notices. All Error Corrections and Shared Modifications You create +or contribute to must include a file documenting the additions and +changes You made and the date of such additions and changes. You must +also include the notice set forth in Attachment A-1 in the file header. +If it is not possible to put the notice in a particular Source Code file +due to its structure, then You must include the notice in a location +(such as a relevant directory file), where a recipient would be most +likely to look for such a notice. + +(d) Redistribution. + +(i) Source. Covered Code may be distributed in Source Code form only to +another Licensee (except for students as provided below). You may not +offer or impose any terms on any Covered Code that alter the rights, +requirements, or responsibilities of such Licensee. You may distribute +Covered Code to students for use in connection with their course work +and research projects undertaken at accredited educational institutions. +Such students need not be Licensees, but must be given a copy of the +notice set forth in Attachment A-3 and such notice must also be included +in a file header or prominent location in the Source Code made available +to such students. + +(ii) Executable. You may distribute Executable version(s) of Covered +Code to Licensees and other third parties only for the purpose of +evaluation and comment in connection with Research Use by You and under +a license of Your choice, but which limits use of such Executable +version(s) of Covered Code only to that purpose. + +(iii) Modified Class, Interface and Package Naming. In connection with +Research Use by You only, You may use Original Contributor's class, +Interface and package names only to accurately reference or invoke the +Source Code files You modify. Original Contributor grants to You a +limited license to the extent necessary for such purposes. + +(iv) You expressly agree that any distribution, in whole or in part, of +Modifications developed by You shall only be done pursuant to the terms +and conditions of this License. + +(e) Extensions. + +(i) Covered Code. You may not include any Source Code of Community Code +in any Extensions. You may include the compiled Header Files of +Community Code in an Extension provided that Your use of the Covered +Code, including Heading Files, complies with the Commercial Use License, +the TCK and all other terms of this License. + +(ii) Publication. No later than the date on which You first distribute +such Extension for Commercial Use, You must publish to the industry, on +a non-confidential basis and free of all copyright restrictions with +respect to reproduction and use, an accurate and current specification +for any Extension. In addition, You must make available an appropriate +test suite, pursuant to the same rights as the specification, +sufficiently detailed to allow any third party reasonably skilled in the +technology to produce implementations of the Extension compatible with +the specification. Such test suites must be made available as soon as +reasonably practicable but, in no event, later than ninety (90) days +after Your first Commercial Use of the Extension. You must use +reasonable efforts to promptly clarify and correct the specification and +the test suite upon written request by Original Contributor. + +(iii) Open. You agree to refrain from enforcing any Intellectual +Property Rights You may have covering any interface(s) of Your +Extension, which would prevent the implementation of such interface(s) +by Original Contributor or any Licensee. This obligation does not +prevent You from enforcing any Intellectual Property Right You have that +would otherwise be infringed by an implementation of Your Extension. + +(iv) Interface Modifications and Naming. You may not modify or add to +the GUID space * * "xxxxxxxx-0901-11d1-8B06-00A024406D59" or any other +GUID space designated by Original Contributor. You may not modify any +Interface prefix provided with the Covered Code or any other prefix +designated by Original Contributor.* * + +* * + +(f) You agree that any Specifications provided to You by Original +Contributor are confidential and proprietary information of Original +Contributor. You must maintain the confidentiality of the Specifications +and may not disclose them to any third party without Original +Contributor's prior written consent. You may only use the Specifications +under the terms of this License and only for the purpose of implementing +the terms of this License with respect to Covered Code. You agree not +use, copy or distribute any such Specifications except as provided in +writing by Original Contributor. + +3.2 Commercial Use License. + +You may not make Commercial Use of any Covered Code unless You and +Original Contributor have executed a copy of the Commercial Use and +Trademark License attached as Attachment D. + +*4. Versions of the License.* + +4.1 License Versions. + +Original Contributor may publish revised versions of the License from +time to time. Each version will be given a distinguishing version number. + +4.2 Effect. + +Once a particular version of Covered Code has been provided under a +version of the License, You may always continue to use such Covered Code +under the terms of that version of the License. You may also choose to +use such Covered Code under the terms of any subsequent version of the +License. No one other than Original Contributor has the right to +promulgate License versions. + +4.3 Multiple-Licensed Code. + +Original Contributor may designate portions of the Covered Code as +"Multiple-Licensed." "Multiple-Licensed" means that the Original +Contributor permits You to utilize those designated portions of the +Covered Code under Your choice of this License or the alternative +license(s), if any, specified by the Original Contributor in an +Attachment to this License. + +*5. Disclaimer of Warranty.* + +5.1 COVERED CODE PROVIDED AS IS. + +COVERED CODE IS PROVIDED UNDER THIS LICENSE "AS IS," WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, +WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT +FOR A PARTICULAR PURPOSE OR NON-INFRINGING. YOU AGREE TO BEAR THE ENTIRE +RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF COVERED CODE UNDER +THIS LICENSE. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART +OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER +EXCEPT SUBJECT TO THIS DISCLAIMER. + +5.2 Not Designed for High Risk Activities. + +You acknowledge that Original Code, Upgraded Code and Specifications are +not designed or intended for use in high risk activities including, but +not limited to: (i) on-line control of aircraft, air traffic, aircraft +navigation or aircraft communications; or (ii) in the design, +construction, operation or maintenance of any nuclear facility. Original +Contributor disclaims any express or implied warranty of fitness for +such uses. + +*6. Termination.* + +6.1 By You. + +You may terminate this Research Use license at anytime by providing +written notice to Original Contributor. + +6.2 By Original Contributor. + +This License and the rights granted hereunder will terminate: + +(i) automatically if You fail to comply with the terms of this License +and fail to cure such breach within 30 days of receipt of written notice +of the breach; + +(ii) immediately in the event of circumstances specified in Sections 7.1 +and 8.4; or + +(iii) at Original Contributor's discretion upon any action initiated by +You (including by cross-claim or counter claim) alleging that use or +distribution by Original Contributor or any Licensee, of Original Code, +Upgraded Code, Error Corrections, Shared Modifications or Specifications +infringe a patent owned or controlled by You. + +6.3 Effective of Termination. + +Upon termination, You agree to discontinue use of and destroy all copies +of Covered Code in Your possession. All sublicenses to the Covered Code +which You have properly granted shall survive any termination of this +License. Provisions that, by their nature, should remain in effect +beyond the termination of this License shall survive including, without +limitation, Sections 2.2, 3, 5, 7 and 8. + +6.4 No Compensation. + +Each party waives and releases the other from any claim to compensation +or indemnity for permitted or lawful termination of the business +relationship established by this License. + +*7. Liability.* + +7.1 Infringement. Should any of the Original Code, Upgraded Code, TCK or +Specifications ("Materials") become the subject of a claim of +infringement, Original Contributor may, at its sole option, (i) attempt +to procure the rights necessary for You to continue using the Materials, +(ii) modify the Materials so that they are no longer infringing, or +(iii) terminate Your right to use the Materials, immediately upon +written notice, and refund to You the amount, if any, having then +actually been paid by You to Original Contributor for the Original Code, +Upgraded Code and TCK, depreciated on a straight line, five year basis. + +7.2 LIMITATION OF LIABILITY. TO THE FULL EXTENT ALLOWED BY APPLICABLE +LAW, ORIGINAL CONTRIBUTOR'S LIABILITY TO YOU FOR CLAIMS RELATING TO THIS +LICENSE, WHETHER FOR BREACH OR IN TORT, SHALL BE LIMITED TO ONE HUNDRED +PERCENT (100%) OF THE AMOUNT HAVING THEN ACTUALLY BEEN PAID BY YOU TO +ORIGINAL CONTRIBUTOR FOR ALL COPIES LICENSED HEREUNDER OF THE PARTICULAR +ITEMS GIVING RISE TO SUCH CLAIM, IF ANY, DURING THE TWELVE MONTHS +PRECEDING THE CLAIMED BREACH. IN NO EVENT WILL YOU (RELATIVE TO YOUR +SHARED MODIFICATIONS OR ERROR CORRECTIONS) OR ORIGINAL CONTRIBUTOR BE +LIABLE FOR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES IN CONNECTION WITH OR RISING OUT OF THIS LICENSE (INCLUDING, +WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR OTHER ECONOMIC +ADVANTAGE), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY, WHETHER IN +AN ACTION FOR CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE) +OR OTHERWISE, WHETHER OR NOT YOU OR ORIGINAL CONTRIBUTOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE AND NOTWITHSTANDING THE +FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. + +*8. Miscellaneous.* + +8.1 Trademark. + +You shall not use any Trademark unless You and Original Contributor +execute a copy of the Commercial Use and Trademark License Agreement +attached hereto as Attachment D. Except as expressly provided in the +License, You are granted no right, title or license to, or interest in, +any Trademarks. Whether or not You and Original Contributor enter into +the Trademark License, You agree not to (i) challenge Original +Contributor's ownership or use of Trademarks; (ii) attempt to register +any Trademarks, or any mark or logo substantially similar thereto; or +(iii) incorporate any Trademarks into Your own trademarks, product +names, service marks, company names, or domain names. + +8.2 Integration. + +This License represents the complete agreement concerning the subject +matter hereof. + +8.3 Assignment. + +Original Contributor may assign this License, and its rights and +obligations hereunder, in its sole discretion. You may assign the +Research Use portions of this License and the TCK license to a third +party upon prior written notice to Original Contributor (which may be +provided electronically via the Community Web-Server). You may not +assign the Commercial Use and Trademark license, the Add-On Technology +License, or the Add-On Technology Source Code Porting License, including +by way of merger (regardless of whether You are the surviving entity) or +acquisition, without Original Contributor's prior written consent. + +8.4 Severability. + +If any provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to make it +enforceable. Notwithstanding the foregoing, if You are prohibited by law +from fully and specifically complying with Sections 2.2 or 3, this +License will immediately terminate and You must immediately discontinue +any use of Covered Code. + +8.5 Governing Law. + +This License shall be governed by the laws of the United States and the +State of Washington, as applied to contracts entered into and to be +performed in Washington between Washington residents. The application of +the United Nations Convention on Contracts for the International Sale of +Goods is expressly excluded. You agree that the state and federal courts +located in Seattle, Washington have exclusive jurisdiction over any +claim relating to the License, including contract and tort claims. + +8.6 Dispute Resolution. + +a) Arbitration. Any dispute arising out of or relating to this License +shall be finally settled by arbitration as set out herein, except that +either party may bring any action, in a court of competent jurisdiction +(which jurisdiction shall be exclusive), with respect to any dispute +relating to such party's Intellectual Property Rights or with respect to +Your compliance with the TCK license. Arbitration shall be administered: +(i) by the American Arbitration Association (AAA), (ii) in accordance +with the rules of the United Nations Commission on International Trade +Law (UNCITRAL) (the "Rules") in effect at the time of arbitration as +modified herein; and (iii) the arbitrator will apply the substantive +laws of Washington and the United States. Judgment upon the award +rendered by the arbitrator may be entered in any court having +jurisdiction to enforce such award. + +b) Arbitration language, venue and damages. All arbitration proceedings +shall be conducted in English by a single arbitrator selected in +accordance with the Rules, who must be fluent in English and be either a +retired judge or practicing attorney having at least ten (10) years +litigation experience and be reasonably familiar with the technology +matters relative to the dispute. Unless otherwise agreed, arbitration +venue shall be in Seattle, Washington. The arbitrator may award monetary +damages only and nothing shall preclude either party from seeking +provisional or emergency relief from a court of competent jurisdiction. +The arbitrator shall have no authority to award damages in excess of +those permitted in this License and any such award in excess is void. +All awards will be payable in U.S. dollars and may include, for the +prevailing party (i) pre-judgment award interest, (ii) reasonable +attorneys' fees incurred in connection with the arbitration, and (iii) +reasonable costs and expenses incurred in enforcing the award. The +arbitrator will order each party to produce identified documents and +respond to no more than twenty-five single question interrogatories. + +8.7 Construction. + +Any law or regulation, which provides that the language of a contract +shall be construed against the drafter, shall not apply to this License. + +8.8 U.S. Government End Users. + +The Covered Code is a "commercial item," as that term is defined in 48 +C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" +and "commercial computer software documentation," as such terms are used +in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and +48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government +End Users acquire Covered Code with only those rights set forth herein. +You agree to pass this notice to our licensees. + +8.9 Marketing Activities. + +Licensee hereby grants Original Contributor a non-exclusive, +non-transferable, limited license to use the Licensee's company name and +logo ("Licensee Marks") in any presentations, press releases, or +marketing materials solely for the purpose of identifying Licensee as a +member of the Helix Community. Licensee shall provide samples of +Licensee Marks to Original Contributor upon request by Original +Contributor. Original Contributor acknowledges that the Licensee Marks +are the trademarks of Licensee. Original Contributor shall not use the +Licensee Marks in a way that may imply that Original Contributor is an +agency or branch of Licensee. Original Contributor understands and +agrees that the use of any Licensee Marks in connection with this +Agreement shall not create any right, title or interest, in, or to the +Licensee Marks or any Licensee trademarks and that all such use and +goodwill associated with any such trademarks will inure to the benefit +of Licensee. Further the Original Contributor will stop usage of the +Licensee Marks upon Licensee's request. + +8.10 Press Announcements. + +You may make press announcements or other public statements regarding +this License without the prior written consent of the Original +Contributor, if Your statement is limited to announcing the licensing of +the Covered Code or the availability of Your Product and its +compatibility with the Covered Code. All other public announcements +regarding this license require the prior written consent of the Original +Contributor. Consent requests are welcome at press@helixcommunity.org. + +8.11 International Use. + +a) Export/Import laws. Covered Code is subject to U.S. export control +laws and may be subject to export or import regulations in other +countries. Each party agrees to comply strictly with all such laws and +regulations and acknowledges their responsibility to obtain such +licenses to export, re-export, or import as may be required. You agree +to pass these obligations to Your licensees. + +b) Intellectual Property Protection. Due to limited intellectual +property protection and enforcement in certain countries, You agree not +to redistribute the Original Code, Upgraded Code, TCK and Specifications +to any country on the list of restricted countries on the Community Web +Server. + +8.12 Language. + +This License is in the English language only, which language shall be +controlling in all respects, and all versions of this License in any +other language shall be for accommodation only and shall not be binding +on the parties to this License. All communications and notices made or +given pursuant to this License, and all documentation and support to be +provided, unless otherwise noted, shall be in the English language. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH REALNETWORKS, INC. IF YOU ARE AGREEING +TO THIS LICENSE ON BEHALF OF A COMPANY, YOU REPRESENT THAT YOU ARE +AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. WHETHER YOU ARE ACTING +ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, YOU MUST BE OF MAJORITY +AGE AND BE OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. IF YOU DO NOT +MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY OF THE TERMS AND +CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON TO EXIT. + + + GLOSSARY + +1. *"Added Value"* means code which: + +(i) has a principal purpose which is substantially different from that +of the stand-alone Technology; + +(ii) represents a significant functional and value enhancement to the +Technology; + +(iii) operates in conjunction with the Technology; and + +(iv) is not marketed as a technology which replaces or substitutes for +the Technology + +2. "*Applicable Patent Rights*" mean: (a) in the case where Original +Contributor is the grantor of rights, claims of patents that (i) are now +or hereafter acquired, owned by or assigned to Original Contributor and +(ii) are necessarily infringed by using or making the Original Code or +Upgraded Code, including Modifications provided by Original Contributor, +alone and not in combination with other software or hardware; and (b) in +the case where Licensee is the grantor of rights, claims of patents that +(i) are now or hereafter acquired, owned by or assigned to Licensee and +(ii) are infringed (directly or indirectly) by using or making +Licensee's Modifications or Error Corrections, taken alone or in +combination with Covered Code. + +3. "*Application Programming Interfaces (APIs)"* means the interfaces, +associated header files, service provider interfaces, and protocols that +enable a device, application, Operating System, or other program to +obtain services from or make requests of (or provide services in +response to requests from) other programs, and to use, benefit from, or +rely on the resources, facilities, and capabilities of the relevant +programs using the APIs. APIs includes the technical documentation +describing the APIs, the Source Code constituting the API, and any +Header Files used with the APIs. + +4. "*Commercial Use*" means any use (internal or external), copying, +sublicensing or distribution (internal or external), directly or +indirectly of Covered Code by You other than Your Research Use of +Covered Code within Your business or organization or in conjunction with +other Licensees with equivalent Research Use rights. Commercial Use +includes any use of the Covered Code for direct or indirect commercial +or strategic gain, advantage or other business purpose. Any Commercial +Use requires execution of Attachment D by You and Original Contributor. + +5. "*Community Code*" means the Original Code, Upgraded Code, Error +Corrections, Shared Modifications, or any combination thereof. + +6. "*Community Webserver(s)"* means the webservers designated by +Original Contributor for access to the Original Code, Upgraded Code, TCK +and Specifications and for posting Error Corrections and Shared +Modifications. + +7. "*Compliant Covered Code*" means Covered Code that complies with the +requirements of the TCK. + +8. "*Contributor*" means each Licensee that creates or contributes to +the creation of any Error Correction or Shared Modification. + +9. "*Covered Code*" means the Original Code, Upgraded Code, +Modifications, or any combination thereof. + +10. "*Error Correction*" means any change made to Community Code which +conforms to the Specification and corrects the adverse effect of a +failure of Community Code to perform any function set forth in or +required by the Specifications. + +11. "*Executable*" means Covered Code that has been converted from +Source Code to the preferred form for execution by a computer or digital +processor (e.g. binary form). + +12. "*Extension(s)"* means any additional Interfaces developed by or for +You which: (i) are designed for use with the Technology; (ii) constitute +an API for a library of computing functions or services; and (iii) are +disclosed or otherwise made available to third party software developers +for the purpose of developing software which invokes such additional +Interfaces. The foregoing shall not apply to software developed by Your +subcontractors to be exclusively used by You. + +13. "*Header File(s)"* means that portion of the Source Code that +provides the names and types of member functions, data members, class +definitions, and interface definitions necessary to implement the APIs +for the Covered Code. Header Files include, files specifically +designated by Original Contributor as Header Files. Header Files do not +include the code necessary to implement the functionality underlying the +Interface. + +14. *"Helix DNA Server Technology"* means the program(s) that implement +the Helix Universal Server streaming engine for the Technology as +defined in the Specification. + +15. *"Helix DNA Client Technology"* means the Covered Code that +implements the RealOne Player engine as defined in the Specification. + +16. *"Helix DNA Producer Technology"* means the Covered Code that +implements the Helix Producer engine as defined in the Specification. + +17. *"Helix DNA Technology"* means the Helix DNA Server Technology, the +Helix DNA Client Technology, the Helix DNA Producer Technology and other +Helix technologies designated by Original Contributor. + +18. "*Intellectual Property Rights*" means worldwide statutory and +common law rights associated solely with (i) Applicable Patent Rights; +(ii) works of authorship including copyrights, copyright applications, +copyright registrations and "moral rights"; (iii) the protection of +trade and industrial secrets and confidential information; and (iv) +divisions, continuations, renewals, and re-issuances of the foregoing +now existing or acquired in the future. + +19. *"Interface*" means interfaces, functions, properties, class +definitions, APIs, Header Files, GUIDs, V-Tables, and/or protocols +allowing one piece of software, firmware or hardware to communicate or +interoperate with another piece of software, firmware or hardware. + +20. "*Internal Deployment Use*" means use of Compliant Covered Code +(excluding Research Use) within Your business or organization only by +Your employees and/or agents on behalf of Your business or organization, +but not to provide services, including content distribution, to third +parties, subject to execution of Attachment D by You and Original +Contributor, if required. + +21. "*Licensee*" means any party that has entered into and has in effect +a version of this License with Original Contributor. + +22. "*MIME type*" means a description of what type of media or other +content is in a file, including by way of example but not limited to +'audio/x-pn-realaudio-plugin.' + +23. "*Modification(s)"* means (i) any addition to, deletion from and/or +change to the substance and/or structure of the Covered Code, including +Interfaces; (ii) the combination of any Covered Code and any previous +Modifications; (iii) any new file or other representation of computer +program statements that contains any portion of Covered Code; and/or +(iv) any new Source Code implementing any portion of the Specifications. + +24. "*MP3 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Picture Experts Group known as MPEG-1 Audio Layer-3 or MP3, +including but not limited to all past and future versions, profiles, +extensions, parts and amendments relating to the MP3 specification. + +25. "*MPEG-4 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Pictures Experts Group known as MPEG-4, including but not +limited to all past and future versions, profiles, extensions, parts and +amendments relating to the MPEG-4 specification. + +26. "*Original Code*" means the initial Source Code for the Technology +as described on the Community Web Server. + +27. "*Original Contributor*" means RealNetworks, Inc., its affiliates +and its successors and assigns. + +28. "*Original Contributor MIME Type*" means the MIME registry, browser +preferences, or local file/protocol associations invoking any Helix DNA +Client-based application, including the RealOne Player, for playback of +RealAudio, RealVideo, other RealMedia MIME types or datatypes (e.g., +.ram, .rnx, .rpm, .ra, .rm, .rp, .rt, .rf, .prx, .mpe, .rmp, .rmj, .rav, +.rjs, .rmx, .rjt, .rms), and any other Original Contributor-specific or +proprietary MIME types that Original Contributor may introduce in the +future. + +29. "*Personal Use*" means use of Covered Code by an individual solely +for his or her personal, private and non-commercial purposes. An +individual's use of Covered Code in his or her capacity as an officer, +employee, member, independent contractor or agent of a corporation, +business or organization (commercial or non-commercial) does not qualify +as Personal Use. + +30. "*RealMedia File Format*" means the file format designed and +developed by RealNetworks for storing multimedia data and used to store +RealAudio and RealVideo encoded streams. Valid RealMedia File Format +extensions include: .rm, .rmj, .rmc, .rmvb, .rms. + +31. "*RCSL Webpage*" means the RealNetworks Community Source License +webpage located at https://www.helixcommunity.org/content/rcsl or such +other URL that Original Contributor may designate from time to time. + +32. "*Reformatted Specifications*" means any revision to the +Specifications which translates or reformats the Specifications (as for +example in connection with Your documentation) but which does not alter, +subset or superset * *the functional or operational aspects of the +Specifications. + +33. "*Research Use*" means use and distribution of Covered Code only for +Your Personal Use, research or development use and expressly excludes +Internal Deployment Use and Commercial Use. Research Use also includes +use of Covered Code to teach individuals how to use Covered Code. + +34. "*Shared Modifications*" means Modifications that You distribute or +use for a Commercial Use, in addition to any Modifications provided by +You, at Your option, pursuant to Section 2.2, or received by You from a +Contributor pursuant to Section 2.3. + +35. "*Source Code*" means the preferred form of the Covered Code for +making modifications to it, including all modules it contains, plus any +associated interface definition files, scripts used to control +compilation and installation of an Executable, or source code +differential comparisons against either the Original Code or another +well known, available Covered Code of the Contributor's choice. The +Source Code can be in a compressed or archival form, provided the +appropriate decompression or de-archiving software is widely available +for no charge. + +36. "*Specifications*" means the specifications for the Technology and +other documentation, as designated on the Community Web Server, as may +be revised by Original Contributor from time to time. + +37. "*Trademarks*" means Original Contributor's trademarks and logos, +including, but not limited to, RealNetworks, RealAudio, RealVideo, +RealOne, RealSystem, SureStream, Helix, Helix DNA and other trademarks +whether now used or adopted in the future. + +38. "*Technology*" means the technology described in Attachment B, and +Upgrades. + +39. "*Technology Compatibility Kit"* or *"TCK*" means the test programs, +procedures, acceptance criteria and/or other requirements, designated by +Original Contributor for use in verifying compliance of Covered Code +with the Specifications, in conjunction with the Original Code and +Upgraded Code. Original Contributor may, in its sole discretion and from +time to time, revise a TCK to correct errors and/or omissions and in +connection with Upgrades. + +40. "*Upgrade(s)"* means new versions of Technology designated +exclusively by Original Contributor as an "Upgrade" and released by +Original Contributor from time to time under the terms of the License. + +41. "*Upgraded Code*" means the Source Code and/or Executables for +Upgrades, possibly including Modifications made by Contributors. + +42. *"User's Guide"* means the users guide for the TCK which Original +Contributor makes available to You to provide direction in how to run +the TCK and properly interpret the results, as may be revised by +Original Contributor from time to time. + +43. "*You(r)*" means an individual, or a legal entity acting by and +through an individual or individuals, exercising rights either under +this License or under a future version of this License issued pursuant +to Section 4.1. For legal entities, "You(r)" includes any entity that by +majority voting interest controls, is controlled by, or is under common +control with You. + +44. "*Your Products*" means any (i) hardware products You distribute +integrating the Covered Code; (ii) any software products You distribute +with the Covered Code that utilize the APIs of the Covered Code; or +(iii) any services You provide using the Covered Code. + + + ATTACHMENT A + +REQUIRED NOTICES + + + ATTACHMENT A-1 + +REQUIRED IN ALL CASES + +Notice to be included in header file of all Error Corrections and Shared +Modifications: + +Portions Copyright 1994-2003 RealNetworks, Inc. All rights reserved. + +The contents of this file, and the files included with this file, are +subject to the current version of RealNetworks Community Source License +Version 1.1 (the "License"). You may not use this file except in +compliance with the License executed by both You and RealNetworks. You +may obtain a copy of the License at * +https://www.helixcommunity.org/content/rcsl.* You may also obtain a copy +of the License by contacting RealNetworks directly. Please see the +License for the rights, obligations and limitations governing use of the +contents of the file. + +This file is part of the Helix DNA technology. RealNetworks, Inc., is +the developer of the Original code and owns the copyrights in the +portions it created. + +This file, and the files included with this file, are distributed on an +'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, +AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): + +_______________________________________________ + +Technology Compatibility Kit Test Suite(s) Location: + +________________________________ + + + ATTACHMENT A-2 + +SAMPLE LICENSEE CERTIFICATION + +"By clicking the `Agree' button below, You certify that You are a +Licensee in good standing under the RealNetworks Community Source +License, ("License") and that Your access, use and distribution of code +and information You may obtain at this site is subject to the License. +If You are not a Licensee under the RealNetworks Community Source +License You agree not to download, copy or use the Helix DNA technology. + + + ATTACHMENT A-3 + +REQUIRED STUDENT NOTIFICATION + +"This software and related documentation has been obtained by Your +educational institution subject to the RealNetworks Community Source +License. You have been provided access to the software and related +documentation for use only in connection with your course work and +research activities as a matriculated student of Your educational +institution. Any other use is expressly prohibited. + +THIS SOFTWARE AND RELATED DOCUMENTATION CONTAINS PROPRIETARY MATERIAL OF +REALNETWORKS, INC, WHICH ARE PROTECTED BY VARIOUS INTELLECTUAL PROPERTY +RIGHTS. + +You may not use this file except in compliance with the License. You may +obtain a copy of the License on the web at +https://www.helixcommunity.org/content/rcsl. + +* +* + + + ATTACHMENT B + +Description of Technology + +Helix DNA, which consists of Helix DNA Client, Helix DNA Server and +Helix DNA Producer. + +Description of "Technology" + +Helix DNA Technology v1.0 as described on the Community Web Server. + + + ATTACHMENT C + +TECHNOLOGY COMPATIBILITY KIT LICENSE + +The following license is effective for the *Helix DNA* Technology +Compatibility Kit - as described on the Community Web Server. The +Technology Compatibility Kit(s) for the Technology specified in +Attachment B may be accessed at the Community Web Server. + +1. TCK License. + +1.1 Grants to use TCK + +Subject to the terms and restrictions set forth below and the +RealNetworks Community Source License, and the Research Use license, +Original Contributor grants to You a worldwide, non-exclusive, +non-transferable license, to the extent of Original Contributor's +Intellectual Property Rights in the TCK (without the right to +sublicense), to use the TCK to develop and test Covered Code. + +1.2 TCK Use Restrictions. + +You are not authorized to create derivative works of the TCK or use the +TCK to test any implementation of the Specification that is not Covered +Code. You may not publish Your test results or make claims of +comparative compatibility with respect to other implementations of the +Specification. In consideration for the license grant in Section 1.1 +above You agree not to develop Your own tests that are intended to +validate conformation with the Specification. + +2. Test Results. + +You agree to provide to Original Contributor or the third party test +facility if applicable, Your test results that demonstrate that Covered +Code is Compliant Covered Code and that Original Contributor may publish +or otherwise distribute such test results. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH THE ORIGINAL CONTRIBUTOR, REALNETWORKS, +INC. IF YOU ARE AGREEING TO THIS LICENSE ON BEHALF OF A COMPANY, YOU +REPRESENT THAT YOU ARE AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. +WHETHER YOU ARE ACTING ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, +YOU MUST BE OF MAJORITY AGE AND BE OTHERWISE COMPETENT TO ENTER INTO +CONTRACTS. IF YOU DO NOT MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY +OF THE TERMS AND CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON +TO EXIT. + +*ACCEPT / REJECT +* + +* +* + +*To agree to the R&D/academic terms of this license, please register + on the site -- +you will then be given a chance to agree to the clickwrap RCSL + +R&D License + +and gain access to the RCSL-licensed source code. To build or deploy +commercial applications based on the RCSL, you will need to agree to the +Commercial Use license attachments +* + + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/RPSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/RPSL.txt new file mode 100644 index 0000000..d040a45 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/RPSL.txt @@ -0,0 +1,518 @@ +RealNetworks Public Source License Version 1.0 +(Rev. Date October 28, 2002) + +1. General Definitions. This License applies to any program or other work which +RealNetworks, Inc., or any other entity that elects to use this license, +("Licensor") makes publicly available and which contains a notice placed by +Licensor identifying such program or work as "Original Code" and stating that it +is subject to the terms of this RealNetworks Public Source License version 1.0 +(or subsequent version thereof) ("License"). You are not required to accept this +License. However, nothing else grants You permission to use, copy, modify or +distribute the software or its derivative works. These actions are prohibited by +law if You do not accept this License. Therefore, by modifying, copying or +distributing the software (or any work based on the software), You indicate your +acceptance of this License to do so, and all its terms and conditions. In +addition, you agree to the terms of this License by clicking the Accept button +or downloading the software. As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Licensor is the +grantor of rights, claims of patents that (i) are now or hereafter acquired, +owned by or assigned to Licensor and (ii) are necessarily infringed by using or +making the Original Code alone and not in combination with other software or +hardware; and (b) in the case where You are the grantor of rights, claims of +patents that (i) are now or hereafter acquired, owned by or assigned to You and +(ii) are infringed (directly or indirectly) by using or making Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Compatible Source License" means any one of the licenses listed on Exhibit +B or at https://www.helixcommunity.org/content/complicense or other licenses +specifically identified by Licensor in writing. Notwithstanding any term to the +contrary in any Compatible Source License, any code covered by any Compatible +Source License that is used with Covered Code must be made readily available in +Source Code format for royalty-free use under the terms of the Compatible Source +License or this License. + +1.3 "Contributor" means any person or entity that creates or contributes to the +creation of Modifications. + +1.4 "Covered Code" means the Original Code, Modifications, the combination of +Original Code and any Modifications, and/or any respective portions thereof. + +1.5 "Deploy" means to use, sublicense or distribute Covered Code other than for +Your internal research and development (R&D) and/or Personal Use, and includes +without limitation, any and all internal use or distribution of Covered Code +within Your business or organization except for R&D use and/or Personal Use, as +well as direct or indirect sublicensing or distribution of Covered Code by You +to any third party in any form or manner. + +1.6 "Derivative Work" means either the Covered Code or any derivative work under +United States copyright law, and including any work containing or including any +portion of the Covered Code or Modifications, either verbatim or with +modifications and/or translated into another language. Derivative Work also +includes any work which combines any portion of Covered Code or Modifications +with code not otherwise governed by the terms of this License. + +1.7 "Externally Deploy" means to Deploy the Covered Code in any way that may be +accessed or used by anyone other than You, used to provide any services to +anyone other than You, or used in any way to deliver any content to anyone other +than You, whether the Covered Code is distributed to those parties, made +available as an application intended for use over a computer network, or used to +provide services or otherwise deliver content to anyone other than You. + +1.8. "Interface" means interfaces, functions, properties, class definitions, +APIs, header files, GUIDs, V-Tables, and/or protocols allowing one piece of +software, firmware or hardware to communicate or interoperate with another piece +of software, firmware or hardware. + +1.9 "Modifications" mean any addition to, deletion from, and/or change to, the +substance and/or structure of the Original Code, any previous Modifications, the +combination of Original Code and any previous Modifications, and/or any +respective portions thereof. When code is released as a series of files, a +Modification is: (a) any addition to or deletion from the contents of a file +containing Covered Code; and/or (b) any new file or other representation of +computer program statements that contains any part of Covered Code. + +1.10 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Licensor under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Licensor under this License, and that has been expressly identified by Licensor +as such in the header file(s) of such work; and (b) the object code compiled +from such Source Code and originally made available by Licensor under this +License. + +1.11 "Personal Use" means use of Covered Code by an individual solely for his or +her personal, private and non-commercial purposes. An individual's use of +Covered Code in his or her capacity as an officer, employee, member, independent +contractor or agent of a corporation, business or organization (commercial or +non-commercial) does not qualify as Personal Use. + +1.12 "Source Code" means the human readable form of a program or other work that +is suitable for making modifications to it, including all modules it contains, +plus any associated interface definition files, scripts used to control +compilation and installation of an executable (object code). + +1.13 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership of +fifty percent (50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Licensor hereby grants You, effective on the date +You accept this License (via downloading or using Covered Code or otherwise +indicating your acceptance of this License), a worldwide, royalty-free, +non-exclusive copyright license, to the extent of Licensor's copyrights cover +the Original Code, to do the following: + +2.1 You may reproduce, display, perform, modify and Deploy Covered Code, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the copyright +and other proprietary notices and disclaimers of Licensor as they appear in the +Original Code, and keep intact all notices in the Original Code that refer to +this License; + +(b) You must include a copy of this License with every copy of Source Code of +Covered Code and documentation You distribute, and You may not offer or impose +any terms on such Source Code that alter or restrict this License or the +recipients' rights hereunder, except as permitted under Section 6; + +(c) You must duplicate, to the extent it does not already exist, the notice in +Exhibit A in each file of the Source Code of all Your Modifications, and cause +the modified files to carry prominent notices stating that You changed the files +and the date of any change; + +(d) You must make Source Code of all Your Externally Deployed Modifications +publicly available under the terms of this License, including the license grants +set forth in Section 3 below, for as long as you Deploy the Covered Code or +twelve (12) months from the date of initial Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Deployed Modifications +electronically (e.g. download from a web site); and + +(e) if You Deploy Covered Code in object code, executable form only, You must +include a prominent notice, in the code itself as well as in related +documentation, stating that Source Code of the Covered Code is available under +the terms of this License with information on how and where to obtain such +Source Code. You must also include the Object Code Notice set forth in Exhibit A +in the "about" box or other appropriate place where other copyright notices are +placed, including any packaging materials. + +2.2 You expressly acknowledge and agree that although Licensor and each +Contributor grants the licenses to their respective portions of the Covered Code +set forth herein, no assurances are provided by Licensor or any Contributor that +the Covered Code does not infringe the patent or other intellectual property +rights of any other entity. Licensor and each Contributor disclaim any liability +to You for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, You hereby assume sole responsibility to +secure any other intellectual property rights needed, if any. For example, if a +third party patent license is required to allow You to make, use, sell, import +or offer for sale the Covered Code, it is Your responsibility to acquire such +license(s). + +2.3 Subject to the terms and conditions of this License, Licensor hereby grants +You, effective on the date You accept this License (via downloading or using +Covered Code or otherwise indicating your acceptance of this License), a +worldwide, royalty-free, perpetual, non-exclusive patent license under +Licensor's Applicable Patent Rights to make, use, sell, offer for sale and +import the Covered Code, provided that in each instance you comply with the +terms of this License. + +3. Your Grants. In consideration of, and as a condition to, the licenses granted +to You under this License: + +(a) You grant to Licensor and all third parties a non-exclusive, perpetual, +irrevocable, royalty free license under Your Applicable Patent Rights and other +intellectual property rights owned or controlled by You, to make, sell, offer +for sale, use, import, reproduce, display, perform, modify, distribute and +Deploy Your Modifications of the same scope and extent as Licensor's licenses +under Sections 2.1 and 2.2; and + +(b) You grant to Licensor and its subsidiaries a non-exclusive, worldwide, +royalty-free, perpetual and irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights owned or controlled by You, to +make, use, sell, offer for sale, import, reproduce, display, perform, +distribute, modify or have modified (for Licensor and/or its subsidiaries), +sublicense and distribute Your Modifications, in any form and for any purpose, +through multiple tiers of distribution. + +(c) You agree not use any information derived from Your use and review of the +Covered Code, including but not limited to any algorithms or inventions that may +be contained in the Covered Code, for the purpose of asserting any of Your +patent rights, or assisting a third party to assert any of its patent rights, +against Licensor or any Contributor. + +4. Derivative Works. You may create a Derivative Work by combining Covered Code +with other code not otherwise governed by the terms of this License and +distribute the Derivative Work as an integrated product. In each such instance, +You must make sure the requirements of this License are fulfilled for the +Covered Code or any portion thereof, including all Modifications. + +4.1 You must cause any Derivative Work that you distribute, publish or +Externally Deploy, that in whole or in part contains or is derived from the +Covered Code or any part thereof, to be licensed as a whole at no charge to all +third parties under the terms of this License and no other license except as +provided in Section 4.2. You also must make Source Code available for the +Derivative Work under the same terms as Modifications, described in Sections 2 +and 3, above. + +4.2 Compatible Source Licenses. Software modules that have been independently +developed without any use of Covered Code and which contain no portion of the +Covered Code, Modifications or other Derivative Works, but are used or combined +in any way wtih the Covered Code or any Derivative Work to form a larger +Derivative Work, are exempt from the conditions described in Section 4.1 but +only to the extent that: the software module, including any software that is +linked to, integrated with, or part of the same applications as, the software +module by any method must be wholly subject to one of the Compatible Source +Licenses. Notwithstanding the foregoing, all Covered Code must be subject to the +terms of this License. Thus, the entire Derivative Work must be licensed under a +combination of the RPSL (for Covered Code) and a Compatible Source License for +any independently developed software modules within the Derivative Work. The +foregoing requirement applies even if the Compatible Source License would +ordinarily allow the software module to link with, or form larger works with, +other software that is not subject to the Compatible Source License. For +example, although the Mozilla Public License v1.1 allows Mozilla code to be +combined with proprietary software that is not subject to the MPL, if +MPL-licensed code is used with Covered Code the MPL-licensed code could not be +combined or linked with any code not governed by the MPL. The general intent of +this section 4.2 is to enable use of Covered Code with applications that are +wholly subject to an acceptable open source license. You are responsible for +determining whether your use of software with Covered Code is allowed under Your +license to such software. + +4.3 Mere aggregation of another work not based on the Covered Code with the +Covered Code (or with a work based on the Covered Code) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. If You deliver the Covered Code for combination and/or integration with +an application previously provided by You (for example, via automatic updating +technology), such combination and/or integration constitutes a Derivative Work +subject to the terms of this License. + +5. Exclusions From License Grant. Nothing in this License shall be deemed to +grant any rights to trademarks, copyrights, patents, trade secrets or any other +intellectual property of Licensor or any Contributor except as expressly stated +herein. No right is granted to the trademarks of Licensor or any Contributor +even if such marks are included in the Covered Code. Nothing in this License +shall be interpreted to prohibit Licensor from licensing under different terms +from this License any code that Licensor otherwise would have a right to +license. Modifications, Derivative Works and/or any use or combination of +Covered Code with other technology provided by Licensor or third parties may +require additional patent licenses from Licensor which Licensor may grant in its +sole discretion. No patent license is granted separate from the Original Code or +combinations of the Original Code with other software or hardware. + +5.1. Trademarks. This License does not grant any rights to use the trademarks or +trade names owned by Licensor ("Licensor Marks" defined in Exhibit C) or to any +trademark or trade name belonging to any Contributor. No Licensor Marks may be +used to endorse or promote products derived from the Original Code other than as +permitted by the Licensor Trademark Policy defined in Exhibit C. + +6. Additional Terms. You may choose to offer, and to charge a fee for, warranty, +support, indemnity or liability obligations and/or other rights consistent with +the scope of the license granted herein ("Additional Terms") to one or more +recipients of Covered Code. However, You may do so only on Your own behalf and +as Your sole responsibility, and not on behalf of Licensor or any Contributor. +You must obtain the recipient's agreement that any such Additional Terms are +offered by You alone, and You hereby agree to indemnify, defend and hold +Licensor and every Contributor harmless for any liability incurred by or claims +asserted against Licensor or such Contributor by reason of any such Additional +Terms. + +7. Versions of the License. Licensor may publish revised and/or new versions of +this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular version +of this License, You may continue to use it under the terms of that version. You +may also choose to use such Original Code under the terms of any subsequent +version of this License published by Licensor. No one other than Licensor has +the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in part +pre-release, untested, or not fully tested works. The Covered Code may contain +errors that could cause failures or loss of data, and may be incomplete or +contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND LICENSOR AND LICENSOR'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS +"LICENSOR" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY +DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET +ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. LICENSOR AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN DOCUMENTATION, INFORMATION OR ADVICE GIVEN BY LICENSOR, A LICENSOR +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You +acknowledge that the Covered Code is not intended for use in high risk +activities, including, but not limited to, the design, construction, operation +or maintenance of nuclear facilities, aircraft navigation, aircraft +communication systems, or air traffic control machines in which case the failure +of the Covered Code could lead to death, personal injury, or severe physical or +environmental damage. Licensor disclaims any express or implied warranty of +fitness for such uses. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT +SHALL LICENSOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR STRICT +LIABILITY), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF LICENSOR OR SUCH +CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND +NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. SOME +JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF INCIDENTAL OR +CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event +shall Licensor's total liability to You for all damages (other than as may be +required by applicable law) under this License exceed the amount of ten dollars +($10.00). + +10. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Licensor retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Licensor +("Licensor Modifications"), and such Licensor Modifications will not be +automatically subject to this License. Licensor may, at its sole discretion, +choose to license such Licensor Modifications under this License, or on +different terms from those contained in this License or may choose not to +license them at all. + +11. Termination. + +11.1 Term and Termination. The term of this License is perpetual unless +terminated as provided below. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Licensor if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; + +(b) immediately in the event of the circumstances described in Section 12.5(b); +or + +(c) automatically without notice from Licensor if You, at any time during the +term of this License, commence an action for patent infringement against +Licensor (including by cross-claim or counter claim in a lawsuit); + +(d) upon written notice from Licensor if You, at any time during the term of +this License, commence an action for patent infringement against any third party +alleging that the Covered Code itself (excluding combinations with other +software or hardware) infringes any patent (including by cross-claim or counter +claim in a lawsuit). + +11.2 Effect of Termination. Upon termination, You agree to immediately stop any +further use, reproduction, modification, sublicensing and distribution of the +Covered Code and to destroy all copies of the Covered Code that are in your +possession or control. All sublicenses to the Covered Code which have been +properly granted prior to termination shall survive any termination of this +License. Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to Sections +3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other for +compensation, indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this License will +be without prejudice to any other right or remedy of any party. + +12. Miscellaneous. + +12.1 Government End Users. The Covered Code is a "commercial item" as defined in +FAR 2.101. Government software and technical data rights in the Covered Code +include only those rights customarily provided to the public as defined in this +License. This customary commercial license in technical data and software is +provided in accordance with FAR 12.211 (Technical Data) and 12.212 (Computer +Software) and, for Department of Defense purchases, DFAR 252.227-7015 (Technical +Data -- Commercial Items) and 227.7202-3 (Rights in Commercial Computer Software +or Computer Software Documentation). Accordingly, all U.S. Government End Users +acquire Covered Code with only those rights set forth herein. + +12.2 Relationship of Parties. This License will not be construed as creating an +agency, partnership, joint venture or any other form of legal association +between or among You, Licensor or any Contributor, and You will not represent to +the contrary, whether expressly, by implication, appearance or otherwise. + +12.3 Independent Development. Nothing in this License will impair Licensor's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions as, +or otherwise compete with, Modifications, Derivative Works, technology or +products that You may develop, produce, market or distribute. + +12.4 Waiver; Construction. Failure by Licensor or any Contributor to enforce any +provision of this License will not be deemed a waiver of future enforcement of +that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +12.5 Severability. (a) If for any reason a court of competent jurisdiction finds +any provision of this License, or portion thereof, to be unenforceable, that +provision of the License will be enforced to the maximum extent permissible so +as to effect the economic benefits and intent of the parties, and the remainder +of this License will continue in full force and effect. (b) Notwithstanding the +foregoing, if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the enforceability +of either of those Sections, this License will immediately terminate and You +must immediately discontinue any use of the Covered Code and destroy all copies +of it that are in your possession or control. + +12.6 Dispute Resolution. Any litigation or other dispute resolution between You +and Licensor relating to this License shall take place in the Seattle, +Washington, and You and Licensor hereby consent to the personal jurisdiction of, +and venue in, the state and federal courts within that District with respect to +this License. The application of the United Nations Convention on Contracts for +the International Sale of Goods is expressly excluded. + +12.7 Export/Import Laws. This software is subject to all export and import laws +and restrictions and regulations of the country in which you receive the Covered +Code and You are solely responsible for ensuring that You do not export, +re-export or import the Covered Code or any direct product thereof in violation +of any such restrictions, laws or regulations, or without all necessary +authorizations. + +12.8 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +Washington. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé +que le présent contrat et tous les documents connexes soient +rédigés en anglais. + + EXHIBIT A. + +"Copyright © 1995-2002 +RealNetworks, Inc. and/or its licensors. All Rights Reserved. + +The contents of this file, and the files included with this file, are subject to +the current version of the RealNetworks Public Source License Version 1.0 (the +"RPSL") available at https://www.helixcommunity.org/content/rpsl unless you have +licensed the file under the RealNetworks Community Source License Version 1.0 +(the "RCSL") available at https://www.helixcommunity.org/content/rcsl, in which +case the RCSL will apply. You may also obtain the license terms directly from +RealNetworks. You may not use this file except in compliance with the RPSL or, +if you have a valid RCSL with RealNetworks applicable to this file, the RCSL. +Please see the applicable RPSL or RCSL for the rights, obligations and +limitations governing use of the contents of the file. + +This file is part of the Helix DNA Technology. RealNetworks is the developer of +the Original code and owns the copyrights in the portions it created. + +This file, and the files included with this file, is distributed and made +available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR +IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING +WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): ____________________________________ + +Technology Compatibility Kit Test +Suite(s) Location (if licensed under the RCSL): ______________________________ + +Object Code Notice: Helix DNA Client technology included. Copyright (c) +RealNetworks, Inc., 1995-2002. All rights reserved. + + + EXHIBIT B + +Compatible Source Licenses for the RealNetworks Public Source License. The +following list applies to the most recent version of the license as of October +25, 2002, unless otherwise indicated. + +* Academic Free License +* Apache Software License +* Apple Public Source License +* Artistic license +* Attribution Assurance Licenses +* BSD license +* Common Public License (1) +* Eiffel Forum License +* GNU General Public License (GPL) (1) +* GNU Library or "Lesser" General Public License (LGPL) (1) +* IBM Public License +* Intel Open Source License +* Jabber Open Source License +* MIT license +* MITRE Collaborative Virtual Workspace License (CVW License) +* Motosoto License +* Mozilla Public License 1.0 (MPL) +* Mozilla Public License 1.1 (MPL) +* Nokia Open Source License +* Open Group Test Suite License +* Python Software Foundation License +* Ricoh Source Code Public License +* Sun Industry Standards Source License (SISSL) +* Sun Public License +* University of Illinois/NCSA Open Source License +* Vovida Software License v. 1.0 +* W3C License +* X.Net License +* Zope Public License +* zlib/libpng license + +(1) Note: because this license contains certain reciprocal licensing terms that +purport to extend to independently developed code, You may be prohibited under +the terms of this otherwise compatible license from using code licensed under +its terms with Covered Code because Covered Code may only be licensed under the +RealNetworks Public Source License. Any attempt to apply non RPSL license terms, +including without limitation the GPL, to Covered Code is expressly forbidden. +You are responsible for ensuring that Your use of Compatible Source Licensed +code does not violate either the RPSL or the Compatible Source License. + +The latest version of this list can be found at: +https://www.helixcommunity.org/content/complicense + + EXHIBIT C + +RealNetworks' Trademark policy. + +RealNetworks defines the following trademarks collectively as "Licensor +Trademarks": "RealNetworks", "RealPlayer", "RealJukebox", "RealSystem", +"RealAudio", "RealVideo", "RealOne Player", "RealMedia", "Helix" or any other +trademarks or trade names belonging to RealNetworks. + +RealNetworks "Licensor Trademark Policy" forbids any use of Licensor Trademarks +except as permitted by and in strict compliance at all times with RealNetworks' +third party trademark usage guidelines which are posted at +http://www.realnetworks.com/info/helixlogo.html. + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/mp3dec.vcp b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/mp3dec.vcp new file mode 100644 index 0000000..b0d942d --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/mp3dec.vcp @@ -0,0 +1,335 @@ +# Microsoft eMbedded Visual Tools Project File - Name="mp3dec" - Package Owner=<4> +# Microsoft eMbedded Visual Tools Generated Build File, Format Version 6.02 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (WCE ARM) Static Library" 0x8504 + +CFG=mp3dec - Win32 (WCE ARM) Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mp3dec.vcn". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mp3dec.vcn" CFG="mp3dec - Win32 (WCE ARM) Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mp3dec - Win32 (WCE ARM) Release" (based on "Win32 (WCE ARM) Static Library") +!MESSAGE "mp3dec - Win32 (WCE ARM) Debug" (based on "Win32 (WCE ARM) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +# PROP ATL_Project 2 +CPP=xicle3 + +!IF "$(CFG)" == "mp3dec - Win32 (WCE ARM) Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ARMRel" +# PROP BASE Intermediate_Dir "ARMRel" +# PROP BASE CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}" +# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ARMRel" +# PROP Intermediate_Dir "ARMRel_obj" +# PROP CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}" +# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "NDEBUG" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /YX /Oxs /M$(CECrtMT) /c +# ADD CPP /nologo /W3 /Zi /O2 /I "..\..\..\..\..\..\..\common\runtime\pub" /I "..\..\..\..\..\..\..\common\include" /I "..\..\..\pub" /D "NDEBUG" /D "_WINDOWS" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /Oxs /M$(CECrtMT) /c +# SUBTRACT CPP /YX +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo + +!ELSEIF "$(CFG)" == "mp3dec - Win32 (WCE ARM) Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ARMDbg" +# PROP BASE Intermediate_Dir "ARMDbg" +# PROP BASE CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}" +# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "ARMDbg" +# PROP Intermediate_Dir "ARMDbg" +# PROP CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}" +# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /YX /M$(CECrtMTDebug) /c +# ADD CPP /nologo /W3 /Zi /Od /I "..\..\..\pub" /I "..\..\..\..\..\..\..\common\runtime\pub" /I "..\..\..\..\..\..\..\common\include" /D "DEBUG" /D "_WINDOWS" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_LIB" /M$(CECrtMTDebug) /c +# SUBTRACT CPP /YX +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo + +!ENDIF + +# Begin Target + +# Name "mp3dec - Win32 (WCE ARM) Release" +# Name "mp3dec - Win32 (WCE ARM) Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "general" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\mp3dec.c +DEP_CPP_MP3DE=\ + "..\..\..\..\..\..\..\common\include\hxbastsd.h"\ + "..\..\..\..\..\..\..\common\include\hxtypes.h"\ + "..\..\..\..\..\..\..\common\include\platform\symbian\symbiantypes.h"\ + "..\..\..\..\..\..\..\common\runtime\pub\hlxclib\stdlib.h"\ + "..\..\..\..\..\..\..\common\runtime\pub\hlxclib\string.h"\ + "..\..\..\..\..\..\..\common\runtime\pub\platform\openwave\hx_op_stdc.h"\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + +NODEP_CPP_MP3DE=\ + "..\..\..\..\..\..\..\common\include\types\vxTypesOld.h"\ + "..\..\..\..\..\..\..\common\include\vxWorks.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\mp3tabs.c +DEP_CPP_MP3TA=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + +# End Source File +# End Group +# Begin Group "csource" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\bitstream.c +DEP_CPP_BITST=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\assembly.h"\ + "..\..\coder.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\buffers.c +DEP_CPP_BUFFE=\ + "..\..\..\..\..\..\..\common\include\hxbastsd.h"\ + "..\..\..\..\..\..\..\common\include\hxtypes.h"\ + "..\..\..\..\..\..\..\common\include\platform\symbian\symbiantypes.h"\ + "..\..\..\..\..\..\..\common\runtime\pub\hlxclib\stdlib.h"\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\coder.h"\ + +NODEP_CPP_BUFFE=\ + "..\..\..\..\..\..\..\common\include\types\vxTypesOld.h"\ + "..\..\..\..\..\..\..\common\include\vxWorks.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\dct32.c +DEP_CPP_DCT32=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\assembly.h"\ + "..\..\coder.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\dequant.c +DEP_CPP_DEQUA=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\assembly.h"\ + "..\..\coder.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\dqchan.c +DEP_CPP_DQCHA=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\assembly.h"\ + "..\..\coder.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\huffman.c +DEP_CPP_HUFFM=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\coder.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\hufftabs.c +DEP_CPP_HUFFT=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\coder.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\imdct.c +DEP_CPP_IMDCT=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\assembly.h"\ + "..\..\coder.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\scalfact.c +DEP_CPP_SCALF=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\coder.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\stproc.c +DEP_CPP_STPRO=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\assembly.h"\ + "..\..\coder.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\subband.c +DEP_CPP_SUBBA=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\assembly.h"\ + "..\..\coder.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\trigtabs.c +DEP_CPP_TRIGT=\ + "..\..\..\pub\mp3common.h"\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\statname.h"\ + "..\..\coder.h"\ + +# End Source File +# End Group +# Begin Group "assembly" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\arm\asmmisc.s + +!IF "$(CFG)" == "mp3dec - Win32 (WCE ARM) Release" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build - Performing Custom Build Step on $(InputPath) +IntDir=.\ARMRel_obj +InputPath=..\..\arm\asmmisc.s +InputName=asmmisc + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + "$(EVCROOT)\wce300\bin\armasm" $(InputPath) $(IntDir)\$(InputName).obj + +# End Custom Build + +!ELSEIF "$(CFG)" == "mp3dec - Win32 (WCE ARM) Debug" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build - Performing Custom Build Step on $(InputPath) +IntDir=.\ARMDbg +InputPath=..\..\arm\asmmisc.s +InputName=asmmisc + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + "$(EVCROOT)\wce300\bin\armasm" $(InputPath) $(IntDir)\$(InputName).obj + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\arm\asmpoly.s + +!IF "$(CFG)" == "mp3dec - Win32 (WCE ARM) Release" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build +IntDir=.\ARMRel_obj +InputPath=..\..\arm\asmpoly.s +InputName=asmpoly + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + "$(EVCROOT)\wce300\bin\armasm" $(InputPath) $(IntDir)\$(InputName).obj + +# End Custom Build + +!ELSEIF "$(CFG)" == "mp3dec - Win32 (WCE ARM) Debug" + +# PROP Ignore_Default_Tool 1 +# Begin Custom Build +IntDir=.\ARMDbg +InputPath=..\..\arm\asmpoly.s +InputName=asmpoly + +"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + "$(EVCROOT)\wce300\bin\armasm" $(InputPath) $(IntDir)\$(InputName).obj + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/mp3dec.vcw b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/mp3dec.vcw new file mode 100644 index 0000000..82b2baf --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/mp3dec.vcw @@ -0,0 +1,44 @@ +Microsoft eMbedded Visual Tools Workspace File, Format Version 3.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "mp3dec"=.\mp3dec.vcp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "testwrap"=.\testwrap.vcp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name mp3dec + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/testwrap.vcp b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/testwrap.vcp new file mode 100644 index 0000000..5b36680 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/armwince/testwrap.vcp @@ -0,0 +1,146 @@ +# Microsoft eMbedded Visual Tools Project File - Name="testwrap" - Package Owner=<4> +# Microsoft eMbedded Visual Tools Generated Build File, Format Version 6.02 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (WCE ARM) Application" 0x8501 + +CFG=testwrap - Win32 (WCE ARM) Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "testwrap.vcn". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "testwrap.vcn" CFG="testwrap - Win32 (WCE ARM) Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "testwrap - Win32 (WCE ARM) Release" (based on "Win32 (WCE ARM) Application") +!MESSAGE "testwrap - Win32 (WCE ARM) Debug" (based on "Win32 (WCE ARM) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +# PROP ATL_Project 2 +CPP=xicle3 +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "testwrap - Win32 (WCE ARM) Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ARMRel" +# PROP BASE Intermediate_Dir "ARMRel" +# PROP BASE CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}" +# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ARMRel" +# PROP Intermediate_Dir "ARMRel" +# PROP CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}" +# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /r +# ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /r +# ADD BASE CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /YX /Oxs /M$(CECrtMT) /c +# ADD CPP /nologo /W3 /Zi /O2 /I "..\..\..\pub" /I "..\..\..\testwrap" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /YX /Oxs /M$(CECrtMT) /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilinke3 +# ADD BASE LINK32 commctrl.lib coredll.lib aygshell.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"WinMainCRTStartup" /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM +# ADD LINK32 commctrl.lib coredll.lib aygshell.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"WinMainCRTStartup" /debug /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM + +!ELSEIF "$(CFG)" == "testwrap - Win32 (WCE ARM) Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ARMDbg" +# PROP BASE Intermediate_Dir "ARMDbg" +# PROP BASE CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}" +# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "ARMDbg" +# PROP Intermediate_Dir "ARMDbg" +# PROP CPU_ID "{D6518FFC-710F-11D3-99F2-00105A0DF099}" +# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" +# PROP Target_Dir "" +# ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /r +# ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /r +# ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /YX /M$(CECrtMTDebug) /c +# ADD CPP /nologo /W3 /Zi /Od /I "..\..\..\pub" /I "..\..\..\testwrap" /D "DEBUG" /D "ARM" /D "_ARM_" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /YX /M$(CECrtMTDebug) /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilinke3 +# ADD BASE LINK32 commctrl.lib coredll.lib aygshell.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"WinMainCRTStartup" /debug /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM +# ADD LINK32 commctrl.lib coredll.lib aygshell.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"WinMainCRTStartup" /debug /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM + +!ENDIF + +# Begin Target + +# Name "testwrap - Win32 (WCE ARM) Release" +# Name "testwrap - Win32 (WCE ARM) Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\..\testwrap\debug.c +DEP_CPP_DEBUG=\ + "..\..\..\testwrap\debug.h"\ + +NODEP_CPP_DEBUG=\ + "..\..\..\testwrap\fortify.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\mpadecobj.cpp +DEP_CPP_MPADE=\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\mpadecobjfixpt.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\testwrap\timing.c +DEP_CPP_TIMIN=\ + "..\..\..\testwrap\timing.h"\ + +# End Source File +# Begin Source File + +SOURCE=..\..\..\testwrap\winmain.cpp +DEP_CPP_WINMA=\ + "..\..\..\pub\mp3dec.h"\ + "..\..\..\pub\mpadecobjfixpt.h"\ + "..\..\..\testwrap\debug.h"\ + "..\..\..\testwrap\timing.h"\ + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/LICENSE.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/LICENSE.txt new file mode 100644 index 0000000..12e5372 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/LICENSE.txt @@ -0,0 +1,30 @@ + Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. + + The contents of this directory, and (except where otherwise + indicated) the directories included within this directory, are + subject to the current version of the RealNetworks Public Source + License (the "RPSL") available at RPSL.txt in this directory, unless + you have licensed the directory under the current version of the + RealNetworks Community Source License (the "RCSL") available at + RCSL.txt in this directory, in which case the RCSL will apply. You + may also obtain the license terms directly from RealNetworks. You + may not use the files in this directory except in compliance with the + RPSL or, if you have a valid RCSL with RealNetworks applicable to + this directory, the RCSL. Please see the applicable RPSL or RCSL for + the rights, obligations and limitations governing use of the contents + of the directory. + + This directory is part of the Helix DNA Technology. RealNetworks is + the developer of the Original Code and owns the copyrights in the + portions it created. + + This directory, and the directories included with this directory, are + distributed and made available on an 'AS IS' basis, WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY + DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, + QUIET ENJOYMENT OR NON-INFRINGEMENT. + + Technology Compatibility Kit Test Suite(s) Location: + http://www.helixcommunity.org/content/tck + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/RCSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/RCSL.txt new file mode 100644 index 0000000..a809759 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/RCSL.txt @@ -0,0 +1,948 @@ +The RCSL is made up of a base agreement and a few Attachments. + +For Research and Development use, you agree to the terms of the +RCSL R&D License (base RCSL and Attachments A, B, and C) + +For Commercial Use (either distribution or internal commercial +deployment) of the Helix DNA with or without support for RealNetworks' +RealAudio and RealVideo Add-on Technology, you agree to the +terms of the same RCSL R&D license +and execute one or more additional Commercial Use License attachments +. + +------------------------------------------------------------------------ + + + REALNETWORKS COMMUNITY SOURCE LICENSE + +Version 1.2 (Rev. Date: January 22, 2003). + + + RECITALS + +Original Contributor has developed Specifications, Source Code +implementations and Executables of certain Technology; and + +Original Contributor desires to license the Technology to a large +community to facilitate research, innovation and product development +while maintaining compatibility of such products with the Technology as +delivered by Original Contributor; and + +Original Contributor desires to license certain Trademarks for the +purpose of branding products that are compatible with the relevant +Technology delivered by Original Contributor; and + +You desire to license the Technology and possibly certain Trademarks +from Original Contributor on the terms and conditions specified in this +License. + +In consideration for the mutual covenants contained herein, You and +Original Contributor agree as follows: + + + AGREEMENT + +*1. Introduction.* + +The RealNetworks Community Source License ("RCSL") and effective +attachments ("License") may include five distinct licenses: + +i) Research Use license -- License plus Attachments A, B and C only. + +ii) Commercial Use and Trademark License, which may be for Internal +Deployment Use or external distribution, or both -- License plus +Attachments A, B, C, and D. + +iii) Technology Compatibility Kit (TCK) license -- Attachment C. + +iv) Add-On Technology License (Executable) Commercial Use License +-Attachment F. + +v) Add-On Technology Source Code Porting and Optimization +License-Attachment G. + +The Research Use license is effective when You click and accept this +License. The TCK is effective when You click and accept this License, +unless otherwise specified in the TCK attachments. The Commercial Use +and Trademark, Add-On Technology License, and the Add-On Technology +Source Code Porting and Optimization licenses must each be signed by You +and Original Contributor to become effective. Once effective, these +licenses and the associated requirements and responsibilities are +cumulative. Capitalized terms used in this License are defined in the +Glossary. + +*2. License Grants.* + +2.1 Original Contributor Grant. + +Subject to Your compliance with Sections 3, 8.10 and Attachment A of +this License, Original Contributor grants to You a worldwide, +royalty-free, non-exclusive license, to the extent of Original +Contributor's Intellectual Property Rights covering the Original Code, +Upgraded Code and Specifications, to do the following: + +(a) Research Use License: + +(i) use, reproduce and modify the Original Code, Upgraded Code and +Specifications to create Modifications and Reformatted Specifications +for Research Use by You; + +(ii) publish and display Original Code, Upgraded Code and Specifications +with, or as part of Modifications, as permitted under Section 3.1(b) below; + +(iii) reproduce and distribute copies of Original Code and Upgraded Code +to Licensees and students for Research Use by You; + +(iv) compile, reproduce and distribute Original Code and Upgraded Code +in Executable form, and Reformatted Specifications to anyone for +Research Use by You. + +(b) Other than the licenses expressly granted in this License, Original +Contributor retains all right, title, and interest in Original Code and +Upgraded Code and Specifications. + +2.2 Your Grants. + +(a) To Other Licensees. You hereby grant to each Licensee a license to +Your Error Corrections and Shared Modifications, of the same scope and +extent as Original Contributor's licenses under Section 2.1 a) above +relative to Research Use and Attachment D relative to Commercial Use. + +(b) To Original Contributor. You hereby grant to Original Contributor a +worldwide, royalty-free, non-exclusive, perpetual and irrevocable +license, to the extent of Your Intellectual Property Rights covering +Your Error Corrections, Shared Modifications and Reformatted +Specifications, to use, reproduce, modify, display and distribute Your +Error Corrections, Shared Modifications and Reformatted Specifications, +in any form, including the right to sublicense such rights through +multiple tiers of distribution. + +(c) Other than the licenses expressly granted in Sections 2.2(a) and (b) +above, and the restrictions set forth in Section 3.1(d)(iv) below, You +retain all right, title, and interest in Your Error Corrections, Shared +Modifications and Reformatted Specifications. + +2.3 Contributor Modifications. + +You may use, reproduce, modify, display and distribute Contributor Error +Corrections, Shared Modifications and Reformatted Specifications, +obtained by You under this License, to the same scope and extent as with +Original Code, Upgraded Code and Specifications. + +2.4 Subcontracting. + +You may deliver the Source Code of Covered Code to other Licensees +having at least a Research Use license, for the sole purpose of +furnishing development services to You in connection with Your rights +granted in this License. All such Licensees must execute appropriate +documents with respect to such work consistent with the terms of this +License, and acknowledging their work-made-for-hire status or assigning +exclusive right to the work product and associated Intellectual Property +Rights to You. + +*3. Requirements and Responsibilities*. + +3.1 Research Use License. + +As a condition of exercising the rights granted under Section 2.1(a) +above, You agree to comply with the following: + +(a) Your Contribution to the Community. All Error Corrections and Shared +Modifications which You create or contribute to are automatically +subject to the licenses granted under Section 2.2 above. You are +encouraged to license all of Your other Modifications under Section 2.2 +as Shared Modifications, but are not required to do so. You agree to +notify Original Contributor of any errors in the Specification. + +(b) Source Code Availability. You agree to provide all Your Error +Corrections to Original Contributor as soon as reasonably practicable +and, in any event, prior to Internal Deployment Use or Commercial Use, +if applicable. Original Contributor may, at its discretion, post Source +Code for Your Error Corrections and Shared Modifications on the +Community Webserver. You may also post Error Corrections and Shared +Modifications on a web-server of Your choice; provided, that You must +take reasonable precautions to ensure that only Licensees have access to +such Error Corrections and Shared Modifications. Such precautions shall +include, without limitation, a password protection scheme limited to +Licensees and a click-on, download certification of Licensee status +required of those attempting to download from the server. An example of +an acceptable certification is attached as Attachment A-2. + +(c) Notices. All Error Corrections and Shared Modifications You create +or contribute to must include a file documenting the additions and +changes You made and the date of such additions and changes. You must +also include the notice set forth in Attachment A-1 in the file header. +If it is not possible to put the notice in a particular Source Code file +due to its structure, then You must include the notice in a location +(such as a relevant directory file), where a recipient would be most +likely to look for such a notice. + +(d) Redistribution. + +(i) Source. Covered Code may be distributed in Source Code form only to +another Licensee (except for students as provided below). You may not +offer or impose any terms on any Covered Code that alter the rights, +requirements, or responsibilities of such Licensee. You may distribute +Covered Code to students for use in connection with their course work +and research projects undertaken at accredited educational institutions. +Such students need not be Licensees, but must be given a copy of the +notice set forth in Attachment A-3 and such notice must also be included +in a file header or prominent location in the Source Code made available +to such students. + +(ii) Executable. You may distribute Executable version(s) of Covered +Code to Licensees and other third parties only for the purpose of +evaluation and comment in connection with Research Use by You and under +a license of Your choice, but which limits use of such Executable +version(s) of Covered Code only to that purpose. + +(iii) Modified Class, Interface and Package Naming. In connection with +Research Use by You only, You may use Original Contributor's class, +Interface and package names only to accurately reference or invoke the +Source Code files You modify. Original Contributor grants to You a +limited license to the extent necessary for such purposes. + +(iv) You expressly agree that any distribution, in whole or in part, of +Modifications developed by You shall only be done pursuant to the terms +and conditions of this License. + +(e) Extensions. + +(i) Covered Code. You may not include any Source Code of Community Code +in any Extensions. You may include the compiled Header Files of +Community Code in an Extension provided that Your use of the Covered +Code, including Heading Files, complies with the Commercial Use License, +the TCK and all other terms of this License. + +(ii) Publication. No later than the date on which You first distribute +such Extension for Commercial Use, You must publish to the industry, on +a non-confidential basis and free of all copyright restrictions with +respect to reproduction and use, an accurate and current specification +for any Extension. In addition, You must make available an appropriate +test suite, pursuant to the same rights as the specification, +sufficiently detailed to allow any third party reasonably skilled in the +technology to produce implementations of the Extension compatible with +the specification. Such test suites must be made available as soon as +reasonably practicable but, in no event, later than ninety (90) days +after Your first Commercial Use of the Extension. You must use +reasonable efforts to promptly clarify and correct the specification and +the test suite upon written request by Original Contributor. + +(iii) Open. You agree to refrain from enforcing any Intellectual +Property Rights You may have covering any interface(s) of Your +Extension, which would prevent the implementation of such interface(s) +by Original Contributor or any Licensee. This obligation does not +prevent You from enforcing any Intellectual Property Right You have that +would otherwise be infringed by an implementation of Your Extension. + +(iv) Interface Modifications and Naming. You may not modify or add to +the GUID space * * "xxxxxxxx-0901-11d1-8B06-00A024406D59" or any other +GUID space designated by Original Contributor. You may not modify any +Interface prefix provided with the Covered Code or any other prefix +designated by Original Contributor.* * + +* * + +(f) You agree that any Specifications provided to You by Original +Contributor are confidential and proprietary information of Original +Contributor. You must maintain the confidentiality of the Specifications +and may not disclose them to any third party without Original +Contributor's prior written consent. You may only use the Specifications +under the terms of this License and only for the purpose of implementing +the terms of this License with respect to Covered Code. You agree not +use, copy or distribute any such Specifications except as provided in +writing by Original Contributor. + +3.2 Commercial Use License. + +You may not make Commercial Use of any Covered Code unless You and +Original Contributor have executed a copy of the Commercial Use and +Trademark License attached as Attachment D. + +*4. Versions of the License.* + +4.1 License Versions. + +Original Contributor may publish revised versions of the License from +time to time. Each version will be given a distinguishing version number. + +4.2 Effect. + +Once a particular version of Covered Code has been provided under a +version of the License, You may always continue to use such Covered Code +under the terms of that version of the License. You may also choose to +use such Covered Code under the terms of any subsequent version of the +License. No one other than Original Contributor has the right to +promulgate License versions. + +4.3 Multiple-Licensed Code. + +Original Contributor may designate portions of the Covered Code as +"Multiple-Licensed." "Multiple-Licensed" means that the Original +Contributor permits You to utilize those designated portions of the +Covered Code under Your choice of this License or the alternative +license(s), if any, specified by the Original Contributor in an +Attachment to this License. + +*5. Disclaimer of Warranty.* + +5.1 COVERED CODE PROVIDED AS IS. + +COVERED CODE IS PROVIDED UNDER THIS LICENSE "AS IS," WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, +WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT +FOR A PARTICULAR PURPOSE OR NON-INFRINGING. YOU AGREE TO BEAR THE ENTIRE +RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF COVERED CODE UNDER +THIS LICENSE. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART +OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER +EXCEPT SUBJECT TO THIS DISCLAIMER. + +5.2 Not Designed for High Risk Activities. + +You acknowledge that Original Code, Upgraded Code and Specifications are +not designed or intended for use in high risk activities including, but +not limited to: (i) on-line control of aircraft, air traffic, aircraft +navigation or aircraft communications; or (ii) in the design, +construction, operation or maintenance of any nuclear facility. Original +Contributor disclaims any express or implied warranty of fitness for +such uses. + +*6. Termination.* + +6.1 By You. + +You may terminate this Research Use license at anytime by providing +written notice to Original Contributor. + +6.2 By Original Contributor. + +This License and the rights granted hereunder will terminate: + +(i) automatically if You fail to comply with the terms of this License +and fail to cure such breach within 30 days of receipt of written notice +of the breach; + +(ii) immediately in the event of circumstances specified in Sections 7.1 +and 8.4; or + +(iii) at Original Contributor's discretion upon any action initiated by +You (including by cross-claim or counter claim) alleging that use or +distribution by Original Contributor or any Licensee, of Original Code, +Upgraded Code, Error Corrections, Shared Modifications or Specifications +infringe a patent owned or controlled by You. + +6.3 Effective of Termination. + +Upon termination, You agree to discontinue use of and destroy all copies +of Covered Code in Your possession. All sublicenses to the Covered Code +which You have properly granted shall survive any termination of this +License. Provisions that, by their nature, should remain in effect +beyond the termination of this License shall survive including, without +limitation, Sections 2.2, 3, 5, 7 and 8. + +6.4 No Compensation. + +Each party waives and releases the other from any claim to compensation +or indemnity for permitted or lawful termination of the business +relationship established by this License. + +*7. Liability.* + +7.1 Infringement. Should any of the Original Code, Upgraded Code, TCK or +Specifications ("Materials") become the subject of a claim of +infringement, Original Contributor may, at its sole option, (i) attempt +to procure the rights necessary for You to continue using the Materials, +(ii) modify the Materials so that they are no longer infringing, or +(iii) terminate Your right to use the Materials, immediately upon +written notice, and refund to You the amount, if any, having then +actually been paid by You to Original Contributor for the Original Code, +Upgraded Code and TCK, depreciated on a straight line, five year basis. + +7.2 LIMITATION OF LIABILITY. TO THE FULL EXTENT ALLOWED BY APPLICABLE +LAW, ORIGINAL CONTRIBUTOR'S LIABILITY TO YOU FOR CLAIMS RELATING TO THIS +LICENSE, WHETHER FOR BREACH OR IN TORT, SHALL BE LIMITED TO ONE HUNDRED +PERCENT (100%) OF THE AMOUNT HAVING THEN ACTUALLY BEEN PAID BY YOU TO +ORIGINAL CONTRIBUTOR FOR ALL COPIES LICENSED HEREUNDER OF THE PARTICULAR +ITEMS GIVING RISE TO SUCH CLAIM, IF ANY, DURING THE TWELVE MONTHS +PRECEDING THE CLAIMED BREACH. IN NO EVENT WILL YOU (RELATIVE TO YOUR +SHARED MODIFICATIONS OR ERROR CORRECTIONS) OR ORIGINAL CONTRIBUTOR BE +LIABLE FOR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES IN CONNECTION WITH OR RISING OUT OF THIS LICENSE (INCLUDING, +WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR OTHER ECONOMIC +ADVANTAGE), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY, WHETHER IN +AN ACTION FOR CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE) +OR OTHERWISE, WHETHER OR NOT YOU OR ORIGINAL CONTRIBUTOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE AND NOTWITHSTANDING THE +FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. + +*8. Miscellaneous.* + +8.1 Trademark. + +You shall not use any Trademark unless You and Original Contributor +execute a copy of the Commercial Use and Trademark License Agreement +attached hereto as Attachment D. Except as expressly provided in the +License, You are granted no right, title or license to, or interest in, +any Trademarks. Whether or not You and Original Contributor enter into +the Trademark License, You agree not to (i) challenge Original +Contributor's ownership or use of Trademarks; (ii) attempt to register +any Trademarks, or any mark or logo substantially similar thereto; or +(iii) incorporate any Trademarks into Your own trademarks, product +names, service marks, company names, or domain names. + +8.2 Integration. + +This License represents the complete agreement concerning the subject +matter hereof. + +8.3 Assignment. + +Original Contributor may assign this License, and its rights and +obligations hereunder, in its sole discretion. You may assign the +Research Use portions of this License and the TCK license to a third +party upon prior written notice to Original Contributor (which may be +provided electronically via the Community Web-Server). You may not +assign the Commercial Use and Trademark license, the Add-On Technology +License, or the Add-On Technology Source Code Porting License, including +by way of merger (regardless of whether You are the surviving entity) or +acquisition, without Original Contributor's prior written consent. + +8.4 Severability. + +If any provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to make it +enforceable. Notwithstanding the foregoing, if You are prohibited by law +from fully and specifically complying with Sections 2.2 or 3, this +License will immediately terminate and You must immediately discontinue +any use of Covered Code. + +8.5 Governing Law. + +This License shall be governed by the laws of the United States and the +State of Washington, as applied to contracts entered into and to be +performed in Washington between Washington residents. The application of +the United Nations Convention on Contracts for the International Sale of +Goods is expressly excluded. You agree that the state and federal courts +located in Seattle, Washington have exclusive jurisdiction over any +claim relating to the License, including contract and tort claims. + +8.6 Dispute Resolution. + +a) Arbitration. Any dispute arising out of or relating to this License +shall be finally settled by arbitration as set out herein, except that +either party may bring any action, in a court of competent jurisdiction +(which jurisdiction shall be exclusive), with respect to any dispute +relating to such party's Intellectual Property Rights or with respect to +Your compliance with the TCK license. Arbitration shall be administered: +(i) by the American Arbitration Association (AAA), (ii) in accordance +with the rules of the United Nations Commission on International Trade +Law (UNCITRAL) (the "Rules") in effect at the time of arbitration as +modified herein; and (iii) the arbitrator will apply the substantive +laws of Washington and the United States. Judgment upon the award +rendered by the arbitrator may be entered in any court having +jurisdiction to enforce such award. + +b) Arbitration language, venue and damages. All arbitration proceedings +shall be conducted in English by a single arbitrator selected in +accordance with the Rules, who must be fluent in English and be either a +retired judge or practicing attorney having at least ten (10) years +litigation experience and be reasonably familiar with the technology +matters relative to the dispute. Unless otherwise agreed, arbitration +venue shall be in Seattle, Washington. The arbitrator may award monetary +damages only and nothing shall preclude either party from seeking +provisional or emergency relief from a court of competent jurisdiction. +The arbitrator shall have no authority to award damages in excess of +those permitted in this License and any such award in excess is void. +All awards will be payable in U.S. dollars and may include, for the +prevailing party (i) pre-judgment award interest, (ii) reasonable +attorneys' fees incurred in connection with the arbitration, and (iii) +reasonable costs and expenses incurred in enforcing the award. The +arbitrator will order each party to produce identified documents and +respond to no more than twenty-five single question interrogatories. + +8.7 Construction. + +Any law or regulation, which provides that the language of a contract +shall be construed against the drafter, shall not apply to this License. + +8.8 U.S. Government End Users. + +The Covered Code is a "commercial item," as that term is defined in 48 +C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" +and "commercial computer software documentation," as such terms are used +in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and +48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government +End Users acquire Covered Code with only those rights set forth herein. +You agree to pass this notice to our licensees. + +8.9 Marketing Activities. + +Licensee hereby grants Original Contributor a non-exclusive, +non-transferable, limited license to use the Licensee's company name and +logo ("Licensee Marks") in any presentations, press releases, or +marketing materials solely for the purpose of identifying Licensee as a +member of the Helix Community. Licensee shall provide samples of +Licensee Marks to Original Contributor upon request by Original +Contributor. Original Contributor acknowledges that the Licensee Marks +are the trademarks of Licensee. Original Contributor shall not use the +Licensee Marks in a way that may imply that Original Contributor is an +agency or branch of Licensee. Original Contributor understands and +agrees that the use of any Licensee Marks in connection with this +Agreement shall not create any right, title or interest, in, or to the +Licensee Marks or any Licensee trademarks and that all such use and +goodwill associated with any such trademarks will inure to the benefit +of Licensee. Further the Original Contributor will stop usage of the +Licensee Marks upon Licensee's request. + +8.10 Press Announcements. + +You may make press announcements or other public statements regarding +this License without the prior written consent of the Original +Contributor, if Your statement is limited to announcing the licensing of +the Covered Code or the availability of Your Product and its +compatibility with the Covered Code. All other public announcements +regarding this license require the prior written consent of the Original +Contributor. Consent requests are welcome at press@helixcommunity.org. + +8.11 International Use. + +a) Export/Import laws. Covered Code is subject to U.S. export control +laws and may be subject to export or import regulations in other +countries. Each party agrees to comply strictly with all such laws and +regulations and acknowledges their responsibility to obtain such +licenses to export, re-export, or import as may be required. You agree +to pass these obligations to Your licensees. + +b) Intellectual Property Protection. Due to limited intellectual +property protection and enforcement in certain countries, You agree not +to redistribute the Original Code, Upgraded Code, TCK and Specifications +to any country on the list of restricted countries on the Community Web +Server. + +8.12 Language. + +This License is in the English language only, which language shall be +controlling in all respects, and all versions of this License in any +other language shall be for accommodation only and shall not be binding +on the parties to this License. All communications and notices made or +given pursuant to this License, and all documentation and support to be +provided, unless otherwise noted, shall be in the English language. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH REALNETWORKS, INC. IF YOU ARE AGREEING +TO THIS LICENSE ON BEHALF OF A COMPANY, YOU REPRESENT THAT YOU ARE +AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. WHETHER YOU ARE ACTING +ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, YOU MUST BE OF MAJORITY +AGE AND BE OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. IF YOU DO NOT +MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY OF THE TERMS AND +CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON TO EXIT. + + + GLOSSARY + +1. *"Added Value"* means code which: + +(i) has a principal purpose which is substantially different from that +of the stand-alone Technology; + +(ii) represents a significant functional and value enhancement to the +Technology; + +(iii) operates in conjunction with the Technology; and + +(iv) is not marketed as a technology which replaces or substitutes for +the Technology + +2. "*Applicable Patent Rights*" mean: (a) in the case where Original +Contributor is the grantor of rights, claims of patents that (i) are now +or hereafter acquired, owned by or assigned to Original Contributor and +(ii) are necessarily infringed by using or making the Original Code or +Upgraded Code, including Modifications provided by Original Contributor, +alone and not in combination with other software or hardware; and (b) in +the case where Licensee is the grantor of rights, claims of patents that +(i) are now or hereafter acquired, owned by or assigned to Licensee and +(ii) are infringed (directly or indirectly) by using or making +Licensee's Modifications or Error Corrections, taken alone or in +combination with Covered Code. + +3. "*Application Programming Interfaces (APIs)"* means the interfaces, +associated header files, service provider interfaces, and protocols that +enable a device, application, Operating System, or other program to +obtain services from or make requests of (or provide services in +response to requests from) other programs, and to use, benefit from, or +rely on the resources, facilities, and capabilities of the relevant +programs using the APIs. APIs includes the technical documentation +describing the APIs, the Source Code constituting the API, and any +Header Files used with the APIs. + +4. "*Commercial Use*" means any use (internal or external), copying, +sublicensing or distribution (internal or external), directly or +indirectly of Covered Code by You other than Your Research Use of +Covered Code within Your business or organization or in conjunction with +other Licensees with equivalent Research Use rights. Commercial Use +includes any use of the Covered Code for direct or indirect commercial +or strategic gain, advantage or other business purpose. Any Commercial +Use requires execution of Attachment D by You and Original Contributor. + +5. "*Community Code*" means the Original Code, Upgraded Code, Error +Corrections, Shared Modifications, or any combination thereof. + +6. "*Community Webserver(s)"* means the webservers designated by +Original Contributor for access to the Original Code, Upgraded Code, TCK +and Specifications and for posting Error Corrections and Shared +Modifications. + +7. "*Compliant Covered Code*" means Covered Code that complies with the +requirements of the TCK. + +8. "*Contributor*" means each Licensee that creates or contributes to +the creation of any Error Correction or Shared Modification. + +9. "*Covered Code*" means the Original Code, Upgraded Code, +Modifications, or any combination thereof. + +10. "*Error Correction*" means any change made to Community Code which +conforms to the Specification and corrects the adverse effect of a +failure of Community Code to perform any function set forth in or +required by the Specifications. + +11. "*Executable*" means Covered Code that has been converted from +Source Code to the preferred form for execution by a computer or digital +processor (e.g. binary form). + +12. "*Extension(s)"* means any additional Interfaces developed by or for +You which: (i) are designed for use with the Technology; (ii) constitute +an API for a library of computing functions or services; and (iii) are +disclosed or otherwise made available to third party software developers +for the purpose of developing software which invokes such additional +Interfaces. The foregoing shall not apply to software developed by Your +subcontractors to be exclusively used by You. + +13. "*Header File(s)"* means that portion of the Source Code that +provides the names and types of member functions, data members, class +definitions, and interface definitions necessary to implement the APIs +for the Covered Code. Header Files include, files specifically +designated by Original Contributor as Header Files. Header Files do not +include the code necessary to implement the functionality underlying the +Interface. + +14. *"Helix DNA Server Technology"* means the program(s) that implement +the Helix Universal Server streaming engine for the Technology as +defined in the Specification. + +15. *"Helix DNA Client Technology"* means the Covered Code that +implements the RealOne Player engine as defined in the Specification. + +16. *"Helix DNA Producer Technology"* means the Covered Code that +implements the Helix Producer engine as defined in the Specification. + +17. *"Helix DNA Technology"* means the Helix DNA Server Technology, the +Helix DNA Client Technology, the Helix DNA Producer Technology and other +Helix technologies designated by Original Contributor. + +18. "*Intellectual Property Rights*" means worldwide statutory and +common law rights associated solely with (i) Applicable Patent Rights; +(ii) works of authorship including copyrights, copyright applications, +copyright registrations and "moral rights"; (iii) the protection of +trade and industrial secrets and confidential information; and (iv) +divisions, continuations, renewals, and re-issuances of the foregoing +now existing or acquired in the future. + +19. *"Interface*" means interfaces, functions, properties, class +definitions, APIs, Header Files, GUIDs, V-Tables, and/or protocols +allowing one piece of software, firmware or hardware to communicate or +interoperate with another piece of software, firmware or hardware. + +20. "*Internal Deployment Use*" means use of Compliant Covered Code +(excluding Research Use) within Your business or organization only by +Your employees and/or agents on behalf of Your business or organization, +but not to provide services, including content distribution, to third +parties, subject to execution of Attachment D by You and Original +Contributor, if required. + +21. "*Licensee*" means any party that has entered into and has in effect +a version of this License with Original Contributor. + +22. "*MIME type*" means a description of what type of media or other +content is in a file, including by way of example but not limited to +'audio/x-pn-realaudio-plugin.' + +23. "*Modification(s)"* means (i) any addition to, deletion from and/or +change to the substance and/or structure of the Covered Code, including +Interfaces; (ii) the combination of any Covered Code and any previous +Modifications; (iii) any new file or other representation of computer +program statements that contains any portion of Covered Code; and/or +(iv) any new Source Code implementing any portion of the Specifications. + +24. "*MP3 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Picture Experts Group known as MPEG-1 Audio Layer-3 or MP3, +including but not limited to all past and future versions, profiles, +extensions, parts and amendments relating to the MP3 specification. + +25. "*MPEG-4 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Pictures Experts Group known as MPEG-4, including but not +limited to all past and future versions, profiles, extensions, parts and +amendments relating to the MPEG-4 specification. + +26. "*Original Code*" means the initial Source Code for the Technology +as described on the Community Web Server. + +27. "*Original Contributor*" means RealNetworks, Inc., its affiliates +and its successors and assigns. + +28. "*Original Contributor MIME Type*" means the MIME registry, browser +preferences, or local file/protocol associations invoking any Helix DNA +Client-based application, including the RealOne Player, for playback of +RealAudio, RealVideo, other RealMedia MIME types or datatypes (e.g., +.ram, .rnx, .rpm, .ra, .rm, .rp, .rt, .rf, .prx, .mpe, .rmp, .rmj, .rav, +.rjs, .rmx, .rjt, .rms), and any other Original Contributor-specific or +proprietary MIME types that Original Contributor may introduce in the +future. + +29. "*Personal Use*" means use of Covered Code by an individual solely +for his or her personal, private and non-commercial purposes. An +individual's use of Covered Code in his or her capacity as an officer, +employee, member, independent contractor or agent of a corporation, +business or organization (commercial or non-commercial) does not qualify +as Personal Use. + +30. "*RealMedia File Format*" means the file format designed and +developed by RealNetworks for storing multimedia data and used to store +RealAudio and RealVideo encoded streams. Valid RealMedia File Format +extensions include: .rm, .rmj, .rmc, .rmvb, .rms. + +31. "*RCSL Webpage*" means the RealNetworks Community Source License +webpage located at https://www.helixcommunity.org/content/rcsl or such +other URL that Original Contributor may designate from time to time. + +32. "*Reformatted Specifications*" means any revision to the +Specifications which translates or reformats the Specifications (as for +example in connection with Your documentation) but which does not alter, +subset or superset * *the functional or operational aspects of the +Specifications. + +33. "*Research Use*" means use and distribution of Covered Code only for +Your Personal Use, research or development use and expressly excludes +Internal Deployment Use and Commercial Use. Research Use also includes +use of Covered Code to teach individuals how to use Covered Code. + +34. "*Shared Modifications*" means Modifications that You distribute or +use for a Commercial Use, in addition to any Modifications provided by +You, at Your option, pursuant to Section 2.2, or received by You from a +Contributor pursuant to Section 2.3. + +35. "*Source Code*" means the preferred form of the Covered Code for +making modifications to it, including all modules it contains, plus any +associated interface definition files, scripts used to control +compilation and installation of an Executable, or source code +differential comparisons against either the Original Code or another +well known, available Covered Code of the Contributor's choice. The +Source Code can be in a compressed or archival form, provided the +appropriate decompression or de-archiving software is widely available +for no charge. + +36. "*Specifications*" means the specifications for the Technology and +other documentation, as designated on the Community Web Server, as may +be revised by Original Contributor from time to time. + +37. "*Trademarks*" means Original Contributor's trademarks and logos, +including, but not limited to, RealNetworks, RealAudio, RealVideo, +RealOne, RealSystem, SureStream, Helix, Helix DNA and other trademarks +whether now used or adopted in the future. + +38. "*Technology*" means the technology described in Attachment B, and +Upgrades. + +39. "*Technology Compatibility Kit"* or *"TCK*" means the test programs, +procedures, acceptance criteria and/or other requirements, designated by +Original Contributor for use in verifying compliance of Covered Code +with the Specifications, in conjunction with the Original Code and +Upgraded Code. Original Contributor may, in its sole discretion and from +time to time, revise a TCK to correct errors and/or omissions and in +connection with Upgrades. + +40. "*Upgrade(s)"* means new versions of Technology designated +exclusively by Original Contributor as an "Upgrade" and released by +Original Contributor from time to time under the terms of the License. + +41. "*Upgraded Code*" means the Source Code and/or Executables for +Upgrades, possibly including Modifications made by Contributors. + +42. *"User's Guide"* means the users guide for the TCK which Original +Contributor makes available to You to provide direction in how to run +the TCK and properly interpret the results, as may be revised by +Original Contributor from time to time. + +43. "*You(r)*" means an individual, or a legal entity acting by and +through an individual or individuals, exercising rights either under +this License or under a future version of this License issued pursuant +to Section 4.1. For legal entities, "You(r)" includes any entity that by +majority voting interest controls, is controlled by, or is under common +control with You. + +44. "*Your Products*" means any (i) hardware products You distribute +integrating the Covered Code; (ii) any software products You distribute +with the Covered Code that utilize the APIs of the Covered Code; or +(iii) any services You provide using the Covered Code. + + + ATTACHMENT A + +REQUIRED NOTICES + + + ATTACHMENT A-1 + +REQUIRED IN ALL CASES + +Notice to be included in header file of all Error Corrections and Shared +Modifications: + +Portions Copyright 1994-2003 RealNetworks, Inc. All rights reserved. + +The contents of this file, and the files included with this file, are +subject to the current version of RealNetworks Community Source License +Version 1.1 (the "License"). You may not use this file except in +compliance with the License executed by both You and RealNetworks. You +may obtain a copy of the License at * +https://www.helixcommunity.org/content/rcsl.* You may also obtain a copy +of the License by contacting RealNetworks directly. Please see the +License for the rights, obligations and limitations governing use of the +contents of the file. + +This file is part of the Helix DNA technology. RealNetworks, Inc., is +the developer of the Original code and owns the copyrights in the +portions it created. + +This file, and the files included with this file, are distributed on an +'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, +AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): + +_______________________________________________ + +Technology Compatibility Kit Test Suite(s) Location: + +________________________________ + + + ATTACHMENT A-2 + +SAMPLE LICENSEE CERTIFICATION + +"By clicking the `Agree' button below, You certify that You are a +Licensee in good standing under the RealNetworks Community Source +License, ("License") and that Your access, use and distribution of code +and information You may obtain at this site is subject to the License. +If You are not a Licensee under the RealNetworks Community Source +License You agree not to download, copy or use the Helix DNA technology. + + + ATTACHMENT A-3 + +REQUIRED STUDENT NOTIFICATION + +"This software and related documentation has been obtained by Your +educational institution subject to the RealNetworks Community Source +License. You have been provided access to the software and related +documentation for use only in connection with your course work and +research activities as a matriculated student of Your educational +institution. Any other use is expressly prohibited. + +THIS SOFTWARE AND RELATED DOCUMENTATION CONTAINS PROPRIETARY MATERIAL OF +REALNETWORKS, INC, WHICH ARE PROTECTED BY VARIOUS INTELLECTUAL PROPERTY +RIGHTS. + +You may not use this file except in compliance with the License. You may +obtain a copy of the License on the web at +https://www.helixcommunity.org/content/rcsl. + +* +* + + + ATTACHMENT B + +Description of Technology + +Helix DNA, which consists of Helix DNA Client, Helix DNA Server and +Helix DNA Producer. + +Description of "Technology" + +Helix DNA Technology v1.0 as described on the Community Web Server. + + + ATTACHMENT C + +TECHNOLOGY COMPATIBILITY KIT LICENSE + +The following license is effective for the *Helix DNA* Technology +Compatibility Kit - as described on the Community Web Server. The +Technology Compatibility Kit(s) for the Technology specified in +Attachment B may be accessed at the Community Web Server. + +1. TCK License. + +1.1 Grants to use TCK + +Subject to the terms and restrictions set forth below and the +RealNetworks Community Source License, and the Research Use license, +Original Contributor grants to You a worldwide, non-exclusive, +non-transferable license, to the extent of Original Contributor's +Intellectual Property Rights in the TCK (without the right to +sublicense), to use the TCK to develop and test Covered Code. + +1.2 TCK Use Restrictions. + +You are not authorized to create derivative works of the TCK or use the +TCK to test any implementation of the Specification that is not Covered +Code. You may not publish Your test results or make claims of +comparative compatibility with respect to other implementations of the +Specification. In consideration for the license grant in Section 1.1 +above You agree not to develop Your own tests that are intended to +validate conformation with the Specification. + +2. Test Results. + +You agree to provide to Original Contributor or the third party test +facility if applicable, Your test results that demonstrate that Covered +Code is Compliant Covered Code and that Original Contributor may publish +or otherwise distribute such test results. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH THE ORIGINAL CONTRIBUTOR, REALNETWORKS, +INC. IF YOU ARE AGREEING TO THIS LICENSE ON BEHALF OF A COMPANY, YOU +REPRESENT THAT YOU ARE AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. +WHETHER YOU ARE ACTING ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, +YOU MUST BE OF MAJORITY AGE AND BE OTHERWISE COMPETENT TO ENTER INTO +CONTRACTS. IF YOU DO NOT MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY +OF THE TERMS AND CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON +TO EXIT. + +*ACCEPT / REJECT +* + +* +* + +*To agree to the R&D/academic terms of this license, please register + on the site -- +you will then be given a chance to agree to the clickwrap RCSL + +R&D License + +and gain access to the RCSL-licensed source code. To build or deploy +commercial applications based on the RCSL, you will need to agree to the +Commercial Use license attachments +* + + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/RPSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/RPSL.txt new file mode 100644 index 0000000..d040a45 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/RPSL.txt @@ -0,0 +1,518 @@ +RealNetworks Public Source License Version 1.0 +(Rev. Date October 28, 2002) + +1. General Definitions. This License applies to any program or other work which +RealNetworks, Inc., or any other entity that elects to use this license, +("Licensor") makes publicly available and which contains a notice placed by +Licensor identifying such program or work as "Original Code" and stating that it +is subject to the terms of this RealNetworks Public Source License version 1.0 +(or subsequent version thereof) ("License"). You are not required to accept this +License. However, nothing else grants You permission to use, copy, modify or +distribute the software or its derivative works. These actions are prohibited by +law if You do not accept this License. Therefore, by modifying, copying or +distributing the software (or any work based on the software), You indicate your +acceptance of this License to do so, and all its terms and conditions. In +addition, you agree to the terms of this License by clicking the Accept button +or downloading the software. As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Licensor is the +grantor of rights, claims of patents that (i) are now or hereafter acquired, +owned by or assigned to Licensor and (ii) are necessarily infringed by using or +making the Original Code alone and not in combination with other software or +hardware; and (b) in the case where You are the grantor of rights, claims of +patents that (i) are now or hereafter acquired, owned by or assigned to You and +(ii) are infringed (directly or indirectly) by using or making Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Compatible Source License" means any one of the licenses listed on Exhibit +B or at https://www.helixcommunity.org/content/complicense or other licenses +specifically identified by Licensor in writing. Notwithstanding any term to the +contrary in any Compatible Source License, any code covered by any Compatible +Source License that is used with Covered Code must be made readily available in +Source Code format for royalty-free use under the terms of the Compatible Source +License or this License. + +1.3 "Contributor" means any person or entity that creates or contributes to the +creation of Modifications. + +1.4 "Covered Code" means the Original Code, Modifications, the combination of +Original Code and any Modifications, and/or any respective portions thereof. + +1.5 "Deploy" means to use, sublicense or distribute Covered Code other than for +Your internal research and development (R&D) and/or Personal Use, and includes +without limitation, any and all internal use or distribution of Covered Code +within Your business or organization except for R&D use and/or Personal Use, as +well as direct or indirect sublicensing or distribution of Covered Code by You +to any third party in any form or manner. + +1.6 "Derivative Work" means either the Covered Code or any derivative work under +United States copyright law, and including any work containing or including any +portion of the Covered Code or Modifications, either verbatim or with +modifications and/or translated into another language. Derivative Work also +includes any work which combines any portion of Covered Code or Modifications +with code not otherwise governed by the terms of this License. + +1.7 "Externally Deploy" means to Deploy the Covered Code in any way that may be +accessed or used by anyone other than You, used to provide any services to +anyone other than You, or used in any way to deliver any content to anyone other +than You, whether the Covered Code is distributed to those parties, made +available as an application intended for use over a computer network, or used to +provide services or otherwise deliver content to anyone other than You. + +1.8. "Interface" means interfaces, functions, properties, class definitions, +APIs, header files, GUIDs, V-Tables, and/or protocols allowing one piece of +software, firmware or hardware to communicate or interoperate with another piece +of software, firmware or hardware. + +1.9 "Modifications" mean any addition to, deletion from, and/or change to, the +substance and/or structure of the Original Code, any previous Modifications, the +combination of Original Code and any previous Modifications, and/or any +respective portions thereof. When code is released as a series of files, a +Modification is: (a) any addition to or deletion from the contents of a file +containing Covered Code; and/or (b) any new file or other representation of +computer program statements that contains any part of Covered Code. + +1.10 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Licensor under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Licensor under this License, and that has been expressly identified by Licensor +as such in the header file(s) of such work; and (b) the object code compiled +from such Source Code and originally made available by Licensor under this +License. + +1.11 "Personal Use" means use of Covered Code by an individual solely for his or +her personal, private and non-commercial purposes. An individual's use of +Covered Code in his or her capacity as an officer, employee, member, independent +contractor or agent of a corporation, business or organization (commercial or +non-commercial) does not qualify as Personal Use. + +1.12 "Source Code" means the human readable form of a program or other work that +is suitable for making modifications to it, including all modules it contains, +plus any associated interface definition files, scripts used to control +compilation and installation of an executable (object code). + +1.13 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership of +fifty percent (50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Licensor hereby grants You, effective on the date +You accept this License (via downloading or using Covered Code or otherwise +indicating your acceptance of this License), a worldwide, royalty-free, +non-exclusive copyright license, to the extent of Licensor's copyrights cover +the Original Code, to do the following: + +2.1 You may reproduce, display, perform, modify and Deploy Covered Code, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the copyright +and other proprietary notices and disclaimers of Licensor as they appear in the +Original Code, and keep intact all notices in the Original Code that refer to +this License; + +(b) You must include a copy of this License with every copy of Source Code of +Covered Code and documentation You distribute, and You may not offer or impose +any terms on such Source Code that alter or restrict this License or the +recipients' rights hereunder, except as permitted under Section 6; + +(c) You must duplicate, to the extent it does not already exist, the notice in +Exhibit A in each file of the Source Code of all Your Modifications, and cause +the modified files to carry prominent notices stating that You changed the files +and the date of any change; + +(d) You must make Source Code of all Your Externally Deployed Modifications +publicly available under the terms of this License, including the license grants +set forth in Section 3 below, for as long as you Deploy the Covered Code or +twelve (12) months from the date of initial Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Deployed Modifications +electronically (e.g. download from a web site); and + +(e) if You Deploy Covered Code in object code, executable form only, You must +include a prominent notice, in the code itself as well as in related +documentation, stating that Source Code of the Covered Code is available under +the terms of this License with information on how and where to obtain such +Source Code. You must also include the Object Code Notice set forth in Exhibit A +in the "about" box or other appropriate place where other copyright notices are +placed, including any packaging materials. + +2.2 You expressly acknowledge and agree that although Licensor and each +Contributor grants the licenses to their respective portions of the Covered Code +set forth herein, no assurances are provided by Licensor or any Contributor that +the Covered Code does not infringe the patent or other intellectual property +rights of any other entity. Licensor and each Contributor disclaim any liability +to You for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, You hereby assume sole responsibility to +secure any other intellectual property rights needed, if any. For example, if a +third party patent license is required to allow You to make, use, sell, import +or offer for sale the Covered Code, it is Your responsibility to acquire such +license(s). + +2.3 Subject to the terms and conditions of this License, Licensor hereby grants +You, effective on the date You accept this License (via downloading or using +Covered Code or otherwise indicating your acceptance of this License), a +worldwide, royalty-free, perpetual, non-exclusive patent license under +Licensor's Applicable Patent Rights to make, use, sell, offer for sale and +import the Covered Code, provided that in each instance you comply with the +terms of this License. + +3. Your Grants. In consideration of, and as a condition to, the licenses granted +to You under this License: + +(a) You grant to Licensor and all third parties a non-exclusive, perpetual, +irrevocable, royalty free license under Your Applicable Patent Rights and other +intellectual property rights owned or controlled by You, to make, sell, offer +for sale, use, import, reproduce, display, perform, modify, distribute and +Deploy Your Modifications of the same scope and extent as Licensor's licenses +under Sections 2.1 and 2.2; and + +(b) You grant to Licensor and its subsidiaries a non-exclusive, worldwide, +royalty-free, perpetual and irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights owned or controlled by You, to +make, use, sell, offer for sale, import, reproduce, display, perform, +distribute, modify or have modified (for Licensor and/or its subsidiaries), +sublicense and distribute Your Modifications, in any form and for any purpose, +through multiple tiers of distribution. + +(c) You agree not use any information derived from Your use and review of the +Covered Code, including but not limited to any algorithms or inventions that may +be contained in the Covered Code, for the purpose of asserting any of Your +patent rights, or assisting a third party to assert any of its patent rights, +against Licensor or any Contributor. + +4. Derivative Works. You may create a Derivative Work by combining Covered Code +with other code not otherwise governed by the terms of this License and +distribute the Derivative Work as an integrated product. In each such instance, +You must make sure the requirements of this License are fulfilled for the +Covered Code or any portion thereof, including all Modifications. + +4.1 You must cause any Derivative Work that you distribute, publish or +Externally Deploy, that in whole or in part contains or is derived from the +Covered Code or any part thereof, to be licensed as a whole at no charge to all +third parties under the terms of this License and no other license except as +provided in Section 4.2. You also must make Source Code available for the +Derivative Work under the same terms as Modifications, described in Sections 2 +and 3, above. + +4.2 Compatible Source Licenses. Software modules that have been independently +developed without any use of Covered Code and which contain no portion of the +Covered Code, Modifications or other Derivative Works, but are used or combined +in any way wtih the Covered Code or any Derivative Work to form a larger +Derivative Work, are exempt from the conditions described in Section 4.1 but +only to the extent that: the software module, including any software that is +linked to, integrated with, or part of the same applications as, the software +module by any method must be wholly subject to one of the Compatible Source +Licenses. Notwithstanding the foregoing, all Covered Code must be subject to the +terms of this License. Thus, the entire Derivative Work must be licensed under a +combination of the RPSL (for Covered Code) and a Compatible Source License for +any independently developed software modules within the Derivative Work. The +foregoing requirement applies even if the Compatible Source License would +ordinarily allow the software module to link with, or form larger works with, +other software that is not subject to the Compatible Source License. For +example, although the Mozilla Public License v1.1 allows Mozilla code to be +combined with proprietary software that is not subject to the MPL, if +MPL-licensed code is used with Covered Code the MPL-licensed code could not be +combined or linked with any code not governed by the MPL. The general intent of +this section 4.2 is to enable use of Covered Code with applications that are +wholly subject to an acceptable open source license. You are responsible for +determining whether your use of software with Covered Code is allowed under Your +license to such software. + +4.3 Mere aggregation of another work not based on the Covered Code with the +Covered Code (or with a work based on the Covered Code) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. If You deliver the Covered Code for combination and/or integration with +an application previously provided by You (for example, via automatic updating +technology), such combination and/or integration constitutes a Derivative Work +subject to the terms of this License. + +5. Exclusions From License Grant. Nothing in this License shall be deemed to +grant any rights to trademarks, copyrights, patents, trade secrets or any other +intellectual property of Licensor or any Contributor except as expressly stated +herein. No right is granted to the trademarks of Licensor or any Contributor +even if such marks are included in the Covered Code. Nothing in this License +shall be interpreted to prohibit Licensor from licensing under different terms +from this License any code that Licensor otherwise would have a right to +license. Modifications, Derivative Works and/or any use or combination of +Covered Code with other technology provided by Licensor or third parties may +require additional patent licenses from Licensor which Licensor may grant in its +sole discretion. No patent license is granted separate from the Original Code or +combinations of the Original Code with other software or hardware. + +5.1. Trademarks. This License does not grant any rights to use the trademarks or +trade names owned by Licensor ("Licensor Marks" defined in Exhibit C) or to any +trademark or trade name belonging to any Contributor. No Licensor Marks may be +used to endorse or promote products derived from the Original Code other than as +permitted by the Licensor Trademark Policy defined in Exhibit C. + +6. Additional Terms. You may choose to offer, and to charge a fee for, warranty, +support, indemnity or liability obligations and/or other rights consistent with +the scope of the license granted herein ("Additional Terms") to one or more +recipients of Covered Code. However, You may do so only on Your own behalf and +as Your sole responsibility, and not on behalf of Licensor or any Contributor. +You must obtain the recipient's agreement that any such Additional Terms are +offered by You alone, and You hereby agree to indemnify, defend and hold +Licensor and every Contributor harmless for any liability incurred by or claims +asserted against Licensor or such Contributor by reason of any such Additional +Terms. + +7. Versions of the License. Licensor may publish revised and/or new versions of +this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular version +of this License, You may continue to use it under the terms of that version. You +may also choose to use such Original Code under the terms of any subsequent +version of this License published by Licensor. No one other than Licensor has +the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in part +pre-release, untested, or not fully tested works. The Covered Code may contain +errors that could cause failures or loss of data, and may be incomplete or +contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND LICENSOR AND LICENSOR'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS +"LICENSOR" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY +DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET +ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. LICENSOR AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN DOCUMENTATION, INFORMATION OR ADVICE GIVEN BY LICENSOR, A LICENSOR +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You +acknowledge that the Covered Code is not intended for use in high risk +activities, including, but not limited to, the design, construction, operation +or maintenance of nuclear facilities, aircraft navigation, aircraft +communication systems, or air traffic control machines in which case the failure +of the Covered Code could lead to death, personal injury, or severe physical or +environmental damage. Licensor disclaims any express or implied warranty of +fitness for such uses. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT +SHALL LICENSOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR STRICT +LIABILITY), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF LICENSOR OR SUCH +CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND +NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. SOME +JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF INCIDENTAL OR +CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event +shall Licensor's total liability to You for all damages (other than as may be +required by applicable law) under this License exceed the amount of ten dollars +($10.00). + +10. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Licensor retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Licensor +("Licensor Modifications"), and such Licensor Modifications will not be +automatically subject to this License. Licensor may, at its sole discretion, +choose to license such Licensor Modifications under this License, or on +different terms from those contained in this License or may choose not to +license them at all. + +11. Termination. + +11.1 Term and Termination. The term of this License is perpetual unless +terminated as provided below. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Licensor if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; + +(b) immediately in the event of the circumstances described in Section 12.5(b); +or + +(c) automatically without notice from Licensor if You, at any time during the +term of this License, commence an action for patent infringement against +Licensor (including by cross-claim or counter claim in a lawsuit); + +(d) upon written notice from Licensor if You, at any time during the term of +this License, commence an action for patent infringement against any third party +alleging that the Covered Code itself (excluding combinations with other +software or hardware) infringes any patent (including by cross-claim or counter +claim in a lawsuit). + +11.2 Effect of Termination. Upon termination, You agree to immediately stop any +further use, reproduction, modification, sublicensing and distribution of the +Covered Code and to destroy all copies of the Covered Code that are in your +possession or control. All sublicenses to the Covered Code which have been +properly granted prior to termination shall survive any termination of this +License. Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to Sections +3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other for +compensation, indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this License will +be without prejudice to any other right or remedy of any party. + +12. Miscellaneous. + +12.1 Government End Users. The Covered Code is a "commercial item" as defined in +FAR 2.101. Government software and technical data rights in the Covered Code +include only those rights customarily provided to the public as defined in this +License. This customary commercial license in technical data and software is +provided in accordance with FAR 12.211 (Technical Data) and 12.212 (Computer +Software) and, for Department of Defense purchases, DFAR 252.227-7015 (Technical +Data -- Commercial Items) and 227.7202-3 (Rights in Commercial Computer Software +or Computer Software Documentation). Accordingly, all U.S. Government End Users +acquire Covered Code with only those rights set forth herein. + +12.2 Relationship of Parties. This License will not be construed as creating an +agency, partnership, joint venture or any other form of legal association +between or among You, Licensor or any Contributor, and You will not represent to +the contrary, whether expressly, by implication, appearance or otherwise. + +12.3 Independent Development. Nothing in this License will impair Licensor's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions as, +or otherwise compete with, Modifications, Derivative Works, technology or +products that You may develop, produce, market or distribute. + +12.4 Waiver; Construction. Failure by Licensor or any Contributor to enforce any +provision of this License will not be deemed a waiver of future enforcement of +that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +12.5 Severability. (a) If for any reason a court of competent jurisdiction finds +any provision of this License, or portion thereof, to be unenforceable, that +provision of the License will be enforced to the maximum extent permissible so +as to effect the economic benefits and intent of the parties, and the remainder +of this License will continue in full force and effect. (b) Notwithstanding the +foregoing, if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the enforceability +of either of those Sections, this License will immediately terminate and You +must immediately discontinue any use of the Covered Code and destroy all copies +of it that are in your possession or control. + +12.6 Dispute Resolution. Any litigation or other dispute resolution between You +and Licensor relating to this License shall take place in the Seattle, +Washington, and You and Licensor hereby consent to the personal jurisdiction of, +and venue in, the state and federal courts within that District with respect to +this License. The application of the United Nations Convention on Contracts for +the International Sale of Goods is expressly excluded. + +12.7 Export/Import Laws. This software is subject to all export and import laws +and restrictions and regulations of the country in which you receive the Covered +Code and You are solely responsible for ensuring that You do not export, +re-export or import the Covered Code or any direct product thereof in violation +of any such restrictions, laws or regulations, or without all necessary +authorizations. + +12.8 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +Washington. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé +que le présent contrat et tous les documents connexes soient +rédigés en anglais. + + EXHIBIT A. + +"Copyright © 1995-2002 +RealNetworks, Inc. and/or its licensors. All Rights Reserved. + +The contents of this file, and the files included with this file, are subject to +the current version of the RealNetworks Public Source License Version 1.0 (the +"RPSL") available at https://www.helixcommunity.org/content/rpsl unless you have +licensed the file under the RealNetworks Community Source License Version 1.0 +(the "RCSL") available at https://www.helixcommunity.org/content/rcsl, in which +case the RCSL will apply. You may also obtain the license terms directly from +RealNetworks. You may not use this file except in compliance with the RPSL or, +if you have a valid RCSL with RealNetworks applicable to this file, the RCSL. +Please see the applicable RPSL or RCSL for the rights, obligations and +limitations governing use of the contents of the file. + +This file is part of the Helix DNA Technology. RealNetworks is the developer of +the Original code and owns the copyrights in the portions it created. + +This file, and the files included with this file, is distributed and made +available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR +IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING +WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): ____________________________________ + +Technology Compatibility Kit Test +Suite(s) Location (if licensed under the RCSL): ______________________________ + +Object Code Notice: Helix DNA Client technology included. Copyright (c) +RealNetworks, Inc., 1995-2002. All rights reserved. + + + EXHIBIT B + +Compatible Source Licenses for the RealNetworks Public Source License. The +following list applies to the most recent version of the license as of October +25, 2002, unless otherwise indicated. + +* Academic Free License +* Apache Software License +* Apple Public Source License +* Artistic license +* Attribution Assurance Licenses +* BSD license +* Common Public License (1) +* Eiffel Forum License +* GNU General Public License (GPL) (1) +* GNU Library or "Lesser" General Public License (LGPL) (1) +* IBM Public License +* Intel Open Source License +* Jabber Open Source License +* MIT license +* MITRE Collaborative Virtual Workspace License (CVW License) +* Motosoto License +* Mozilla Public License 1.0 (MPL) +* Mozilla Public License 1.1 (MPL) +* Nokia Open Source License +* Open Group Test Suite License +* Python Software Foundation License +* Ricoh Source Code Public License +* Sun Industry Standards Source License (SISSL) +* Sun Public License +* University of Illinois/NCSA Open Source License +* Vovida Software License v. 1.0 +* W3C License +* X.Net License +* Zope Public License +* zlib/libpng license + +(1) Note: because this license contains certain reciprocal licensing terms that +purport to extend to independently developed code, You may be prohibited under +the terms of this otherwise compatible license from using code licensed under +its terms with Covered Code because Covered Code may only be licensed under the +RealNetworks Public Source License. Any attempt to apply non RPSL license terms, +including without limitation the GPL, to Covered Code is expressly forbidden. +You are responsible for ensuring that Your use of Compatible Source Licensed +code does not violate either the RPSL or the Compatible Source License. + +The latest version of this list can be found at: +https://www.helixcommunity.org/content/complicense + + EXHIBIT C + +RealNetworks' Trademark policy. + +RealNetworks defines the following trademarks collectively as "Licensor +Trademarks": "RealNetworks", "RealPlayer", "RealJukebox", "RealSystem", +"RealAudio", "RealVideo", "RealOne Player", "RealMedia", "Helix" or any other +trademarks or trade names belonging to RealNetworks. + +RealNetworks "Licensor Trademark Policy" forbids any use of Licensor Trademarks +except as permitted by and in strict compliance at all times with RealNetworks' +third party trademark usage guidelines which are posted at +http://www.realnetworks.com/info/helixlogo.html. + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/mp3dec.dsp b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/mp3dec.dsp new file mode 100644 index 0000000..368124a --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/mp3dec.dsp @@ -0,0 +1,158 @@ +# Microsoft Developer Studio Project File - Name="mp3dec" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=mp3dec - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "mp3dec.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mp3dec.mak" CFG="mp3dec - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "mp3dec - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "mp3dec - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "mp3dec - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "release" +# PROP Intermediate_Dir "rel_obj" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\..\..\..\..\common\include" /I "..\.." /I "..\..\..\pub" /I "..\..\..\..\..\..\..\common\runtime\pub" /D "NDEBUG" /D "REL_ENABLE_ASSERTS" /D "_WINDOWS" /D "_LIB" /D "WIN32" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "mp3dec - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "debug" +# PROP Intermediate_Dir "debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\..\..\..\..\common\include" /I "..\.." /I "..\..\..\pub" /I "..\..\..\..\..\..\..\common\runtime\pub" /D "_DEBUG" /D "_LIB" /D "WIN32" /D "_MBCS" /D "_WINDOWS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "mp3dec - Win32 Release" +# Name "mp3dec - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "general" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\mp3dec.c +# End Source File +# Begin Source File + +SOURCE=..\..\..\mp3tabs.c +# End Source File +# End Group +# Begin Group "csource" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\bitstream.c +# End Source File +# Begin Source File + +SOURCE=..\..\buffers.c +# End Source File +# Begin Source File + +SOURCE=..\..\dct32.c +# End Source File +# Begin Source File + +SOURCE=..\..\dequant.c +# End Source File +# Begin Source File + +SOURCE=..\..\dqchan.c +# End Source File +# Begin Source File + +SOURCE=..\..\huffman.c +# End Source File +# Begin Source File + +SOURCE=..\..\hufftabs.c +# End Source File +# Begin Source File + +SOURCE=..\..\imdct.c +# End Source File +# Begin Source File + +SOURCE=..\..\polyphase.c +# End Source File +# Begin Source File + +SOURCE=..\..\scalfact.c +# End Source File +# Begin Source File + +SOURCE=..\..\stproc.c +# End Source File +# Begin Source File + +SOURCE=..\..\subband.c +# End Source File +# Begin Source File + +SOURCE=..\..\trigtabs.c +# End Source File +# End Group +# End Group +# End Target +# End Project diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/mp3dec.dsw b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/mp3dec.dsw new file mode 100644 index 0000000..e4fef3d --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/mp3dec.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "mp3dec"=.\mp3dec.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "testwrap"=.\testwrap.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name mp3dec + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/testwrap.dsp b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/testwrap.dsp new file mode 100644 index 0000000..f92b9d6 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/projects/visualc/testwrap.dsp @@ -0,0 +1,174 @@ +# Microsoft Developer Studio Project File - Name="testwrap" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=testwrap - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "testwrap.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "testwrap.mak" CFG="testwrap - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "testwrap - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "testwrap - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "testwrap - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "release" +# PROP Intermediate_Dir "rel_obj" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\..\pub" /D "NDEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /D "HELIX_FEATURE_AUDIO_MPA_LAYER3" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"release\mp3dec.exe" + +!ELSEIF "$(CFG)" == "testwrap - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "debug" +# PROP Intermediate_Dir "debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\pub" /D "_DEBUG" /D "_CONSOLE" /D "WIN32" /D "_MBCS" /D "HELIX_FEATURE_AUDIO_MPA_LAYER3" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"debug\mp3dec.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "testwrap - Win32 Release" +# Name "testwrap - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "cppwrapper" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\mpadecobj.cpp + +!IF "$(CFG)" == "testwrap - Win32 Release" + +# ADD CPP /I "..\..\..\testwrap\cppshim" + +!ELSEIF "$(CFG)" == "testwrap - Win32 Debug" + +# PROP Exclude_From_Build 1 +# ADD CPP /I "..\..\..\testwrap\cppshim" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\testwrap\winmain.cpp + +!IF "$(CFG)" == "testwrap - Win32 Release" + +!ELSEIF "$(CFG)" == "testwrap - Win32 Debug" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# End Group +# Begin Group "cwrapper" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\testwrap\main.c + +!IF "$(CFG)" == "testwrap - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "testwrap - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\..\..\testwrap\timing.c + +!IF "$(CFG)" == "testwrap - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "testwrap - Win32 Debug" + +!ENDIF + +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\testwrap\debug.c + +!IF "$(CFG)" == "testwrap - Win32 Release" + +!ELSEIF "$(CFG)" == "testwrap - Win32 Debug" + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/scalfact.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/scalfact.c new file mode 100644 index 0000000..ca921eb --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/scalfact.c @@ -0,0 +1,391 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * scalfact.c - scalefactor unpacking functions + **************************************************************************************/ + +#include "coder.h" + +/* scale factor lengths (num bits) */ +static const char SFLenTab[16][2] = { + {0, 0}, {0, 1}, + {0, 2}, {0, 3}, + {3, 0}, {1, 1}, + {1, 2}, {1, 3}, + {2, 1}, {2, 2}, + {2, 3}, {3, 1}, + {3, 2}, {3, 3}, + {4, 2}, {4, 3}, +}; + +/************************************************************************************** + * Function: UnpackSFMPEG1 + * + * Description: unpack MPEG 1 scalefactors from bitstream + * + * Inputs: BitStreamInfo, SideInfoSub, ScaleFactorInfoSub structs for this + * granule/channel + * vector of scfsi flags from side info, length = 4 (MAX_SCFBD) + * index of current granule + * ScaleFactorInfoSub from granule 0 (for granule 1, if scfsi[i] is set, + * then we just replicate the scale factors from granule 0 in the + * i'th set of scalefactor bands) + * + * Outputs: updated BitStreamInfo struct + * scalefactors in sfis (short and/or long arrays, as appropriate) + * + * Return: none + * + * Notes: set order of short blocks to s[band][window] instead of s[window][band] + * so that we index through consectutive memory locations when unpacking + * (make sure dequantizer follows same convention) + * Illegal Intensity Position = 7 (always) for MPEG1 scale factors + **************************************************************************************/ +static void UnpackSFMPEG1(BitStreamInfo *bsi, SideInfoSub *sis, ScaleFactorInfoSub *sfis, int *scfsi, int gr, ScaleFactorInfoSub *sfisGr0) +{ + int sfb; + int slen0, slen1; + + /* these can be 0, so make sure GetBits(bsi, 0) returns 0 (no >> 32 or anything) */ + slen0 = (int)SFLenTab[sis->sfCompress][0]; + slen1 = (int)SFLenTab[sis->sfCompress][1]; + + if (sis->blockType == 2) { + /* short block, type 2 (implies winSwitchFlag == 1) */ + if (sis->mixedBlock) { + /* do long block portion */ + for (sfb = 0; sfb < 8; sfb++) + sfis->l[sfb] = (char)GetBits(bsi, slen0); + sfb = 3; + } else { + /* all short blocks */ + sfb = 0; + } + + for ( ; sfb < 6; sfb++) { + sfis->s[sfb][0] = (char)GetBits(bsi, slen0); + sfis->s[sfb][1] = (char)GetBits(bsi, slen0); + sfis->s[sfb][2] = (char)GetBits(bsi, slen0); + } + + for ( ; sfb < 12; sfb++) { + sfis->s[sfb][0] = (char)GetBits(bsi, slen1); + sfis->s[sfb][1] = (char)GetBits(bsi, slen1); + sfis->s[sfb][2] = (char)GetBits(bsi, slen1); + } + + /* last sf band not transmitted */ + sfis->s[12][0] = sfis->s[12][1] = sfis->s[12][2] = 0; + } else { + /* long blocks, type 0, 1, or 3 */ + if(gr == 0) { + /* first granule */ + for (sfb = 0; sfb < 11; sfb++) + sfis->l[sfb] = (char)GetBits(bsi, slen0); + for (sfb = 11; sfb < 21; sfb++) + sfis->l[sfb] = (char)GetBits(bsi, slen1); + return; + } else { + /* second granule + * scfsi: 0 = different scalefactors for each granule, 1 = copy sf's from granule 0 into granule 1 + * for block type == 2, scfsi is always 0 + */ + sfb = 0; + if(scfsi[0]) for( ; sfb < 6 ; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else for( ; sfb < 6 ; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen0); + if(scfsi[1]) for( ; sfb <11 ; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else for( ; sfb <11 ; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen0); + if(scfsi[2]) for( ; sfb <16 ; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else for( ; sfb <16 ; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen1); + if(scfsi[3]) for( ; sfb <21 ; sfb++) sfis->l[sfb] = sfisGr0->l[sfb]; + else for( ; sfb <21 ; sfb++) sfis->l[sfb] = (char)GetBits(bsi, slen1); + } + /* last sf band not transmitted */ + sfis->l[21] = 0; + sfis->l[22] = 0; + } +} + +/* NRTab[size + 3*is_right][block type][partition] + * block type index: 0 = (bt0,bt1,bt3), 1 = bt2 non-mixed, 2 = bt2 mixed + * partition: scale factor groups (sfb1 through sfb4) + * for block type = 2 (mixed or non-mixed) / by 3 is rolled into this table + * (for 3 short blocks per long block) + * see 2.4.3.2 in MPEG 2 (low sample rate) spec + * stuff rolled into this table: + * NRTab[x][1][y] --> (NRTab[x][1][y]) / 3 + * NRTab[x][2][>=1] --> (NRTab[x][2][>=1]) / 3 (first partition is long block) + */ +static const char NRTab[6][3][4] = { + /* non-intensity stereo */ + { {6, 5, 5, 5}, + {3, 3, 3, 3}, /* includes / 3 */ + {6, 3, 3, 3}, /* includes / 3 except for first entry */ + }, + { {6, 5, 7, 3}, + {3, 3, 4, 2}, + {6, 3, 4, 2}, + }, + { {11, 10, 0, 0}, + {6, 6, 0, 0}, + {6, 3, 6, 0}, /* spec = [15,18,0,0], but 15 = 6L + 9S, so move 9/3=3 into col 1, 18/3=6 into col 2 and adj. slen[1,2] below */ + }, + /* intensity stereo, right chan */ + { {7, 7, 7, 0}, + {4, 4, 4, 0}, + {6, 5, 4, 0}, + }, + { {6, 6, 6, 3}, + {4, 3, 3, 2}, + {6, 4, 3, 2}, + }, + { {8, 8, 5, 0}, + {5, 4, 3, 0}, + {6, 6, 3, 0}, + } +}; + +/************************************************************************************** + * Function: UnpackSFMPEG2 + * + * Description: unpack MPEG 2 scalefactors from bitstream + * + * Inputs: BitStreamInfo, SideInfoSub, ScaleFactorInfoSub structs for this + * granule/channel + * index of current granule and channel + * ScaleFactorInfoSub from this granule + * modeExt field from frame header, to tell whether intensity stereo is on + * ScaleFactorJS struct for storing IIP info used in Dequant() + * + * Outputs: updated BitStreamInfo struct + * scalefactors in sfis (short and/or long arrays, as appropriate) + * updated intensityScale and preFlag flags + * + * Return: none + * + * Notes: Illegal Intensity Position = (2^slen) - 1 for MPEG2 scale factors + * + * TODO: optimize the / and % stuff (only do one divide, get modulo x + * with (x / m) * m, etc.) + **************************************************************************************/ +static void UnpackSFMPEG2(BitStreamInfo *bsi, SideInfoSub *sis, ScaleFactorInfoSub *sfis, int gr, int ch, int modeExt, ScaleFactorJS *sfjs) +{ + + int i, sfb, sfcIdx, btIdx, nrIdx, iipTest; + int slen[4], nr[4]; + int sfCompress, preFlag, intensityScale; + + sfCompress = sis->sfCompress; + preFlag = 0; + intensityScale = 0; + + /* stereo mode bits (1 = on): bit 1 = mid-side on/off, bit 0 = intensity on/off */ + if (! ((modeExt & 0x01) && (ch == 1)) ) { + /* in other words: if ((modeExt & 0x01) == 0 || ch == 0) */ + if (sfCompress < 400) { + /* max slen = floor[(399/16) / 5] = 4 */ + slen[0] = (sfCompress >> 4) / 5; + slen[1]= (sfCompress >> 4) % 5; + slen[2]= (sfCompress & 0x0f) >> 2; + slen[3]= (sfCompress & 0x03); + sfcIdx = 0; + } else if (sfCompress < 500) { + /* max slen = floor[(99/4) / 5] = 4 */ + sfCompress -= 400; + slen[0] = (sfCompress >> 2) / 5; + slen[1]= (sfCompress >> 2) % 5; + slen[2]= (sfCompress & 0x03); + slen[3]= 0; + sfcIdx = 1; + } else { + /* max slen = floor[11/3] = 3 (sfCompress = 9 bits in MPEG2) */ + sfCompress -= 500; + slen[0] = sfCompress / 3; + slen[1] = sfCompress % 3; + slen[2] = slen[3] = 0; + if (sis->mixedBlock) { + /* adjust for long/short mix logic (see comment above in NRTab[] definition) */ + slen[2] = slen[1]; + slen[1] = slen[0]; + } + preFlag = 1; + sfcIdx = 2; + } + } else { + /* intensity stereo ch = 1 (right) */ + intensityScale = sfCompress & 0x01; + sfCompress >>= 1; + if (sfCompress < 180) { + /* max slen = floor[35/6] = 5 (from mod 36) */ + slen[0] = (sfCompress / 36); + slen[1] = (sfCompress % 36) / 6; + slen[2] = (sfCompress % 36) % 6; + slen[3] = 0; + sfcIdx = 3; + } else if (sfCompress < 244) { + /* max slen = floor[63/16] = 3 */ + sfCompress -= 180; + slen[0] = (sfCompress & 0x3f) >> 4; + slen[1] = (sfCompress & 0x0f) >> 2; + slen[2] = (sfCompress & 0x03); + slen[3] = 0; + sfcIdx = 4; + } else { + /* max slen = floor[11/3] = 3 (max sfCompress >> 1 = 511/2 = 255) */ + sfCompress -= 244; + slen[0] = (sfCompress / 3); + slen[1] = (sfCompress % 3); + slen[2] = slen[3] = 0; + sfcIdx = 5; + } + } + + /* set index based on block type: (0,1,3) --> 0, (2 non-mixed) --> 1, (2 mixed) ---> 2 */ + btIdx = 0; + if (sis->blockType == 2) + btIdx = (sis->mixedBlock ? 2 : 1); + for (i = 0; i < 4; i++) + nr[i] = (int)NRTab[sfcIdx][btIdx][i]; + + /* save intensity stereo scale factor info */ + if( (modeExt & 0x01) && (ch == 1) ) { + for (i = 0; i < 4; i++) { + sfjs->slen[i] = slen[i]; + sfjs->nr[i] = nr[i]; + } + sfjs->intensityScale = intensityScale; + } + sis->preFlag = preFlag; + + /* short blocks */ + if(sis->blockType == 2) { + if(sis->mixedBlock) { + /* do long block portion */ + iipTest = (1 << slen[0]) - 1; + for (sfb=0; sfb < 6; sfb++) { + sfis->l[sfb] = (char)GetBits(bsi, slen[0]); + } + sfb = 3; /* start sfb for short */ + nrIdx = 1; + } else { + /* all short blocks, so start nr, sfb at 0 */ + sfb = 0; + nrIdx = 0; + } + + /* remaining short blocks, sfb just keeps incrementing */ + for ( ; nrIdx <= 3; nrIdx++) { + iipTest = (1 << slen[nrIdx]) - 1; + for (i=0; i < nr[nrIdx]; i++, sfb++) { + sfis->s[sfb][0] = (char)GetBits(bsi, slen[nrIdx]); + sfis->s[sfb][1] = (char)GetBits(bsi, slen[nrIdx]); + sfis->s[sfb][2] = (char)GetBits(bsi, slen[nrIdx]); + } + } + /* last sf band not transmitted */ + sfis->s[12][0] = sfis->s[12][1] = sfis->s[12][2] = 0; + } else { + /* long blocks */ + sfb = 0; + for (nrIdx = 0; nrIdx <= 3; nrIdx++) { + iipTest = (1 << slen[nrIdx]) - 1; + for(i=0; i < nr[nrIdx]; i++, sfb++) { + sfis->l[sfb] = (char)GetBits(bsi, slen[nrIdx]); + } + } + /* last sf band not transmitted */ + sfis->l[21] = sfis->l[22] = 0; + + } +} + +/************************************************************************************** + * Function: UnpackScaleFactors + * + * Description: parse the fields of the MP3 scale factor data section + * + * Inputs: MP3DecInfo structure filled by UnpackFrameHeader() and UnpackSideInfo() + * buffer pointing to the MP3 scale factor data + * pointer to bit offset (0-7) indicating starting bit in buf[0] + * number of bits available in data buffer + * index of current granule and channel + * + * Outputs: updated platform-specific ScaleFactorInfo struct + * updated bitOffset + * + * Return: length (in bytes) of scale factor data, -1 if null input pointers + **************************************************************************************/ +int UnpackScaleFactors(MP3DecInfo *mp3DecInfo, unsigned char *buf, int *bitOffset, int bitsAvail, int gr, int ch) +{ + int bitsUsed; + unsigned char *startBuf; + BitStreamInfo bitStreamInfo, *bsi; + FrameHeader *fh; + SideInfo *si; + ScaleFactorInfo *sfi; + + /* validate pointers */ + if (!mp3DecInfo || !mp3DecInfo->FrameHeaderPS || !mp3DecInfo->SideInfoPS || !mp3DecInfo->ScaleFactorInfoPS) + return -1; + fh = ((FrameHeader *)(mp3DecInfo->FrameHeaderPS)); + si = ((SideInfo *)(mp3DecInfo->SideInfoPS)); + sfi = ((ScaleFactorInfo *)(mp3DecInfo->ScaleFactorInfoPS)); + + /* init GetBits reader */ + startBuf = buf; + bsi = &bitStreamInfo; + SetBitstreamPointer(bsi, (bitsAvail + *bitOffset + 7) / 8, buf); + if (*bitOffset) + GetBits(bsi, *bitOffset); + + if (fh->ver == MPEG1) + UnpackSFMPEG1(bsi, &si->sis[gr][ch], &sfi->sfis[gr][ch], si->scfsi[ch], gr, &sfi->sfis[0][ch]); + else + UnpackSFMPEG2(bsi, &si->sis[gr][ch], &sfi->sfis[gr][ch], gr, ch, fh->modeExt, &sfi->sfjs); + + mp3DecInfo->part23Length[gr][ch] = si->sis[gr][ch].part23Length; + + bitsUsed = CalcBitsUsed(bsi, buf, *bitOffset); + buf += (bitsUsed + *bitOffset) >> 3; + *bitOffset = (bitsUsed + *bitOffset) & 0x07; + + return (buf - startBuf); +} + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/stproc.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/stproc.c new file mode 100644 index 0000000..4f6a751 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/stproc.c @@ -0,0 +1,296 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * stproc.c - mid-side and intensity (MPEG1 and MPEG2) stereo processing + **************************************************************************************/ + +#include "coder.h" +#include "assembly.h" + +/************************************************************************************** + * Function: MidSideProc + * + * Description: sum-difference stereo reconstruction + * + * Inputs: vector x with dequantized samples from left and right channels + * number of non-zero samples (MAX of left and right) + * assume 1 guard bit in input + * guard bit mask (left and right channels) + * + * Outputs: updated sample vector x + * updated guard bit mask + * + * Return: none + * + * Notes: assume at least 1 GB in input + **************************************************************************************/ +void MidSideProc(int x[MAX_NCHAN][MAX_NSAMP], int nSamps, int mOut[2]) +{ + int i, xr, xl, mOutL, mOutR; + + /* L = (M+S)/sqrt(2), R = (M-S)/sqrt(2) + * NOTE: 1/sqrt(2) done in DequantChannel() - see comments there + */ + mOutL = mOutR = 0; + for(i = 0; i < nSamps; i++) { + xl = x[0][i]; + xr = x[1][i]; + x[0][i] = xl + xr; + x[1][i] = xl - xr; + mOutL |= FASTABS(x[0][i]); + mOutR |= FASTABS(x[1][i]); + } + mOut[0] |= mOutL; + mOut[1] |= mOutR; +} + +/************************************************************************************** + * Function: IntensityProcMPEG1 + * + * Description: intensity stereo processing for MPEG1 + * + * Inputs: vector x with dequantized samples from left and right channels + * number of non-zero samples in left channel + * valid FrameHeader struct + * two each of ScaleFactorInfoSub, CriticalBandInfo structs (both channels) + * flags indicating midSide on/off, mixedBlock on/off + * guard bit mask (left and right channels) + * + * Outputs: updated sample vector x + * updated guard bit mask + * + * Return: none + * + * Notes: assume at least 1 GB in input + * + * TODO: combine MPEG1/2 into one function (maybe) + * make sure all the mixed-block and IIP logic is right + **************************************************************************************/ +void IntensityProcMPEG1(int x[MAX_NCHAN][MAX_NSAMP], int nSamps, FrameHeader *fh, ScaleFactorInfoSub *sfis, + CriticalBandInfo *cbi, int midSideFlag, int mixFlag, int mOut[2]) +{ + int i=0, j=0, n=0, cb=0, w=0; + int sampsLeft, isf, mOutL, mOutR, xl, xr; + int fl, fr, fls[3], frs[3]; + int cbStartL=0, cbStartS=0, cbEndL=0, cbEndS=0; + int *isfTab; + + /* NOTE - this works fine for mixed blocks, as long as the switch point starts in the + * short block section (i.e. on or after sample 36 = sfBand->l[8] = 3*sfBand->s[3] + * is this a safe assumption? + * TODO - intensity + mixed not quite right (diff = 11 on he_mode) + * figure out correct implementation (spec ambiguous about when to do short block reorder) + */ + if (cbi[1].cbType == 0) { + /* long block */ + cbStartL = cbi[1].cbEndL + 1; + cbEndL = cbi[0].cbEndL + 1; + cbStartS = cbEndS = 0; + i = fh->sfBand->l[cbStartL]; + } else if (cbi[1].cbType == 1 || cbi[1].cbType == 2) { + /* short or mixed block */ + cbStartS = cbi[1].cbEndSMax + 1; + cbEndS = cbi[0].cbEndSMax + 1; + cbStartL = cbEndL = 0; + i = 3 * fh->sfBand->s[cbStartS]; + } + + sampsLeft = nSamps - i; /* process to length of left */ + isfTab = (int *)ISFMpeg1[midSideFlag]; + mOutL = mOutR = 0; + + /* long blocks */ + for (cb = cbStartL; cb < cbEndL && sampsLeft > 0; cb++) { + isf = sfis->l[cb]; + if (isf == 7) { + fl = ISFIIP[midSideFlag][0]; + fr = ISFIIP[midSideFlag][1]; + } else { + fl = isfTab[isf]; + fr = isfTab[6] - isfTab[isf]; + } + + n = fh->sfBand->l[cb + 1] - fh->sfBand->l[cb]; + for (j = 0; j < n && sampsLeft > 0; j++, i++) { + xr = MULSHIFT32(fr, x[0][i]) << 2; x[1][i] = xr; mOutR |= FASTABS(xr); + xl = MULSHIFT32(fl, x[0][i]) << 2; x[0][i] = xl; mOutL |= FASTABS(xl); + sampsLeft--; + } + } + + /* short blocks */ + for (cb = cbStartS; cb < cbEndS && sampsLeft >= 3; cb++) { + for (w = 0; w < 3; w++) { + isf = sfis->s[cb][w]; + if (isf == 7) { + fls[w] = ISFIIP[midSideFlag][0]; + frs[w] = ISFIIP[midSideFlag][1]; + } else { + fls[w] = isfTab[isf]; + frs[w] = isfTab[6] - isfTab[isf]; + } + } + + n = fh->sfBand->s[cb + 1] - fh->sfBand->s[cb]; + for (j = 0; j < n && sampsLeft >= 3; j++, i+=3) { + xr = MULSHIFT32(frs[0], x[0][i+0]) << 2; x[1][i+0] = xr; mOutR |= FASTABS(xr); + xl = MULSHIFT32(fls[0], x[0][i+0]) << 2; x[0][i+0] = xl; mOutL |= FASTABS(xl); + xr = MULSHIFT32(frs[1], x[0][i+1]) << 2; x[1][i+1] = xr; mOutR |= FASTABS(xr); + xl = MULSHIFT32(fls[1], x[0][i+1]) << 2; x[0][i+1] = xl; mOutL |= FASTABS(xl); + xr = MULSHIFT32(frs[2], x[0][i+2]) << 2; x[1][i+2] = xr; mOutR |= FASTABS(xr); + xl = MULSHIFT32(fls[2], x[0][i+2]) << 2; x[0][i+2] = xl; mOutL |= FASTABS(xl); + sampsLeft -= 3; + } + } + mOut[0] = mOutL; + mOut[1] = mOutR; + + return; +} + +/************************************************************************************** + * Function: IntensityProcMPEG2 + * + * Description: intensity stereo processing for MPEG2 + * + * Inputs: vector x with dequantized samples from left and right channels + * number of non-zero samples in left channel + * valid FrameHeader struct + * two each of ScaleFactorInfoSub, CriticalBandInfo structs (both channels) + * ScaleFactorJS struct with joint stereo info from UnpackSFMPEG2() + * flags indicating midSide on/off, mixedBlock on/off + * guard bit mask (left and right channels) + * + * Outputs: updated sample vector x + * updated guard bit mask + * + * Return: none + * + * Notes: assume at least 1 GB in input + * + * TODO: combine MPEG1/2 into one function (maybe) + * make sure all the mixed-block and IIP logic is right + * probably redo IIP logic to be simpler + **************************************************************************************/ +void IntensityProcMPEG2(int x[MAX_NCHAN][MAX_NSAMP], int nSamps, FrameHeader *fh, ScaleFactorInfoSub *sfis, + CriticalBandInfo *cbi, ScaleFactorJS *sfjs, int midSideFlag, int mixFlag, int mOut[2]) +{ + int i, j, k, n, r, cb, w; + int fl, fr, mOutL, mOutR, xl, xr; + int sampsLeft; + int isf, sfIdx, tmp, il[23]; + int *isfTab; + int cbStartL, cbStartS, cbEndL, cbEndS; + + isfTab = (int *)ISFMpeg2[sfjs->intensityScale][midSideFlag]; + mOutL = mOutR = 0; + + /* fill buffer with illegal intensity positions (depending on slen) */ + for (k = r = 0; r < 4; r++) { + tmp = (1 << sfjs->slen[r]) - 1; + for (j = 0; j < sfjs->nr[r]; j++, k++) + il[k] = tmp; + } + + if (cbi[1].cbType == 0) { + /* long blocks */ + il[21] = il[22] = 1; + cbStartL = cbi[1].cbEndL + 1; /* start at end of right */ + cbEndL = cbi[0].cbEndL + 1; /* process to end of left */ + i = fh->sfBand->l[cbStartL]; + sampsLeft = nSamps - i; + + for(cb = cbStartL; cb < cbEndL; cb++) { + sfIdx = sfis->l[cb]; + if (sfIdx == il[cb]) { + fl = ISFIIP[midSideFlag][0]; + fr = ISFIIP[midSideFlag][1]; + } else { + isf = (sfis->l[cb] + 1) >> 1; + fl = isfTab[(sfIdx & 0x01 ? isf : 0)]; + fr = isfTab[(sfIdx & 0x01 ? 0 : isf)]; + } + n = MIN(fh->sfBand->l[cb + 1] - fh->sfBand->l[cb], sampsLeft); + + for(j = 0; j < n; j++, i++) { + xr = MULSHIFT32(fr, x[0][i]) << 2; x[1][i] = xr; mOutR |= FASTABS(xr); + xl = MULSHIFT32(fl, x[0][i]) << 2; x[0][i] = xl; mOutL |= FASTABS(xl); + } + + /* early exit once we've used all the non-zero samples */ + sampsLeft -= n; + if (sampsLeft == 0) + break; + } + } else { + /* short or mixed blocks */ + il[12] = 1; + + for(w = 0; w < 3; w++) { + cbStartS = cbi[1].cbEndS[w] + 1; /* start at end of right */ + cbEndS = cbi[0].cbEndS[w] + 1; /* process to end of left */ + i = 3 * fh->sfBand->s[cbStartS] + w; + + /* skip through sample array by 3, so early-exit logic would be more tricky */ + for(cb = cbStartS; cb < cbEndS; cb++) { + sfIdx = sfis->s[cb][w]; + if (sfIdx == il[cb]) { + fl = ISFIIP[midSideFlag][0]; + fr = ISFIIP[midSideFlag][1]; + } else { + isf = (sfis->s[cb][w] + 1) >> 1; + fl = isfTab[(sfIdx & 0x01 ? isf : 0)]; + fr = isfTab[(sfIdx & 0x01 ? 0 : isf)]; + } + n = fh->sfBand->s[cb + 1] - fh->sfBand->s[cb]; + + for(j = 0; j < n; j++, i+=3) { + xr = MULSHIFT32(fr, x[0][i]) << 2; x[1][i] = xr; mOutR |= FASTABS(xr); + xl = MULSHIFT32(fl, x[0][i]) << 2; x[0][i] = xl; mOutL |= FASTABS(xl); + } + } + } + } + mOut[0] = mOutL; + mOut[1] = mOutR; + + return; +} + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/subband.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/subband.c new file mode 100644 index 0000000..c0e6c3d --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/subband.c @@ -0,0 +1,96 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * subband.c - subband transform (synthesis filterbank implemented via 32-point DCT + * followed by polyphase filter) + **************************************************************************************/ + +#include "coder.h" +#include "assembly.h" + +/************************************************************************************** + * Function: Subband + * + * Description: do subband transform on all the blocks in one granule, all channels + * + * Inputs: filled MP3DecInfo structure, after calling IMDCT for all channels + * vbuf[ch] and vindex[ch] must be preserved between calls + * + * Outputs: decoded PCM data, interleaved LRLRLR... if stereo + * + * Return: 0 on success, -1 if null input pointers + **************************************************************************************/ +int Subband(MP3DecInfo *mp3DecInfo, short *pcmBuf) +{ + int b; + HuffmanInfo *hi; + IMDCTInfo *mi; + SubbandInfo *sbi; + + /* validate pointers */ + if (!mp3DecInfo || !mp3DecInfo->HuffmanInfoPS || !mp3DecInfo->IMDCTInfoPS || !mp3DecInfo->SubbandInfoPS) + return -1; + + hi = (HuffmanInfo *)mp3DecInfo->HuffmanInfoPS; + mi = (IMDCTInfo *)(mp3DecInfo->IMDCTInfoPS); + sbi = (SubbandInfo*)(mp3DecInfo->SubbandInfoPS); + + if (mp3DecInfo->nChans == 2) { + /* stereo */ + for (b = 0; b < BLOCK_SIZE; b++) { + FDCT32(mi->outBuf[0][b], sbi->vbuf + 0*32, sbi->vindex, (b & 0x01), mi->gb[0]); + FDCT32(mi->outBuf[1][b], sbi->vbuf + 1*32, sbi->vindex, (b & 0x01), mi->gb[1]); + PolyphaseStereo(pcmBuf, sbi->vbuf + sbi->vindex + VBUF_LENGTH * (b & 0x01), polyCoef); + sbi->vindex = (sbi->vindex - (b & 0x01)) & 7; + pcmBuf += (2 * NBANDS); + } + } else { + /* mono */ + for (b = 0; b < BLOCK_SIZE; b++) { + FDCT32(mi->outBuf[0][b], sbi->vbuf + 0*32, sbi->vindex, (b & 0x01), mi->gb[0]); + PolyphaseMono(pcmBuf, sbi->vbuf + sbi->vindex + VBUF_LENGTH * (b & 0x01), polyCoef); + sbi->vindex = (sbi->vindex - (b & 0x01)) & 7; + pcmBuf += NBANDS; + } + } + + return 0; +} + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/trigtabs.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/trigtabs.c new file mode 100644 index 0000000..13a6a8a --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/real/trigtabs.c @@ -0,0 +1,314 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * trigtabs.c - global ROM tables for pre-calculated trig coefficients + **************************************************************************************/ + +// constants in RAM are not significantly faster + +#include "coder.h" + +/* post-IMDCT window, win[blockType][i] + * format = Q31 + * Fused sin window with final stage of IMDCT + * includes 1/sqrt(2) scaling, since we scale by sqrt(2) in dequant in order + * for fast IMDCT36 to be usable + * + * for(i=0;i<9;i++) win[0][i] = sin(pi/36 *(i+0.5)); + * for(i=9;i<36;i++) win[0][i] = -sin(pi/36 *(i+0.5)); + * + * for(i=0;i<9;i++) win[1][i] = sin(pi/36 *(i+0.5)); + * for(i=9;i<18;i++) win[1][i] = -sin(pi/36 *(i+0.5)); + * for(i=18;i<24;i++) win[1][i] = -1; + * for(i=24;i<30;i++) win[1][i] = -sin(pi/12 *(i+0.5-18)); + * for(i=30;i<36;i++) win[1][i] = 0; + * + * for(i=0;i<6;i++) win[3][i] = 0; + * for(i=6;i<9;i++) win[3][i] = sin(pi/12 *(i+0.5-6)); + * for(i=9;i<12;i++) win[3][i] = -sin(pi/12 *(i+0.5-6)); + * for(i=12;i<18;i++) win[3][i] = -1; + * for(i=18;i<36;i++) win[3][i] = -sin(pi/36*(i+0.5)); + * + * for(i=0;i<3;i++) win[2][i] = sin(pi/12*(i+0.5)); + * for(i=3;i<12;i++) win[2][i] = -sin(pi/12*(i+0.5)); + * for(i=12;i<36;i++) win[2][i] = 0; + * + * for (i = 0; i < 4; i++) { + * if (i == 2) { + * win[i][8] *= cos(pi/12 * (0+0.5)); + * win[i][9] *= cos(pi/12 * (0+0.5)); + * win[i][7] *= cos(pi/12 * (1+0.5)); + * win[i][10] *= cos(pi/12 * (1+0.5)); + * win[i][6] *= cos(pi/12 * (2+0.5)); + * win[i][11] *= cos(pi/12 * (2+0.5)); + * win[i][0] *= cos(pi/12 * (3+0.5)); + * win[i][5] *= cos(pi/12 * (3+0.5)); + * win[i][1] *= cos(pi/12 * (4+0.5)); + * win[i][4] *= cos(pi/12 * (4+0.5)); + * win[i][2] *= cos(pi/12 * (5+0.5)); + * win[i][3] *= cos(pi/12 * (5+0.5)); + * } else { + * for (j = 0; j < 9; j++) { + * win[i][8-j] *= cos(pi/36 * (17-j+0.5)); + * win[i][9+j] *= cos(pi/36 * (17-j+0.5)); + * } + * for (j = 0; j < 9; j++) { + * win[i][18+8-j] *= cos(pi/36 * (j+0.5)); + * win[i][18+9+j] *= cos(pi/36 * (j+0.5)); + * } + * } + * } + * for (i = 0; i < 4; i++) + * for (j = 0; j < 36; j++) + * win[i][j] *= 1.0 / sqrt(2); + */ + +const int imdctWin[4][36] = { + { + 0x02aace8b, 0x07311c28, 0x0a868fec, 0x0c913b52, 0x0d413ccd, 0x0c913b52, 0x0a868fec, 0x07311c28, + 0x02aace8b, 0xfd16d8dd, 0xf6a09e66, 0xef7a6275, 0xe7dbc161, 0xe0000000, 0xd8243e9f, 0xd0859d8b, + 0xc95f619a, 0xc2e92723, 0xbd553175, 0xb8cee3d8, 0xb5797014, 0xb36ec4ae, 0xb2bec333, 0xb36ec4ae, + 0xb5797014, 0xb8cee3d8, 0xbd553175, 0xc2e92723, 0xc95f619a, 0xd0859d8b, 0xd8243e9f, 0xe0000000, + 0xe7dbc161, 0xef7a6275, 0xf6a09e66, 0xfd16d8dd, + }, + { + 0x02aace8b, 0x07311c28, 0x0a868fec, 0x0c913b52, 0x0d413ccd, 0x0c913b52, 0x0a868fec, 0x07311c28, + 0x02aace8b, 0xfd16d8dd, 0xf6a09e66, 0xef7a6275, 0xe7dbc161, 0xe0000000, 0xd8243e9f, 0xd0859d8b, + 0xc95f619a, 0xc2e92723, 0xbd44ef14, 0xb831a052, 0xb3aa3837, 0xafb789a4, 0xac6145bb, 0xa9adecdc, + 0xa864491f, 0xad1868f0, 0xb8431f49, 0xc8f42236, 0xdda8e6b1, 0xf47755dc, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x07311c28, 0x0d413ccd, 0x07311c28, 0xf6a09e66, 0xe0000000, 0xc95f619a, 0xb8cee3d8, 0xb2bec333, + 0xb8cee3d8, 0xc95f619a, 0xe0000000, 0xf6a09e66, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }, + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x028e9709, 0x04855ec0, + 0x026743a1, 0xfcde2c10, 0xf515dc82, 0xec93e53b, 0xe4c880f8, 0xdd5d0b08, 0xd63510b7, 0xcf5e834a, + 0xc8e6b562, 0xc2da4105, 0xbd553175, 0xb8cee3d8, 0xb5797014, 0xb36ec4ae, 0xb2bec333, 0xb36ec4ae, + 0xb5797014, 0xb8cee3d8, 0xbd553175, 0xc2e92723, 0xc95f619a, 0xd0859d8b, 0xd8243e9f, 0xe0000000, + 0xe7dbc161, 0xef7a6275, 0xf6a09e66, 0xfd16d8dd, + }, +}; + +/* indexing = [mid-side off/on][intensity scale factor] + * format = Q30, range = [0.0, 1.414] + * + * mid-side off: + * ISFMpeg1[0][i] = tan(i*pi/12) / [1 + tan(i*pi/12)] (left scalefactor) + * = 1 / [1 + tan(i*pi/12)] (right scalefactor) + * + * mid-side on: + * ISFMpeg1[1][i] = sqrt(2) * ISFMpeg1[0][i] + * + * output L = ISFMpeg1[midSide][isf][0] * input L + * output R = ISFMpeg1[midSide][isf][1] * input L + * + * obviously left scalefactor + right scalefactor = 1 (m-s off) or sqrt(2) (m-s on) + * so just store left and calculate right as 1 - left + * (can derive as right = ISFMpeg1[x][6] - left) + * + * if mid-side enabled, multiply joint stereo scale factors by sqrt(2) + * - we scaled whole spectrum by 1/sqrt(2) in Dequant for the M+S/sqrt(2) in MidSideProc + * - but the joint stereo part of the spectrum doesn't need this, so we have to undo it + * + * if scale factor is and illegal intensity position, this becomes a passthrough + * - gain = [1, 0] if mid-side off, since L is coded directly and R = 0 in this region + * - gain = [1, 1] if mid-side on, since L = (M+S)/sqrt(2), R = (M-S)/sqrt(2) + * - and since S = 0 in the joint stereo region (above NZB right) then L = R = M * 1.0 + */ +const int ISFMpeg1[2][7] = { + {0x00000000, 0x0d8658ba, 0x176cf5d0, 0x20000000, 0x28930a2f, 0x3279a745, 0x40000000}, + {0x00000000, 0x13207f5c, 0x2120fb83, 0x2d413ccc, 0x39617e16, 0x4761fa3d, 0x5a827999} +}; + +/* indexing = [intensity scale on/off][mid-side off/on][intensity scale factor] + * format = Q30, range = [0.0, 1.414] + * + * if (isf == 0) kl = 1.0 kr = 1.0 + * else if (isf & 0x01 == 0x01) kl = i0^((isf+1)/2), kr = 1.0 + * else if (isf & 0x01 == 0x00) kl = 1.0, kr = i0^(isf/2) + * + * if (intensityScale == 1) i0 = 1/sqrt(2) = 0x2d413ccc (Q30) + * else i0 = 1/sqrt(sqrt(2)) = 0x35d13f32 (Q30) + * + * see comments for ISFMpeg1 (just above) regarding scaling, sqrt(2), etc. + * + * compress the MPEG2 table using the obvious identities above... + * for isf = [0, 1, 2, ... 30], let sf = table[(isf+1) >> 1] + * - if isf odd, L = sf*L, R = tab[0]*R + * - if isf even, L = tab[0]*L, R = sf*R + */ +const int ISFMpeg2[2][2][16] = { +{ + { + /* intensityScale off, mid-side off */ + 0x40000000, 0x35d13f32, 0x2d413ccc, 0x260dfc14, 0x1fffffff, 0x1ae89f99, 0x16a09e66, 0x1306fe0a, + 0x0fffffff, 0x0d744fcc, 0x0b504f33, 0x09837f05, 0x07ffffff, 0x06ba27e6, 0x05a82799, 0x04c1bf82, + }, + { + /* intensityScale off, mid-side on */ + 0x5a827999, 0x4c1bf827, 0x3fffffff, 0x35d13f32, 0x2d413ccc, 0x260dfc13, 0x1fffffff, 0x1ae89f99, + 0x16a09e66, 0x1306fe09, 0x0fffffff, 0x0d744fcc, 0x0b504f33, 0x09837f04, 0x07ffffff, 0x06ba27e6, + }, +}, +{ + { + /* intensityScale on, mid-side off */ + 0x40000000, 0x2d413ccc, 0x20000000, 0x16a09e66, 0x10000000, 0x0b504f33, 0x08000000, 0x05a82799, + 0x04000000, 0x02d413cc, 0x02000000, 0x016a09e6, 0x01000000, 0x00b504f3, 0x00800000, 0x005a8279, + }, + /* intensityScale on, mid-side on */ + { + 0x5a827999, 0x3fffffff, 0x2d413ccc, 0x1fffffff, 0x16a09e66, 0x0fffffff, 0x0b504f33, 0x07ffffff, + 0x05a82799, 0x03ffffff, 0x02d413cc, 0x01ffffff, 0x016a09e6, 0x00ffffff, 0x00b504f3, 0x007fffff, + } +} +}; + +/* indexing = [intensity scale on/off][left/right] + * format = Q30, range = [0.0, 1.414] + * + * illegal intensity position scalefactors (see comments on ISFMpeg1) + */ +const int ISFIIP[2][2] = { + {0x40000000, 0x00000000}, /* mid-side off */ + {0x40000000, 0x40000000}, /* mid-side on */ +}; + +const unsigned char uniqueIDTab[8] = {0x5f, 0x4b, 0x43, 0x5f, 0x5f, 0x4a, 0x52, 0x5f}; + +/* anti-alias coefficients - see spec Annex B, table 3-B.9 + * csa[0][i] = CSi, csa[1][i] = CAi + * format = Q31 + */ +const int csa[8][2] = { + {0x6dc253f0, 0xbe2500aa}, + {0x70dcebe4, 0xc39e4949}, + {0x798d6e73, 0xd7e33f4a}, + {0x7ddd40a7, 0xe8b71176}, + {0x7f6d20b7, 0xf3e4fe2f}, + {0x7fe47e40, 0xfac1a3c7}, + {0x7ffcb263, 0xfe2ebdc6}, + {0x7fffc694, 0xff86c25d}, +}; + +/* format = Q30, range = [0.0981, 1.9976] + * + * n = 16; + * k = 0; + * for(i=0; i<5; i++, n=n/2) { + * for(p=0; p. + +------------------------------------------------------------------------ + + + REALNETWORKS COMMUNITY SOURCE LICENSE + +Version 1.2 (Rev. Date: January 22, 2003). + + + RECITALS + +Original Contributor has developed Specifications, Source Code +implementations and Executables of certain Technology; and + +Original Contributor desires to license the Technology to a large +community to facilitate research, innovation and product development +while maintaining compatibility of such products with the Technology as +delivered by Original Contributor; and + +Original Contributor desires to license certain Trademarks for the +purpose of branding products that are compatible with the relevant +Technology delivered by Original Contributor; and + +You desire to license the Technology and possibly certain Trademarks +from Original Contributor on the terms and conditions specified in this +License. + +In consideration for the mutual covenants contained herein, You and +Original Contributor agree as follows: + + + AGREEMENT + +*1. Introduction.* + +The RealNetworks Community Source License ("RCSL") and effective +attachments ("License") may include five distinct licenses: + +i) Research Use license -- License plus Attachments A, B and C only. + +ii) Commercial Use and Trademark License, which may be for Internal +Deployment Use or external distribution, or both -- License plus +Attachments A, B, C, and D. + +iii) Technology Compatibility Kit (TCK) license -- Attachment C. + +iv) Add-On Technology License (Executable) Commercial Use License +-Attachment F. + +v) Add-On Technology Source Code Porting and Optimization +License-Attachment G. + +The Research Use license is effective when You click and accept this +License. The TCK is effective when You click and accept this License, +unless otherwise specified in the TCK attachments. The Commercial Use +and Trademark, Add-On Technology License, and the Add-On Technology +Source Code Porting and Optimization licenses must each be signed by You +and Original Contributor to become effective. Once effective, these +licenses and the associated requirements and responsibilities are +cumulative. Capitalized terms used in this License are defined in the +Glossary. + +*2. License Grants.* + +2.1 Original Contributor Grant. + +Subject to Your compliance with Sections 3, 8.10 and Attachment A of +this License, Original Contributor grants to You a worldwide, +royalty-free, non-exclusive license, to the extent of Original +Contributor's Intellectual Property Rights covering the Original Code, +Upgraded Code and Specifications, to do the following: + +(a) Research Use License: + +(i) use, reproduce and modify the Original Code, Upgraded Code and +Specifications to create Modifications and Reformatted Specifications +for Research Use by You; + +(ii) publish and display Original Code, Upgraded Code and Specifications +with, or as part of Modifications, as permitted under Section 3.1(b) below; + +(iii) reproduce and distribute copies of Original Code and Upgraded Code +to Licensees and students for Research Use by You; + +(iv) compile, reproduce and distribute Original Code and Upgraded Code +in Executable form, and Reformatted Specifications to anyone for +Research Use by You. + +(b) Other than the licenses expressly granted in this License, Original +Contributor retains all right, title, and interest in Original Code and +Upgraded Code and Specifications. + +2.2 Your Grants. + +(a) To Other Licensees. You hereby grant to each Licensee a license to +Your Error Corrections and Shared Modifications, of the same scope and +extent as Original Contributor's licenses under Section 2.1 a) above +relative to Research Use and Attachment D relative to Commercial Use. + +(b) To Original Contributor. You hereby grant to Original Contributor a +worldwide, royalty-free, non-exclusive, perpetual and irrevocable +license, to the extent of Your Intellectual Property Rights covering +Your Error Corrections, Shared Modifications and Reformatted +Specifications, to use, reproduce, modify, display and distribute Your +Error Corrections, Shared Modifications and Reformatted Specifications, +in any form, including the right to sublicense such rights through +multiple tiers of distribution. + +(c) Other than the licenses expressly granted in Sections 2.2(a) and (b) +above, and the restrictions set forth in Section 3.1(d)(iv) below, You +retain all right, title, and interest in Your Error Corrections, Shared +Modifications and Reformatted Specifications. + +2.3 Contributor Modifications. + +You may use, reproduce, modify, display and distribute Contributor Error +Corrections, Shared Modifications and Reformatted Specifications, +obtained by You under this License, to the same scope and extent as with +Original Code, Upgraded Code and Specifications. + +2.4 Subcontracting. + +You may deliver the Source Code of Covered Code to other Licensees +having at least a Research Use license, for the sole purpose of +furnishing development services to You in connection with Your rights +granted in this License. All such Licensees must execute appropriate +documents with respect to such work consistent with the terms of this +License, and acknowledging their work-made-for-hire status or assigning +exclusive right to the work product and associated Intellectual Property +Rights to You. + +*3. Requirements and Responsibilities*. + +3.1 Research Use License. + +As a condition of exercising the rights granted under Section 2.1(a) +above, You agree to comply with the following: + +(a) Your Contribution to the Community. All Error Corrections and Shared +Modifications which You create or contribute to are automatically +subject to the licenses granted under Section 2.2 above. You are +encouraged to license all of Your other Modifications under Section 2.2 +as Shared Modifications, but are not required to do so. You agree to +notify Original Contributor of any errors in the Specification. + +(b) Source Code Availability. You agree to provide all Your Error +Corrections to Original Contributor as soon as reasonably practicable +and, in any event, prior to Internal Deployment Use or Commercial Use, +if applicable. Original Contributor may, at its discretion, post Source +Code for Your Error Corrections and Shared Modifications on the +Community Webserver. You may also post Error Corrections and Shared +Modifications on a web-server of Your choice; provided, that You must +take reasonable precautions to ensure that only Licensees have access to +such Error Corrections and Shared Modifications. Such precautions shall +include, without limitation, a password protection scheme limited to +Licensees and a click-on, download certification of Licensee status +required of those attempting to download from the server. An example of +an acceptable certification is attached as Attachment A-2. + +(c) Notices. All Error Corrections and Shared Modifications You create +or contribute to must include a file documenting the additions and +changes You made and the date of such additions and changes. You must +also include the notice set forth in Attachment A-1 in the file header. +If it is not possible to put the notice in a particular Source Code file +due to its structure, then You must include the notice in a location +(such as a relevant directory file), where a recipient would be most +likely to look for such a notice. + +(d) Redistribution. + +(i) Source. Covered Code may be distributed in Source Code form only to +another Licensee (except for students as provided below). You may not +offer or impose any terms on any Covered Code that alter the rights, +requirements, or responsibilities of such Licensee. You may distribute +Covered Code to students for use in connection with their course work +and research projects undertaken at accredited educational institutions. +Such students need not be Licensees, but must be given a copy of the +notice set forth in Attachment A-3 and such notice must also be included +in a file header or prominent location in the Source Code made available +to such students. + +(ii) Executable. You may distribute Executable version(s) of Covered +Code to Licensees and other third parties only for the purpose of +evaluation and comment in connection with Research Use by You and under +a license of Your choice, but which limits use of such Executable +version(s) of Covered Code only to that purpose. + +(iii) Modified Class, Interface and Package Naming. In connection with +Research Use by You only, You may use Original Contributor's class, +Interface and package names only to accurately reference or invoke the +Source Code files You modify. Original Contributor grants to You a +limited license to the extent necessary for such purposes. + +(iv) You expressly agree that any distribution, in whole or in part, of +Modifications developed by You shall only be done pursuant to the terms +and conditions of this License. + +(e) Extensions. + +(i) Covered Code. You may not include any Source Code of Community Code +in any Extensions. You may include the compiled Header Files of +Community Code in an Extension provided that Your use of the Covered +Code, including Heading Files, complies with the Commercial Use License, +the TCK and all other terms of this License. + +(ii) Publication. No later than the date on which You first distribute +such Extension for Commercial Use, You must publish to the industry, on +a non-confidential basis and free of all copyright restrictions with +respect to reproduction and use, an accurate and current specification +for any Extension. In addition, You must make available an appropriate +test suite, pursuant to the same rights as the specification, +sufficiently detailed to allow any third party reasonably skilled in the +technology to produce implementations of the Extension compatible with +the specification. Such test suites must be made available as soon as +reasonably practicable but, in no event, later than ninety (90) days +after Your first Commercial Use of the Extension. You must use +reasonable efforts to promptly clarify and correct the specification and +the test suite upon written request by Original Contributor. + +(iii) Open. You agree to refrain from enforcing any Intellectual +Property Rights You may have covering any interface(s) of Your +Extension, which would prevent the implementation of such interface(s) +by Original Contributor or any Licensee. This obligation does not +prevent You from enforcing any Intellectual Property Right You have that +would otherwise be infringed by an implementation of Your Extension. + +(iv) Interface Modifications and Naming. You may not modify or add to +the GUID space * * "xxxxxxxx-0901-11d1-8B06-00A024406D59" or any other +GUID space designated by Original Contributor. You may not modify any +Interface prefix provided with the Covered Code or any other prefix +designated by Original Contributor.* * + +* * + +(f) You agree that any Specifications provided to You by Original +Contributor are confidential and proprietary information of Original +Contributor. You must maintain the confidentiality of the Specifications +and may not disclose them to any third party without Original +Contributor's prior written consent. You may only use the Specifications +under the terms of this License and only for the purpose of implementing +the terms of this License with respect to Covered Code. You agree not +use, copy or distribute any such Specifications except as provided in +writing by Original Contributor. + +3.2 Commercial Use License. + +You may not make Commercial Use of any Covered Code unless You and +Original Contributor have executed a copy of the Commercial Use and +Trademark License attached as Attachment D. + +*4. Versions of the License.* + +4.1 License Versions. + +Original Contributor may publish revised versions of the License from +time to time. Each version will be given a distinguishing version number. + +4.2 Effect. + +Once a particular version of Covered Code has been provided under a +version of the License, You may always continue to use such Covered Code +under the terms of that version of the License. You may also choose to +use such Covered Code under the terms of any subsequent version of the +License. No one other than Original Contributor has the right to +promulgate License versions. + +4.3 Multiple-Licensed Code. + +Original Contributor may designate portions of the Covered Code as +"Multiple-Licensed." "Multiple-Licensed" means that the Original +Contributor permits You to utilize those designated portions of the +Covered Code under Your choice of this License or the alternative +license(s), if any, specified by the Original Contributor in an +Attachment to this License. + +*5. Disclaimer of Warranty.* + +5.1 COVERED CODE PROVIDED AS IS. + +COVERED CODE IS PROVIDED UNDER THIS LICENSE "AS IS," WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, +WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT +FOR A PARTICULAR PURPOSE OR NON-INFRINGING. YOU AGREE TO BEAR THE ENTIRE +RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF COVERED CODE UNDER +THIS LICENSE. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART +OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER +EXCEPT SUBJECT TO THIS DISCLAIMER. + +5.2 Not Designed for High Risk Activities. + +You acknowledge that Original Code, Upgraded Code and Specifications are +not designed or intended for use in high risk activities including, but +not limited to: (i) on-line control of aircraft, air traffic, aircraft +navigation or aircraft communications; or (ii) in the design, +construction, operation or maintenance of any nuclear facility. Original +Contributor disclaims any express or implied warranty of fitness for +such uses. + +*6. Termination.* + +6.1 By You. + +You may terminate this Research Use license at anytime by providing +written notice to Original Contributor. + +6.2 By Original Contributor. + +This License and the rights granted hereunder will terminate: + +(i) automatically if You fail to comply with the terms of this License +and fail to cure such breach within 30 days of receipt of written notice +of the breach; + +(ii) immediately in the event of circumstances specified in Sections 7.1 +and 8.4; or + +(iii) at Original Contributor's discretion upon any action initiated by +You (including by cross-claim or counter claim) alleging that use or +distribution by Original Contributor or any Licensee, of Original Code, +Upgraded Code, Error Corrections, Shared Modifications or Specifications +infringe a patent owned or controlled by You. + +6.3 Effective of Termination. + +Upon termination, You agree to discontinue use of and destroy all copies +of Covered Code in Your possession. All sublicenses to the Covered Code +which You have properly granted shall survive any termination of this +License. Provisions that, by their nature, should remain in effect +beyond the termination of this License shall survive including, without +limitation, Sections 2.2, 3, 5, 7 and 8. + +6.4 No Compensation. + +Each party waives and releases the other from any claim to compensation +or indemnity for permitted or lawful termination of the business +relationship established by this License. + +*7. Liability.* + +7.1 Infringement. Should any of the Original Code, Upgraded Code, TCK or +Specifications ("Materials") become the subject of a claim of +infringement, Original Contributor may, at its sole option, (i) attempt +to procure the rights necessary for You to continue using the Materials, +(ii) modify the Materials so that they are no longer infringing, or +(iii) terminate Your right to use the Materials, immediately upon +written notice, and refund to You the amount, if any, having then +actually been paid by You to Original Contributor for the Original Code, +Upgraded Code and TCK, depreciated on a straight line, five year basis. + +7.2 LIMITATION OF LIABILITY. TO THE FULL EXTENT ALLOWED BY APPLICABLE +LAW, ORIGINAL CONTRIBUTOR'S LIABILITY TO YOU FOR CLAIMS RELATING TO THIS +LICENSE, WHETHER FOR BREACH OR IN TORT, SHALL BE LIMITED TO ONE HUNDRED +PERCENT (100%) OF THE AMOUNT HAVING THEN ACTUALLY BEEN PAID BY YOU TO +ORIGINAL CONTRIBUTOR FOR ALL COPIES LICENSED HEREUNDER OF THE PARTICULAR +ITEMS GIVING RISE TO SUCH CLAIM, IF ANY, DURING THE TWELVE MONTHS +PRECEDING THE CLAIMED BREACH. IN NO EVENT WILL YOU (RELATIVE TO YOUR +SHARED MODIFICATIONS OR ERROR CORRECTIONS) OR ORIGINAL CONTRIBUTOR BE +LIABLE FOR ANY INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES IN CONNECTION WITH OR RISING OUT OF THIS LICENSE (INCLUDING, +WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR OTHER ECONOMIC +ADVANTAGE), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY, WHETHER IN +AN ACTION FOR CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE) +OR OTHERWISE, WHETHER OR NOT YOU OR ORIGINAL CONTRIBUTOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE AND NOTWITHSTANDING THE +FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. + +*8. Miscellaneous.* + +8.1 Trademark. + +You shall not use any Trademark unless You and Original Contributor +execute a copy of the Commercial Use and Trademark License Agreement +attached hereto as Attachment D. Except as expressly provided in the +License, You are granted no right, title or license to, or interest in, +any Trademarks. Whether or not You and Original Contributor enter into +the Trademark License, You agree not to (i) challenge Original +Contributor's ownership or use of Trademarks; (ii) attempt to register +any Trademarks, or any mark or logo substantially similar thereto; or +(iii) incorporate any Trademarks into Your own trademarks, product +names, service marks, company names, or domain names. + +8.2 Integration. + +This License represents the complete agreement concerning the subject +matter hereof. + +8.3 Assignment. + +Original Contributor may assign this License, and its rights and +obligations hereunder, in its sole discretion. You may assign the +Research Use portions of this License and the TCK license to a third +party upon prior written notice to Original Contributor (which may be +provided electronically via the Community Web-Server). You may not +assign the Commercial Use and Trademark license, the Add-On Technology +License, or the Add-On Technology Source Code Porting License, including +by way of merger (regardless of whether You are the surviving entity) or +acquisition, without Original Contributor's prior written consent. + +8.4 Severability. + +If any provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to make it +enforceable. Notwithstanding the foregoing, if You are prohibited by law +from fully and specifically complying with Sections 2.2 or 3, this +License will immediately terminate and You must immediately discontinue +any use of Covered Code. + +8.5 Governing Law. + +This License shall be governed by the laws of the United States and the +State of Washington, as applied to contracts entered into and to be +performed in Washington between Washington residents. The application of +the United Nations Convention on Contracts for the International Sale of +Goods is expressly excluded. You agree that the state and federal courts +located in Seattle, Washington have exclusive jurisdiction over any +claim relating to the License, including contract and tort claims. + +8.6 Dispute Resolution. + +a) Arbitration. Any dispute arising out of or relating to this License +shall be finally settled by arbitration as set out herein, except that +either party may bring any action, in a court of competent jurisdiction +(which jurisdiction shall be exclusive), with respect to any dispute +relating to such party's Intellectual Property Rights or with respect to +Your compliance with the TCK license. Arbitration shall be administered: +(i) by the American Arbitration Association (AAA), (ii) in accordance +with the rules of the United Nations Commission on International Trade +Law (UNCITRAL) (the "Rules") in effect at the time of arbitration as +modified herein; and (iii) the arbitrator will apply the substantive +laws of Washington and the United States. Judgment upon the award +rendered by the arbitrator may be entered in any court having +jurisdiction to enforce such award. + +b) Arbitration language, venue and damages. All arbitration proceedings +shall be conducted in English by a single arbitrator selected in +accordance with the Rules, who must be fluent in English and be either a +retired judge or practicing attorney having at least ten (10) years +litigation experience and be reasonably familiar with the technology +matters relative to the dispute. Unless otherwise agreed, arbitration +venue shall be in Seattle, Washington. The arbitrator may award monetary +damages only and nothing shall preclude either party from seeking +provisional or emergency relief from a court of competent jurisdiction. +The arbitrator shall have no authority to award damages in excess of +those permitted in this License and any such award in excess is void. +All awards will be payable in U.S. dollars and may include, for the +prevailing party (i) pre-judgment award interest, (ii) reasonable +attorneys' fees incurred in connection with the arbitration, and (iii) +reasonable costs and expenses incurred in enforcing the award. The +arbitrator will order each party to produce identified documents and +respond to no more than twenty-five single question interrogatories. + +8.7 Construction. + +Any law or regulation, which provides that the language of a contract +shall be construed against the drafter, shall not apply to this License. + +8.8 U.S. Government End Users. + +The Covered Code is a "commercial item," as that term is defined in 48 +C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" +and "commercial computer software documentation," as such terms are used +in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and +48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government +End Users acquire Covered Code with only those rights set forth herein. +You agree to pass this notice to our licensees. + +8.9 Marketing Activities. + +Licensee hereby grants Original Contributor a non-exclusive, +non-transferable, limited license to use the Licensee's company name and +logo ("Licensee Marks") in any presentations, press releases, or +marketing materials solely for the purpose of identifying Licensee as a +member of the Helix Community. Licensee shall provide samples of +Licensee Marks to Original Contributor upon request by Original +Contributor. Original Contributor acknowledges that the Licensee Marks +are the trademarks of Licensee. Original Contributor shall not use the +Licensee Marks in a way that may imply that Original Contributor is an +agency or branch of Licensee. Original Contributor understands and +agrees that the use of any Licensee Marks in connection with this +Agreement shall not create any right, title or interest, in, or to the +Licensee Marks or any Licensee trademarks and that all such use and +goodwill associated with any such trademarks will inure to the benefit +of Licensee. Further the Original Contributor will stop usage of the +Licensee Marks upon Licensee's request. + +8.10 Press Announcements. + +You may make press announcements or other public statements regarding +this License without the prior written consent of the Original +Contributor, if Your statement is limited to announcing the licensing of +the Covered Code or the availability of Your Product and its +compatibility with the Covered Code. All other public announcements +regarding this license require the prior written consent of the Original +Contributor. Consent requests are welcome at press@helixcommunity.org. + +8.11 International Use. + +a) Export/Import laws. Covered Code is subject to U.S. export control +laws and may be subject to export or import regulations in other +countries. Each party agrees to comply strictly with all such laws and +regulations and acknowledges their responsibility to obtain such +licenses to export, re-export, or import as may be required. You agree +to pass these obligations to Your licensees. + +b) Intellectual Property Protection. Due to limited intellectual +property protection and enforcement in certain countries, You agree not +to redistribute the Original Code, Upgraded Code, TCK and Specifications +to any country on the list of restricted countries on the Community Web +Server. + +8.12 Language. + +This License is in the English language only, which language shall be +controlling in all respects, and all versions of this License in any +other language shall be for accommodation only and shall not be binding +on the parties to this License. All communications and notices made or +given pursuant to this License, and all documentation and support to be +provided, unless otherwise noted, shall be in the English language. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH REALNETWORKS, INC. IF YOU ARE AGREEING +TO THIS LICENSE ON BEHALF OF A COMPANY, YOU REPRESENT THAT YOU ARE +AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. WHETHER YOU ARE ACTING +ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, YOU MUST BE OF MAJORITY +AGE AND BE OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. IF YOU DO NOT +MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY OF THE TERMS AND +CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON TO EXIT. + + + GLOSSARY + +1. *"Added Value"* means code which: + +(i) has a principal purpose which is substantially different from that +of the stand-alone Technology; + +(ii) represents a significant functional and value enhancement to the +Technology; + +(iii) operates in conjunction with the Technology; and + +(iv) is not marketed as a technology which replaces or substitutes for +the Technology + +2. "*Applicable Patent Rights*" mean: (a) in the case where Original +Contributor is the grantor of rights, claims of patents that (i) are now +or hereafter acquired, owned by or assigned to Original Contributor and +(ii) are necessarily infringed by using or making the Original Code or +Upgraded Code, including Modifications provided by Original Contributor, +alone and not in combination with other software or hardware; and (b) in +the case where Licensee is the grantor of rights, claims of patents that +(i) are now or hereafter acquired, owned by or assigned to Licensee and +(ii) are infringed (directly or indirectly) by using or making +Licensee's Modifications or Error Corrections, taken alone or in +combination with Covered Code. + +3. "*Application Programming Interfaces (APIs)"* means the interfaces, +associated header files, service provider interfaces, and protocols that +enable a device, application, Operating System, or other program to +obtain services from or make requests of (or provide services in +response to requests from) other programs, and to use, benefit from, or +rely on the resources, facilities, and capabilities of the relevant +programs using the APIs. APIs includes the technical documentation +describing the APIs, the Source Code constituting the API, and any +Header Files used with the APIs. + +4. "*Commercial Use*" means any use (internal or external), copying, +sublicensing or distribution (internal or external), directly or +indirectly of Covered Code by You other than Your Research Use of +Covered Code within Your business or organization or in conjunction with +other Licensees with equivalent Research Use rights. Commercial Use +includes any use of the Covered Code for direct or indirect commercial +or strategic gain, advantage or other business purpose. Any Commercial +Use requires execution of Attachment D by You and Original Contributor. + +5. "*Community Code*" means the Original Code, Upgraded Code, Error +Corrections, Shared Modifications, or any combination thereof. + +6. "*Community Webserver(s)"* means the webservers designated by +Original Contributor for access to the Original Code, Upgraded Code, TCK +and Specifications and for posting Error Corrections and Shared +Modifications. + +7. "*Compliant Covered Code*" means Covered Code that complies with the +requirements of the TCK. + +8. "*Contributor*" means each Licensee that creates or contributes to +the creation of any Error Correction or Shared Modification. + +9. "*Covered Code*" means the Original Code, Upgraded Code, +Modifications, or any combination thereof. + +10. "*Error Correction*" means any change made to Community Code which +conforms to the Specification and corrects the adverse effect of a +failure of Community Code to perform any function set forth in or +required by the Specifications. + +11. "*Executable*" means Covered Code that has been converted from +Source Code to the preferred form for execution by a computer or digital +processor (e.g. binary form). + +12. "*Extension(s)"* means any additional Interfaces developed by or for +You which: (i) are designed for use with the Technology; (ii) constitute +an API for a library of computing functions or services; and (iii) are +disclosed or otherwise made available to third party software developers +for the purpose of developing software which invokes such additional +Interfaces. The foregoing shall not apply to software developed by Your +subcontractors to be exclusively used by You. + +13. "*Header File(s)"* means that portion of the Source Code that +provides the names and types of member functions, data members, class +definitions, and interface definitions necessary to implement the APIs +for the Covered Code. Header Files include, files specifically +designated by Original Contributor as Header Files. Header Files do not +include the code necessary to implement the functionality underlying the +Interface. + +14. *"Helix DNA Server Technology"* means the program(s) that implement +the Helix Universal Server streaming engine for the Technology as +defined in the Specification. + +15. *"Helix DNA Client Technology"* means the Covered Code that +implements the RealOne Player engine as defined in the Specification. + +16. *"Helix DNA Producer Technology"* means the Covered Code that +implements the Helix Producer engine as defined in the Specification. + +17. *"Helix DNA Technology"* means the Helix DNA Server Technology, the +Helix DNA Client Technology, the Helix DNA Producer Technology and other +Helix technologies designated by Original Contributor. + +18. "*Intellectual Property Rights*" means worldwide statutory and +common law rights associated solely with (i) Applicable Patent Rights; +(ii) works of authorship including copyrights, copyright applications, +copyright registrations and "moral rights"; (iii) the protection of +trade and industrial secrets and confidential information; and (iv) +divisions, continuations, renewals, and re-issuances of the foregoing +now existing or acquired in the future. + +19. *"Interface*" means interfaces, functions, properties, class +definitions, APIs, Header Files, GUIDs, V-Tables, and/or protocols +allowing one piece of software, firmware or hardware to communicate or +interoperate with another piece of software, firmware or hardware. + +20. "*Internal Deployment Use*" means use of Compliant Covered Code +(excluding Research Use) within Your business or organization only by +Your employees and/or agents on behalf of Your business or organization, +but not to provide services, including content distribution, to third +parties, subject to execution of Attachment D by You and Original +Contributor, if required. + +21. "*Licensee*" means any party that has entered into and has in effect +a version of this License with Original Contributor. + +22. "*MIME type*" means a description of what type of media or other +content is in a file, including by way of example but not limited to +'audio/x-pn-realaudio-plugin.' + +23. "*Modification(s)"* means (i) any addition to, deletion from and/or +change to the substance and/or structure of the Covered Code, including +Interfaces; (ii) the combination of any Covered Code and any previous +Modifications; (iii) any new file or other representation of computer +program statements that contains any portion of Covered Code; and/or +(iv) any new Source Code implementing any portion of the Specifications. + +24. "*MP3 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Picture Experts Group known as MPEG-1 Audio Layer-3 or MP3, +including but not limited to all past and future versions, profiles, +extensions, parts and amendments relating to the MP3 specification. + +25. "*MPEG-4 Patents*" means any patents necessary to make, use or sell +technology implementing any portion of the specification developed by +the Moving Pictures Experts Group known as MPEG-4, including but not +limited to all past and future versions, profiles, extensions, parts and +amendments relating to the MPEG-4 specification. + +26. "*Original Code*" means the initial Source Code for the Technology +as described on the Community Web Server. + +27. "*Original Contributor*" means RealNetworks, Inc., its affiliates +and its successors and assigns. + +28. "*Original Contributor MIME Type*" means the MIME registry, browser +preferences, or local file/protocol associations invoking any Helix DNA +Client-based application, including the RealOne Player, for playback of +RealAudio, RealVideo, other RealMedia MIME types or datatypes (e.g., +.ram, .rnx, .rpm, .ra, .rm, .rp, .rt, .rf, .prx, .mpe, .rmp, .rmj, .rav, +.rjs, .rmx, .rjt, .rms), and any other Original Contributor-specific or +proprietary MIME types that Original Contributor may introduce in the +future. + +29. "*Personal Use*" means use of Covered Code by an individual solely +for his or her personal, private and non-commercial purposes. An +individual's use of Covered Code in his or her capacity as an officer, +employee, member, independent contractor or agent of a corporation, +business or organization (commercial or non-commercial) does not qualify +as Personal Use. + +30. "*RealMedia File Format*" means the file format designed and +developed by RealNetworks for storing multimedia data and used to store +RealAudio and RealVideo encoded streams. Valid RealMedia File Format +extensions include: .rm, .rmj, .rmc, .rmvb, .rms. + +31. "*RCSL Webpage*" means the RealNetworks Community Source License +webpage located at https://www.helixcommunity.org/content/rcsl or such +other URL that Original Contributor may designate from time to time. + +32. "*Reformatted Specifications*" means any revision to the +Specifications which translates or reformats the Specifications (as for +example in connection with Your documentation) but which does not alter, +subset or superset * *the functional or operational aspects of the +Specifications. + +33. "*Research Use*" means use and distribution of Covered Code only for +Your Personal Use, research or development use and expressly excludes +Internal Deployment Use and Commercial Use. Research Use also includes +use of Covered Code to teach individuals how to use Covered Code. + +34. "*Shared Modifications*" means Modifications that You distribute or +use for a Commercial Use, in addition to any Modifications provided by +You, at Your option, pursuant to Section 2.2, or received by You from a +Contributor pursuant to Section 2.3. + +35. "*Source Code*" means the preferred form of the Covered Code for +making modifications to it, including all modules it contains, plus any +associated interface definition files, scripts used to control +compilation and installation of an Executable, or source code +differential comparisons against either the Original Code or another +well known, available Covered Code of the Contributor's choice. The +Source Code can be in a compressed or archival form, provided the +appropriate decompression or de-archiving software is widely available +for no charge. + +36. "*Specifications*" means the specifications for the Technology and +other documentation, as designated on the Community Web Server, as may +be revised by Original Contributor from time to time. + +37. "*Trademarks*" means Original Contributor's trademarks and logos, +including, but not limited to, RealNetworks, RealAudio, RealVideo, +RealOne, RealSystem, SureStream, Helix, Helix DNA and other trademarks +whether now used or adopted in the future. + +38. "*Technology*" means the technology described in Attachment B, and +Upgrades. + +39. "*Technology Compatibility Kit"* or *"TCK*" means the test programs, +procedures, acceptance criteria and/or other requirements, designated by +Original Contributor for use in verifying compliance of Covered Code +with the Specifications, in conjunction with the Original Code and +Upgraded Code. Original Contributor may, in its sole discretion and from +time to time, revise a TCK to correct errors and/or omissions and in +connection with Upgrades. + +40. "*Upgrade(s)"* means new versions of Technology designated +exclusively by Original Contributor as an "Upgrade" and released by +Original Contributor from time to time under the terms of the License. + +41. "*Upgraded Code*" means the Source Code and/or Executables for +Upgrades, possibly including Modifications made by Contributors. + +42. *"User's Guide"* means the users guide for the TCK which Original +Contributor makes available to You to provide direction in how to run +the TCK and properly interpret the results, as may be revised by +Original Contributor from time to time. + +43. "*You(r)*" means an individual, or a legal entity acting by and +through an individual or individuals, exercising rights either under +this License or under a future version of this License issued pursuant +to Section 4.1. For legal entities, "You(r)" includes any entity that by +majority voting interest controls, is controlled by, or is under common +control with You. + +44. "*Your Products*" means any (i) hardware products You distribute +integrating the Covered Code; (ii) any software products You distribute +with the Covered Code that utilize the APIs of the Covered Code; or +(iii) any services You provide using the Covered Code. + + + ATTACHMENT A + +REQUIRED NOTICES + + + ATTACHMENT A-1 + +REQUIRED IN ALL CASES + +Notice to be included in header file of all Error Corrections and Shared +Modifications: + +Portions Copyright 1994-2003 RealNetworks, Inc. All rights reserved. + +The contents of this file, and the files included with this file, are +subject to the current version of RealNetworks Community Source License +Version 1.1 (the "License"). You may not use this file except in +compliance with the License executed by both You and RealNetworks. You +may obtain a copy of the License at * +https://www.helixcommunity.org/content/rcsl.* You may also obtain a copy +of the License by contacting RealNetworks directly. Please see the +License for the rights, obligations and limitations governing use of the +contents of the file. + +This file is part of the Helix DNA technology. RealNetworks, Inc., is +the developer of the Original code and owns the copyrights in the +portions it created. + +This file, and the files included with this file, are distributed on an +'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, +AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): + +_______________________________________________ + +Technology Compatibility Kit Test Suite(s) Location: + +________________________________ + + + ATTACHMENT A-2 + +SAMPLE LICENSEE CERTIFICATION + +"By clicking the `Agree' button below, You certify that You are a +Licensee in good standing under the RealNetworks Community Source +License, ("License") and that Your access, use and distribution of code +and information You may obtain at this site is subject to the License. +If You are not a Licensee under the RealNetworks Community Source +License You agree not to download, copy or use the Helix DNA technology. + + + ATTACHMENT A-3 + +REQUIRED STUDENT NOTIFICATION + +"This software and related documentation has been obtained by Your +educational institution subject to the RealNetworks Community Source +License. You have been provided access to the software and related +documentation for use only in connection with your course work and +research activities as a matriculated student of Your educational +institution. Any other use is expressly prohibited. + +THIS SOFTWARE AND RELATED DOCUMENTATION CONTAINS PROPRIETARY MATERIAL OF +REALNETWORKS, INC, WHICH ARE PROTECTED BY VARIOUS INTELLECTUAL PROPERTY +RIGHTS. + +You may not use this file except in compliance with the License. You may +obtain a copy of the License on the web at +https://www.helixcommunity.org/content/rcsl. + +* +* + + + ATTACHMENT B + +Description of Technology + +Helix DNA, which consists of Helix DNA Client, Helix DNA Server and +Helix DNA Producer. + +Description of "Technology" + +Helix DNA Technology v1.0 as described on the Community Web Server. + + + ATTACHMENT C + +TECHNOLOGY COMPATIBILITY KIT LICENSE + +The following license is effective for the *Helix DNA* Technology +Compatibility Kit - as described on the Community Web Server. The +Technology Compatibility Kit(s) for the Technology specified in +Attachment B may be accessed at the Community Web Server. + +1. TCK License. + +1.1 Grants to use TCK + +Subject to the terms and restrictions set forth below and the +RealNetworks Community Source License, and the Research Use license, +Original Contributor grants to You a worldwide, non-exclusive, +non-transferable license, to the extent of Original Contributor's +Intellectual Property Rights in the TCK (without the right to +sublicense), to use the TCK to develop and test Covered Code. + +1.2 TCK Use Restrictions. + +You are not authorized to create derivative works of the TCK or use the +TCK to test any implementation of the Specification that is not Covered +Code. You may not publish Your test results or make claims of +comparative compatibility with respect to other implementations of the +Specification. In consideration for the license grant in Section 1.1 +above You agree not to develop Your own tests that are intended to +validate conformation with the Specification. + +2. Test Results. + +You agree to provide to Original Contributor or the third party test +facility if applicable, Your test results that demonstrate that Covered +Code is Compliant Covered Code and that Original Contributor may publish +or otherwise distribute such test results. + +PLEASE READ THE TERMS OF THIS LICENSE CAREFULLY. BY CLICKING ON THE +"ACCEPT" BUTTON BELOW YOU ARE ACCEPTING AND AGREEING TO THE TERMS AND +CONDITIONS OF THIS LICENSE WITH THE ORIGINAL CONTRIBUTOR, REALNETWORKS, +INC. IF YOU ARE AGREEING TO THIS LICENSE ON BEHALF OF A COMPANY, YOU +REPRESENT THAT YOU ARE AUTHORIZED TO BIND THE COMPANY TO SUCH A LICENSE. +WHETHER YOU ARE ACTING ON YOUR OWN BEHALF, OR REPRESENTING A COMPANY, +YOU MUST BE OF MAJORITY AGE AND BE OTHERWISE COMPETENT TO ENTER INTO +CONTRACTS. IF YOU DO NOT MEET THIS CRITERIA OR YOU DO NOT AGREE TO ANY +OF THE TERMS AND CONDITIONS OF THIS LICENSE, CLICK ON THE REJECT BUTTON +TO EXIT. + +*ACCEPT / REJECT +* + +* +* + +*To agree to the R&D/academic terms of this license, please register + on the site -- +you will then be given a chance to agree to the clickwrap RCSL + +R&D License + +and gain access to the RCSL-licensed source code. To build or deploy +commercial applications based on the RCSL, you will need to agree to the +Commercial Use license attachments +* + + + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/RPSL.txt b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/RPSL.txt new file mode 100644 index 0000000..d040a45 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/RPSL.txt @@ -0,0 +1,518 @@ +RealNetworks Public Source License Version 1.0 +(Rev. Date October 28, 2002) + +1. General Definitions. This License applies to any program or other work which +RealNetworks, Inc., or any other entity that elects to use this license, +("Licensor") makes publicly available and which contains a notice placed by +Licensor identifying such program or work as "Original Code" and stating that it +is subject to the terms of this RealNetworks Public Source License version 1.0 +(or subsequent version thereof) ("License"). You are not required to accept this +License. However, nothing else grants You permission to use, copy, modify or +distribute the software or its derivative works. These actions are prohibited by +law if You do not accept this License. Therefore, by modifying, copying or +distributing the software (or any work based on the software), You indicate your +acceptance of this License to do so, and all its terms and conditions. In +addition, you agree to the terms of this License by clicking the Accept button +or downloading the software. As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Licensor is the +grantor of rights, claims of patents that (i) are now or hereafter acquired, +owned by or assigned to Licensor and (ii) are necessarily infringed by using or +making the Original Code alone and not in combination with other software or +hardware; and (b) in the case where You are the grantor of rights, claims of +patents that (i) are now or hereafter acquired, owned by or assigned to You and +(ii) are infringed (directly or indirectly) by using or making Your +Modifications, taken alone or in combination with Original Code. + +1.2 "Compatible Source License" means any one of the licenses listed on Exhibit +B or at https://www.helixcommunity.org/content/complicense or other licenses +specifically identified by Licensor in writing. Notwithstanding any term to the +contrary in any Compatible Source License, any code covered by any Compatible +Source License that is used with Covered Code must be made readily available in +Source Code format for royalty-free use under the terms of the Compatible Source +License or this License. + +1.3 "Contributor" means any person or entity that creates or contributes to the +creation of Modifications. + +1.4 "Covered Code" means the Original Code, Modifications, the combination of +Original Code and any Modifications, and/or any respective portions thereof. + +1.5 "Deploy" means to use, sublicense or distribute Covered Code other than for +Your internal research and development (R&D) and/or Personal Use, and includes +without limitation, any and all internal use or distribution of Covered Code +within Your business or organization except for R&D use and/or Personal Use, as +well as direct or indirect sublicensing or distribution of Covered Code by You +to any third party in any form or manner. + +1.6 "Derivative Work" means either the Covered Code or any derivative work under +United States copyright law, and including any work containing or including any +portion of the Covered Code or Modifications, either verbatim or with +modifications and/or translated into another language. Derivative Work also +includes any work which combines any portion of Covered Code or Modifications +with code not otherwise governed by the terms of this License. + +1.7 "Externally Deploy" means to Deploy the Covered Code in any way that may be +accessed or used by anyone other than You, used to provide any services to +anyone other than You, or used in any way to deliver any content to anyone other +than You, whether the Covered Code is distributed to those parties, made +available as an application intended for use over a computer network, or used to +provide services or otherwise deliver content to anyone other than You. + +1.8. "Interface" means interfaces, functions, properties, class definitions, +APIs, header files, GUIDs, V-Tables, and/or protocols allowing one piece of +software, firmware or hardware to communicate or interoperate with another piece +of software, firmware or hardware. + +1.9 "Modifications" mean any addition to, deletion from, and/or change to, the +substance and/or structure of the Original Code, any previous Modifications, the +combination of Original Code and any previous Modifications, and/or any +respective portions thereof. When code is released as a series of files, a +Modification is: (a) any addition to or deletion from the contents of a file +containing Covered Code; and/or (b) any new file or other representation of +computer program statements that contains any part of Covered Code. + +1.10 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Licensor under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Licensor under this License, and that has been expressly identified by Licensor +as such in the header file(s) of such work; and (b) the object code compiled +from such Source Code and originally made available by Licensor under this +License. + +1.11 "Personal Use" means use of Covered Code by an individual solely for his or +her personal, private and non-commercial purposes. An individual's use of +Covered Code in his or her capacity as an officer, employee, member, independent +contractor or agent of a corporation, business or organization (commercial or +non-commercial) does not qualify as Personal Use. + +1.12 "Source Code" means the human readable form of a program or other work that +is suitable for making modifications to it, including all modules it contains, +plus any associated interface definition files, scripts used to control +compilation and installation of an executable (object code). + +1.13 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership of +fifty percent (50%) or more of the outstanding shares or beneficial ownership of +such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Licensor hereby grants You, effective on the date +You accept this License (via downloading or using Covered Code or otherwise +indicating your acceptance of this License), a worldwide, royalty-free, +non-exclusive copyright license, to the extent of Licensor's copyrights cover +the Original Code, to do the following: + +2.1 You may reproduce, display, perform, modify and Deploy Covered Code, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the copyright +and other proprietary notices and disclaimers of Licensor as they appear in the +Original Code, and keep intact all notices in the Original Code that refer to +this License; + +(b) You must include a copy of this License with every copy of Source Code of +Covered Code and documentation You distribute, and You may not offer or impose +any terms on such Source Code that alter or restrict this License or the +recipients' rights hereunder, except as permitted under Section 6; + +(c) You must duplicate, to the extent it does not already exist, the notice in +Exhibit A in each file of the Source Code of all Your Modifications, and cause +the modified files to carry prominent notices stating that You changed the files +and the date of any change; + +(d) You must make Source Code of all Your Externally Deployed Modifications +publicly available under the terms of this License, including the license grants +set forth in Section 3 below, for as long as you Deploy the Covered Code or +twelve (12) months from the date of initial Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Deployed Modifications +electronically (e.g. download from a web site); and + +(e) if You Deploy Covered Code in object code, executable form only, You must +include a prominent notice, in the code itself as well as in related +documentation, stating that Source Code of the Covered Code is available under +the terms of this License with information on how and where to obtain such +Source Code. You must also include the Object Code Notice set forth in Exhibit A +in the "about" box or other appropriate place where other copyright notices are +placed, including any packaging materials. + +2.2 You expressly acknowledge and agree that although Licensor and each +Contributor grants the licenses to their respective portions of the Covered Code +set forth herein, no assurances are provided by Licensor or any Contributor that +the Covered Code does not infringe the patent or other intellectual property +rights of any other entity. Licensor and each Contributor disclaim any liability +to You for claims brought by any other entity based on infringement of +intellectual property rights or otherwise. As a condition to exercising the +rights and licenses granted hereunder, You hereby assume sole responsibility to +secure any other intellectual property rights needed, if any. For example, if a +third party patent license is required to allow You to make, use, sell, import +or offer for sale the Covered Code, it is Your responsibility to acquire such +license(s). + +2.3 Subject to the terms and conditions of this License, Licensor hereby grants +You, effective on the date You accept this License (via downloading or using +Covered Code or otherwise indicating your acceptance of this License), a +worldwide, royalty-free, perpetual, non-exclusive patent license under +Licensor's Applicable Patent Rights to make, use, sell, offer for sale and +import the Covered Code, provided that in each instance you comply with the +terms of this License. + +3. Your Grants. In consideration of, and as a condition to, the licenses granted +to You under this License: + +(a) You grant to Licensor and all third parties a non-exclusive, perpetual, +irrevocable, royalty free license under Your Applicable Patent Rights and other +intellectual property rights owned or controlled by You, to make, sell, offer +for sale, use, import, reproduce, display, perform, modify, distribute and +Deploy Your Modifications of the same scope and extent as Licensor's licenses +under Sections 2.1 and 2.2; and + +(b) You grant to Licensor and its subsidiaries a non-exclusive, worldwide, +royalty-free, perpetual and irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights owned or controlled by You, to +make, use, sell, offer for sale, import, reproduce, display, perform, +distribute, modify or have modified (for Licensor and/or its subsidiaries), +sublicense and distribute Your Modifications, in any form and for any purpose, +through multiple tiers of distribution. + +(c) You agree not use any information derived from Your use and review of the +Covered Code, including but not limited to any algorithms or inventions that may +be contained in the Covered Code, for the purpose of asserting any of Your +patent rights, or assisting a third party to assert any of its patent rights, +against Licensor or any Contributor. + +4. Derivative Works. You may create a Derivative Work by combining Covered Code +with other code not otherwise governed by the terms of this License and +distribute the Derivative Work as an integrated product. In each such instance, +You must make sure the requirements of this License are fulfilled for the +Covered Code or any portion thereof, including all Modifications. + +4.1 You must cause any Derivative Work that you distribute, publish or +Externally Deploy, that in whole or in part contains or is derived from the +Covered Code or any part thereof, to be licensed as a whole at no charge to all +third parties under the terms of this License and no other license except as +provided in Section 4.2. You also must make Source Code available for the +Derivative Work under the same terms as Modifications, described in Sections 2 +and 3, above. + +4.2 Compatible Source Licenses. Software modules that have been independently +developed without any use of Covered Code and which contain no portion of the +Covered Code, Modifications or other Derivative Works, but are used or combined +in any way wtih the Covered Code or any Derivative Work to form a larger +Derivative Work, are exempt from the conditions described in Section 4.1 but +only to the extent that: the software module, including any software that is +linked to, integrated with, or part of the same applications as, the software +module by any method must be wholly subject to one of the Compatible Source +Licenses. Notwithstanding the foregoing, all Covered Code must be subject to the +terms of this License. Thus, the entire Derivative Work must be licensed under a +combination of the RPSL (for Covered Code) and a Compatible Source License for +any independently developed software modules within the Derivative Work. The +foregoing requirement applies even if the Compatible Source License would +ordinarily allow the software module to link with, or form larger works with, +other software that is not subject to the Compatible Source License. For +example, although the Mozilla Public License v1.1 allows Mozilla code to be +combined with proprietary software that is not subject to the MPL, if +MPL-licensed code is used with Covered Code the MPL-licensed code could not be +combined or linked with any code not governed by the MPL. The general intent of +this section 4.2 is to enable use of Covered Code with applications that are +wholly subject to an acceptable open source license. You are responsible for +determining whether your use of software with Covered Code is allowed under Your +license to such software. + +4.3 Mere aggregation of another work not based on the Covered Code with the +Covered Code (or with a work based on the Covered Code) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. If You deliver the Covered Code for combination and/or integration with +an application previously provided by You (for example, via automatic updating +technology), such combination and/or integration constitutes a Derivative Work +subject to the terms of this License. + +5. Exclusions From License Grant. Nothing in this License shall be deemed to +grant any rights to trademarks, copyrights, patents, trade secrets or any other +intellectual property of Licensor or any Contributor except as expressly stated +herein. No right is granted to the trademarks of Licensor or any Contributor +even if such marks are included in the Covered Code. Nothing in this License +shall be interpreted to prohibit Licensor from licensing under different terms +from this License any code that Licensor otherwise would have a right to +license. Modifications, Derivative Works and/or any use or combination of +Covered Code with other technology provided by Licensor or third parties may +require additional patent licenses from Licensor which Licensor may grant in its +sole discretion. No patent license is granted separate from the Original Code or +combinations of the Original Code with other software or hardware. + +5.1. Trademarks. This License does not grant any rights to use the trademarks or +trade names owned by Licensor ("Licensor Marks" defined in Exhibit C) or to any +trademark or trade name belonging to any Contributor. No Licensor Marks may be +used to endorse or promote products derived from the Original Code other than as +permitted by the Licensor Trademark Policy defined in Exhibit C. + +6. Additional Terms. You may choose to offer, and to charge a fee for, warranty, +support, indemnity or liability obligations and/or other rights consistent with +the scope of the license granted herein ("Additional Terms") to one or more +recipients of Covered Code. However, You may do so only on Your own behalf and +as Your sole responsibility, and not on behalf of Licensor or any Contributor. +You must obtain the recipient's agreement that any such Additional Terms are +offered by You alone, and You hereby agree to indemnify, defend and hold +Licensor and every Contributor harmless for any liability incurred by or claims +asserted against Licensor or such Contributor by reason of any such Additional +Terms. + +7. Versions of the License. Licensor may publish revised and/or new versions of +this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular version +of this License, You may continue to use it under the terms of that version. You +may also choose to use such Original Code under the terms of any subsequent +version of this License published by Licensor. No one other than Licensor has +the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in part +pre-release, untested, or not fully tested works. The Covered Code may contain +errors that could cause failures or loss of data, and may be incomplete or +contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND LICENSOR AND LICENSOR'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS +"LICENSOR" FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY +DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET +ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. LICENSOR AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN DOCUMENTATION, INFORMATION OR ADVICE GIVEN BY LICENSOR, A LICENSOR +AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You +acknowledge that the Covered Code is not intended for use in high risk +activities, including, but not limited to, the design, construction, operation +or maintenance of nuclear facilities, aircraft navigation, aircraft +communication systems, or air traffic control machines in which case the failure +of the Covered Code could lead to death, personal injury, or severe physical or +environmental damage. Licensor disclaims any express or implied warranty of +fitness for such uses. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT +SHALL LICENSOR OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR STRICT +LIABILITY), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF LICENSOR OR SUCH +CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND +NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY REMEDY. SOME +JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF INCIDENTAL OR +CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event +shall Licensor's total liability to You for all damages (other than as may be +required by applicable law) under this License exceed the amount of ten dollars +($10.00). + +10. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Licensor retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Licensor +("Licensor Modifications"), and such Licensor Modifications will not be +automatically subject to this License. Licensor may, at its sole discretion, +choose to license such Licensor Modifications under this License, or on +different terms from those contained in this License or may choose not to +license them at all. + +11. Termination. + +11.1 Term and Termination. The term of this License is perpetual unless +terminated as provided below. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Licensor if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; + +(b) immediately in the event of the circumstances described in Section 12.5(b); +or + +(c) automatically without notice from Licensor if You, at any time during the +term of this License, commence an action for patent infringement against +Licensor (including by cross-claim or counter claim in a lawsuit); + +(d) upon written notice from Licensor if You, at any time during the term of +this License, commence an action for patent infringement against any third party +alleging that the Covered Code itself (excluding combinations with other +software or hardware) infringes any patent (including by cross-claim or counter +claim in a lawsuit). + +11.2 Effect of Termination. Upon termination, You agree to immediately stop any +further use, reproduction, modification, sublicensing and distribution of the +Covered Code and to destroy all copies of the Covered Code that are in your +possession or control. All sublicenses to the Covered Code which have been +properly granted prior to termination shall survive any termination of this +License. Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to Sections +3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other for +compensation, indemnity or damages of any sort solely as a result of terminating +this License in accordance with its terms, and termination of this License will +be without prejudice to any other right or remedy of any party. + +12. Miscellaneous. + +12.1 Government End Users. The Covered Code is a "commercial item" as defined in +FAR 2.101. Government software and technical data rights in the Covered Code +include only those rights customarily provided to the public as defined in this +License. This customary commercial license in technical data and software is +provided in accordance with FAR 12.211 (Technical Data) and 12.212 (Computer +Software) and, for Department of Defense purchases, DFAR 252.227-7015 (Technical +Data -- Commercial Items) and 227.7202-3 (Rights in Commercial Computer Software +or Computer Software Documentation). Accordingly, all U.S. Government End Users +acquire Covered Code with only those rights set forth herein. + +12.2 Relationship of Parties. This License will not be construed as creating an +agency, partnership, joint venture or any other form of legal association +between or among You, Licensor or any Contributor, and You will not represent to +the contrary, whether expressly, by implication, appearance or otherwise. + +12.3 Independent Development. Nothing in this License will impair Licensor's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions as, +or otherwise compete with, Modifications, Derivative Works, technology or +products that You may develop, produce, market or distribute. + +12.4 Waiver; Construction. Failure by Licensor or any Contributor to enforce any +provision of this License will not be deemed a waiver of future enforcement of +that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +12.5 Severability. (a) If for any reason a court of competent jurisdiction finds +any provision of this License, or portion thereof, to be unenforceable, that +provision of the License will be enforced to the maximum extent permissible so +as to effect the economic benefits and intent of the parties, and the remainder +of this License will continue in full force and effect. (b) Notwithstanding the +foregoing, if applicable law prohibits or restricts You from fully and/or +specifically complying with Sections 2 and/or 3 or prevents the enforceability +of either of those Sections, this License will immediately terminate and You +must immediately discontinue any use of the Covered Code and destroy all copies +of it that are in your possession or control. + +12.6 Dispute Resolution. Any litigation or other dispute resolution between You +and Licensor relating to this License shall take place in the Seattle, +Washington, and You and Licensor hereby consent to the personal jurisdiction of, +and venue in, the state and federal courts within that District with respect to +this License. The application of the United Nations Convention on Contracts for +the International Sale of Goods is expressly excluded. + +12.7 Export/Import Laws. This software is subject to all export and import laws +and restrictions and regulations of the country in which you receive the Covered +Code and You are solely responsible for ensuring that You do not export, +re-export or import the Covered Code or any direct product thereof in violation +of any such restrictions, laws or regulations, or without all necessary +authorizations. + +12.8 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +Washington. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé +que le présent contrat et tous les documents connexes soient +rédigés en anglais. + + EXHIBIT A. + +"Copyright © 1995-2002 +RealNetworks, Inc. and/or its licensors. All Rights Reserved. + +The contents of this file, and the files included with this file, are subject to +the current version of the RealNetworks Public Source License Version 1.0 (the +"RPSL") available at https://www.helixcommunity.org/content/rpsl unless you have +licensed the file under the RealNetworks Community Source License Version 1.0 +(the "RCSL") available at https://www.helixcommunity.org/content/rcsl, in which +case the RCSL will apply. You may also obtain the license terms directly from +RealNetworks. You may not use this file except in compliance with the RPSL or, +if you have a valid RCSL with RealNetworks applicable to this file, the RCSL. +Please see the applicable RPSL or RCSL for the rights, obligations and +limitations governing use of the contents of the file. + +This file is part of the Helix DNA Technology. RealNetworks is the developer of +the Original code and owns the copyrights in the portions it created. + +This file, and the files included with this file, is distributed and made +available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR +IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING +WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + +Contributor(s): ____________________________________ + +Technology Compatibility Kit Test +Suite(s) Location (if licensed under the RCSL): ______________________________ + +Object Code Notice: Helix DNA Client technology included. Copyright (c) +RealNetworks, Inc., 1995-2002. All rights reserved. + + + EXHIBIT B + +Compatible Source Licenses for the RealNetworks Public Source License. The +following list applies to the most recent version of the license as of October +25, 2002, unless otherwise indicated. + +* Academic Free License +* Apache Software License +* Apple Public Source License +* Artistic license +* Attribution Assurance Licenses +* BSD license +* Common Public License (1) +* Eiffel Forum License +* GNU General Public License (GPL) (1) +* GNU Library or "Lesser" General Public License (LGPL) (1) +* IBM Public License +* Intel Open Source License +* Jabber Open Source License +* MIT license +* MITRE Collaborative Virtual Workspace License (CVW License) +* Motosoto License +* Mozilla Public License 1.0 (MPL) +* Mozilla Public License 1.1 (MPL) +* Nokia Open Source License +* Open Group Test Suite License +* Python Software Foundation License +* Ricoh Source Code Public License +* Sun Industry Standards Source License (SISSL) +* Sun Public License +* University of Illinois/NCSA Open Source License +* Vovida Software License v. 1.0 +* W3C License +* X.Net License +* Zope Public License +* zlib/libpng license + +(1) Note: because this license contains certain reciprocal licensing terms that +purport to extend to independently developed code, You may be prohibited under +the terms of this otherwise compatible license from using code licensed under +its terms with Covered Code because Covered Code may only be licensed under the +RealNetworks Public Source License. Any attempt to apply non RPSL license terms, +including without limitation the GPL, to Covered Code is expressly forbidden. +You are responsible for ensuring that Your use of Compatible Source Licensed +code does not violate either the RPSL or the Compatible Source License. + +The latest version of this list can be found at: +https://www.helixcommunity.org/content/complicense + + EXHIBIT C + +RealNetworks' Trademark policy. + +RealNetworks defines the following trademarks collectively as "Licensor +Trademarks": "RealNetworks", "RealPlayer", "RealJukebox", "RealSystem", +"RealAudio", "RealVideo", "RealOne Player", "RealMedia", "Helix" or any other +trademarks or trade names belonging to RealNetworks. + +RealNetworks "Licensor Trademark Policy" forbids any use of Licensor Trademarks +except as permitted by and in strict compliance at all times with RealNetworks' +third party trademark usage guidelines which are posted at +http://www.realnetworks.com/info/helixlogo.html. + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/Umakefil b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/Umakefil new file mode 100644 index 0000000..b04aa15 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/Umakefil @@ -0,0 +1,52 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: RCSL 1.0/RPSL 1.0 +# +# Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. +# +# The contents of this file, and the files included with this file, are +# subject to the current version of the RealNetworks Public Source License +# Version 1.0 (the "RPSL") available at +# http://www.helixcommunity.org/content/rpsl unless you have licensed +# the file under the RealNetworks Community Source License Version 1.0 +# (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, +# in which case the RCSL will apply. You may also obtain the license terms +# directly from RealNetworks. You may not use this file except in +# compliance with the RPSL or, if you have a valid RCSL with RealNetworks +# applicable to this file, the RCSL. Please see the applicable RPSL or +# RCSL for the rights, obligations and limitations governing use of the +# contents of the file. +# +# This file is part of the Helix DNA Technology. RealNetworks is the +# developer of the Original Code and owns the copyrights in the portions +# it created. +# +# This file, and the files included with this file, is distributed and made +# available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# +# Technology Compatibility Kit Test Suite(s) Location: +# http://www.helixcommunity.org/content/tck +# +# Contributor(s): +# +# ***** END LICENSE BLOCK ***** +# + +UmakefileVersion(2,1) + +# Uncomment to test using C API +# project.AddSources("main.c", "timing.c", "debug.c") + +# Uncomment to test using C++ API +project.AddSources("winmain.cpp", "timing.c", "debug.c") + +project.AddModuleIncludes("datatype/mp3/codec/fixpt/pub") +project.AddModuleLibraries("datatype/mp3/codec/fixpt[mp3codecfixpt]") + +ProgramTarget("mp3dec") + +DependTarget() + diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/debug.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/debug.c new file mode 100644 index 0000000..8552a88 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/debug.c @@ -0,0 +1,143 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * debug.c - implementations of memory testing functions + **************************************************************************************/ + +#include +#include "debug.h" + +#if !defined (_DEBUG) + +void DebugMemCheckInit(void) +{ +} + +void DebugMemCheckStartPoint(void) +{ +} + +void DebugMemCheckEndPoint(void) +{ +} + +void DebugMemCheckFree(void) +{ +} + +#elif defined (_WIN32) && !defined (_WIN32_WCE) + +#include + +#ifdef FORTIFY +#include "fortify.h" +#else +static _CrtMemState oldState, newState, stateDiff; +#endif + +void DebugMemCheckInit(void) +{ + int tmpDbgFlag; + + /* Send all reports to STDOUT */ + _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT ); + _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT ); + _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE ); + _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT ); + + tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF; + tmpDbgFlag |= _CRTDBG_CHECK_ALWAYS_DF; + _CrtSetDbgFlag(tmpDbgFlag); +} + +void DebugMemCheckStartPoint(void) +{ +#ifdef FORTIFY + Fortify_EnterScope(); +#else + _CrtMemCheckpoint(&oldState); +#endif +} + +void DebugMemCheckEndPoint(void) +{ +#ifdef FORTIFY + Fortify_LeaveScope(); +#else + _CrtMemCheckpoint(&newState); + _CrtMemDifference(&stateDiff, &oldState, &newState); + _CrtMemDumpStatistics(&stateDiff); +#endif +} + +void DebugMemCheckFree(void) +{ + printf("\n"); + if (!_CrtDumpMemoryLeaks()) + printf("Memory leak test: no leaks\n"); + + if (!_CrtCheckMemory()) + printf("Memory integrity test: error!\n"); + else + printf("Memory integrity test: okay\n"); +} + +#elif defined (ARM_ADS) + +void DebugMemCheckInit(void) +{ +} + +void DebugMemCheckStartPoint(void) +{ +} + +void DebugMemCheckEndPoint(void) +{ +} + +void DebugMemCheckFree(void) +{ +} + +#endif diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/debug.h b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/debug.h new file mode 100644 index 0000000..527e311 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/debug.h @@ -0,0 +1,53 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _DEBUG_H +#define _DEBUG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* debug.c */ +void DebugMemCheckInit(void); +void DebugMemCheckStartPoint(void); +void DebugMemCheckEndPoint(void); +void DebugMemCheckFree(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DEBUG_H */ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/main.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/main.c new file mode 100644 index 0000000..0d4d93d --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/main.c @@ -0,0 +1,200 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * main.c - command-line test app that uses C interface to MP3 decoder + **************************************************************************************/ + +#include +#include +#include + +#include "mp3dec.h" +#include "debug.h" +#include "timing.h" + +#define READBUF_SIZE (1024*16) /* feel free to change this, but keep big enough for >= one frame at high bitrates */ +#define MAX_ARM_FRAMES 100 +#define ARMULATE_MUL_FACT 1 + +static int FillReadBuffer(unsigned char *readBuf, unsigned char *readPtr, int bufSize, int bytesLeft, FILE *infile) +{ + int nRead; + + /* move last, small chunk from end of buffer to start, then fill with new data */ + memmove(readBuf, readPtr, bytesLeft); + nRead = fread(readBuf + bytesLeft, 1, bufSize - bytesLeft, infile); + /* zero-pad to avoid finding false sync word after last frame (from old data in readBuf) */ + if (nRead < bufSize - bytesLeft) + memset(readBuf + bytesLeft + nRead, 0, bufSize - bytesLeft - nRead); + + return nRead; +} + +int main(int argc, char **argv) +{ + int bytesLeft, nRead, err, offset, outOfData, eofReached; + unsigned char readBuf[READBUF_SIZE], *readPtr; + short outBuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP]; + FILE *infile, *outfile; + MP3FrameInfo mp3FrameInfo; + HMP3Decoder hMP3Decoder; + int startTime, endTime, diffTime, totalDecTime, nFrames; +#ifdef ARM_ADS + float audioSecs; +#endif + + if (argc != 3) { + printf("usage: mp3dec infile.mp3 outfile.pcm\n"); + return -1; + } + infile = fopen(argv[1], "rb"); + if (!infile) { + printf("file open error\n"); + return -1; + } + + if (strcmp(argv[2], "nul")) { + outfile = fopen(argv[2], "wb"); + if (!outfile) { + printf("file open error\n"); + return -1; + } + } else { + outfile = 0; /* nul output */ + } + + DebugMemCheckInit(); + InitTimer(); + + DebugMemCheckStartPoint(); + + if ( (hMP3Decoder = MP3InitDecoder()) == 0 ) + return -2; + + DebugMemCheckEndPoint(); + + bytesLeft = 0; + outOfData = 0; + eofReached = 0; + readPtr = readBuf; + nRead = 0; + totalDecTime = 0; + nFrames = 0; + do { + /* somewhat arbitrary trigger to refill buffer - should always be enough for a full frame */ + if (bytesLeft < 2*MAINBUF_SIZE && !eofReached) { + nRead = FillReadBuffer(readBuf, readPtr, READBUF_SIZE, bytesLeft, infile); + bytesLeft += nRead; + readPtr = readBuf; + if (nRead == 0) + eofReached = 1; + } + + /* find start of next MP3 frame - assume EOF if no sync found */ + offset = MP3FindSyncWord(readPtr, bytesLeft); + if (offset < 0) { + outOfData = 1; + break; + } + readPtr += offset; + bytesLeft -= offset; + + + /* decode one MP3 frame - if offset < 0 then bytesLeft was less than a full frame */ + startTime = ReadTimer(); + err = MP3Decode(hMP3Decoder, &readPtr, &bytesLeft, outBuf, 0); + nFrames++; + + endTime = ReadTimer(); + diffTime = CalcTimeDifference(startTime, endTime); + totalDecTime += diffTime; + +#if defined ARM_ADS && defined MAX_ARM_FRAMES + printf("frame %5d start = %10d, end = %10d elapsed = %10d ticks\r", + nFrames, startTime, endTime, diffTime); + fflush(stdout); +#endif + + if (err) { + /* error occurred */ + switch (err) { + case ERR_MP3_INDATA_UNDERFLOW: + outOfData = 1; + break; + case ERR_MP3_MAINDATA_UNDERFLOW: + /* do nothing - next call to decode will provide more mainData */ + break; + case ERR_MP3_FREE_BITRATE_SYNC: + default: + outOfData = 1; + break; + } + } else { + /* no error */ + MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); + if (outfile) + fwrite(outBuf, mp3FrameInfo.bitsPerSample / 8, mp3FrameInfo.outputSamps, outfile); + } + +#if defined ARM_ADS && defined MAX_ARM_FRAMES + if (nFrames >= MAX_ARM_FRAMES) + break; +#endif + } while (!outOfData); + + +#ifdef ARM_ADS + MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); + audioSecs = ((float)nFrames * mp3FrameInfo.outputSamps) / ( (float)mp3FrameInfo.samprate * mp3FrameInfo.nChans); + printf("\nTotal clock ticks = %d, MHz usage = %.2f\n", totalDecTime, ARMULATE_MUL_FACT * (1.0f / audioSecs) * totalDecTime * GetClockDivFactor() / 1e6f); + printf("nFrames = %d, output samps = %d, sampRate = %d, nChans = %d\n", nFrames, mp3FrameInfo.outputSamps, mp3FrameInfo.samprate, mp3FrameInfo.nChans); +#endif + + MP3FreeDecoder(hMP3Decoder); + + fclose(infile); + if (outfile) + fclose(outfile); + + FreeTimer(); + DebugMemCheckFree(); + + return 0; +} diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/timing.c b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/timing.c new file mode 100644 index 0000000..a83c520 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/timing.c @@ -0,0 +1,185 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * timing.c - implementations of CPU timing functions + **************************************************************************************/ + +#include "timing.h" + +/* NOTES: + * - for armulator (ARM_ADS) use -clock 100 (100 Hz system clock) for accurate + * timing since CLOCKS_PER_SEC = 100 (this only works for zero wait-state + * memory unless you adjust memory timings accordingly) + * - other option for armulator is to simulate accurate hardware timers (see below) + */ +#if (defined (_WIN32) && !defined (_WIN32_WCE)) || defined (ARM_ADS) || (defined (__GNUC__) && defined (ARM)) + +#include + +int InitTimer(void) +{ + return 0; +} + +UINT ReadTimer(void) +{ + return clock(); +} + +int FreeTimer(void) +{ + return 0; +} + +UINT GetClockFrequency(void) +{ + return CLOCKS_PER_SEC; +} + +UINT GetClockDivFactor(void) +{ + return 1; +} + +UINT CalcTimeDifference(UINT startTime, UINT endTime) +{ + /* timer counts up on x86, 32-bit counter */ + if (endTime < startTime) + return (0x7fffffff - (startTime - endTime) ); + else + return (endTime - startTime); +} +#elif defined (_WIN32) && defined (_WIN32_WCE) + +#include + +int InitTimer(void) +{ + return 0; +} + +UINT ReadTimer(void) +{ + return GetTickCount(); +} + +int FreeTimer(void) +{ + return 0; +} + +UINT GetClockFrequency(void) +{ + return 1000; +} + +UINT GetClockDivFactor(void) +{ + return 1; +} + +UINT CalcTimeDifference(UINT startTime, UINT endTime) +{ + /* timer counts up on x86, 32-bit counter */ + if (endTime < startTime) + return (0x7fffffff - (startTime - endTime) ); + else + return (endTime - startTime); +} + +#elif 0 /* if defined ARM_ADS - this uses simulated high-res hardware timers */ + +/* see definitions in ADSv1_2/bin/peripherals.ami */ +#define TIMER_BASE 0x0a800000 +#define TIMER_VALUE_1 (TIMER_BASE + 0x04) +#define TIMER_CONTROL_1 (TIMER_BASE + 0x08) + +int InitTimer(void) +{ + volatile unsigned int *timerControl1 = (volatile unsigned int *)TIMER_CONTROL_1; + unsigned int control1; + + /* see ARMulator Reference, pg 4-78 + * bits [3:2] = clock divisor factor (00 = 1, 01 = 16, 10 = 256, 11 = undef) + * bit [6] = free-running mode (0) or periodic mode (1) + * bit [7] = timer disabled (0) or enabled (1) + */ + control1 = 0x00000088; + *timerControl1 = control1; + + return 0; +} + +UINT ReadTimer(void) +{ + volatile unsigned int *timerValue1 = (volatile unsigned int *)TIMER_VALUE_1; + unsigned int value; + + value = *timerValue1 & 0x0000ffff; + + return (UINT)value; +} + +int FreeTimer(void) +{ + return 0; +} + +UINT GetClockFrequency(void) +{ + return 0; +} + +UINT GetClockDivFactor(void) +{ + return 256; +} + +UINT CalcTimeDifference(UINT startTime, UINT endTime) +{ + + /* timer counts down int ARMulator, 16-bit counter */ + if (endTime > startTime) + return (startTime + 0x00010000 - endTime); + else + return (startTime - endTime); +} + +#endif diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/timing.h b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/timing.h new file mode 100644 index 0000000..b997177 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/timing.h @@ -0,0 +1,56 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _TIMING_H +#define _TIMING_H + +typedef unsigned int UINT; + +#ifdef __cplusplus +extern "C" { +#endif + +int InitTimer(void); +UINT ReadTimer(void); +int FreeTimer(void); +UINT GetClockFrequency(void); +UINT GetClockDivFactor(void); +UINT CalcTimeDifference(UINT startTime, UINT endTime); + +#ifdef __cplusplus +} +#endif + +#endif /* _TIMING_H */ diff --git a/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/winmain.cpp b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/winmain.cpp new file mode 100644 index 0000000..38cd9d1 --- /dev/null +++ b/managed_components/chmorgan__esp-libhelix-mp3/libhelix-mp3/testwrap/winmain.cpp @@ -0,0 +1,203 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: RCSL 1.0/RPSL 1.0 + * + * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. + * + * The contents of this file, and the files included with this file, are + * subject to the current version of the RealNetworks Public Source License + * Version 1.0 (the "RPSL") available at + * http://www.helixcommunity.org/content/rpsl unless you have licensed + * the file under the RealNetworks Community Source License Version 1.0 + * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, + * in which case the RCSL will apply. You may also obtain the license terms + * directly from RealNetworks. You may not use this file except in + * compliance with the RPSL or, if you have a valid RCSL with RealNetworks + * applicable to this file, the RCSL. Please see the applicable RPSL or + * RCSL for the rights, obligations and limitations governing use of the + * contents of the file. + * + * This file is part of the Helix DNA Technology. RealNetworks is the + * developer of the Original Code and owns the copyrights in the portions + * it created. + * + * This file, and the files included with this file, is distributed and made + * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * + * Technology Compatibility Kit Test Suite(s) Location: + * http://www.helixcommunity.org/content/tck + * + * Contributor(s): + * + * ***** END LICENSE BLOCK ***** */ + +/************************************************************************************** + * Fixed-point MP3 decoder + * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) + * June 2003 + * + * winmain.cpp - command-line test app that uses C++ interface to MP3 decoder + **************************************************************************************/ + +#include +#include +#include + +#include "mpadecobjfixpt.h" +#include "debug.h" +#include "timing.h" + +#define READBUF_SIZE (1024*16) /* feel free to change this, but keep big enough for >= one frame at high bitrates */ +#define MAX_ARM_FRAMES 25 + +static int FillReadBuffer(unsigned char *readBuf, unsigned char *readPtr, int bufSize, int bytesLeft, FILE *infile) +{ + int nRead; + + /* move last, small chunk from end of buffer to start, then fill with new data */ + memmove(readBuf, readPtr, bytesLeft); + nRead = fread(readBuf + bytesLeft, 1, bufSize - bytesLeft, infile); + /* zero-pad to avoid finding false sync word after last frame (from old data in readBuf) */ + if (nRead < bufSize - bytesLeft) + memset(readBuf + bytesLeft + nRead, 0, bufSize - bytesLeft - nRead); + + return nRead; +} + +#if defined (_WIN32) && defined (_WIN32_WCE) +#include +#define main TestMain +static int main(int argc, char **argv); + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) +{ + /* not designed to do anything right now - just lets us build application to force linker + * to run and check for link errors + */ + char *testArgs[3] = { + "testwrap.exe", + "\\My Documents\\test128.mp3", + "nul" + }; + + TestMain(3, testArgs); + + return 0; +} + +#endif + +int main(int argc, char **argv) +{ + int bytesLeft, bytesIn, err, nRead, offset, outOfData, eofReached; + unsigned char readBuf[READBUF_SIZE], *readPtr; + short outBuf[MAX_NCHAN * MAX_NGRAN * MAX_NSAMP]; + FILE *infile, *outfile; + int initFlag, chans, bits; + unsigned long sampRate, outBytes; + CMpaDecObj *decobj; + + if (argc != 3) { + printf("usage: mp3dec infile.mp3 outfile.pcm\n"); + return -1; + } + infile = fopen(argv[1], "rb"); + if (!infile) { + printf("file open error\n"); + return -1; + } + + if (strcmp(argv[2], "nul")) { + outfile = fopen(argv[2], "wb"); + if (!outfile) { + printf("file open error\n"); + return -1; + } + } else { + outfile = 0; /* nul output */ + } + + DebugMemCheckInit(); + decobj = new CMpaDecObj; + if (!decobj) + return -1; + + bytesLeft = 0; + outOfData = 0; + eofReached = 0; + readPtr = readBuf; + nRead = 0; + err = 0; + initFlag = 0; + do { + /* somewhat arbitrary trigger to refill buffer - should always be enough for a full frame */ + if (bytesLeft < 2*MAINBUF_SIZE && !eofReached) { + nRead = FillReadBuffer(readBuf, readPtr, READBUF_SIZE, bytesLeft, infile); + bytesLeft += nRead; + readPtr = readBuf; + if (nRead == 0) + eofReached = 1; + } + + /* find start of next MP3 frame - assume EOF if no sync found */ + offset = MP3FindSyncWord(readPtr, bytesLeft); + if (offset < 0) { + outOfData = 1; + break; + } + readPtr += offset; + bytesLeft -= offset; + + /* lazy initialization for backwards compatibility with mpadecobj API */ + if (!initFlag) { + DebugMemCheckStartPoint(); + if (!decobj->Init_n(readPtr, bytesLeft)) + return -1; /* init error */ + DebugMemCheckEndPoint(); + + decobj->GetPCMInfo_v(sampRate, chans, bits); + decobj->GetSamplesPerFrame_n(); + initFlag = 1; + } + + /* decode one MP3 frame - if offset < 0 then bytesLeft was less than a full frame */ + outBytes = sizeof(outBuf); + bytesIn = bytesLeft; + decobj->DecodeFrame_v(readPtr, (unsigned long *)(&bytesIn), (unsigned char *)outBuf, &outBytes, &err); + readPtr += bytesIn; + bytesLeft -= bytesIn; + + if (err) { + /* error occurred */ + switch (err) { + case ERR_MP3_INDATA_UNDERFLOW: + outOfData = 1; + break; + case ERR_MP3_MAINDATA_UNDERFLOW: + /* do nothing - next call to decode will provide more mainData */ + break; + case ERR_MP3_FREE_BITRATE_SYNC: + default: + outOfData = 1; + break; + } + } else { + /* no error */ + if (outfile) + fwrite(outBuf, 1, (unsigned int)outBytes, outfile); + } + } while (!outOfData); + + fclose(infile); + if (outfile) + fclose(outfile); + + delete decobj; + + DebugMemCheckFree(); + + return 0; +} + diff --git a/managed_components/espressif__button/.component_hash b/managed_components/espressif__button/.component_hash new file mode 100644 index 0000000..983b521 --- /dev/null +++ b/managed_components/espressif__button/.component_hash @@ -0,0 +1 @@ +30a3f495c3862d505ce6e41adbbd218b2750e9723ab2151feff00e9fe685b326 \ No newline at end of file diff --git a/managed_components/espressif__button/CHANGELOG.md b/managed_components/espressif__button/CHANGELOG.md new file mode 100644 index 0000000..818132b --- /dev/null +++ b/managed_components/espressif__button/CHANGELOG.md @@ -0,0 +1,157 @@ +# ChangeLog + +## v3.5.0 - 2024-12-27 + +### Enhancements: + +* Add config to disable gpio button internal pull resistor. + +## v3.4.1 - 2024-12-6 + +### Fix: + +* Fix the issue where `BUTTON_LONG_PRESS_START` is not triggered when the polling interval exceeds 20ms. +* Remove the `BUTTON_LONG_PRESS_TOLERANCE_MS` configuration option. + +## v3.4.0 - 2024-10-22 + +### Enhancements: + +* Supports a maximum button polling interval of 500ms. +* Fixed a potential counter overflow issue. + +### Break change: + +* The return value of `iot_button_get_ticks_time` has been changed from `uint16_t` to `uint32_t`. + +## v3.3.2 - 2024-8-28 + +### Enhancements: + +* Support macro CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP in power save mode. +* Supports retrieving and printing the string corresponding to a button event. +* Fixed the bug where the event was not assigned to `BUTTON_LONG_PRESS_START` before the `BUTTON_LONG_PRESS_START` event occurred. + +## v3.3.1 - 2024-8-8 + +### Enhancements: + +* Add Button Event **BUTTON_PRESS_END**. + +## v3.3.0 - 2024-8-7 + +### Enhancements: + +* Add Callback **button_power_save_cb_t** to support enter power save manually. +* Increase the maximum polling interval supported by the button from 20ms to 50ms. + +## v3.2.3 - 2024-7-2 + +* Fixed the issue where the GPIO button in low-power mode continuously woke up the CPU after being pressed, causing abnormal power consumption. + +## v3.2.2 - 2024-6-17 + +* Fix the compilation error for chips that do not support ADC. + +## v3.2.1 - 2024-6-17 + +### bugfix + +- Fixed ignored ADC button tied to GND. thanks `demianzenkov` for the fix. + +## v3.2.0 - 2023-11-13 + +### Enhancements: + +* The power consumption of GPIO buttons is lower during light sleep mode. + +## v3.1.3 - 2023-11-13 + +* Resolved issue 'ADC_ATTEN_DB_11 is deprecated'. + +## v3.1.2 - 2023-10-24 + +### bugfix + +* Fixed a bug where iot_button_delete feature crashes for custom button + +## v3.1.1 - 2023-10-18 + +### bugfix + +* Fixed a bug where multiple callbacks feature crashes for BUTTON_MULTIPLE_CLICK + +## v3.1.0 - 2023-10-9 + +### Enhancements: + +* Support matrix keypad + +## v3.0.1 - 2023-9-1 + +### Enhancements: + +* Resolves bug for iot_button_unregister_event function returned error when reallocating with 0 byte. +* Update Test cases to test iot_button_unregister_event_cb +* Add api iot_button_stop & iot_button_resume for power save. + +## v3.0.0 - 2023-8-15 + +### Enhancements: + +* Add support to register multiple callbacks for a button_event + + * Update iot_button_unregister_cb, to unregister all the callbacks for that event + * Add iot_button_unregister_event to unregister specific callbacks of that event + * Add iot_button_count_event to return number of callbacks registered for the event. + * Update iot_button_count_cb, to return sum of number of registered callbacks. + +* Add support for Long press on specific time + + * Add iot_button_register_event, which takes specific event_config_t data as input. + * Add BUTTON_LONG_PRESS_UP to trigger callback at the latest time of button release + * Update BUTTON_LONG_PRESS_START to trigger callback as the time passes for long_press. + +* Add support to trigger callback for specified number of clicks. + +## v2.5.6 - 2023-8-22 + +### bugfix + +* Fixed a bug where the Serial trigger interval in button_long_press_hold event fires at an incorrect time + +## v2.5.5 - 2023-8-3 + +* Add modify api which can change long_press_time and short_press_time + +## v2.5.4 - 2023-7-27 + +### Enhancements: + +* Add test apps and ci auto test + +## v2.5.3 - 2023-7-26 + +### Enhancements: + +* `repeat` defined in struct button_dev_t is reset to 0 after event `BUTTON_PRESS_REPEAT_DONE` + +## v2.5.2 - 2023-7-18 + +### Enhancements: + +* Set "event" member to BUTTON_PRESS_REPEAT before calling the BUTTON_PRESS_REPEAT callback + +## v2.5.1 - 2023-3-14 + +### Enhancements: + +* Update doc and code specification +* Avoid overwriting callback by @franz-ms-muc in #252 + +## v2.5.0 - 2023-2-1 + +### Enhancements: + +* Support custom button +* Add BUTTON_PRESS_REPEAT_DONE event diff --git a/managed_components/espressif__button/CMakeLists.txt b/managed_components/espressif__button/CMakeLists.txt new file mode 100644 index 0000000..2c0a5d8 --- /dev/null +++ b/managed_components/espressif__button/CMakeLists.txt @@ -0,0 +1,32 @@ +set(PRIVREQ esp_timer) +set(REQ driver) +set(SRC_FILES "button_gpio.c" "iot_button.c" "button_matrix.c") + +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + list(APPEND REQ esp_adc) + if(CONFIG_SOC_ADC_SUPPORTED) + list(APPEND SRC_FILES "button_adc.c") + endif() +else() + list(APPEND REQ esp_adc_cal) + list(APPEND SRC_FILES "button_adc.c") +endif() + +idf_component_register(SRCS ${SRC_FILES} + INCLUDE_DIRS include + REQUIRES ${REQ} + PRIV_REQUIRES ${PRIVREQ}) + +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_LESS "5.0") + # Add the macro CONFIG_SOC_ADC_SUPPORTED for the following chips. + if(CONFIG_IDF_TARGET STREQUAL "esp32" OR + CONFIG_IDF_TARGET STREQUAL "esp32s2" OR + CONFIG_IDF_TARGET STREQUAL "esp32s3" OR + CONFIG_IDF_TARGET STREQUAL "esp32c3" OR + CONFIG_IDF_TARGET STREQUAL "esp32h2") + target_compile_definitions(${COMPONENT_LIB} PUBLIC CONFIG_SOC_ADC_SUPPORTED) + endif() +endif() + +include(package_manager) +cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR}) diff --git a/managed_components/espressif__button/Kconfig b/managed_components/espressif__button/Kconfig new file mode 100644 index 0000000..35cb17e --- /dev/null +++ b/managed_components/espressif__button/Kconfig @@ -0,0 +1,65 @@ +menu "IoT Button" + + config BUTTON_PERIOD_TIME_MS + int "BUTTON PERIOD TIME (MS)" + range 2 500 + default 5 + help + "Button scan interval" + + config BUTTON_DEBOUNCE_TICKS + int "BUTTON DEBOUNCE TICKS" + range 1 7 + default 2 + help + "One CONFIG_BUTTON_DEBOUNCE_TICKS equal to CONFIG_BUTTON_PERIOD_TIME_MS" + + config BUTTON_SHORT_PRESS_TIME_MS + int "BUTTON SHORT PRESS TIME (MS)" + range 50 800 + default 180 + + config BUTTON_LONG_PRESS_TIME_MS + int "BUTTON LONG PRESS TIME (MS)" + range 500 5000 + default 1500 + + config BUTTON_SERIAL_TIME_MS + int "BUTTON SERIAL TIME (MS)" + range 2 1000 + default 20 + help + "Serial trigger interval" + + config GPIO_BUTTON_SUPPORT_POWER_SAVE + bool "GPIO BUTTON SUPPORT POWER SAVE" + default n + help + Enable GPIO button power save + + The function enables the use of GPIO buttons during light sleep, + but enabling this function prevents the simultaneous use of other + types of buttons. + + config ADC_BUTTON_MAX_CHANNEL + int "ADC BUTTON MAX CHANNEL" + range 1 5 + default 3 + help + "Maximum number of channels for ADC buttons" + + config ADC_BUTTON_MAX_BUTTON_PER_CHANNEL + int "ADC BUTTON MAX BUTTON PER CHANNEL" + range 1 10 + default 8 + help + "Maximum number of buttons per channel" + + config ADC_BUTTON_SAMPLE_TIMES + int "ADC BUTTON SAMPLE TIMES" + range 1 4 + default 1 + help + "Number of samples per scan" + +endmenu diff --git a/managed_components/espressif__button/README.md b/managed_components/espressif__button/README.md new file mode 100644 index 0000000..3fd7d12 --- /dev/null +++ b/managed_components/espressif__button/README.md @@ -0,0 +1,42 @@ +[![Component Registry](https://components.espressif.com/components/espressif/button/badge.svg)](https://components.espressif.com/components/espressif/button) + +# Component: Button +[Online documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/input_device/button.html) + +After creating a new button object by calling function `button_create()`, the button object can create press events, every press event can have its own callback. + +List of supported events: + * Button pressed + * Button released + * Button pressed repeat + * Button press repeat done + * Button single click + * Button double click + * Button multiple click + * Button long press start + * Button long press hold + * Button long press up + * Button Press end + +![](https://dl.espressif.com/AE/esp-iot-solution/button_3.3.1.svg) + +There are three ways this driver can handle buttons: +1. Buttons connected to standard digital GPIO +2. Multiple buttons connected to single ADC channel +3. Matrix keyboard employs multiple GPIOs for operation. +4. Custom button connect to any driver + +The component supports the following functionalities: +1. Creation of an unlimited number of buttons, accommodating various types simultaneously. +2. Multiple callback functions for a single event. +3. Allowing customization of the consecutive key press count to any desired number. +4. Facilitating the setup of callbacks for any specified long-press duration. +5. Support power save mode (Only for gpio button) + +## Add component to your project + +Please use the component manager command `add-dependency` to add the `button` to your project's dependency, during the `CMake` step the component will be downloaded automatically + +``` +idf.py add-dependency "espressif/button=*" +``` \ No newline at end of file diff --git a/managed_components/espressif__button/button_adc.c b/managed_components/espressif__button/button_adc.c new file mode 100644 index 0000000..96e527a --- /dev/null +++ b/managed_components/espressif__button/button_adc.c @@ -0,0 +1,312 @@ +/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "esp_log.h" +#include "esp_timer.h" +#include "esp_idf_version.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#include "soc/soc_caps.h" +#include "esp_adc/adc_oneshot.h" +#include "esp_adc/adc_cali.h" +#include "esp_adc/adc_cali_scheme.h" +#else +#include "driver/gpio.h" +#include "driver/adc.h" +#include "esp_adc_cal.h" +#endif +#include "button_adc.h" + +static const char *TAG = "adc button"; + +#define ADC_BTN_CHECK(a, str, ret_val) \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): %s", __FUNCTION__, __LINE__, str); \ + return (ret_val); \ + } + +#define DEFAULT_VREF 1100 +#define NO_OF_SAMPLES CONFIG_ADC_BUTTON_SAMPLE_TIMES //Multisampling + +/*!< Using atten bigger than 6db by default, it will be 11db or 12db in different target */ +#define DEFAULT_ADC_ATTEN (ADC_ATTEN_DB_6 + 1) + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#define ADC_BUTTON_WIDTH SOC_ADC_RTC_MAX_BITWIDTH +#define ADC1_BUTTON_CHANNEL_MAX SOC_ADC_MAX_CHANNEL_NUM +#define ADC_BUTTON_ATTEN DEFAULT_ADC_ATTEN +#else +#define ADC_BUTTON_WIDTH ADC_WIDTH_MAX-1 +#define ADC1_BUTTON_CHANNEL_MAX ADC1_CHANNEL_MAX +#define ADC_BUTTON_ATTEN DEFAULT_ADC_ATTEN +#endif +#define ADC_BUTTON_ADC_UNIT ADC_UNIT_1 +#define ADC_BUTTON_MAX_CHANNEL CONFIG_ADC_BUTTON_MAX_CHANNEL +#define ADC_BUTTON_MAX_BUTTON CONFIG_ADC_BUTTON_MAX_BUTTON_PER_CHANNEL + +typedef struct { + uint16_t min; + uint16_t max; +} button_data_t; + +typedef struct { + uint8_t channel; + uint8_t is_init; + button_data_t btns[ADC_BUTTON_MAX_BUTTON]; /* all button on the channel */ + uint64_t last_time; /* the last time of adc sample */ +} btn_adc_channel_t; + +typedef struct { + bool is_configured; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + adc_cali_handle_t adc1_cali_handle; + adc_oneshot_unit_handle_t adc1_handle; +#else + esp_adc_cal_characteristics_t adc_chars; +#endif + btn_adc_channel_t ch[ADC_BUTTON_MAX_CHANNEL]; + uint8_t ch_num; +} adc_button_t; + +static adc_button_t g_button = {0}; + +static int find_unused_channel(void) +{ + for (size_t i = 0; i < ADC_BUTTON_MAX_CHANNEL; i++) { + if (0 == g_button.ch[i].is_init) { + return i; + } + } + return -1; +} + +static int find_channel(uint8_t channel) +{ + for (size_t i = 0; i < ADC_BUTTON_MAX_CHANNEL; i++) { + if (channel == g_button.ch[i].channel) { + return i; + } + } + return -1; +} + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +static esp_err_t adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle) +{ + adc_cali_handle_t handle = NULL; + esp_err_t ret = ESP_FAIL; + bool calibrated = false; + +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + if (!calibrated) { + ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting"); + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = ADC_BUTTON_WIDTH, + }; + ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle); + if (ret == ESP_OK) { + calibrated = true; + } + } +#endif + +#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + if (!calibrated) { + ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting"); + adc_cali_line_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = ADC_BUTTON_WIDTH, + }; + ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle); + if (ret == ESP_OK) { + calibrated = true; + } + } +#endif + + *out_handle = handle; + if (ret == ESP_OK) { + ESP_LOGI(TAG, "Calibration Success"); + } else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) { + ESP_LOGW(TAG, "eFuse not burnt, skip software calibration"); + } else { + ESP_LOGE(TAG, "Invalid arg or no memory"); + } + + return calibrated ? ESP_OK : ESP_FAIL; +} +#endif + +esp_err_t button_adc_init(const button_adc_config_t *config) +{ + ADC_BTN_CHECK(NULL != config, "Pointer of config is invalid", ESP_ERR_INVALID_ARG); + ADC_BTN_CHECK(config->adc_channel < ADC1_BUTTON_CHANNEL_MAX, "channel out of range", ESP_ERR_NOT_SUPPORTED); + ADC_BTN_CHECK(config->button_index < ADC_BUTTON_MAX_BUTTON, "button_index out of range", ESP_ERR_NOT_SUPPORTED); + ADC_BTN_CHECK(config->max > 0, "key max voltage invalid", ESP_ERR_INVALID_ARG); + + int ch_index = find_channel(config->adc_channel); + if (ch_index >= 0) { /**< the channel has been initialized */ + ADC_BTN_CHECK(g_button.ch[ch_index].btns[config->button_index].max == 0, "The button_index has been used", ESP_ERR_INVALID_STATE); + } else { /**< this is a new channel */ + int unused_ch_index = find_unused_channel(); + ADC_BTN_CHECK(unused_ch_index >= 0, "exceed max channel number, can't create a new channel", ESP_ERR_INVALID_STATE); + ch_index = unused_ch_index; + } + + /** initialize adc */ + if (0 == g_button.is_configured) { +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + esp_err_t ret; + if (NULL == config->adc_handle) { + //ADC1 Init + adc_oneshot_unit_init_cfg_t init_config = { + .unit_id = ADC_UNIT_1, + }; + ret = adc_oneshot_new_unit(&init_config, &g_button.adc1_handle); + ADC_BTN_CHECK(ret == ESP_OK, "adc oneshot new unit fail!", ESP_FAIL); + } else { + g_button.adc1_handle = *config->adc_handle ; + ESP_LOGI(TAG, "ADC1 has been initialized"); + } +#else + //Configure ADC + adc1_config_width(ADC_BUTTON_WIDTH); + //Characterize ADC + esp_adc_cal_value_t val_type = esp_adc_cal_characterize(ADC_BUTTON_ADC_UNIT, ADC_BUTTON_ATTEN, ADC_BUTTON_WIDTH, DEFAULT_VREF, &g_button.adc_chars); + if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) { + ESP_LOGI(TAG, "Characterized using Two Point Value"); + } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) { + ESP_LOGI(TAG, "Characterized using eFuse Vref"); + } else { + ESP_LOGI(TAG, "Characterized using Default Vref"); + } +#endif + g_button.is_configured = 1; + } + + /** initialize adc channel */ + if (0 == g_button.ch[ch_index].is_init) { +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + //ADC1 Config + adc_oneshot_chan_cfg_t oneshot_config = { + .bitwidth = ADC_BUTTON_WIDTH, + .atten = ADC_BUTTON_ATTEN, + }; + esp_err_t ret = adc_oneshot_config_channel(g_button.adc1_handle, config->adc_channel, &oneshot_config); + ADC_BTN_CHECK(ret == ESP_OK, "adc oneshot config channel fail!", ESP_FAIL); + //-------------ADC1 Calibration Init---------------// + ret = adc_calibration_init(ADC_BUTTON_ADC_UNIT, ADC_BUTTON_ATTEN, &g_button.adc1_cali_handle); + ADC_BTN_CHECK(ret == ESP_OK, "ADC1 Calibration Init False", 0); +#else + adc1_config_channel_atten(config->adc_channel, ADC_BUTTON_ATTEN); +#endif + g_button.ch[ch_index].channel = config->adc_channel; + g_button.ch[ch_index].is_init = 1; + g_button.ch[ch_index].last_time = 0; + } + g_button.ch[ch_index].btns[config->button_index].max = config->max; + g_button.ch[ch_index].btns[config->button_index].min = config->min; + g_button.ch_num++; + + return ESP_OK; +} + +esp_err_t button_adc_deinit(uint8_t channel, int button_index) +{ + ADC_BTN_CHECK(channel < ADC1_BUTTON_CHANNEL_MAX, "channel out of range", ESP_ERR_INVALID_ARG); + ADC_BTN_CHECK(button_index < ADC_BUTTON_MAX_BUTTON, "button_index out of range", ESP_ERR_INVALID_ARG); + + int ch_index = find_channel(channel); + ADC_BTN_CHECK(ch_index >= 0, "can't find the channel", ESP_ERR_INVALID_ARG); + + g_button.ch[ch_index].btns[button_index].max = 0; + g_button.ch[ch_index].btns[button_index].min = 0; + + /** check button usage on the channel*/ + uint8_t unused_button = 0; + for (size_t i = 0; i < ADC_BUTTON_MAX_BUTTON; i++) { + if (0 == g_button.ch[ch_index].btns[i].max) { + unused_button++; + } + } + if (unused_button == ADC_BUTTON_MAX_BUTTON && g_button.ch[ch_index].is_init) { /**< if all button is unused, deinit the channel */ + g_button.ch[ch_index].is_init = 0; + g_button.ch[ch_index].channel = ADC1_BUTTON_CHANNEL_MAX; + ESP_LOGD(TAG, "all button is unused on channel%d, deinit the channel", g_button.ch[ch_index].channel); + } + + /** check channel usage on the adc*/ + uint8_t unused_ch = 0; + for (size_t i = 0; i < ADC_BUTTON_MAX_CHANNEL; i++) { + if (0 == g_button.ch[i].is_init) { + unused_ch++; + } + } + if (unused_ch == ADC_BUTTON_MAX_CHANNEL && g_button.is_configured) { /**< if all channel is unused, deinit the adc */ + g_button.is_configured = false; + memset(&g_button, 0, sizeof(adc_button_t)); + ESP_LOGD(TAG, "all channel is unused, , deinit adc"); + } +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + esp_err_t ret = adc_oneshot_del_unit(g_button.adc1_handle); + ADC_BTN_CHECK(ret == ESP_OK, "adc oneshot deinit fail", ESP_FAIL); +#endif + return ESP_OK; +} + +static uint32_t get_adc_volatge(uint8_t channel) +{ + uint32_t adc_reading = 0; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + int adc_raw = 0; + for (int i = 0; i < NO_OF_SAMPLES; i++) { + adc_oneshot_read(g_button.adc1_handle, channel, &adc_raw); + adc_reading += adc_raw; + } + adc_reading /= NO_OF_SAMPLES; + //Convert adc_reading to voltage in mV + int voltage = 0; + adc_cali_raw_to_voltage(g_button.adc1_cali_handle, adc_reading, &voltage); + ESP_LOGV(TAG, "Raw: %"PRIu32"\tVoltage: %dmV", adc_reading, voltage); +#else + //Multisampling + for (int i = 0; i < NO_OF_SAMPLES; i++) { + adc_reading += adc1_get_raw(channel); + } + adc_reading /= NO_OF_SAMPLES; + //Convert adc_reading to voltage in mV + uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, &g_button.adc_chars); + ESP_LOGV(TAG, "Raw: %"PRIu32"\tVoltage: %"PRIu32"mV", adc_reading, voltage); +#endif + return voltage; +} + +uint8_t button_adc_get_key_level(void *button_index) +{ + static uint16_t vol = 0; + uint32_t ch = ADC_BUTTON_SPLIT_CHANNEL(button_index); + uint32_t index = ADC_BUTTON_SPLIT_INDEX(button_index); + ADC_BTN_CHECK(ch < ADC1_BUTTON_CHANNEL_MAX, "channel out of range", 0); + ADC_BTN_CHECK(index < ADC_BUTTON_MAX_BUTTON, "button_index out of range", 0); + int ch_index = find_channel(ch); + ADC_BTN_CHECK(ch_index >= 0, "The button_index is not init", 0); + + /** It starts only when the elapsed time is more than 1ms */ + if ((esp_timer_get_time() - g_button.ch[ch_index].last_time) > 1000) { + vol = get_adc_volatge(ch); + g_button.ch[ch_index].last_time = esp_timer_get_time(); + } + + if (vol <= g_button.ch[ch_index].btns[index].max && + vol >= g_button.ch[ch_index].btns[index].min) { + return 1; + } + return 0; +} diff --git a/managed_components/espressif__button/button_gpio.c b/managed_components/espressif__button/button_gpio.c new file mode 100644 index 0000000..7b2ea07 --- /dev/null +++ b/managed_components/espressif__button/button_gpio.c @@ -0,0 +1,114 @@ +/* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_log.h" +#include "driver/gpio.h" +#include "button_gpio.h" +#include "esp_sleep.h" + +static const char *TAG = "gpio button"; + +#define GPIO_BTN_CHECK(a, str, ret_val) \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): %s", __FUNCTION__, __LINE__, str); \ + return (ret_val); \ + } + +esp_err_t button_gpio_init(const button_gpio_config_t *config) +{ + GPIO_BTN_CHECK(NULL != config, "Pointer of config is invalid", ESP_ERR_INVALID_ARG); + GPIO_BTN_CHECK(GPIO_IS_VALID_GPIO(config->gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + + gpio_config_t gpio_conf; + gpio_conf.intr_type = GPIO_INTR_DISABLE; + gpio_conf.mode = GPIO_MODE_INPUT; + gpio_conf.pin_bit_mask = (1ULL << config->gpio_num); + if (config->disable_pull) { + gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_conf.pull_up_en = GPIO_PULLUP_DISABLE; + } else { + if (config->active_level) { + gpio_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + gpio_conf.pull_up_en = GPIO_PULLUP_DISABLE; + } else { + gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE; + } + } + gpio_config(&gpio_conf); + +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE + if (config->enable_power_save) { +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + if (!esp_sleep_is_valid_wakeup_gpio(config->gpio_num)) { + ESP_LOGE(TAG, "GPIO %ld is not a valid wakeup source under CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE", config->gpio_num); + return ESP_FAIL; + } + gpio_hold_en(config->gpio_num); +#endif + /* Enable wake up from GPIO */ + esp_err_t ret = gpio_wakeup_enable(config->gpio_num, config->active_level == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL); + GPIO_BTN_CHECK(ret == ESP_OK, "Enable gpio wakeup failed", ESP_FAIL); +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP +#if SOC_PM_SUPPORT_EXT1_WAKEUP + ret = esp_sleep_enable_ext1_wakeup_io((1ULL << config->gpio_num), config->active_level == 0 ? ESP_EXT1_WAKEUP_ANY_LOW : ESP_EXT1_WAKEUP_ANY_HIGH); +#else + /*!< Not support etc: esp32c2, esp32c3. Target must support ext1 wakeup */ + ret = ESP_FAIL; + GPIO_BTN_CHECK(ret == ESP_OK, "Target must support ext1 wakeup", ESP_FAIL); +#endif +#else + ret = esp_sleep_enable_gpio_wakeup(); +#endif + GPIO_BTN_CHECK(ret == ESP_OK, "Configure gpio as wakeup source failed", ESP_FAIL); + } +#endif + + return ESP_OK; +} + +esp_err_t button_gpio_deinit(int gpio_num) +{ + return gpio_reset_pin(gpio_num);; +} + +uint8_t button_gpio_get_key_level(void *gpio_num) +{ + return (uint8_t)gpio_get_level((uint32_t)gpio_num); +} + +esp_err_t button_gpio_set_intr(int gpio_num, gpio_int_type_t intr_type, gpio_isr_t isr_handler, void *args) +{ + static bool isr_service_installed = false; + gpio_set_intr_type(gpio_num, intr_type); + if (!isr_service_installed) { + gpio_install_isr_service(ESP_INTR_FLAG_IRAM); + isr_service_installed = true; + } + gpio_isr_handler_add(gpio_num, isr_handler, args); + return ESP_OK; +} + +esp_err_t button_gpio_intr_control(int gpio_num, bool enable) +{ + if (enable) { + gpio_intr_enable(gpio_num); + } else { + gpio_intr_disable(gpio_num); + } + return ESP_OK; +} + +esp_err_t button_gpio_enable_gpio_wakeup(uint32_t gpio_num, uint8_t active_level, bool enable) +{ + esp_err_t ret; + if (enable) { + ret = gpio_wakeup_enable(gpio_num, active_level == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL); + } else { + ret = gpio_wakeup_disable(gpio_num); + } + return ret; +} diff --git a/managed_components/espressif__button/button_matrix.c b/managed_components/espressif__button/button_matrix.c new file mode 100644 index 0000000..113754e --- /dev/null +++ b/managed_components/espressif__button/button_matrix.c @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_log.h" +#include "driver/gpio.h" +#include "button_matrix.h" + +static const char *TAG = "matrix button"; + +#define MATRIX_BTN_CHECK(a, str, ret_val) \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): %s", __FUNCTION__, __LINE__, str); \ + return (ret_val); \ + } + +esp_err_t button_matrix_init(const button_matrix_config_t *config) +{ + MATRIX_BTN_CHECK(NULL != config, "Pointer of config is invalid", ESP_ERR_INVALID_ARG); + MATRIX_BTN_CHECK(GPIO_IS_VALID_GPIO(config->row_gpio_num), "row GPIO number error", ESP_ERR_INVALID_ARG); + MATRIX_BTN_CHECK(GPIO_IS_VALID_GPIO(config->col_gpio_num), "col GPIO number error", ESP_ERR_INVALID_ARG); + + // set row gpio as output + gpio_config_t gpio_conf = {0}; + gpio_conf.intr_type = GPIO_INTR_DISABLE; + gpio_conf.mode = GPIO_MODE_OUTPUT; + gpio_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + gpio_conf.pin_bit_mask = (1ULL << config->row_gpio_num); + gpio_config(&gpio_conf); + + // set col gpio as input + gpio_conf.mode = GPIO_MODE_INPUT; + gpio_conf.pin_bit_mask = (1ULL << config->col_gpio_num); + gpio_config(&gpio_conf); + + return ESP_OK; +} + +esp_err_t button_matrix_deinit(int row_gpio_num, int col_gpio_num) +{ + //Reset an gpio to default state (select gpio function, enable pullup and disable input and output). + gpio_reset_pin(row_gpio_num); + gpio_reset_pin(col_gpio_num); + return ESP_OK; +} + +uint8_t button_matrix_get_key_level(void *hardware_data) +{ + uint32_t row = MATRIX_BUTTON_SPLIT_ROW(hardware_data); + uint32_t col = MATRIX_BUTTON_SPLIT_COL(hardware_data); + gpio_set_level(row, 1); + uint8_t level = gpio_get_level(col); + gpio_set_level(row, 0); + + return level; +} diff --git a/managed_components/espressif__button/examples/button_power_save/CMakeLists.txt b/managed_components/espressif__button/examples/button_power_save/CMakeLists.txt new file mode 100644 index 0000000..78c65a1 --- /dev/null +++ b/managed_components/espressif__button/examples/button_power_save/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(button_power_save) diff --git a/managed_components/espressif__button/examples/button_power_save/README.md b/managed_components/espressif__button/examples/button_power_save/README.md new file mode 100644 index 0000000..4e05d2e --- /dev/null +++ b/managed_components/espressif__button/examples/button_power_save/README.md @@ -0,0 +1,43 @@ +## Button Power Save Example + +This example demonstrates how to utilize the `button` component in conjunction with the light sleep low-power mode. + +* `button` [Component Introduction](https://docs.espressif.com/projects/esp-iot-solution/en/latest/input_device/button.html) + +## Hardware + +* Any GPIO on any development board can be used in this example. + +## Build and Flash + +Build the project and flash it to the board, then run the monitor tool to view the serial output: + +* Run `. ./export.sh` to set IDF environment +* Run `idf.py set-target esp32xx` to set target chip +* Run `idf.py -p PORT flash monitor` to build, flash and monitor the project + +(To exit the serial monitor, type `Ctrl-]`.) + +See the Getting Started Guide for all the steps to configure and use the ESP-IDF to build projects. + +## Example Output + +``` +I (1139) pm: Frequency switching config: CPU_MAX: 160, APB_MAX: 80, APB_MIN: 80, Light sleep: ENABLED +I (1149) sleep: Code start at 42000020, total 119.03 KiB, data start at 3c000000, total 49152.00 KiB +I (1159) button: IoT Button Version: 3.2.0 +I (1163) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 +I (2922) button_power_save: Button event BUTTON_PRESS_DOWN +I (3017) button_power_save: Button event BUTTON_PRESS_UP +I (3017) button_power_save: Wake up from light sleep, reason 4 +I (3200) button_power_save: Button event BUTTON_SINGLE_CLICK +I (3200) button_power_save: Wake up from light sleep, reason 4 +I (3202) button_power_save: Button event BUTTON_PRESS_REPEAT_DONE +I (3208) button_power_save: Wake up from light sleep, reason 4 +I (3627) button_power_save: Button event BUTTON_PRESS_DOWN +I (3702) button_power_save: Button event BUTTON_PRESS_UP +I (3702) button_power_save: Wake up from light sleep, reason 4 +I (3887) button_power_save: Button event BUTTON_SINGLE_CLICK +I (3887) button_power_save: Wake up from light sleep, reason 4 +I (3889) button_power_save: Button event BUTTON_PRESS_REPEAT_DONE +``` \ No newline at end of file diff --git a/managed_components/espressif__button/examples/button_power_save/main/CMakeLists.txt b/managed_components/espressif__button/examples/button_power_save/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/managed_components/espressif__button/examples/button_power_save/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/managed_components/espressif__button/examples/button_power_save/main/Kconfig.projbuild b/managed_components/espressif__button/examples/button_power_save/main/Kconfig.projbuild new file mode 100644 index 0000000..a8bc22c --- /dev/null +++ b/managed_components/espressif__button/examples/button_power_save/main/Kconfig.projbuild @@ -0,0 +1,87 @@ +menu "Example Configuration" + + choice ENTER_LIGHT_SLEEP_MODE + prompt "Enter light sleep mode" + default ENTER_LIGHT_SLEEP_AUTO + depends on PM_ENABLE + help + Enable light sleep mode to save power. + + config ENTER_LIGHT_SLEEP_AUTO + bool "Auto enter Light Sleep" + config ENTER_LIGHT_SLEEP_MODE_MANUALLY + bool "Manually enter Light Sleep" + endchoice + + choice EXAMPLE_MAX_CPU_FREQ + prompt "Maximum CPU frequency" + default EXAMPLE_MAX_CPU_FREQ_80 if !IDF_TARGET_ESP32H2 + default EXAMPLE_MAX_CPU_FREQ_96 if IDF_TARGET_ESP32H2 + depends on PM_ENABLE + help + Maximum CPU frequency to use for dynamic frequency scaling. + + config EXAMPLE_MAX_CPU_FREQ_80 + bool "80 MHz" + config EXAMPLE_MAX_CPU_FREQ_96 + bool "96 MHz" + depends on IDF_TARGET_ESP32H2 + config EXAMPLE_MAX_CPU_FREQ_120 + bool "120 MHz" + depends on IDF_TARGET_ESP32C2 + config EXAMPLE_MAX_CPU_FREQ_160 + bool "160 MHz" + depends on !IDF_TARGET_ESP32C2 + config EXAMPLE_MAX_CPU_FREQ_240 + bool "240 MHz" + depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + endchoice + + config EXAMPLE_MAX_CPU_FREQ_MHZ + int + default 80 if EXAMPLE_MAX_CPU_FREQ_80 + default 96 if EXAMPLE_MAX_CPU_FREQ_96 + default 120 if EXAMPLE_MAX_CPU_FREQ_120 + default 160 if EXAMPLE_MAX_CPU_FREQ_160 + default 240 if EXAMPLE_MAX_CPU_FREQ_240 + + choice EXAMPLE_MIN_CPU_FREQ + prompt "Minimum CPU frequency" + default EXAMPLE_MIN_CPU_FREQ_10M if !IDF_TARGET_ESP32H2 + default EXAMPLE_MIN_CPU_FREQ_32M if IDF_TARGET_ESP32H2 + depends on PM_ENABLE + help + Minimum CPU frequency to use for dynamic frequency scaling. + Should be set to XTAL frequency or XTAL frequency divided by integer. + + config EXAMPLE_MIN_CPU_FREQ_40M + bool "40 MHz (use with 40MHz XTAL)" + depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO || ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO || !IDF_TARGET_ESP32 + config EXAMPLE_MIN_CPU_FREQ_20M + bool "20 MHz (use with 40MHz XTAL)" + depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO || ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO || !IDF_TARGET_ESP32 + config EXAMPLE_MIN_CPU_FREQ_10M + bool "10 MHz (use with 40MHz XTAL)" + depends on XTAL_FREQ_40 || XTAL_FREQ_AUTO || ESP32_XTAL_FREQ_40 || ESP32_XTAL_FREQ_AUTO || !IDF_TARGET_ESP32 + config EXAMPLE_MIN_CPU_FREQ_26M + bool "26 MHz (use with 26MHz XTAL)" + depends on XTAL_FREQ_26 || XTAL_FREQ_AUTO || ESP32_XTAL_FREQ_26 || ESP32_XTAL_FREQ_AUTO + config EXAMPLE_MIN_CPU_FREQ_13M + bool "13 MHz (use with 26MHz XTAL)" + depends on XTAL_FREQ_26 || XTAL_FREQ_AUTO || ESP32_XTAL_FREQ_26 || ESP32_XTAL_FREQ_AUTO + config EXAMPLE_MIN_CPU_FREQ_32M + bool "32 MHz (use with 32MHz XTAL)" + depends on IDF_TARGET_ESP32H2 + depends on XTAL_FREQ_32 || XTAL_FREQ_AUTO + endchoice + + config EXAMPLE_MIN_CPU_FREQ_MHZ + int + default 40 if EXAMPLE_MIN_CPU_FREQ_40M + default 20 if EXAMPLE_MIN_CPU_FREQ_20M + default 10 if EXAMPLE_MIN_CPU_FREQ_10M + default 26 if EXAMPLE_MIN_CPU_FREQ_26M + default 13 if EXAMPLE_MIN_CPU_FREQ_13M + default 32 if EXAMPLE_MIN_CPU_FREQ_32M + +endmenu diff --git a/managed_components/espressif__button/examples/button_power_save/main/idf_component.yml b/managed_components/espressif__button/examples/button_power_save/main/idf_component.yml new file mode 100644 index 0000000..e132670 --- /dev/null +++ b/managed_components/espressif__button/examples/button_power_save/main/idf_component.yml @@ -0,0 +1,6 @@ +version: "0.1.0" +dependencies: + idf: ">=4.4" + button: + version: "*" + override_path: "../../../../components/button" diff --git a/managed_components/espressif__button/examples/button_power_save/main/main.c b/managed_components/espressif__button/examples/button_power_save/main/main.c new file mode 100644 index 0000000..eb62a8d --- /dev/null +++ b/managed_components/espressif__button/examples/button_power_save/main/main.c @@ -0,0 +1,125 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_pm.h" +#include "iot_button.h" +#include "esp_sleep.h" +#include "esp_idf_version.h" + +/* Most development boards have "boot" button attached to GPIO0. + * You can also change this to another pin. + */ +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6 +#define BOOT_BUTTON_NUM 9 +#else +#define BOOT_BUTTON_NUM 0 +#endif +#define BUTTON_ACTIVE_LEVEL 0 + +static const char *TAG = "button_power_save"; + +static void button_event_cb(void *arg, void *data) +{ + iot_button_print_event((button_handle_t)arg); + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + if (cause != ESP_SLEEP_WAKEUP_UNDEFINED) { + ESP_LOGI(TAG, "Wake up from light sleep, reason %d", cause); + } +} + +#if CONFIG_ENTER_LIGHT_SLEEP_MODE_MANUALLY +void button_enter_power_save(void *usr_data) +{ + ESP_LOGI(TAG, "Can enter power save now"); + esp_light_sleep_start(); +} +#endif + +void button_init(uint32_t button_num) +{ + button_config_t btn_cfg = { + .type = BUTTON_TYPE_GPIO, + .gpio_button_config = { + .gpio_num = button_num, + .active_level = BUTTON_ACTIVE_LEVEL, +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE + .enable_power_save = true, +#endif + }, + }; + button_handle_t btn = iot_button_create(&btn_cfg); + assert(btn); + esp_err_t err = iot_button_register_cb(btn, BUTTON_PRESS_DOWN, button_event_cb, NULL); + err |= iot_button_register_cb(btn, BUTTON_PRESS_UP, button_event_cb, NULL); + err |= iot_button_register_cb(btn, BUTTON_PRESS_REPEAT, button_event_cb, NULL); + err |= iot_button_register_cb(btn, BUTTON_PRESS_REPEAT_DONE, button_event_cb, NULL); + err |= iot_button_register_cb(btn, BUTTON_SINGLE_CLICK, button_event_cb, NULL); + err |= iot_button_register_cb(btn, BUTTON_DOUBLE_CLICK, button_event_cb, NULL); + err |= iot_button_register_cb(btn, BUTTON_LONG_PRESS_START, button_event_cb, NULL); + err |= iot_button_register_cb(btn, BUTTON_LONG_PRESS_HOLD, button_event_cb, NULL); + err |= iot_button_register_cb(btn, BUTTON_LONG_PRESS_UP, button_event_cb, NULL); + err |= iot_button_register_cb(btn, BUTTON_PRESS_END, button_event_cb, NULL); + +#if CONFIG_ENTER_LIGHT_SLEEP_MODE_MANUALLY + /*!< For enter Power Save */ + button_power_save_config_t config = { + .enter_power_save_cb = button_enter_power_save, + }; + err |= iot_button_register_power_save_cb(&config); +#endif + + ESP_ERROR_CHECK(err); +} + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0) +void power_save_init(void) +{ + esp_pm_config_t pm_config = { + .max_freq_mhz = CONFIG_EXAMPLE_MAX_CPU_FREQ_MHZ, + .min_freq_mhz = CONFIG_EXAMPLE_MIN_CPU_FREQ_MHZ, +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + .light_sleep_enable = true +#endif + }; + ESP_ERROR_CHECK(esp_pm_configure(&pm_config)); +} +#else +void power_save_init(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + esp_pm_config_esp32_t pm_config = { +#elif CONFIG_IDF_TARGET_ESP32S2 + esp_pm_config_esp32s2_t pm_config = { +#elif CONFIG_IDF_TARGET_ESP32C3 + esp_pm_config_esp32c3_t pm_config = { +#elif CONFIG_IDF_TARGET_ESP32S3 + esp_pm_config_esp32s3_t pm_config = { +#elif CONFIG_IDF_TARGET_ESP32C2 + esp_pm_config_esp32c2_t pm_config = { +#endif + .max_freq_mhz = CONFIG_EXAMPLE_MAX_CPU_FREQ_MHZ, + .min_freq_mhz = CONFIG_EXAMPLE_MIN_CPU_FREQ_MHZ, +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + .light_sleep_enable = true +#endif + }; + ESP_ERROR_CHECK(esp_pm_configure(&pm_config)); +} +#endif + +void app_main(void) +{ + button_init(BOOT_BUTTON_NUM); +#if CONFIG_ENTER_LIGHT_SLEEP_AUTO + power_save_init(); +#else + esp_light_sleep_start(); +#endif +} diff --git a/managed_components/espressif__button/examples/button_power_save/sdkconfig.ci.ls_manually b/managed_components/espressif__button/examples/button_power_save/sdkconfig.ci.ls_manually new file mode 100644 index 0000000..f554092 --- /dev/null +++ b/managed_components/espressif__button/examples/button_power_save/sdkconfig.ci.ls_manually @@ -0,0 +1 @@ +CONFIG_ENTER_LIGHT_SLEEP_MODE_MANUALLY=y\ diff --git a/managed_components/espressif__button/examples/button_power_save/sdkconfig.defaults b/managed_components/espressif__button/examples/button_power_save/sdkconfig.defaults new file mode 100644 index 0000000..eeb3f14 --- /dev/null +++ b/managed_components/espressif__button/examples/button_power_save/sdkconfig.defaults @@ -0,0 +1,11 @@ +# Enable support for power management +CONFIG_PM_ENABLE=y +# Enable tickless idle mode +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +# Put related source code in IRAM +CONFIG_PM_SLP_IRAM_OPT=y +CONFIG_PM_RTOS_IDLE_OPT=y +# Use 1000Hz freertos tick to lower sleep time threshold +CONFIG_FREERTOS_HZ=1000 +# For button power save +CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE=y diff --git a/managed_components/espressif__button/idf_component.yml b/managed_components/espressif__button/idf_component.yml new file mode 100644 index 0000000..a87cb80 --- /dev/null +++ b/managed_components/espressif__button/idf_component.yml @@ -0,0 +1,12 @@ +dependencies: + cmake_utilities: 0.* + idf: '>=4.0' +description: GPIO and ADC button driver +documentation: https://docs.espressif.com/projects/esp-iot-solution/en/latest/input_device/button.html +issues: https://github.com/espressif/esp-iot-solution/issues +repository: git://github.com/espressif/esp-iot-solution.git +repository_info: + commit_sha: ef19f4a5524a0ea147c9eccde0438123b41aeeb1 + path: components/button +url: https://github.com/espressif/esp-iot-solution/tree/master/components/button +version: 3.5.0 diff --git a/managed_components/espressif__button/include/button_adc.h b/managed_components/espressif__button/include/button_adc.h new file mode 100644 index 0000000..7ba1270 --- /dev/null +++ b/managed_components/espressif__button/include/button_adc.h @@ -0,0 +1,76 @@ +/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_idf_version.h" +#include "driver/gpio.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#include "esp_adc/adc_oneshot.h" +#else +#include "driver/adc.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define ADC_BUTTON_COMBINE(channel, index) ((channel)<<8 | (index)) +#define ADC_BUTTON_SPLIT_INDEX(data) ((uint32_t)(data)&0xff) +#define ADC_BUTTON_SPLIT_CHANNEL(data) (((uint32_t)(data) >> 8) & 0xff) + +/** + * @brief adc button configuration + * + */ +typedef struct { + uint8_t adc_channel; /**< Channel of ADC */ + uint8_t button_index; /**< button index on the channel */ + uint16_t min; /**< min voltage in mv corresponding to the button */ + uint16_t max; /**< max voltage in mv corresponding to the button */ +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + adc_oneshot_unit_handle_t *adc_handle; /**< handle of adc unit, if NULL will create new one internal, else will use the handle */ +#endif +} button_adc_config_t; + +/** + * @brief Initialize gpio button + * + * @param config pointer of configuration struct + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG Arguments is NULL. + * - ESP_ERR_NOT_SUPPORTED Arguments out of range. + * - ESP_ERR_INVALID_STATE State is error. + */ +esp_err_t button_adc_init(const button_adc_config_t *config); + +/** + * @brief Deinitialize gpio button + * + * @param channel ADC channel + * @param button_index Button index on the channel + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG Arguments is invalid. + */ +esp_err_t button_adc_deinit(uint8_t channel, int button_index); + +/** + * @brief Get the adc button level + * + * @param button_index It is compressed by ADC channel and button index, use the macro ADC_BUTTON_COMBINE to generate. It will be treated as a uint32_t variable. + * + * @return + * - 0 Not pressed + * - 1 Pressed + */ +uint8_t button_adc_get_key_level(void *button_index); + +#ifdef __cplusplus +} +#endif diff --git a/managed_components/espressif__button/include/button_gpio.h b/managed_components/espressif__button/include/button_gpio.h new file mode 100644 index 0000000..429392f --- /dev/null +++ b/managed_components/espressif__button/include/button_gpio.h @@ -0,0 +1,92 @@ +/* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "driver/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief gpio button configuration + * + */ +typedef struct { + int32_t gpio_num; /**< num of gpio */ + uint8_t active_level; /**< gpio level when press down */ +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE + bool enable_power_save; /**< enable power save mode */ +#endif + bool disable_pull; /**< disable internal pull or not */ +} button_gpio_config_t; + +/** + * @brief Initialize gpio button + * + * @param config pointer of configuration struct + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG Arguments is NULL. + */ +esp_err_t button_gpio_init(const button_gpio_config_t *config); + +/** + * @brief Deinitialize gpio button + * + * @param gpio_num gpio number of button + * + * @return Always return ESP_OK + */ +esp_err_t button_gpio_deinit(int gpio_num); + +/** + * @brief Get current level on button gpio + * + * @param gpio_num gpio number of button, it will be treated as a uint32_t variable. + * + * @return Level on gpio + */ +uint8_t button_gpio_get_key_level(void *gpio_num); + +/** + * @brief Sets up interrupt for GPIO button. + * + * @param gpio_num gpio number of button + * @param intr_type The type of GPIO interrupt. + * @param isr_handler The ISR (Interrupt Service Routine) handler function. + * @param args Arguments to be passed to the ISR handler function. + * @return Always return ESP_OK + */ +esp_err_t button_gpio_set_intr(int gpio_num, gpio_int_type_t intr_type, gpio_isr_t isr_handler, void *args); + +/** + * @brief Enable or disable interrupt for GPIO button. + * + * @param gpio_num gpio number of button + * @param enable enable or disable + * @return Always return ESP_OK + */ +esp_err_t button_gpio_intr_control(int gpio_num, bool enable); + +/** + * @brief Enable or disable GPIO wakeup functionality. + * + * This function allows enabling or disabling GPIO wakeup feature. + * + * @param gpio_num GPIO number for wakeup functionality. + * @param active_level Active level of the GPIO when triggered. + * @param enable Enable or disable the GPIO wakeup. + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE if trigger was not active or in conflict. + */ +esp_err_t button_gpio_enable_gpio_wakeup(uint32_t gpio_num, uint8_t active_level, bool enable); + +#ifdef __cplusplus +} +#endif diff --git a/managed_components/espressif__button/include/button_matrix.h b/managed_components/espressif__button/include/button_matrix.h new file mode 100644 index 0000000..b2dff93 --- /dev/null +++ b/managed_components/espressif__button/include/button_matrix.h @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define MATRIX_BUTTON_COMBINE(row_gpio, col_gpio) ((row_gpio)<<8 | (col_gpio)) +#define MATRIX_BUTTON_SPLIT_COL(data) ((uint32_t)(data)&0xff) +#define MATRIX_BUTTON_SPLIT_ROW(data) (((uint32_t)(data) >> 8) & 0xff) + +/** + * @brief Button matrix key configuration. + * Just need to configure the GPIO associated with this GPIO in the matrix keyboard. + * + * Matrix Keyboard Layout (3x3): + * ---------------------------------------- + * | Button 1 | Button 2 | Button 3 | + * | (R1-C1) | (R1-C2) | (R1-C3) | + * |--------------------------------------| + * | Button 4 | Button 5 | Button 6 | + * | (R2-C1) | (R2-C2) | (R2-C3) | + * |--------------------------------------| + * | Button 7 | Button 8 | Button 9 | + * | (R3-C1) | (R3-C2) | (R3-C3) | + * ---------------------------------------- + * + * - Button matrix key is driven using row scanning. + * - Buttons within the same column cannot be detected simultaneously, + * but buttons within the same row can be detected without conflicts. + */ +typedef struct { + int32_t row_gpio_num; /**< GPIO number associated with the row */ + int32_t col_gpio_num; /**< GPIO number associated with the column */ +} button_matrix_config_t; + +/** + * @brief Initialize a button matrix keyboard. + * + * @param config Pointer to the button matrix key configuration. + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the argument is NULL. + * + * @note When initializing the button matrix keyboard, the row GPIO pins will be set as outputs, + * and the column GPIO pins will be set as inputs, both with pull-down resistors enabled. + */ +esp_err_t button_matrix_init(const button_matrix_config_t *config); + +/** + * @brief Deinitialize a button in the matrix keyboard. + * + * @param row_gpio_num GPIO number of the row where the button is located. + * @param col_gpio_num GPIO number of the column where the button is located. + * @return + * - ESP_OK if the button is successfully deinitialized + * + * @note When deinitializing a button, please exercise caution and avoid deinitializing a button individually, as it may affect the proper functioning of other buttons in the same row or column. + */ +esp_err_t button_matrix_deinit(int row_gpio_num, int col_gpio_num); + +/** + * @brief Get the key level from the button matrix hardware. + * + * @param hardware_data Pointer to hardware-specific data containing information about row GPIO and column GPIO. + * @return uint8_t[out] The key level read from the hardware. + * + * @note This function retrieves the key level from the button matrix hardware. + * The `hardware_data` parameter should contain information about the row and column GPIO pins, + * and you can access this information using the `MATRIX_BUTTON_SPLIT_COL` and `MATRIX_BUTTON_SPLIT_ROW` macros. + */ +uint8_t button_matrix_get_key_level(void *hardware_data); + +#ifdef __cplusplus +} +#endif diff --git a/managed_components/espressif__button/include/iot_button.h b/managed_components/espressif__button/include/iot_button.h new file mode 100644 index 0000000..6c58ff8 --- /dev/null +++ b/managed_components/espressif__button/include/iot_button.h @@ -0,0 +1,363 @@ +/* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" +#if CONFIG_SOC_ADC_SUPPORTED +#include "button_adc.h" +#endif +#include "button_gpio.h" +#include "button_matrix.h" +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (* button_cb_t)(void *button_handle, void *usr_data); + +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE +typedef void (* button_power_save_cb_t)(void *usr_data); + +/** + * @brief Structs to store power save callback info + * + */ +typedef struct { + button_power_save_cb_t enter_power_save_cb; + void *usr_data; +} button_power_save_config_t; +#endif + +typedef void *button_handle_t; + +/** + * @brief Button events + * + */ +typedef enum { + BUTTON_PRESS_DOWN = 0, + BUTTON_PRESS_UP, + BUTTON_PRESS_REPEAT, + BUTTON_PRESS_REPEAT_DONE, + BUTTON_SINGLE_CLICK, + BUTTON_DOUBLE_CLICK, + BUTTON_MULTIPLE_CLICK, + BUTTON_LONG_PRESS_START, + BUTTON_LONG_PRESS_HOLD, + BUTTON_LONG_PRESS_UP, + BUTTON_PRESS_END, + BUTTON_EVENT_MAX, + BUTTON_NONE_PRESS, +} button_event_t; + +/** + * @brief Button events data + * + */ +typedef union { + /** + * @brief Long press time event data + * + */ + struct long_press_t { + uint16_t press_time; /**< press time(ms) for the corresponding callback to trigger */ + } long_press; /**< long press struct, for event BUTTON_LONG_PRESS_START and BUTTON_LONG_PRESS_UP */ + + /** + * @brief Multiple clicks event data + * + */ + struct multiple_clicks_t { + uint16_t clicks; /**< number of clicks, to trigger the callback */ + } multiple_clicks; /**< multiple clicks struct, for event BUTTON_MULTIPLE_CLICK */ +} button_event_data_t; + +/** + * @brief Button events configuration + * + */ +typedef struct { + button_event_t event; /**< button event type */ + button_event_data_t event_data; /**< event data corresponding to the event */ +} button_event_config_t; + +/** + * @brief Supported button type + * + */ +typedef enum { + BUTTON_TYPE_GPIO, + BUTTON_TYPE_ADC, + BUTTON_TYPE_MATRIX, + BUTTON_TYPE_CUSTOM +} button_type_t; + +/** + * @brief Button parameter + * + */ +typedef enum { + BUTTON_LONG_PRESS_TIME_MS = 0, + BUTTON_SHORT_PRESS_TIME_MS, + BUTTON_PARAM_MAX, +} button_param_t; + +/** + * @brief custom button configuration + * + */ +typedef struct { + uint8_t active_level; /**< active level when press down */ + esp_err_t (*button_custom_init)(void *param); /**< user defined button init */ + uint8_t (*button_custom_get_key_value)(void *param); /**< user defined button get key value */ + esp_err_t (*button_custom_deinit)(void *param); /**< user defined button deinit */ + void *priv; /**< private data used for custom button, MUST be allocated dynamically and will be auto freed in iot_button_delete*/ +} button_custom_config_t; + +/** + * @brief Button configuration + * + */ +typedef struct { + button_type_t type; /**< button type, The corresponding button configuration must be filled */ + uint16_t long_press_time; /**< Trigger time(ms) for long press, if 0 default to BUTTON_LONG_PRESS_TIME_MS */ + uint16_t short_press_time; /**< Trigger time(ms) for short press, if 0 default to BUTTON_SHORT_PRESS_TIME_MS */ + union { + button_gpio_config_t gpio_button_config; /**< gpio button configuration */ +#if CONFIG_SOC_ADC_SUPPORTED + button_adc_config_t adc_button_config; /**< adc button configuration */ +#endif + button_matrix_config_t matrix_button_config; /**< matrix key button configuration */ + button_custom_config_t custom_button_config; /**< custom button configuration */ + }; /**< button configuration */ +} button_config_t; + +/** + * @brief Create a button + * + * @param config pointer of button configuration, must corresponding the button type + * + * @return A handle to the created button, or NULL in case of error. + */ +button_handle_t iot_button_create(const button_config_t *config); + +/** + * @brief Delete a button + * + * @param btn_handle A button handle to delete + * + * @return + * - ESP_OK Success + * - ESP_FAIL Failure + */ +esp_err_t iot_button_delete(button_handle_t btn_handle); + +/** + * @brief Register the button event callback function. + * + * @param btn_handle A button handle to register + * @param event Button event + * @param cb Callback function. + * @param usr_data user data + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG Arguments is invalid. + * - ESP_ERR_INVALID_STATE The Callback is already registered. No free Space for another Callback. + * - ESP_ERR_NO_MEM No more memory allocation for the event + */ +esp_err_t iot_button_register_cb(button_handle_t btn_handle, button_event_t event, button_cb_t cb, void *usr_data); + +/** + * @brief Register the button event callback function. + * + * @param btn_handle A button handle to register + * @param event_cfg Button event configuration + * @param cb Callback function. + * @param usr_data user data + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG Arguments is invalid. + * - ESP_ERR_INVALID_STATE The Callback is already registered. No free Space for another Callback. + * - ESP_ERR_NO_MEM No more memory allocation for the event + */ +esp_err_t iot_button_register_event_cb(button_handle_t btn_handle, button_event_config_t event_cfg, button_cb_t cb, void *usr_data); + +/** + * @brief Unregister the button event callback function. + * In case event_data is also passed it will unregister function for that particular event_data only. + * + * @param btn_handle A button handle to unregister + * @param event_cfg Button event + * @param cb callback to unregister + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG Arguments is invalid. + * - ESP_ERR_INVALID_STATE The Callback was never registered with the event + */ +esp_err_t iot_button_unregister_event(button_handle_t btn_handle, button_event_config_t event_cfg, button_cb_t cb); + +/** + * @brief Unregister all the callbacks associated with the event. + * + * @param btn_handle A button handle to unregister + * @param event Button event + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG Arguments is invalid. + * - ESP_ERR_INVALID_STATE No callbacks registered for the event + */ +esp_err_t iot_button_unregister_cb(button_handle_t btn_handle, button_event_t event); + +/** + * @brief counts total callbacks registered + * + * @param btn_handle A button handle to the button + * + * @return + * - 0 if no callbacks registered, or 1 .. (BUTTON_EVENT_MAX-1) for the number of Registered Buttons. + * - ESP_ERR_INVALID_ARG if btn_handle is invalid + */ +size_t iot_button_count_cb(button_handle_t btn_handle); + +/** + * @brief how many callbacks are registered for the event + * + * @param btn_handle A button handle to the button + * + * @param event Button event + * + * @return + * - 0 if no callbacks registered, or 1 .. (BUTTON_EVENT_MAX-1) for the number of Registered Buttons. + * - ESP_ERR_INVALID_ARG if btn_handle is invalid + */ +size_t iot_button_count_event(button_handle_t btn_handle, button_event_t event); + +/** + * @brief Get button event + * + * @param btn_handle Button handle + * + * @return Current button event. See button_event_t + */ +button_event_t iot_button_get_event(button_handle_t btn_handle); + +/** + * @brief Get the string representation of a button event. + * + * This function returns the corresponding string for a given button event. + * If the event value is outside the valid range, the function returns error string "event value is invalid". + * + * @param[in] event The button event to be converted to a string. + * + * @return + * - Pointer to the event string if the event is valid. + * - "invalid event" if the event value is invalid. + */ +const char *iot_button_get_event_str(button_event_t event); + +/** + * @brief Log the current button event as a string. + * + * This function prints the string representation of the current event associated with the button. + * + * @param[in] btn_handle Handle to the button object. + * + * @return + * - ESP_OK: Successfully logged the event string. + * - ESP_FAIL: Invalid button handle. + */ +esp_err_t iot_button_print_event(button_handle_t btn_handle); + +/** + * @brief Get button repeat times + * + * @param btn_handle Button handle + * + * @return button pressed times. For example, double-click return 2, triple-click return 3, etc. + */ +uint8_t iot_button_get_repeat(button_handle_t btn_handle); + +/** + * @brief Get button ticks time + * + * @param btn_handle Button handle + * + * @return Actual time from press down to up (ms). + */ +uint32_t iot_button_get_ticks_time(button_handle_t btn_handle); + +/** + * @brief Get button long press hold count + * + * @param btn_handle Button handle + * + * @return Count of trigger cb(BUTTON_LONG_PRESS_HOLD) + */ +uint16_t iot_button_get_long_press_hold_cnt(button_handle_t btn_handle); + +/** + * @brief Dynamically change the parameters of the iot button + * + * @param btn_handle Button handle + * @param param Button parameter + * @param value new value + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG Arguments is invalid. + */ +esp_err_t iot_button_set_param(button_handle_t btn_handle, button_param_t param, void *value); + +/** + * @brief Get button key level + * + * @param btn_handle Button handle + * @return + * - 1 if key is pressed + * - 0 if key is released or invalid button handle + */ +uint8_t iot_button_get_key_level(button_handle_t btn_handle); + +/** + * @brief resume button timer, if button timer is stopped. Make sure iot_button_create() is called before calling this API. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE timer state is invalid. + */ +esp_err_t iot_button_resume(void); + +/** + * @brief stop button timer, if button timer is running. Make sure iot_button_create() is called before calling this API. + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE timer state is invalid + */ +esp_err_t iot_button_stop(void); + +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE +/** + * @brief Register a callback function for power saving. + * The config->enter_power_save_cb function will be called when all keys stop working. + * + * @param config Button power save config + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE No button registered + * - ESP_ERR_INVALID_ARG Arguments is invalid + * - ESP_ERR_NO_MEM Not enough memory + */ +esp_err_t iot_button_register_power_save_cb(const button_power_save_config_t *config); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/managed_components/espressif__button/iot_button.c b/managed_components/espressif__button/iot_button.c new file mode 100644 index 0000000..9c9f1eb --- /dev/null +++ b/managed_components/espressif__button/iot_button.c @@ -0,0 +1,821 @@ +/* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/timers.h" +#include "driver/gpio.h" +#include "esp_timer.h" +#include "esp_log.h" +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE +#include "esp_pm.h" +#endif +#include "iot_button.h" +#include "sdkconfig.h" + +static const char *TAG = "button"; +static portMUX_TYPE s_button_lock = portMUX_INITIALIZER_UNLOCKED; +#define BUTTON_ENTER_CRITICAL() portENTER_CRITICAL(&s_button_lock) +#define BUTTON_EXIT_CRITICAL() portEXIT_CRITICAL(&s_button_lock) + +#define BTN_CHECK(a, str, ret_val) \ + if (!(a)) { \ + ESP_LOGE(TAG, "%s(%d): %s", __FUNCTION__, __LINE__, str); \ + return (ret_val); \ + } + +static const char *button_event_str[] = { + "BUTTON_PRESS_DOWN", + "BUTTON_PRESS_UP", + "BUTTON_PRESS_REPEAT", + "BUTTON_PRESS_REPEAT_DONE", + "BUTTON_SINGLE_CLICK", + "BUTTON_DOUBLE_CLICK", + "BUTTON_MULTIPLE_CLICK", + "BUTTON_LONG_PRESS_START", + "BUTTON_LONG_PRESS_HOLD", + "BUTTON_LONG_PRESS_UP", + "BUTTON_PRESS_END", + "BUTTON_EVENT_MAX", + "BUTTON_NONE_PRESS", +}; + +/** + * @brief Structs to store callback info + * + */ +typedef struct { + button_cb_t cb; + void *usr_data; + button_event_data_t event_data; +} button_cb_info_t; + +/** + * @brief Structs to record individual key parameters + * + */ +typedef struct Button { + uint32_t ticks; /*!< Count for the current button state. */ + uint32_t long_press_ticks; /*!< Trigger ticks for long press, */ + uint32_t short_press_ticks; /*!< Trigger ticks for repeat press */ + uint32_t long_press_hold_cnt; /*!< Record long press hold count */ + uint8_t repeat; + uint8_t state: 3; + uint8_t debounce_cnt: 3; + uint8_t active_level: 1; + uint8_t button_level: 1; + uint8_t enable_power_save: 1; + button_event_t event; + uint8_t (*hal_button_Level)(void *hardware_data); + esp_err_t (*hal_button_deinit)(void *hardware_data); + void *hardware_data; + button_type_t type; + button_cb_info_t *cb_info[BUTTON_EVENT_MAX]; + size_t size[BUTTON_EVENT_MAX]; + int count[2]; + struct Button *next; +} button_dev_t; + +//button handle list head. +static button_dev_t *g_head_handle = NULL; +static esp_timer_handle_t g_button_timer_handle = NULL; +static bool g_is_timer_running = false; +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE +static button_power_save_config_t power_save_usr_cfg = {0}; +#endif + +#define TICKS_INTERVAL CONFIG_BUTTON_PERIOD_TIME_MS +#define DEBOUNCE_TICKS CONFIG_BUTTON_DEBOUNCE_TICKS //MAX 8 +#define SHORT_TICKS (CONFIG_BUTTON_SHORT_PRESS_TIME_MS /TICKS_INTERVAL) +#define LONG_TICKS (CONFIG_BUTTON_LONG_PRESS_TIME_MS /TICKS_INTERVAL) +#define SERIAL_TICKS (CONFIG_BUTTON_SERIAL_TIME_MS /TICKS_INTERVAL) +#define TOLERANCE (CONFIG_BUTTON_PERIOD_TIME_MS*4) + +#define CALL_EVENT_CB(ev) \ + if (btn->cb_info[ev]) { \ + for (int i = 0; i < btn->size[ev]; i++) { \ + btn->cb_info[ev][i].cb(btn, btn->cb_info[ev][i].usr_data); \ + } \ + } \ + +#define TIME_TO_TICKS(time, congfig_time) (0 == (time))?congfig_time:(((time) / TICKS_INTERVAL))?((time) / TICKS_INTERVAL):1 + +/** + * @brief Button driver core function, driver state machine. + */ +static void button_handler(button_dev_t *btn) +{ + uint8_t read_gpio_level = btn->hal_button_Level(btn->hardware_data); + + /** ticks counter working.. */ + if ((btn->state) > 0) { + btn->ticks++; + } + + /**< button debounce handle */ + if (read_gpio_level != btn->button_level) { + if (++(btn->debounce_cnt) >= DEBOUNCE_TICKS) { + btn->button_level = read_gpio_level; + btn->debounce_cnt = 0; + } + } else { + btn->debounce_cnt = 0; + } + + /** State machine */ + switch (btn->state) { + case 0: + if (btn->button_level == btn->active_level) { + btn->event = (uint8_t)BUTTON_PRESS_DOWN; + CALL_EVENT_CB(BUTTON_PRESS_DOWN); + btn->ticks = 0; + btn->repeat = 1; + btn->state = 1; + } else { + btn->event = (uint8_t)BUTTON_NONE_PRESS; + } + break; + + case 1: + if (btn->button_level != btn->active_level) { + btn->event = (uint8_t)BUTTON_PRESS_UP; + CALL_EVENT_CB(BUTTON_PRESS_UP); + btn->ticks = 0; + btn->state = 2; + + } else if (btn->ticks >= btn->long_press_ticks) { + btn->event = (uint8_t)BUTTON_LONG_PRESS_START; + btn->state = 4; + /** Calling callbacks for BUTTON_LONG_PRESS_START */ + uint32_t ticks_time = iot_button_get_ticks_time(btn); + int32_t diff = ticks_time - btn->long_press_ticks * TICKS_INTERVAL; + if (btn->cb_info[btn->event] && btn->count[0] == 0) { + if (abs(diff) <= TOLERANCE && btn->cb_info[btn->event][btn->count[0]].event_data.long_press.press_time == (btn->long_press_ticks * TICKS_INTERVAL)) { + do { + btn->cb_info[btn->event][btn->count[0]].cb(btn, btn->cb_info[btn->event][btn->count[0]].usr_data); + btn->count[0]++; + if (btn->count[0] >= btn->size[btn->event]) { + break; + } + } while (btn->cb_info[btn->event][btn->count[0]].event_data.long_press.press_time == btn->long_press_ticks * TICKS_INTERVAL); + } + } + } + break; + + case 2: + if (btn->button_level == btn->active_level) { + btn->event = (uint8_t)BUTTON_PRESS_DOWN; + CALL_EVENT_CB(BUTTON_PRESS_DOWN); + btn->event = (uint8_t)BUTTON_PRESS_REPEAT; + btn->repeat++; + CALL_EVENT_CB(BUTTON_PRESS_REPEAT); // repeat hit + btn->ticks = 0; + btn->state = 3; + } else if (btn->ticks > btn->short_press_ticks) { + if (btn->repeat == 1) { + btn->event = (uint8_t)BUTTON_SINGLE_CLICK; + CALL_EVENT_CB(BUTTON_SINGLE_CLICK); + } else if (btn->repeat == 2) { + btn->event = (uint8_t)BUTTON_DOUBLE_CLICK; + CALL_EVENT_CB(BUTTON_DOUBLE_CLICK); // repeat hit + } + + btn->event = (uint8_t)BUTTON_MULTIPLE_CLICK; + + /** Calling the callbacks for MULTIPLE BUTTON CLICKS */ + for (int i = 0; i < btn->size[btn->event]; i++) { + if (btn->repeat == btn->cb_info[btn->event][i].event_data.multiple_clicks.clicks) { + do { + btn->cb_info[btn->event][i].cb(btn, btn->cb_info[btn->event][i].usr_data); + i++; + if (i >= btn->size[btn->event]) { + break; + } + } while (btn->cb_info[btn->event][i].event_data.multiple_clicks.clicks == btn->repeat); + } + } + + btn->event = (uint8_t)BUTTON_PRESS_REPEAT_DONE; + CALL_EVENT_CB(BUTTON_PRESS_REPEAT_DONE); // repeat hit + btn->repeat = 0; + btn->state = 0; + btn->event = (uint8_t)BUTTON_PRESS_END; + CALL_EVENT_CB(BUTTON_PRESS_END); + } + break; + + case 3: + if (btn->button_level != btn->active_level) { + btn->event = (uint8_t)BUTTON_PRESS_UP; + CALL_EVENT_CB(BUTTON_PRESS_UP); + if (btn->ticks < btn->short_press_ticks) { + btn->ticks = 0; + btn->state = 2; //repeat press + } else { + btn->state = 0; + btn->event = (uint8_t)BUTTON_PRESS_END; + CALL_EVENT_CB(BUTTON_PRESS_END); + } + } + break; + + case 4: + if (btn->button_level == btn->active_level) { + //continue hold trigger + if (btn->ticks >= (btn->long_press_hold_cnt + 1) * SERIAL_TICKS + btn->long_press_ticks) { + btn->event = (uint8_t)BUTTON_LONG_PRESS_HOLD; + btn->long_press_hold_cnt++; + CALL_EVENT_CB(BUTTON_LONG_PRESS_HOLD); + + /** Calling callbacks for BUTTON_LONG_PRESS_START based on press_time */ + uint32_t ticks_time = iot_button_get_ticks_time(btn); + if (btn->cb_info[BUTTON_LONG_PRESS_START]) { + button_cb_info_t *cb_info = btn->cb_info[BUTTON_LONG_PRESS_START]; + uint16_t time = cb_info[btn->count[0]].event_data.long_press.press_time; + if (btn->long_press_ticks * TICKS_INTERVAL > time) { + for (int i = btn->count[0] + 1; i < btn->size[BUTTON_LONG_PRESS_START]; i++) { + time = cb_info[i].event_data.long_press.press_time; + if (btn->long_press_ticks * TICKS_INTERVAL <= time) { + btn->count[0] = i; + break; + } + } + } + if (btn->count[0] < btn->size[BUTTON_LONG_PRESS_START] && abs((int)ticks_time - (int)time) <= TOLERANCE) { + btn->event = (uint8_t)BUTTON_LONG_PRESS_START; + do { + cb_info[btn->count[0]].cb(btn, cb_info[btn->count[0]].usr_data); + btn->count[0]++; + if (btn->count[0] >= btn->size[BUTTON_LONG_PRESS_START]) { + break; + } + } while (time == cb_info[btn->count[0]].event_data.long_press.press_time); + } + } + + /** Updating counter for BUTTON_LONG_PRESS_UP press_time */ + if (btn->cb_info[BUTTON_LONG_PRESS_UP]) { + button_cb_info_t *cb_info = btn->cb_info[BUTTON_LONG_PRESS_UP]; + uint16_t time = cb_info[btn->count[1] + 1].event_data.long_press.press_time; + if (btn->long_press_ticks * TICKS_INTERVAL > time) { + for (int i = btn->count[1] + 1; i < btn->size[BUTTON_LONG_PRESS_UP]; i++) { + time = cb_info[i].event_data.long_press.press_time; + if (btn->long_press_ticks * TICKS_INTERVAL <= time) { + btn->count[1] = i; + break; + } + } + } + if (btn->count[1] + 1 < btn->size[BUTTON_LONG_PRESS_UP] && abs((int)ticks_time - (int)time) <= TOLERANCE) { + do { + btn->count[1]++; + if (btn->count[1] + 1 >= btn->size[BUTTON_LONG_PRESS_UP]) { + break; + } + } while (time == cb_info[btn->count[1] + 1].event_data.long_press.press_time); + } + } + } + } else { //releasd + + btn->event = BUTTON_LONG_PRESS_UP; + + /** calling callbacks for BUTTON_LONG_PRESS_UP press_time */ + if (btn->cb_info[btn->event] && btn->count[1] >= 0) { + button_cb_info_t *cb_info = btn->cb_info[btn->event]; + do { + cb_info[btn->count[1]].cb(btn, cb_info[btn->count[1]].usr_data); + if (!btn->count[1]) { + break; + } + btn->count[1]--; + } while (cb_info[btn->count[1]].event_data.long_press.press_time == cb_info[btn->count[1] + 1].event_data.long_press.press_time); + + /** Reset the counter */ + btn->count[1] = -1; + } + /** Reset counter */ + if (btn->cb_info[BUTTON_LONG_PRESS_START]) { + btn->count[0] = 0; + } + + btn->event = (uint8_t)BUTTON_PRESS_UP; + CALL_EVENT_CB(BUTTON_PRESS_UP); + btn->state = 0; //reset + btn->long_press_hold_cnt = 0; + btn->event = (uint8_t)BUTTON_PRESS_END; + CALL_EVENT_CB(BUTTON_PRESS_END); + } + break; + } +} + +static void button_cb(void *args) +{ + button_dev_t *target; + /*!< When all buttons enter the BUTTON_NONE_PRESS state, the system enters low-power mode */ +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE + bool enter_power_save_flag = true; +#endif + for (target = g_head_handle; target; target = target->next) { + button_handler(target); +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE + if (!(target->enable_power_save && target->debounce_cnt == 0 && target->event == BUTTON_NONE_PRESS)) { + enter_power_save_flag = false; + } +#endif + } +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE + if (enter_power_save_flag) { + /*!< Stop esp timer for power save */ + if (g_is_timer_running) { + esp_timer_stop(g_button_timer_handle); + g_is_timer_running = false; + } + for (target = g_head_handle; target; target = target->next) { + if (target->type == BUTTON_TYPE_GPIO && target->enable_power_save) { + button_gpio_intr_control((int)(target->hardware_data), true); + button_gpio_enable_gpio_wakeup((uint32_t)(target->hardware_data), target->active_level, true); + } + } + /*!< Notify the user that the Button has entered power save mode by calling this callback function. */ + if (power_save_usr_cfg.enter_power_save_cb) { + power_save_usr_cfg.enter_power_save_cb(power_save_usr_cfg.usr_data); + } + } +#endif +} + +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE +static void IRAM_ATTR button_power_save_isr_handler(void* arg) +{ + if (!g_is_timer_running) { + esp_timer_start_periodic(g_button_timer_handle, TICKS_INTERVAL * 1000U); + g_is_timer_running = true; + } + button_gpio_intr_control((int)arg, false); + /*!< disable gpio wakeup not need active level*/ + button_gpio_enable_gpio_wakeup((uint32_t)arg, 0, false); +} +#endif + +static button_dev_t *button_create_com(uint8_t active_level, uint8_t (*hal_get_key_state)(void *hardware_data), void *hardware_data, uint16_t long_press_ticks, uint16_t short_press_ticks) +{ + BTN_CHECK(NULL != hal_get_key_state, "Function pointer is invalid", NULL); + + button_dev_t *btn = (button_dev_t *) calloc(1, sizeof(button_dev_t)); + BTN_CHECK(NULL != btn, "Button memory alloc failed", NULL); + btn->hardware_data = hardware_data; + btn->event = BUTTON_NONE_PRESS; + btn->active_level = active_level; + btn->hal_button_Level = hal_get_key_state; + btn->button_level = !active_level; + btn->long_press_ticks = long_press_ticks; + btn->short_press_ticks = short_press_ticks; + + /** Add handle to list */ + btn->next = g_head_handle; + g_head_handle = btn; + + if (!g_button_timer_handle) { + esp_timer_create_args_t button_timer = {0}; + button_timer.arg = NULL; + button_timer.callback = button_cb; + button_timer.dispatch_method = ESP_TIMER_TASK; + button_timer.name = "button_timer"; + esp_timer_create(&button_timer, &g_button_timer_handle); + } + + return btn; +} + +static esp_err_t button_delete_com(button_dev_t *btn) +{ + BTN_CHECK(NULL != btn, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG); + + button_dev_t **curr; + for (curr = &g_head_handle; *curr;) { + button_dev_t *entry = *curr; + if (entry == btn) { + *curr = entry->next; + free(entry); + } else { + curr = &entry->next; + } + } + + /* count button number */ + uint16_t number = 0; + button_dev_t *target = g_head_handle; + while (target) { + target = target->next; + number++; + } + ESP_LOGD(TAG, "remain btn number=%d", number); + + if (0 == number && g_is_timer_running) { /**< if all button is deleted, stop the timer */ + esp_timer_stop(g_button_timer_handle); + esp_timer_delete(g_button_timer_handle); + g_button_timer_handle = NULL; + g_is_timer_running = false; + } + return ESP_OK; +} + +button_handle_t iot_button_create(const button_config_t *config) +{ + ESP_LOGI(TAG, "IoT Button Version: %d.%d.%d", BUTTON_VER_MAJOR, BUTTON_VER_MINOR, BUTTON_VER_PATCH); + BTN_CHECK(config, "Invalid button config", NULL); + + esp_err_t ret = ESP_OK; + button_dev_t *btn = NULL; + uint16_t long_press_time = 0; + uint16_t short_press_time = 0; + long_press_time = TIME_TO_TICKS(config->long_press_time, LONG_TICKS); + short_press_time = TIME_TO_TICKS(config->short_press_time, SHORT_TICKS); + switch (config->type) { + case BUTTON_TYPE_GPIO: { + const button_gpio_config_t *cfg = &(config->gpio_button_config); + ret = button_gpio_init(cfg); + BTN_CHECK(ESP_OK == ret, "gpio button init failed", NULL); + btn = button_create_com(cfg->active_level, button_gpio_get_key_level, (void *)cfg->gpio_num, long_press_time, short_press_time); +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE + if (cfg->enable_power_save) { + btn->enable_power_save = cfg->enable_power_save; + button_gpio_set_intr(cfg->gpio_num, cfg->active_level == 0 ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL, button_power_save_isr_handler, (void *)cfg->gpio_num); + } +#endif + } break; +#if CONFIG_SOC_ADC_SUPPORTED + case BUTTON_TYPE_ADC: { + const button_adc_config_t *cfg = &(config->adc_button_config); + ret = button_adc_init(cfg); + BTN_CHECK(ESP_OK == ret, "adc button init failed", NULL); + btn = button_create_com(1, button_adc_get_key_level, (void *)ADC_BUTTON_COMBINE(cfg->adc_channel, cfg->button_index), long_press_time, short_press_time); + } break; +#endif + case BUTTON_TYPE_MATRIX: { + const button_matrix_config_t *cfg = &(config->matrix_button_config); + ret = button_matrix_init(cfg); + BTN_CHECK(ESP_OK == ret, "matrix button init failed", NULL); + btn = button_create_com(1, button_matrix_get_key_level, (void *)MATRIX_BUTTON_COMBINE(cfg->row_gpio_num, cfg->col_gpio_num), long_press_time, short_press_time); + } break; + case BUTTON_TYPE_CUSTOM: { + if (config->custom_button_config.button_custom_init) { + ret = config->custom_button_config.button_custom_init(config->custom_button_config.priv); + BTN_CHECK(ESP_OK == ret, "custom button init failed", NULL); + } + + btn = button_create_com(config->custom_button_config.active_level, + config->custom_button_config.button_custom_get_key_value, + config->custom_button_config.priv, + long_press_time, short_press_time); + if (btn) { + btn->hal_button_deinit = config->custom_button_config.button_custom_deinit; + } + } break; + + default: + ESP_LOGE(TAG, "Unsupported button type"); + break; + } + BTN_CHECK(NULL != btn, "button create failed", NULL); + btn->type = config->type; + if (!btn->enable_power_save && !g_is_timer_running) { + esp_timer_start_periodic(g_button_timer_handle, TICKS_INTERVAL * 1000U); + g_is_timer_running = true; + } + return (button_handle_t)btn; +} + +esp_err_t iot_button_delete(button_handle_t btn_handle) +{ + esp_err_t ret = ESP_OK; + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG); + button_dev_t *btn = (button_dev_t *)btn_handle; + switch (btn->type) { + case BUTTON_TYPE_GPIO: + ret = button_gpio_deinit((int)(btn->hardware_data)); + break; +#if CONFIG_SOC_ADC_SUPPORTED + case BUTTON_TYPE_ADC: + ret = button_adc_deinit(ADC_BUTTON_SPLIT_CHANNEL(btn->hardware_data), ADC_BUTTON_SPLIT_INDEX(btn->hardware_data)); + break; +#endif + case BUTTON_TYPE_MATRIX: + ret = button_matrix_deinit(MATRIX_BUTTON_SPLIT_ROW(btn->hardware_data), MATRIX_BUTTON_SPLIT_COL(btn->hardware_data)); + break; + case BUTTON_TYPE_CUSTOM: + if (btn->hal_button_deinit) { + ret = btn->hal_button_deinit(btn->hardware_data); + } + + break; + default: + break; + } + BTN_CHECK(ESP_OK == ret, "button deinit failed", ESP_FAIL); + for (int i = 0; i < BUTTON_EVENT_MAX; i++) { + if (btn->cb_info[i]) { + free(btn->cb_info[i]); + } + } + button_delete_com(btn); + return ESP_OK; +} + +esp_err_t iot_button_register_cb(button_handle_t btn_handle, button_event_t event, button_cb_t cb, void *usr_data) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG); + button_dev_t *btn = (button_dev_t *) btn_handle; + BTN_CHECK(event != BUTTON_MULTIPLE_CLICK, "event argument is invalid", ESP_ERR_INVALID_ARG); + button_event_config_t event_cfg = { + .event = event, + }; + + if ((event == BUTTON_LONG_PRESS_START || event == BUTTON_LONG_PRESS_UP) && !event_cfg.event_data.long_press.press_time) { + event_cfg.event_data.long_press.press_time = btn->long_press_ticks * TICKS_INTERVAL; + } + + return iot_button_register_event_cb(btn_handle, event_cfg, cb, usr_data); +} + +esp_err_t iot_button_register_event_cb(button_handle_t btn_handle, button_event_config_t event_cfg, button_cb_t cb, void *usr_data) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG); + button_dev_t *btn = (button_dev_t *) btn_handle; + button_event_t event = event_cfg.event; + BTN_CHECK(event < BUTTON_EVENT_MAX, "event is invalid", ESP_ERR_INVALID_ARG); + BTN_CHECK(!(event == BUTTON_LONG_PRESS_START || event == BUTTON_LONG_PRESS_UP) || event_cfg.event_data.long_press.press_time > btn->short_press_ticks * TICKS_INTERVAL, "event_data is invalid", ESP_ERR_INVALID_ARG); + BTN_CHECK(event != BUTTON_MULTIPLE_CLICK || event_cfg.event_data.multiple_clicks.clicks, "event_data is invalid", ESP_ERR_INVALID_ARG); + + if (!btn->cb_info[event]) { + btn->cb_info[event] = calloc(1, sizeof(button_cb_info_t)); + BTN_CHECK(NULL != btn->cb_info[event], "calloc cb_info failed", ESP_ERR_NO_MEM); + if (event == BUTTON_LONG_PRESS_START) { + btn->count[0] = 0; + } else if (event == BUTTON_LONG_PRESS_UP) { + btn->count[1] = -1; + } + } else { + button_cb_info_t *p = realloc(btn->cb_info[event], sizeof(button_cb_info_t) * (btn->size[event] + 1)); + BTN_CHECK(NULL != p, "realloc cb_info failed", ESP_ERR_NO_MEM); + btn->cb_info[event] = p; + } + + btn->cb_info[event][btn->size[event]].cb = cb; + btn->cb_info[event][btn->size[event]].usr_data = usr_data; + btn->size[event]++; + + /** Inserting the event_data in sorted manner */ + if (event == BUTTON_LONG_PRESS_START || event == BUTTON_LONG_PRESS_UP) { + uint16_t press_time = event_cfg.event_data.long_press.press_time; + BTN_CHECK(press_time / TICKS_INTERVAL > btn->short_press_ticks, "press_time event_data is less than short_press_ticks", ESP_ERR_INVALID_ARG); + if (btn->size[event] >= 2) { + for (int i = btn->size[event] - 2; i >= 0; i--) { + if (btn->cb_info[event][i].event_data.long_press.press_time > press_time) { + btn->cb_info[event][i + 1] = btn->cb_info[event][i]; + + btn->cb_info[event][i].event_data.long_press.press_time = press_time; + btn->cb_info[event][i].cb = cb; + btn->cb_info[event][i].usr_data = usr_data; + } else { + btn->cb_info[event][i + 1].event_data.long_press.press_time = press_time; + btn->cb_info[event][i + 1].cb = cb; + btn->cb_info[event][i + 1].usr_data = usr_data; + break; + } + } + } else { + btn->cb_info[event][btn->size[event] - 1].event_data.long_press.press_time = press_time; + } + + int32_t press_ticks = press_time / TICKS_INTERVAL; + if (btn->short_press_ticks < press_ticks && press_ticks < btn->long_press_ticks) { + iot_button_set_param(btn, BUTTON_LONG_PRESS_TIME_MS, (void*)(intptr_t)press_time); + } + } + + if (event == BUTTON_MULTIPLE_CLICK) { + if (btn->size[event] >= 2) { + for (int i = btn->size[event] - 2; i >= 0; i--) { + if (btn->cb_info[event][i].event_data.multiple_clicks.clicks > event_cfg.event_data.multiple_clicks.clicks) { + btn->cb_info[event][i + 1] = btn->cb_info[event][i]; + + btn->cb_info[event][i].event_data.multiple_clicks.clicks = event_cfg.event_data.multiple_clicks.clicks; + btn->cb_info[event][i].cb = cb; + btn->cb_info[event][i].usr_data = usr_data; + } else { + btn->cb_info[event][i + 1].event_data.multiple_clicks.clicks = event_cfg.event_data.multiple_clicks.clicks; + btn->cb_info[event][i + 1].cb = cb; + btn->cb_info[event][i + 1].usr_data = usr_data; + break; + } + } + } else { + btn->cb_info[event][btn->size[event] - 1].event_data.multiple_clicks.clicks = event_cfg.event_data.multiple_clicks.clicks; + } + } + + return ESP_OK; +} + +esp_err_t iot_button_unregister_cb(button_handle_t btn_handle, button_event_t event) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG); + BTN_CHECK(event < BUTTON_EVENT_MAX, "event is invalid", ESP_ERR_INVALID_ARG); + button_dev_t *btn = (button_dev_t *) btn_handle; + BTN_CHECK(NULL != btn->cb_info[event], "No callbacks registered for the event", ESP_ERR_INVALID_STATE); + + if (btn->cb_info[event]) { + free(btn->cb_info[event]); + + /** Reset the counter */ + if (event == BUTTON_LONG_PRESS_START) { + btn->count[0] = 0; + } else if (event == BUTTON_LONG_PRESS_UP) { + btn->count[1] = -1; + } + + } + + btn->cb_info[event] = NULL; + btn->size[event] = 0; + return ESP_OK; +} + +esp_err_t iot_button_unregister_event(button_handle_t btn_handle, button_event_config_t event_cfg, button_cb_t cb) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG); + button_event_t event = event_cfg.event; + BTN_CHECK(event < BUTTON_EVENT_MAX, "event is invalid", ESP_ERR_INVALID_ARG); + BTN_CHECK(NULL != cb, "Pointer to function callback is invalid", ESP_ERR_INVALID_ARG); + button_dev_t *btn = (button_dev_t *) btn_handle; + + int check = -1; + + for (int i = 0; i < btn->size[event]; i++) { + if (cb == btn->cb_info[event][i].cb) { + if ((event == BUTTON_LONG_PRESS_START || event == BUTTON_LONG_PRESS_UP) && event_cfg.event_data.long_press.press_time) { + if (event_cfg.event_data.long_press.press_time != btn->cb_info[event][i].event_data.long_press.press_time) { + continue; + } + } + + if (event == BUTTON_MULTIPLE_CLICK && event_cfg.event_data.multiple_clicks.clicks) { + if (event_cfg.event_data.multiple_clicks.clicks != btn->cb_info[event][i].event_data.multiple_clicks.clicks) { + continue; + } + } + check = i; + for (int j = i; j <= btn->size[event] - 1; j++) { + btn->cb_info[event][j] = btn->cb_info[event][j + 1]; + } + + if (btn->size[event] != 1) { + button_cb_info_t *p = realloc(btn->cb_info[event], sizeof(button_cb_info_t) * (btn->size[event] - 1)); + BTN_CHECK(NULL != p, "realloc cb_info failed", ESP_ERR_NO_MEM); + btn->cb_info[event] = p; + btn->size[event]--; + } else { + free(btn->cb_info[event]); + btn->cb_info[event] = NULL; + btn->size[event] = 0; + } + break; + } + } + + BTN_CHECK(check != -1, "No such callback registered for the event", ESP_ERR_INVALID_STATE); + + return ESP_OK; +} + +size_t iot_button_count_cb(button_handle_t btn_handle) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG); + button_dev_t *btn = (button_dev_t *) btn_handle; + size_t ret = 0; + for (size_t i = 0; i < BUTTON_EVENT_MAX; i++) { + if (btn->cb_info[i]) { + ret += btn->size[i]; + } + } + return ret; +} + +size_t iot_button_count_event(button_handle_t btn_handle, button_event_t event) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG); + button_dev_t *btn = (button_dev_t *) btn_handle; + return btn->size[event]; +} + +button_event_t iot_button_get_event(button_handle_t btn_handle) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", BUTTON_NONE_PRESS); + button_dev_t *btn = (button_dev_t *) btn_handle; + return btn->event; +} + +const char *iot_button_get_event_str(button_event_t event) +{ + BTN_CHECK(event <= BUTTON_NONE_PRESS && event >= BUTTON_PRESS_DOWN, "event value is invalid", "invalid event"); + return button_event_str[event]; +} + +esp_err_t iot_button_print_event(button_handle_t btn_handle) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_FAIL); + button_dev_t *btn = (button_dev_t *) btn_handle; + ESP_LOGI(TAG, "%s", button_event_str[btn->event]); + return ESP_OK; +} + +uint8_t iot_button_get_repeat(button_handle_t btn_handle) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", 0); + button_dev_t *btn = (button_dev_t *) btn_handle; + return btn->repeat; +} + +uint32_t iot_button_get_ticks_time(button_handle_t btn_handle) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", 0); + button_dev_t *btn = (button_dev_t *) btn_handle; + return (btn->ticks * TICKS_INTERVAL); +} + +uint16_t iot_button_get_long_press_hold_cnt(button_handle_t btn_handle) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", 0); + button_dev_t *btn = (button_dev_t *) btn_handle; + return btn->long_press_hold_cnt; +} + +esp_err_t iot_button_set_param(button_handle_t btn_handle, button_param_t param, void *value) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG); + button_dev_t *btn = (button_dev_t *) btn_handle; + BUTTON_ENTER_CRITICAL(); + switch (param) { + case BUTTON_LONG_PRESS_TIME_MS: + btn->long_press_ticks = (int32_t)value / TICKS_INTERVAL; + break; + case BUTTON_SHORT_PRESS_TIME_MS: + btn->short_press_ticks = (int32_t)value / TICKS_INTERVAL; + break; + default: + break; + } + BUTTON_EXIT_CRITICAL(); + return ESP_OK; +} + +uint8_t iot_button_get_key_level(button_handle_t btn_handle) +{ + BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", 0); + button_dev_t *btn = (button_dev_t *)btn_handle; + uint8_t level = btn->hal_button_Level(btn->hardware_data); + return (level == btn->active_level) ? 1 : 0; +} + +esp_err_t iot_button_resume(void) +{ + BTN_CHECK(g_button_timer_handle, "Button timer handle is invalid", ESP_ERR_INVALID_STATE); + BTN_CHECK(!g_is_timer_running, "Button timer is already running", ESP_ERR_INVALID_STATE); + + esp_err_t err = esp_timer_start_periodic(g_button_timer_handle, TICKS_INTERVAL * 1000U); + BTN_CHECK(ESP_OK == err, "Button timer start failed", ESP_FAIL); + g_is_timer_running = true; + return ESP_OK; +} + +esp_err_t iot_button_stop(void) +{ + BTN_CHECK(g_button_timer_handle, "Button timer handle is invalid", ESP_ERR_INVALID_STATE); + BTN_CHECK(g_is_timer_running, "Button timer is not running", ESP_ERR_INVALID_STATE); + + esp_err_t err = esp_timer_stop(g_button_timer_handle); + BTN_CHECK(ESP_OK == err, "Button timer stop failed", ESP_FAIL); + g_is_timer_running = false; + return ESP_OK; +} + +#if CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE +esp_err_t iot_button_register_power_save_cb(const button_power_save_config_t *config) +{ + BTN_CHECK(g_head_handle, "No button registered", ESP_ERR_INVALID_STATE); + BTN_CHECK(config->enter_power_save_cb, "Enter power save callback is invalid", ESP_ERR_INVALID_ARG); + + power_save_usr_cfg.enter_power_save_cb = config->enter_power_save_cb; + power_save_usr_cfg.usr_data = config->usr_data; + return ESP_OK; +} +#endif diff --git a/managed_components/espressif__button/license.txt b/managed_components/espressif__button/license.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/managed_components/espressif__button/license.txt @@ -0,0 +1,202 @@ + + 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 [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 + + 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. diff --git a/managed_components/espressif__button/test_apps/CMakeLists.txt b/managed_components/espressif__button/test_apps/CMakeLists.txt new file mode 100644 index 0000000..180743a --- /dev/null +++ b/managed_components/espressif__button/test_apps/CMakeLists.txt @@ -0,0 +1,9 @@ + +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components" + "../../button") +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(button_test) diff --git a/managed_components/espressif__button/test_apps/main/CMakeLists.txt b/managed_components/espressif__button/test_apps/main/CMakeLists.txt new file mode 100644 index 0000000..0fc53ca --- /dev/null +++ b/managed_components/espressif__button/test_apps/main/CMakeLists.txt @@ -0,0 +1,9 @@ +if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") + list(APPEND PRIVREQ esp_adc) +else() + list(APPEND PRIVREQ esp_adc_cal) +endif() + +idf_component_register(SRC_DIRS "." + PRIV_INCLUDE_DIRS "." + PRIV_REQUIRES unity test_utils button ${PRIVREQ}) diff --git a/managed_components/espressif__button/test_apps/main/button_test.c b/managed_components/espressif__button/test_apps/main/button_test.c new file mode 100644 index 0000000..daec61d --- /dev/null +++ b/managed_components/espressif__button/test_apps/main/button_test.c @@ -0,0 +1,743 @@ +/* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/timers.h" +#include "freertos/semphr.h" +#include "freertos/event_groups.h" +#include "esp_idf_version.h" +#include "esp_log.h" +#include "unity.h" +#include "iot_button.h" +#include "sdkconfig.h" + +static const char *TAG = "BUTTON TEST"; + +#define TEST_MEMORY_LEAK_THRESHOLD (-400) +#define BUTTON_IO_NUM 0 +#define BUTTON_ACTIVE_LEVEL 0 +#define BUTTON_NUM 16 + +static size_t before_free_8bit; +static size_t before_free_32bit; +static button_handle_t g_btns[BUTTON_NUM] = {0}; + +static int get_btn_index(button_handle_t btn) +{ + for (size_t i = 0; i < BUTTON_NUM; i++) { + if (btn == g_btns[i]) { + return i; + } + } + return -1; +} + +static void button_press_down_cb(void *arg, void *data) +{ + TEST_ASSERT_EQUAL_HEX(BUTTON_PRESS_DOWN, iot_button_get_event(arg)); + ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_DOWN", get_btn_index((button_handle_t)arg)); +} + +static void button_press_up_cb(void *arg, void *data) +{ + TEST_ASSERT_EQUAL_HEX(BUTTON_PRESS_UP, iot_button_get_event(arg)); + ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_UP[%"PRIu32"]", get_btn_index((button_handle_t)arg), iot_button_get_ticks_time((button_handle_t)arg)); +} + +static void button_press_repeat_cb(void *arg, void *data) +{ + ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_REPEAT[%d]", get_btn_index((button_handle_t)arg), iot_button_get_repeat((button_handle_t)arg)); +} + +static void button_single_click_cb(void *arg, void *data) +{ + TEST_ASSERT_EQUAL_HEX(BUTTON_SINGLE_CLICK, iot_button_get_event(arg)); + ESP_LOGI(TAG, "BTN%d: BUTTON_SINGLE_CLICK", get_btn_index((button_handle_t)arg)); +} + +static void button_double_click_cb(void *arg, void *data) +{ + TEST_ASSERT_EQUAL_HEX(BUTTON_DOUBLE_CLICK, iot_button_get_event(arg)); + ESP_LOGI(TAG, "BTN%d: BUTTON_DOUBLE_CLICK", get_btn_index((button_handle_t)arg)); +} + +static void button_long_press_start_cb(void *arg, void *data) +{ + TEST_ASSERT_EQUAL_HEX(BUTTON_LONG_PRESS_START, iot_button_get_event(arg)); + ESP_LOGI(TAG, "BTN%d: BUTTON_LONG_PRESS_START", get_btn_index((button_handle_t)arg)); +} + +static void button_long_press_hold_cb(void *arg, void *data) +{ + TEST_ASSERT_EQUAL_HEX(BUTTON_LONG_PRESS_HOLD, iot_button_get_event(arg)); + ESP_LOGI(TAG, "BTN%d: BUTTON_LONG_PRESS_HOLD[%"PRIu32"],count is [%d]", get_btn_index((button_handle_t)arg), iot_button_get_ticks_time((button_handle_t)arg), iot_button_get_long_press_hold_cnt((button_handle_t)arg)); +} + +static void button_press_repeat_done_cb(void *arg, void *data) +{ + TEST_ASSERT_EQUAL_HEX(BUTTON_PRESS_REPEAT_DONE, iot_button_get_event(arg)); + ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_REPEAT_DONE[%d]", get_btn_index((button_handle_t)arg), iot_button_get_repeat((button_handle_t)arg)); +} + +static esp_err_t custom_button_gpio_init(void *param) +{ + button_gpio_config_t *cfg = (button_gpio_config_t *)param; + + return button_gpio_init(cfg); +} + +static uint8_t custom_button_gpio_get_key_value(void *param) +{ + button_gpio_config_t *cfg = (button_gpio_config_t *)param; + + return button_gpio_get_key_level((void *)cfg->gpio_num); +} + +static esp_err_t custom_button_gpio_deinit(void *param) +{ + button_gpio_config_t *cfg = (button_gpio_config_t *)param; + + return button_gpio_deinit(cfg->gpio_num); +} + +TEST_CASE("custom button test", "[button][iot]") +{ + button_gpio_config_t *gpio_cfg = calloc(1, sizeof(button_gpio_config_t)); + gpio_cfg->active_level = 0; + gpio_cfg->gpio_num = 0; + + button_config_t cfg = { + .type = BUTTON_TYPE_CUSTOM, + .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS, + .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS, + .custom_button_config = { + .button_custom_init = custom_button_gpio_init, + .button_custom_deinit = custom_button_gpio_deinit, + .button_custom_get_key_value = custom_button_gpio_get_key_value, + .active_level = 0, + .priv = gpio_cfg, + }, + }; + + g_btns[0] = iot_button_create(&cfg); + TEST_ASSERT_NOT_NULL(g_btns[0]); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_DOWN, button_press_down_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_press_up_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL); + + while (1) { + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + iot_button_delete(g_btns[0]); +} + +TEST_CASE("gpio button test", "[button][iot]") +{ + button_config_t cfg = { + .type = BUTTON_TYPE_GPIO, + .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS, + .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS, + .gpio_button_config = { + .gpio_num = 0, + .active_level = 0, + }, + }; + g_btns[0] = iot_button_create(&cfg); + TEST_ASSERT_NOT_NULL(g_btns[0]); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_DOWN, button_press_down_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_press_up_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL); + + uint8_t level = 0; + level = iot_button_get_key_level(g_btns[0]); + ESP_LOGI(TAG, "button level is %d", level); + + while (1) { + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + iot_button_delete(g_btns[0]); +} + +TEST_CASE("gpio button get event test", "[button][iot]") +{ + button_config_t cfg = { + .type = BUTTON_TYPE_GPIO, + .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS, + .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS, + .gpio_button_config = { + .gpio_num = 0, + .active_level = 0, + }, + }; + g_btns[0] = iot_button_create(&cfg); + TEST_ASSERT_NOT_NULL(g_btns[0]); + + uint8_t level = 0; + level = iot_button_get_key_level(g_btns[0]); + ESP_LOGI(TAG, "button level is %d", level); + + while (1) { + button_event_t event = iot_button_get_event(g_btns[0]); + if (event != BUTTON_NONE_PRESS) { + ESP_LOGI(TAG, "event is %s", iot_button_get_event_str(event)); + } + vTaskDelay(pdMS_TO_TICKS(1)); + } + + iot_button_delete(g_btns[0]); +} + +TEST_CASE("gpio button test power save", "[button][iot][power save]") +{ + button_config_t cfg = { + .type = BUTTON_TYPE_GPIO, + .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS, + .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS, + .gpio_button_config = { + .gpio_num = 0, + .active_level = 0, + }, + }; + g_btns[0] = iot_button_create(&cfg); + TEST_ASSERT_NOT_NULL(g_btns[0]); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_DOWN, button_press_down_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_press_up_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL); + iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL); + + TEST_ASSERT_EQUAL(ESP_OK, iot_button_stop()); + vTaskDelay(pdMS_TO_TICKS(1000)); + TEST_ASSERT_EQUAL(ESP_OK, iot_button_resume()); + + while (1) { + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + iot_button_delete(g_btns[0]); +} + +TEST_CASE("matrix keyboard button test", "[button][matrix key]") +{ + int32_t row_gpio[4] = {4, 5, 6, 7}; + int32_t col_gpio[4] = {3, 8, 16, 15}; + button_config_t cfg = { + .type = BUTTON_TYPE_MATRIX, + .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS, + .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS, + .matrix_button_config = { + .row_gpio_num = 0, + .col_gpio_num = 0, + } + }; + + for (int i = 0; i < 4; i++) { + cfg.matrix_button_config.row_gpio_num = row_gpio[i]; + for (int j = 0; j < 4; j++) { + cfg.matrix_button_config.col_gpio_num = col_gpio[j]; + g_btns[i * 4 + j] = iot_button_create(&cfg); + TEST_ASSERT_NOT_NULL(g_btns[i * 4 + j]); + iot_button_register_cb(g_btns[i * 4 + j], BUTTON_PRESS_DOWN, button_press_down_cb, NULL); + iot_button_register_cb(g_btns[i * 4 + j], BUTTON_PRESS_UP, button_press_up_cb, NULL); + iot_button_register_cb(g_btns[i * 4 + j], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL); + iot_button_register_cb(g_btns[i * 4 + j], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL); + iot_button_register_cb(g_btns[i * 4 + j], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL); + iot_button_register_cb(g_btns[i * 4 + j], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL); + iot_button_register_cb(g_btns[i * 4 + j], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL); + iot_button_register_cb(g_btns[i * 4 + j], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL); + } + } + + while (1) { + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + iot_button_delete(g_btns[i * 4 + j]); + } + } +} + +#if CONFIG_SOC_ADC_SUPPORTED +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) +TEST_CASE("adc button test", "[button][iot]") +{ + /** ESP32-S3-Korvo board */ + const uint16_t vol[6] = {380, 820, 1180, 1570, 1980, 2410}; + button_config_t cfg = {0}; + cfg.type = BUTTON_TYPE_ADC; + cfg.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS; + cfg.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS; + for (size_t i = 0; i < 6; i++) { + cfg.adc_button_config.adc_channel = 7, + cfg.adc_button_config.button_index = i; + if (i == 0) { + cfg.adc_button_config.min = (0 + vol[i]) / 2; + } else { + cfg.adc_button_config.min = (vol[i - 1] + vol[i]) / 2; + } + + if (i == 5) { + cfg.adc_button_config.max = (vol[i] + 3000) / 2; + } else { + cfg.adc_button_config.max = (vol[i] + vol[i + 1]) / 2; + } + + g_btns[i] = iot_button_create(&cfg); + TEST_ASSERT_NOT_NULL(g_btns[i]); + iot_button_register_cb(g_btns[i], BUTTON_PRESS_DOWN, button_press_down_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_PRESS_UP, button_press_up_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL); + } + + while (1) { + vTaskDelay(pdMS_TO_TICKS(1000)); + } + for (size_t i = 0; i < 6; i++) { + iot_button_delete(g_btns[i]); + } +} +#else + +#include "esp_adc/adc_cali.h" + +static esp_err_t adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle) +{ + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#define ADC_BUTTON_WIDTH SOC_ADC_RTC_MAX_BITWIDTH +#else +#define ADC_BUTTON_WIDTH ADC_WIDTH_MAX - 1 +#endif + + adc_cali_handle_t handle = NULL; + esp_err_t ret = ESP_FAIL; + bool calibrated = false; + +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + if (!calibrated) { + ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting"); + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = ADC_BUTTON_WIDTH, + }; + ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle); + if (ret == ESP_OK) { + calibrated = true; + } + } +#endif + +#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + if (!calibrated) { + ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting"); + adc_cali_line_fitting_config_t cali_config = { + .unit_id = unit, + .atten = atten, + .bitwidth = ADC_BUTTON_WIDTH, + }; + ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle); + if (ret == ESP_OK) { + calibrated = true; + } + } +#endif + + *out_handle = handle; + if (ret == ESP_OK) { + ESP_LOGI(TAG, "Calibration Success"); + } else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) { + ESP_LOGW(TAG, "eFuse not burnt, skip software calibration"); + } else { + ESP_LOGE(TAG, "Invalid arg or no memory"); + } + + return calibrated ? ESP_OK : ESP_FAIL; +} + +TEST_CASE("adc button idf5 drive test", "[button][iot]") +{ + adc_oneshot_unit_handle_t adc1_handle; + adc_cali_handle_t adc1_cali_handle; + adc_oneshot_unit_init_cfg_t init_config = { + .unit_id = ADC_UNIT_1, + }; + esp_err_t ret = adc_oneshot_new_unit(&init_config, &adc1_handle); + TEST_ASSERT_TRUE(ret == ESP_OK); + /*!< use atten 11db or 12db */ + adc_calibration_init(ADC_UNIT_1, 3, &adc1_cali_handle); + + /** ESP32-S3-Korvo board */ + const uint16_t vol[6] = {380, 820, 1180, 1570, 1980, 2410}; + button_config_t cfg = {0}; + cfg.type = BUTTON_TYPE_ADC; + cfg.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS; + cfg.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS; + for (size_t i = 0; i < 6; i++) { + cfg.adc_button_config.adc_handle = &adc1_handle; + cfg.adc_button_config.adc_channel = 7, + cfg.adc_button_config.button_index = i; + if (i == 0) { + cfg.adc_button_config.min = (0 + vol[i]) / 2; + } else { + cfg.adc_button_config.min = (vol[i - 1] + vol[i]) / 2; + } + + if (i == 5) { + cfg.adc_button_config.max = (vol[i] + 3000) / 2; + } else { + cfg.adc_button_config.max = (vol[i] + vol[i + 1]) / 2; + } + + g_btns[i] = iot_button_create(&cfg); + TEST_ASSERT_NOT_NULL(g_btns[i]); + iot_button_register_cb(g_btns[i], BUTTON_PRESS_DOWN, button_press_down_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_PRESS_UP, button_press_up_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL); + iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL); + } + + while (1) { + vTaskDelay(pdMS_TO_TICKS(1000)); + } + for (size_t i = 0; i < 6; i++) { + iot_button_delete(g_btns[i]); + } +} +#endif +#endif // CONFIG_SOC_ADC_SUPPORTED + +#define GPIO_OUTPUT_IO_45 45 +static EventGroupHandle_t g_check = NULL; +static SemaphoreHandle_t g_auto_check_pass = NULL; + +static button_event_t state = BUTTON_PRESS_DOWN; + +static void button_auto_press_test_task(void *arg) +{ + // test BUTTON_PRESS_DOWN + xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY); + gpio_set_level(GPIO_OUTPUT_IO_45, 0); + vTaskDelay(pdMS_TO_TICKS(100)); + + // // test BUTTON_PRESS_UP + xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + vTaskDelay(pdMS_TO_TICKS(200)); + + // test BUTTON_PRESS_REPEAT + xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY); + gpio_set_level(GPIO_OUTPUT_IO_45, 0); + vTaskDelay(pdMS_TO_TICKS(100)); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + vTaskDelay(pdMS_TO_TICKS(100)); + gpio_set_level(GPIO_OUTPUT_IO_45, 0); + vTaskDelay(pdMS_TO_TICKS(100)); + + // test BUTTON_PRESS_REPEAT_DONE + xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + vTaskDelay(pdMS_TO_TICKS(200)); + + // test BUTTON_SINGLE_CLICK + xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY); + gpio_set_level(GPIO_OUTPUT_IO_45, 0); + vTaskDelay(pdMS_TO_TICKS(100)); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + vTaskDelay(pdMS_TO_TICKS(200)); + + // test BUTTON_DOUBLE_CLICK + xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY); + gpio_set_level(GPIO_OUTPUT_IO_45, 0); + vTaskDelay(pdMS_TO_TICKS(100)); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + vTaskDelay(pdMS_TO_TICKS(100)); + gpio_set_level(GPIO_OUTPUT_IO_45, 0); + vTaskDelay(pdMS_TO_TICKS(100)); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + vTaskDelay(pdMS_TO_TICKS(200)); + + // test BUTTON_MULTIPLE_CLICK + xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY); + for (int i = 0; i < 4; i++) { + gpio_set_level(GPIO_OUTPUT_IO_45, 0); + vTaskDelay(pdMS_TO_TICKS(100)); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + vTaskDelay(pdMS_TO_TICKS(100)); + } + vTaskDelay(pdMS_TO_TICKS(100)); + + // test BUTTON_LONG_PRESS_START + xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY); + gpio_set_level(GPIO_OUTPUT_IO_45, 0); + vTaskDelay(pdMS_TO_TICKS(1600)); + + // test BUTTON_LONG_PRESS_HOLD and BUTTON_LONG_PRESS_UP + xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + + ESP_LOGI(TAG, "Auto Press Success!"); + vTaskDelete(NULL); +} +static void button_auto_check_cb_1(void *arg, void *data) +{ + if (iot_button_get_event(g_btns[0]) == state) { + xEventGroupSetBits(g_check, BIT(1)); + } +} +static void button_auto_check_cb(void *arg, void *data) +{ + if (iot_button_get_event(g_btns[0]) == state) { + ESP_LOGI(TAG, "Auto check: button event %s pass", iot_button_get_event_str(state)); + xEventGroupSetBits(g_check, BIT(0)); + if (++state >= BUTTON_EVENT_MAX) { + xSemaphoreGive(g_auto_check_pass); + return; + } + } +} + +TEST_CASE("gpio button auto-test", "[button][iot][auto]") +{ + state = BUTTON_PRESS_DOWN; + g_check = xEventGroupCreate(); + g_auto_check_pass = xSemaphoreCreateBinary(); + xEventGroupSetBits(g_check, BIT(0) | BIT(1)); + button_config_t cfg = { + .type = BUTTON_TYPE_GPIO, + .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS, + .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS, + .gpio_button_config = { + .gpio_num = 0, + .active_level = 0, + }, + }; + g_btns[0] = iot_button_create(&cfg); + TEST_ASSERT_NOT_NULL(g_btns[0]); + + /* register iot_button callback for all the button_event */ + for (uint8_t i = 0; i < BUTTON_EVENT_MAX; i++) { + if (i == BUTTON_MULTIPLE_CLICK) { + button_event_config_t btn_cfg; + btn_cfg.event = i; + btn_cfg.event_data.multiple_clicks.clicks = 4; + iot_button_register_event_cb(g_btns[0], btn_cfg, button_auto_check_cb_1, NULL); + iot_button_register_event_cb(g_btns[0], btn_cfg, button_auto_check_cb, NULL); + } else { + iot_button_register_cb(g_btns[0], i, button_auto_check_cb_1, NULL); + iot_button_register_cb(g_btns[0], i, button_auto_check_cb, NULL); + } + } + + TEST_ASSERT_EQUAL(ESP_OK, iot_button_set_param(g_btns[0], BUTTON_LONG_PRESS_TIME_MS, (void *)1500)); + + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = (1ULL << GPIO_OUTPUT_IO_45), + .pull_down_en = 0, + .pull_up_en = 0, + }; + gpio_config(&io_conf); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + + xTaskCreate(button_auto_press_test_task, "button_auto_press_test_task", 1024 * 4, NULL, 10, NULL); + + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(g_auto_check_pass, pdMS_TO_TICKS(6000))); + + for (uint8_t i = 0; i < BUTTON_EVENT_MAX; i++) { + button_event_config_t btn_cfg; + btn_cfg.event = i; + if (i == BUTTON_MULTIPLE_CLICK) { + btn_cfg.event_data.multiple_clicks.clicks = 4; + } else if (i == BUTTON_LONG_PRESS_UP || i == BUTTON_LONG_PRESS_START) { + btn_cfg.event_data.long_press.press_time = 1500; + } + iot_button_unregister_event(g_btns[0], btn_cfg, button_auto_check_cb); + iot_button_unregister_event(g_btns[0], btn_cfg, button_auto_check_cb_1); + } + + TEST_ASSERT_EQUAL(ESP_OK, iot_button_delete(g_btns[0])); + vEventGroupDelete(g_check); + vSemaphoreDelete(g_auto_check_pass); + vTaskDelay(pdMS_TO_TICKS(100)); +} + +#define TOLERANCE (CONFIG_BUTTON_PERIOD_TIME_MS * 4) + +uint16_t long_press_time[5] = {2000, 2500, 3000, 3500, 4000}; +static SemaphoreHandle_t long_press_check = NULL; +static SemaphoreHandle_t long_press_auto_check_pass = NULL; +unsigned int status = 0; + +static void button_auto_long_press_test_task(void *arg) +{ + // Test for BUTTON_LONG_PRESS_START + for (int i = 0; i < 5; i++) { + xSemaphoreTake(long_press_check, portMAX_DELAY); + gpio_set_level(GPIO_OUTPUT_IO_45, 0); + status = (BUTTON_LONG_PRESS_START << 16) | long_press_time[i]; + if (i > 0) { + vTaskDelay(pdMS_TO_TICKS(long_press_time[i] - long_press_time[i - 1])); + } else { + vTaskDelay(pdMS_TO_TICKS(long_press_time[i])); + } + } + vTaskDelay(pdMS_TO_TICKS(100)); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + xSemaphoreGive(long_press_auto_check_pass); + vTaskDelay(pdMS_TO_TICKS(100)); + // Test for BUTTON_LONG_PRESS_UP + for (int i = 0; i < 5; i++) { + xSemaphoreTake(long_press_check, portMAX_DELAY); + status = (BUTTON_LONG_PRESS_UP << 16) | long_press_time[i]; + gpio_set_level(GPIO_OUTPUT_IO_45, 0); + vTaskDelay(pdMS_TO_TICKS(long_press_time[i] + 10)); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + } + + ESP_LOGI(TAG, "Auto Long Press Success!"); + vTaskDelete(NULL); +} + +static void button_long_press_auto_check_cb(void *arg, void *data) +{ + uint32_t value = (uint32_t)data; + uint16_t event = (0xffff0000 & value) >> 16; + uint16_t time = 0xffff & value; + uint32_t ticks_time = iot_button_get_ticks_time(g_btns[0]); + int32_t diff = ticks_time - time; + if (status == value && abs(diff) <= TOLERANCE) { + ESP_LOGI(TAG, "Auto check: button event: %s and time: %d pass", iot_button_get_event_str(state), time); + + if (event == BUTTON_LONG_PRESS_UP && time == long_press_time[4]) { + xSemaphoreGive(long_press_auto_check_pass); + } + + xSemaphoreGive(long_press_check); + } +} + +TEST_CASE("gpio button long_press auto-test", "[button][long_press][auto]") +{ + ESP_LOGI(TAG, "Starting the test"); + long_press_check = xSemaphoreCreateBinary(); + long_press_auto_check_pass = xSemaphoreCreateBinary(); + xSemaphoreGive(long_press_check); + button_config_t cfg = { + .type = BUTTON_TYPE_GPIO, + .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS, + .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS, + .gpio_button_config = { + .gpio_num = 0, + .active_level = 0, + }, + }; + g_btns[0] = iot_button_create(&cfg); + TEST_ASSERT_NOT_NULL(g_btns[0]); + + button_event_config_t btn_cfg; + btn_cfg.event = BUTTON_LONG_PRESS_START; + for (int i = 0; i < 5; i++) { + btn_cfg.event_data.long_press.press_time = long_press_time[i]; + uint32_t data = (btn_cfg.event << 16) | long_press_time[i]; + iot_button_register_event_cb(g_btns[0], btn_cfg, button_long_press_auto_check_cb, (void*)data); + } + + gpio_config_t io_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = (1ULL << GPIO_OUTPUT_IO_45), + .pull_down_en = 0, + .pull_up_en = 0, + }; + gpio_config(&io_conf); + gpio_set_level(GPIO_OUTPUT_IO_45, 1); + xTaskCreate(button_auto_long_press_test_task, "button_auto_long_press_test_task", 1024 * 4, NULL, 10, NULL); + + xSemaphoreTake(long_press_auto_check_pass, portMAX_DELAY); + iot_button_unregister_cb(g_btns[0], BUTTON_LONG_PRESS_START); + btn_cfg.event = BUTTON_LONG_PRESS_UP; + for (int i = 0; i < 5; i++) { + btn_cfg.event_data.long_press.press_time = long_press_time[i]; + uint32_t data = (btn_cfg.event << 16) | long_press_time[i]; + iot_button_register_event_cb(g_btns[0], btn_cfg, button_long_press_auto_check_cb, (void*)data); + } + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(long_press_auto_check_pass, pdMS_TO_TICKS(17000))); + TEST_ASSERT_EQUAL(ESP_OK, iot_button_delete(g_btns[0])); + vSemaphoreDelete(long_press_check); + vSemaphoreDelete(long_press_auto_check_pass); + vTaskDelay(pdMS_TO_TICKS(100)); +} + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); +} + +void app_main(void) +{ + /* + * ____ _ _ _______ _ + *| _ \ | | | | |__ __| | | + *| |_) | _ _ | |_ | |_ ___ _ __ | | ___ ___ | |_ + *| _ < | | | || __|| __|/ _ \ | '_ \ | | / _ \/ __|| __| + *| |_) || |_| || |_ | |_| (_) || | | | | || __/\__ \| |_ + *|____/ \__,_| \__| \__|\___/ |_| |_| |_| \___||___/ \__| + */ + printf(" ____ _ _ _______ _ \n"); + printf(" | _ \\ | | | | |__ __| | | \n"); + printf(" | |_) | _ _ | |_ | |_ ___ _ __ | | ___ ___ | |_ \n"); + printf(" | _ < | | | || __|| __|/ _ \\ | '_ \\ | | / _ \\/ __|| __|\n"); + printf(" | |_) || |_| || |_ | |_| (_) || | | | | || __/\\__ \\| |_ \n"); + printf(" |____/ \\__,_| \\__| \\__|\\___/ |_| |_| |_| \\___||___/ \\__|\n"); + unity_run_menu(); +} diff --git a/managed_components/espressif__button/test_apps/pytest_button.py b/managed_components/espressif__button/test_apps/pytest_button.py new file mode 100644 index 0000000..1aa4dce --- /dev/null +++ b/managed_components/espressif__button/test_apps/pytest_button.py @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +''' +Steps to run these cases: +- Build + - . ${IDF_PATH}/export.sh + - pip install idf_build_apps + - python tools/build_apps.py components/button/test_apps -t esp32s3 +- Test + - pip install -r tools/requirements/requirement.pytest.txt + - pytest components/button/test_apps --target esp32s3 +''' + +import pytest +from pytest_embedded import Dut + +@pytest.mark.target('esp32s3') +@pytest.mark.env('button') +@pytest.mark.parametrize( + 'config', + [ + 'defaults', + ], +) +def test_button(dut: Dut)-> None: + dut.expect_exact('Press ENTER to see the list of tests.') + dut.write('[auto]') + dut.expect_unity_test_output(timeout = 300) diff --git a/managed_components/espressif__button/test_apps/sdkconfig.ci.pm b/managed_components/espressif__button/test_apps/sdkconfig.ci.pm new file mode 100644 index 0000000..c3befd9 --- /dev/null +++ b/managed_components/espressif__button/test_apps/sdkconfig.ci.pm @@ -0,0 +1 @@ +CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE=y diff --git a/managed_components/espressif__button/test_apps/sdkconfig.defaults b/managed_components/espressif__button/test_apps/sdkconfig.defaults new file mode 100644 index 0000000..3778471 --- /dev/null +++ b/managed_components/espressif__button/test_apps/sdkconfig.defaults @@ -0,0 +1,9 @@ +# For IDF 5.0 +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT_EN=n + +# For IDF4.4 +CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y +CONFIG_ESP_TASK_WDT=n diff --git a/managed_components/espressif__cmake_utilities/.component_hash b/managed_components/espressif__cmake_utilities/.component_hash new file mode 100644 index 0000000..b110e53 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/.component_hash @@ -0,0 +1 @@ +351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f \ No newline at end of file diff --git a/managed_components/espressif__cmake_utilities/CHANGELOG.md b/managed_components/espressif__cmake_utilities/CHANGELOG.md new file mode 100644 index 0000000..26fd7eb --- /dev/null +++ b/managed_components/espressif__cmake_utilities/CHANGELOG.md @@ -0,0 +1,89 @@ +## v0.5.3 - 2023-09-15 + +* fix `add_dependencies called with incorrect number of arguments` in `relinker.cmake` +* `include(cmake_utilities)` is not suggested now, to avoid cmake_utilities dependency issue + +## v0.5.2 - 2023-09-15 + +* Support work on older ESP-IDF, eg: 4.3.x + +## v0.5.1 - 2023-08-22 + +* Add string 1-byte align support + +## v0.5.0 - 2023-08-02 + +* Add GCC LTO support + +## v0.4.8 - 2023-05-24 + +* Add unit test app + +### Bugfix: + +* fix customer target redefinition issue + +## v0.4.7 - 2023-04-21 + +* gen_compressed_ota: support the addition of a v2 compressed OTA header to compressed firmware. + +## v0.4.6 - 2023-04-20 + +* relinker: add IDF v4.3.x support + +## v0.4.5 - 2023-04-17 + +* gen_compressed_ota: remove slash use in gen_custom_ota.py so that the script can be used in the Windows cmd terminal. + +## v0.4.4 - 2023-04-07 + +* relinker: suppressing the creation of `__pycache__` +* relinker: support same name objects in one library + +## v0.4.3 - 2023-03-24 + +* relinker: support decoding to get IRAM excluded libraries + +## v0.4.2 - 2023-03-20 + +### Bugfix: + +* gen_compressed_ota: Fix the number of bytes reserved in the v3 compressed image header +* gen_compressed_ota: Fix definition of MD5 length in compressed image header for different versions. + +## v0.4.1 - 2023-03-15 + +* relinker: add option to use customized configuration files +* relinker: add option to print error information instead of throwing exception when missing function +* relinker: move functions of SPI flash from IRAM to flash only when enable CONFIG_SPI_FLASH_ROM_IMPL +* relinker: move some functions of esp_timer from IRAM to flash only when disable CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD + +## v0.4.0 - 2023-03-13 + +### Feature: + +* Add command `idf.py gen_single_bin` to generate merged bin file +* Add command `idf.py flash_single_bin` to flash generated merged bin +* Add config `Color in diagnostics` to control the GCC color output + +## v0.3.0 - 2023-03-10 + +* Add gen_compressed_ota functionality, please refer to [gen_compressed_ota.md](https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities/docs/gen_compressed_ota.md) + +## v0.2.1 - 2023-03-09 + +### Bugfix: + +* package manager: Fix the compile issue when the name of the component has `-`, just like esp-xxx + +## v0.2.0 - 2023-02-23 + +* Add relinker functionality, please refer to [relinker.md](https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities/docs/relinker.md) + +## v0.1.0 - 2023-01-12 + +### Feature: + +* Add function cu_pkg_get_version +* Add macro cu_pkg_define_version +* Add cmake script to CMAKE_MODULE_PATH diff --git a/managed_components/espressif__cmake_utilities/CMakeLists.txt b/managed_components/espressif__cmake_utilities/CMakeLists.txt new file mode 100644 index 0000000..a96dced --- /dev/null +++ b/managed_components/espressif__cmake_utilities/CMakeLists.txt @@ -0,0 +1 @@ +idf_component_register() diff --git a/managed_components/espressif__cmake_utilities/Kconfig b/managed_components/espressif__cmake_utilities/Kconfig new file mode 100644 index 0000000..96747fd --- /dev/null +++ b/managed_components/espressif__cmake_utilities/Kconfig @@ -0,0 +1,65 @@ +menu "CMake Utilities" + + config CU_RELINKER_ENABLE + bool "Enable relinker" + default n + help + "Enable relinker to linker some IRAM functions to Flash" + + if CU_RELINKER_ENABLE + config CU_RELINKER_ENABLE_PRINT_ERROR_INFO_WHEN_MISSING_FUNCTION + bool "Print error information when missing function" + default y + help + "Enable this option to print error information instead of + throwing exception when missing function" + + config CU_RELINKER_ENABLE_CUSTOMIZED_CONFIGURATION_FILES + bool "Enable customized relinker configuration files" + default n + help + "Enable this option to use customized relinker configuration + files instead of default ones" + + if CU_RELINKER_ENABLE_CUSTOMIZED_CONFIGURATION_FILES + config CU_RELINKER_CUSTOMIZED_CONFIGURATION_FILES_PATH + string "Customized relinker configuration files path" + default "" + help + "Customized relinker configuration files path. This path is + evaluated relative to the project root directory." + endif + endif + + choice CU_DIAGNOSTICS_COLOR + prompt "Color in diagnostics" + default CU_DIAGNOSTICS_COLOR_ALWAYS + help + Use color in diagnostics. "never", "always", or "auto". If "always", GCC will output + with color defined in GCC_COLORS environment variable. If "never", only output plain + text. If "auto", only output with color when the standard error is a terminal and when + not executing in an emacs shell. + + config CU_DIAGNOSTICS_COLOR_NEVER + bool "never" + config CU_DIAGNOSTICS_COLOR_ALWAYS + bool "always" + config CU_DIAGNOSTICS_COLOR_AUTO + bool "auto" + endchoice + + config CU_GCC_LTO_ENABLE + bool "Enable GCC link time optimization(LTO)" + default n + help + "Enable this option, users can enable GCC link time optimization(LTO) + feature for target components or dependencies. + + config CU_GCC_STRING_1BYTE_ALIGN + bool "GCC string 1-byte align" + default n + help + "Enable this option, user can make string in designated components align + by 1-byte instead 1-word(4-byte), this can reduce unnecessary filled data + so that to reduce firmware size." +endmenu diff --git a/managed_components/espressif__cmake_utilities/README.md b/managed_components/espressif__cmake_utilities/README.md new file mode 100644 index 0000000..834ab73 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/README.md @@ -0,0 +1,31 @@ +# Cmake utilities + +[![Component Registry](https://components.espressif.com/components/espressif/cmake_utilities/badge.svg)](https://components.espressif.com/components/espressif/cmake_utilities) + +This component is aiming to provide some useful CMake utilities outside of ESP-IDF. + +## Use + +1. Add dependency of this component in your component or project's idf_component.yml. + + ```yml + dependencies: + espressif/cmake_utilities: "0.*" + ``` + +2. Include the CMake file you need in your component's CMakeLists.txt after `idf_component_register`, or in your project's CMakeLists.txt + + ```cmake + // Note: should remove .cmake postfix when using include(), otherwise the requested file will not found + // Note: should place this line after `idf_component_register` function + // only include the one you needed. + include(package_manager) + ``` + +3. Then you can use the corresponding CMake function which is provided by the CMake file. + +## Supported features + +1. [relinker](https://github.com/espressif/esp-iot-solution/blob/master/tools/cmake_utilities/docs/relinker.md) +2. [gen_compressed_ota](https://github.com/espressif/esp-iot-solution/blob/master/tools/cmake_utilities/docs/gen_compressed_ota.md) +3. [GCC Optimization](https://github.com/espressif/esp-iot-solution/blob/master/tools/cmake_utilities/docs/gcc.md) diff --git a/managed_components/espressif__cmake_utilities/cmake_utilities.cmake b/managed_components/espressif__cmake_utilities/cmake_utilities.cmake new file mode 100644 index 0000000..92ba9bd --- /dev/null +++ b/managed_components/espressif__cmake_utilities/cmake_utilities.cmake @@ -0,0 +1,7 @@ +# Include all cmake modules + +include(gcc) +include(gen_compressed_ota) +include(gen_single_bin) +include(package_manager) +include(relinker) diff --git a/managed_components/espressif__cmake_utilities/docs/gcc.md b/managed_components/espressif__cmake_utilities/docs/gcc.md new file mode 100644 index 0000000..a7817fe --- /dev/null +++ b/managed_components/espressif__cmake_utilities/docs/gcc.md @@ -0,0 +1,108 @@ +# Link Time Optimization(LTO) + +Link time optimization(LTO) improves the optimization effect of GCC, such as reducing binary size, increasing performance, and so on. For more details please refer to related [GCC documents](https://gcc.gnu.org/onlinedocs/gccint/LTO.html). + +## Use + +To use this feature, you need to include the required CMake file in your project's CMakeLists.txt after `project(XXXX)`. + +```cmake +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +project(XXXX) + +include(gcc) +``` + +The LTO feature is disabled by default. To use it, you should enable the option `CU_GCC_LTO_ENABLE` in menuconfig. Then specify target components or dependencies to be optimized by LTO after `include(gcc)` as follows: + +```cmake +include(gcc) + +cu_gcc_lto_set(COMPONENTS component_a component_b + DEPENDS dependence_a dependence_b) + +cu_gcc_string_1byte_align(COMPONENTS component_c component_d + DEPENDS dependence_c dependence_d) +``` + +Based on your requirement, set compiling optimization level in the option `COMPILER_OPTIMIZATION`. + +* Note + + ``` + 1. Reducing firmware size may decrease performance + 2. Increasing performance may increase firmware size + 3. Enable LTO cause compiling time cost increases a lot + 4. Enable LTO may increase task stack cost + 5. Enable string 1-byte align may decrease string process speed + ``` + +## Limitation + +At the linking stage, the LTO generates new function indexes instead of the file path as follows: + +- LTO + + ```txt + .text 0x00000000420016f4 0x6 /tmp/ccdjwYMH.ltrans51.ltrans.o + 0x00000000420016f4 app_main + ``` + +- Without LTO + + ```txt + .text.app_main 0x00000000420016f4 0x6 esp-idf/main/libmain.a(app_main.c.obj) + 0x00000000420016f4 app_main + ``` + +So tools used to relink functions between flash and IRAM can't affect these optimized components and dependencies again. It is recommended that users had better optimize application components and dependencies than kernel and hardware driver ones. + +## Example + +The example applies LTO in `light` of `esp-matter` because its application code is much larger. Add LTO configuration into project script `CMakeLists.txt` as follows: + +```cmake + +project(light) + +include(gcc) + +# Add +set(app_lto_components main chip esp_matter) +# Add +set(idf_lto_components lwip wpa_supplicant nvs_flash) +# Add +set(lto_depends mbedcrypto) + +# Add +cu_gcc_lto_set(COMPONENTS ${app_lto_components} ${idf_lto_components} + DEPENDS ${lto_depends}) +``` + +Configure `ESP32-C2` as the target platform, enable `CU_GCC_LTO_ENABLE` and `CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE`, set `COMPILER_OPTIMIZATION` to be `-Os`. +Increase the `main` task stack size to `5120` by option `ESP_MAIN_TASK_STACK_SIZE`. +Compile the project, and then you can see the firmware size decrease a lot: + +Option | Firmware size | Stask cost +|:-:|:-:|:-:| + -Os | 1,113,376 | 2508 + -Os + LTO | 1,020,640 | 4204 + +Then add `cu_gcc_string_1byte_align` after `cu_gcc_lto_set`: + +```cmake +# Add +cu_gcc_lto_set(COMPONENTS ${app_lto_components} ${idf_lto_components} + DEPENDS ${lto_depends}) + +cu_gcc_string_1byte_align(COMPONENTS ${app_lto_components} ${idf_lto_components} + DEPENDS ${lto_depends}) +``` + +Build the project and the firmware size is: + +Option | Firmware size | +|:-:|:-:| + -Os + LTO | 1,020,640 | + -Os + LTO + string 1-byte align | 1,018,340 | diff --git a/managed_components/espressif__cmake_utilities/docs/gen_compressed_ota.md b/managed_components/espressif__cmake_utilities/docs/gen_compressed_ota.md new file mode 100644 index 0000000..e3054b3 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/docs/gen_compressed_ota.md @@ -0,0 +1,41 @@ +# Gen Compressed OTA + +When using the compressed OTA, we need to generate the compressed app firmware. This document mainly describes how to generate the compressed app firmware. + +For more information about compressed OTA, refer to [bootloader_support_plus](https://github.com/espressif/esp-iot-solution/tree/master/components/bootloader_support_plus). + +## Use +In order to use this feature, you need to include the needed CMake file in your project's CMakeLists.txt after `project(XXXX)`. + +```cmake +project(XXXX) + +include(gen_compressed_ota) +``` + +Generate the compressed app firmware in an ESP-IDF "project" directory by running: + +```plaintext +idf.py gen_compressed_ota +``` + +This command will compile your project first, then it will generate the compressed app firmware. For example, run the command under the project `simple_ota_examples` folder. If there are no errors, the `custom_ota_binaries` folder will be created and contains the following files: + +```plaintext +simple_ota.bin.xz +simple_ota.bin.xz.packed +``` + +The file named `simple_ota.bin.xz.packed` is the actual compressed app binary file to be transferred. + +In addition, if [secure boot](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/security/secure-boot-v2.html) is enabled, the command will generate the signed compressed app binary file: + +```plaintext +simple_ota.bin.xz.packed.signed +``` + +you can also use the script [gen_custom_ota.py](https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities/scripts/gen_custom_ota.py) to compress the specified app: + +```plaintext +python3 gen_custom_ota.py -i simple_ota.bin +``` diff --git a/managed_components/espressif__cmake_utilities/docs/relinker.md b/managed_components/espressif__cmake_utilities/docs/relinker.md new file mode 100644 index 0000000..2b7be18 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/docs/relinker.md @@ -0,0 +1,66 @@ +# Relinker + +In ESP-IDF, some functions are put in SRAM when link stage, the reason is that some functions are critical, we need to put them in SRAM to speed up the program, or the functions will be executed when the cache is disabled. But actually, some functions can be put into Flash, here, we provide a script to let the user set the functions which are located in SRAM by default to put them into Flash, in order to save more SRAM which can be used as heap region later. This happens in the linker stage, so we call it as relinker. + +## Use + +In order to use this feature, you need to include the needed CMake file in your project's CMakeLists.txt after `project(XXXX)`. + +```cmake +project(XXXX) + +include(relinker) +``` + +The relinker feature is disabled by default, in order to use it, you need to enable the option `CU_RELINKER_ENABLE` in menuconfig. + +Here are the default configuration files in the folder `cmake_utilities/scripts/relinker/examples/esp32c2`, it's just used as a reference. If you would like to use your own configuration files, please enable option `CU_RELINKER_ENABLE_CUSTOMIZED_CONFIGURATION_FILES` and set the path of your configuration files as following, this path is evaluated relative to the project root directory: + +``` +[*] Enable customized relinker configuration files +(path of your configuration files) Customized relinker configuration files path +``` + +> Note: Currently only esp32c2 is supported. + +## Configuration Files + +You can refer to the files in the directory of `cmake_utilities/scripts/relinker/examples/esp32c2`: + +- library.csv +- object.csv +- function.csv + +For example, if you want to link function `__getreent` from SRAM to Flash, firstly you should add it to `function.csv` file as following: + +``` +libfreertos.a,tasks.c.obj,__getreent, +``` + +This means function `__getreent` is in object file `tasks.c.obj`, and object file `tasks.c.obj` is in library `libfreertos.a`. + +If function `__getreent` depends on the option `FREERTOS_PLACE_FUNCTIONS_INTO_FLASH` in menuconfig, then it should be: + +``` +libfreertos.a,tasks.c.obj,__getreent,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +``` + +This means when only `FREERTOS_PLACE_FUNCTIONS_INTO_FLASH` is enabled in menuconfig, function `__getreent` will be linked from SRAM to Flash. + +Next step you should add the path of the object file to `object.csv`: + +``` +libfreertos.a,tasks.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/tasks.c.obj +``` + +This means the object file `tasks.c.obj` is in library `libfreertos.a` and its location is `esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/tasks.c.obj` relative to directory of `build`. + +Next step you should add path of library to `library.csv`: + +``` +libfreertos.a,./esp-idf/freertos/libfreertos.a +``` + +This means library `libfreertos.a`'s location is `./esp-idf/freertos/libfreertos.a` relative to `build`. + +If above related data has exists in corresponding files, please don't add this repeatedly. \ No newline at end of file diff --git a/managed_components/espressif__cmake_utilities/gcc.cmake b/managed_components/espressif__cmake_utilities/gcc.cmake new file mode 100644 index 0000000..5fdd13e --- /dev/null +++ b/managed_components/espressif__cmake_utilities/gcc.cmake @@ -0,0 +1,84 @@ +if(CONFIG_CU_GCC_LTO_ENABLE) + # Enable cmake interprocedural optimization(IPO) support to check if GCC supports link time optimization(LTO) + cmake_policy(SET CMP0069 NEW) + include(CheckIPOSupported) + + # Compare to "ar" and "ranlib", "gcc-ar" and "gcc-ranlib" integrate GCC LTO plugin + set(CMAKE_AR ${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar) + set(CMAKE_RANLIB ${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib) + + macro(cu_gcc_lto_set) + check_ipo_supported(RESULT result) + if(result) + message(STATUS "GCC link time optimization(LTO) is enable") + + set(multi_value COMPONENTS DEPENDS) + cmake_parse_arguments(LTO "" "" "${multi_value}" ${ARGN}) + + # Use full format LTO object file + set(GCC_LTO_OBJECT_TYPE "-ffat-lto-objects") + # Set compression level 9(min:0, max:9) + set(GCC_LTO_COMPRESSION_LEVEL "-flto-compression-level=9") + # Set partition level max to removed used symbol + set(GCC_LTO_PARTITION_LEVEL "-flto-partition=max") + + # Set mode "auto" to increase compiling speed + set(GCC_LTO_COMPILE_OPTIONS "-flto=auto" + ${GCC_LTO_OBJECT_TYPE} + ${GCC_LTO_COMPRESSION_LEVEL}) + + # Enable GCC LTO and plugin when linking stage + set(GCC_LTO_LINK_OPTIONS "-flto" + "-fuse-linker-plugin" + ${GCC_LTO_OBJECT_TYPE} + ${GCC_LTO_PARTITION_LEVEL}) + + message(STATUS "GCC LTO for components: ${LTO_COMPONENTS}") + foreach(c ${LTO_COMPONENTS}) + idf_component_get_property(t ${c} COMPONENT_LIB) + target_compile_options(${t} PRIVATE ${GCC_LTO_COMPILE_OPTIONS}) + endforeach() + + message(STATUS "GCC LTO for dependencies: ${LTO_DEPENDS}") + foreach(d ${LTO_DEPENDS}) + target_compile_options(${d} PRIVATE ${GCC_LTO_COMPILE_OPTIONS}) + endforeach() + + if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "4.4") + target_link_libraries(${project_elf} PRIVATE ${GCC_LTO_LINK_OPTIONS}) + else() + target_link_libraries(${project_elf} ${GCC_LTO_LINK_OPTIONS}) + endif() + else() + message(FATAL_ERROR "GCC link time optimization(LTO) is not supported") + endif() + endmacro() +else() + macro(cu_gcc_lto_set) + message(STATUS "GCC link time optimization(LTO) is not enable") + endmacro() +endif() + +if(CONFIG_CU_GCC_STRING_1BYTE_ALIGN) + macro(cu_gcc_string_1byte_align) + message(STATUS "GCC string 1-byte align is enable") + + set(multi_value COMPONENTS DEPENDS) + cmake_parse_arguments(STR_ALIGN "" "" "${multi_value}" ${ARGN}) + + message(STATUS "GCC string 1-byte align for components: ${STR_ALIGN_COMPONENTS}") + foreach(c ${STR_ALIGN_COMPONENTS}) + idf_component_get_property(t ${c} COMPONENT_LIB) + target_compile_options(${t} PRIVATE "-malign-data=natural") + endforeach() + + message(STATUS "GCC string 1-byte align for dependencies: ${STR_ALIGN_DEPENDS}") + foreach(d ${STR_ALIGN_DEPENDS}) + target_compile_options(${d} PRIVATE "-malign-data=natural") + endforeach() + endmacro() +else() + macro(cu_gcc_string_1byte_align) + message(STATUS "GCC string 1-byte align is not enable") + endmacro() +endif() diff --git a/managed_components/espressif__cmake_utilities/gen_compressed_ota.cmake b/managed_components/espressif__cmake_utilities/gen_compressed_ota.cmake new file mode 100644 index 0000000..2bd41e5 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/gen_compressed_ota.cmake @@ -0,0 +1,18 @@ +if (NOT TARGET gen_compressed_ota) + add_custom_target(gen_compressed_ota) + + if (CONFIG_SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT OR CONFIG_SECURE_BOOT_V2_ENABLED) + set(COMPRESSED_OTA_BIN_SIGN_PARA --sign_key ${PROJECT_DIR}/${CONFIG_SECURE_BOOT_SIGNING_KEY}) + else() + set(COMPRESSED_OTA_BIN_SIGN_PARA ) + endif() + + set(GEN_COMPRESSED_BIN_CMD ${CMAKE_CURRENT_LIST_DIR}/scripts/gen_custom_ota.py ${COMPRESSED_OTA_BIN_SIGN_PARA} --add_app_header) + + add_custom_command(TARGET gen_compressed_ota + POST_BUILD + COMMAND ${PYTHON} ${GEN_COMPRESSED_BIN_CMD} + COMMENT "The gen compresssed bin cmd is: ${GEN_COMPRESSED_BIN_CMD}" + ) + add_dependencies(gen_compressed_ota gen_project_binary) +endif() \ No newline at end of file diff --git a/managed_components/espressif__cmake_utilities/gen_single_bin.cmake b/managed_components/espressif__cmake_utilities/gen_single_bin.cmake new file mode 100644 index 0000000..c13c665 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/gen_single_bin.cmake @@ -0,0 +1,27 @@ +# Extend command to idf.py + +# Generate single bin with name ${CMAKE_PROJECT_NAME}_merged.bin +if (NOT TARGET gen_single_bin) + add_custom_target( + gen_single_bin + COMMAND ${CMAKE_COMMAND} -E echo "Merge bin files to ${CMAKE_PROJECT_NAME}_merged.bin" + COMMAND ${ESPTOOLPY} --chip ${IDF_TARGET} merge_bin -o ${CMAKE_PROJECT_NAME}_merged.bin @flash_args + COMMAND ${CMAKE_COMMAND} -E echo "Merge bin done" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS gen_project_binary bootloader + VERBATIM USES_TERMINAL + ) +endif() + +# Flash bin ${CMAKE_PROJECT_NAME}_merged.bin to target chip +if (NOT TARGET flash_single_bin) + add_custom_target( + flash_single_bin + COMMAND ${CMAKE_COMMAND} -E echo "Flash merged bin ${CMAKE_PROJECT_NAME}_merged.bin to address 0x0" + COMMAND ${ESPTOOLPY} --chip ${IDF_TARGET} write_flash 0x0 ${CMAKE_PROJECT_NAME}_merged.bin + COMMAND ${CMAKE_COMMAND} -E echo "Flash merged bin done" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS gen_single_bin + VERBATIM USES_TERMINAL + ) +endif() diff --git a/managed_components/espressif__cmake_utilities/idf_component.yml b/managed_components/espressif__cmake_utilities/idf_component.yml new file mode 100644 index 0000000..e683f53 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + idf: + version: '>=4.1' +description: A collection of useful cmake utilities +issues: https://github.com/espressif/esp-iot-solution/issues +url: https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities +version: 0.5.3 diff --git a/managed_components/espressif__cmake_utilities/license.txt b/managed_components/espressif__cmake_utilities/license.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/license.txt @@ -0,0 +1,202 @@ + + 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 [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 + + 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. diff --git a/managed_components/espressif__cmake_utilities/package_manager.cmake b/managed_components/espressif__cmake_utilities/package_manager.cmake new file mode 100644 index 0000000..caef11b --- /dev/null +++ b/managed_components/espressif__cmake_utilities/package_manager.cmake @@ -0,0 +1,45 @@ +# cu_pkg_get_version +# +# @brief Get the package's version information, the package is installed by component manager. +# +# @param[in] pkg_path the package's path, normally it's ${CMAKE_CURRENT_LIST_DIR}. +# +# @param[out] ver_major the major version of the package +# @param[out] ver_minor the minor version of the package +# @param[out] ver_patch the patch version of the package +function(cu_pkg_get_version pkg_path ver_major ver_minor ver_patch) + set(yml_file "${pkg_path}/idf_component.yml") + if(EXISTS ${yml_file}) + file(READ ${yml_file} ver) + string(REGEX MATCH "(^|\n)version: \"?([0-9]+).([0-9]+).([0-9]+)\"?" _ ${ver}) + set(${ver_major} ${CMAKE_MATCH_2} PARENT_SCOPE) + set(${ver_minor} ${CMAKE_MATCH_3} PARENT_SCOPE) + set(${ver_patch} ${CMAKE_MATCH_4} PARENT_SCOPE) + else() + message(WARNING " ${yml_file} not exist") + endif() +endfunction() + +# cu_pkg_define_version +# +# @brief Add the package's version definitions using format ${NAME}_VER_MAJOR ${NAME}_VER_MINOR ${NAME}_VER_PATCH, +# the ${NAME} will be inferred from package path, and namespace like `espressif__` will be removed if the package download from esp-registry +# eg. espressif__usb_stream and usb_stream will generate same version definitions USB_STREAM_VER_MAJOR ... +# +# @param[in] pkg_path the package's path, normally it's ${CMAKE_CURRENT_LIST_DIR}. +# +macro(cu_pkg_define_version pkg_path) + cu_pkg_get_version(${pkg_path} ver_major ver_minor ver_patch) + get_filename_component(pkg_name ${pkg_path} NAME) + string(FIND ${pkg_name} "__" pkg_name_pos) + if(pkg_name_pos GREATER -1) + math(EXPR pkg_name_pos "${pkg_name_pos} + 2") + string(SUBSTRING ${pkg_name} ${pkg_name_pos} -1 pkg_name) + endif() + string(TOUPPER ${pkg_name} pkg_name) + string(REPLACE "-" "_" pkg_name ${pkg_name}) + message(STATUS "${pkg_name}: ${ver_major}.${ver_minor}.${ver_patch}") + list(LENGTH pkg_name_list len) + target_compile_options(${COMPONENT_LIB} PUBLIC + -D${pkg_name}_VER_MAJOR=${ver_major} -D${pkg_name}_VER_MINOR=${ver_minor} -D${pkg_name}_VER_PATCH=${ver_patch}) +endmacro() diff --git a/managed_components/espressif__cmake_utilities/project_include.cmake b/managed_components/espressif__cmake_utilities/project_include.cmake new file mode 100644 index 0000000..a5de922 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/project_include.cmake @@ -0,0 +1,9 @@ +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_MODULE_PATH}) + +if(CONFIG_CU_DIAGNOSTICS_COLOR_ALWAYS) + add_compile_options(-fdiagnostics-color=always) +elseif(CONFIG_CU_DIAGNOSTICS_COLOR_AUTO) + add_compile_options(-fdiagnostics-color=auto) +elseif(CONFIG_CU_DIAGNOSTICS_COLOR_NEVER) + add_compile_options(-fdiagnostics-color=never) +endif() diff --git a/managed_components/espressif__cmake_utilities/relinker.cmake b/managed_components/espressif__cmake_utilities/relinker.cmake new file mode 100644 index 0000000..10b9aaf --- /dev/null +++ b/managed_components/espressif__cmake_utilities/relinker.cmake @@ -0,0 +1,73 @@ +# @brief Link designated functions from SRAM to Flash to save SRAM +if(CONFIG_CU_RELINKER_ENABLE) + # project_elf variable is only in project.cmake + if(NOT TARGET customer_sections AND DEFINED project_elf) + message(STATUS "Relinker is enabled.") + if(CONFIG_IDF_TARGET_ESP32C2) + set(target "esp32c2") + else() + message(FATAL_ERROR "Other targets are not supported.") + endif() + + if(CONFIG_CU_RELINKER_ENABLE_CUSTOMIZED_CONFIGURATION_FILES) + idf_build_get_property(project_dir PROJECT_DIR) + get_filename_component(cfg_file_path "${CONFIG_CU_RELINKER_CUSTOMIZED_CONFIGURATION_FILES_PATH}" + ABSOLUTE BASE_DIR "${project_dir}") + + if(NOT EXISTS "${cfg_file_path}") + message(FATAL_ERROR "Relinker Configuration files path ${cfg_file_path} is not found.") + endif() + else() + set(cfg_file_path ${PROJECT_DIR}/relinker/${target}) + if(NOT EXISTS ${cfg_file_path}) + set(cfg_file_path ${CMAKE_CURRENT_LIST_DIR}/scripts/relinker/examples/${target}) + endif() + endif() + + message(STATUS "Relinker configuration files: ${cfg_file_path}") + + set(library_file "${cfg_file_path}/library.csv") + set(object_file "${cfg_file_path}/object.csv") + set(function_file "${cfg_file_path}/function.csv") + set(relinker_script "${CMAKE_CURRENT_LIST_DIR}/scripts/relinker/relinker.py") + + set(cmake_objdump "${CMAKE_OBJDUMP}") + set(link_path "${CMAKE_BINARY_DIR}/esp-idf/esp_system/ld") + set(link_src_file "${link_path}/sections.ld") + set(link_dst_file "${link_path}/customer_sections.ld") + + set(relinker_opts --input ${link_src_file} + --output ${link_dst_file} + --library ${library_file} + --object ${object_file} + --function ${function_file} + --sdkconfig ${sdkconfig} + --objdump ${cmake_objdump}) + + if(CONFIG_CU_RELINKER_ENABLE_PRINT_ERROR_INFO_WHEN_MISSING_FUNCTION) + list(APPEND relinker_opts --missing_function_info True) + endif() + + idf_build_get_property(link_depends __LINK_DEPENDS) + + add_custom_command(OUTPUT ${link_dst_file} + COMMAND ${python} -B ${relinker_script} + ${relinker_opts} + COMMAND ${CMAKE_COMMAND} -E copy + ${link_dst_file} + ${link_src_file} + COMMAND ${CMAKE_COMMAND} -E echo + /*relinker*/ >> + ${link_dst_file} + DEPENDS "${link_depends}" + "${library_file}" + "${object_file}" + "${function_file}" + VERBATIM) + + add_custom_target(customer_sections DEPENDS ${link_dst_file}) + add_dependencies(${project_elf} customer_sections) + endif() +else() + message(STATUS "Relinker isn't enabled.") +endif() diff --git a/managed_components/espressif__cmake_utilities/scripts/gen_custom_ota.py b/managed_components/espressif__cmake_utilities/scripts/gen_custom_ota.py new file mode 100755 index 0000000..00cffc6 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/scripts/gen_custom_ota.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python +# +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: Apache-2.0 + +import sys +import struct +import argparse +import binascii +import hashlib +import os +import subprocess +import shutil +import json +import lzma + +# src_file = 'hello-world.bin' +# compressed_file = 'hello-world.bin.xz' +# packed_compressed_file = 'hello-world.bin.xz.packed' +# siged_packed_compressed_file = 'hello-world.bin.xz.packed.signed' + +binary_compress_type = {'none': 0, 'xz':1} +header_version = {'v1': 1, 'v2': 2, 'v3': 3} + +SCRIPT_VERSION = '1.0.0' +ORIGIN_APP_IMAGE_HEADER_LEN = 288 # sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t). See esp_app_format.h +# At present, we calculate the checksum of the first 4KB data of the old app. +OLD_APP_CHECK_DATA_SIZE = 4096 + +# v1 compressed data header: +# Note: Encryption_type field is deprecated, the field is reserved for compatibility. +# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|--------------|------------| +# | | Magic | header | Compress | delta | Encryption | Reserved | Firmware | The length of | The MD5 of | The CRC32 for| compressed | +# | | number | version | type | type | type | | version | compressed data| compressed data| the header | data | +# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|--------------|------------| +# | Size | 4 bytes | 1 byte | 4 bits | 4 bits | 1 bytes | 1 bytes | 32 bytes | 4 bytes | 32 bytes | 4 bytes | | +# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|--------------|------------| +# | Data | String | | | | | | String | little-endian | byte string | little-endian| | +# | type | ended | | | | | | ended | integer | | integer | | +# | |with ‘\0’| | | | | | with ‘\0’| | | | Binary data| +# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|--------------|------------| +# | Data | “ESP” | 1 | 0/1 | 0/1 | | | | | | | | +# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|--------------|------------| + +# v2 compressed data header +# Note: Encryption_type field is deprecated, the field is reserved for compatibility. +# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|---------------|---------------|--------------|------------| +# | | Magic | header | Compress | delta | Encryption | Reserved | Firmware | The length of | The MD5 of | base app check| The CRC32 for | The CRC32 for| compressed | +# | | number | version | type | type | type | | version | compressed data| compressed data| data len | base app data | the header | data | +# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|---------------|---------------|--------------|------------| +# | Size | 4 bytes | 1 byte | 4 bits | 4 bits | 1 bytes | 1 bytes | 32 bytes | 4 bytes | 32 bytes | 4 bytes | 4 bytes | 4 bytes | | +# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|---------------|---------------|--------------|------------| +# | Data | String | | | | | | String | little-endian | byte string | little-endian | little-endian | little-endian| | +# | type | ended | | | | | | ended | integer | | integer | integer | integer | | +# | |with ‘\0’| | | | | | with ‘\0’| | | | | | Binary data| +# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|---------------|---------------|--------------|------------| +# | Data | “ESP” | 1 | 0/1 | 0/1 | | | | | | | | | | +# |------|---------|---------|----------|------------|------------|-----------|----------|----------------|----------------|---------------|---------------|--------------|------------| + +# v3 compressed data header: +# |------|---------|---------|----------|------------|-----------|----------------|----------------|--------------|------------| +# | | Magic | header | Compress | Reserved | Reserved | The length of | The MD5 of | The CRC32 for| compressed | +# | | number | version | type | | | compressed data| compressed data| the header | data | +# |------|---------|---------|----------|------------|-----------|----------------|----------------|--------------|------------| +# | Size | 4 bytes | 1 byte | 4 bits | 4 bits | 8 bytes | 4 bytes | 16 bytes | 4 bytes | | +# |------|---------|---------|----------|------------|-----------|----------------|----------------|--------------|------------| +# | Data | String | integer | | | | little-endian | byte string | little-endian| | +# | type | ended | | | | | integer | | integer | | +# | |with ‘\0’| | | | | | | | Binary data| +# |------|---------|---------|----------|------------|-----------|----------------|----------------|--------------|------------| +# | Data | “ESP” | 3 | 0/1 | | | | | | | +# |------|---------|---------|----------|------------|-----------|----------------|----------------|--------------|------------| + +def xz_compress(store_directory, in_file): + compressed_file = ''.join([in_file,'.xz']) + if(os.path.exists(compressed_file)): + os.remove(compressed_file) + + xz_compressor_filter = [ + {"id": lzma.FILTER_LZMA2, "preset": 6, "dict_size": 64*1024}, + ] + with open(in_file, 'rb') as src_f: + data = src_f.read() + with lzma.open(compressed_file, "wb", format=lzma.FORMAT_XZ, check=lzma.CHECK_CRC32, filters=xz_compressor_filter) as f: + f.write(data) + f.close() + + if not os.path.exists(os.path.join(store_directory, os.path.split(compressed_file)[1])): + shutil.copy(compressed_file, store_directory) + print('copy xz file done') + +def secure_boot_sign(sign_key, in_file, out_file): + ret = subprocess.call('espsecure.py sign_data --version 2 --keyfile {} --output {} {}'.format(sign_key, out_file, in_file), shell = True) + if ret: + raise Exception('sign failed') + +def get_app_name(): + with open('flasher_args.json') as f: + try: + flasher_args = json.load(f) + return flasher_args['app']['file'] + except Exception as e: + print(e) + + return '' + +def get_script_version(): + return SCRIPT_VERSION + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('-hv', '--header_ver', nargs='?', choices = ['v1', 'v2', 'v3'], + default='v3', help='the version of the packed file header [default:v3]') + parser.add_argument('-c', '--compress_type', nargs= '?', choices = ['none', 'xz'], + default='xz', help='compressed type [default:xz]') + parser.add_argument('-i', '--in_file', nargs = '?', + default='', help='the new app firmware') + parser.add_argument('--sign_key', nargs = '?', + default='', help='the sign key used for secure boot') + parser.add_argument('-fv', '--fw_ver', nargs='?', + default='', help='the version of the compressed data(this field is deprecated in v3)') + parser.add_argument('--add_app_header', action="store_true", help='add app header to use native esp_ota_* & esp_https_ota_* APIs') + parser.add_argument('-v', '--version', action='version', version=get_script_version(), help='the version of the script') + + args = parser.parse_args() + + compress_type = args.compress_type + firmware_ver = args.fw_ver + src_file = args.in_file + sign_key = args.sign_key + header_ver = args.header_ver + add_app_header = args.add_app_header + + if src_file == '': + origin_app_name = get_app_name() + if(origin_app_name == ''): + print('get origin app name fail') + return + + if os.path.exists(origin_app_name): + src_file = origin_app_name + else: + print('origin app.bin not found') + return + + print('src file is: {}'.format(src_file)) + + # rebuild the cpmpressed_app directroy + cpmoressed_app_directory = 'custom_ota_binaries' + if os.path.exists(cpmoressed_app_directory): + shutil.rmtree(cpmoressed_app_directory) + + os.mkdir(cpmoressed_app_directory) + print('The compressed file will store in {}'.format(cpmoressed_app_directory)) + + #step1: compress + if compress_type == 'xz': + xz_compress(cpmoressed_app_directory, os.path.abspath(src_file)) + + origin_app_name = os.path.split(src_file)[1] + + compressed_file_name = ''.join([origin_app_name, '.xz']) + compressed_file = os.path.join(cpmoressed_app_directory, compressed_file_name) + else: + compressed_file = ''.join(src_file) + + print('compressed file is: {}'.format(compressed_file)) + + #step2: packet the compressed image header + with open(src_file, 'rb') as s_f: + src_image_header = bytearray(s_f.read(ORIGIN_APP_IMAGE_HEADER_LEN)) + src_image_header[1] = 0x00 + + packed_file = ''.join([compressed_file,'.packed']) + with open(compressed_file, 'rb') as src_f: + data = src_f.read() + f_len = src_f.tell() + # magic number + bin_data = struct.pack('4s', b'ESP') + # header version + bin_data += struct.pack('B', header_version[header_ver]) + # Compress type + bin_data += struct.pack('B', binary_compress_type[compress_type]) + print('compressed type: {}'.format(binary_compress_type[compress_type])) + # in header v1/v2, there is a field "Encryption type", this field has been deprecated in v3 + if (header_version[header_ver] < 3): + bin_data += struct.pack('B', 0) + # Reserved + bin_data += struct.pack('?', 0) + # Firmware version + bin_data += struct.pack('32s', firmware_ver.encode()) + else: + # Reserved + bin_data += struct.pack('10s', b'0') + # The length of the compressed data + bin_data += struct.pack(' OPT_MIN_LEN and l[0] != '#': + mo = re.match( r'(.*)=(.*)', l, re.M|re.I) + if mo: + config[mo.group(1)]=mo.group(2).replace('"', '') + self.config = config + + def index(self, i): + return self.config[i] + + def check(self, options): + options = options.replace(' ', '') + if '&&' in options: + for i in options.split('&&'): + if i[0] == '!': + i = i[1:] + if i in self.config: + return False + else: + if i not in self.config: + return False + else: + i = options + if i[0] == '!': + i = i[1:] + if i in self.config: + return False + else: + if i not in self.config: + return False + return True + +class object_c: + def read_dump_info(self, pathes): + new_env = os.environ.copy() + new_env['LC_ALL'] = 'C' + dumps = list() + print('pathes:', pathes) + for path in pathes: + try: + dump = StringIO(subprocess.check_output([espidf_objdump, '-t', path], env=new_env).decode()) + dumps.append(dump.readlines()) + except subprocess.CalledProcessError as e: + raise RuntimeError('cmd:%s result:%s'%(e.cmd, e.returncode)) + return dumps + + def get_func_section(self, dumps, func): + for dump in dumps: + for l in dump: + if ' %s'%(func) in l and '*UND*' not in l: + m = re.match(r'(\S*)\s*([glw])\s*([F|O])\s*(\S*)\s*(\S*)\s*(\S*)\s*', l, re.M|re.I) + if m and m[6] == func: + return m[4].replace('.text.', '') + if espidf_missing_function_info: + print('%s failed to find section'%(func)) + return None + else: + raise RuntimeError('%s failed to find section'%(func)) + + def __init__(self, name, pathes, libray): + self.name = name + self.libray = libray + self.funcs = dict() + self.pathes = pathes + self.dumps = self.read_dump_info(pathes) + + def append(self, func): + section = self.get_func_section(self.dumps, func) + if section != None: + self.funcs[func] = section + + def functions(self): + nlist = list() + for i in self.funcs: + nlist.append(i) + return nlist + + def sections(self): + nlist = list() + for i in self.funcs: + nlist.append(self.funcs[i]) + return nlist + +class library_c: + def __init__(self, name, path): + self.name = name + self.path = path + self.objs = dict() + + def append(self, obj, path, func): + if obj not in self.objs: + self.objs[obj] = object_c(obj, path, self.name) + self.objs[obj].append(func) + +class libraries_c: + def __init__(self): + self.libs = dict() + + def append(self, lib, lib_path, obj, obj_path, func): + if lib not in self.libs: + self.libs[lib] = library_c(lib, lib_path) + self.libs[lib].append(obj, obj_path, func) + + def dump(self): + for libname in self.libs: + lib = self.libs[libname] + for objname in lib.objs: + obj = lib.objs[objname] + print('%s, %s, %s, %s'%(libname, objname, obj.path, obj.funcs)) + +class paths_c: + def __init__(self): + self.paths = dict() + + def append(self, lib, obj, path): + if '$IDF_PATH' in path: + path = path.replace('$IDF_PATH', os.environ['IDF_PATH']) + + if lib not in self.paths: + self.paths[lib] = dict() + if obj not in self.paths[lib]: + self.paths[lib][obj] = list() + self.paths[lib][obj].append(path) + + def index(self, lib, obj): + if lib not in self.paths: + return None + if '*' in self.paths[lib]: + obj = '*' + return self.paths[lib][obj] + +def generator(library_file, object_file, function_file, sdkconfig_file, missing_function_info, objdump='riscv32-esp-elf-objdump'): + global espidf_objdump, espidf_missing_function_info + espidf_objdump = objdump + espidf_missing_function_info = missing_function_info + + sdkconfig = sdkconfig_c(sdkconfig_file) + + lib_paths = paths_c() + for p in csv.DictReader(open(library_file, 'r')): + lib_paths.append(p['library'], '*', p['path']) + + obj_paths = paths_c() + for p in csv.DictReader(open(object_file, 'r')): + obj_paths.append(p['library'], p['object'], p['path']) + + libraries = libraries_c() + for d in csv.DictReader(open(function_file, 'r')): + if d['option'] and sdkconfig.check(d['option']) == False: + print('skip %s(%s)'%(d['function'], d['option'])) + continue + lib_path = lib_paths.index(d['library'], '*') + obj_path = obj_paths.index(d['library'], d['object']) + if not obj_path: + obj_path = lib_path + libraries.append(d['library'], lib_path[0], d['object'], obj_path, d['function']) + return libraries + +def main(): + argparser = argparse.ArgumentParser(description='Libraries management') + + argparser.add_argument( + '--library', '-l', + help='Library description file', + type=str) + + argparser.add_argument( + '--object', '-b', + help='Object description file', + type=str) + + argparser.add_argument( + '--function', '-f', + help='Function description file', + type=str) + + argparser.add_argument( + '--sdkconfig', '-s', + help='sdkconfig file', + type=str) + + args = argparser.parse_args() + + libraries = generator(args.library, args.object, args.function, args.sdkconfig) + # libraries.dump() + +if __name__ == '__main__': + main() diff --git a/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/function.csv b/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/function.csv new file mode 100644 index 0000000..73c089a --- /dev/null +++ b/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/function.csv @@ -0,0 +1,365 @@ +library,object,function,option +libble_app.a,ble_hw.c.o,r_ble_hw_resolv_list_get_cur_entry, +libble_app.a,ble_ll_adv.c.o,r_ble_ll_adv_set_sched, +libble_app.a,ble_ll_adv.c.o,r_ble_ll_adv_sync_pdu_make, +libble_app.a,ble_ll_adv.c.o,r_ble_ll_adv_sync_calculate, +libble_app.a,ble_ll_conn.c.o,r_ble_ll_conn_is_dev_connected, +libble_app.a,ble_ll_ctrl.c.o,r_ble_ll_ctrl_tx_done, +libble_app.a,ble_lll_adv.c.o,r_ble_lll_adv_aux_scannable_pdu_payload_len, +libble_app.a,ble_lll_adv.c.o,r_ble_lll_adv_halt, +libble_app.a,ble_lll_adv.c.o,r_ble_lll_adv_periodic_schedule_next, +libble_app.a,ble_lll_conn.c.o,r_ble_lll_conn_cth_flow_free_credit, +libble_app.a,ble_lll_conn.c.o,r_ble_lll_conn_update_encryption, +libble_app.a,ble_lll_conn.c.o,r_ble_lll_conn_set_slave_flow_control, +libble_app.a,ble_lll_conn.c.o,r_ble_lll_init_rx_pkt_isr, +libble_app.a,ble_lll_conn.c.o,r_ble_lll_conn_get_rx_mbuf, +libble_app.a,ble_lll_rfmgmt.c.o,r_ble_lll_rfmgmt_enable, +libble_app.a,ble_lll_rfmgmt.c.o,r_ble_lll_rfmgmt_timer_reschedule, +libble_app.a,ble_lll_rfmgmt.c.o,r_ble_lll_rfmgmt_timer_exp, +libble_app.a,ble_lll_scan.c.o,r_ble_lll_scan_targeta_is_matched, +libble_app.a,ble_lll_scan.c.o,r_ble_lll_scan_rx_isr_on_legacy, +libble_app.a,ble_lll_scan.c.o,r_ble_lll_scan_rx_isr_on_aux, +libble_app.a,ble_lll_scan.c.o,r_ble_lll_scan_process_rsp_in_isr, +libble_app.a,ble_lll_scan.c.o,r_ble_lll_scan_rx_pkt_isr, +libble_app.a,ble_lll_sched.c.o,r_ble_lll_sched_execute_check, +libble_app.a,ble_lll_sync.c.o,r_ble_lll_sync_event_start_cb, +libble_app.a,ble_phy.c.o,r_ble_phy_set_rxhdr, +libble_app.a,ble_phy.c.o,r_ble_phy_update_conn_sequence, +libble_app.a,ble_phy.c.o,r_ble_phy_set_sequence_mode, +libble_app.a,ble_phy.c.o,r_ble_phy_txpower_round, +libble_app.a,os_mempool.c.obj,r_os_memblock_put, +libbootloader_support.a,bootloader_flash.c.obj,bootloader_read_flash_id, +libbootloader_support.a,flash_encrypt.c.obj,esp_flash_encryption_enabled, +libbt.a,bt_osi_mem.c.obj,bt_osi_mem_calloc,CONFIG_BT_ENABLED +libbt.a,bt_osi_mem.c.obj,bt_osi_mem_malloc,CONFIG_BT_ENABLED +libbt.a,bt_osi_mem.c.obj,bt_osi_mem_malloc_internal,CONFIG_BT_ENABLED +libbt.a,bt_osi_mem.c.obj,bt_osi_mem_free,CONFIG_BT_ENABLED +libbt.a,bt.c.obj,esp_reset_rpa_moudle,CONFIG_BT_ENABLED +libbt.a,bt.c.obj,osi_assert_wrapper,CONFIG_BT_ENABLED +libbt.a,bt.c.obj,osi_random_wrapper,CONFIG_BT_ENABLED +libbt.a,nimble_port.c.obj,nimble_port_run,CONFIG_BT_NIMBLE_ENABLED +libbt.a,nimble_port.c.obj,nimble_port_get_dflt_eventq,CONFIG_BT_NIMBLE_ENABLED +libbt.a,npl_os_freertos.c.obj,os_callout_timer_cb,CONFIG_BT_ENABLED && !CONFIG_BT_NIMBLE_USE_ESP_TIMER +libbt.a,npl_os_freertos.c.obj,npl_freertos_event_run,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_stop,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_time_get,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_reset,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_is_active,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_get_ticks,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_remaining_ticks,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_time_delay,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_is_empty,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_mutex_pend,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_mutex_release,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_sem_init,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_sem_pend,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_sem_release,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_init,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_deinit,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_event_is_queued,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_event_get_arg,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_time_ms_to_ticks32,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_time_ticks_to_ms32,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_hw_is_in_critical,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_get_time_forever,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_os_started,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_get_current_task_id,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_event_reset,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_mem_reset,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_event_init,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_sem_get_count,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_remove,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_hw_exit_critical,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_mutex_init,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_hw_enter_critical,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_put,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_get,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_sem_deinit,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_mutex_deinit,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_deinit,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_init,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_event_deinit,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_time_ticks_to_ms,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_time_ms_to_ticks,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_callout_set_arg,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_event_set_arg,CONFIG_BT_ENABLED +libbt.a,npl_os_freertos.c.obj,npl_freertos_eventq_put,CONFIG_BT_ENABLED +libdriver.a,gpio.c.obj,gpio_intr_service, +libesp_app_format.a,esp_app_desc.c.obj,esp_app_get_elf_sha256, +libesp_hw_support.a,cpu.c.obj,esp_cpu_wait_for_intr, +libesp_hw_support.a,cpu.c.obj,esp_cpu_reset, +libesp_hw_support.a,esp_clk.c.obj,esp_clk_cpu_freq, +libesp_hw_support.a,esp_clk.c.obj,esp_clk_apb_freq, +libesp_hw_support.a,esp_clk.c.obj,esp_clk_xtal_freq, +libesp_hw_support.a,esp_memory_utils.c.obj,esp_ptr_byte_accessible, +libesp_hw_support.a,hw_random.c.obj,esp_random, +libesp_hw_support.a,intr_alloc.c.obj,shared_intr_isr, +libesp_hw_support.a,intr_alloc.c.obj,esp_intr_noniram_disable, +libesp_hw_support.a,intr_alloc.c.obj,esp_intr_noniram_enable, +libesp_hw_support.a,intr_alloc.c.obj,esp_intr_enable, +libesp_hw_support.a,intr_alloc.c.obj,esp_intr_disable, +libesp_hw_support.a,periph_ctrl.c.obj,wifi_bt_common_module_enable, +libesp_hw_support.a,periph_ctrl.c.obj,wifi_bt_common_module_disable, +libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_ctrl_read_reg, +libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_ctrl_read_reg_mask, +libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_ctrl_write_reg, +libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_ctrl_write_reg_mask, +libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_enter_critical, +libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_exit_critical, +libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_analog_cali_reg_read, +libesp_hw_support.a,regi2c_ctrl.c.obj,regi2c_analog_cali_reg_write, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_32k_enable_external, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_fast_src_set, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_slow_freq_get_hz, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_slow_src_get, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_slow_src_set, +libesp_hw_support.a,rtc_clk.c.obj,rtc_dig_clk8m_disable, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_set_config_fast, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_8m_enable, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_8md256_enabled, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_bbpll_configure, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_bbpll_enable, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_get_config, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_mhz_to_config, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_set_config, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_to_8m, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_to_pll_mhz, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_set_xtal, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_xtal_freq_get, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_cpu_freq_to_xtal, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_bbpll_disable, +libesp_hw_support.a,rtc_clk.c.obj,rtc_clk_apb_freq_update, +libesp_hw_support.a,rtc_clk.c.obj,clk_ll_rtc_slow_get_src,FALSE +libesp_hw_support.a,rtc_init.c.obj,rtc_vddsdio_set_config, +libesp_hw_support.a,rtc_module.c.obj,rtc_isr, +libesp_hw_support.a,rtc_module.c.obj,rtc_isr_noniram_disable, +libesp_hw_support.a,rtc_module.c.obj,rtc_isr_noniram_enable, +libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_pu, +libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_finish, +libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_get_default_config, +libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_init, +libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_low_init, +libesp_hw_support.a,rtc_sleep.c.obj,rtc_sleep_start, +libesp_hw_support.a,rtc_time.c.obj,rtc_clk_cal, +libesp_hw_support.a,rtc_time.c.obj,rtc_clk_cal_internal, +libesp_hw_support.a,rtc_time.c.obj,rtc_time_get, +libesp_hw_support.a,rtc_time.c.obj,rtc_time_us_to_slowclk, +libesp_hw_support.a,rtc_time.c.obj,rtc_time_slowclk_to_us, +libesp_hw_support.a,sleep_modes.c.obj,periph_ll_periph_enabled, +libesp_hw_support.a,sleep_modes.c.obj,flush_uarts, +libesp_hw_support.a,sleep_modes.c.obj,suspend_uarts, +libesp_hw_support.a,sleep_modes.c.obj,resume_uarts, +libesp_hw_support.a,sleep_modes.c.obj,esp_sleep_start, +libesp_hw_support.a,sleep_modes.c.obj,esp_deep_sleep_start, +libesp_hw_support.a,sleep_modes.c.obj,esp_light_sleep_inner, +libesp_phy.a,phy_init.c.obj,esp_phy_common_clock_enable, +libesp_phy.a,phy_init.c.obj,esp_phy_common_clock_disable, +libesp_phy.a,phy_init.c.obj,esp_wifi_bt_power_domain_on, +libesp_phy.a,phy_override.c.obj,phy_i2c_enter_critical, +libesp_phy.a,phy_override.c.obj,phy_i2c_exit_critical, +libesp_pm.a,pm_locks.c.obj,esp_pm_lock_acquire, +libesp_pm.a,pm_locks.c.obj,esp_pm_lock_release, +libesp_pm.a,pm_impl.c.obj,get_lowest_allowed_mode, +libesp_pm.a,pm_impl.c.obj,esp_pm_impl_switch_mode, +libesp_pm.a,pm_impl.c.obj,on_freq_update, +libesp_pm.a,pm_impl.c.obj,vApplicationSleep,CONFIG_FREERTOS_USE_TICKLESS_IDLE +libesp_pm.a,pm_impl.c.obj,do_switch, +libesp_ringbuf.a,ringbuf.c.obj,prvCheckItemAvail, +libesp_ringbuf.a,ringbuf.c.obj,prvGetFreeSize, +libesp_ringbuf.a,ringbuf.c.obj,prvReceiveGenericFromISR, +libesp_ringbuf.a,ringbuf.c.obj,xRingbufferGetMaxItemSize, +libesp_rom.a,esp_rom_systimer.c.obj,systimer_hal_init, +libesp_rom.a,esp_rom_systimer.c.obj,systimer_hal_set_alarm_period, +libesp_rom.a,esp_rom_systimer.c.obj,systimer_hal_set_alarm_target, +libesp_rom.a,esp_rom_systimer.c.obj,systimer_hal_set_tick_rate_ops, +libesp_rom.a,esp_rom_uart.c.obj,esp_rom_uart_set_clock_baudrate, +libesp_system.a,brownout.c.obj,rtc_brownout_isr_handler, +libesp_system.a,cache_err_int.c.obj,esp_cache_err_get_cpuid, +libesp_system.a,cpu_start.c.obj,call_start_cpu0, +libesp_system.a,crosscore_int.c.obj,esp_crosscore_int_send, +libesp_system.a,crosscore_int.c.obj,esp_crosscore_int_send_yield, +libesp_system.a,esp_system.c.obj,esp_restart, +libesp_system.a,esp_system.c.obj,esp_system_abort, +libesp_system.a,reset_reason.c.obj,esp_reset_reason_set_hint, +libesp_system.a,reset_reason.c.obj,esp_reset_reason_get_hint, +libesp_system.a,ubsan.c.obj,__ubsan_include, +libesp_timer.a,esp_timer.c.obj,esp_timer_get_next_alarm_for_wake_up, +libesp_timer.a,esp_timer.c.obj,timer_list_unlock,!CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD +libesp_timer.a,esp_timer.c.obj,timer_list_lock,!CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD +libesp_timer.a,esp_timer.c.obj,timer_armed, +libesp_timer.a,esp_timer.c.obj,timer_remove, +libesp_timer.a,esp_timer.c.obj,timer_insert,!CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD +libesp_timer.a,esp_timer.c.obj,esp_timer_start_once, +libesp_timer.a,esp_timer.c.obj,esp_timer_start_periodic, +libesp_timer.a,esp_timer.c.obj,esp_timer_stop, +libesp_timer.a,esp_timer.c.obj,esp_timer_get_expiry_time, +libesp_timer.a,esp_timer_impl_systimer.c.obj,esp_timer_impl_get_time,!CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD +libesp_timer.a,esp_timer_impl_systimer.c.obj,esp_timer_impl_set_alarm_id,!CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD +libesp_timer.a,esp_timer_impl_systimer.c.obj,esp_timer_impl_update_apb_freq, +libesp_timer.a,esp_timer_impl_systimer.c.obj,esp_timer_impl_get_min_period_us, +libesp_timer.a,ets_timer_legacy.c.obj,timer_initialized, +libesp_timer.a,ets_timer_legacy.c.obj,ets_timer_arm_us, +libesp_timer.a,ets_timer_legacy.c.obj,ets_timer_arm, +libesp_timer.a,ets_timer_legacy.c.obj,ets_timer_disarm, +libesp_timer.a,system_time.c.obj,esp_system_get_time, +libesp_wifi.a,esp_adapter.c.obj,semphr_take_from_isr_wrapper, +libesp_wifi.a,esp_adapter.c.obj,wifi_realloc, +libesp_wifi.a,esp_adapter.c.obj,coex_event_duration_get_wrapper, +libesp_wifi.a,esp_adapter.c.obj,coex_schm_interval_set_wrapper, +libesp_wifi.a,esp_adapter.c.obj,esp_empty_wrapper, +libesp_wifi.a,esp_adapter.c.obj,wifi_calloc, +libesp_wifi.a,esp_adapter.c.obj,wifi_zalloc_wrapper, +libesp_wifi.a,esp_adapter.c.obj,env_is_chip_wrapper, +libesp_wifi.a,esp_adapter.c.obj,is_from_isr_wrapper, +libesp_wifi.a,esp_adapter.c.obj,semphr_give_from_isr_wrapper, +libesp_wifi.a,esp_adapter.c.obj,mutex_lock_wrapper, +libesp_wifi.a,esp_adapter.c.obj,mutex_unlock_wrapper, +libesp_wifi.a,esp_adapter.c.obj,task_ms_to_tick_wrapper, +libesp_wifi.a,esp_adapter.c.obj,wifi_apb80m_request_wrapper, +libesp_wifi.a,esp_adapter.c.obj,wifi_apb80m_release_wrapper, +libesp_wifi.a,esp_adapter.c.obj,timer_arm_wrapper, +libesp_wifi.a,esp_adapter.c.obj,wifi_malloc, +libesp_wifi.a,esp_adapter.c.obj,timer_disarm_wrapper, +libesp_wifi.a,esp_adapter.c.obj,timer_arm_us_wrapper, +libesp_wifi.a,esp_adapter.c.obj,wifi_rtc_enable_iso_wrapper, +libesp_wifi.a,esp_adapter.c.obj,wifi_rtc_disable_iso_wrapper, +libesp_wifi.a,esp_adapter.c.obj,malloc_internal_wrapper, +libesp_wifi.a,esp_adapter.c.obj,realloc_internal_wrapper, +libesp_wifi.a,esp_adapter.c.obj,calloc_internal_wrapper, +libesp_wifi.a,esp_adapter.c.obj,zalloc_internal_wrapper, +libesp_wifi.a,esp_adapter.c.obj,coex_status_get_wrapper, +libesp_wifi.a,esp_adapter.c.obj,coex_wifi_release_wrapper, +libfreertos.a,list.c.obj,uxListRemove,FALSE +libfreertos.a,list.c.obj,vListInitialise,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,list.c.obj,vListInitialiseItem,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,list.c.obj,vListInsert,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,list.c.obj,vListInsertEnd,FALSE +libfreertos.a,port.c.obj,vApplicationStackOverflowHook,FALSE +libfreertos.a,port.c.obj,vPortYieldOtherCore,FALSE +libfreertos.a,port.c.obj,vPortYield, +libfreertos.a,port_common.c.obj,xPortcheckValidStackMem, +libfreertos.a,port_common.c.obj,vApplicationGetTimerTaskMemory, +libfreertos.a,port_common.c.obj,esp_startup_start_app_common, +libfreertos.a,port_common.c.obj,xPortCheckValidTCBMem, +libfreertos.a,port_common.c.obj,vApplicationGetIdleTaskMemory, +libfreertos.a,port_systick.c.obj,vPortSetupTimer, +libfreertos.a,port_systick.c.obj,xPortSysTickHandler,FALSE +libfreertos.a,queue.c.obj,prvCopyDataFromQueue, +libfreertos.a,queue.c.obj,prvGetDisinheritPriorityAfterTimeout, +libfreertos.a,queue.c.obj,prvIsQueueEmpty, +libfreertos.a,queue.c.obj,prvNotifyQueueSetContainer, +libfreertos.a,queue.c.obj,xQueueReceive, +libfreertos.a,queue.c.obj,prvUnlockQueue, +libfreertos.a,queue.c.obj,xQueueSemaphoreTake, +libfreertos.a,queue.c.obj,xQueueReceiveFromISR, +libfreertos.a,queue.c.obj,uxQueueMessagesWaitingFromISR, +libfreertos.a,queue.c.obj,xQueueIsQueueEmptyFromISR, +libfreertos.a,queue.c.obj,xQueueGiveFromISR, +libfreertos.a,tasks.c.obj,__getreent,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,pcTaskGetName,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,prvAddCurrentTaskToDelayedList,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,prvDeleteTLS,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,pvTaskIncrementMutexHeldCount,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,taskSelectHighestPriorityTaskSMP,FALSE +libfreertos.a,tasks.c.obj,taskYIELD_OTHER_CORE,FALSE +libfreertos.a,tasks.c.obj,vTaskGetSnapshot,CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH +libfreertos.a,tasks.c.obj,vTaskInternalSetTimeOutState,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,vTaskPlaceOnEventList,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,vTaskPlaceOnEventListRestricted,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,vTaskPlaceOnUnorderedEventList,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,vTaskPriorityDisinheritAfterTimeout,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,vTaskReleaseEventListLock,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,vTaskTakeEventListLock,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,xTaskCheckForTimeOut,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,xTaskGetCurrentTaskHandle,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,xTaskGetSchedulerState,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,xTaskGetTickCount,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,xTaskPriorityDisinherit,FALSE +libfreertos.a,tasks.c.obj,xTaskPriorityInherit,CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH +libfreertos.a,tasks.c.obj,prvGetExpectedIdleTime,FALSE +libfreertos.a,tasks.c.obj,vTaskStepTick,FALSE +libhal.a,brownout_hal.c.obj,brownout_hal_intr_clear, +libhal.a,efuse_hal.c.obj,efuse_hal_chip_revision, +libhal.a,efuse_hal.c.obj,efuse_hal_get_major_chip_version, +libhal.a,efuse_hal.c.obj,efuse_hal_get_minor_chip_version, +libheap.a,heap_caps.c.obj,dram_alloc_to_iram_addr, +libheap.a,heap_caps.c.obj,heap_caps_free, +libheap.a,heap_caps.c.obj,heap_caps_realloc_base, +libheap.a,heap_caps.c.obj,heap_caps_realloc, +libheap.a,heap_caps.c.obj,heap_caps_calloc_base, +libheap.a,heap_caps.c.obj,heap_caps_calloc, +libheap.a,heap_caps.c.obj,heap_caps_malloc_base, +libheap.a,heap_caps.c.obj,heap_caps_malloc, +libheap.a,heap_caps.c.obj,heap_caps_malloc_default, +libheap.a,heap_caps.c.obj,heap_caps_realloc_default, +libheap.a,heap_caps.c.obj,find_containing_heap, +libheap.a,multi_heap.c.obj,_multi_heap_lock, +libheap.a,multi_heap.c.obj,multi_heap_in_rom_init, +liblog.a,log_freertos.c.obj,esp_log_timestamp, +liblog.a,log_freertos.c.obj,esp_log_impl_lock, +liblog.a,log_freertos.c.obj,esp_log_impl_unlock, +liblog.a,log_freertos.c.obj,esp_log_impl_lock_timeout, +liblog.a,log_freertos.c.obj,esp_log_early_timestamp, +liblog.a,log.c.obj,esp_log_write, +libmbedcrypto.a,esp_mem.c.obj,esp_mbedtls_mem_calloc,!CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC +libmbedcrypto.a,esp_mem.c.obj,esp_mbedtls_mem_free,!CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC +libnewlib.a,assert.c.obj,__assert_func, +libnewlib.a,assert.c.obj,newlib_include_assert_impl, +libnewlib.a,heap.c.obj,_calloc_r, +libnewlib.a,heap.c.obj,_free_r, +libnewlib.a,heap.c.obj,_malloc_r, +libnewlib.a,heap.c.obj,_realloc_r, +libnewlib.a,heap.c.obj,calloc, +libnewlib.a,heap.c.obj,cfree, +libnewlib.a,heap.c.obj,free, +libnewlib.a,heap.c.obj,malloc, +libnewlib.a,heap.c.obj,newlib_include_heap_impl, +libnewlib.a,heap.c.obj,realloc, +libnewlib.a,locks.c.obj,_lock_try_acquire_recursive, +libnewlib.a,locks.c.obj,lock_release_generic, +libnewlib.a,locks.c.obj,_lock_release, +libnewlib.a,locks.c.obj,_lock_release_recursive, +libnewlib.a,locks.c.obj,__retarget_lock_init, +libnewlib.a,locks.c.obj,__retarget_lock_init_recursive, +libnewlib.a,locks.c.obj,__retarget_lock_close, +libnewlib.a,locks.c.obj,__retarget_lock_close_recursive, +libnewlib.a,locks.c.obj,check_lock_nonzero, +libnewlib.a,locks.c.obj,__retarget_lock_acquire, +libnewlib.a,locks.c.obj,lock_init_generic, +libnewlib.a,locks.c.obj,__retarget_lock_acquire_recursive, +libnewlib.a,locks.c.obj,__retarget_lock_try_acquire, +libnewlib.a,locks.c.obj,__retarget_lock_try_acquire_recursive, +libnewlib.a,locks.c.obj,__retarget_lock_release, +libnewlib.a,locks.c.obj,__retarget_lock_release_recursive, +libnewlib.a,locks.c.obj,_lock_close, +libnewlib.a,locks.c.obj,lock_acquire_generic, +libnewlib.a,locks.c.obj,_lock_acquire, +libnewlib.a,locks.c.obj,_lock_acquire_recursive, +libnewlib.a,locks.c.obj,_lock_try_acquire, +libnewlib.a,reent_init.c.obj,esp_reent_init, +libnewlib.a,time.c.obj,_times_r, +libnewlib.a,time.c.obj,_gettimeofday_r, +libpp.a,pp_debug.o,wifi_gpio_debug, +libpthread.a,pthread.c.obj,pthread_mutex_lock_internal, +libpthread.a,pthread.c.obj,pthread_mutex_lock, +libpthread.a,pthread.c.obj,pthread_mutex_unlock, +libriscv.a,interrupt.c.obj,intr_handler_get, +libriscv.a,interrupt.c.obj,intr_handler_set, +libriscv.a,interrupt.c.obj,intr_matrix_route, +libspi_flash.a,flash_brownout_hook.c.obj,spi_flash_needs_reset_check,FALSE +libspi_flash.a,flash_brownout_hook.c.obj,spi_flash_set_erasing_flag,FALSE +libspi_flash.a,flash_ops.c.obj,spi_flash_guard_set,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,flash_ops.c.obj,spi_flash_malloc_internal,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,flash_ops.c.obj,spi_flash_rom_impl_init,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,flash_ops.c.obj,esp_mspi_pin_init,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,flash_ops.c.obj,spi_flash_init_chip_state,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,spi_flash_os_func_app.c.obj,delay_us,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,spi_flash_os_func_app.c.obj,get_buffer_malloc,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,spi_flash_os_func_app.c.obj,release_buffer_malloc,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,spi_flash_os_func_app.c.obj,main_flash_region_protected,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,spi_flash_os_func_app.c.obj,main_flash_op_status,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,spi_flash_os_func_app.c.obj,spi1_flash_os_check_yield,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,spi_flash_os_func_app.c.obj,spi1_flash_os_yield,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,spi_flash_os_func_noos.c.obj,start,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,spi_flash_os_func_noos.c.obj,end,CONFIG_SPI_FLASH_ROM_IMPL +libspi_flash.a,spi_flash_os_func_noos.c.obj,delay_us,CONFIG_SPI_FLASH_ROM_IMPL diff --git a/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/library.csv b/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/library.csv new file mode 100644 index 0000000..3fd9e4a --- /dev/null +++ b/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/library.csv @@ -0,0 +1,24 @@ +library,path +libble_app.a,$IDF_PATH/components/bt/controller/lib_esp32c2/esp32c2-bt-lib/libble_app.a +libpp.a,$IDF_PATH/components/esp_wifi/lib/esp32c2/libpp.a +libbootloader_support.a,./esp-idf/bootloader_support/libbootloader_support.a +libbt.a,./esp-idf/bt/libbt.a +libdriver.a,./esp-idf/driver/libdriver.a +libesp_app_format.a,./esp-idf/esp_app_format/libesp_app_format.a +libesp_hw_support.a,./esp-idf/esp_hw_support/libesp_hw_support.a +libesp_phy.a,./esp-idf/esp_phy/libesp_phy.a +libesp_pm.a,./esp-idf/esp_pm/libesp_pm.a +libesp_ringbuf.a,./esp-idf/esp_ringbuf/libesp_ringbuf.a +libesp_rom.a,./esp-idf/esp_rom/libesp_rom.a +libesp_system.a,./esp-idf/esp_system/libesp_system.a +libesp_timer.a,./esp-idf/esp_timer/libesp_timer.a +libesp_wifi.a,./esp-idf/esp_wifi/libesp_wifi.a +libfreertos.a,./esp-idf/freertos/libfreertos.a +libhal.a,./esp-idf/hal/libhal.a +libheap.a,./esp-idf/heap/libheap.a +liblog.a,./esp-idf/log/liblog.a +libmbedcrypto.a,./esp-idf/mbedtls/mbedtls/library/libmbedcrypto.a +libnewlib.a,./esp-idf/newlib/libnewlib.a +libpthread.a,./esp-idf/pthread/libpthread.a +libriscv.a,./esp-idf/riscv/libriscv.a +libspi_flash.a,./esp-idf/spi_flash/libspi_flash.a diff --git a/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/object.csv b/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/object.csv new file mode 100644 index 0000000..a897d84 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/object.csv @@ -0,0 +1,66 @@ +library,object,path +libbootloader_support.a,bootloader_flash.c.obj,esp-idf/bootloader_support/CMakeFiles/__idf_bootloader_support.dir/bootloader_flash/src/bootloader_flash.c.obj +libbootloader_support.a,flash_encrypt.c.obj,esp-idf/bootloader_support/CMakeFiles/__idf_bootloader_support.dir/src/flash_encrypt.c.obj +libbt.a,bt_osi_mem.c.obj,esp-idf/bt/CMakeFiles/__idf_bt.dir/porting/mem/bt_osi_mem.c.obj +libbt.a,bt.c.obj,esp-idf/bt/CMakeFiles/__idf_bt.dir/controller/esp32c2/bt.c.obj +libbt.a,npl_os_freertos.c.obj,esp-idf/bt/CMakeFiles/__idf_bt.dir/porting/npl/freertos/src/npl_os_freertos.c.obj +libbt.a,nimble_port.c.obj,esp-idf/bt/CMakeFiles/__idf_bt.dir/host/nimble/nimble/porting/nimble/src/nimble_port.c.obj +libdriver.a,gpio.c.obj,esp-idf/driver/CMakeFiles/__idf_driver.dir/gpio/gpio.c.obj +libesp_app_format.a,esp_app_desc.c.obj,esp-idf/esp_app_format/CMakeFiles/__idf_esp_app_format.dir/esp_app_desc.c.obj +libesp_hw_support.a,cpu.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/cpu.c.obj +libesp_hw_support.a,esp_clk.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/esp_clk.c.obj +libesp_hw_support.a,esp_memory_utils.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/esp_memory_utils.c.obj +libesp_hw_support.a,hw_random.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/hw_random.c.obj +libesp_hw_support.a,intr_alloc.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/intr_alloc.c.obj +libesp_hw_support.a,periph_ctrl.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/periph_ctrl.c.obj +libesp_hw_support.a,regi2c_ctrl.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/regi2c_ctrl.c.obj +libesp_hw_support.a,rtc_clk.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/port/esp32c2/rtc_clk.c.obj +libesp_hw_support.a,rtc_init.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/port/esp32c2/rtc_init.c.obj +libesp_hw_support.a,rtc_module.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/rtc_module.c.obj +libesp_hw_support.a,rtc_sleep.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/port/esp32c2/rtc_sleep.c.obj +libesp_hw_support.a,rtc_time.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/port/esp32c2/rtc_time.c.obj +libesp_hw_support.a,sleep_modes.c.obj,esp-idf/esp_hw_support/CMakeFiles/__idf_esp_hw_support.dir/sleep_modes.c.obj +libesp_phy.a,phy_init.c.obj,esp-idf/esp_phy/CMakeFiles/__idf_esp_phy.dir/src/phy_init.c.obj +libesp_phy.a,phy_override.c.obj,esp-idf/esp_phy/CMakeFiles/__idf_esp_phy.dir/src/phy_override.c.obj +libesp_pm.a,pm_locks.c.obj,esp-idf/esp_pm/CMakeFiles/__idf_esp_pm.dir/pm_locks.c.obj +libesp_pm.a,pm_impl.c.obj,esp-idf/esp_pm/CMakeFiles/__idf_esp_pm.dir/pm_impl.c.obj +libesp_ringbuf.a,ringbuf.c.obj,esp-idf/esp_ringbuf/CMakeFiles/__idf_esp_ringbuf.dir/ringbuf.c.obj +libesp_rom.a,esp_rom_systimer.c.obj,esp-idf/esp_rom/CMakeFiles/__idf_esp_rom.dir/patches/esp_rom_systimer.c.obj +libesp_rom.a,esp_rom_uart.c.obj,esp-idf/esp_rom/CMakeFiles/__idf_esp_rom.dir/patches/esp_rom_uart.c.obj +libesp_system.a,brownout.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/brownout.c.obj +libesp_system.a,cache_err_int.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/soc/esp32c2/cache_err_int.c.obj +libesp_system.a,cpu_start.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/cpu_start.c.obj +libesp_system.a,crosscore_int.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/crosscore_int.c.obj +libesp_system.a,esp_system.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/esp_system.c.obj +libesp_system.a,reset_reason.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/soc/esp32c2/reset_reason.c.obj +libesp_system.a,ubsan.c.obj,esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/ubsan.c.obj +libesp_timer.a,esp_timer.c.obj,esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/esp_timer.c.obj +libesp_timer.a,esp_timer_impl_systimer.c.obj,esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/esp_timer_impl_systimer.c.obj +libesp_timer.a,ets_timer_legacy.c.obj,esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/ets_timer_legacy.c.obj +libesp_timer.a,system_time.c.obj,esp-idf/esp_timer/CMakeFiles/__idf_esp_timer.dir/src/system_time.c.obj +libesp_wifi.a,esp_adapter.c.obj,esp-idf/esp_wifi/CMakeFiles/__idf_esp_wifi.dir/esp32c2/esp_adapter.c.obj +libfreertos.a,list.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/list.c.obj +libfreertos.a,port.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/portable/riscv/port.c.obj +libfreertos.a,port_common.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/portable/port_common.c.obj +libfreertos.a,port_systick.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/portable/port_systick.c.obj +libfreertos.a,queue.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/queue.c.obj +libfreertos.a,tasks.c.obj,esp-idf/freertos/CMakeFiles/__idf_freertos.dir/FreeRTOS-Kernel/tasks.c.obj +libhal.a,brownout_hal.c.obj,esp-idf/hal/CMakeFiles/__idf_hal.dir/esp32c2/brownout_hal.c.obj +libhal.a,efuse_hal.c.obj,esp-idf/hal/CMakeFiles/__idf_hal.dir/efuse_hal.c.obj +libhal.a,efuse_hal.c.obj,esp-idf/hal/CMakeFiles/__idf_hal.dir/esp32c2/efuse_hal.c.obj +libheap.a,heap_caps.c.obj,esp-idf/heap/CMakeFiles/__idf_heap.dir/heap_caps.c.obj +libheap.a,multi_heap.c.obj,./esp-idf/heap/CMakeFiles/__idf_heap.dir/multi_heap.c.obj +liblog.a,log_freertos.c.obj,esp-idf/log/CMakeFiles/__idf_log.dir/log_freertos.c.obj +liblog.a,log.c.obj,esp-idf/log/CMakeFiles/__idf_log.dir/log.c.obj +libmbedcrypto.a,esp_mem.c.obj,esp-idf/mbedtls/mbedtls/library/CMakeFiles/mbedcrypto.dir/$IDF_PATH/components/mbedtls/port/esp_mem.c.obj +libnewlib.a,assert.c.obj,esp-idf/newlib/CMakeFiles/__idf_newlib.dir/assert.c.obj +libnewlib.a,heap.c.obj,esp-idf/newlib/CMakeFiles/__idf_newlib.dir/heap.c.obj +libnewlib.a,locks.c.obj,esp-idf/newlib/CMakeFiles/__idf_newlib.dir/locks.c.obj +libnewlib.a,reent_init.c.obj,esp-idf/newlib/CMakeFiles/__idf_newlib.dir/reent_init.c.obj +libnewlib.a,time.c.obj,esp-idf/newlib/CMakeFiles/__idf_newlib.dir/time.c.obj +libpthread.a,pthread.c.obj,esp-idf/pthread/CMakeFiles/__idf_pthread.dir/pthread.c.obj +libriscv.a,interrupt.c.obj,esp-idf/riscv/CMakeFiles/__idf_riscv.dir/interrupt.c.obj +libspi_flash.a,flash_brownout_hook.c.obj,esp-idf/spi_flash/CMakeFiles/__idf_spi_flash.dir/flash_brownout_hook.c.obj +libspi_flash.a,flash_ops.c.obj,esp-idf/spi_flash/CMakeFiles/__idf_spi_flash.dir/flash_ops.c.obj +libspi_flash.a,spi_flash_os_func_app.c.obj,esp-idf/spi_flash/CMakeFiles/__idf_spi_flash.dir/spi_flash_os_func_app.c.obj +libspi_flash.a,spi_flash_os_func_noos.c.obj,esp-idf/spi_flash/CMakeFiles/__idf_spi_flash.dir/spi_flash_os_func_noos.c.obj diff --git a/managed_components/espressif__cmake_utilities/scripts/relinker/relinker.py b/managed_components/espressif__cmake_utilities/scripts/relinker/relinker.py new file mode 100755 index 0000000..151b877 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/scripts/relinker/relinker.py @@ -0,0 +1,311 @@ +#!/usr/bin/env python3 +# +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + + +import logging +import argparse +import csv +import os +import subprocess +import sys +import re +from io import StringIO +import configuration + +sys.path.append(os.environ['IDF_PATH'] + '/tools/ldgen') +sys.path.append(os.environ['IDF_PATH'] + '/tools/ldgen/ldgen') +from entity import EntityDB + +espidf_objdump = None + +def lib_secs(lib, file, lib_path): + new_env = os.environ.copy() + new_env['LC_ALL'] = 'C' + dump = StringIO(subprocess.check_output([espidf_objdump, '-h', lib_path], env=new_env).decode()) + dump.name = lib + + sections_infos = EntityDB() + sections_infos.add_sections_info(dump) + + secs = sections_infos.get_sections(lib, file.split('.')[0] + '.c') + if len(secs) == 0: + secs = sections_infos.get_sections(lib, file.split('.')[0]) + if len(secs) == 0: + raise ValueError('Failed to get sections from lib %s'%(lib_path)) + + return secs + +def filter_secs(secs_a, secs_b): + new_secs = list() + for s_a in secs_a: + for s_b in secs_b: + if s_b in s_a: + new_secs.append(s_a) + return new_secs + +def strip_secs(secs_a, secs_b): + secs = list(set(secs_a) - set(secs_b)) + secs.sort() + return secs + +def func2sect(func): + if ' ' in func: + func_l = func.split(' ') + else: + func_l = list() + func_l.append(func) + + secs = list() + for l in func_l: + if '.iram1.' not in l: + secs.append('.literal.%s'%(l,)) + secs.append('.text.%s'%(l, )) + else: + secs.append(l) + return secs + +class filter_c: + def __init__(self, file): + lines = open(file).read().splitlines() + self.libs_desc = '' + self.libs = '' + for l in lines: + if ') .iram1 EXCLUDE_FILE(*' in l and ') .iram1.*)' in l: + desc = '\(EXCLUDE_FILE\((.*)\) .iram1 ' + self.libs_desc = re.search(desc, l)[1] + self.libs = self.libs_desc.replace('*', '') + return + + def match(self, lib): + if lib in self.libs: + print('Remove lib %s'%(lib)) + return True + return False + + def add(self): + return self.libs_desc + +class target_c: + def __init__(self, lib, lib_path, file, fsecs): + self.lib = lib + self.file = file + + self.lib_path = lib_path + self.fsecs = func2sect(fsecs) + self.desc = '*%s:%s.*'%(lib, file.split('.')[0]) + + secs = lib_secs(lib, file, lib_path) + if '.iram1.' in self.fsecs[0]: + self.secs = filter_secs(secs, ('.iram1.', )) + else: + self.secs = filter_secs(secs, ('.iram1.', '.text.', '.literal.')) + self.isecs = strip_secs(self.secs, self.fsecs) + + def __str__(self): + s = 'lib=%s\nfile=%s\lib_path=%s\ndesc=%s\nsecs=%s\nfsecs=%s\nisecs=%s\n'%(\ + self.lib, self.file, self.lib_path, self.desc, self.secs, self.fsecs,\ + self.isecs) + return s + +class relink_c: + def __init__(self, input, library_file, object_file, function_file, sdkconfig_file, missing_function_info): + self.filter = filter_c(input) + + libraries = configuration.generator(library_file, object_file, function_file, sdkconfig_file, missing_function_info, espidf_objdump) + self.targets = list() + for i in libraries.libs: + lib = libraries.libs[i] + + if self.filter.match(lib.name): + continue + + for j in lib.objs: + obj = lib.objs[j] + self.targets.append(target_c(lib.name, lib.path, obj.name, + ' '.join(obj.sections()))) + # for i in self.targets: + # print(i) + self.__transform__() + + def __transform__(self): + iram1_exclude = list() + iram1_include = list() + flash_include = list() + + for t in self.targets: + secs = filter_secs(t.fsecs, ('.iram1.', )) + if len(secs) > 0: + iram1_exclude.append(t.desc) + + secs = filter_secs(t.isecs, ('.iram1.', )) + if len(secs) > 0: + iram1_include.append(' %s(%s)'%(t.desc, ' '.join(secs))) + + secs = t.fsecs + if len(secs) > 0: + flash_include.append(' %s(%s)'%(t.desc, ' '.join(secs))) + + self.iram1_exclude = ' *(EXCLUDE_FILE(%s %s) .iram1.*) *(EXCLUDE_FILE(%s %s) .iram1)' % \ + (self.filter.add(), ' '.join(iram1_exclude), \ + self.filter.add(), ' '.join(iram1_exclude)) + self.iram1_include = '\n'.join(iram1_include) + self.flash_include = '\n'.join(flash_include) + + logging.debug('IRAM1 Exclude: %s'%(self.iram1_exclude)) + logging.debug('IRAM1 Include: %s'%(self.iram1_include)) + logging.debug('Flash Include: %s'%(self.flash_include)) + + def __replace__(self, lines): + def is_iram_desc(l): + if '*(.iram1 .iram1.*)' in l or (') .iram1 EXCLUDE_FILE(*' in l and ') .iram1.*)' in l): + return True + return False + + iram_start = False + flash_done = False + + for i in range(0, len(lines) - 1): + l = lines[i] + if '.iram0.text :' in l: + logging.debug('start to process .iram0.text') + iram_start = True + elif '.dram0.data :' in l: + logging.debug('end to process .iram0.text') + iram_start = False + elif is_iram_desc(l): + if iram_start: + lines[i] = '%s\n%s\n'%(self.iram1_exclude, self.iram1_include) + elif '(.stub .gnu.warning' in l: + if not flash_done: + lines[i] = '%s\n\n%s'%(self.flash_include, l) + elif self.flash_include in l: + flash_done = True + else: + if iram_start: + new_l = self._replace_func(l) + if new_l: + lines[i] = new_l + + return lines + + def _replace_func(self, l): + for t in self.targets: + if t.desc in l: + S = '.literal .literal.* .text .text.*' + if S in l: + if len(t.isecs) > 0: + return l.replace(S, ' '.join(t.isecs)) + else: + return ' ' + + S = '%s(%s)'%(t.desc, ' '.join(t.fsecs)) + if S in l: + return ' ' + + replaced = False + for s in t.fsecs: + s2 = s + ' ' + if s2 in l: + l = l.replace(s2, '') + replaced = True + s2 = s + ')' + if s2 in l: + l = l.replace(s2, ')') + replaced = True + if '( )' in l or '()' in l: + return ' ' + if replaced: + return l + else: + index = '*%s:(EXCLUDE_FILE'%(t.lib) + if index in l and t.file.split('.')[0] not in l: + for m in self.targets: + index = '*%s:(EXCLUDE_FILE'%(m.lib) + if index in l and m.file.split('.')[0] not in l: + l = l.replace('EXCLUDE_FILE(', 'EXCLUDE_FILE(%s '%(m.desc)) + if len(m.isecs) > 0: + l += '\n %s(%s)'%(m.desc, ' '.join(m.isecs)) + return l + + return False + + def save(self, input, output): + lines = open(input).read().splitlines() + lines = self.__replace__(lines) + open(output, 'w+').write('\n'.join(lines)) + +def main(): + argparser = argparse.ArgumentParser(description='Relinker script generator') + + argparser.add_argument( + '--input', '-i', + help='Linker template file', + type=str) + + argparser.add_argument( + '--output', '-o', + help='Output linker script', + type=str) + + argparser.add_argument( + '--library', '-l', + help='Library description directory', + type=str) + + argparser.add_argument( + '--object', '-b', + help='Object description file', + type=str) + + argparser.add_argument( + '--function', '-f', + help='Function description file', + type=str) + + argparser.add_argument( + '--sdkconfig', '-s', + help='sdkconfig file', + type=str) + + argparser.add_argument( + '--objdump', '-g', + help='GCC objdump command', + type=str) + + argparser.add_argument( + '--debug', '-d', + help='Debug level(option is \'debug\')', + default='no', + type=str) + + argparser.add_argument( + '--missing_function_info', + help='Print error information instead of throwing exception when missing function', + default=False, + type=bool) + + args = argparser.parse_args() + + if args.debug == 'debug': + logging.basicConfig(level=logging.DEBUG) + + logging.debug('input: %s'%(args.input)) + logging.debug('output: %s'%(args.output)) + logging.debug('library: %s'%(args.library)) + logging.debug('object: %s'%(args.object)) + logging.debug('function: %s'%(args.function)) + logging.debug('sdkconfig:%s'%(args.sdkconfig)) + logging.debug('objdump: %s'%(args.objdump)) + logging.debug('debug: %s'%(args.debug)) + logging.debug('missing_function_info: %s'%(args.missing_function_info)) + + global espidf_objdump + espidf_objdump = args.objdump + + relink = relink_c(args.input, args.library, args.object, args.function, args.sdkconfig, args.missing_function_info) + relink.save(args.input, args.output) + +if __name__ == '__main__': + main() diff --git a/managed_components/espressif__cmake_utilities/test_apps/CMakeLists.txt b/managed_components/espressif__cmake_utilities/test_apps/CMakeLists.txt new file mode 100644 index 0000000..4ac13eb --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components" + "../../cmake_utilities") +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(cmake_utilities_test_apps) \ No newline at end of file diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/CMakeLists.txt b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/CMakeLists.txt new file mode 100644 index 0000000..6d9ee69 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/CMakeLists.txt @@ -0,0 +1,10 @@ +idf_component_register( SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES cmake_utilities) + +include(gcc) +include(gen_compressed_ota) +include(gen_single_bin) +include(package_manager) +include(relinker) +cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR}) \ No newline at end of file diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/idf_component.yml b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/idf_component.yml new file mode 100644 index 0000000..5a0b9df --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/idf_component.yml @@ -0,0 +1,6 @@ +version: "3.2.1" +description: Test2 for cmake utilities +url: https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities +issues: https://github.com/espressif/esp-iot-solution/issues +dependencies: + idf: ">=4.1" \ No newline at end of file diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/test_component2.c b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/test_component2.c new file mode 100644 index 0000000..3cb6555 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/test_component2.c @@ -0,0 +1,16 @@ +#include + +int test_component2_version_major() +{ + return TEST_COMPONENT2_VER_MAJOR; +} + +int test_component2_version_minor() +{ + return TEST_COMPONENT2_VER_MINOR; +} + +int test_component2_version_patch() +{ + return TEST_COMPONENT2_VER_PATCH; +} diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/test_component2.h b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/test_component2.h new file mode 100644 index 0000000..1323ccb --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/test_component2.h @@ -0,0 +1,14 @@ +#include +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +int test_component2_version_major(); +int test_component2_version_minor(); +int test_component2_version_patch(); + +#ifdef __cplusplus +} +#endif diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/CMakeLists.txt b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/CMakeLists.txt new file mode 100644 index 0000000..6d9ee69 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/CMakeLists.txt @@ -0,0 +1,10 @@ +idf_component_register( SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES cmake_utilities) + +include(gcc) +include(gen_compressed_ota) +include(gen_single_bin) +include(package_manager) +include(relinker) +cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR}) \ No newline at end of file diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/idf_component.yml b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/idf_component.yml new file mode 100644 index 0000000..cc5a946 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/idf_component.yml @@ -0,0 +1,6 @@ +version: "1.2.3" +description: Test1 for cmake utilities +url: https://github.com/espressif/esp-iot-solution/tree/master/tools/cmake_utilities +issues: https://github.com/espressif/esp-iot-solution/issues +dependencies: + idf: ">=4.1" \ No newline at end of file diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/test_component1.c b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/test_component1.c new file mode 100644 index 0000000..7f607e0 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/test_component1.c @@ -0,0 +1,16 @@ +#include + +int test_component1_version_major() +{ + return TEST_COMPONENT1_VER_MAJOR; +} + +int test_component1_version_minor() +{ + return TEST_COMPONENT1_VER_MINOR; +} + +int test_component1_version_patch() +{ + return TEST_COMPONENT1_VER_PATCH; +} diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/test_component1.h b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/test_component1.h new file mode 100644 index 0000000..794cc49 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/test_component1.h @@ -0,0 +1,14 @@ +#include +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +int test_component1_version_major(); +int test_component1_version_minor(); +int test_component1_version_patch(); + +#ifdef __cplusplus +} +#endif diff --git a/managed_components/espressif__cmake_utilities/test_apps/main/CMakeLists.txt b/managed_components/espressif__cmake_utilities/test_apps/main/CMakeLists.txt new file mode 100644 index 0000000..4d89cab --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES unity test_utils test_component1 TEST-component2) \ No newline at end of file diff --git a/managed_components/espressif__cmake_utilities/test_apps/main/test_cmake_utilities.c b/managed_components/espressif__cmake_utilities/test_apps/main/test_cmake_utilities.c new file mode 100644 index 0000000..9c2cb95 --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/main/test_cmake_utilities.c @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "esp_system.h" +#include "esp_log.h" +#include "unity.h" +#include "test_component1.h" +#include "test_component2.h" + + +/* USB PIN fixed in esp32-s2, can not use io matrix */ +#define TEST_MEMORY_LEAK_THRESHOLD (-400) + +TEST_CASE("Test package manager version", "[cmake_utilities][package_manager]") +{ + esp_log_level_set("*", ESP_LOG_INFO); + TEST_ASSERT_EQUAL_INT(test_component1_version_major(), 1); + TEST_ASSERT_EQUAL_INT(test_component1_version_minor(), 2); + TEST_ASSERT_EQUAL_INT(test_component1_version_patch(), 3); + TEST_ASSERT_EQUAL_INT(test_component2_version_major(), 3); + TEST_ASSERT_EQUAL_INT(test_component2_version_minor(), 2); + TEST_ASSERT_EQUAL_INT(test_component2_version_patch(), 1); +} + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); +} + +void app_main(void) +{ + printf("Cmake Utilities TEST \n"); + unity_run_menu(); +} diff --git a/managed_components/espressif__cmake_utilities/test_apps/pytest_cmake_utilities.py b/managed_components/espressif__cmake_utilities/test_apps/pytest_cmake_utilities.py new file mode 100644 index 0000000..3b188bf --- /dev/null +++ b/managed_components/espressif__cmake_utilities/test_apps/pytest_cmake_utilities.py @@ -0,0 +1,20 @@ +''' +Steps to run these cases: +- Build + - . ${IDF_PATH}/export.sh + - pip install idf_build_apps + - python tools/build_apps.py tools/cmake_utilities/test_apps -t esp32s2 +- Test + - pip install -r tools/requirements/requirement.pytest.txt + - pytest tools/cmake_utilities/test_apps --target esp32s2 +''' + +import pytest +from pytest_embedded import Dut + +@pytest.mark.target('esp32s3') +@pytest.mark.env('generic') +def test_cmake_utilities(dut: Dut)-> None: + dut.expect_exact('Press ENTER to see the list of tests.') + dut.write('*') + dut.expect_unity_test_output(timeout = 1000) diff --git a/managed_components/espressif__mdns/.component_hash b/managed_components/espressif__mdns/.component_hash new file mode 100644 index 0000000..27bf760 --- /dev/null +++ b/managed_components/espressif__mdns/.component_hash @@ -0,0 +1 @@ +d36b265164be5139f92de993f08f5ecaa0de0c0acbf84deee1f10bb5902d04ff \ No newline at end of file diff --git a/managed_components/espressif__mdns/.cz.yaml b/managed_components/espressif__mdns/.cz.yaml new file mode 100644 index 0000000..a8390ac --- /dev/null +++ b/managed_components/espressif__mdns/.cz.yaml @@ -0,0 +1,8 @@ +--- +commitizen: + bump_message: 'bump(mdns): $current_version -> $new_version' + pre_bump_hooks: python ../../ci/changelog.py mdns + tag_format: mdns-v$version + version: 1.4.3 + version_files: + - idf_component.yml diff --git a/managed_components/espressif__mdns/CHANGELOG.md b/managed_components/espressif__mdns/CHANGELOG.md new file mode 100644 index 0000000..2fae369 --- /dev/null +++ b/managed_components/espressif__mdns/CHANGELOG.md @@ -0,0 +1,493 @@ +# Changelog + +## [1.4.3](https://github.com/espressif/esp-protocols/commits/mdns-v1.4.3) + +### Features + +- support zero item when update subtype ([5bd82c01](https://github.com/espressif/esp-protocols/commit/5bd82c01)) + +## [1.4.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.4.2) + +### Features + +- support update subtype ([062b8dca](https://github.com/espressif/esp-protocols/commit/062b8dca)) + +### Updated + +- chore(mdns): Add more info to idf_component.yml ([4a1cb65c](https://github.com/espressif/esp-protocols/commit/4a1cb65c)) + +## [1.4.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.4.1) + +### Features + +- Send PTR query for mdns browse when interface is ready ([010a404a](https://github.com/espressif/esp-protocols/commit/010a404a)) + +### Bug Fixes + +- Prevent deadlock when deleting a browse request ([3f48f9ea](https://github.com/espressif/esp-protocols/commit/3f48f9ea)) +- Fix use after free reported by coverity ([25b3d5fd](https://github.com/espressif/esp-protocols/commit/25b3d5fd)) +- Fixed dead-code reported by coverity ([11846c7d](https://github.com/espressif/esp-protocols/commit/11846c7d)) + +## [1.4.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.4.0) + +### Major changes + +- Fixed mdns API issues when add/remove/update records from multiple threads ([Fix services API races to directly add/remove services](https://github.com/espressif/esp-protocols/commit/8a690503)) + +### Features + +- Unit tests for add/remove/update deleg/selfhosted services ([0660ece1](https://github.com/espressif/esp-protocols/commit/0660ece1)) +- Add console command for mdns browsing ([1e8ede33](https://github.com/espressif/esp-protocols/commit/1e8ede33)) +- Console test: set instance for service ([f107dcd1](https://github.com/espressif/esp-protocols/commit/f107dcd1)) +- Console test: add subtype for service ([ee00e97b](https://github.com/espressif/esp-protocols/commit/ee00e97b)) +- Console test: set port for (delegated) srvs ([07b79abf](https://github.com/espressif/esp-protocols/commit/07b79abf)) +- Console test: add/remove TXT recs for delegated srvs ([c9a58d73](https://github.com/espressif/esp-protocols/commit/c9a58d73)) +- Console test for changing TXT records ([6b9a6ce6](https://github.com/espressif/esp-protocols/commit/6b9a6ce6)) +- Console test for add/remove delegated service APIs ([43de7e5c](https://github.com/espressif/esp-protocols/commit/43de7e5c)) +- Console test for add/remove delegated host APIs ([ce7f326a](https://github.com/espressif/esp-protocols/commit/ce7f326a)) +- Console test for lookup service APIs ([a91ead8e](https://github.com/espressif/esp-protocols/commit/a91ead8e)) +- Add linux console functional tests ([50d059af](https://github.com/espressif/esp-protocols/commit/50d059af)) +- check if the txt items is changed when browsing ([e2f0477a](https://github.com/espressif/esp-protocols/commit/e2f0477a)) + +### Bug Fixes + +- Fix mdns_delegate_hostname_add() to block until done ([2c1b1661](https://github.com/espressif/esp-protocols/commit/2c1b1661)) +- Fix API races when removing all services ([169405b5](https://github.com/espressif/esp-protocols/commit/169405b5)) +- Fix API races setting instance name for services ([643dc6d4](https://github.com/espressif/esp-protocols/commit/643dc6d4)) +- Fix API races while adding subtypes for services ([f9f234c4](https://github.com/espressif/esp-protocols/commit/f9f234c4)) +- Fix API races removing txt item for services ([3f97a822](https://github.com/espressif/esp-protocols/commit/3f97a822)) +- Fix API races adding txt item for services ([c62b920b](https://github.com/espressif/esp-protocols/commit/c62b920b)) +- Fix API races while setting txt for services ([a927bf3a](https://github.com/espressif/esp-protocols/commit/a927bf3a)) +- Fix API races while setting port for services ([99d5fb27](https://github.com/espressif/esp-protocols/commit/99d5fb27)) +- Fix services API races to directly add/remove services ([8a690503](https://github.com/espressif/esp-protocols/commit/8a690503)) +- Fix mdns mdns_lookup_service() to handle empty TXT ([d4da9cb0](https://github.com/espressif/esp-protocols/commit/d4da9cb0)) + +## [1.3.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.3.2) + +### Features + +- add check of instance when handling PTR query ([6af6ca5](https://github.com/espressif/esp-protocols/commit/6af6ca5)) + +### Bug Fixes + +- Fix of mdns afl tests ([139166c](https://github.com/espressif/esp-protocols/commit/139166c)) +- remove same protocol services with different instances ([042533a](https://github.com/espressif/esp-protocols/commit/042533a)) + +## [1.3.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.3.1) + +### Bug Fixes + +- free txt value len ([afd98bb](https://github.com/espressif/esp-protocols/commit/afd98bb)) + +## [1.3.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.3.0) + +### Features + +- add a new mdns query mode `browse` ([af330b6](https://github.com/espressif/esp-protocols/commit/af330b6)) +- Make including mdns_console KConfigurable ([27adbfe](https://github.com/espressif/esp-protocols/commit/27adbfe)) + +### Bug Fixes + +- Schedule all queued Tx packets from timer task ([d4e693e](https://github.com/espressif/esp-protocols/commit/d4e693e)) +- add lock for some common apis ([21c84bf](https://github.com/espressif/esp-protocols/commit/21c84bf)) +- fix mdns answer append while host is invalid ([7be16bc](https://github.com/espressif/esp-protocols/commit/7be16bc)) + +## [1.2.5](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.5) + +### Bug Fixes + +- Fixed build issues for targets without WiFi caps ([302b46f](https://github.com/espressif/esp-protocols/commit/302b46f)) + +## [1.2.4](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.4) + +### Bug Fixes + +- Correction on 6d2c475 MDNS_PREDEF_NETIF_ETH fix ([fc59f87c4e](https://github.com/espressif/esp-protocols/commit/fc59f87c4e)) +- fix the logic of creating pcb for networking socket ([5000a9a20a](https://github.com/espressif/esp-protocols/commit/5000a9a20a)) +- fix compiling issue when disabling IPv4 ([2646dcd23a](https://github.com/espressif/esp-protocols/commit/2646dcd23a)) +- Fix compile error when MDNS_PREDEF_NETIF_ETH is defined, but ETH_ENABLED is not (#459) ([6d2c475c20](https://github.com/espressif/esp-protocols/commit/6d2c475c20)) + +## [1.2.3](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.3) + +### Bug Fixes + +- fixed CI issues for host and afl tests ([4be5efc84e](https://github.com/espressif/esp-protocols/commit/4be5efc84e)) +- fix copy delegated host addr ([19fb36000c](https://github.com/espressif/esp-protocols/commit/19fb36000c)) +- enable CONFIG_ESP_WIFI_ENABLED if CONFIG_SOC_WIFI_SUPPORTED is also enabled (for ESP-IDF <= 5.1) ([d20a718320](https://github.com/espressif/esp-protocols/commit/d20a718320)) +- remove protocol_examples_common ([1ee9dae6bf](https://github.com/espressif/esp-protocols/commit/1ee9dae6bf)) +- move the example into a subdirectory ([d28232b9f8](https://github.com/espressif/esp-protocols/commit/d28232b9f8)) +- reference protocol_examples_common from IDF ([c83b76ea8f](https://github.com/espressif/esp-protocols/commit/c83b76ea8f)) + +## [1.2.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.2) + +### Bug Fixes + +- add terminator for the getting host name ([b6a4d94](https://github.com/espressif/esp-protocols/commit/b6a4d94)) +- Enable ESP_WIFI_CONFIG when ESP-IDF <= 5.1 ([0b783c0](https://github.com/espressif/esp-protocols/commit/0b783c0)) +- set host list NULL on destroy ([ea54eef](https://github.com/espressif/esp-protocols/commit/ea54eef)) +- removed Wno-format flag and fixed formatting warnings ([c48e442](https://github.com/espressif/esp-protocols/commit/c48e442)) +- remove the the range of MDNS_MAX_SERVICES and fix issues of string functions ([3dadce2](https://github.com/espressif/esp-protocols/commit/3dadce2)) + +## [1.2.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.1) + +### Features + +- Allow setting length of mDNS action queue in menuconfig ([28cd898](https://github.com/espressif/esp-protocols/commit/28cd898)) + +### Bug Fixes + +- fix build issue if CONFIG_ESP_WIFI_ENABLED disabled ([24f7031](https://github.com/espressif/esp-protocols/commit/24f7031)) +- added idf_component.yml for examples ([d273e10](https://github.com/espressif/esp-protocols/commit/d273e10)) +- added guard check for null pointer ([71bb461](https://github.com/espressif/esp-protocols/commit/71bb461)) + +## [1.2.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.2.0) + +### Features + +- add an API for setting address to a delegated host ([ddc3eb6](https://github.com/espressif/esp-protocols/commit/ddc3eb6)) +- Add support for lwip build under linux ([588465d](https://github.com/espressif/esp-protocols/commit/588465d)) +- Allow for adding a delegated host with no address ([c562461](https://github.com/espressif/esp-protocols/commit/c562461)) +- Add APIs for looking up self hosted services and getting the self hostname ([f0df12d](https://github.com/espressif/esp-protocols/commit/f0df12d)) + +### Bug Fixes + +- Refactor freertos linux compat layers ([79a0e57](https://github.com/espressif/esp-protocols/commit/79a0e57)) +- Fix delegated service PTR response ([cab0e1d](https://github.com/espressif/esp-protocols/commit/cab0e1d)) +- Added unit tests to CI + minor fix to pass it ([c974c14](https://github.com/espressif/esp-protocols/commit/c974c14)) + +### Updated + +- docs: update documentation links ([4de5298](https://github.com/espressif/esp-protocols/commit/4de5298)) + +## [1.1.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.1.0) + +### Features + +- Decouple main module from mdns-networking ([d238e93](https://github.com/espressif/esp-protocols/commit/d238e93)) + +### Bug Fixes + +- Use idf-build-apps package for building mdns ([1a0a41f](https://github.com/espressif/esp-protocols/commit/1a0a41f)) +- socket networking to init interfaces properly ([ee9b04f](https://github.com/espressif/esp-protocols/commit/ee9b04f)) +- Removed unused internal lock from mdns_server struct ([a06fb77](https://github.com/espressif/esp-protocols/commit/a06fb77)) +- Resolve conflicts only on self hosted items ([e69a9eb](https://github.com/espressif/esp-protocols/commit/e69a9eb), [#185](https://github.com/espressif/esp-protocols/issues/185)) +- Fix memory issues reported by valgrind ([0a682e7](https://github.com/espressif/esp-protocols/commit/0a682e7)) + +### Updated + +- docs(common): updated component and example links ([f48d9b2](https://github.com/espressif/esp-protocols/commit/f48d9b2)) +- Add APIs to look up delegated services ([87dcd7d](https://github.com/espressif/esp-protocols/commit/87dcd7d)) +- Fix deadly mdns crash ([4fa3023](https://github.com/espressif/esp-protocols/commit/4fa3023)) +- docs(common): improving documentation ([ca3fce0](https://github.com/espressif/esp-protocols/commit/ca3fce0)) +- append all ipv6 address in mdns answer ([5ed3e9a](https://github.com/espressif/esp-protocols/commit/5ed3e9a)) +- test(mdns): Host tests to use IDF's esp_event_stub ([537d170](https://github.com/espressif/esp-protocols/commit/537d170)) + +## [1.0.9](https://github.com/espressif/esp-protocols/commits/mdns-v1.0.9) + +### Features + +- Add reverse lookup to the example and test ([d464ed7](https://github.com/espressif/esp-protocols/commit/d464ed7)) +- Add support for IPv6 reverse query ([d4825f5](https://github.com/espressif/esp-protocols/commit/d4825f5)) + +### Bug Fixes + +- Reintroduce missing CHANGELOGs ([200cbb3](https://github.com/espressif/esp-protocols/commit/200cbb3)) +- use semaphore instead of task notification bits (IDFGH-9380) ([73f2800](https://github.com/espressif/esp-protocols/commit/73f2800), [IDF#10754](https://github.com/espressif/esp-idf/issues/10754)) + +### Updated + +- ci(common): force scoping commit messages with components ([c55fcc0](https://github.com/espressif/esp-protocols/commit/c55fcc0)) +- Add homepage URL and License to all components ([ef3f0ee](https://github.com/espressif/esp-protocols/commit/ef3f0ee)) +- docs: fix of mdns link translation ([1c850dd](https://github.com/espressif/esp-protocols/commit/1c850dd)) +- unite all tags under common structure py test: update tags under common structure ([c6db3ea](https://github.com/espressif/esp-protocols/commit/c6db3ea)) + +## [1.0.8](https://github.com/espressif/esp-protocols/commits/b9b4a75) + +### Features + +- Add support for IPv4 reverse query ([b87bef5](https://github.com/espressif/esp-protocols/commit/b87bef5)) + +### Bug Fixes + +- Host test with IDFv5.1 ([fb8a2f0](https://github.com/espressif/esp-protocols/commit/fb8a2f0)) +- Remove strict mode as it's invalid ([d0c9070](https://github.com/espressif/esp-protocols/commit/d0c9070)) +- Allow setting instance name only after hostname set ([a8339e4](https://github.com/espressif/esp-protocols/commit/a8339e4), [#190](https://github.com/espressif/esp-protocols/issues/190)) +- Make unit test executable with pytest ([12cfcb5](https://github.com/espressif/esp-protocols/commit/12cfcb5)) +- AFL port layer per IDF-latest changes ([0247926](https://github.com/espressif/esp-protocols/commit/0247926)) + +### Updated + +- bump the component version to 1.0.8 ([b9b4a75](https://github.com/espressif/esp-protocols/commit/b9b4a75)) +- Make reverse query conditional per Kconfig ([91134f1](https://github.com/espressif/esp-protocols/commit/91134f1)) +- Added badges with version of components to the respective README files ([e4c8a59](https://github.com/espressif/esp-protocols/commit/e4c8a59)) +- fix some coverity reported issues ([c73c797](https://github.com/espressif/esp-protocols/commit/c73c797)) +- Examples: using pytest.ini from top level directory ([aee016d](https://github.com/espressif/esp-protocols/commit/aee016d)) +- mDNS: test_app pytest migration ([f71f61f](https://github.com/espressif/esp-protocols/commit/f71f61f)) +- CI: fixing the files to be complient with pre-commit hooks ([945bd17](https://github.com/espressif/esp-protocols/commit/945bd17)) +- prevent crash when hostname is null ([3498e86](https://github.com/espressif/esp-protocols/commit/3498e86)) +- Example tests integration ([a045c1c](https://github.com/espressif/esp-protocols/commit/a045c1c)) +- Replace hardcoded TTL values with named defines ([bb4c002](https://github.com/espressif/esp-protocols/commit/bb4c002)) +- Fix add_service() to report error if no-hostname ([656ab21](https://github.com/espressif/esp-protocols/commit/656ab21)) + + +## [1.0.7](https://github.com/espressif/esp-protocols/commits/088f7ac) + +### Updated + +- bump up the component version ([088f7ac](https://github.com/espressif/esp-protocols/commit/088f7ac)) +- fix IPV4 only build and also update CI configuration ([e079f8b](https://github.com/espressif/esp-protocols/commit/e079f8b)) +- add test configuration for IPV6 disabled build ([330332a](https://github.com/espressif/esp-protocols/commit/330332a)) + + +## [1.0.6](https://github.com/espressif/esp-protocols/commits/48c157b) + +### Bug Fixes + +- Example makefile to add only mdns as extra comps ([d74c296](https://github.com/espressif/esp-protocols/commit/d74c296)) +- ignore authoritative flag on reception ([415e04a](https://github.com/espressif/esp-protocols/commit/415e04a)) + +### Updated + +- fix build issue with CONFIG_LWIP_IPV6 disabled ([48c157b](https://github.com/espressif/esp-protocols/commit/48c157b)) +- fix bit order issue in DNS header flags ([c4e85bd](https://github.com/espressif/esp-protocols/commit/c4e85bd)) +- updated package version to 0.1.19 ([469f953](https://github.com/espressif/esp-protocols/commit/469f953)) + + +## [1.0.5](https://github.com/espressif/esp-protocols/commits/36de9af) + +### Features + +- Define explicit dependencies on esp-wifi ([36de9af](https://github.com/espressif/esp-protocols/commit/36de9af)) + +### Updated + +- bugfix: mdns IPv6 address convert error ([238ee96](https://github.com/espressif/esp-protocols/commit/238ee96)) + + +## [1.0.4](https://github.com/espressif/esp-protocols/commits/57afa38) + +### Updated + +- Bump asio/mdns/esp_websocket_client versions ([57afa38](https://github.com/espressif/esp-protocols/commit/57afa38)) +- ignore format warnings ([d66f9dc](https://github.com/espressif/esp-protocols/commit/d66f9dc)) +- Fix test_app build ([0b102f6](https://github.com/espressif/esp-protocols/commit/0b102f6)) + + +## [1.0.3](https://github.com/espressif/esp-protocols/commits/4868689) + +### Updated + +- Updated mDNS to explicitely use esp-eth dependency if needed ([4868689](https://github.com/espressif/esp-protocols/commit/4868689), [IDF@5e19b9c](https://github.com/espressif/esp-idf/commit/5e19b9c9518ae253d82400ab24b86af8af832425)) + + +## [1.0.2](https://github.com/espressif/esp-protocols/commits/8fe2a3a) + +### Features + +- fix bug when clean action memory ([81c219d](https://github.com/espressif/esp-protocols/commit/81c219d), [IDF@3d4deb9](https://github.com/espressif/esp-idf/commit/3d4deb972620cae8e8ce4d0050153cc6f39db372)) + +### Bug Fixes + +- add the maximum number of services ([0191d6f](https://github.com/espressif/esp-protocols/commit/0191d6f), [IDF@ba458c6](https://github.com/espressif/esp-idf/commit/ba458c69cfb2f18478d73690c289b09641c62004)) +- fix the exception when remove one of multiple service ([b26c866](https://github.com/espressif/esp-protocols/commit/b26c866), [IDF@696d733](https://github.com/espressif/esp-idf/commit/696d733eb04ee98f764dffdc82bcef51a724c9c6)) + +### Updated + +- Minor fixes here and there ([8fe2a3a](https://github.com/espressif/esp-protocols/commit/8fe2a3a)) +- mDNS: Initial version based on IDF 5.0 ([b6b20ad](https://github.com/espressif/esp-protocols/commit/b6b20ad)) +- soc: moved kconfig options out of the target component. ([4a52cf2](https://github.com/espressif/esp-protocols/commit/4a52cf2), [IDF@d287209](https://github.com/espressif/esp-idf/commit/d2872095f93ed82fb91c776081bc1d032493d93e)) +- cmake: fix issue with passing cxx_std option for GCC 11, a common workaround ([87c2699](https://github.com/espressif/esp-protocols/commit/87c2699), [IDF@ea0d212](https://github.com/espressif/esp-idf/commit/ea0d2123c806bd0ad77bc49843ee905cf9be65ff)) +- kconfig: Changed default values of bool configs - Some bool configs were using default values true and false, instead of y and n. ([eb536a7](https://github.com/espressif/esp-protocols/commit/eb536a7), [IDF@25c5c21](https://github.com/espressif/esp-idf/commit/25c5c214f38ca690b03533e12fb5a4d774c7eae0)) +- esp_netif: Remove tcpip_adapter compatibility layer ([3e93ea9](https://github.com/espressif/esp-protocols/commit/3e93ea9), [IDF@795b7ed](https://github.com/espressif/esp-idf/commit/795b7ed993784e3134195e12b0978504d83dfd56)) +- Fix copyright messages, update API descrition ([2c764b1](https://github.com/espressif/esp-protocols/commit/2c764b1), [IDF@42ba8a8](https://github.com/espressif/esp-idf/commit/42ba8a8338fd5efd82498a5989fc5c105938d447)) +- Add API to control custom network interfaces ([f836ae7](https://github.com/espressif/esp-protocols/commit/f836ae7), [IDF@b02468d](https://github.com/espressif/esp-idf/commit/b02468dc98d614f931d14cd8b5e2373ca51fb18d)) +- CI/mdns: Fix fuzzer build ([4b5f24f](https://github.com/espressif/esp-protocols/commit/4b5f24f), [IDF@98e9426](https://github.com/espressif/esp-idf/commit/98e9426b660a6e825f811cccd45a0722cc801ccd)) +- Add support for registering custom netif ([30f37c0](https://github.com/espressif/esp-protocols/commit/30f37c0), [IDF@bec42ff](https://github.com/espressif/esp-idf/commit/bec42ff85d5091d71e1cb1063bea20d7c6ac8c76)) +- Indicate interface using esp_netif in search results ([ddc58e8](https://github.com/espressif/esp-protocols/commit/ddc58e8), [IDF@f8495f1](https://github.com/espressif/esp-idf/commit/f8495f1e86de9a8e7d046bf13d0ca04775041b4c)) +- Use predefined interfaces to prepare for custom netifs ([fa951bf](https://github.com/espressif/esp-protocols/commit/fa951bf), [IDF@f90b3b7](https://github.com/espressif/esp-idf/commit/f90b3b798b446382d848f8c55c5e1653c81871cd)) +- Prepare for dynamic esp-netif support ([605d1fa](https://github.com/espressif/esp-protocols/commit/605d1fa), [IDF@f9892f7](https://github.com/espressif/esp-idf/commit/f9892f77b88ba77dc6608ba746175f6dc64a7607)) +- esp_hw_support/esp_system: Re-evaluate header inclusions and include directories ([58bf218](https://github.com/espressif/esp-protocols/commit/58bf218), [IDF@a9fda54](https://github.com/espressif/esp-idf/commit/a9fda54d39d1321005c3bc9b3cc268d0b7e9f052)) +- system: move kconfig options out of target component ([ec491ec](https://github.com/espressif/esp-protocols/commit/ec491ec), [IDF@bb88338](https://github.com/espressif/esp-idf/commit/bb88338118957c2214a4c0a33cd4a152e2e1f8ba)) +- Update to drop our own packet if bounced back ([94ae672](https://github.com/espressif/esp-protocols/commit/94ae672), [IDF@b5149e3](https://github.com/espressif/esp-idf/commit/b5149e3ee73728f790798e6757d732fe426e21c7)) +- Fix potential read behind parsed packet ([e5a3a3d](https://github.com/espressif/esp-protocols/commit/e5a3a3d), [IDF@51a5de2](https://github.com/espressif/esp-idf/commit/51a5de2525d0e82adea2e298a0edcc9b2dee5edd)) +- Fix memleak when adding delegated host ([7710ea9](https://github.com/espressif/esp-protocols/commit/7710ea9), [IDF@9cbdb87](https://github.com/espressif/esp-idf/commit/9cbdb8767bdf6e9745e895b2c5af74d0376965e7)) +- Fix null-service issue when parsing packets ([034c55e](https://github.com/espressif/esp-protocols/commit/034c55e), [IDF#8307](https://github.com/espressif/esp-idf/issues/8307), [IDF@a57be7b](https://github.com/espressif/esp-idf/commit/a57be7b7d1135ddb29f9da636e9ad315f7fa1fa7)) +- Update fuzzer test (add delegation, check memory) ([ec03fec](https://github.com/espressif/esp-protocols/commit/ec03fec), [IDF@2c10071](https://github.com/espressif/esp-idf/commit/2c1007156e01b4707b5c89d73cad05c0eef0264f)) +- Remove legacy esp_event API ([5909e9e](https://github.com/espressif/esp-protocols/commit/5909e9e), [IDF@e46aa51](https://github.com/espressif/esp-idf/commit/e46aa515bdf5606a3d868f1034774d5fc96904b8)) +- added missing includes ([82e2a5d](https://github.com/espressif/esp-protocols/commit/82e2a5d), [IDF@28d09c7](https://github.com/espressif/esp-idf/commit/28d09c7dbe145ffa6a7dd90531062d4f7669a9c8)) +- Clear notification value in mdns_hostname_set ([48e4d40](https://github.com/espressif/esp-protocols/commit/48e4d40), [IDF@83a4ddb](https://github.com/espressif/esp-idf/commit/83a4ddbd250e2b386bccabb4705d4c58c1a22bcb)) +- esp_timer: remove legacy ESP32 FRC timer implementation. ([ac6dcb6](https://github.com/espressif/esp-protocols/commit/ac6dcb6), [IDF@edb76f1](https://github.com/espressif/esp-idf/commit/edb76f14d6b3e925568ff04a87befe733ecc4517)) +- freertos: Remove legacy data types ([085dbd8](https://github.com/espressif/esp-protocols/commit/085dbd8), [IDF@57fd78f](https://github.com/espressif/esp-idf/commit/57fd78f5baf93a368a82cf4b2e00ca17ffc09115)) +- Tools: Custom baud-rate setup is not possible for IDF Monitor from menuconfig anymore ([f78e8cf](https://github.com/espressif/esp-protocols/commit/f78e8cf), [IDF@36a4011](https://github.com/espressif/esp-idf/commit/36a4011ff8985bfbae08ba0272194e6c3ef93bbf)) +- Use memcpy() for copy to support non-text TXTs ([6cdf5ee](https://github.com/espressif/esp-protocols/commit/6cdf5ee), [IDF@6aefe9c](https://github.com/espressif/esp-idf/commit/6aefe9c18563ed567d384a956cf02b6f57d6894c)) +- Support for null-value TXT records ([fcb5515](https://github.com/espressif/esp-protocols/commit/fcb5515), [IDF#8267](https://github.com/espressif/esp-idf/issues/8267), [IDF@23c2db4](https://github.com/espressif/esp-idf/commit/23c2db406dee8df09dbdba21cb7eef9fbca8bf27)) +- Fix alloc issue if TXT has empty value ([9fdbe5f](https://github.com/espressif/esp-protocols/commit/9fdbe5f), [IDF@205f6ba](https://github.com/espressif/esp-idf/commit/205f6ba8541e12d958c7c56af5a7136090f12a0e)) +- Fix random crash when defalt service instance queried ([20e6e9e](https://github.com/espressif/esp-protocols/commit/20e6e9e), [IDF@f46dffc](https://github.com/espressif/esp-idf/commit/f46dffca627e9578e49a510580f9754ec1e27e2e)) +- Fix minor memory leaks when creating services ([c588263](https://github.com/espressif/esp-protocols/commit/c588263), [IDF@fad62cc](https://github.com/espressif/esp-idf/commit/fad62cc1ed3dce63b58297172a72a489d7af2d9d)) +- Fix mDNS memory leak ([6258edf](https://github.com/espressif/esp-protocols/commit/6258edf), [IDF@119b4a9](https://github.com/espressif/esp-idf/commit/119b4a9dd12cf89cc5eaf63f8aa19730607ef30b)) +- Fix mDNS memory leak ([c8b0d5e](https://github.com/espressif/esp-protocols/commit/c8b0d5e), [IDF@f5ffd53](https://github.com/espressif/esp-idf/commit/f5ffd53aeb402afc1333a98168bb2fa35d7cdc77)) +- Use multi/uni-cast types in API ([5252b1d](https://github.com/espressif/esp-protocols/commit/5252b1d), [IDF@125c312](https://github.com/espressif/esp-idf/commit/125c3125524c71f4f48f635eda12e22fa3bca500)) +- Allow for unicast PTR queries ([4e11cc8](https://github.com/espressif/esp-protocols/commit/4e11cc8), [IDF@7eeeb01](https://github.com/espressif/esp-idf/commit/7eeeb01ea705745b027bd8bc11d2b142418e9927)) +- Fix potential null deref for ANY query type ([7af91ec](https://github.com/espressif/esp-protocols/commit/7af91ec), [IDF@99dd8ee](https://github.com/espressif/esp-idf/commit/99dd8eedb1a0e957f5f74344e3e4172e61c29ef8)) +- Make fuzzer layers compatible with llvm>=6 ([01256d3](https://github.com/espressif/esp-protocols/commit/01256d3), [IDF@1882cbe](https://github.com/espressif/esp-idf/commit/1882cbe44e6140bebb2d27dc18af06dfcb0157f5)) +- Fix copyright ([5a2d4ea](https://github.com/espressif/esp-protocols/commit/5a2d4ea), [IDF@c83678f](https://github.com/espressif/esp-idf/commit/c83678f64fe27844fc28050bde6433ccb04a0704)) +- Add mDNS miss comment ([9de3f53](https://github.com/espressif/esp-protocols/commit/9de3f53), [IDF@08e0813](https://github.com/espressif/esp-idf/commit/08e081340d9d76d1244e9f2dc527e5ae370b1fbe)) +- freertos: remove FREERTOS_ASSERT option ([bcabc8e](https://github.com/espressif/esp-protocols/commit/bcabc8e), [IDF@7255497](https://github.com/espressif/esp-idf/commit/72554971467a5edc9bd6e390cf8fe7b05e6ade81)) +- Minor err print fix in socket-networking layer ([dfb27b3](https://github.com/espressif/esp-protocols/commit/dfb27b3), [IDF@f1b8f5c](https://github.com/espressif/esp-idf/commit/f1b8f5c1023df7d649161bc76f2bcc9a8f8f4d8b)) +- unified errno format ([076c095](https://github.com/espressif/esp-protocols/commit/076c095), [IDF@87506f4](https://github.com/espressif/esp-idf/commit/87506f46e2922710f48a6b96ca75e53543ff45c4)) +- always send A/AAAA records in announcements ([7dd0bc1](https://github.com/espressif/esp-protocols/commit/7dd0bc1), [IDF@456f80b](https://github.com/espressif/esp-idf/commit/456f80b754ebd0bd74e02c7febdf461c6b573b7a)) +- filter instance name for ANY queries ([7e82a7c](https://github.com/espressif/esp-protocols/commit/7e82a7c), [IDF@5d0c473](https://github.com/espressif/esp-idf/commit/5d0c47303dd9ead0f2ad291dca1d4b7ce4e23b2b)) +- Fix potential null deref reported by fuzzer test ([ae381b7](https://github.com/espressif/esp-protocols/commit/ae381b7), [IDF@cb5653f](https://github.com/espressif/esp-idf/commit/cb5653fd940a9cd41e8554a6d753fab46e0459d7)) +- Minor fix of API description and API usage ([941dc5c](https://github.com/espressif/esp-protocols/commit/941dc5c), [IDF@c297301](https://github.com/espressif/esp-idf/commit/c297301ecc350f8315d7eaf78c72b4aba68d422a)) +- Added results count to MDNS ([525c649](https://github.com/espressif/esp-protocols/commit/525c649), [IDF@f391d61](https://github.com/espressif/esp-idf/commit/f391d610e8185631b5361dc6c844c4c04aac30b1)) +- fix mdns server instance mismatch ([f0839d9](https://github.com/espressif/esp-protocols/commit/f0839d9), [IDF@6173dd7](https://github.com/espressif/esp-idf/commit/6173dd78097216261277c20ebd92a53c68c47f89)) +- support multiple instance for mdns service txt set ([69902ea](https://github.com/espressif/esp-protocols/commit/69902ea), [IDF@50f6302](https://github.com/espressif/esp-idf/commit/50f6302c5d7c0498fa1baa6fd6129d8233971a81)) +- fix wrong PTR record count ([d0bbe88](https://github.com/espressif/esp-protocols/commit/d0bbe88), [IDF@5d3f815](https://github.com/espressif/esp-idf/commit/5d3f8157e0e481363ef93d54a29d957fc91cca86)) +- Build & config: Remove leftover files from the unsupported "make" build system ([4a9d55e](https://github.com/espressif/esp-protocols/commit/4a9d55e), [IDF@766aa57](https://github.com/espressif/esp-idf/commit/766aa5708443099f3f033b739cda0e1de101cca6)) +- Build & config: Remove the "make" build system ([be2a924](https://github.com/espressif/esp-protocols/commit/be2a924), [IDF@9c1d4f5](https://github.com/espressif/esp-idf/commit/9c1d4f5b549d6a7125e5c7c323c80d37361991cb)) +- freertos: update freertos folder structure to match upstream ([76fcd41](https://github.com/espressif/esp-protocols/commit/76fcd41), [IDF@4846222](https://github.com/espressif/esp-idf/commit/48462221029c7da4b1ea233e9e781cd57ff91c7e)) +- support service subtype ([fd8499c](https://github.com/espressif/esp-protocols/commit/fd8499c), [IDF#5508](https://github.com/espressif/esp-idf/issues/5508), [IDF@e7e8610](https://github.com/espressif/esp-idf/commit/e7e8610f563e0b8532a093ea8b803f0eb132fd0e)) +- Fix parsing non-standard queries ([38b4fe2](https://github.com/espressif/esp-protocols/commit/38b4fe2), [IDF#7694](https://github.com/espressif/esp-idf/issues/7694), [IDF@d16f9ba](https://github.com/espressif/esp-idf/commit/d16f9bade5beab3785677dd5b39ebc4e9c895008)) +- allow mutiple instances with same service type ([b266062](https://github.com/espressif/esp-protocols/commit/b266062), [IDF@b7a99f4](https://github.com/espressif/esp-idf/commit/b7a99f46587a69a2cd07e7616c3bb30b7b1a6edf)) +- Update copyright header ([5e087d8](https://github.com/espressif/esp-protocols/commit/5e087d8), [IDF@2a2b95b](https://github.com/espressif/esp-idf/commit/2a2b95b9c22bc5090d87a4f4317288b64b14fcd9)) +- Fix potential null dereference identified by fuzzer tests ([91a3d95](https://github.com/espressif/esp-protocols/commit/91a3d95), [IDF@e7dabb1](https://github.com/espressif/esp-idf/commit/e7dabb14f7c8fd9bd2bea55d8f1accc65323a1c0)) +- components/bt: move config BT_RESERVE_DRAM from bluedroid to ESP32 controller ([6d6dd2b](https://github.com/espressif/esp-protocols/commit/6d6dd2b), [IDF@b310c06](https://github.com/espressif/esp-idf/commit/b310c062cd25f249e00dd03dd27baed783921630)) +- add notification callback for async APIs ([52306e9](https://github.com/espressif/esp-protocols/commit/52306e9), [IDF@986603c](https://github.com/espressif/esp-idf/commit/986603cf07413b46c88c76c324bf500edcfb6171)) +- add more mdns result attributes ([d37ab6d](https://github.com/espressif/esp-protocols/commit/d37ab6d), [IDF@76ec76c](https://github.com/espressif/esp-idf/commit/76ec76c12c871554147343bb7141da1e5de58011)) +- Add host test using linux target ([5c55ea6](https://github.com/espressif/esp-protocols/commit/5c55ea6), [IDF@fc7e2d9](https://github.com/espressif/esp-idf/commit/fc7e2d9e908f61fb4b852cfae72aa5ff7c662ebc)) +- Implement mdns_networking using BSD sockets ([0c71c7b](https://github.com/espressif/esp-protocols/commit/0c71c7b), [IDF@73dfe84](https://github.com/espressif/esp-idf/commit/73dfe84bf295a850edfad39b6b097a71f15964dc)) +- fix crash when adding services without hostname set ([4c368c0](https://github.com/espressif/esp-protocols/commit/4c368c0), [IDF@5e98772](https://github.com/espressif/esp-idf/commit/5e98772eaf7e50d96cf2e6ecdfedcd928b61c864)) +- Fix fuzzer IDF-mock layer ([af22753](https://github.com/espressif/esp-protocols/commit/af22753), [IDF@619235c](https://github.com/espressif/esp-idf/commit/619235c2ee5a1fe8411bd2be2de8798209f95902)) +- Clean the main mdns module from lwip dependencies ([b0957e7](https://github.com/espressif/esp-protocols/commit/b0957e7), [IDF@54e3294](https://github.com/espressif/esp-idf/commit/54e329444a5dd19c51e84b5f1e16455a0f1c6225)) +- Add asynchronous query API ([47c7266](https://github.com/espressif/esp-protocols/commit/47c7266), [IDF#7090](https://github.com/espressif/esp-idf/issues/7090), [IDF@d81482d](https://github.com/espressif/esp-idf/commit/d81482d699232b22f4a5cbee2a76199a5285dadb)) +- Fix crashes reported by the fuzzer tests ([40da0d2](https://github.com/espressif/esp-protocols/commit/40da0d2), [IDF@4a2e726](https://github.com/espressif/esp-idf/commit/4a2e72677c6fb7681a7e2acd1a878d3deb114079)) +- mdns/fuzzer: Fix non-instrumentation test to reproduce fuzzer issues ([5f6b6f9](https://github.com/espressif/esp-protocols/commit/5f6b6f9), [IDF@dae8033](https://github.com/espressif/esp-idf/commit/dae803335e6bc6d9751a360cd3f675ce4027853b)) +- return ESP_OK rather than ERR_OK in API functions ([8a12082](https://github.com/espressif/esp-protocols/commit/8a12082), [IDF@2386113](https://github.com/espressif/esp-idf/commit/2386113972ee51ea93e9740d8c34bfe9289ce909)) +- fix memory leak in mdns_free when adding delegated hostnames ([46f28a8](https://github.com/espressif/esp-protocols/commit/46f28a8), [IDF@0baee93](https://github.com/espressif/esp-idf/commit/0baee932111268c4a2103e1c1adeb7d99914a937)) +- Support for One-Shot mDNS queries ([5a81eae](https://github.com/espressif/esp-protocols/commit/5a81eae), [IDF@f167238](https://github.com/espressif/esp-idf/commit/f167238fac37818aed75dc689eed54ad47528ab9)) +- allow explicit txt value length ([2ddaee2](https://github.com/espressif/esp-protocols/commit/2ddaee2), [IDF@b4e0088](https://github.com/espressif/esp-idf/commit/b4e0088b68321acc4698b01faec7e2ffbe1e37c1)) +- Fix crashes reported by the fuzzer ([27fc285](https://github.com/espressif/esp-protocols/commit/27fc285), [IDF@79ba738](https://github.com/espressif/esp-idf/commit/79ba738626d643d8c6f32bdcd455e0d2476f94c7)) +- Minor correction of the test code ([93e6efe](https://github.com/espressif/esp-protocols/commit/93e6efe), [IDF@7d76245](https://github.com/espressif/esp-idf/commit/7d762451731cb305c3b090509827740f0195a496)) +- Fix fuzzer from miss-interpreting adding services as timeouts ([bc4cda8](https://github.com/espressif/esp-protocols/commit/bc4cda8), [IDF@14099fe](https://github.com/espressif/esp-idf/commit/14099fe15efb1b0cde0a8370096c55bba62ff937)) +- fix test script delayed response ([8a8d58d](https://github.com/espressif/esp-protocols/commit/8a8d58d), [IDF@a4f2639](https://github.com/espressif/esp-idf/commit/a4f263948c35c13340b6f4b59a649c5073787d5e)) +- fix wrong SRV/PTR record handling ([402baeb](https://github.com/espressif/esp-protocols/commit/402baeb), [IDF@e613555](https://github.com/espressif/esp-idf/commit/e6135552d26480e39e11632437020535b1667b7a)) +- fix wrong service hostname after mangling ([9fa25ef](https://github.com/espressif/esp-protocols/commit/9fa25ef), [IDF@439b31d](https://github.com/espressif/esp-idf/commit/439b31d065eddfdfb6eb4cf9c00454edfebc3d9b)) +- fix empty address change announce packets ([121b525](https://github.com/espressif/esp-protocols/commit/121b525), [IDF@7bbb72d](https://github.com/espressif/esp-idf/commit/7bbb72d86540f04d37b0e2c4efb6dc66ee9c9ea0)) +- fix mdns probe/reply behavior ([418fb60](https://github.com/espressif/esp-protocols/commit/418fb60), [IDF@d2a5d25](https://github.com/espressif/esp-idf/commit/d2a5d25984432d149ca31aea4a0d177f3509dd7b)) +- make delegate host address a list ([4049b3b](https://github.com/espressif/esp-protocols/commit/4049b3b), [IDF@2d34352](https://github.com/espressif/esp-idf/commit/2d34352f3db0fa71366a838933a29138a90eb2af)) +- add remove delegate host api ([c882119](https://github.com/espressif/esp-protocols/commit/c882119), [IDF@2174693](https://github.com/espressif/esp-idf/commit/2174693096b73ce93261611c44ecba647cd01859)) +- add mdns delegation ([1eb5df9](https://github.com/espressif/esp-protocols/commit/1eb5df9), [IDF@401ff56](https://github.com/espressif/esp-idf/commit/401ff56cc1ad1d11284143a348cc0c0e4a363e98)) +- fix memory free issue when repeating the query in reply ([b62b4b3](https://github.com/espressif/esp-protocols/commit/b62b4b3), [IDF@5f244c8](https://github.com/espressif/esp-idf/commit/5f244c86f29da46c17610563a245d1663a46b439)) +- Fix of crash when wifi interface get deleted and mdns receives the packets ([4d8aec1](https://github.com/espressif/esp-protocols/commit/4d8aec1), [IDF#6973](https://github.com/espressif/esp-idf/issues/6973), [IDF@03de74a](https://github.com/espressif/esp-idf/commit/03de74a728d4b278f55e1fc30e0425483b806e80)) +- Docs: Added README.md for lwip fuzzer tests ([6d64910](https://github.com/espressif/esp-protocols/commit/6d64910), [IDF@53c18a8](https://github.com/espressif/esp-idf/commit/53c18a85db104bb37ebeadec2faf5d42d764d0f9)) +- Fixed the ip header TTL to be correctly set to 255 ([ab3fa69](https://github.com/espressif/esp-protocols/commit/ab3fa69), [IDF@5cce919](https://github.com/espressif/esp-idf/commit/5cce919cbef87f543bb9f5275b77b97b3b1ea67e)) +- Fix parsing answers with questions when instance name not set ([c3a5826](https://github.com/espressif/esp-protocols/commit/c3a5826), [IDF#6598](https://github.com/espressif/esp-idf/issues/6598), [IDF@3404945](https://github.com/espressif/esp-idf/commit/34049454dfaf5132d9b258ef4d04921befc8997b)) +- Fix the resolver to correctly parse it's own non-strict answers ([cbcbe4f](https://github.com/espressif/esp-protocols/commit/cbcbe4f), [IDF@b649603](https://github.com/espressif/esp-idf/commit/b649603a0d70ec804567f57752c3eddaed56198f)) +- Add MDNS_STRICT_MODE config option ([adc3430](https://github.com/espressif/esp-protocols/commit/adc3430), [IDF@0eee315](https://github.com/espressif/esp-idf/commit/0eee31546dd4e6df0d1c1cc2740da0675dffb4bf)) +- freertos: common config header ([c30617d](https://github.com/espressif/esp-protocols/commit/c30617d), [IDF@39cf818](https://github.com/espressif/esp-idf/commit/39cf818838b0259b3e00b3c198ad47b4add41939)) +- Removed freeRTOS dependancies from fuzzer tests ([1e5eeb1](https://github.com/espressif/esp-protocols/commit/1e5eeb1), [IDF@5571694](https://github.com/espressif/esp-idf/commit/55716945a9908e057743d69e1d59399df03e49bd)) +- mDNS: Updated APIs description and shows the warning when hostname contains domain name during the query ([22c7c0a](https://github.com/espressif/esp-protocols/commit/22c7c0a), [IDF#6590](https://github.com/espressif/esp-idf/issues/6590), [IDF@9f8d2b9](https://github.com/espressif/esp-idf/commit/9f8d2b944d2b3736a012e0dff1a8459b6941d295)) +- components: Use CONFIG_LWIP_IPV6 to strip IPv6 function in components ([1623c0e](https://github.com/espressif/esp-protocols/commit/1623c0e), [IDF@da58235](https://github.com/espressif/esp-idf/commit/da58235a0ee262ff552c5f1155d531b5c31e8de6)) +- add bound check when setting interface as duplicate ([b114ed6](https://github.com/espressif/esp-protocols/commit/b114ed6), [IDF@2b9d2c0](https://github.com/espressif/esp-idf/commit/2b9d2c06f54924b680c41ae641978c8d81612f65)) +- mDNS: Fix of text length calculation when detecting a collision ([2ffd223](https://github.com/espressif/esp-protocols/commit/2ffd223), [IDF@be0ae1e](https://github.com/espressif/esp-idf/commit/be0ae1ebbbe9fae6ecf7de09e8d50cba063b61f4)) +- global: fix sign-compare warnings ([1fe901f](https://github.com/espressif/esp-protocols/commit/1fe901f), [IDF@753a929](https://github.com/espressif/esp-idf/commit/753a9295259126217a9fe6ef1c5e9da21e9b4e28)) +- lwip: Moved default SNTP API to esp_sntp.h ([2cf9fd8](https://github.com/espressif/esp-protocols/commit/2cf9fd8), [IDF@76f6dd6](https://github.com/espressif/esp-idf/commit/76f6dd6214ca583b1a94c7c553ccac739a27f6d5)) +- Allow resolve its own non-strict answers ([89439e0](https://github.com/espressif/esp-protocols/commit/89439e0), [IDF#6190](https://github.com/espressif/esp-idf/issues/6190), [IDF@0693e17](https://github.com/espressif/esp-idf/commit/0693e172de392086b9bfd8cf1474d8d133af3298)) +- mDNS: Fix of collision detection during txt length calculation ([becd5d0](https://github.com/espressif/esp-protocols/commit/becd5d0), [IDF#6114](https://github.com/espressif/esp-idf/issues/6114), [IDF@f33772c](https://github.com/espressif/esp-idf/commit/f33772c96037c795366e60082bdbbefe2a69165f)) +- esp32c3: Apply one-liner/small changes for ESP32-C3 ([0d7a309](https://github.com/espressif/esp-protocols/commit/0d7a309), [IDF@5228d9f](https://github.com/espressif/esp-idf/commit/5228d9f9ced16118d87326f94d9f9dfd411e0be9)) +- test: fix several test build error ([1fdffbb](https://github.com/espressif/esp-protocols/commit/1fdffbb), [IDF@b7ecccd](https://github.com/espressif/esp-idf/commit/b7ecccd9010f1deaba83de54374231c3c7f5b472)) +- freertos: Add RISC-V port ([988d120](https://github.com/espressif/esp-protocols/commit/988d120), [IDF@87e13ba](https://github.com/espressif/esp-idf/commit/87e13baaf12fe6deae715d95e912a310fea4ba88)) +- Fix wrong mdns source address if lwIP IPv6 zones disabled ([fd47df3](https://github.com/espressif/esp-protocols/commit/fd47df3), [IDF@7ac9761](https://github.com/espressif/esp-idf/commit/7ac97616c119e4d2f4cdd377dfc5abbf75ec5e30)) +- Whitespace: Automated whitespace fixes (large commit) ([2cb3a6e](https://github.com/espressif/esp-protocols/commit/2cb3a6e), [IDF@66fb5a2](https://github.com/espressif/esp-idf/commit/66fb5a29bbdc2482d67c52e6f66b303378c9b789)) +- test_compile_fuzzers: Fix include paths for host build ([825652f](https://github.com/espressif/esp-protocols/commit/825652f), [IDF@98a0cc7](https://github.com/espressif/esp-idf/commit/98a0cc783f701b238bea232b53250a538d34920a)) +- CI: Add a test to pre-check fuzzer tests compilation before weekly run ([fc53888](https://github.com/espressif/esp-protocols/commit/fc53888), [IDF@637f5c0](https://github.com/espressif/esp-idf/commit/637f5c0a6842c42ee6cf7f41d3c5ae0cb28a68af)) +- soc: descriptive part occupy whole component ([7635c04](https://github.com/espressif/esp-protocols/commit/7635c04), [IDF@79887fd](https://github.com/espressif/esp-idf/commit/79887fdc6c3d9a2e509cc189bb43c998d3f0f4ee)) +- Coredump config option rename throughout IDF ([d5fe42b](https://github.com/espressif/esp-protocols/commit/d5fe42b), [IDF@20af94f](https://github.com/espressif/esp-idf/commit/20af94ff53c5147a76342800d007a6c49be50a7b)) +- mdns, dns, dhcp, dhcps: update fuzzer test to work in CI ([e0bc60a](https://github.com/espressif/esp-protocols/commit/e0bc60a), [IDF@a43c06a](https://github.com/espressif/esp-idf/commit/a43c06a592bcf9404297b22268c33bb7a246632c)) +- cmock: added cmock as component ([9772e49](https://github.com/espressif/esp-protocols/commit/9772e49), [IDF@20c068e](https://github.com/espressif/esp-idf/commit/20c068ef3b49999387896b90f8011b02f718485f)) +- Support queries in responses in mDNS non-strict mode ([6021a88](https://github.com/espressif/esp-protocols/commit/6021a88), [IDF#5521](https://github.com/espressif/esp-idf/issues/5521), [IDF@bcfa36d](https://github.com/espressif/esp-idf/commit/bcfa36db8ffff997f1f95eaf6b011ffc4d46a10f)) +- Fix include query ID in reponses ([78f71ec](https://github.com/espressif/esp-protocols/commit/78f71ec), [IDF#5574](https://github.com/espressif/esp-idf/issues/5574), [IDF@f62e321](https://github.com/espressif/esp-idf/commit/f62e321d87c1d520cccca951715c27730e06607a)) +- Allow config mDNS task stack size ([3319844](https://github.com/espressif/esp-protocols/commit/3319844), [IDF@cf7e48c](https://github.com/espressif/esp-idf/commit/cf7e48c779edd84c3f99d5e8ed81027932302382)) +- Remove mbedtls dependency ([ac70c9a](https://github.com/espressif/esp-protocols/commit/ac70c9a), [IDF@f4a4549](https://github.com/espressif/esp-idf/commit/f4a4549a344e7ff2444a188adbebbc136b47a7bb)) +- limit the GOT_IP6_EVENT to only known network interfaces ([2b7d43e](https://github.com/espressif/esp-protocols/commit/2b7d43e), [IDF@ab8cab1](https://github.com/espressif/esp-idf/commit/ab8cab1c553ee5312ef47a7dea002f2585605006)) +- esp32: add implementation of esp_timer based on TG0 LAC timer ([4eb3e89](https://github.com/espressif/esp-protocols/commit/4eb3e89), [IDF@739eb05](https://github.com/espressif/esp-idf/commit/739eb05bb97736b70507e7ebcfee58e670672d23)) +- fixed typos in the variable names and the comments ([b5e5a64](https://github.com/espressif/esp-protocols/commit/b5e5a64), [IDF@ecca39e](https://github.com/espressif/esp-idf/commit/ecca39e19f663e32e16aef2a09df15443de347e9)) +- fix preset of esp_netif ptr for local interfaces ([6713ffe](https://github.com/espressif/esp-protocols/commit/6713ffe), [IDF@09e36f9](https://github.com/espressif/esp-idf/commit/09e36f9f3354092b2a528baaaaccab28ff4774d6)) +- fixed crash on event during deinit ([817c4fd](https://github.com/espressif/esp-protocols/commit/817c4fd), [IDF@eaa2f12](https://github.com/espressif/esp-idf/commit/eaa2f12d6761710d2633b4934fe09f6f45e20f4f)) +- respond to discovery with the proper pseudo name _services._dns-sd._udp ([8f0dc6d](https://github.com/espressif/esp-protocols/commit/8f0dc6d), [IDF#4369](https://github.com/espressif/esp-idf/issues/4369), [IDF@de17a14](https://github.com/espressif/esp-idf/commit/de17a1487f8ba6f432b06199f2261132ec6e735f)) +- fixed forgotten merge conflicts in debug code ([d20666f](https://github.com/espressif/esp-protocols/commit/d20666f), [IDF@d9433ef](https://github.com/espressif/esp-idf/commit/d9433ef69223a32d05abdca543fb530f2e6679e4)) +- add missing include of esp_task.h ([662a4ce](https://github.com/espressif/esp-protocols/commit/662a4ce), [IDF@5884b80](https://github.com/espressif/esp-idf/commit/5884b80908d680874e27fa0c8b2df85b69d03dd3)) +- add configuration values for task priority, affinity and internal service timeouts ([fb1de80](https://github.com/espressif/esp-protocols/commit/fb1de80), [IDF@c6f38f0](https://github.com/espressif/esp-idf/commit/c6f38f04f8eec1aae937cc87c111609772681cb3)) +- tcpip_adapter: updated tcpip_adapter compatablity layer to include all public API and keep 100% backward compatibility update build of tcpip adapter when ethernet disabled ([1f35e9a](https://github.com/espressif/esp-protocols/commit/1f35e9a), [IDF@7f5cda1](https://github.com/espressif/esp-idf/commit/7f5cda1b825586903f85dc4ad7736b35712e46d7)) +- update mdns to use esp-netif for mdns supported services such as STA, AP, ETH ([48b819b](https://github.com/espressif/esp-protocols/commit/48b819b), [IDF@19e24fe](https://github.com/espressif/esp-idf/commit/19e24fe61ed5ea6698dfd5e1f427e783360aa846)) +- esp_netif: Introduction of esp-netif component as a replacement of tcpip_adpter ([53e2aa3](https://github.com/espressif/esp-protocols/commit/53e2aa3), [IDF@ffe043b](https://github.com/espressif/esp-idf/commit/ffe043b1a81a0f9e1cc2cfa8873e21318ec89143)) +- examples: removed ip4addr_ntoa and used prefered IP2STR for displaying IP addresses ([3cc6446](https://github.com/espressif/esp-protocols/commit/3cc6446), [IDF@ec9f245](https://github.com/espressif/esp-idf/commit/ec9f245dd35d3e8e7b19a8dec5e05e003dc21f39)) +- esp_event, mdns: fixes for CONFIG_ETH_ENABLED=n ([248b11b](https://github.com/espressif/esp-protocols/commit/248b11b), [IDF@569ad75](https://github.com/espressif/esp-idf/commit/569ad7545c32a2f1d0eff3f1e81df70fb76ad125)) +- build and link hello-world for esp32s2beta ([901124b](https://github.com/espressif/esp-protocols/commit/901124b), [IDF@84b2f9f](https://github.com/espressif/esp-idf/commit/84b2f9f14d16533c84db2210f13a24cd817e0b0a)) +- fix crash for hostname queries ([f6ff165](https://github.com/espressif/esp-protocols/commit/f6ff165), [IDF#4224](https://github.com/espressif/esp-idf/issues/4224), [IDF@3d11700](https://github.com/espressif/esp-idf/commit/3d1170031b340a231949fdc0d9c46d87af0d1b5d)) +- fix possible race condition when checking DHCP status on WIFI_EVENT_STA_CONNECTED event. ([f44c569](https://github.com/espressif/esp-protocols/commit/f44c569), [IDF@7f410a0](https://github.com/espressif/esp-idf/commit/7f410a0bcbafa85dba05807c53c3c38999506509)) +- use constant size of AAAA answer in mdns packets instead of deriving from lwip struct size, since the struct could contain also zones ([286c646](https://github.com/espressif/esp-protocols/commit/286c646), [IDF@e5e31c5](https://github.com/espressif/esp-idf/commit/e5e31c5d0172d68fd207fa31cc5d3bba82dad020)) +- esp_wifi: wifi support new event mechanism ([c70d527](https://github.com/espressif/esp-protocols/commit/c70d527), [IDF@003a987](https://github.com/espressif/esp-idf/commit/003a9872b7de69d799e9d37521cfbcaff9b37e85)) +- fix missing bye packet if services removed with mdns_service_remove_all() or mdns_free() ([7cdf96c](https://github.com/espressif/esp-protocols/commit/7cdf96c), [IDF#3660](https://github.com/espressif/esp-idf/issues/3660), [IDF@a001998](https://github.com/espressif/esp-idf/commit/a001998d5283b29ca9a374adf7cef3357b39a03a)) +- mdns_service_remove_all doesn't take an argument ([407875d](https://github.com/espressif/esp-protocols/commit/407875d), [IDF@c2764f6](https://github.com/espressif/esp-idf/commit/c2764f6fe85681cfaf5dbbe168295284f09c09cd)) +- tools: Mass fixing of empty prototypes (for -Wstrict-prototypes) ([3e753f5](https://github.com/espressif/esp-protocols/commit/3e753f5), [IDF@afbaf74](https://github.com/espressif/esp-idf/commit/afbaf74007e89d016dbade4072bf2e7a3874139a)) +- fix ignoring mdns packet with some invalid name entries in question field ([144d4ad](https://github.com/espressif/esp-protocols/commit/144d4ad), [IDF@4bd4c7c](https://github.com/espressif/esp-idf/commit/4bd4c7caf3f9ef8402c5a27ab44561537407eb60)) +- add esp_eth component ([680bad6](https://github.com/espressif/esp-protocols/commit/680bad6), [IDF@90c4827](https://github.com/espressif/esp-idf/commit/90c4827bd22aa61894a5b22b3b39247a7e44d6cf)) +- components: use new component registration api ([7fb6686](https://github.com/espressif/esp-protocols/commit/7fb6686), [IDF@9eccd7c](https://github.com/espressif/esp-idf/commit/9eccd7c0826d6cc2e9de59304d1e5f76c0063ccf)) +- fix static analysis warnings ([4912bef](https://github.com/espressif/esp-protocols/commit/4912bef), [IDF@c34de4c](https://github.com/espressif/esp-idf/commit/c34de4cba658e8331f8a3ab2f466190c7640595b)) +- added initial suite of api unit tests ([181a22e](https://github.com/espressif/esp-protocols/commit/181a22e), [IDF@e680191](https://github.com/espressif/esp-idf/commit/e6801912c5c4861f828ab1f447280628bba9a5d7)) +- mdns tests: adapt mdns fuzzer test to compile with event loop library ([4172219](https://github.com/espressif/esp-protocols/commit/4172219), [IDF@38d15cb](https://github.com/espressif/esp-idf/commit/38d15cbd637e8b8baacda9fc43e8e99d224530f5)) +- fixed mdns crashing on reception of txt packet without a corresponding service closes #2866 ([98d2c1a](https://github.com/espressif/esp-protocols/commit/98d2c1a), [IDF@af48977](https://github.com/espressif/esp-idf/commit/af48977f21cea6b18dae10b2c8b64a78acfc647f)) +- use const char* for mdns txt items types to remove warning when assigning ([84cbb1f](https://github.com/espressif/esp-protocols/commit/84cbb1f), [IDF@c050a75](https://github.com/espressif/esp-idf/commit/c050a75616803c7871ef11c060e440fae09000d9)) +- updated doxygen comments documenting mdns api ([4c6818e](https://github.com/espressif/esp-protocols/commit/4c6818e), [IDF#1718](https://github.com/espressif/esp-idf/issues/1718), [IDF@a851aac](https://github.com/espressif/esp-idf/commit/a851aac255311124529f504486ca55bad15c1951)) +- update mdns_out_question_s to be in line with mdns_parsed_question_s struct ([c440114](https://github.com/espressif/esp-protocols/commit/c440114), [IDF#1568]( https://github.com/espressif/esp-idf/issues/1568), [IDF@eddd5c4](https://github.com/espressif/esp-idf/commit/eddd5c4f2c686d9a1d6d3258569cc33752e78880)) +- use esp_event library to handle events ([6ea0ea9](https://github.com/espressif/esp-protocols/commit/6ea0ea9), [IDF@a2d5952](https://github.com/espressif/esp-idf/commit/a2d59525e53099ee1ad63c3d60ff853f573ab535)) +- fuzzer tests: update of mdns and lwip host compilation for fuzzer testing ([d9aec9f](https://github.com/espressif/esp-protocols/commit/d9aec9f), [IDF@bc60bbb](https://github.com/espressif/esp-idf/commit/bc60bbbeaf89f2bbfc5db4bd4f1e7ace81a2ab37)) +- fix possible crash when probing on particular interface with duplicated service instances due to naming conflicts on network ([985e691](https://github.com/espressif/esp-protocols/commit/985e691), [IDF@265e983](https://github.com/espressif/esp-idf/commit/265e983a452a7eaefc1662cdc0e6ed839a37fe1a)) +- enable pcbs before starting service thread to avoid updating pcb's internal variables from concurent tasks ([75deebb](https://github.com/espressif/esp-protocols/commit/75deebb), [IDF@c87f0cb](https://github.com/espressif/esp-idf/commit/c87f0cb6cad3c36b077f4aaeb1ca52fe6ed0cdaf)) +- fix possible deadlock on mdns deinit calling mdns_free() ([fdd27dc](https://github.com/espressif/esp-protocols/commit/fdd27dc), [IDF#1696](https://github.com/espressif/esp-idf/issues/1696), [IDF@48b5501](https://github.com/espressif/esp-idf/commit/48b5501c250ed90da51a55ad4fc18e09f466a517)) +- mdsn: fix race condition in updating packet data from user task when failed to allocate or queue a new service ([2ec3b55](https://github.com/espressif/esp-protocols/commit/2ec3b55), [IDF@021dc5d](https://github.com/espressif/esp-idf/commit/021dc5d453e21e2d1707f194668e69cf63ef4e84)) +- fix possible crash when packet scheduled to transmit contained service which might have been already removed ([450cbf0](https://github.com/espressif/esp-protocols/commit/450cbf0), [IDF@67051a2](https://github.com/espressif/esp-idf/commit/67051a286ba60a01d4755c3682129153c2f95953)) +- use binary semaphore instead of mutex when searching ([34f6d8d](https://github.com/espressif/esp-protocols/commit/34f6d8d), [IDF@eef0b50](https://github.com/espressif/esp-idf/commit/eef0b5090aee87efef1a6a37772b3b88c9ce8df8)) +- fix memory leak in pbuf if tcpipadapter failed to get netif ([b6efc68](https://github.com/espressif/esp-protocols/commit/b6efc68), [IDF@8462751](https://github.com/espressif/esp-idf/commit/8462751f95a3ff18bdc1b01d02fabd1829fd9135)) +- fix malfuctional query_txt ([90e4bab](https://github.com/espressif/esp-protocols/commit/90e4bab), [IDF@1a02773](https://github.com/espressif/esp-idf/commit/1a027734af06abf08fcb1c34ee65bdf50d12be4d)) +- fix possible crash when mdns_free called while action queue not empty ([c546ab8](https://github.com/espressif/esp-protocols/commit/c546ab8), [IDF@206b47c](https://github.com/espressif/esp-idf/commit/206b47c03aca0acdf40d1d9c250e18aeddfe1bd7)) +- fix memory leak when query for service receives multiple ptr entries for one instance ([6582b41](https://github.com/espressif/esp-protocols/commit/6582b41), [IDF@9a4da97](https://github.com/espressif/esp-idf/commit/9a4da97fb4b3c241998cb969a08c3a917ffb4cd1)) +- fix crash after init if no memory for task ([358d26c](https://github.com/espressif/esp-protocols/commit/358d26c), [IDF@a47768d](https://github.com/espressif/esp-idf/commit/a47768dc4e4750fd7e1c29b15d6e2dd3c76e6591)) +- fixed crash on free undefined ptr after skipped strdup ([2ac83d0](https://github.com/espressif/esp-protocols/commit/2ac83d0), [IDF@e0a8044](https://github.com/espressif/esp-idf/commit/e0a8044a16907e642001b883469618a999dbe6db)) +- Correct Kconfigs according to the coding style ([98e3171](https://github.com/espressif/esp-protocols/commit/98e3171), [IDF@37126d3](https://github.com/espressif/esp-idf/commit/37126d3451eabb44eeeb48b8e2ee554dc233e2a8)) +- fix networking running udp_sendif from lwip thread ([2f85c07](https://github.com/espressif/esp-protocols/commit/2f85c07), [IDF@f7d4a4b](https://github.com/espressif/esp-idf/commit/f7d4a4be6a9e0b0ac5edb9400d3b123dbbed2ffc)) +- fixed static memory leak ([b30a7fe](https://github.com/espressif/esp-protocols/commit/b30a7fe), [IDF@6bb68a5](https://github.com/espressif/esp-idf/commit/6bb68a5a7567a94c3605136d44960ff060c74663)) +- check all mallocs for failure and add default hook to log error with free heap ([7a4fdad](https://github.com/espressif/esp-protocols/commit/7a4fdad), [IDF@c8cb4cd](https://github.com/espressif/esp-idf/commit/c8cb4cd3c8eb56d5901ade03302ad1231d7f3de5)) +- resolve memory leak when txt record received multiple times ([b4e5742](https://github.com/espressif/esp-protocols/commit/b4e5742), [IDF@a6b2b73](https://github.com/espressif/esp-idf/commit/a6b2b73f03bbb75a39685ddba6cf877fd1e5e6d7)) +- skip sending search when finished, not properly locked timer task ([2763bcd](https://github.com/espressif/esp-protocols/commit/2763bcd), [IDF@31163f0](https://github.com/espressif/esp-idf/commit/31163f02d5c414d8b492dce6f729b43a0061581b)) +- sending search packets also in probing and announcing state ([8cd0e8a](https://github.com/espressif/esp-protocols/commit/8cd0e8a), [IDF@d16762a](https://github.com/espressif/esp-idf/commit/d16762a036e35ce86ece86bb44e6e99f9cc7c431)) +- fixed crashes on network changes ([9b3b41c](https://github.com/espressif/esp-protocols/commit/9b3b41c), [IDF@097282a](https://github.com/espressif/esp-idf/commit/097282a8e3f85958747430d9931ce0a545d37700)) +- Update network code for mDNS to work with newest LwIP ([ea23007](https://github.com/espressif/esp-protocols/commit/ea23007), [IDF@3ec0e7e](https://github.com/espressif/esp-idf/commit/3ec0e7e2d2ddea70e9f8fb5025664d0fe24c301a)) +- bugfix: mdns_service_txt_set() wasn't allocating memory for TXT records ([0c17121](https://github.com/espressif/esp-protocols/commit/0c17121), [IDF@e5e2702](https://github.com/espressif/esp-idf/commit/e5e2702ca3f63a29da57eb138f75a20c74fb2a94)) +- cmake: make main a component again ([67173f6](https://github.com/espressif/esp-protocols/commit/67173f6), [IDF@d9939ce](https://github.com/espressif/esp-idf/commit/d9939cedd9b44d63dc148354c3a0a139b9c7113d)) +- Feature/sync lwip as submodule ([fed787f](https://github.com/espressif/esp-protocols/commit/fed787f), [IDF@3578fe3](https://github.com/espressif/esp-idf/commit/3578fe39e01ba0c2d54824ac70c3276502661c6b)) +- Fix a portion of the queries are issued with the wildcard query type ([b4ab30b](https://github.com/espressif/esp-protocols/commit/b4ab30b), [IDF@f3f0445](https://github.com/espressif/esp-idf/commit/f3f0445f4db7c9ad97ae10a9728767337aa7bb62)) +- added CI job for AFL fuzzer tests ([dd71494](https://github.com/espressif/esp-protocols/commit/dd71494), [IDF@0c14764](https://github.com/espressif/esp-idf/commit/0c147648f7642d058b63fbe2ddd5de31c2326304)) +- Minor fix for mdns_service_remove() ([39de491](https://github.com/espressif/esp-protocols/commit/39de491), [IDF@5c7eb7e](https://github.com/espressif/esp-idf/commit/5c7eb7e27be7508130459d896cf7d13ffefda87f)) +- Replace all DOS line endings with Unix ([19acac7](https://github.com/espressif/esp-protocols/commit/19acac7), [IDF@a67d5d8](https://github.com/espressif/esp-idf/commit/a67d5d89e0e90390fa7ff02816a6a79008d75d40)) +- remove executable permission from source files ([98069f9](https://github.com/espressif/esp-protocols/commit/98069f9), [IDF@cb649e4](https://github.com/espressif/esp-idf/commit/cb649e452f3c64a7db1f4a61e162a16b70248204)) +- Fixed nullptr dereference in MDNS.c ([ad29d34](https://github.com/espressif/esp-protocols/commit/ad29d34), [IDF@fffbf7b](https://github.com/espressif/esp-idf/commit/fffbf7b75065b5852e064e04b0c5102dd0fc2244)) +- MDNS-Fuzzer: AFL fuzzer tests for mdsn packet parser ([9f1be36](https://github.com/espressif/esp-protocols/commit/9f1be36), [IDF@e983230](https://github.com/espressif/esp-idf/commit/e983230be933fb83cebdd1945ba6539a7dc99b28)) +- cmake: Add component dependency support ([c7701d4](https://github.com/espressif/esp-protocols/commit/c7701d4), [IDF@1cb5712](https://github.com/espressif/esp-idf/commit/1cb5712463a8963cd3e8331da90fb5e03f13575f)) +- cmake: Remove defaults for COMPONENT_SRCDIRS, COMPONENT_SRCS, COMPONENT_ADD_INCLUDEDIRS ([f1ccc40](https://github.com/espressif/esp-protocols/commit/f1ccc40), [IDF@4f1a856](https://github.com/espressif/esp-idf/commit/4f1a856dbfd752336cd71730105e02ad8c045541)) +- build system: Initial cmake support, work in progress ([84bd1d7](https://github.com/espressif/esp-protocols/commit/84bd1d7), [IDF@c671a0c](https://github.com/espressif/esp-idf/commit/c671a0c3ebf90f18576d6db55b51b62730c58301)) +- fix the bug that in mdns test code redefine esp_err_t to uint32_t, which should be int32_t ([259d3fc](https://github.com/espressif/esp-protocols/commit/259d3fc), [IDF@81e4cad](https://github.com/espressif/esp-idf/commit/81e4cad61593cde879a5c44a08060d9d336e5a3f)) +- Fix exception when service is removed while there are pending packets that depend on it ([7784d00](https://github.com/espressif/esp-protocols/commit/7784d00), [IDF@421c6f1](https://github.com/espressif/esp-idf/commit/421c6f154b10d9253b78875ab28ee6bdcaaaf3c0)) +- Fix case where service is NULL and that will cause exception ([bce7d52](https://github.com/espressif/esp-protocols/commit/bce7d52), [IDF@4fa130a](https://github.com/espressif/esp-idf/commit/4fa130ae4fb5de99ddddc5a7bed7e26ae645591c)) +- Fix issue with some mDNS parsers ([ef924f1](https://github.com/espressif/esp-protocols/commit/ef924f1), [IDF@51dde19](https://github.com/espressif/esp-idf/commit/51dde19a765533af67fc7be21f116641773a9be4)) +- Import mDNS changes ([ad8c92d](https://github.com/espressif/esp-protocols/commit/ad8c92d), [IDF@4bddbc0](https://github.com/espressif/esp-idf/commit/4bddbc031cee83935c0e4df1dc72cc7000c97ba5)) +- Fix compilation errors when using gcc-7.2.0 for the crosstool-ng toolchain ([3aa605f](https://github.com/espressif/esp-protocols/commit/3aa605f), [IDF@519edc3](https://github.com/espressif/esp-idf/commit/519edc332dae0160069fd790467cde8de78f1a0e)) +- components/mdns: wrong Message compression detect ([00a72b8](https://github.com/espressif/esp-protocols/commit/00a72b8), [IDF@6e24566](https://github.com/espressif/esp-idf/commit/6e24566186c52dc5432b6b25c81abda577c21e85)) +- fix leak after _mdns_create_service if we have a malloc error. ([907e7ee](https://github.com/espressif/esp-protocols/commit/907e7ee), [IDF@b6b36bd](https://github.com/espressif/esp-idf/commit/b6b36bd9ddf169039a5528f8b766048d97b975f7)) +- Use LwIP IPC for low-level API calls ([b367484](https://github.com/espressif/esp-protocols/commit/b367484), [IDF@713964f](https://github.com/espressif/esp-idf/commit/713964fe9e98b4fa34145c497b7ab638dc57614c)) +- Add AFL fuzz test ([4a8582f](https://github.com/espressif/esp-protocols/commit/4a8582f), [IDF@4c26227](https://github.com/espressif/esp-idf/commit/4c2622755d92efa1818d062d433725553437993c)) +- implement fixes for issues found while fuzz testing ([75de31c](https://github.com/espressif/esp-protocols/commit/75de31c), [IDF@99d3990](https://github.com/espressif/esp-idf/commit/99d39909c4f19c63909d663e927ac0a8933a3ed5)) +- add simple dns-sd meta query support ([4acf639](https://github.com/espressif/esp-protocols/commit/4acf639), [IDF@96e8a3c](https://github.com/espressif/esp-idf/commit/96e8a3c725095562d2725aaefa15adcfc5d78dd5)) +- address security issues with mDNS ([91bb509](https://github.com/espressif/esp-protocols/commit/91bb509), [IDF@c89e11c](https://github.com/espressif/esp-idf/commit/c89e11c8fa64641edddf9a055745d825ae3fab9d)) +- Initial mDNS component and example ([7fbf8e5](https://github.com/espressif/esp-protocols/commit/7fbf8e5), [IDF@dd3f18d](https://github.com/espressif/esp-idf/commit/dd3f18d2d88ee78909d4af2840dfdf0b9f715f28)) diff --git a/managed_components/espressif__mdns/CMakeLists.txt b/managed_components/espressif__mdns/CMakeLists.txt new file mode 100644 index 0000000..e0b2a4d --- /dev/null +++ b/managed_components/espressif__mdns/CMakeLists.txt @@ -0,0 +1,38 @@ +if(CONFIG_MDNS_NETWORKING_SOCKET) + set(MDNS_NETWORKING "mdns_networking_socket.c") +else() + set(MDNS_NETWORKING "mdns_networking_lwip.c") +endif() + +if(CONFIG_MDNS_ENABLE_CONSOLE_CLI) + set(MDNS_CONSOLE "mdns_console.c") +else() + set(MDNS_CONSOLE "") +endif() + +idf_build_get_property(target IDF_TARGET) +if(${target} STREQUAL "linux") + set(dependencies esp_netif_linux esp_event) + set(private_dependencies esp_timer console esp_system) + set(srcs "mdns.c" ${MDNS_NETWORKING} ${MDNS_CONSOLE}) +else() + set(dependencies lwip console esp_netif) + set(private_dependencies esp_timer esp_wifi) + set(srcs "mdns.c" ${MDNS_NETWORKING} ${MDNS_CONSOLE}) +endif() + +idf_component_register( + SRCS ${srcs} + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "private_include" + REQUIRES ${dependencies} + PRIV_REQUIRES ${private_dependencies}) + +if(${target} STREQUAL "linux") + target_link_libraries(${COMPONENT_LIB} PRIVATE "-lbsd") +endif() + + +if(CONFIG_ETH_ENABLED) + idf_component_optional_requires(PRIVATE esp_eth) +endif() diff --git a/managed_components/espressif__mdns/Kconfig b/managed_components/espressif__mdns/Kconfig new file mode 100644 index 0000000..3ef88c8 --- /dev/null +++ b/managed_components/espressif__mdns/Kconfig @@ -0,0 +1,148 @@ +menu "mDNS" + + config MDNS_MAX_INTERFACES + int "Max number of interfaces" + range 1 9 + default 3 + help + Number of network interfaces to be served by the mDNS library. + Lowering this number helps to reduce some static RAM usage. + + config MDNS_MAX_SERVICES + int "Max number of services" + default 10 + help + Services take up a certain amount of memory, and allowing fewer + services to be open at the same time conserves memory. Specify + the maximum amount of services here. + + config MDNS_TASK_PRIORITY + int "mDNS task priority" + range 1 255 + default 1 + help + Allows setting mDNS task priority. Please do not set the task priority + higher than priorities of system tasks. Compile time warning/error + would be emitted if the chosen task priority were too high. + + config MDNS_ACTION_QUEUE_LEN + int "Maximum actions pending to the server" + range 8 64 + default 16 + help + Allows setting the length of mDNS action queue. + + config MDNS_TASK_STACK_SIZE + int "mDNS task stack size" + default 4096 + help + Allows setting mDNS task stacksize. + + choice MDNS_TASK_AFFINITY + prompt "mDNS task affinity" + default MDNS_TASK_AFFINITY_CPU0 + help + Allows setting mDNS tasks affinity, i.e. whether the task is pinned to + CPU0, pinned to CPU1, or allowed to run on any CPU. + + config MDNS_TASK_AFFINITY_NO_AFFINITY + bool "No affinity" + config MDNS_TASK_AFFINITY_CPU0 + bool "CPU0" + config MDNS_TASK_AFFINITY_CPU1 + bool "CPU1" + depends on !FREERTOS_UNICORE + + endchoice + + config MDNS_TASK_AFFINITY + hex + default FREERTOS_NO_AFFINITY if MDNS_TASK_AFFINITY_NO_AFFINITY + default 0x0 if MDNS_TASK_AFFINITY_CPU0 + default 0x1 if MDNS_TASK_AFFINITY_CPU1 + + config MDNS_SERVICE_ADD_TIMEOUT_MS + int "mDNS adding service timeout (ms)" + range 10 30000 + default 2000 + help + Configures timeout for adding a new mDNS service. Adding a service + fails if could not be completed within this time. + + config MDNS_TIMER_PERIOD_MS + int "mDNS timer period (ms)" + range 10 10000 + default 100 + help + Configures period of mDNS timer, which periodically transmits packets + and schedules mDNS searches. + + config MDNS_NETWORKING_SOCKET + bool "Use BSD sockets for mDNS networking" + default n + help + Enables optional mDNS networking implementation using BSD sockets + in UDP multicast mode. + This option creates a new thread to serve receiving packets (TODO). + This option uses additional N sockets, where N is number of interfaces. + + config MDNS_SKIP_SUPPRESSING_OWN_QUERIES + bool "Skip suppressing our own packets" + default n + help + Enable only if the querier and the responder share the same IP address. + This usually happens in test mode, where we may run multiple instances of + responders/queriers on the same interface. + + config MDNS_ENABLE_DEBUG_PRINTS + bool "Enable debug prints of mDNS packets" + default n + help + Enable for the library to log received and sent mDNS packets to stdout. + + config MDNS_ENABLE_CONSOLE_CLI + bool "Enable Command Line Interface on device console" + default y + help + Enable for the console cli to be available on the device. + + config MDNS_RESPOND_REVERSE_QUERIES + bool "Enable responding to IPv4 reverse queries" + default n + help + Enables support for IPv4 reverse lookup. If enabled, the mDNS library + response to PTR queries of "A.B.C.D.in-addr.arpa" type. + + config MDNS_MULTIPLE_INSTANCE + bool "Multiple instances under the same service type" + default y + help + Enables adding multiple service instances under the same service type. + + menu "MDNS Predefined interfaces" + + config MDNS_PREDEF_NETIF_STA + bool "Use predefined interface for WiFi Station" + default y + help + Set up mDNS for the default WiFi station. + Disable this option if you do not need mDNS on default WiFi STA. + + config MDNS_PREDEF_NETIF_AP + bool "Use predefined interface for WiFi Access Point" + default y + help + Set up mDNS for the default WiFi Access Point. + Disable this option if you do not need mDNS on default WiFi AP. + + config MDNS_PREDEF_NETIF_ETH + bool "Use predefined interface for Ethernet" + depends on ETH_ENABLED + default y + help + Set up mDNS for the default Ethernet interface. + Disable this option if you do not need mDNS on default Ethernet. + + endmenu # MDNS Predefined interfaces + +endmenu diff --git a/managed_components/espressif__mdns/LICENSE b/managed_components/espressif__mdns/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/managed_components/espressif__mdns/LICENSE @@ -0,0 +1,202 @@ + + 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 [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 + + 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. diff --git a/managed_components/espressif__mdns/README.md b/managed_components/espressif__mdns/README.md new file mode 100644 index 0000000..a644ad4 --- /dev/null +++ b/managed_components/espressif__mdns/README.md @@ -0,0 +1,14 @@ +# mDNS Service + +[![Component Registry](https://components.espressif.com/components/espressif/mdns/badge.svg)](https://components.espressif.com/components/espressif/mdns) + +mDNS is a multicast UDP service that is used to provide local network service and host discovery. + +## Examples + +Get started with example test [Example](https://github.com/espressif/esp-protocols/tree/master/components/mdns/examples): + +## Documentation + +* View the full [documentation(English)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/en/index.html) +* View the full [documentation(Chinese)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/zh_CN/index.html) diff --git a/managed_components/espressif__mdns/examples/query_advertise/CMakeLists.txt b/managed_components/espressif__mdns/examples/query_advertise/CMakeLists.txt new file mode 100644 index 0000000..9a16f14 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(query_advertise) diff --git a/managed_components/espressif__mdns/examples/query_advertise/README.md b/managed_components/espressif__mdns/examples/query_advertise/README.md new file mode 100644 index 0000000..6ccdef9 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/README.md @@ -0,0 +1,91 @@ +# mDNS example + +Shows how to use mDNS to advertise and query services and hosts + +## Example workflow + +- mDNS is initialized with host name and instance name defined through the project configuration and `_http._tcp` service is added to be advertised +- A delegated host `esp32-delegated._local` is added and another `_http._tcp` service is added for this host. +- WiFi STA is started and trying to connect to the access point defined through the project configuration +- The system event handler is used to pass the network events to mDNS so the service is aware when the interface comes up or down +- GPIO0 (BOOT Button) is initialized as pulled-up input that can be monitored for button press +- Example task is started to check if the button is pressed so it can execute the mDNS queries defined + +### Configure the project + +* Open the project configuration menu (`idf.py menuconfig`) + +* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu +* Set `mDNS Hostname` as host name prefix for the device and its instance name in `mDNS Instance Name` +* Disable `Resolve test services` to prevent the example from querying defined names/services on startup (cause warnings in example logs, as illustrated below) + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +- Wait for WiFi to connect to your access point +- You can now ping the device at `[board-hostname].local`, where `[board-hostname]` is preconfigured hostname, `esp32-mdns` by default. +- You can also browse for `_http._tcp` on the same network to find the advertised service +- Pressing the BOOT button will start querying the local network for the predefined in `check_button` hosts and services +- Note that for purpose of CI tests, configuration options of `MDNS_RESOLVE_TEST_SERVICES` and `MDNS_ADD_MAC_TO_HOSTNAME` are available, but disabled by default. If enabled, then the hostname suffix of last 3 bytes from device MAC address is added, e.g. `esp32-mdns-80FFFF`, and a query for test service is issued. + + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output +``` +I (0) cpu_start: Starting scheduler on APP CPU. +I (276) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE +I (276) mdns-test: mdns hostname set to: [esp32-mdns] +I (286) wifi: wifi driver task: 3ffc2fa4, prio:23, stack:3584, core=0 +I (286) wifi: wifi firmware version: a3be639 +I (286) wifi: config NVS flash: enabled +I (296) wifi: config nano formating: disabled +I (296) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE +I (306) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE +I (336) wifi: Init dynamic tx buffer num: 32 +I (336) wifi: Init data frame dynamic rx buffer num: 32 +I (336) wifi: Init management frame dynamic rx buffer num: 32 +I (346) wifi: Init static rx buffer size: 1600 +I (346) wifi: Init static rx buffer num: 10 +I (346) wifi: Init dynamic rx buffer num: 32 +I (356) mdns-test: Setting WiFi configuration SSID myssid... +I (426) phy: phy_version: 4000, b6198fa, Sep 3 2018, 15:11:06, 0, 0 +I (426) wifi: mode : sta (30:ae:a4:80:FF:FF) +I (426) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 +I (1756) wifi: n:11 0, o:1 0, ap:255 255, sta:11 0, prof:1 +I (2736) wifi: state: init -> auth (b0) +I (2756) wifi: state: auth -> assoc (0) +I (2766) wifi: state: assoc -> run (10) +I (2786) wifi: connected with myssid, channel 11 +I (2786) wifi: pm start, type: 1 + +I (4786) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2 +I (21126) mdns-test: Query A: esp32.local +W (23176) mdns-test: ESP_ERR_NOT_FOUND: Host was not found! +I (23176) mdns-test: Query PTR: _arduino._tcp.local +W (26276) mdns-test: No results found! +I (26276) mdns-test: Query PTR: _http._tcp.local +1: Interface: STA, Type: V6 + PTR : HP Color LaserJet MFP M277dw (7C2E10) + SRV : NPI7C2E10.local:80 + A : 254.128.0.0 +2: Interface: STA, Type: V4 + PTR : switch4e4919 + SRV : switch4e4919.local:80 + TXT : [1] path=/config/authentication_page.htm; + A : 192.168.0.118 +I (29396) mdns-test: Query PTR: _printer._tcp.local +1: Interface: STA, Type: V6 + PTR : HP Color LaserJet MFP M277dw (7C2E10) + SRV : NPI7C2E10.local:515 + A : 254.128.0.0 +2: Interface: STA, Type: V4 + PTR : HP Color LaserJet MFP M277dw (7C2E10) +``` diff --git a/managed_components/espressif__mdns/examples/query_advertise/main/CMakeLists.txt b/managed_components/espressif__mdns/examples/query_advertise/main/CMakeLists.txt new file mode 100644 index 0000000..eb0e6d9 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "mdns_example_main.c" + INCLUDE_DIRS ".") diff --git a/managed_components/espressif__mdns/examples/query_advertise/main/Kconfig.projbuild b/managed_components/espressif__mdns/examples/query_advertise/main/Kconfig.projbuild new file mode 100644 index 0000000..18e1cc2 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/main/Kconfig.projbuild @@ -0,0 +1,55 @@ +menu "Example Configuration" + + orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps" + + config MDNS_HOSTNAME + string "mDNS Hostname" + default "esp32-mdns" + help + mDNS Hostname for example to use + + config MDNS_INSTANCE + string "mDNS Instance Name" + default "ESP32 with mDNS" + help + mDNS Instance Name for example to use + + config MDNS_PUBLISH_DELEGATE_HOST + bool "Publish a delegated host" + help + Enable publishing a delegated host other than ESP32. + The example will also add a mock service for this host. + + config MDNS_RESOLVE_TEST_SERVICES + bool "Resolve test services" + default n + help + Enable resolving test services on startup. + These services are advertized and evaluated in automated tests. + When executed locally, these will not be resolved and warnings appear in the log. + Please set to false to disable initial querying to avoid warnings. + + config MDNS_ADD_MAC_TO_HOSTNAME + bool "Add mac suffix to hostname" + default n + help + If enabled, a portion of MAC address is added to the hostname, this is used + for evaluation of tests in CI + + config MDNS_BUTTON_GPIO + int "Button GPIO to trigger querries" + range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX + default 0 + help + Set the GPIO number used as mDNS test button + + config MDNS_ADD_CUSTOM_NETIF + bool "Add user netif to mdns service" + default n + help + If enabled, we try to add a custom netif to mdns service. + Note that for using with common connection example code, we have to disable + all predefined interfaces in mdns component setup (since we're adding one + of the default interfaces) + +endmenu diff --git a/managed_components/espressif__mdns/examples/query_advertise/main/idf_component.yml b/managed_components/espressif__mdns/examples/query_advertise/main/idf_component.yml new file mode 100644 index 0000000..e9277df --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/main/idf_component.yml @@ -0,0 +1,8 @@ +dependencies: + ## Required IDF version + idf: ">=5.0" + espressif/mdns: + version: "^1.0.0" + override_path: "../../../" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/managed_components/espressif__mdns/examples/query_advertise/main/mdns_example_main.c b/managed_components/espressif__mdns/examples/query_advertise/main/mdns_example_main.c new file mode 100644 index 0000000..a6aaea2 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/main/mdns_example_main.c @@ -0,0 +1,421 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +/* + * MDNS-SD Query and advertise Example +*/ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_netif_ip_addr.h" +#include "esp_mac.h" +#include "esp_event.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_netif.h" +#include "protocol_examples_common.h" +#include "mdns.h" +#include "driver/gpio.h" +#include "netdb.h" + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0) +/* CONFIG_LWIP_IPV4 was introduced in IDF v5.1, set CONFIG_LWIP_IPV4 to 1 by default for IDF v5.0 */ +#ifndef CONFIG_LWIP_IPV4 +#define CONFIG_LWIP_IPV4 1 +#endif // CONFIG_LWIP_IPV4 +#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0) + +#define EXAMPLE_MDNS_INSTANCE CONFIG_MDNS_INSTANCE +#define EXAMPLE_BUTTON_GPIO CONFIG_MDNS_BUTTON_GPIO + +static const char *TAG = "mdns-test"; +static char *generate_hostname(void); + +#if CONFIG_MDNS_RESOLVE_TEST_SERVICES == 1 +static void query_mdns_host_with_gethostbyname(char *host); +static void query_mdns_host_with_getaddrinfo(char *host); +#endif + +static void initialise_mdns(void) +{ + char *hostname = generate_hostname(); + + //initialize mDNS + ESP_ERROR_CHECK( mdns_init() ); + //set mDNS hostname (required if you want to advertise services) + ESP_ERROR_CHECK( mdns_hostname_set(hostname) ); + ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname); + //set default mDNS instance name + ESP_ERROR_CHECK( mdns_instance_name_set(EXAMPLE_MDNS_INSTANCE) ); + + //structure with TXT records + mdns_txt_item_t serviceTxtData[3] = { + {"board", "esp32"}, + {"u", "user"}, + {"p", "password"} + }; + + //initialize service + ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData, 3) ); + ESP_ERROR_CHECK( mdns_service_subtype_add_for_host("ESP32-WebServer", "_http", "_tcp", NULL, "_server") ); +#if CONFIG_MDNS_MULTIPLE_INSTANCE + ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer1", "_http", "_tcp", 80, NULL, 0) ); +#endif + +#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST + char *delegated_hostname; + if (-1 == asprintf(&delegated_hostname, "%s-delegated", hostname)) { + abort(); + } + + mdns_ip_addr_t addr4, addr6; + esp_netif_str_to_ip4("10.0.0.1", &addr4.addr.u_addr.ip4); + addr4.addr.type = ESP_IPADDR_TYPE_V4; + esp_netif_str_to_ip6("fd11:22::1", &addr6.addr.u_addr.ip6); + addr6.addr.type = ESP_IPADDR_TYPE_V6; + addr4.next = &addr6; + addr6.next = NULL; + ESP_ERROR_CHECK( mdns_delegate_hostname_add(delegated_hostname, &addr4) ); + ESP_ERROR_CHECK( mdns_service_add_for_host("test0", "_http", "_tcp", delegated_hostname, 1234, serviceTxtData, 3) ); + free(delegated_hostname); +#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST + + //add another TXT item + ESP_ERROR_CHECK( mdns_service_txt_item_set("_http", "_tcp", "path", "/foobar") ); + //change TXT item value + ESP_ERROR_CHECK( mdns_service_txt_item_set_with_explicit_value_len("_http", "_tcp", "u", "admin", strlen("admin")) ); + free(hostname); +} + +/* these strings match mdns_ip_protocol_t enumeration */ +static const char *ip_protocol_str[] = {"V4", "V6", "MAX"}; + +static void mdns_print_results(mdns_result_t *results) +{ + mdns_result_t *r = results; + mdns_ip_addr_t *a = NULL; + int i = 1, t; + while (r) { + if (r->esp_netif) { + printf("%d: Interface: %s, Type: %s, TTL: %" PRIu32 "\n", i++, esp_netif_get_ifkey(r->esp_netif), + ip_protocol_str[r->ip_protocol], r->ttl); + } + if (r->instance_name) { + printf(" PTR : %s.%s.%s\n", r->instance_name, r->service_type, r->proto); + } + if (r->hostname) { + printf(" SRV : %s.local:%u\n", r->hostname, r->port); + } + if (r->txt_count) { + printf(" TXT : [%zu] ", r->txt_count); + for (t = 0; t < r->txt_count; t++) { + printf("%s=%s(%d); ", r->txt[t].key, r->txt[t].value ? r->txt[t].value : "NULL", r->txt_value_len[t]); + } + printf("\n"); + } + a = r->addr; + while (a) { + if (a->addr.type == ESP_IPADDR_TYPE_V6) { + printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); + } else { + printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); + } + a = a->next; + } + r = r->next; + } +} + +static void query_mdns_service(const char *service_name, const char *proto) +{ + ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto); + + mdns_result_t *results = NULL; + esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results); + if (err) { + ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); + return; + } + if (!results) { + ESP_LOGW(TAG, "No results found!"); + return; + } + + mdns_print_results(results); + mdns_query_results_free(results); +} + +#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST +static void lookup_mdns_delegated_service(const char *service_name, const char *proto) +{ + ESP_LOGI(TAG, "Lookup delegated service: %s.%s.local", service_name, proto); + + mdns_result_t *results = NULL; + esp_err_t err = mdns_lookup_delegated_service(NULL, service_name, proto, 20, &results); + if (err) { + ESP_LOGE(TAG, "Lookup Failed: %s", esp_err_to_name(err)); + return; + } + if (!results) { + ESP_LOGW(TAG, "No results found!"); + return; + } + + mdns_print_results(results); + mdns_query_results_free(results); +} +#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST + +static void lookup_mdns_selfhosted_service(const char *service_name, const char *proto) +{ + ESP_LOGI(TAG, "Lookup selfhosted service: %s.%s.local", service_name, proto); + mdns_result_t *results = NULL; + esp_err_t err = mdns_lookup_selfhosted_service(NULL, service_name, proto, 20, &results); + if (err) { + ESP_LOGE(TAG, "Lookup Failed: %s", esp_err_to_name(err)); + return; + } + if (!results) { + ESP_LOGW(TAG, "No results found!"); + return; + } + mdns_print_results(results); + mdns_query_results_free(results); +} + +static bool check_and_print_result(mdns_search_once_t *search) +{ + // Check if any result is available + mdns_result_t *result = NULL; + if (!mdns_query_async_get_results(search, 0, &result, NULL)) { + return false; + } + + if (!result) { // search timeout, but no result + return true; + } + + // If yes, print the result + mdns_ip_addr_t *a = result->addr; + while (a) { + if (a->addr.type == ESP_IPADDR_TYPE_V6) { + printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); + } else { + printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); + } + a = a->next; + } + // and free the result + mdns_query_results_free(result); + return true; +} + +static void query_mdns_hosts_async(const char *host_name) +{ + ESP_LOGI(TAG, "Query both A and AAA: %s.local", host_name); + + mdns_search_once_t *s_a = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_A, 1000, 1, NULL); + mdns_search_once_t *s_aaaa = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_AAAA, 1000, 1, NULL); + while (s_a || s_aaaa) { + if (s_a && check_and_print_result(s_a)) { + ESP_LOGI(TAG, "Query A %s.local finished", host_name); + mdns_query_async_delete(s_a); + s_a = NULL; + } + if (s_aaaa && check_and_print_result(s_aaaa)) { + ESP_LOGI(TAG, "Query AAAA %s.local finished", host_name); + mdns_query_async_delete(s_aaaa); + s_aaaa = NULL; + } + vTaskDelay(50 / portTICK_PERIOD_MS); + } +} +#ifdef CONFIG_LWIP_IPV4 +static void query_mdns_host(const char *host_name) +{ + ESP_LOGI(TAG, "Query A: %s.local", host_name); + + struct esp_ip4_addr addr; + addr.addr = 0; + + esp_err_t err = mdns_query_a(host_name, 2000, &addr); + if (err) { + if (err == ESP_ERR_NOT_FOUND) { + ESP_LOGW(TAG, "%s: Host was not found!", esp_err_to_name(err)); + return; + } + ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); + return; + } + + ESP_LOGI(TAG, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr)); +} +#endif // CONFIG_LWIP_IPV4 + +static void initialise_button(void) +{ + gpio_config_t io_conf = {0}; + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.pin_bit_mask = BIT64(EXAMPLE_BUTTON_GPIO); + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = 1; + io_conf.pull_down_en = 0; + gpio_config(&io_conf); +} + +static void check_button(void) +{ + static bool old_level = true; + bool new_level = gpio_get_level(EXAMPLE_BUTTON_GPIO); + if (!new_level && old_level) { + query_mdns_hosts_async("esp32-mdns"); +#ifdef CONFIG_LWIP_IPV4 + query_mdns_host("esp32"); +#endif + query_mdns_service("_arduino", "_tcp"); + query_mdns_service("_http", "_tcp"); + query_mdns_service("_printer", "_tcp"); + query_mdns_service("_ipp", "_tcp"); + query_mdns_service("_afpovertcp", "_tcp"); + query_mdns_service("_smb", "_tcp"); + query_mdns_service("_ftp", "_tcp"); + query_mdns_service("_nfs", "_tcp"); +#if CONFIG_MDNS_PUBLISH_DELEGATE_HOST + lookup_mdns_delegated_service("_http", "_tcp"); +#endif // CONFIG_MDNS_PUBLISH_DELEGATE_HOST + lookup_mdns_selfhosted_service("_http", "_tcp"); + } + old_level = new_level; +} + +static void mdns_example_task(void *pvParameters) +{ +#if CONFIG_MDNS_RESOLVE_TEST_SERVICES == 1 + /* Send initial queries that are started by CI tester */ +#ifdef CONFIG_LWIP_IPV4 + query_mdns_host("tinytester"); +#endif + query_mdns_host_with_gethostbyname("tinytester-lwip.local"); + query_mdns_host_with_getaddrinfo("tinytester-lwip.local"); +#endif + + while (1) { + check_button(); + vTaskDelay(50 / portTICK_PERIOD_MS); + } +} + +void app_main(void) +{ + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + initialise_mdns(); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + +#if defined(CONFIG_MDNS_ADD_CUSTOM_NETIF) && !defined(CONFIG_MDNS_PREDEF_NETIF_STA) && !defined(CONFIG_MDNS_PREDEF_NETIF_ETH) + /* Demonstration of adding a custom netif to mdns service, but we're adding the default example one, + * so we must disable all predefined interfaces (PREDEF_NETIF_STA, AP and ETH) first + */ + ESP_ERROR_CHECK(mdns_register_netif(EXAMPLE_INTERFACE)); + /* It is not enough to just register the interface, we have to enable is manually. + * This is typically performed in "GOT_IP" event handler, but we call it here directly + * since the `EXAMPLE_INTERFACE` netif is connected already, to keep the example simple. + */ + ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ENABLE_IP4 | MDNS_EVENT_ENABLE_IP6)); + ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_ANNOUNCE_IP4 | MDNS_EVENT_ANNOUNCE_IP6)); + +#if defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES) + ESP_ERROR_CHECK(mdns_netif_action(EXAMPLE_INTERFACE, MDNS_EVENT_IP4_REVERSE_LOOKUP | MDNS_EVENT_IP6_REVERSE_LOOKUP)); +#endif + +#endif // CONFIG_MDNS_ADD_CUSTOM_NETIF + + initialise_button(); + xTaskCreate(&mdns_example_task, "mdns_example_task", 2048, NULL, 5, NULL); +} + +/** Generate host name based on sdkconfig, optionally adding a portion of MAC address to it. + * @return host name string allocated from the heap + */ +static char *generate_hostname(void) +{ +#ifndef CONFIG_MDNS_ADD_MAC_TO_HOSTNAME + return strdup(CONFIG_MDNS_HOSTNAME); +#else + uint8_t mac[6]; + char *hostname; + esp_read_mac(mac, ESP_MAC_WIFI_STA); + if (-1 == asprintf(&hostname, "%s-%02X%02X%02X", CONFIG_MDNS_HOSTNAME, mac[3], mac[4], mac[5])) { + abort(); + } + return hostname; +#endif +} + +#if CONFIG_MDNS_RESOLVE_TEST_SERVICES == 1 +/** + * @brief Executes gethostbyname and displays list of resolved addresses. + * Note: This function is used only to test advertised mdns hostnames resolution + */ +static void query_mdns_host_with_gethostbyname(char *host) +{ + struct hostent *res = gethostbyname(host); + if (res) { + unsigned int i = 0; + while (res->h_addr_list[i] != NULL) { + ESP_LOGI(TAG, "gethostbyname: %s resolved to: %s", host, +#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_LWIP_IPV4) + res->h_addrtype == AF_INET ? inet_ntoa(*(struct in_addr *) (res->h_addr_list[i])) : + inet6_ntoa(*(struct in6_addr *) (res->h_addr_list[i])) +#elif defined(CONFIG_LWIP_IPV6) + inet6_ntoa(*(struct in6_addr *) (res->h_addr_list[i])) +#else + inet_ntoa(*(struct in_addr *) (res->h_addr_list[i])) +#endif + ); + i++; + } + } +} + +/** + * @brief Executes getaddrinfo and displays list of resolved addresses. + * Note: This function is used only to test advertised mdns hostnames resolution + */ +static void query_mdns_host_with_getaddrinfo(char *host) +{ + struct addrinfo hints; + struct addrinfo *res; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (!getaddrinfo(host, NULL, &hints, &res)) { + while (res) { + char *resolved_addr; +#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_LWIP_IPV4) + resolved_addr = res->ai_family == AF_INET ? + inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr) : + inet6_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr); +#elif defined(CONFIG_LWIP_IPV6) + resolved_addr = inet6_ntoa(((struct sockaddr_in6 *) res->ai_addr)->sin6_addr); +#else + resolved_addr = inet_ntoa(((struct sockaddr_in *) res->ai_addr)->sin_addr); +#endif // CONFIG_LWIP_IPV6 + ESP_LOGI(TAG, "getaddrinfo: %s resolved to: %s", host, resolved_addr); + res = res->ai_next; + } + } +} +#endif diff --git a/managed_components/espressif__mdns/examples/query_advertise/pytest_mdns.py b/managed_components/espressif__mdns/examples/query_advertise/pytest_mdns.py new file mode 100644 index 0000000..e78e094 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/pytest_mdns.py @@ -0,0 +1,203 @@ +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import re +import select +import socket +import struct +import subprocess +import time +from threading import Event, Thread + +try: + import dpkt + import dpkt.dns +except ImportError: + pass + + +def get_dns_query_for_esp(esp_host): + dns = dpkt.dns.DNS( + b'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01' + ) + dns.qd[0].name = esp_host + u'.local' + print('Created query for esp host: {} '.format(dns.__repr__())) + return dns.pack() + + +def get_dns_answer_to_mdns(tester_host): + dns = dpkt.dns.DNS( + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + ) + dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA + dns.rcode = dpkt.dns.DNS_RCODE_NOERR + arr = dpkt.dns.DNS.RR() + arr.cls = dpkt.dns.DNS_IN + arr.type = dpkt.dns.DNS_A + arr.name = tester_host + arr.ip = socket.inet_aton('127.0.0.1') + dns.an.append(arr) + print('Created answer to mdns query: {} '.format(dns.__repr__())) + return dns.pack() + + +def get_dns_answer_to_mdns_lwip(tester_host, id): + dns = dpkt.dns.DNS( + b'\x5e\x39\x84\x00\x00\x01\x00\x01\x00\x00\x00\x00\x0a\x64\x61\x76\x69\x64' + b'\x2d\x63\x6f\x6d\x70\x05\x6c\x6f\x63\x61\x6c\x00\x00\x01\x00\x01\xc0\x0c' + b'\x00\x01\x00\x01\x00\x00\x00\x0a\x00\x04\xc0\xa8\x0a\x6c') + dns.qd[0].name = tester_host + dns.an[0].name = tester_host + dns.an[0].ip = socket.inet_aton('127.0.0.1') + dns.an[0].rdata = socket.inet_aton('127.0.0.1') + dns.id = id + print('Created answer to mdns (lwip) query: {} '.format(dns.__repr__())) + return dns.pack() + + +def mdns_server(esp_host, events): + UDP_IP = '0.0.0.0' + UDP_PORT = 5353 + MCAST_GRP = '224.0.0.251' + TESTER_NAME = u'tinytester.local' + TESTER_NAME_LWIP = u'tinytester-lwip.local' + QUERY_TIMEOUT = 0.2 + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + sock.setblocking(False) + sock.bind((UDP_IP, UDP_PORT)) + mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY) + sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) + last_query_timepoint = time.time() + while not events['stop'].is_set(): + try: + current_time = time.time() + if current_time - last_query_timepoint > QUERY_TIMEOUT: + last_query_timepoint = current_time + if not events['esp_answered'].is_set(): + sock.sendto(get_dns_query_for_esp(esp_host), + (MCAST_GRP, UDP_PORT)) + if not events['esp_delegated_answered'].is_set(): + sock.sendto(get_dns_query_for_esp(esp_host + '-delegated'), + (MCAST_GRP, UDP_PORT)) + timeout = max( + 0, QUERY_TIMEOUT - (current_time - last_query_timepoint)) + read_socks, _, _ = select.select([sock], [], [], timeout) + if not read_socks: + continue + data, addr = sock.recvfrom(1024) + dns = dpkt.dns.DNS(data) + if len(dns.qd) > 0: + for dns_query in dns.qd: + if dns_query.type == dpkt.dns.DNS_A: + if dns_query.name == TESTER_NAME: + print('Received query: {} '.format(dns.__repr__())) + sock.sendto(get_dns_answer_to_mdns(TESTER_NAME), + (MCAST_GRP, UDP_PORT)) + elif dns_query.name == TESTER_NAME_LWIP: + print('Received query: {} '.format(dns.__repr__())) + sock.sendto( + get_dns_answer_to_mdns_lwip(TESTER_NAME_LWIP, dns.id), + addr) + if len(dns.an) > 0: + for dns_answer in dns.an: + if dns_answer.type == dpkt.dns.DNS_A: + print('Received answer from {}'.format(dns_answer.name)) + if dns_answer.name == esp_host + u'.local': + print('Received answer to esp32-mdns query: {}'.format( + dns.__repr__())) + events['esp_answered'].set() + if dns_answer.name == esp_host + u'-delegated.local': + print('Received answer to esp32-mdns-delegate query: {}'.format( + dns.__repr__())) + events['esp_delegated_answered'].set() + except socket.timeout: + break + except dpkt.UnpackError: + continue + + +def test_examples_protocol_mdns(dut): + """ + steps: | + 1. obtain IP address + init mdns example + 2. get the dut host name (and IP address) + 3. check the mdns name is accessible + 4. check DUT output if mdns advertized host is resolved + 5. check if DUT responds to dig + 6. check the DUT is searchable via reverse IP lookup + """ + + specific_host = dut.expect(r'mdns hostname set to: \[(.*?)\]')[1].decode() + + mdns_server_events = { + 'stop': Event(), + 'esp_answered': Event(), + 'esp_delegated_answered': Event() + } + mdns_responder = Thread(target=mdns_server, + args=(str(specific_host), mdns_server_events)) + ip_addresses = [] + if dut.app.sdkconfig.get('LWIP_IPV4') is True: + ipv4 = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', + timeout=30)[1].decode() + ip_addresses.append(ipv4) + if dut.app.sdkconfig.get('LWIP_IPV6') is True: + ipv6_r = r':'.join((r'[0-9a-fA-F]{4}', ) * 8) + ipv6 = dut.expect(ipv6_r, timeout=30)[0].decode() + ip_addresses.append(ipv6) + print('Connected with IP addresses: {}'.format(','.join(ip_addresses))) + try: + # TODO: Add test for example disabling IPV4 + mdns_responder.start() + if dut.app.sdkconfig.get('LWIP_IPV4') is True: + # 3. check the mdns name is accessible. + if not mdns_server_events['esp_answered'].wait(timeout=30): + raise ValueError( + 'Test has failed: did not receive mdns answer within timeout') + if not mdns_server_events['esp_delegated_answered'].wait(timeout=30): + raise ValueError( + 'Test has failed: did not receive mdns answer for delegated host within timeout' + ) + # 4. check DUT output if mdns advertized host is resolved + dut.expect( + re.compile( + b'mdns-test: Query A: tinytester.local resolved to: 127.0.0.1') + ) + dut.expect( + re.compile( + b'mdns-test: gethostbyname: tinytester-lwip.local resolved to: 127.0.0.1' + )) + dut.expect( + re.compile( + b'mdns-test: getaddrinfo: tinytester-lwip.local resolved to: 127.0.0.1' + )) + # 5. check the DUT answers to `dig` command + dig_output = subprocess.check_output([ + 'dig', '+short', '-p', '5353', '@224.0.0.251', + '{}.local'.format(specific_host) + ]) + print('Resolving {} using "dig" succeeded with:\n{}'.format( + specific_host, dig_output)) + if not ipv4.encode('utf-8') in dig_output: + raise ValueError( + 'Test has failed: Incorrectly resolved DUT hostname using dig' + "Output should've contained DUT's IP address:{}".format(ipv4)) + # 6. check the DUT reverse lookup + if dut.app.sdkconfig.get('MDNS_RESPOND_REVERSE_QUERIES') is True: + for ip_address in ip_addresses: + dig_output = subprocess.check_output([ + 'dig', '+short', '-p', '5353', '@224.0.0.251', '-x', + '{}'.format(ip_address) + ]) + print('Reverse lookup for {} using "dig" succeeded with:\n{}'. + format(ip_address, dig_output)) + if specific_host not in dig_output.decode(): + raise ValueError( + 'Test has failed: Incorrectly resolved DUT IP address using dig' + "Output should've contained DUT's name:{}".format( + specific_host)) + + finally: + mdns_server_events['stop'].set() + mdns_responder.join() diff --git a/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_custom_netif b/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_custom_netif new file mode 100644 index 0000000..b9d7120 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_custom_netif @@ -0,0 +1,20 @@ +CONFIG_IDF_TARGET="esp32" +CONFIG_MDNS_RESOLVE_TEST_SERVICES=y +CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y +CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y +CONFIG_MDNS_PREDEF_NETIF_STA=n +CONFIG_MDNS_PREDEF_NETIF_AP=n +CONFIG_MDNS_PREDEF_NETIF_ETH=n +CONFIG_MDNS_ADD_CUSTOM_NETIF=y +CONFIG_MDNS_RESPOND_REVERSE_QUERIES=y +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +CONFIG_EXAMPLE_CONNECT_ETHERNET=y +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y +CONFIG_EXAMPLE_ETH_PHY_IP101=y +CONFIG_EXAMPLE_ETH_MDC_GPIO=23 +CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 +CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 +CONFIG_EXAMPLE_ETH_PHY_ADDR=1 +CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_MDNS_BUTTON_GPIO=32 diff --git a/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_def b/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_def new file mode 100644 index 0000000..703b454 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_def @@ -0,0 +1,15 @@ +CONFIG_IDF_TARGET="esp32" +CONFIG_MDNS_RESOLVE_TEST_SERVICES=y +CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y +CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +CONFIG_EXAMPLE_CONNECT_ETHERNET=y +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y +CONFIG_EXAMPLE_ETH_PHY_IP101=y +CONFIG_EXAMPLE_ETH_MDC_GPIO=23 +CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 +CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 +CONFIG_EXAMPLE_ETH_PHY_ADDR=1 +CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_MDNS_BUTTON_GPIO=32 diff --git a/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_no_ipv4 b/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_no_ipv4 new file mode 100644 index 0000000..b77a752 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_no_ipv4 @@ -0,0 +1,15 @@ +CONFIG_IDF_TARGET="esp32" +CONFIG_MDNS_RESOLVE_TEST_SERVICES=y +CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y +CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +CONFIG_LWIP_IPV4=n +CONFIG_EXAMPLE_CONNECT_ETHERNET=y +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y +CONFIG_EXAMPLE_ETH_PHY_IP101=y +CONFIG_EXAMPLE_ETH_MDC_GPIO=23 +CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 +CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 +CONFIG_EXAMPLE_ETH_PHY_ADDR=1 +CONFIG_MDNS_BUTTON_GPIO=32 diff --git a/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_no_ipv6 b/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_no_ipv6 new file mode 100644 index 0000000..d669ec0 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_no_ipv6 @@ -0,0 +1,16 @@ +CONFIG_IDF_TARGET="esp32" +CONFIG_MDNS_RESOLVE_TEST_SERVICES=y +CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y +CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +CONFIG_LWIP_IPV6=n +CONFIG_EXAMPLE_CONNECT_IPV6=n +CONFIG_EXAMPLE_CONNECT_ETHERNET=y +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y +CONFIG_EXAMPLE_ETH_PHY_IP101=y +CONFIG_EXAMPLE_ETH_MDC_GPIO=23 +CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 +CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 +CONFIG_EXAMPLE_ETH_PHY_ADDR=1 +CONFIG_MDNS_BUTTON_GPIO=32 diff --git a/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_socket b/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_socket new file mode 100644 index 0000000..5d92405 --- /dev/null +++ b/managed_components/espressif__mdns/examples/query_advertise/sdkconfig.ci.eth_socket @@ -0,0 +1,16 @@ +CONFIG_IDF_TARGET="esp32" +CONFIG_MDNS_RESOLVE_TEST_SERVICES=y +CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y +CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y +CONFIG_MDNS_NETWORKING_SOCKET=y +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +CONFIG_EXAMPLE_CONNECT_ETHERNET=y +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y +CONFIG_EXAMPLE_ETH_PHY_IP101=y +CONFIG_EXAMPLE_ETH_MDC_GPIO=23 +CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 +CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 +CONFIG_EXAMPLE_ETH_PHY_ADDR=1 +CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_MDNS_BUTTON_GPIO=32 diff --git a/managed_components/espressif__mdns/idf_component.yml b/managed_components/espressif__mdns/idf_component.yml new file mode 100644 index 0000000..89994b8 --- /dev/null +++ b/managed_components/espressif__mdns/idf_component.yml @@ -0,0 +1,13 @@ +dependencies: + idf: + version: '>=5.0' +description: Multicast UDP service used to provide local network service and host + discovery. +documentation: https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/en/index.html +issues: https://github.com/espressif/esp-protocols/issues +repository: git://github.com/espressif/esp-protocols.git +repository_info: + commit_sha: 4394f845fccf93bc49111808c24bbd25fbbb20f4 + path: components/mdns +url: https://github.com/espressif/esp-protocols/tree/master/components/mdns +version: 1.4.3 diff --git a/managed_components/espressif__mdns/include/mdns.h b/managed_components/espressif__mdns/include/mdns.h new file mode 100644 index 0000000..8676717 --- /dev/null +++ b/managed_components/espressif__mdns/include/mdns.h @@ -0,0 +1,929 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ESP_MDNS_H_ +#define ESP_MDNS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define MDNS_TYPE_A 0x0001 +#define MDNS_TYPE_PTR 0x000C +#define MDNS_TYPE_TXT 0x0010 +#define MDNS_TYPE_AAAA 0x001C +#define MDNS_TYPE_SRV 0x0021 +#define MDNS_TYPE_OPT 0x0029 +#define MDNS_TYPE_NSEC 0x002F +#define MDNS_TYPE_ANY 0x00FF + +/** + * @brief Asynchronous query handle + */ +typedef struct mdns_search_once_s mdns_search_once_t; + +/** + * @brief Daemon query handle + */ +typedef struct mdns_browse_s mdns_browse_t; + +typedef enum { + MDNS_EVENT_ENABLE_IP4 = 1 << 1, + MDNS_EVENT_ENABLE_IP6 = 1 << 2, + MDNS_EVENT_ANNOUNCE_IP4 = 1 << 3, + MDNS_EVENT_ANNOUNCE_IP6 = 1 << 4, + MDNS_EVENT_DISABLE_IP4 = 1 << 5, + MDNS_EVENT_DISABLE_IP6 = 1 << 6, + MDNS_EVENT_IP4_REVERSE_LOOKUP = 1 << 7, + MDNS_EVENT_IP6_REVERSE_LOOKUP = 1 << 8, +} mdns_event_actions_t; + +/** + * @brief mDNS enum to specify the ip_protocol type + */ +typedef enum { + MDNS_IP_PROTOCOL_V4, + MDNS_IP_PROTOCOL_V6, + MDNS_IP_PROTOCOL_MAX +} mdns_ip_protocol_t; + +/** + * @brief mDNS basic text item structure + * Used in mdns_service_add() + */ +typedef struct { + const char *key; /*!< item key name */ + const char *value; /*!< item value string */ +} mdns_txt_item_t; + +/** + * @brief mDNS basic subtype item structure + * Used in mdns_service_subtype_xxx() APIs + */ +typedef struct { + const char *subtype; /*!< subtype name */ +} mdns_subtype_item_t; + +/** + * @brief mDNS query linked list IP item + */ +typedef struct mdns_ip_addr_s { + esp_ip_addr_t addr; /*!< IP address */ + struct mdns_ip_addr_s *next; /*!< next IP, or NULL for the last IP in the list */ +} mdns_ip_addr_t; + +/** + * @brief mDNS query type to be explicitly set to either Unicast or Multicast + */ +typedef enum { + MDNS_QUERY_UNICAST, + MDNS_QUERY_MULTICAST, +} mdns_query_transmission_type_t; + +/** + * @brief mDNS query result structure + */ +typedef struct mdns_result_s { + struct mdns_result_s *next; /*!< next result, or NULL for the last result in the list */ + + esp_netif_t *esp_netif; /*!< ptr to corresponding esp-netif */ + uint32_t ttl; /*!< time to live */ + + mdns_ip_protocol_t ip_protocol; /*!< ip_protocol type of the interface (v4/v6) */ + // PTR + char *instance_name; /*!< instance name */ + char *service_type; /*!< service type */ + char *proto; /*!< srevice protocol */ + // SRV + char *hostname; /*!< hostname */ + uint16_t port; /*!< service port */ + // TXT + mdns_txt_item_t *txt; /*!< txt record */ + uint8_t *txt_value_len; /*!< array of txt value len of each record */ + size_t txt_count; /*!< number of txt items */ + // A and AAAA + mdns_ip_addr_t *addr; /*!< linked list of IP addresses found */ +} mdns_result_t; + +typedef void (*mdns_query_notify_t)(mdns_search_once_t *search); +typedef void (*mdns_browse_notify_t)(mdns_result_t *result); + +/** + * @brief Initialize mDNS on given interface + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE when failed to register event handler + * - ESP_ERR_NO_MEM on memory error + * - ESP_FAIL when failed to start mdns task + */ +esp_err_t mdns_init(void); + +/** + * @brief Stop and free mDNS server + * + */ +void mdns_free(void); + +/** + * @brief Set the hostname for mDNS server + * required if you want to advertise services + * + * @param hostname Hostname to set + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_hostname_set(const char *hostname); + +/** + * @brief Get the hostname for mDNS server + * + * @param hostname pointer to the hostname, it should be allocated + * and hold at least MDNS_NAME_BUF_LEN chars + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_INVALID_STATE when mdns is not initialized + */ +esp_err_t mdns_hostname_get(char *hostname); + +/** + * @brief Adds a hostname and address to be delegated + * A/AAAA queries will be replied for the hostname and + * services can be added to this host. + * + * @param hostname Hostname to add + * @param address_list The IP address list of the host + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM memory error + * + */ +esp_err_t mdns_delegate_hostname_add(const char *hostname, const mdns_ip_addr_t *address_list); + +/** + * @brief Set the address to a delegated hostname + * + * @param hostname Hostname to set + * @param address_list The IP address list of the host + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM memory error + * + */ +esp_err_t mdns_delegate_hostname_set_address(const char *hostname, const mdns_ip_addr_t *address_list); + +/** + * @brief Remove a delegated hostname + * All the services added to this host will also be removed. + * + * @param hostname Hostname to remove + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM memory error + * + */ +esp_err_t mdns_delegate_hostname_remove(const char *hostname); + +/** + * @brief Query whether a hostname has been added + * + * @param hostname Hostname to query + * + * @return + * - true The hostname has been added. + * - false The hostname has not been added. + * + */ +bool mdns_hostname_exists(const char *hostname); + +/** + * @brief Set the default instance name for mDNS server + * + * @param instance_name Instance name to set + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_instance_name_set(const char *instance_name); + +/** + * @brief Add service to mDNS server + * + * @note The value length of txt items will be automatically decided by strlen + * + * @param instance_name instance name to set. If NULL, + * global instance name or hostname will be used. + * Note that MDNS_MULTIPLE_INSTANCE config option + * needs to be enabled for adding multiple instances + * with the same instance type. + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param port service port + * @param txt string array of TXT data (eg. {{"var","val"},{"other","2"}}) + * @param num_items number of items in TXT data + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM memory error + * - ESP_FAIL failed to add service + */ +esp_err_t mdns_service_add(const char *instance_name, const char *service_type, const char *proto, uint16_t port, mdns_txt_item_t txt[], size_t num_items); + +/** + * @brief Add service to mDNS server with a delegated hostname + * + * @note The value length of txt items will be automatically decided by strlen + * + * @param instance_name instance name to set. If NULL, + * global instance name or hostname will be used + * Note that MDNS_MULTIPLE_INSTANCE config option + * needs to be enabled for adding multiple instances + * with the same instance type. + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param port service port + * @param txt string array of TXT data (eg. {{"var","val"},{"other","2"}}) + * @param num_items number of items in TXT data + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NO_MEM memory error + * - ESP_FAIL failed to add service + */ +esp_err_t mdns_service_add_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, uint16_t port, mdns_txt_item_t txt[], size_t num_items); + +/** + * @brief Check whether a service has been added. + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, checks for the local hostname. + * + * @return + * - true Correspondding service has been added. + * - false Service not found. + */ +bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname); + +/** + * @brief Check whether a service has been added. + * + * @param instance instance name + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, checks for the local hostname. + * + * @return + * - true Correspondding service has been added. + * - false Service not found. + */ +bool mdns_service_exists_with_instance(const char *instance, const char *service_type, const char *proto, + const char *hostname); + +/** + * @brief Remove service from mDNS server + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_remove(const char *service_type, const char *proto); + +/** + * @brief Remove service from mDNS server with hostname + * + * @param instance instance name + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_remove_for_host(const char *instance, const char *service_type, const char *proto, const char *hostname); + +/** + * @brief Set instance name for service + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param instance_name instance name to set + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_instance_name_set(const char *service_type, const char *proto, const char *instance_name); + +/** + * @brief Set instance name for service with hostname + * + * @param instance_old original instance name + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param instance_name instance name to set + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_instance_name_set_for_host(const char *instance_old, const char *service_type, const char *proto, const char *hostname, + const char *instance_name); + +/** + * @brief Set service port + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param port service port + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_port_set(const char *service_type, const char *proto, uint16_t port); + + +/** + * @brief Set service port with hostname + * + * @param instance instance name + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param port service port + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_port_set_for_host(const char *instance, const char *service_type, const char *proto, const char *hostname, + uint16_t port); + +/** + * @brief Replace all TXT items for service + * + * @note The value length of txt items will be automatically decided by strlen + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param txt array of TXT data (eg. {{"var","val"},{"other","2"}}) + * @param num_items number of items in TXT data + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_set(const char *service_type, const char *proto, mdns_txt_item_t txt[], uint8_t num_items); + +/** + * @brief Replace all TXT items for service with hostname + * + * @note The value length of txt items will be automatically decided by strlen + * + * @param instance instance name + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param txt array of TXT data (eg. {{"var","val"},{"other","2"}}) + * @param num_items number of items in TXT data + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_set_for_host(const char *instance, const char *service_type, const char *proto, const char *hostname, + mdns_txt_item_t txt[], uint8_t num_items); + +/** + * @brief Set/Add TXT item for service TXT record + * + * @note The value length will be automatically decided by strlen + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param key the key that you want to add/update + * @param value the new value of the key + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_item_set(const char *service_type, const char *proto, const char *key, const char *value); + +/** + * @brief Set/Add TXT item for service TXT record + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param key the key that you want to add/update + * @param value the new value of the key + * @param value_len the length of the value + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_item_set_with_explicit_value_len(const char *service_type, const char *proto, + const char *key, const char *value, uint8_t value_len); + +/** + * @brief Set/Add TXT item for service TXT record with hostname + * + * @note The value length will be automatically decided by strlen + * + * @param instance instance name + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param key the key that you want to add/update + * @param value the new value of the key + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_item_set_for_host(const char *instance, const char *service_type, const char *proto, const char *hostname, + const char *key, const char *value); + +/** + * @brief Set/Add TXT item for service TXT record with hostname and txt value length + * + * @param instance instance name + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param key the key that you want to add/update + * @param value the new value of the key + * @param value_len the length of the value + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_item_set_for_host_with_explicit_value_len(const char *instance, const char *service_type, const char *proto, + const char *hostname, const char *key, + const char *value, uint8_t value_len); + +/** + * @brief Remove TXT item for service TXT record + * + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param key the key that you want to remove + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_item_remove(const char *service_type, const char *proto, const char *key); + +/** + * @brief Remove TXT item for service TXT record with hostname + * + * @param instance instance name + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param key the key that you want to remove + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_txt_item_remove_for_host(const char *instance, const char *service_type, const char *proto, const char *hostname, + const char *key); + +/** + * @brief Add a subtype for service. + * + * @param instance_name instance name. If NULL, will find the first service with the same service type and protocol. + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param subtype The subtype to add. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, const char *subtype); + +/** + * @brief Remove a subtype for service. + * + * @param instance_name instance name. If NULL, will find the first service with the same service type and protocol. + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param subtype The subtype to remove. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + */ +esp_err_t mdns_service_subtype_remove_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, const char *subtype); + +/** + * @brief Add multiple subtypes for service at once. + * + * @param instance_name instance name. If NULL, will find the first service with the same service type and protocol. + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param subtype the pointer of subtype array to add. + * @param num_items number of items in subtype array + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_subtype_add_multiple_items_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, mdns_subtype_item_t subtype[], uint8_t num_items); + +/** + * @brief Update subtype for service. + * + * @param instance_name instance name. If NULL, will find the first service with the same service type and protocol. + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param hostname service hostname. If NULL, local hostname will be used. + * @param subtype the pointer of subtype array to add. + * @param num_items number of items in subtype array + * + * @note If `num_items` is 0, then remove all subtypes. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_NOT_FOUND Service not found + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_service_subtype_update_multiple_items_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, mdns_subtype_item_t subtype[], uint8_t num_items); +/** + * @brief Remove and free all services from mDNS server + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t mdns_service_remove_all(void); + +/** + * @brief Deletes the finished query. Call this only after the search has ended! + * + * @param search pointer to search object + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE search has not finished + * - ESP_ERR_INVALID_ARG pointer to search object is NULL + */ +esp_err_t mdns_query_async_delete(mdns_search_once_t *search); + +/** + * @brief Get results from search pointer. Results available as a pointer to the output parameter. + * Pointer to search object has to be deleted via `mdns_query_async_delete` once the query has finished. + * The results although have to be freed manually. + * + * @param search pointer to search object + * @param timeout time in milliseconds to wait for answers + * @param results pointer to the results of the query + * @param num_results pointer to the number of the actual result items (set to NULL to ignore this return value) + * + * @return + * True if search has finished before or at timeout + * False if search timeout is over + */ +bool mdns_query_async_get_results(mdns_search_once_t *search, uint32_t timeout, mdns_result_t **results, uint8_t *num_results); + +/** + * @brief Query mDNS for host or service asynchronousely. + * Search has to be tested for progress and deleted manually! + * + * @param name service instance or host name (NULL for PTR queries) + * @param service_type service type (_http, _arduino, _ftp etc.) (NULL for host queries) + * @param proto service protocol (_tcp, _udp, etc.) (NULL for host queries) + * @param type type of query (MDNS_TYPE_*) + * @param timeout time in milliseconds during which mDNS query is active + * @param max_results maximum results to be collected + * @param notifier Notification function to be called when the result is ready, can be NULL + * + * @return mdns_search_once_s pointer to new search object if query initiated successfully. + * NULL otherwise. + */ +mdns_search_once_t *mdns_query_async_new(const char *name, const char *service_type, const char *proto, uint16_t type, + uint32_t timeout, size_t max_results, mdns_query_notify_t notifier); + +/** + * @brief Generic mDNS query + * All following query methods are derived from this one + * + * @param name service instance or host name (NULL for PTR queries) + * @param service_type service type (_http, _arduino, _ftp etc.) (NULL for host queries) + * @param proto service protocol (_tcp, _udp, etc.) (NULL for host queries) + * @param type type of query (MDNS_TYPE_*) + * @param transmission_type either Unicast query, or Multicast query + * @param timeout time in milliseconds to wait for answers. + * @param max_results maximum results to be collected + * @param results pointer to the results of the query + * results must be freed using mdns_query_results_free below + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NO_MEM memory error + * - ESP_ERR_INVALID_ARG timeout was not given + */ +esp_err_t mdns_query_generic(const char *name, const char *service_type, const char *proto, uint16_t type, + mdns_query_transmission_type_t transmission_type, uint32_t timeout, size_t max_results, mdns_result_t **results); + +/** + * @brief Query mDNS for host or service + * + * Note that querying PTR types sends Multicast query, all other types send Unicast queries + * + * @param name service instance or host name (NULL for PTR queries) + * @param service_type service type (_http, _arduino, _ftp etc.) (NULL for host queries) + * @param proto service protocol (_tcp, _udp, etc.) (NULL for host queries) + * @param type type of query (MDNS_TYPE_*) + * @param timeout time in milliseconds to wait for answers. + * @param max_results maximum results to be collected + * @param results pointer to the results of the query + * results must be freed using mdns_query_results_free below + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NO_MEM memory error + * - ESP_ERR_INVALID_ARG timeout was not given + */ +esp_err_t mdns_query(const char *name, const char *service_type, const char *proto, uint16_t type, uint32_t timeout, size_t max_results, mdns_result_t **results); + +/** + * @brief Free query results + * + * @param results linked list of results to be freed + */ +void mdns_query_results_free(mdns_result_t *results); + +/** + * @brief Query mDNS for service + * + * @param service_type service type (_http, _arduino, _ftp etc.) + * @param proto service protocol (_tcp, _udp, etc.) + * @param timeout time in milliseconds to wait for answer. + * @param max_results maximum results to be collected + * @param results pointer to the results of the query + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NO_MEM memory error + * - ESP_ERR_INVALID_ARG parameter error + */ +esp_err_t mdns_query_ptr(const char *service_type, const char *proto, uint32_t timeout, size_t max_results, mdns_result_t **results); + +/** + * @brief Query mDNS for SRV record + * + * @param instance_name service instance name + * @param service_type service type (_http, _arduino, _ftp etc.) + * @param proto service protocol (_tcp, _udp, etc.) + * @param timeout time in milliseconds to wait for answer. + * @param result pointer to the result of the query + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NO_MEM memory error + * - ESP_ERR_INVALID_ARG parameter error + */ +esp_err_t mdns_query_srv(const char *instance_name, const char *service_type, const char *proto, uint32_t timeout, mdns_result_t **result); + +/** + * @brief Query mDNS for TXT record + * + * @param instance_name service instance name + * @param service_type service type (_http, _arduino, _ftp etc.) + * @param proto service protocol (_tcp, _udp, etc.) + * @param timeout time in milliseconds to wait for answer. + * @param result pointer to the result of the query + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NO_MEM memory error + * - ESP_ERR_INVALID_ARG parameter error + */ +esp_err_t mdns_query_txt(const char *instance_name, const char *service_type, const char *proto, uint32_t timeout, mdns_result_t **result); + +/** + * @brief Look up delegated services. + * + * @param instance instance name (NULL for uncertain instance) + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param max_results maximum results to be collected + * @param result pointer to the result of the search + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NO_MEM memory error + * - ESP_ERR_INVALID_ARG parameter error + */ +esp_err_t mdns_lookup_delegated_service(const char *instance, const char *service_type, const char *proto, size_t max_results, + mdns_result_t **result); + +/** + * @brief Look up self hosted services. + * + * @param instance instance name (NULL for uncertain instance) + * @param service_type service type (_http, _ftp, etc) + * @param proto service protocol (_tcp, _udp) + * @param max_results maximum results to be collected + * @param result pointer to the result of the search + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NO_MEM memory error + * - ESP_ERR_INVALID_ARG parameter error + */ +esp_err_t mdns_lookup_selfhosted_service(const char *instance, const char *service_type, const char *proto, size_t max_results, + mdns_result_t **result); + +/** + * @brief Query mDNS for A record + * + * @param host_name host name to look for + * @param timeout time in milliseconds to wait for answer. + * @param addr pointer to the resulting IP4 address + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NO_MEM memory error + * - ESP_ERR_INVALID_ARG parameter error + */ +esp_err_t mdns_query_a(const char *host_name, uint32_t timeout, esp_ip4_addr_t *addr); + +#if CONFIG_LWIP_IPV6 +/** + * @brief Query mDNS for A record + * + * Please note that hostname must not contain domain name, as mDNS uses '.local' domain. + * + * @param host_name host name to look for + * @param timeout time in milliseconds to wait for answer. If 0, max_results needs to be defined + * @param addr pointer to the resulting IP6 address + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NO_MEM memory error + * - ESP_ERR_INVALID_ARG parameter error + */ +esp_err_t mdns_query_aaaa(const char *host_name, uint32_t timeout, esp_ip6_addr_t *addr); +#endif + + +/** + * @brief Register custom esp_netif with mDNS functionality + * mDNS service runs by default on preconfigured interfaces (STA, AP, ETH). + * This API enables running the service on any customized interface, + * either using standard WiFi or Ethernet driver or any kind of user defined driver. + * + * @param esp_netif Pointer to esp-netif interface + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running or this netif is already registered + * - ESP_ERR_NO_MEM not enough memory for this in interface in the netif list (see CONFIG_MDNS_MAX_INTERFACES) + */ +esp_err_t mdns_register_netif(esp_netif_t *esp_netif); + +/** + * @brief Unregister esp-netif already registered in mDNS service + * + * @param esp_netif Pointer to esp-netif interface + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running + * - ESP_ERR_NOT_FOUND this esp-netif was not registered in mDNS service + */ +esp_err_t mdns_unregister_netif(esp_netif_t *esp_netif); + +/** + * @brief Set esp_netif to a desired state, or perform a desired action, such as enable/disable this interface + * or send announcement packets to this netif + * + * * This function is used to enable (probe, resolve conflicts and announce), announce, or disable (send bye) mDNS + * services on the specified network interface. + * * This function must be called if users registers a specific interface using mdns_register_netif() + * to enable mDNS services on that interface. + * * This function could be used in IP/connection event handlers to automatically enable/announce mDNS services + * when network properties change and/or disable them on disconnection. + * + * @param esp_netif Pointer to esp-netif interface + * @param event_action Disable/Enable/Announce on this interface over IPv4/IPv6 protocol. + * Actions enumerated in mdns_event_actions_t type. + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_STATE mDNS is not running or this netif is not registered + * - ESP_ERR_NO_MEM memory error + */ +esp_err_t mdns_netif_action(esp_netif_t *esp_netif, mdns_event_actions_t event_action); + +/** + * @brief Browse mDNS for a service `_service._proto`. + * + * @param service Pointer to the `_service` which will be browsed. + * @param proto Pointer to the `_proto` which will be browsed. + * @param notifier The callback which will be called when the browsing service changed. + * @return mdns_browse_t pointer to new browse object if initiated successfully. + * NULL otherwise. + */ +mdns_browse_t *mdns_browse_new(const char *service, const char *proto, mdns_browse_notify_t notifier); + +/** + * @brief Stop the `_service._proto` browse. + * @param service Pointer to the `_service` which will be browsed. + * @param proto Pointer to the `_proto` which will be browsed. + * @return + * - ESP_OK success. + * - ESP_ERR_FAIL mDNS is not running or the browsing of `_service._proto` is never started. + * - ESP_ERR_NO_MEM memory error. + */ +esp_err_t mdns_browse_delete(const char *service, const char *proto); + +#ifdef __cplusplus +} +#endif + +#endif /* ESP_MDNS_H_ */ diff --git a/managed_components/espressif__mdns/include/mdns_console.h b/managed_components/espressif__mdns/include/mdns_console.h new file mode 100644 index 0000000..cb28eca --- /dev/null +++ b/managed_components/espressif__mdns/include/mdns_console.h @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _MDNS_CONSOLE_H_ +#define _MDNS_CONSOLE_H_ + +/** + * @brief Register MDNS functions with the console component + */ +void mdns_console_register(void); + +#endif /* _MDNS_CONSOLE_H_ */ diff --git a/managed_components/espressif__mdns/mdns.c b/managed_components/espressif__mdns/mdns.c new file mode 100644 index 0000000..0d75836 --- /dev/null +++ b/managed_components/espressif__mdns/mdns.c @@ -0,0 +1,7695 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "esp_log.h" +#include "esp_event.h" +#include "mdns.h" +#include "mdns_private.h" +#include "mdns_networking.h" +#include "esp_log.h" +#include "esp_random.h" +#include "esp_check.h" + +static void _mdns_browse_item_free(mdns_browse_t *browse); +static esp_err_t _mdns_send_browse_action(mdns_action_type_t type, mdns_browse_t *browse); +static esp_err_t _mdns_sync_browse_action(mdns_action_type_t type, mdns_browse_sync_t *browse_sync); +static void _mdns_browse_sync(mdns_browse_sync_t *browse_sync); +static void _mdns_browse_finish(mdns_browse_t *browse); +static void _mdns_browse_add(mdns_browse_t *browse); +static void _mdns_browse_send(mdns_browse_t *browse, mdns_if_t interface); + +#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH +#include "esp_eth.h" +#endif + +#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(5, 1, 0) +#define MDNS_ESP_WIFI_ENABLED CONFIG_SOC_WIFI_SUPPORTED +#else +#define MDNS_ESP_WIFI_ENABLED CONFIG_ESP_WIFI_ENABLED +#endif + +#if MDNS_ESP_WIFI_ENABLED && (CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP) +#include "esp_wifi.h" +#endif + +#ifdef MDNS_ENABLE_DEBUG +void mdns_debug_packet(const uint8_t *data, size_t len); +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#endif + +// Internal size of IPv6 address is defined here as size of AAAA record in mdns packet +// since the ip6_addr_t is defined in lwip and depends on using IPv6 zones +#define _MDNS_SIZEOF_IP6_ADDR (MDNS_ANSWER_AAAA_SIZE) + +static const char *MDNS_DEFAULT_DOMAIN = "local"; +static const char *MDNS_SUB_STR = "_sub"; + +mdns_server_t *_mdns_server = NULL; +static mdns_host_item_t *_mdns_host_list = NULL; +static mdns_host_item_t _mdns_self_host; + +static const char *TAG = "mdns"; + +static volatile TaskHandle_t _mdns_service_task_handle = NULL; +static SemaphoreHandle_t _mdns_service_semaphore = NULL; + +static void _mdns_search_finish_done(void); +static mdns_search_once_t *_mdns_search_find_from(mdns_search_once_t *search, mdns_name_t *name, uint16_t type, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); +static mdns_browse_t *_mdns_browse_find_from(mdns_browse_t *b, mdns_name_t *name, uint16_t type, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); +static void _mdns_browse_result_add_srv(mdns_browse_t *browse, const char *hostname, const char *instance, const char *service, const char *proto, + uint16_t port, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint32_t ttl, mdns_browse_sync_t *out_sync_browse); +static void _mdns_browse_result_add_ip(mdns_browse_t *browse, const char *hostname, esp_ip_addr_t *ip, + mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint32_t ttl, mdns_browse_sync_t *out_sync_browse); +static void _mdns_browse_result_add_txt(mdns_browse_t *browse, const char *instance, const char *service, const char *proto, + mdns_txt_item_t *txt, uint8_t *txt_value_len, size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, + uint32_t ttl, mdns_browse_sync_t *out_sync_browse); +#ifdef MDNS_ENABLE_DEBUG +static void debug_printf_browse_result(mdns_result_t *r_t, mdns_browse_t *b_t); +static void debug_printf_browse_result_all(mdns_result_t *r_t); +#endif // MDNS_ENABLE_DEBUG +static void _mdns_search_result_add_ip(mdns_search_once_t *search, const char *hostname, esp_ip_addr_t *ip, + mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint32_t ttl); +static void _mdns_search_result_add_srv(mdns_search_once_t *search, const char *hostname, uint16_t port, + mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint32_t ttl); +static void _mdns_search_result_add_txt(mdns_search_once_t *search, mdns_txt_item_t *txt, uint8_t *txt_value_len, + size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, + uint32_t ttl); +static mdns_result_t *_mdns_search_result_add_ptr(mdns_search_once_t *search, const char *instance, + const char *service_type, const char *proto, mdns_if_t tcpip_if, + mdns_ip_protocol_t ip_protocol, uint32_t ttl); +static bool _mdns_append_host_list_in_services(mdns_out_answer_t **destination, mdns_srv_item_t *services[], size_t services_len, bool flush, bool bye); +static bool _mdns_append_host_list(mdns_out_answer_t **destination, bool flush, bool bye); +static void _mdns_remap_self_service_hostname(const char *old_hostname, const char *new_hostname); +static esp_err_t mdns_post_custom_action_tcpip_if(mdns_if_t mdns_if, mdns_event_actions_t event_action); + +static void _mdns_query_results_free(mdns_result_t *results); +typedef enum { + MDNS_IF_STA = 0, + MDNS_IF_AP = 1, + MDNS_IF_ETH = 2, +} mdns_predef_if_t; + +typedef struct mdns_interfaces mdns_interfaces_t; + +struct mdns_interfaces { + const bool predefined; + esp_netif_t *netif; + const mdns_predef_if_t predef_if; + mdns_if_t duplicate; +}; + +/* + * @brief Internal collection of mdns supported interfaces + * + */ +static mdns_interfaces_t s_esp_netifs[MDNS_MAX_INTERFACES] = { +#if CONFIG_MDNS_PREDEF_NETIF_STA + { .predefined = true, .netif = NULL, .predef_if = MDNS_IF_STA, .duplicate = MDNS_MAX_INTERFACES }, +#endif +#if CONFIG_MDNS_PREDEF_NETIF_AP + { .predefined = true, .netif = NULL, .predef_if = MDNS_IF_AP, .duplicate = MDNS_MAX_INTERFACES }, +#endif +#if CONFIG_MDNS_PREDEF_NETIF_ETH + { .predefined = true, .netif = NULL, .predef_if = MDNS_IF_ETH, .duplicate = MDNS_MAX_INTERFACES }, +#endif +}; + + +/** + * @brief Convert Predefined interface to the netif id from the internal netif list + * @param predef_if Predefined interface enum + * @return Ordinal number of internal list of mdns network interface. + * Returns MDNS_MAX_INTERFACES if the predefined interface wasn't found in the list + */ +static mdns_if_t mdns_if_from_preset_if(mdns_predef_if_t predef_if) +{ + for (int i = 0; i < MDNS_MAX_INTERFACES; ++i) { + if (s_esp_netifs[i].predefined && s_esp_netifs[i].predef_if == predef_if) { + return i; + } + } + return MDNS_MAX_INTERFACES; +} + +/** + * @brief Convert Predefined interface to esp-netif handle + * @param predef_if Predefined interface enum + * @return esp_netif pointer from system list of network interfaces + */ +static inline esp_netif_t *esp_netif_from_preset_if(mdns_predef_if_t predef_if) +{ + switch (predef_if) { + case MDNS_IF_STA: + return esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + case MDNS_IF_AP: + return esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"); +#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH + case MDNS_IF_ETH: + return esp_netif_get_handle_from_ifkey("ETH_DEF"); +#endif + default: + return NULL; + } +} + +/** + * @brief Gets the actual esp_netif pointer from the internal network interface list + * + * The supplied ordinal number could + * - point to a predef netif -> "STA", "AP", "ETH" + * - if no entry in the list (NULL) -> check if the system added this netif + * - point to a custom netif -> just return the entry in the list + * - users is responsible for the lifetime of this netif (to be valid between mdns-init -> deinit) + * + * @param tcpip_if Ordinal number of the interface + * @return Pointer ot the esp_netif object if the interface is available, NULL otherwise + */ +esp_netif_t *_mdns_get_esp_netif(mdns_if_t tcpip_if) +{ + if (tcpip_if < MDNS_MAX_INTERFACES) { + if (s_esp_netifs[tcpip_if].netif == NULL && s_esp_netifs[tcpip_if].predefined) { + // If the local copy is NULL and this netif is predefined -> we can find it in the global netif list + s_esp_netifs[tcpip_if].netif = esp_netif_from_preset_if(s_esp_netifs[tcpip_if].predef_if); + // failing to find it means that the netif is *not* available -> return NULL + } + return s_esp_netifs[tcpip_if].netif; + } + return NULL; +} + + +/* + * @brief Clean internal mdns interface's pointer + */ +static inline void _mdns_clean_netif_ptr(mdns_if_t tcpip_if) +{ + if (tcpip_if < MDNS_MAX_INTERFACES) { + s_esp_netifs[tcpip_if].netif = NULL; + } +} + + +/* + * @brief Convert esp-netif handle to mdns if + */ +static mdns_if_t _mdns_get_if_from_esp_netif(esp_netif_t *esp_netif) +{ + for (int i = 0; i < MDNS_MAX_INTERFACES; ++i) { + // The predefined netifs in the static array are NULL when firstly calling this function + // if IPv4 is disabled. Set these netifs here. + if (s_esp_netifs[i].netif == NULL && s_esp_netifs[i].predefined) { + s_esp_netifs[i].netif = esp_netif_from_preset_if(s_esp_netifs[i].predef_if); + } + if (esp_netif == s_esp_netifs[i].netif) { + return i; + } + } + return MDNS_MAX_INTERFACES; +} + + + +static inline bool _str_null_or_empty(const char *str) +{ + return (str == NULL || *str == 0); +} + +/* + * @brief Appends/increments a number to name/instance in case of collision + * */ +static char *_mdns_mangle_name(char *in) +{ + char *p = strrchr(in, '-'); + int suffix = 0; + if (p == NULL) { + //No - in ``in`` + suffix = 2; + } else { + char *endp = NULL; + suffix = strtol(p + 1, &endp, 10); + if (*endp != 0) { + //suffix is not numerical + suffix = 2; + p = NULL; //so we append -suffix to the entire string + } + } + char *ret; + if (p == NULL) { + //need to add -2 to string + ret = malloc(strlen(in) + 3); + if (ret == NULL) { + HOOK_MALLOC_FAILED; + return NULL; + } + sprintf(ret, "%s-2", in); + } else { + ret = malloc(strlen(in) + 2); //one extra byte in case 9-10 or 99-100 etc + if (ret == NULL) { + HOOK_MALLOC_FAILED; + return NULL; + } + strcpy(ret, in); + int baseLen = p - in; //length of 'bla' in 'bla-123' + //overwrite suffix with new suffix + sprintf(ret + baseLen, "-%d", suffix + 1); + } + return ret; +} + +static bool _mdns_service_match(const mdns_service_t *srv, const char *service, const char *proto, + const char *hostname) +{ + if (!service || !proto || !srv->hostname) { + return false; + } + return !strcasecmp(srv->service, service) && !strcasecmp(srv->proto, proto) && + (_str_null_or_empty(hostname) || !strcasecmp(srv->hostname, hostname)); +} + +/** + * @brief finds service from given service type + * @param server the server + * @param service service type to match + * @param proto proto to match + * @param hostname hostname of the service (if non-null) + * + * @return the service item if found or NULL on error + */ +static mdns_srv_item_t *_mdns_get_service_item(const char *service, const char *proto, const char *hostname) +{ + mdns_srv_item_t *s = _mdns_server->services; + while (s) { + if (_mdns_service_match(s->service, service, proto, hostname)) { + return s; + } + s = s->next; + } + return NULL; +} + +static mdns_srv_item_t *_mdns_get_service_item_subtype(const char *subtype, const char *service, const char *proto) +{ + mdns_srv_item_t *s = _mdns_server->services; + while (s) { + if (_mdns_service_match(s->service, service, proto, NULL)) { + mdns_subtype_t *subtype_item = s->service->subtype; + while (subtype_item) { + if (!strcasecmp(subtype_item->subtype, subtype)) { + return s; + } + subtype_item = subtype_item->next; + } + } + s = s->next; + } + return NULL; +} + +static mdns_host_item_t *mdns_get_host_item(const char *hostname) +{ + if (hostname == NULL || strcasecmp(hostname, _mdns_server->hostname) == 0) { + return &_mdns_self_host; + } + mdns_host_item_t *host = _mdns_host_list; + while (host != NULL) { + if (strcasecmp(host->hostname, hostname) == 0) { + return host; + } + host = host->next; + } + return NULL; +} + +static bool _mdns_can_add_more_services(void) +{ + mdns_srv_item_t *s = _mdns_server->services; + uint16_t service_num = 0; + while (s) { + service_num ++; + s = s->next; + if (service_num >= MDNS_MAX_SERVICES) { + return false; + } + } + + return true; +} + +esp_err_t _mdns_send_rx_action(mdns_rx_packet_t *packet) +{ + mdns_action_t *action = NULL; + + action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + return ESP_ERR_NO_MEM; + } + + action->type = ACTION_RX_HANDLE; + action->data.rx_handle.packet = packet; + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(action); + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} + +static const char *_mdns_get_default_instance_name(void) +{ + if (_mdns_server && !_str_null_or_empty(_mdns_server->instance)) { + return _mdns_server->instance; + } + + if (_mdns_server && !_str_null_or_empty(_mdns_server->hostname)) { + return _mdns_server->hostname; + } + + return NULL; +} + +/** + * @brief Get the service name of a service + */ +static const char *_mdns_get_service_instance_name(const mdns_service_t *service) +{ + if (service && !_str_null_or_empty(service->instance)) { + return service->instance; + } + + return _mdns_get_default_instance_name(); +} + +static bool _mdns_instance_name_match(const char *lhs, const char *rhs) +{ + if (lhs == NULL) { + lhs = _mdns_get_default_instance_name(); + } + if (rhs == NULL) { + rhs = _mdns_get_default_instance_name(); + } + return !strcasecmp(lhs, rhs); +} + +static bool _mdns_service_match_instance(const mdns_service_t *srv, const char *instance, const char *service, + const char *proto, const char *hostname) +{ + // service and proto must be supplied, if not this instance won't match + if (!service || !proto) { + return false; + } + // instance==NULL -> _mdns_instance_name_match() will check the default instance + // hostname==NULL -> matches if instance, service and proto matches + return !strcasecmp(srv->service, service) && _mdns_instance_name_match(srv->instance, instance) && + !strcasecmp(srv->proto, proto) && (_str_null_or_empty(hostname) || !strcasecmp(srv->hostname, hostname)); +} + +static mdns_srv_item_t *_mdns_get_service_item_instance(const char *instance, const char *service, const char *proto, + const char *hostname) +{ + mdns_srv_item_t *s = _mdns_server->services; + while (s) { + if (instance) { + if (_mdns_service_match_instance(s->service, instance, service, proto, hostname)) { + return s; + } + } else { + if (_mdns_service_match(s->service, service, proto, hostname)) { + return s; + } + } + s = s->next; + } + return NULL; +} + +/** + * @brief reads MDNS FQDN into mdns_name_t structure + * FQDN is in format: [hostname.|[instance.]_service._proto.]local. + * + * @param packet MDNS packet + * @param start Starting point of FQDN + * @param name mdns_name_t structure to populate + * @param buf temporary char buffer + * + * @return the address after the parsed FQDN in the packet or NULL on error + */ +static const uint8_t *_mdns_read_fqdn(const uint8_t *packet, const uint8_t *start, mdns_name_t *name, char *buf, size_t packet_len) +{ + size_t index = 0; + const uint8_t *packet_end = packet + packet_len; + while (start + index < packet_end && start[index]) { + if (name->parts == 4) { + name->invalid = true; + } + uint8_t len = start[index++]; + if (len < 0xC0) { + if (len > 63) { + //length can not be more than 63 + return NULL; + } + uint8_t i; + for (i = 0; i < len; i++) { + if (start + index >= packet_end) { + return NULL; + } + buf[i] = start[index++]; + } + buf[len] = '\0'; + if (name->parts == 1 && buf[0] != '_' + && (strcasecmp(buf, MDNS_DEFAULT_DOMAIN) != 0) + && (strcasecmp(buf, "arpa") != 0) +#ifndef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + && (strcasecmp(buf, "ip6") != 0) + && (strcasecmp(buf, "in-addr") != 0) +#endif + ) { + strlcat(name->host, ".", sizeof(name->host)); + strlcat(name->host, buf, sizeof(name->host)); + } else if (strcasecmp(buf, MDNS_SUB_STR) == 0) { + name->sub = 1; + } else if (!name->invalid) { + char *mdns_name_ptrs[] = {name->host, name->service, name->proto, name->domain}; + memcpy(mdns_name_ptrs[name->parts++], buf, len + 1); + } + } else { + size_t address = (((uint16_t)len & 0x3F) << 8) | start[index++]; + if ((packet + address) >= start) { + //reference address can not be after where we are + return NULL; + } + if (_mdns_read_fqdn(packet, packet + address, name, buf, packet_len)) { + return start + index; + } + return NULL; + } + } + return start + index + 1; +} + +/** + * @brief sets uint16_t value in a packet + * + * @param packet MDNS packet + * @param index offset of uint16_t value + * @param value the value to set + */ +static inline void _mdns_set_u16(uint8_t *packet, uint16_t index, uint16_t value) +{ + if ((index + 1) >= MDNS_MAX_PACKET_SIZE) { + return; + } + packet[index] = (value >> 8) & 0xFF; + packet[index + 1] = value & 0xFF; +} + +/** + * @brief appends byte in a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param value the value to set + * + * @return length of added data: 0 on error or 1 on success + */ +static inline uint8_t _mdns_append_u8(uint8_t *packet, uint16_t *index, uint8_t value) +{ + if (*index >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + packet[*index] = value; + *index += 1; + return 1; +} + +/** + * @brief appends uint16_t in a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param value the value to set + * + * @return length of added data: 0 on error or 2 on success + */ +static inline uint8_t _mdns_append_u16(uint8_t *packet, uint16_t *index, uint16_t value) +{ + if ((*index + 1) >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + _mdns_append_u8(packet, index, (value >> 8) & 0xFF); + _mdns_append_u8(packet, index, value & 0xFF); + return 2; +} + +/** + * @brief appends uint32_t in a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param value the value to set + * + * @return length of added data: 0 on error or 4 on success + */ +static inline uint8_t _mdns_append_u32(uint8_t *packet, uint16_t *index, uint32_t value) +{ + if ((*index + 3) >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + _mdns_append_u8(packet, index, (value >> 24) & 0xFF); + _mdns_append_u8(packet, index, (value >> 16) & 0xFF); + _mdns_append_u8(packet, index, (value >> 8) & 0xFF); + _mdns_append_u8(packet, index, value & 0xFF); + return 4; +} + +/** + * @brief appends answer type, class, ttl and data length to a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param type answer type + * @param ttl answer ttl + * + * @return length of added data: 0 on error or 10 on success + */ +static inline uint8_t _mdns_append_type(uint8_t *packet, uint16_t *index, uint8_t type, bool flush, uint32_t ttl) +{ + if ((*index + 10) >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + uint16_t mdns_class = MDNS_CLASS_IN; + if (flush) { + mdns_class = MDNS_CLASS_IN_FLUSH_CACHE; + } + if (type == MDNS_ANSWER_PTR) { + _mdns_append_u16(packet, index, MDNS_TYPE_PTR); + _mdns_append_u16(packet, index, mdns_class); + } else if (type == MDNS_ANSWER_TXT) { + _mdns_append_u16(packet, index, MDNS_TYPE_TXT); + _mdns_append_u16(packet, index, mdns_class); + } else if (type == MDNS_ANSWER_SRV) { + _mdns_append_u16(packet, index, MDNS_TYPE_SRV); + _mdns_append_u16(packet, index, mdns_class); + } else if (type == MDNS_ANSWER_A) { + _mdns_append_u16(packet, index, MDNS_TYPE_A); + _mdns_append_u16(packet, index, mdns_class); + } else if (type == MDNS_ANSWER_AAAA) { + _mdns_append_u16(packet, index, MDNS_TYPE_AAAA); + _mdns_append_u16(packet, index, mdns_class); + } else { + return 0; + } + _mdns_append_u32(packet, index, ttl); + _mdns_append_u16(packet, index, 0); + return 10; +} + +static inline uint8_t _mdns_append_string_with_len(uint8_t *packet, uint16_t *index, const char *string, uint8_t len) +{ + if ((*index + len + 1) >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + _mdns_append_u8(packet, index, len); + memcpy(packet + *index, string, len); + *index += len; + return len + 1; +} + +/** + * @brief appends single string to a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param string the string to append + * + * @return length of added data: 0 on error or length of the string + 1 on success + */ +static inline uint8_t _mdns_append_string(uint8_t *packet, uint16_t *index, const char *string) +{ + uint8_t len = strlen(string); + if ((*index + len + 1) >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + _mdns_append_u8(packet, index, len); + memcpy(packet + *index, string, len); + *index += len; + return len + 1; +} + +/** + * @brief appends one TXT record ("key=value" or "key") + * + * @param packet MDNS packet + * @param index offset in the packet + * @param txt one txt record + * + * @return length of added data: length of the added txt value + 1 on success + * 0 if data won't fit the packet + * -1 if invalid TXT entry + */ +static inline int append_one_txt_record_entry(uint8_t *packet, uint16_t *index, mdns_txt_linked_item_t *txt) +{ + if (txt == NULL || txt->key == NULL) { + return -1; + } + size_t key_len = strlen(txt->key); + size_t len = key_len + txt->value_len + (txt->value ? 1 : 0); + if ((*index + len + 1) >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + _mdns_append_u8(packet, index, len); + memcpy(packet + *index, txt->key, key_len); + if (txt->value) { + packet[*index + key_len] = '='; + memcpy(packet + *index + key_len + 1, txt->value, txt->value_len); + } + *index += len; + return len + 1; +} + +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES +static inline int append_single_str(uint8_t *packet, uint16_t *index, const char *str, int len) +{ + if ((*index + len + 1) >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + if (!_mdns_append_u8(packet, index, len)) { + return 0; + } + memcpy(packet + *index, str, len); + *index += len; + return *index; +} + +/** + * @brief appends FQDN to a packet from hostname separated by dots. This API works the same way as + * _mdns_append_fqdn(), but refrains from DNS compression (as it's mainly used for IP addresses (many short items), + * where we gain very little (or compression even gets counter-productive mainly for IPv6 addresses) + * + * @param packet MDNS packet + * @param index offset in the packet + * @param name name representing FQDN in '.' separated parts + * @param last true if appending the last part (domain, typically "arpa") + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t append_fqdn_dots(uint8_t *packet, uint16_t *index, const char *name, bool last) +{ + int len = strlen(name); + char *host = (char *)name; + char *end = host; + char *start = host; + do { + end = memchr(start, '.', host + len - start); + end = end ? end : host + len; + int part_len = end - start; + if (!append_single_str(packet, index, start, part_len)) { + return 0; + } + start = ++end; + } while (end < name + len); + + if (!append_single_str(packet, index, "arpa", sizeof("arpa") - 1)) { + return 0; + } + + //empty string so terminate + if (!_mdns_append_u8(packet, index, 0)) { + return 0; + } + return *index; +} +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + +/** + * @brief appends FQDN to a packet, incrementing the index and + * compressing the output if previous occurrence of the string (or part of it) has been found + * + * @param packet MDNS packet + * @param index offset in the packet + * @param strings string array containing the parts of the FQDN + * @param count number of strings in the array + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t _mdns_append_fqdn(uint8_t *packet, uint16_t *index, const char *strings[], uint8_t count, size_t packet_len) +{ + if (!count) { + //empty string so terminate + return _mdns_append_u8(packet, index, 0); + } + mdns_name_t name; + static char buf[MDNS_NAME_BUF_LEN]; + uint8_t len = strlen(strings[0]); + //try to find first the string length in the packet (if it exists) + uint8_t *len_location = (uint8_t *)memchr(packet, (char)len, *index); + while (len_location) { + //check if the string after len_location is the string that we are looking for + if (memcmp(len_location + 1, strings[0], len)) { //not continuing with our string +search_next: + //try and find the length byte further in the packet + len_location = (uint8_t *)memchr(len_location + 1, (char)len, *index - (len_location + 1 - packet)); + continue; + } + //seems that we might have found the string that we are looking for + //read the destination into name and compare + name.parts = 0; + name.sub = 0; + name.invalid = false; + name.host[0] = 0; + name.service[0] = 0; + name.proto[0] = 0; + name.domain[0] = 0; + const uint8_t *content = _mdns_read_fqdn(packet, len_location, &name, buf, packet_len); + if (!content) { + //not a readable fqdn? + goto search_next; // could be our unfinished fqdn, continue searching + } + if (name.parts == count) { + uint8_t i; + for (i = 0; i < count; i++) { + if (strcasecmp(strings[i], (const char *)&name + (i * (MDNS_NAME_BUF_LEN)))) { + //not our string! let's search more + goto search_next; + } + } + //we actually have found the string + break; + } else { + goto search_next; + } + } + //string is not yet in the packet, so let's add it + if (!len_location) { + uint8_t written = _mdns_append_string(packet, index, strings[0]); + if (!written) { + return 0; + } + //run the same for the other strings in the name + return written + _mdns_append_fqdn(packet, index, &strings[1], count - 1, packet_len); + } + + //we have found the string so let's insert a pointer to it instead + uint16_t offset = len_location - packet; + offset |= MDNS_NAME_REF; + return _mdns_append_u16(packet, index, offset); +} + +/** + * @brief appends PTR record for service to a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param server the server that is hosting the service + * @param service the service to add record for + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t _mdns_append_ptr_record(uint8_t *packet, uint16_t *index, const char *instance, const char *service, const char *proto, bool flush, bool bye) +{ + const char *str[4]; + uint16_t record_length = 0; + uint8_t part_length; + + if (service == NULL) { + return 0; + } + + str[0] = instance; + str[1] = service; + str[2] = proto; + str[3] = MDNS_DEFAULT_DOMAIN; + + part_length = _mdns_append_fqdn(packet, index, str + 1, 3, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + record_length += part_length; + + part_length = _mdns_append_type(packet, index, MDNS_ANSWER_PTR, false, bye ? 0 : MDNS_ANSWER_PTR_TTL); + if (!part_length) { + return 0; + } + record_length += part_length; + + uint16_t data_len_location = *index - 2; + part_length = _mdns_append_fqdn(packet, index, str, 4, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + _mdns_set_u16(packet, data_len_location, part_length); + record_length += part_length; + return record_length; +} + +/** + * @brief appends PTR record for a subtype to a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param instance the service instance name + * @param subtype the service subtype + * @param proto the service protocol + * @param flush whether to set the flush flag + * @param bye whether to set the bye flag + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t _mdns_append_subtype_ptr_record(uint8_t *packet, uint16_t *index, const char *instance, + const char *subtype, const char *service, const char *proto, bool flush, + bool bye) +{ + const char *subtype_str[5] = {subtype, MDNS_SUB_STR, service, proto, MDNS_DEFAULT_DOMAIN}; + const char *instance_str[4] = {instance, service, proto, MDNS_DEFAULT_DOMAIN}; + uint16_t record_length = 0; + uint8_t part_length; + + if (service == NULL) { + return 0; + } + + part_length = _mdns_append_fqdn(packet, index, subtype_str, ARRAY_SIZE(subtype_str), MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + record_length += part_length; + + part_length = _mdns_append_type(packet, index, MDNS_ANSWER_PTR, false, bye ? 0 : MDNS_ANSWER_PTR_TTL); + if (!part_length) { + return 0; + } + record_length += part_length; + + uint16_t data_len_location = *index - 2; + part_length = _mdns_append_fqdn(packet, index, instance_str, ARRAY_SIZE(instance_str), MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + _mdns_set_u16(packet, data_len_location, part_length); + record_length += part_length; + return record_length; +} + +/** + * @brief appends DNS-SD PTR record for service to a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param server the server that is hosting the service + * @param service the service to add record for + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t _mdns_append_sdptr_record(uint8_t *packet, uint16_t *index, mdns_service_t *service, bool flush, bool bye) +{ + const char *str[3]; + const char *sd_str[4]; + uint16_t record_length = 0; + uint8_t part_length; + + if (service == NULL) { + return 0; + } + + sd_str[0] = (char *)"_services"; + sd_str[1] = (char *)"_dns-sd"; + sd_str[2] = (char *)"_udp"; + sd_str[3] = MDNS_DEFAULT_DOMAIN; + + str[0] = service->service; + str[1] = service->proto; + str[2] = MDNS_DEFAULT_DOMAIN; + + part_length = _mdns_append_fqdn(packet, index, sd_str, 4, MDNS_MAX_PACKET_SIZE); + + record_length += part_length; + + part_length = _mdns_append_type(packet, index, MDNS_ANSWER_PTR, flush, MDNS_ANSWER_PTR_TTL); + if (!part_length) { + return 0; + } + record_length += part_length; + + uint16_t data_len_location = *index - 2; + part_length = _mdns_append_fqdn(packet, index, str, 3, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + _mdns_set_u16(packet, data_len_location, part_length); + record_length += part_length; + return record_length; +} + +/** + * @brief appends TXT record for service to a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param server the server that is hosting the service + * @param service the service to add record for + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t _mdns_append_txt_record(uint8_t *packet, uint16_t *index, mdns_service_t *service, bool flush, bool bye) +{ + const char *str[4]; + uint16_t record_length = 0; + uint8_t part_length; + + if (service == NULL) { + return 0; + } + + str[0] = _mdns_get_service_instance_name(service); + str[1] = service->service; + str[2] = service->proto; + str[3] = MDNS_DEFAULT_DOMAIN; + + if (!str[0]) { + return 0; + } + + part_length = _mdns_append_fqdn(packet, index, str, 4, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + record_length += part_length; + + part_length = _mdns_append_type(packet, index, MDNS_ANSWER_TXT, flush, bye ? 0 : MDNS_ANSWER_TXT_TTL); + if (!part_length) { + return 0; + } + record_length += part_length; + + uint16_t data_len_location = *index - 2; + uint16_t data_len = 0; + + mdns_txt_linked_item_t *txt = service->txt; + while (txt) { + int l = append_one_txt_record_entry(packet, index, txt); + if (l > 0) { + data_len += l; + } else if (l == 0) { // TXT entry won't fit into the mdns packet + return 0; + } + txt = txt->next; + } + if (!data_len) { + data_len = 1; + packet[*index] = 0; + *index = *index + 1; + } + _mdns_set_u16(packet, data_len_location, data_len); + record_length += data_len; + return record_length; +} + +/** + * @brief appends SRV record for service to a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param server the server that is hosting the service + * @param service the service to add record for + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t _mdns_append_srv_record(uint8_t *packet, uint16_t *index, mdns_service_t *service, bool flush, bool bye) +{ + const char *str[4]; + uint16_t record_length = 0; + uint8_t part_length; + + if (service == NULL) { + return 0; + } + + str[0] = _mdns_get_service_instance_name(service); + str[1] = service->service; + str[2] = service->proto; + str[3] = MDNS_DEFAULT_DOMAIN; + + if (!str[0]) { + return 0; + } + + part_length = _mdns_append_fqdn(packet, index, str, 4, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + record_length += part_length; + + part_length = _mdns_append_type(packet, index, MDNS_ANSWER_SRV, flush, bye ? 0 : MDNS_ANSWER_SRV_TTL); + if (!part_length) { + return 0; + } + record_length += part_length; + + uint16_t data_len_location = *index - 2; + + part_length = 0; + part_length += _mdns_append_u16(packet, index, service->priority); + part_length += _mdns_append_u16(packet, index, service->weight); + part_length += _mdns_append_u16(packet, index, service->port); + if (part_length != 6) { + return 0; + } + + if (service->hostname) { + str[0] = service->hostname; + } else { + str[0] = _mdns_server->hostname; + } + str[1] = MDNS_DEFAULT_DOMAIN; + + if (_str_null_or_empty(str[0])) { + return 0; + } + + part_length = _mdns_append_fqdn(packet, index, str, 2, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + _mdns_set_u16(packet, data_len_location, part_length + 6); + + record_length += part_length + 6; + return record_length; +} + +#ifdef CONFIG_LWIP_IPV4 +/** + * @brief appends A record to a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param hostname the hostname address to add + * @param ip the IP address to add + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t _mdns_append_a_record(uint8_t *packet, uint16_t *index, const char *hostname, uint32_t ip, bool flush, bool bye) +{ + const char *str[2]; + uint16_t record_length = 0; + uint8_t part_length; + + str[0] = hostname; + str[1] = MDNS_DEFAULT_DOMAIN; + + if (_str_null_or_empty(str[0])) { + return 0; + } + + part_length = _mdns_append_fqdn(packet, index, str, 2, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + record_length += part_length; + + part_length = _mdns_append_type(packet, index, MDNS_ANSWER_A, flush, bye ? 0 : MDNS_ANSWER_A_TTL); + if (!part_length) { + return 0; + } + record_length += part_length; + + uint16_t data_len_location = *index - 2; + + if ((*index + 3) >= MDNS_MAX_PACKET_SIZE) { + return 0; + } + _mdns_append_u8(packet, index, ip & 0xFF); + _mdns_append_u8(packet, index, (ip >> 8) & 0xFF); + _mdns_append_u8(packet, index, (ip >> 16) & 0xFF); + _mdns_append_u8(packet, index, (ip >> 24) & 0xFF); + _mdns_set_u16(packet, data_len_location, 4); + + record_length += 4; + return record_length; +} +#endif /* CONFIG_LWIP_IPV4 */ + +#ifdef CONFIG_LWIP_IPV6 +/** + * @brief appends AAAA record to a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param hostname the hostname address to add + * @param ipv6 the IPv6 address to add + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t _mdns_append_aaaa_record(uint8_t *packet, uint16_t *index, const char *hostname, uint8_t *ipv6, bool flush, bool bye) +{ + const char *str[2]; + uint16_t record_length = 0; + uint8_t part_length; + + str[0] = hostname; + str[1] = MDNS_DEFAULT_DOMAIN; + + if (_str_null_or_empty(str[0])) { + return 0; + } + + + part_length = _mdns_append_fqdn(packet, index, str, 2, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + record_length += part_length; + + part_length = _mdns_append_type(packet, index, MDNS_ANSWER_AAAA, flush, bye ? 0 : MDNS_ANSWER_AAAA_TTL); + if (!part_length) { + return 0; + } + record_length += part_length; + + uint16_t data_len_location = *index - 2; + + if ((*index + MDNS_ANSWER_AAAA_SIZE) > MDNS_MAX_PACKET_SIZE) { + return 0; + } + + part_length = MDNS_ANSWER_AAAA_SIZE; + memcpy(packet + *index, ipv6, part_length); + *index += part_length; + _mdns_set_u16(packet, data_len_location, part_length); + record_length += part_length; + return record_length; +} +#endif + +/** + * @brief Append question to packet + */ +static uint16_t _mdns_append_question(uint8_t *packet, uint16_t *index, mdns_out_question_t *q) +{ + uint8_t part_length; +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + if (q->host && (strstr(q->host, "in-addr") || strstr(q->host, "ip6"))) { + part_length = append_fqdn_dots(packet, index, q->host, false); + if (!part_length) { + return 0; + } + } else +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + { + const char *str[4]; + uint8_t str_index = 0; + if (q->host) { + str[str_index++] = q->host; + } + if (q->service) { + str[str_index++] = q->service; + } + if (q->proto) { + str[str_index++] = q->proto; + } + if (q->domain) { + str[str_index++] = q->domain; + } + part_length = _mdns_append_fqdn(packet, index, str, str_index, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + } + + part_length += _mdns_append_u16(packet, index, q->type); + part_length += _mdns_append_u16(packet, index, q->unicast ? 0x8001 : 0x0001); + return part_length; +} + +/** + * @brief Helper to get either ETH or STA if the other is provided + * Used when two interfaces are on the same subnet + */ +static mdns_if_t _mdns_get_other_if (mdns_if_t tcpip_if) +{ + if (tcpip_if < MDNS_MAX_INTERFACES) { + return s_esp_netifs[tcpip_if].duplicate; + } + return MDNS_MAX_INTERFACES; +} + +/** + * @brief Check if interface is duplicate (two interfaces on the same subnet) + */ +static bool _mdns_if_is_dup(mdns_if_t tcpip_if) +{ + mdns_if_t other_if = _mdns_get_other_if (tcpip_if); + if (other_if == MDNS_MAX_INTERFACES) { + return false; + } + if (_mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].state == PCB_DUP + || _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].state == PCB_DUP + || _mdns_server->interfaces[other_if].pcbs[MDNS_IP_PROTOCOL_V4].state == PCB_DUP + || _mdns_server->interfaces[other_if].pcbs[MDNS_IP_PROTOCOL_V6].state == PCB_DUP + ) { + return true; + } + return false; +} + +#ifdef CONFIG_LWIP_IPV6 +/** + * @brief Check if IPv6 address is NULL + */ +static bool _ipv6_address_is_zero(esp_ip6_addr_t ip6) +{ + uint8_t i; + uint8_t *data = (uint8_t *)ip6.addr; + for (i = 0; i < _MDNS_SIZEOF_IP6_ADDR; i++) { + if (data[i]) { + return false; + } + } + return true; +} +#endif /* CONFIG_LWIP_IPV6 */ + +static uint8_t _mdns_append_host_answer(uint8_t *packet, uint16_t *index, mdns_host_item_t *host, + uint8_t address_type, bool flush, bool bye) +{ + mdns_ip_addr_t *addr = host->address_list; + uint8_t num_records = 0; + + while (addr != NULL) { + if (addr->addr.type == address_type) { +#ifdef CONFIG_LWIP_IPV4 + if (address_type == ESP_IPADDR_TYPE_V4 && + _mdns_append_a_record(packet, index, host->hostname, addr->addr.u_addr.ip4.addr, flush, bye) <= 0) { + break; + } +#endif /* CONFIG_LWIP_IPV4 */ +#ifdef CONFIG_LWIP_IPV6 + if (address_type == ESP_IPADDR_TYPE_V6 && + _mdns_append_aaaa_record(packet, index, host->hostname, (uint8_t *)addr->addr.u_addr.ip6.addr, flush, + bye) <= 0) { + break; + } +#endif /* CONFIG_LWIP_IPV6 */ + num_records++; + } + addr = addr->next; + } + return num_records; +} + +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES +/** + * @brief Appends reverse lookup PTR record + */ +static uint8_t _mdns_append_reverse_ptr_record(uint8_t *packet, uint16_t *index, const char *name) +{ + if (strstr(name, "in-addr") == NULL && strstr(name, "ip6") == NULL) { + return 0; + } + + if (!append_fqdn_dots(packet, index, name, false)) { + return 0; + } + + if (!_mdns_append_type(packet, index, MDNS_ANSWER_PTR, false, 10 /* TTL set to 10s*/ )) { + return 0; + } + + uint16_t data_len_location = *index - 2; /* store the position of size (2=16bis) of this record */ + const char *str[2] = { _mdns_self_host.hostname, MDNS_DEFAULT_DOMAIN }; + + int part_length = _mdns_append_fqdn(packet, index, str, 2, MDNS_MAX_PACKET_SIZE); + if (!part_length) { + return 0; + } + + _mdns_set_u16(packet, data_len_location, part_length); + return 1; /* appending only 1 record */ +} +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + +/** + * @brief Append PTR answers to packet + * + * @return number of answers added to the packet + */ +static uint8_t _mdns_append_service_ptr_answers(uint8_t *packet, uint16_t *index, mdns_service_t *service, bool flush, + bool bye) +{ + uint8_t appended_answers = 0; + + if (_mdns_append_ptr_record(packet, index, _mdns_get_service_instance_name(service), service->service, + service->proto, flush, bye) <= 0) { + return appended_answers; + } + appended_answers++; + + mdns_subtype_t *subtype = service->subtype; + while (subtype) { + appended_answers += + (_mdns_append_subtype_ptr_record(packet, index, _mdns_get_service_instance_name(service), subtype->subtype, + service->service, service->proto, flush, bye) > 0); + subtype = subtype->next; + } + + return appended_answers; +} + + +/** + * @brief Append answer to packet + * + * @return number of answers added to the packet + */ +static uint8_t _mdns_append_answer(uint8_t *packet, uint16_t *index, mdns_out_answer_t *answer, mdns_if_t tcpip_if) +{ + if (answer->host) { + bool is_host_valid = (&_mdns_self_host == answer->host); + mdns_host_item_t *target_host = _mdns_host_list; + while (target_host && !is_host_valid) { + if (target_host == answer->host) { + is_host_valid = true; + } + target_host = target_host->next; + } + if (!is_host_valid) { + return 0; + } + } + + if (answer->type == MDNS_TYPE_PTR) { + if (answer->service) { + return _mdns_append_service_ptr_answers(packet, index, answer->service, answer->flush, answer->bye); +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + } else if (answer->host && answer->host->hostname && + (strstr(answer->host->hostname, "in-addr") || strstr(answer->host->hostname, "ip6"))) { + return _mdns_append_reverse_ptr_record(packet, index, answer->host->hostname) > 0; +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + } else { + return _mdns_append_ptr_record(packet, index, + answer->custom_instance, answer->custom_service, answer->custom_proto, + answer->flush, answer->bye) > 0; + } + } else if (answer->type == MDNS_TYPE_SRV) { + return _mdns_append_srv_record(packet, index, answer->service, answer->flush, answer->bye) > 0; + } else if (answer->type == MDNS_TYPE_TXT) { + return _mdns_append_txt_record(packet, index, answer->service, answer->flush, answer->bye) > 0; + } else if (answer->type == MDNS_TYPE_SDPTR) { + return _mdns_append_sdptr_record(packet, index, answer->service, answer->flush, answer->bye) > 0; + } +#ifdef CONFIG_LWIP_IPV4 + else if (answer->type == MDNS_TYPE_A) { + if (answer->host == &_mdns_self_host) { + esp_netif_ip_info_t if_ip_info; + if (!mdns_is_netif_ready(tcpip_if, MDNS_IP_PROTOCOL_V4) && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V4].state != PCB_DUP) { + return 0; + } + if (esp_netif_get_ip_info(_mdns_get_esp_netif(tcpip_if), &if_ip_info)) { + return 0; + } + if (_mdns_append_a_record(packet, index, _mdns_server->hostname, if_ip_info.ip.addr, answer->flush, answer->bye) <= 0) { + return 0; + } + if (!_mdns_if_is_dup(tcpip_if)) { + return 1; + } + mdns_if_t other_if = _mdns_get_other_if (tcpip_if); + if (esp_netif_get_ip_info(_mdns_get_esp_netif(other_if), &if_ip_info)) { + return 1; + } + if (_mdns_append_a_record(packet, index, _mdns_server->hostname, if_ip_info.ip.addr, answer->flush, answer->bye) > 0) { + return 2; + } + return 1; + } else if (answer->host != NULL) { + return _mdns_append_host_answer(packet, index, answer->host, ESP_IPADDR_TYPE_V4, answer->flush, answer->bye); + } + } +#endif /* CONFIG_LWIP_IPV4 */ +#ifdef CONFIG_LWIP_IPV6 + else if (answer->type == MDNS_TYPE_AAAA) { + if (answer->host == &_mdns_self_host) { + struct esp_ip6_addr if_ip6s[NETIF_IPV6_MAX_NUMS]; + uint8_t count = 0; + if (!mdns_is_netif_ready(tcpip_if, MDNS_IP_PROTOCOL_V6) && _mdns_server->interfaces[tcpip_if].pcbs[MDNS_IP_PROTOCOL_V6].state != PCB_DUP) { + return 0; + } + count = esp_netif_get_all_ip6(_mdns_get_esp_netif(tcpip_if), if_ip6s); + assert(count <= NETIF_IPV6_MAX_NUMS); + for (int i = 0; i < count; i++) { + if (_ipv6_address_is_zero(if_ip6s[i])) { + return 0; + } + if (_mdns_append_aaaa_record(packet, index, _mdns_server->hostname, (uint8_t *)if_ip6s[i].addr, + answer->flush, answer->bye) <= 0) { + return 0; + } + } + if (!_mdns_if_is_dup(tcpip_if)) { + return count; + } + + mdns_if_t other_if = _mdns_get_other_if(tcpip_if); + struct esp_ip6_addr other_ip6; + if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(other_if), &other_ip6)) { + return count; + } + if (_mdns_append_aaaa_record(packet, index, _mdns_server->hostname, (uint8_t *)other_ip6.addr, + answer->flush, answer->bye) > 0) { + return 1 + count; + } + return count; + } else if (answer->host != NULL) { + return _mdns_append_host_answer(packet, index, answer->host, ESP_IPADDR_TYPE_V6, answer->flush, + answer->bye); + } + } +#endif /* CONFIG_LWIP_IPV6 */ + return 0; +} + +/** + * @brief sends a packet + * + * @param p the packet + */ +static void _mdns_dispatch_tx_packet(mdns_tx_packet_t *p) +{ + static uint8_t packet[MDNS_MAX_PACKET_SIZE]; + uint16_t index = MDNS_HEAD_LEN; + memset(packet, 0, MDNS_HEAD_LEN); + mdns_out_question_t *q; + mdns_out_answer_t *a; + uint8_t count; + + _mdns_set_u16(packet, MDNS_HEAD_FLAGS_OFFSET, p->flags); + _mdns_set_u16(packet, MDNS_HEAD_ID_OFFSET, p->id); + + count = 0; + q = p->questions; + while (q) { + if (_mdns_append_question(packet, &index, q)) { + count++; + } + q = q->next; + } + _mdns_set_u16(packet, MDNS_HEAD_QUESTIONS_OFFSET, count); + + count = 0; + a = p->answers; + while (a) { + count += _mdns_append_answer(packet, &index, a, p->tcpip_if); + a = a->next; + } + _mdns_set_u16(packet, MDNS_HEAD_ANSWERS_OFFSET, count); + + count = 0; + a = p->servers; + while (a) { + count += _mdns_append_answer(packet, &index, a, p->tcpip_if); + a = a->next; + } + _mdns_set_u16(packet, MDNS_HEAD_SERVERS_OFFSET, count); + + count = 0; + a = p->additional; + while (a) { + count += _mdns_append_answer(packet, &index, a, p->tcpip_if); + a = a->next; + } + _mdns_set_u16(packet, MDNS_HEAD_ADDITIONAL_OFFSET, count); + +#ifdef MDNS_ENABLE_DEBUG + _mdns_dbg_printf("\nTX[%lu][%lu]: ", (unsigned long)p->tcpip_if, (unsigned long)p->ip_protocol); +#ifdef CONFIG_LWIP_IPV4 + if (p->dst.type == ESP_IPADDR_TYPE_V4) { + _mdns_dbg_printf("To: " IPSTR ":%u, ", IP2STR(&p->dst.u_addr.ip4), p->port); + } +#endif +#ifdef CONFIG_LWIP_IPV6 + if (p->dst.type == ESP_IPADDR_TYPE_V6) { + _mdns_dbg_printf("To: " IPV6STR ":%u, ", IPV62STR(p->dst.u_addr.ip6), p->port); + } +#endif + mdns_debug_packet(packet, index); +#endif + + _mdns_udp_pcb_write(p->tcpip_if, p->ip_protocol, &p->dst, p->port, packet, index); +} + +/** + * @brief frees a packet + * + * @param packet the packet + */ +static void _mdns_free_tx_packet(mdns_tx_packet_t *packet) +{ + if (!packet) { + return; + } + mdns_out_question_t *q = packet->questions; + while (q) { + mdns_out_question_t *next = q->next; + if (q->own_dynamic_memory) { + free((char *)q->host); + free((char *)q->service); + free((char *)q->proto); + free((char *)q->domain); + } + free(q); + q = next; + } + queueFree(mdns_out_answer_t, packet->answers); + queueFree(mdns_out_answer_t, packet->servers); + queueFree(mdns_out_answer_t, packet->additional); + free(packet); +} + +/** + * @brief schedules a packet to be sent after given milliseconds + * + * @param packet the packet + * @param ms_after number of milliseconds after which the packet should be dispatched + */ +static void _mdns_schedule_tx_packet(mdns_tx_packet_t *packet, uint32_t ms_after) +{ + if (!packet) { + return; + } + packet->send_at = (xTaskGetTickCount() * portTICK_PERIOD_MS) + ms_after; + packet->next = NULL; + if (!_mdns_server->tx_queue_head || _mdns_server->tx_queue_head->send_at > packet->send_at) { + packet->next = _mdns_server->tx_queue_head; + _mdns_server->tx_queue_head = packet; + return; + } + mdns_tx_packet_t *q = _mdns_server->tx_queue_head; + while (q->next && q->next->send_at <= packet->send_at) { + q = q->next; + } + packet->next = q->next; + q->next = packet; +} + +/** + * @brief free all packets scheduled for sending + */ +static void _mdns_clear_tx_queue_head(void) +{ + mdns_tx_packet_t *q; + while (_mdns_server->tx_queue_head) { + q = _mdns_server->tx_queue_head; + _mdns_server->tx_queue_head = _mdns_server->tx_queue_head->next; + _mdns_free_tx_packet(q); + } +} + +/** + * @brief clear packets scheduled for sending on a specific interface + * + * @param tcpip_if the interface + * @param ip_protocol pcb type V4/V6 + */ +static void _mdns_clear_pcb_tx_queue_head(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_tx_packet_t *q, * p; + while (_mdns_server->tx_queue_head && _mdns_server->tx_queue_head->tcpip_if == tcpip_if && _mdns_server->tx_queue_head->ip_protocol == ip_protocol) { + q = _mdns_server->tx_queue_head; + _mdns_server->tx_queue_head = _mdns_server->tx_queue_head->next; + _mdns_free_tx_packet(q); + } + if (_mdns_server->tx_queue_head) { + q = _mdns_server->tx_queue_head; + while (q->next) { + if (q->next->tcpip_if == tcpip_if && q->next->ip_protocol == ip_protocol) { + p = q->next; + q->next = p->next; + _mdns_free_tx_packet(p); + } else { + q = q->next; + } + } + } +} + +/** + * @brief get the next packet scheduled for sending on a specific interface + * + * @param tcpip_if the interface + * @param ip_protocol pcb type V4/V6 + */ +static mdns_tx_packet_t *_mdns_get_next_pcb_packet(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_tx_packet_t *q = _mdns_server->tx_queue_head; + while (q) { + if (q->tcpip_if == tcpip_if && q->ip_protocol == ip_protocol) { + return q; + } + q = q->next; + } + return NULL; +} + +/** + * @brief Find, remove and free answer from the scheduled packets + */ +static void _mdns_remove_scheduled_answer(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint16_t type, mdns_srv_item_t *service) +{ + mdns_srv_item_t s = {NULL, NULL}; + if (!service) { + service = &s; + } + mdns_tx_packet_t *q = _mdns_server->tx_queue_head; + while (q) { + if (q->tcpip_if == tcpip_if && q->ip_protocol == ip_protocol && q->distributed) { + mdns_out_answer_t *a = q->answers; + if (a) { + if (a->type == type && a->service == service->service) { + q->answers = q->answers->next; + free(a); + } else { + while (a->next) { + if (a->next->type == type && a->next->service == service->service) { + mdns_out_answer_t *b = a->next; + a->next = b->next; + free(b); + break; + } + a = a->next; + } + } + } + } + q = q->next; + } +} + +/** + * @brief Remove and free answer from answer list (destination) + */ +static void _mdns_dealloc_answer(mdns_out_answer_t **destination, uint16_t type, mdns_srv_item_t *service) +{ + mdns_out_answer_t *d = *destination; + if (!d) { + return; + } + mdns_srv_item_t s = {NULL, NULL}; + if (!service) { + service = &s; + } + if (d->type == type && d->service == service->service) { + *destination = d->next; + free(d); + return; + } + while (d->next) { + mdns_out_answer_t *a = d->next; + if (a->type == type && a->service == service->service) { + d->next = a->next; + free(a); + return; + } + d = d->next; + } +} + +/** + * @brief Allocate new answer and add it to answer list (destination) + */ +static bool _mdns_alloc_answer(mdns_out_answer_t **destination, uint16_t type, mdns_service_t *service, + mdns_host_item_t *host, bool flush, bool bye) +{ + mdns_out_answer_t *d = *destination; + while (d) { + if (d->type == type && d->service == service && d->host == host) { + return true; + } + d = d->next; + } + + mdns_out_answer_t *a = (mdns_out_answer_t *)malloc(sizeof(mdns_out_answer_t)); + if (!a) { + HOOK_MALLOC_FAILED; + return false; + } + a->type = type; + a->service = service; + a->host = host; + a->custom_service = NULL; + a->bye = bye; + a->flush = flush; + a->next = NULL; + queueToEnd(mdns_out_answer_t, *destination, a); + return true; +} + +/** + * @brief Allocate new packet for sending + */ +static mdns_tx_packet_t *_mdns_alloc_packet_default(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_tx_packet_t *packet = (mdns_tx_packet_t *)malloc(sizeof(mdns_tx_packet_t)); + if (!packet) { + HOOK_MALLOC_FAILED; + return NULL; + } + memset((uint8_t *)packet, 0, sizeof(mdns_tx_packet_t)); + packet->tcpip_if = tcpip_if; + packet->ip_protocol = ip_protocol; + packet->port = MDNS_SERVICE_PORT; +#ifdef CONFIG_LWIP_IPV4 + if (ip_protocol == MDNS_IP_PROTOCOL_V4) { + esp_ip_addr_t addr = ESP_IP4ADDR_INIT(224, 0, 0, 251); + memcpy(&packet->dst, &addr, sizeof(esp_ip_addr_t)); + } +#endif +#ifdef CONFIG_LWIP_IPV6 + if (ip_protocol == MDNS_IP_PROTOCOL_V6) { + esp_ip_addr_t addr = ESP_IP6ADDR_INIT(0x000002ff, 0, 0, 0xfb000000); + memcpy(&packet->dst, &addr, sizeof(esp_ip_addr_t)); + } +#endif + return packet; +} + +static bool _mdns_create_answer_from_service(mdns_tx_packet_t *packet, mdns_service_t *service, + mdns_parsed_question_t *question, bool shared, bool send_flush) +{ + mdns_host_item_t *host = mdns_get_host_item(service->hostname); + bool is_delegated = (host != &_mdns_self_host); + if (question->type == MDNS_TYPE_PTR || question->type == MDNS_TYPE_ANY) { + // According to RFC6763-section12.1, for DNS-SD, SRV, TXT and all address records + // should be included in additional records. + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, service, NULL, false, false) || + !_mdns_alloc_answer(is_delegated ? &packet->additional : &packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) || + !_mdns_alloc_answer(is_delegated ? &packet->additional : &packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false) || + !_mdns_alloc_answer((shared || is_delegated) ? &packet->additional : &packet->answers, MDNS_TYPE_A, service, host, send_flush, + false) || + !_mdns_alloc_answer((shared || is_delegated) ? &packet->additional : &packet->answers, MDNS_TYPE_AAAA, service, host, + send_flush, false)) { + return false; + } + } else if (question->type == MDNS_TYPE_SRV) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, service, NULL, send_flush, false) || + !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_A, service, host, send_flush, false) || + !_mdns_alloc_answer(&packet->additional, MDNS_TYPE_AAAA, service, host, send_flush, false)) { + return false; + } + } else if (question->type == MDNS_TYPE_TXT) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, service, NULL, send_flush, false)) { + return false; + } + } else if (question->type == MDNS_TYPE_SDPTR) { + shared = true; + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, service, NULL, false, false)) { + return false; + } + } + return true; +} + +static bool _mdns_create_answer_from_hostname(mdns_tx_packet_t *packet, const char *hostname, bool send_flush) +{ + mdns_host_item_t *host = mdns_get_host_item(hostname); + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, host, send_flush, false) || + !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, host, send_flush, false)) { + return false; + } + return true; +} + +static bool _mdns_service_match_ptr_question(const mdns_service_t *service, const mdns_parsed_question_t *question) +{ + if (!_mdns_service_match(service, question->service, question->proto, NULL)) { + return false; + } + // The question parser stores anything before _type._proto in question->host + // So the question->host can be subtype or instance name based on its content + if (question->sub) { + mdns_subtype_t *subtype = service->subtype; + while (subtype) { + if (!strcasecmp(subtype->subtype, question->host)) { + return true; + } + subtype = subtype->next; + } + return false; + } + if (question->host) { + if (strcasecmp(_mdns_get_service_instance_name(service), question->host) != 0) { + return false; + } + } + return true; +} + +/** + * @brief Create answer packet to questions from parsed packet + */ +static void _mdns_create_answer_from_parsed_packet(mdns_parsed_packet_t *parsed_packet) +{ + if (!parsed_packet->questions) { + return; + } + bool send_flush = parsed_packet->src_port == MDNS_SERVICE_PORT; + bool unicast = false; + bool shared = false; + mdns_tx_packet_t *packet = _mdns_alloc_packet_default(parsed_packet->tcpip_if, parsed_packet->ip_protocol); + if (!packet) { + return; + } + packet->flags = MDNS_FLAGS_QR_AUTHORITATIVE; + packet->distributed = parsed_packet->distributed; + packet->id = parsed_packet->id; + + mdns_parsed_question_t *q = parsed_packet->questions; + uint32_t out_record_nums = 0; + while (q) { + shared = q->type == MDNS_TYPE_PTR || q->type == MDNS_TYPE_SDPTR || !parsed_packet->probe; + if (q->type == MDNS_TYPE_SRV || q->type == MDNS_TYPE_TXT) { + mdns_srv_item_t *service = _mdns_get_service_item_instance(q->host, q->service, q->proto, NULL); + if (service == NULL || !_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) { + _mdns_free_tx_packet(packet); + return; + } else { + out_record_nums++; + } + } else if (q->service && q->proto) { + mdns_srv_item_t *service = _mdns_server->services; + while (service) { + if (_mdns_service_match_ptr_question(service->service, q)) { + mdns_parsed_record_t *r = parsed_packet->records; + bool is_record_exist = false; + while (r) { + if (service->service->instance && r->host) { + if (_mdns_service_match_instance(service->service, r->host, r->service, r->proto, NULL) && r->ttl > (MDNS_ANSWER_PTR_TTL / 2)) { + is_record_exist = true; + break; + } + } else if (!service->service->instance && !r->host) { + if (_mdns_service_match(service->service, r->service, r->proto, NULL) && r->ttl > (MDNS_ANSWER_PTR_TTL / 2)) { + is_record_exist = true; + break; + } + } + r = r->next; + } + if (!is_record_exist) { + if (!_mdns_create_answer_from_service(packet, service->service, q, shared, send_flush)) { + _mdns_free_tx_packet(packet); + return; + } else { + out_record_nums++; + } + } + } + service = service->next; + } + } else if (q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA) { + if (!_mdns_create_answer_from_hostname(packet, q->host, send_flush)) { + _mdns_free_tx_packet(packet); + return; + } else { + out_record_nums++; + } + } else if (q->type == MDNS_TYPE_ANY) { + if (!_mdns_append_host_list(&packet->answers, send_flush, false)) { + _mdns_free_tx_packet(packet); + return; + } else { + out_record_nums++; + } +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + } else if (q->type == MDNS_TYPE_PTR) { + mdns_host_item_t *host = mdns_get_host_item(q->host); + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, NULL, host, send_flush, false)) { + _mdns_free_tx_packet(packet); + return; + } else { + out_record_nums++; + } +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + } else if (!_mdns_alloc_answer(&packet->answers, q->type, NULL, NULL, send_flush, false)) { + _mdns_free_tx_packet(packet); + return; + } else { + out_record_nums++; + } + + if (parsed_packet->src_port != MDNS_SERVICE_PORT && // Repeat the queries only for "One-Shot mDNS queries" + (q->type == MDNS_TYPE_ANY || q->type == MDNS_TYPE_A || q->type == MDNS_TYPE_AAAA +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + || q->type == MDNS_TYPE_PTR +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + )) { + mdns_out_question_t *out_question = malloc(sizeof(mdns_out_question_t)); + if (out_question == NULL) { + HOOK_MALLOC_FAILED; + _mdns_free_tx_packet(packet); + return; + } + out_question->type = q->type; + out_question->unicast = q->unicast; + out_question->host = q->host; + q->host = NULL; + out_question->service = q->service; + q->service = NULL; + out_question->proto = q->proto; + q->proto = NULL; + out_question->domain = q->domain; + q->domain = NULL; + out_question->next = NULL; + out_question->own_dynamic_memory = true; + queueToEnd(mdns_out_question_t, packet->questions, out_question); + } + if (q->unicast) { + unicast = true; + } + q = q->next; + } + if (out_record_nums == 0) { + _mdns_free_tx_packet(packet); + return; + } + if (unicast || !send_flush) { + memcpy(&packet->dst, &parsed_packet->src, sizeof(esp_ip_addr_t)); + packet->port = parsed_packet->src_port; + } + + static uint8_t share_step = 0; + if (shared) { + _mdns_schedule_tx_packet(packet, 25 + (share_step * 25)); + share_step = (share_step + 1) & 0x03; + } else { + _mdns_dispatch_tx_packet(packet); + _mdns_free_tx_packet(packet); + } +} + +/** + * @brief Check if question is already in the list + */ +static bool _mdns_question_exists(mdns_out_question_t *needle, mdns_out_question_t *haystack) +{ + while (haystack) { + if (haystack->type == needle->type + && haystack->host == needle->host + && haystack->service == needle->service + && haystack->proto == needle->proto) { + return true; + } + haystack = haystack->next; + } + return false; +} + +static bool _mdns_append_host(mdns_out_answer_t **destination, mdns_host_item_t *host, bool flush, bool bye) +{ + if (!_mdns_alloc_answer(destination, MDNS_TYPE_A, NULL, host, flush, bye)) { + return false; + } + if (!_mdns_alloc_answer(destination, MDNS_TYPE_AAAA, NULL, host, flush, bye)) { + return false; + } + return true; +} + +static bool _mdns_append_host_list_in_services(mdns_out_answer_t **destination, mdns_srv_item_t *services[], + size_t services_len, bool flush, bool bye) +{ + if (services == NULL) { + mdns_host_item_t *host = mdns_get_host_item(_mdns_server->hostname); + if (host != NULL) { + return _mdns_append_host(destination, host, flush, bye); + } + return true; + } + for (size_t i = 0; i < services_len; i++) { + mdns_host_item_t *host = mdns_get_host_item(services[i]->service->hostname); + if (!_mdns_append_host(destination, host, flush, bye)) { + return false; + } + } + return true; +} + +static bool _mdns_append_host_list(mdns_out_answer_t **destination, bool flush, bool bye) +{ + if (!_str_null_or_empty(_mdns_server->hostname)) { + mdns_host_item_t *self_host = mdns_get_host_item(_mdns_server->hostname); + if (!_mdns_append_host(destination, self_host, flush, bye)) { + return false; + } + } + mdns_host_item_t *host = _mdns_host_list; + while (host != NULL) { + host = host->next; + if (!_mdns_append_host(destination, host, flush, bye)) { + return false; + } + } + return true; +} + +static bool _mdns_append_host_question(mdns_out_question_t **questions, const char *hostname, bool unicast) +{ + mdns_out_question_t *q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t)); + if (!q) { + HOOK_MALLOC_FAILED; + return false; + } + q->next = NULL; + q->unicast = unicast; + q->type = MDNS_TYPE_ANY; + q->host = hostname; + q->service = NULL; + q->proto = NULL; + q->domain = MDNS_DEFAULT_DOMAIN; + q->own_dynamic_memory = false; + if (_mdns_question_exists(q, *questions)) { + free(q); + } else { + queueToEnd(mdns_out_question_t, *questions, q); + } + return true; +} + +static bool _mdns_append_host_questions_for_services(mdns_out_question_t **questions, mdns_srv_item_t *services[], + size_t len, bool unicast) +{ + if (!_str_null_or_empty(_mdns_server->hostname) && + !_mdns_append_host_question(questions, _mdns_server->hostname, unicast)) { + return false; + } + for (size_t i = 0; i < len; i++) { + if (!_mdns_append_host_question(questions, services[i]->service->hostname, unicast)) { + return false; + } + } + return true; +} + +/** + * @brief Create probe packet for particular services on particular PCB + */ +static mdns_tx_packet_t *_mdns_create_probe_packet(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, mdns_srv_item_t *services[], size_t len, bool first, bool include_ip) +{ + mdns_tx_packet_t *packet = _mdns_alloc_packet_default(tcpip_if, ip_protocol); + if (!packet) { + return NULL; + } + + size_t i; + for (i = 0; i < len; i++) { + mdns_out_question_t *q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t)); + if (!q) { + HOOK_MALLOC_FAILED; + _mdns_free_tx_packet(packet); + return NULL; + } + q->next = NULL; + q->unicast = first; + q->type = MDNS_TYPE_ANY; + q->host = _mdns_get_service_instance_name(services[i]->service); + q->service = services[i]->service->service; + q->proto = services[i]->service->proto; + q->domain = MDNS_DEFAULT_DOMAIN; + q->own_dynamic_memory = false; + if (!q->host || _mdns_question_exists(q, packet->questions)) { + free(q); + continue; + } else { + queueToEnd(mdns_out_question_t, packet->questions, q); + } + + if (!q->host || !_mdns_alloc_answer(&packet->servers, MDNS_TYPE_SRV, services[i]->service, NULL, false, false)) { + _mdns_free_tx_packet(packet); + return NULL; + } + } + + if (include_ip) { + if (!_mdns_append_host_questions_for_services(&packet->questions, services, len, first)) { + _mdns_free_tx_packet(packet); + return NULL; + } + + if (!_mdns_append_host_list_in_services(&packet->servers, services, len, false, false)) { + _mdns_free_tx_packet(packet); + return NULL; + } + } + + return packet; +} + +/** + * @brief Create announce packet for particular services on particular PCB + */ +static mdns_tx_packet_t *_mdns_create_announce_packet(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, mdns_srv_item_t *services[], size_t len, bool include_ip) +{ + mdns_tx_packet_t *packet = _mdns_alloc_packet_default(tcpip_if, ip_protocol); + if (!packet) { + return NULL; + } + packet->flags = MDNS_FLAGS_QR_AUTHORITATIVE; + + uint8_t i; + for (i = 0; i < len; i++) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, services[i]->service, NULL, false, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, services[i]->service, NULL, false, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, services[i]->service, NULL, true, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, services[i]->service, NULL, true, false)) { + _mdns_free_tx_packet(packet); + return NULL; + } + } + if (include_ip) { + if (!_mdns_append_host_list_in_services(&packet->servers, services, len, true, false)) { + _mdns_free_tx_packet(packet); + return NULL; + } + } + return packet; +} + +/** + * @brief Convert probe packet to announce + */ +static mdns_tx_packet_t *_mdns_create_announce_from_probe(mdns_tx_packet_t *probe) +{ + mdns_tx_packet_t *packet = _mdns_alloc_packet_default(probe->tcpip_if, probe->ip_protocol); + if (!packet) { + return NULL; + } + packet->flags = MDNS_FLAGS_QR_AUTHORITATIVE; + + mdns_out_answer_t *s = probe->servers; + while (s) { + if (s->type == MDNS_TYPE_SRV) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SDPTR, s->service, NULL, false, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, s->service, NULL, false, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_SRV, s->service, NULL, true, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_TXT, s->service, NULL, true, false)) { + _mdns_free_tx_packet(packet); + return NULL; + } + mdns_host_item_t *host = mdns_get_host_item(s->service->hostname); + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_A, NULL, host, true, false) + || !_mdns_alloc_answer(&packet->answers, MDNS_TYPE_AAAA, NULL, host, true, false)) { + _mdns_free_tx_packet(packet); + return NULL; + } + + } else if (s->type == MDNS_TYPE_A || s->type == MDNS_TYPE_AAAA) { + if (!_mdns_alloc_answer(&packet->answers, s->type, NULL, s->host, true, false)) { + _mdns_free_tx_packet(packet); + return NULL; + } + } + + s = s->next; + } + return packet; +} + +/** + * @brief Send by for particular services on particular PCB + */ +static void _mdns_pcb_send_bye(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, mdns_srv_item_t **services, size_t len, bool include_ip) +{ + mdns_tx_packet_t *packet = _mdns_alloc_packet_default(tcpip_if, ip_protocol); + if (!packet) { + return; + } + packet->flags = MDNS_FLAGS_QR_AUTHORITATIVE; + size_t i; + for (i = 0; i < len; i++) { + if (!_mdns_alloc_answer(&packet->answers, MDNS_TYPE_PTR, services[i]->service, NULL, true, true)) { + _mdns_free_tx_packet(packet); + return; + } + } + if (include_ip) { + _mdns_append_host_list_in_services(&packet->answers, services, len, true, true); + } + _mdns_dispatch_tx_packet(packet); + _mdns_free_tx_packet(packet); +} + +/** + * @brief Send probe for additional services on particular PCB + */ +static void _mdns_init_pcb_probe_new_service(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, mdns_srv_item_t **services, size_t len, bool probe_ip) +{ + mdns_pcb_t *pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol]; + size_t services_final_len = len; + + if (PCB_STATE_IS_PROBING(pcb)) { + services_final_len += pcb->probe_services_len; + } + mdns_srv_item_t **_services = NULL; + if (services_final_len) { + _services = (mdns_srv_item_t **)malloc(sizeof(mdns_srv_item_t *) * services_final_len); + if (!_services) { + HOOK_MALLOC_FAILED; + return; + } + + size_t i; + for (i = 0; i < len; i++) { + _services[i] = services[i]; + } + if (pcb->probe_services) { + for (i = 0; i < pcb->probe_services_len; i++) { + _services[len + i] = pcb->probe_services[i]; + } + free(pcb->probe_services); + } + } + + probe_ip = pcb->probe_ip || probe_ip; + + pcb->probe_ip = false; + pcb->probe_services = NULL; + pcb->probe_services_len = 0; + pcb->probe_running = false; + + mdns_tx_packet_t *packet = _mdns_create_probe_packet(tcpip_if, ip_protocol, _services, services_final_len, true, probe_ip); + if (!packet) { + free(_services); + return; + } + + pcb->probe_ip = probe_ip; + pcb->probe_services = _services; + pcb->probe_services_len = services_final_len; + pcb->probe_running = true; + _mdns_schedule_tx_packet(packet, ((pcb->failed_probes > 5) ? 1000 : 120) + (esp_random() & 0x7F)); + pcb->state = PCB_PROBE_1; +} + +/** + * @brief Send probe for particular services on particular PCB + * + * Tests possible duplication on probing service structure and probes only for new entries. + * - If pcb probing then add only non-probing services and restarts probing + * - If pcb not probing, run probing for all specified services + */ +static void _mdns_init_pcb_probe(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, mdns_srv_item_t **services, size_t len, bool probe_ip) +{ + mdns_pcb_t *pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol]; + + _mdns_clear_pcb_tx_queue_head(tcpip_if, ip_protocol); + + if (_str_null_or_empty(_mdns_server->hostname)) { + pcb->state = PCB_RUNNING; + return; + } + + if (PCB_STATE_IS_PROBING(pcb)) { + // Looking for already probing services to resolve duplications + mdns_srv_item_t *new_probe_services[len]; + int new_probe_service_len = 0; + bool found; + for (size_t j = 0; j < len; ++j) { + found = false; + for (int i = 0; i < pcb->probe_services_len; ++i) { + if (pcb->probe_services[i] == services[j]) { + found = true; + break; + } + } + if (!found) { + new_probe_services[new_probe_service_len++] = services[j]; + } + } + // init probing for newly added services + _mdns_init_pcb_probe_new_service(tcpip_if, ip_protocol, + new_probe_service_len ? new_probe_services : NULL, new_probe_service_len, probe_ip); + } else { + // not probing, so init for all services + _mdns_init_pcb_probe_new_service(tcpip_if, ip_protocol, services, len, probe_ip); + } +} + +/** + * @brief Restart the responder on particular PCB + */ +static void _mdns_restart_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + size_t srv_count = 0; + mdns_srv_item_t *a = _mdns_server->services; + while (a) { + srv_count++; + a = a->next; + } + mdns_srv_item_t *services[srv_count]; + size_t i = 0; + a = _mdns_server->services; + while (a) { + services[i++] = a; + a = a->next; + } + _mdns_init_pcb_probe(tcpip_if, ip_protocol, services, srv_count, true); +} + +/** + * @brief Send by for particular services + */ +static void _mdns_send_bye(mdns_srv_item_t **services, size_t len, bool include_ip) +{ + uint8_t i, j; + if (_str_null_or_empty(_mdns_server->hostname)) { + return; + } + + for (i = 0; i < MDNS_MAX_INTERFACES; i++) { + for (j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) { + if (mdns_is_netif_ready(i, j) && _mdns_server->interfaces[i].pcbs[j].state == PCB_RUNNING) { + _mdns_pcb_send_bye((mdns_if_t)i, (mdns_ip_protocol_t)j, services, len, include_ip); + } + } + } +} + +/** + * @brief Send announcement on particular PCB + */ +static void _mdns_announce_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, mdns_srv_item_t **services, size_t len, bool include_ip) +{ + mdns_pcb_t *_pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol]; + size_t i; + if (mdns_is_netif_ready(tcpip_if, ip_protocol)) { + if (PCB_STATE_IS_PROBING(_pcb)) { + _mdns_init_pcb_probe(tcpip_if, ip_protocol, services, len, include_ip); + } else if (PCB_STATE_IS_ANNOUNCING(_pcb)) { + mdns_tx_packet_t *p = _mdns_get_next_pcb_packet(tcpip_if, ip_protocol); + if (p) { + for (i = 0; i < len; i++) { + if (!_mdns_alloc_answer(&p->answers, MDNS_TYPE_SDPTR, services[i]->service, NULL, false, false) + || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_PTR, services[i]->service, NULL, false, false) + || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_SRV, services[i]->service, NULL, true, false) + || !_mdns_alloc_answer(&p->answers, MDNS_TYPE_TXT, services[i]->service, NULL, true, false)) { + break; + } + } + if (include_ip) { + _mdns_dealloc_answer(&p->additional, MDNS_TYPE_A, NULL); + _mdns_dealloc_answer(&p->additional, MDNS_TYPE_AAAA, NULL); + _mdns_append_host_list_in_services(&p->answers, services, len, true, false); + } + _pcb->state = PCB_ANNOUNCE_1; + } + } else if (_pcb->state == PCB_RUNNING) { + + if (_str_null_or_empty(_mdns_server->hostname)) { + return; + } + + _pcb->state = PCB_ANNOUNCE_1; + mdns_tx_packet_t *p = _mdns_create_announce_packet(tcpip_if, ip_protocol, services, len, include_ip); + if (p) { + _mdns_schedule_tx_packet(p, 0); + } + } + } +} + +/** + * @brief Send probe on all active PCBs + */ +static void _mdns_probe_all_pcbs(mdns_srv_item_t **services, size_t len, bool probe_ip, bool clear_old_probe) +{ + uint8_t i, j; + for (i = 0; i < MDNS_MAX_INTERFACES; i++) { + for (j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) { + if (mdns_is_netif_ready(i, j)) { + mdns_pcb_t *_pcb = &_mdns_server->interfaces[i].pcbs[j]; + if (clear_old_probe) { + free(_pcb->probe_services); + _pcb->probe_services = NULL; + _pcb->probe_services_len = 0; + _pcb->probe_running = false; + } + _mdns_init_pcb_probe((mdns_if_t)i, (mdns_ip_protocol_t)j, services, len, probe_ip); + } + } + } +} + +/** + * @brief Send announcement on all active PCBs + */ +static void _mdns_announce_all_pcbs(mdns_srv_item_t **services, size_t len, bool include_ip) +{ + uint8_t i, j; + for (i = 0; i < MDNS_MAX_INTERFACES; i++) { + for (j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) { + _mdns_announce_pcb((mdns_if_t)i, (mdns_ip_protocol_t)j, services, len, include_ip); + } + } +} + +/** + * @brief Restart the responder on all active PCBs + */ +static void _mdns_send_final_bye(bool include_ip) +{ + //collect all services and start probe + size_t srv_count = 0; + mdns_srv_item_t *a = _mdns_server->services; + while (a) { + srv_count++; + a = a->next; + } + if (!srv_count) { + return; + } + mdns_srv_item_t *services[srv_count]; + size_t i = 0; + a = _mdns_server->services; + while (a) { + services[i++] = a; + a = a->next; + } + _mdns_send_bye(services, srv_count, include_ip); +} + +/** + * @brief Stop the responder on all services without instance + */ +static void _mdns_send_bye_all_pcbs_no_instance(bool include_ip) +{ + size_t srv_count = 0; + mdns_srv_item_t *a = _mdns_server->services; + while (a) { + if (!a->service->instance) { + srv_count++; + } + a = a->next; + } + if (!srv_count) { + return; + } + mdns_srv_item_t *services[srv_count]; + size_t i = 0; + a = _mdns_server->services; + while (a) { + if (!a->service->instance) { + services[i++] = a; + } + a = a->next; + } + _mdns_send_bye(services, srv_count, include_ip); +} + +/** + * @brief Restart the responder on all services without instance + */ +static void _mdns_restart_all_pcbs_no_instance(void) +{ + size_t srv_count = 0; + mdns_srv_item_t *a = _mdns_server->services; + while (a) { + if (!a->service->instance) { + srv_count++; + } + a = a->next; + } + if (!srv_count) { + return; + } + mdns_srv_item_t *services[srv_count]; + size_t i = 0; + a = _mdns_server->services; + while (a) { + if (!a->service->instance) { + services[i++] = a; + } + a = a->next; + } + _mdns_probe_all_pcbs(services, srv_count, false, true); +} + +/** + * @brief Restart the responder on all active PCBs + */ +static void _mdns_restart_all_pcbs(void) +{ + _mdns_clear_tx_queue_head(); + size_t srv_count = 0; + mdns_srv_item_t *a = _mdns_server->services; + while (a) { + srv_count++; + a = a->next; + } + mdns_srv_item_t *services[srv_count]; + size_t l = 0; + a = _mdns_server->services; + while (a) { + services[l++] = a; + a = a->next; + } + + _mdns_probe_all_pcbs(services, srv_count, true, true); +} + + + +/** + * @brief creates/allocates new text item list + * @param num_items service number of txt items or 0 + * @param txt service txt items array or NULL + * + * @return pointer to the linked txt item list or NULL + */ +static mdns_txt_linked_item_t *_mdns_allocate_txt(size_t num_items, mdns_txt_item_t txt[]) +{ + mdns_txt_linked_item_t *new_txt = NULL; + size_t i = 0; + if (num_items) { + for (i = 0; i < num_items; i++) { + mdns_txt_linked_item_t *new_item = (mdns_txt_linked_item_t *)malloc(sizeof(mdns_txt_linked_item_t)); + if (!new_item) { + HOOK_MALLOC_FAILED; + break; + } + new_item->key = strdup(txt[i].key); + if (!new_item->key) { + free(new_item); + break; + } + new_item->value = strdup(txt[i].value); + if (!new_item->value) { + free((char *)new_item->key); + free(new_item); + break; + } + new_item->value_len = strlen(new_item->value); + new_item->next = new_txt; + new_txt = new_item; + } + } + return new_txt; +} + +/** + * @brief Deallocate the txt linked list + * @param txt pointer to the txt pointer to free, noop if txt==NULL + */ +static void _mdns_free_linked_txt(mdns_txt_linked_item_t *txt) +{ + mdns_txt_linked_item_t *t; + while (txt) { + t = txt; + txt = txt->next; + free((char *)t->value); + free((char *)t->key); + free(t); + } +} + +/** + * @brief creates/allocates new service + * @param service service type + * @param proto service proto + * @param hostname service hostname + * @param port service port + * @param instance service instance + * @param num_items service number of txt items or 0 + * @param txt service txt items array or NULL + * + * @return pointer to the service or NULL on error + */ +static mdns_service_t *_mdns_create_service(const char *service, const char *proto, const char *hostname, + uint16_t port, const char *instance, size_t num_items, + mdns_txt_item_t txt[]) +{ + mdns_service_t *s = (mdns_service_t *)calloc(1, sizeof(mdns_service_t)); + if (!s) { + HOOK_MALLOC_FAILED; + return NULL; + } + + mdns_txt_linked_item_t *new_txt = _mdns_allocate_txt(num_items, txt); + if (num_items && new_txt == NULL) { + goto fail; + } + + s->priority = 0; + s->weight = 0; + s->instance = instance ? strndup(instance, MDNS_NAME_BUF_LEN - 1) : NULL; + s->txt = new_txt; + s->port = port; + s->subtype = NULL; + + if (hostname) { + s->hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1); + if (!s->hostname) { + goto fail; + } + } else { + s->hostname = NULL; + } + + s->service = strndup(service, MDNS_NAME_BUF_LEN - 1); + if (!s->service) { + goto fail; + } + + s->proto = strndup(proto, MDNS_NAME_BUF_LEN - 1); + if (!s->proto) { + goto fail; + } + return s; + +fail: + _mdns_free_linked_txt(s->txt); + free((char *)s->instance); + free((char *)s->service); + free((char *)s->proto); + free((char *)s->hostname); + free(s); + + return NULL; +} + +/** + * @brief Remove and free service answer from answer list (destination) + */ +static void _mdns_dealloc_scheduled_service_answers(mdns_out_answer_t **destination, mdns_service_t *service) +{ + mdns_out_answer_t *d = *destination; + if (!d) { + return; + } + while (d && d->service == service) { + *destination = d->next; + free(d); + d = *destination; + } + while (d && d->next) { + mdns_out_answer_t *a = d->next; + if (a->service == service) { + d->next = a->next; + free(a); + } else { + d = d->next; + } + } +} + +/** + * @brief Find, remove and free answers and scheduled packets for service + */ +static void _mdns_remove_scheduled_service_packets(mdns_service_t *service) +{ + if (!service) { + return; + } + mdns_tx_packet_t *p = NULL; + mdns_tx_packet_t *q = _mdns_server->tx_queue_head; + while (q) { + bool had_answers = (q->answers != NULL); + + _mdns_dealloc_scheduled_service_answers(&(q->answers), service); + _mdns_dealloc_scheduled_service_answers(&(q->additional), service); + _mdns_dealloc_scheduled_service_answers(&(q->servers), service); + + + mdns_pcb_t *_pcb = &_mdns_server->interfaces[q->tcpip_if].pcbs[q->ip_protocol]; + if (mdns_is_netif_ready(q->tcpip_if, q->ip_protocol)) { + if (PCB_STATE_IS_PROBING(_pcb)) { + uint8_t i; + //check if we are probing this service + for (i = 0; i < _pcb->probe_services_len; i++) { + mdns_srv_item_t *s = _pcb->probe_services[i]; + if (s->service == service) { + break; + } + } + if (i < _pcb->probe_services_len) { + if (_pcb->probe_services_len > 1) { + uint8_t n; + for (n = (i + 1); n < _pcb->probe_services_len; n++) { + _pcb->probe_services[n - 1] = _pcb->probe_services[n]; + } + _pcb->probe_services_len--; + } else { + _pcb->probe_services_len = 0; + free(_pcb->probe_services); + _pcb->probe_services = NULL; + if (!_pcb->probe_ip) { + _pcb->probe_running = false; + _pcb->state = PCB_RUNNING; + } + } + + if (q->questions) { + mdns_out_question_t *qsn = NULL; + mdns_out_question_t *qs = q->questions; + if (qs->type == MDNS_TYPE_ANY + && qs->service && strcmp(qs->service, service->service) == 0 + && qs->proto && strcmp(qs->proto, service->proto) == 0) { + q->questions = q->questions->next; + free(qs); + } else while (qs->next) { + qsn = qs->next; + if (qsn->type == MDNS_TYPE_ANY + && qsn->service && strcmp(qsn->service, service->service) == 0 + && qsn->proto && strcmp(qsn->proto, service->proto) == 0) { + qs->next = qsn->next; + free(qsn); + break; + } + qs = qs->next; + } + } + } + } else if (PCB_STATE_IS_ANNOUNCING(_pcb)) { + //if answers were cleared, set to running + if (had_answers && q->answers == NULL) { + _pcb->state = PCB_RUNNING; + } + } + } + + p = q; + q = q->next; + if (!p->questions && !p->answers && !p->additional && !p->servers) { + queueDetach(mdns_tx_packet_t, _mdns_server->tx_queue_head, p); + _mdns_free_tx_packet(p); + } + } +} + +static void _mdns_free_service_subtype(mdns_service_t *service) +{ + while (service->subtype) { + mdns_subtype_t *next = service->subtype->next; + free((char *)service->subtype->subtype); + free(service->subtype); + service->subtype = next; + } +} + +/** + * @brief free service memory + * + * @param service the service + */ +static void _mdns_free_service(mdns_service_t *service) +{ + if (!service) { + return; + } + free((char *)service->instance); + free((char *)service->service); + free((char *)service->proto); + free((char *)service->hostname); + while (service->txt) { + mdns_txt_linked_item_t *s = service->txt; + service->txt = service->txt->next; + free((char *)s->key); + free((char *)s->value); + free(s); + } + _mdns_free_service_subtype(service); + free(service); +} + + +/* + * Received Packet Handling + * */ + +/** + * @brief Detect SRV collision + */ +static int _mdns_check_srv_collision(mdns_service_t *service, uint16_t priority, uint16_t weight, uint16_t port, const char *host, const char *domain) +{ + if (_str_null_or_empty(_mdns_server->hostname)) { + return 0; + } + + size_t our_host_len = strlen(_mdns_server->hostname); + size_t our_len = 14 + our_host_len; + + size_t their_host_len = strlen(host); + size_t their_domain_len = strlen(domain); + size_t their_len = 9 + their_host_len + their_domain_len; + + if (their_len > our_len) { + return 1;//they win + } else if (their_len < our_len) { + return -1;//we win + } + + uint16_t our_index = 0; + uint8_t our_data[our_len]; + _mdns_append_u16(our_data, &our_index, service->priority); + _mdns_append_u16(our_data, &our_index, service->weight); + _mdns_append_u16(our_data, &our_index, service->port); + our_data[our_index++] = our_host_len; + memcpy(our_data + our_index, _mdns_server->hostname, our_host_len); + our_index += our_host_len; + our_data[our_index++] = 5; + memcpy(our_data + our_index, MDNS_DEFAULT_DOMAIN, 5); + our_index += 5; + our_data[our_index++] = 0; + + uint16_t their_index = 0; + uint8_t their_data[their_len]; + _mdns_append_u16(their_data, &their_index, priority); + _mdns_append_u16(their_data, &their_index, weight); + _mdns_append_u16(their_data, &their_index, port); + their_data[their_index++] = their_host_len; + memcpy(their_data + their_index, host, their_host_len); + their_index += their_host_len; + their_data[their_index++] = their_domain_len; + memcpy(their_data + their_index, domain, their_domain_len); + their_index += their_domain_len; + their_data[their_index++] = 0; + + int ret = memcmp(our_data, their_data, our_len); + if (ret > 0) { + return -1;//we win + } else if (ret < 0) { + return 1;//they win + } + return 0;//same +} + +/** + * @brief Detect TXT collision + */ +static int _mdns_check_txt_collision(mdns_service_t *service, const uint8_t *data, size_t len) +{ + size_t data_len = 0; + if (len == 1 && service->txt) { + return -1;//we win + } else if (len > 1 && !service->txt) { + return 1;//they win + } else if (len == 1 && !service->txt) { + return 0;//same + } + + mdns_txt_linked_item_t *txt = service->txt; + while (txt) { + data_len += 1 /* record-len */ + strlen(txt->key) + txt->value_len + (txt->value ? 1 : 0 /* "=" */); + txt = txt->next; + } + + if (len > data_len) { + return 1;//they win + } else if (len < data_len) { + return -1;//we win + } + + uint8_t ours[len]; + uint16_t index = 0; + + txt = service->txt; + while (txt) { + append_one_txt_record_entry(ours, &index, txt); + txt = txt->next; + } + + int ret = memcmp(ours, data, len); + if (ret > 0) { + return -1;//we win + } else if (ret < 0) { + return 1;//they win + } + return 0;//same +} + +static esp_err_t mdns_pcb_deinit_local(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_proto) +{ + esp_err_t err = _mdns_pcb_deinit(tcpip_if, ip_proto); + mdns_pcb_t *_pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_proto]; + if (_pcb == NULL || err != ESP_OK) { + return err; + } + free(_pcb->probe_services); + _pcb->state = PCB_OFF; + _pcb->probe_ip = false; + _pcb->probe_services = NULL; + _pcb->probe_services_len = 0; + _pcb->probe_running = false; + _pcb->failed_probes = 0; + return ESP_OK; +} +/** + * @brief Set interface as duplicate if another is found on the same subnet + */ +static void _mdns_dup_interface(mdns_if_t tcpip_if) +{ + uint8_t i; + mdns_if_t other_if = _mdns_get_other_if (tcpip_if); + if (other_if == MDNS_MAX_INTERFACES) { + return; // no other interface found + } + for (i = 0; i < MDNS_IP_PROTOCOL_MAX; i++) { + if (mdns_is_netif_ready(other_if, i)) { + //stop this interface and mark as dup + if (mdns_is_netif_ready(tcpip_if, i)) { + _mdns_clear_pcb_tx_queue_head(tcpip_if, i); + mdns_pcb_deinit_local(tcpip_if, i); + } + _mdns_server->interfaces[tcpip_if].pcbs[i].state = PCB_DUP; + _mdns_announce_pcb(other_if, i, NULL, 0, true); + } + } +} + +#ifdef CONFIG_LWIP_IPV4 +/** + * @brief Detect IPv4 address collision + */ +static int _mdns_check_a_collision(esp_ip4_addr_t *ip, mdns_if_t tcpip_if) +{ + esp_netif_ip_info_t if_ip_info; + esp_netif_ip_info_t other_ip_info; + if (!ip->addr) { + return 1;//denial! they win + } + if (esp_netif_get_ip_info(_mdns_get_esp_netif(tcpip_if), &if_ip_info)) { + return 1;//they win + } + int ret = memcmp((uint8_t *)&if_ip_info.ip.addr, (uint8_t *)&ip->addr, sizeof(esp_ip4_addr_t)); + if (ret > 0) { + return -1;//we win + } else if (ret < 0) { + //is it the other interface? + mdns_if_t other_if = _mdns_get_other_if (tcpip_if); + if (other_if == MDNS_MAX_INTERFACES) { + return 1;//AP interface! They win + } + if (esp_netif_get_ip_info(_mdns_get_esp_netif(other_if), &other_ip_info)) { + return 1;//IPv4 not active! They win + } + if (ip->addr != other_ip_info.ip.addr) { + return 1;//IPv4 not ours! They win + } + _mdns_dup_interface(tcpip_if); + return 2;//they win + } + return 0;//same +} +#endif /* CONFIG_LWIP_IPV4 */ + +#ifdef CONFIG_LWIP_IPV6 +/** + * @brief Detect IPv6 address collision + */ +static int _mdns_check_aaaa_collision(esp_ip6_addr_t *ip, mdns_if_t tcpip_if) +{ + struct esp_ip6_addr if_ip6; + struct esp_ip6_addr other_ip6; + if (_ipv6_address_is_zero(*ip)) { + return 1;//denial! they win + } + if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(tcpip_if), &if_ip6)) { + return 1;//they win + } + int ret = memcmp((uint8_t *)&if_ip6.addr, (uint8_t *)ip->addr, _MDNS_SIZEOF_IP6_ADDR); + if (ret > 0) { + return -1;//we win + } else if (ret < 0) { + //is it the other interface? + mdns_if_t other_if = _mdns_get_other_if (tcpip_if); + if (other_if == MDNS_MAX_INTERFACES) { + return 1;//AP interface! They win + } + if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(other_if), &other_ip6)) { + return 1;//IPv6 not active! They win + } + if (memcmp((uint8_t *)&other_ip6.addr, (uint8_t *)ip->addr, _MDNS_SIZEOF_IP6_ADDR)) { + return 1;//IPv6 not ours! They win + } + _mdns_dup_interface(tcpip_if); + return 2;//they win + } + return 0;//same +} +#endif /* CONFIG_LWIP_IPV6 */ + +static bool _hostname_is_ours(const char *hostname) +{ + if (!_str_null_or_empty(_mdns_server->hostname) && + strcasecmp(hostname, _mdns_server->hostname) == 0) { + return true; + } + mdns_host_item_t *host = _mdns_host_list; + while (host != NULL) { + if (strcasecmp(hostname, host->hostname) == 0) { + return true; + } + host = host->next; + } + return false; +} + +/** + * @brief Adds a delegated hostname to the linked list + * @param hostname Host name pointer + * @param address_list Address list + * @return true on success + * false if the host wasn't attached (this is our hostname, or alloc failure) so we have to free the structs + */ +static bool _mdns_delegate_hostname_add(const char *hostname, mdns_ip_addr_t *address_list) +{ + if (_hostname_is_ours(hostname)) { + return false; + } + + mdns_host_item_t *host = (mdns_host_item_t *)malloc(sizeof(mdns_host_item_t)); + + if (host == NULL) { + return false; + } + host->address_list = address_list; + host->hostname = hostname; + host->next = _mdns_host_list; + _mdns_host_list = host; + return true; +} + +static void free_address_list(mdns_ip_addr_t *address_list) +{ + while (address_list != NULL) { + mdns_ip_addr_t *next = address_list->next; + free(address_list); + address_list = next; + } +} + + +static bool _mdns_delegate_hostname_set_address(const char *hostname, mdns_ip_addr_t *address_list) +{ + if (!_str_null_or_empty(_mdns_server->hostname) && + strcasecmp(hostname, _mdns_server->hostname) == 0) { + return false; + } + mdns_host_item_t *host = _mdns_host_list; + while (host != NULL) { + if (strcasecmp(hostname, host->hostname) == 0) { + // free previous address list + free_address_list(host->address_list); + // set current address list to the host + host->address_list = address_list; + return true; + } + host = host->next; + } + return false; +} + +static mdns_ip_addr_t *copy_address_list(const mdns_ip_addr_t *address_list) +{ + mdns_ip_addr_t *head = NULL; + mdns_ip_addr_t *tail = NULL; + while (address_list != NULL) { + mdns_ip_addr_t *addr = (mdns_ip_addr_t *)malloc(sizeof(mdns_ip_addr_t)); + if (addr == NULL) { + free_address_list(head); + return NULL; + } + addr->addr = address_list->addr; + addr->next = NULL; + if (head == NULL) { + head = addr; + tail = addr; + } else { + tail->next = addr; + tail = tail->next; + } + address_list = address_list->next; + } + return head; +} + +static void free_delegated_hostnames(void) +{ + mdns_host_item_t *host = _mdns_host_list; + while (host != NULL) { + free_address_list(host->address_list); + free((char *)host->hostname); + mdns_host_item_t *item = host; + host = host->next; + free(item); + } + _mdns_host_list = NULL; +} + +static bool _mdns_delegate_hostname_remove(const char *hostname) +{ + mdns_srv_item_t *srv = _mdns_server->services; + mdns_srv_item_t *prev_srv = NULL; + while (srv) { + if (strcasecmp(srv->service->hostname, hostname) == 0) { + mdns_srv_item_t *to_free = srv; + _mdns_send_bye(&srv, 1, false); + _mdns_remove_scheduled_service_packets(srv->service); + if (prev_srv == NULL) { + _mdns_server->services = srv->next; + srv = srv->next; + } else { + prev_srv->next = srv->next; + srv = srv->next; + } + _mdns_free_service(to_free->service); + free(to_free); + } else { + prev_srv = srv; + srv = srv->next; + } + } + mdns_host_item_t *host = _mdns_host_list; + mdns_host_item_t *prev_host = NULL; + while (host != NULL) { + if (strcasecmp(hostname, host->hostname) == 0) { + if (prev_host == NULL) { + _mdns_host_list = host->next; + } else { + prev_host->next = host->next; + } + free_address_list(host->address_list); + free((char *)host->hostname); + free(host); + break; + } else { + prev_host = host; + host = host->next; + } + } + return true; +} + +/** + * @brief Check if parsed name is discovery + */ +static bool _mdns_name_is_discovery(mdns_name_t *name, uint16_t type) +{ + return ( + (name->host[0] && !strcasecmp(name->host, "_services")) + && (name->service[0] && !strcasecmp(name->service, "_dns-sd")) + && (name->proto[0] && !strcasecmp(name->proto, "_udp")) + && (name->domain[0] && !strcasecmp(name->domain, MDNS_DEFAULT_DOMAIN)) + && type == MDNS_TYPE_PTR + ); +} + +/** + * @brief Check if the parsed name is self-hosted, i.e. we should resolve conflicts + */ +static bool _mdns_name_is_selfhosted(mdns_name_t *name) +{ + if (_str_null_or_empty(_mdns_server->hostname)) { // self-hostname needs to be defined + return false; + } + + // hostname only -- check if selfhosted name + if (_str_null_or_empty(name->service) && _str_null_or_empty(name->proto) && + strcasecmp(name->host, _mdns_server->hostname) == 0 ) { + return true; + } + + // service -- check if selfhosted service + mdns_srv_item_t *srv = _mdns_get_service_item(name->service, name->proto, NULL); + if (srv && strcasecmp(_mdns_server->hostname, srv->service->hostname) == 0) { + return true; + } + return false; +} + +/** + * @brief Check if the parsed name is ours (matches service or host name) + */ +static bool _mdns_name_is_ours(mdns_name_t *name) +{ + //domain have to be "local" + if (_str_null_or_empty(name->domain) || ( strcasecmp(name->domain, MDNS_DEFAULT_DOMAIN) +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES + && strcasecmp(name->domain, "arpa") +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ + ) ) { + return false; + } + + //if service and proto are empty, host must match out hostname + if (_str_null_or_empty(name->service) && _str_null_or_empty(name->proto)) { + if (!_str_null_or_empty(name->host) + && !_str_null_or_empty(_mdns_server->hostname) + && _hostname_is_ours(name->host)) { + return true; + } + return false; + } + + //if service or proto is empty, name is invalid + if (_str_null_or_empty(name->service) || _str_null_or_empty(name->proto)) { + return false; + } + + + //find the service + mdns_srv_item_t *service; + if (name->sub) { + service = _mdns_get_service_item_subtype(name->host, name->service, name->proto); + } else if (_str_null_or_empty(name->host)) { + service = _mdns_get_service_item(name->service, name->proto, NULL); + } else { + service = _mdns_get_service_item_instance(name->host, name->service, name->proto, NULL); + } + if (!service) { + return false; + } + + //if query is PTR query and we have service, we have success + if (name->sub || _str_null_or_empty(name->host)) { + return true; + } + + //OK we have host in the name. find what is the instance of the service + const char *instance = _mdns_get_service_instance_name(service->service); + if (instance == NULL) { + return false; + } + + //compare the instance against the name + if (strcasecmp(name->host, instance) == 0) { + return true; + } + + return false; +} + +/** + * @brief read uint16_t from a packet + * @param packet the packet + * @param index index in the packet where the value starts + * + * @return the value + */ +static inline uint16_t _mdns_read_u16(const uint8_t *packet, uint16_t index) +{ + return (uint16_t)(packet[index]) << 8 | packet[index + 1]; +} + +/** + * @brief read uint32_t from a packet + * @param packet the packet + * @param index index in the packet where the value starts + * + * @return the value + */ +static inline uint32_t _mdns_read_u32(const uint8_t *packet, uint16_t index) +{ + return (uint32_t)(packet[index]) << 24 | (uint32_t)(packet[index + 1]) << 16 | (uint32_t)(packet[index + 2]) << 8 | packet[index + 3]; +} + +/** + * @brief reads and formats MDNS FQDN into mdns_name_t structure + * + * @param packet MDNS packet + * @param start Starting point of FQDN + * @param name mdns_name_t structure to populate + * + * @return the address after the parsed FQDN in the packet or NULL on error + */ +static const uint8_t *_mdns_parse_fqdn(const uint8_t *packet, const uint8_t *start, mdns_name_t *name, size_t packet_len) +{ + name->parts = 0; + name->sub = 0; + name->host[0] = 0; + name->service[0] = 0; + name->proto[0] = 0; + name->domain[0] = 0; + name->invalid = false; + + static char buf[MDNS_NAME_BUF_LEN]; + + const uint8_t *next_data = (uint8_t *)_mdns_read_fqdn(packet, start, name, buf, packet_len); + if (!next_data) { + return 0; + } + if (!name->parts || name->invalid) { + return next_data; + } + if (name->parts == 3) { + memmove((uint8_t *)name + (MDNS_NAME_BUF_LEN), (uint8_t *)name, 3 * (MDNS_NAME_BUF_LEN)); + name->host[0] = 0; + } else if (name->parts == 2) { + memmove((uint8_t *)(name->domain), (uint8_t *)(name->service), (MDNS_NAME_BUF_LEN)); + name->service[0] = 0; + name->proto[0] = 0; + } + if (strcasecmp(name->domain, MDNS_DEFAULT_DOMAIN) == 0 || strcasecmp(name->domain, "arpa") == 0) { + return next_data; + } + name->invalid = true; // mark the current name invalid, but continue with other question + return next_data; +} + +/** + * @brief Called from parser to check if question matches particular service + */ +static bool _mdns_question_matches(mdns_parsed_question_t *question, uint16_t type, mdns_srv_item_t *service) +{ + if (question->type != type) { + return false; + } + if (type == MDNS_TYPE_A || type == MDNS_TYPE_AAAA) { + return true; + } else if (type == MDNS_TYPE_PTR || type == MDNS_TYPE_SDPTR) { + if (question->service && question->proto && question->domain + && !strcasecmp(service->service->service, question->service) + && !strcasecmp(service->service->proto, question->proto) + && !strcasecmp(MDNS_DEFAULT_DOMAIN, question->domain)) { + if (!service->service->instance) { + return true; + } else if (service->service->instance && question->host && !strcasecmp(service->service->instance, question->host)) { + return true; + } + } + } else if (service && (type == MDNS_TYPE_SRV || type == MDNS_TYPE_TXT)) { + const char *name = _mdns_get_service_instance_name(service->service); + if (name && question->host && question->service && question->proto && question->domain + && !strcasecmp(name, question->host) + && !strcasecmp(service->service->service, question->service) + && !strcasecmp(service->service->proto, question->proto) + && !strcasecmp(MDNS_DEFAULT_DOMAIN, question->domain)) { + return true; + } + } + + return false; +} + +/** + * @brief Removes saved question from parsed data + */ +static void _mdns_remove_parsed_question(mdns_parsed_packet_t *parsed_packet, uint16_t type, mdns_srv_item_t *service) +{ + mdns_parsed_question_t *q = parsed_packet->questions; + + if (_mdns_question_matches(q, type, service)) { + parsed_packet->questions = q->next; + free(q->host); + free(q->service); + free(q->proto); + free(q->domain); + free(q); + return; + } + + while (q->next) { + mdns_parsed_question_t *p = q->next; + if (_mdns_question_matches(p, type, service)) { + q->next = p->next; + free(p->host); + free(p->service); + free(p->proto); + free(p->domain); + free(p); + return; + } + q = q->next; + } +} + +/** + * @brief Get number of items in TXT parsed data + */ +static int _mdns_txt_items_count_get(const uint8_t *data, size_t len) +{ + if (len == 1) { + return 0; + } + + int num_items = 0; + uint16_t i = 0; + size_t partLen = 0; + + while (i < len) { + partLen = data[i++]; + if (!partLen) { + break; + } + if ((i + partLen) > len) { + return -1;//error + } + i += partLen; + num_items++; + } + return num_items; +} + +/** + * @brief Get the length of TXT item's key name + */ +static int _mdns_txt_item_name_get_len(const uint8_t *data, size_t len) +{ + if (*data == '=') { + return -1; + } + for (size_t i = 0; i < len; i++) { + if (data[i] == '=') { + return i; + } + } + return len; +} + +/** + * @brief Create TXT result array from parsed TXT data + */ +static void _mdns_result_txt_create(const uint8_t *data, size_t len, mdns_txt_item_t **out_txt, uint8_t **out_value_len, + size_t *out_count) +{ + *out_txt = NULL; + *out_count = 0; + uint16_t i = 0, y; + size_t partLen = 0; + int num_items = _mdns_txt_items_count_get(data, len); + if (num_items < 0) { + return;//error + } + + if (!num_items) { + return; + } + + mdns_txt_item_t *txt = (mdns_txt_item_t *)malloc(sizeof(mdns_txt_item_t) * num_items); + if (!txt) { + HOOK_MALLOC_FAILED; + return; + } + uint8_t *txt_value_len = (uint8_t *)malloc(num_items); + if (!txt_value_len) { + free(txt); + HOOK_MALLOC_FAILED; + return; + } + memset(txt, 0, sizeof(mdns_txt_item_t) * num_items); + memset(txt_value_len, 0, num_items); + size_t txt_num = 0; + + while (i < len) { + partLen = data[i++]; + if (!partLen) { + break; + } + + if ((i + partLen) > len) { + goto handle_error;//error + } + + int name_len = _mdns_txt_item_name_get_len(data + i, partLen); + if (name_len < 0) {//invalid item (no name) + i += partLen; + continue; + } + char *key = (char *)malloc(name_len + 1); + if (!key) { + HOOK_MALLOC_FAILED; + goto handle_error;//error + } + + mdns_txt_item_t *t = &txt[txt_num]; + uint8_t *value_len = &txt_value_len[txt_num]; + txt_num++; + + memcpy(key, data + i, name_len); + key[name_len] = 0; + i += name_len + 1; + t->key = key; + + int new_value_len = partLen - name_len - 1; + if (new_value_len > 0) { + char *value = (char *)malloc(new_value_len + 1); + if (!value) { + HOOK_MALLOC_FAILED; + goto handle_error;//error + } + memcpy(value, data + i, new_value_len); + value[new_value_len] = 0; + *value_len = new_value_len; + i += new_value_len; + t->value = value; + } + } + + *out_txt = txt; + *out_count = txt_num; + *out_value_len = txt_value_len; + return; + +handle_error : + for (y = 0; y < txt_num; y++) { + mdns_txt_item_t *t = &txt[y]; + free((char *)t->key); + free((char *)t->value); + } + free(txt_value_len); + free(txt); +} + +/** + * @brief Duplicate string or return error + */ +static esp_err_t _mdns_strdup_check(char **out, char *in) +{ + if (in && in[0]) { + *out = strdup(in); + if (!*out) { + return ESP_FAIL; + } + return ESP_OK; + } + *out = NULL; + return ESP_OK; +} + +/** + * @brief main packet parser + * + * @param packet the packet + */ +void mdns_parse_packet(mdns_rx_packet_t *packet) +{ + static mdns_name_t n; + mdns_header_t header; + const uint8_t *data = _mdns_get_packet_data(packet); + size_t len = _mdns_get_packet_len(packet); + const uint8_t *content = data + MDNS_HEAD_LEN; + bool do_not_reply = false; + mdns_search_once_t *search_result = NULL; + mdns_browse_t *browse_result = NULL; + char *browse_result_instance = NULL; + char *browse_result_service = NULL; + char *browse_result_proto = NULL; + mdns_browse_sync_t *out_sync_browse = NULL; + +#ifdef MDNS_ENABLE_DEBUG + _mdns_dbg_printf("\nRX[%lu][%lu]: ", (unsigned long)packet->tcpip_if, (unsigned long)packet->ip_protocol); +#ifdef CONFIG_LWIP_IPV4 + if (packet->src.type == ESP_IPADDR_TYPE_V4) { + _mdns_dbg_printf("From: " IPSTR ":%u, To: " IPSTR ", ", IP2STR(&packet->src.u_addr.ip4), packet->src_port, IP2STR(&packet->dest.u_addr.ip4)); + } +#endif +#ifdef CONFIG_LWIP_IPV6 + if (packet->src.type == ESP_IPADDR_TYPE_V6) { + _mdns_dbg_printf("From: " IPV6STR ":%u, To: " IPV6STR ", ", IPV62STR(packet->src.u_addr.ip6), packet->src_port, IPV62STR(packet->dest.u_addr.ip6)); + } +#endif + mdns_debug_packet(data, len); +#endif + +#ifndef CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES + // Check if the packet wasn't sent by us +#ifdef CONFIG_LWIP_IPV4 + if (packet->ip_protocol == MDNS_IP_PROTOCOL_V4) { + esp_netif_ip_info_t if_ip_info; + if (esp_netif_get_ip_info(_mdns_get_esp_netif(packet->tcpip_if), &if_ip_info) == ESP_OK && + memcmp(&if_ip_info.ip.addr, &packet->src.u_addr.ip4.addr, sizeof(esp_ip4_addr_t)) == 0) { + return; + } + } +#endif /* CONFIG_LWIP_IPV4 */ +#ifdef CONFIG_LWIP_IPV6 + if (packet->ip_protocol == MDNS_IP_PROTOCOL_V6) { + struct esp_ip6_addr if_ip6; + if (esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(packet->tcpip_if), &if_ip6) == ESP_OK && + memcmp(&if_ip6, &packet->src.u_addr.ip6, sizeof(esp_ip6_addr_t)) == 0) { + return; + } + } +#endif /* CONFIG_LWIP_IPV6 */ +#endif // CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES + + // Check for the minimum size of mdns packet + if (len <= MDNS_HEAD_ADDITIONAL_OFFSET) { + return; + } + + mdns_parsed_packet_t *parsed_packet = (mdns_parsed_packet_t *)malloc(sizeof(mdns_parsed_packet_t)); + if (!parsed_packet) { + HOOK_MALLOC_FAILED; + return; + } + memset(parsed_packet, 0, sizeof(mdns_parsed_packet_t)); + + mdns_name_t *name = &n; + memset(name, 0, sizeof(mdns_name_t)); + + header.id = _mdns_read_u16(data, MDNS_HEAD_ID_OFFSET); + header.flags = _mdns_read_u16(data, MDNS_HEAD_FLAGS_OFFSET); + header.questions = _mdns_read_u16(data, MDNS_HEAD_QUESTIONS_OFFSET); + header.answers = _mdns_read_u16(data, MDNS_HEAD_ANSWERS_OFFSET); + header.servers = _mdns_read_u16(data, MDNS_HEAD_SERVERS_OFFSET); + header.additional = _mdns_read_u16(data, MDNS_HEAD_ADDITIONAL_OFFSET); + + if (header.flags == MDNS_FLAGS_QR_AUTHORITATIVE && packet->src_port != MDNS_SERVICE_PORT) { + free(parsed_packet); + return; + } + + //if we have not set the hostname, we can not answer questions + if (header.questions && !header.answers && _str_null_or_empty(_mdns_server->hostname)) { + free(parsed_packet); + return; + } + + parsed_packet->tcpip_if = packet->tcpip_if; + parsed_packet->ip_protocol = packet->ip_protocol; + parsed_packet->multicast = packet->multicast; + parsed_packet->authoritative = (header.flags == MDNS_FLAGS_QR_AUTHORITATIVE); + parsed_packet->distributed = header.flags == MDNS_FLAGS_DISTRIBUTED; + parsed_packet->id = header.id; + esp_netif_ip_addr_copy(&parsed_packet->src, &packet->src); + parsed_packet->src_port = packet->src_port; + parsed_packet->records = NULL; + + if (header.questions) { + uint8_t qs = header.questions; + + while (qs--) { + content = _mdns_parse_fqdn(data, content, name, len); + if (!content) { + header.answers = 0; + header.additional = 0; + header.servers = 0; + goto clear_rx_packet;//error + } + + if (content + MDNS_CLASS_OFFSET + 1 >= data + len) { + goto clear_rx_packet; // malformed packet, won't read behind it + } + uint16_t type = _mdns_read_u16(content, MDNS_TYPE_OFFSET); + uint16_t mdns_class = _mdns_read_u16(content, MDNS_CLASS_OFFSET); + bool unicast = !!(mdns_class & 0x8000); + mdns_class &= 0x7FFF; + content = content + 4; + + if (mdns_class != 0x0001 || name->invalid) {//bad class or invalid name for this question entry + continue; + } + + if (_mdns_name_is_discovery(name, type)) { + //service discovery + parsed_packet->discovery = true; + mdns_srv_item_t *a = _mdns_server->services; + while (a) { + mdns_parsed_question_t *question = (mdns_parsed_question_t *)calloc(1, sizeof(mdns_parsed_question_t)); + if (!question) { + HOOK_MALLOC_FAILED; + goto clear_rx_packet; + } + question->next = parsed_packet->questions; + parsed_packet->questions = question; + + question->unicast = unicast; + question->type = MDNS_TYPE_SDPTR; + question->host = NULL; + question->service = strdup(a->service->service); + question->proto = strdup(a->service->proto); + question->domain = strdup(MDNS_DEFAULT_DOMAIN); + if (!question->service || !question->proto || !question->domain) { + goto clear_rx_packet; + } + a = a->next; + } + continue; + } + if (!_mdns_name_is_ours(name)) { + continue; + } + + if (type == MDNS_TYPE_ANY && !_str_null_or_empty(name->host)) { + parsed_packet->probe = true; + } + + mdns_parsed_question_t *question = (mdns_parsed_question_t *)calloc(1, sizeof(mdns_parsed_question_t)); + if (!question) { + HOOK_MALLOC_FAILED; + goto clear_rx_packet; + } + question->next = parsed_packet->questions; + parsed_packet->questions = question; + + question->unicast = unicast; + question->type = type; + question->sub = name->sub; + if (_mdns_strdup_check(&(question->host), name->host) + || _mdns_strdup_check(&(question->service), name->service) + || _mdns_strdup_check(&(question->proto), name->proto) + || _mdns_strdup_check(&(question->domain), name->domain)) { + goto clear_rx_packet; + } + } + } + + if (header.questions && !parsed_packet->questions && !parsed_packet->discovery && !header.answers) { + goto clear_rx_packet; + } else if (header.answers || header.servers || header.additional) { + uint16_t recordIndex = 0; + + while (content < (data + len)) { + + content = _mdns_parse_fqdn(data, content, name, len); + if (!content) { + goto clear_rx_packet;//error + } + + if (content + MDNS_LEN_OFFSET + 1 >= data + len) { + goto clear_rx_packet; // malformed packet, won't read behind it + } + uint16_t type = _mdns_read_u16(content, MDNS_TYPE_OFFSET); + uint16_t mdns_class = _mdns_read_u16(content, MDNS_CLASS_OFFSET); + uint32_t ttl = _mdns_read_u32(content, MDNS_TTL_OFFSET); + uint16_t data_len = _mdns_read_u16(content, MDNS_LEN_OFFSET); + const uint8_t *data_ptr = content + MDNS_DATA_OFFSET; + mdns_class &= 0x7FFF; + + content = data_ptr + data_len; + if (content > (data + len)) { + goto clear_rx_packet; + } + + bool discovery = false; + bool ours = false; + mdns_srv_item_t *service = NULL; + mdns_parsed_record_type_t record_type = MDNS_ANSWER; + + if (recordIndex >= (header.answers + header.servers)) { + record_type = MDNS_EXTRA; + } else if (recordIndex >= (header.answers)) { + record_type = MDNS_NS; + } + recordIndex++; + + if (type == MDNS_TYPE_NSEC || type == MDNS_TYPE_OPT) { + //skip NSEC and OPT + continue; + } + + if (parsed_packet->discovery && _mdns_name_is_discovery(name, type)) { + discovery = true; + } else if (!name->sub && _mdns_name_is_ours(name)) { + ours = true; + if (name->service[0] && name->proto[0]) { + service = _mdns_get_service_item(name->service, name->proto, NULL); + } + } else { + if ((header.flags & MDNS_FLAGS_QUERY_REPSONSE) == 0 || record_type == MDNS_NS) { + //skip this record + continue; + } + search_result = _mdns_search_find_from(_mdns_server->search_once, name, type, packet->tcpip_if, packet->ip_protocol); + browse_result = _mdns_browse_find_from(_mdns_server->browse, name, type, packet->tcpip_if, packet->ip_protocol); + if (browse_result) { + if (!out_sync_browse) { + // will be freed in function `_mdns_browse_sync` + out_sync_browse = (mdns_browse_sync_t *)malloc(sizeof(mdns_browse_sync_t)); + if (!out_sync_browse) { + HOOK_MALLOC_FAILED; + goto clear_rx_packet; + } + out_sync_browse->browse = browse_result; + out_sync_browse->sync_result = NULL; + } + if (!browse_result_service) { + browse_result_service = (char *)malloc(MDNS_NAME_BUF_LEN); + if (!browse_result_service) { + HOOK_MALLOC_FAILED; + goto clear_rx_packet; + } + } + memcpy(browse_result_service, browse_result->service, MDNS_NAME_BUF_LEN); + if (!browse_result_proto) { + browse_result_proto = (char *)malloc(MDNS_NAME_BUF_LEN); + if (!browse_result_proto) { + HOOK_MALLOC_FAILED; + goto clear_rx_packet; + } + } + memcpy(browse_result_proto, browse_result->proto, MDNS_NAME_BUF_LEN); + if (type == MDNS_TYPE_SRV || type == MDNS_TYPE_TXT) { + if (!browse_result_instance) { + browse_result_instance = (char *)malloc(MDNS_NAME_BUF_LEN); + if (!browse_result_instance) { + HOOK_MALLOC_FAILED; + goto clear_rx_packet; + } + } + memcpy(browse_result_instance, name->host, MDNS_NAME_BUF_LEN); + } + } + } + + if (type == MDNS_TYPE_PTR) { + if (!_mdns_parse_fqdn(data, data_ptr, name, len)) { + continue;//error + } + if (search_result) { + _mdns_search_result_add_ptr(search_result, name->host, name->service, name->proto, + packet->tcpip_if, packet->ip_protocol, ttl); + } else if ((discovery || ours) && !name->sub && _mdns_name_is_ours(name)) { + if (name->host[0]) { + service = _mdns_get_service_item_instance(name->host, name->service, name->proto, NULL); + } else { + service = _mdns_get_service_item(name->service, name->proto, NULL); + } + if (discovery && service) { + _mdns_remove_parsed_question(parsed_packet, MDNS_TYPE_SDPTR, service); + } else if (service && parsed_packet->questions && !parsed_packet->probe) { + _mdns_remove_parsed_question(parsed_packet, type, service); + } else if (service) { + //check if TTL is more than half of the full TTL value (4500) + if (ttl > (MDNS_ANSWER_PTR_TTL / 2)) { + _mdns_remove_scheduled_answer(packet->tcpip_if, packet->ip_protocol, type, service); + } + } + if (service) { + mdns_parsed_record_t *record = malloc(sizeof(mdns_parsed_record_t)); + if (!record) { + HOOK_MALLOC_FAILED; + goto clear_rx_packet; + } + record->next = parsed_packet->records; + parsed_packet->records = record; + record->type = MDNS_TYPE_PTR; + record->record_type = MDNS_ANSWER; + record->ttl = ttl; + record->host = NULL; + record->service = NULL; + record->proto = NULL; + if (name->host[0]) { + record->host = malloc(MDNS_NAME_BUF_LEN); + if (!record->host) { + HOOK_MALLOC_FAILED; + goto clear_rx_packet; + } + memcpy(record->host, name->host, MDNS_NAME_BUF_LEN); + } + if (name->service[0]) { + record->service = malloc(MDNS_NAME_BUF_LEN); + if (!record->service) { + HOOK_MALLOC_FAILED; + goto clear_rx_packet; + } + memcpy(record->service, name->service, MDNS_NAME_BUF_LEN); + } + if (name->proto[0]) { + record->proto = malloc(MDNS_NAME_BUF_LEN); + if (!record->proto) { + HOOK_MALLOC_FAILED; + goto clear_rx_packet; + } + memcpy(record->proto, name->proto, MDNS_NAME_BUF_LEN); + } + } + } + } else if (type == MDNS_TYPE_SRV) { + mdns_result_t *result = NULL; + if (search_result && search_result->type == MDNS_TYPE_PTR) { + result = search_result->result; + while (result) { + if (_mdns_get_esp_netif(packet->tcpip_if) == result->esp_netif + && packet->ip_protocol == result->ip_protocol + && result->instance_name && !strcmp(name->host, result->instance_name)) { + break; + } + result = result->next; + } + if (!result) { + result = _mdns_search_result_add_ptr(search_result, name->host, name->service, name->proto, + packet->tcpip_if, packet->ip_protocol, ttl); + if (!result) { + continue;//error + } + } + } + bool is_selfhosted = _mdns_name_is_selfhosted(name); + if (!_mdns_parse_fqdn(data, data_ptr + MDNS_SRV_FQDN_OFFSET, name, len)) { + continue;//error + } + if (data_ptr + MDNS_SRV_PORT_OFFSET + 1 >= data + len) { + goto clear_rx_packet; // malformed packet, won't read behind it + } + uint16_t priority = _mdns_read_u16(data_ptr, MDNS_SRV_PRIORITY_OFFSET); + uint16_t weight = _mdns_read_u16(data_ptr, MDNS_SRV_WEIGHT_OFFSET); + uint16_t port = _mdns_read_u16(data_ptr, MDNS_SRV_PORT_OFFSET); + + if (browse_result) { + _mdns_browse_result_add_srv(browse_result, name->host, browse_result_instance, browse_result_service, + browse_result_proto, port, packet->tcpip_if, packet->ip_protocol, ttl, out_sync_browse); + } + if (search_result) { + if (search_result->type == MDNS_TYPE_PTR) { + if (!result->hostname) { // assign host/port for this entry only if not previously set + result->port = port; + result->hostname = strdup(name->host); + } + } else { + _mdns_search_result_add_srv(search_result, name->host, port, packet->tcpip_if, packet->ip_protocol, ttl); + } + } else if (ours) { + if (parsed_packet->questions && !parsed_packet->probe) { + _mdns_remove_parsed_question(parsed_packet, type, service); + continue; + } else if (parsed_packet->distributed) { + _mdns_remove_scheduled_answer(packet->tcpip_if, packet->ip_protocol, type, service); + continue; + } + if (!is_selfhosted) { + continue; + } + //detect collision (-1=won, 0=none, 1=lost) + int col = 0; + if (mdns_class > 1) { + col = 1; + } else if (!mdns_class) { + col = -1; + } else if (service) { // only detect srv collision if service existed + col = _mdns_check_srv_collision(service->service, priority, weight, port, name->host, name->domain); + } + if (service && col && (parsed_packet->probe || parsed_packet->authoritative)) { + if (col > 0 || !port) { + do_not_reply = true; + if (_mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].probe_running) { + _mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].failed_probes++; + if (!_str_null_or_empty(service->service->instance)) { + char *new_instance = _mdns_mangle_name((char *)service->service->instance); + if (new_instance) { + free((char *)service->service->instance); + service->service->instance = new_instance; + } + _mdns_probe_all_pcbs(&service, 1, false, false); + } else if (!_str_null_or_empty(_mdns_server->instance)) { + char *new_instance = _mdns_mangle_name((char *)_mdns_server->instance); + if (new_instance) { + free((char *)_mdns_server->instance); + _mdns_server->instance = new_instance; + } + _mdns_restart_all_pcbs_no_instance(); + } else { + char *new_host = _mdns_mangle_name((char *)_mdns_server->hostname); + if (new_host) { + _mdns_remap_self_service_hostname(_mdns_server->hostname, new_host); + free((char *)_mdns_server->hostname); + _mdns_server->hostname = new_host; + _mdns_self_host.hostname = new_host; + } + _mdns_restart_all_pcbs(); + } + } else if (service) { + _mdns_pcb_send_bye(packet->tcpip_if, packet->ip_protocol, &service, 1, false); + _mdns_init_pcb_probe(packet->tcpip_if, packet->ip_protocol, &service, 1, false); + } + } + } else if (ttl > 60 && !col && !parsed_packet->authoritative && !parsed_packet->probe && !parsed_packet->questions) { + _mdns_remove_scheduled_answer(packet->tcpip_if, packet->ip_protocol, type, service); + } + } + } else if (type == MDNS_TYPE_TXT) { + mdns_txt_item_t *txt = NULL; + uint8_t *txt_value_len = NULL; + size_t txt_count = 0; + + mdns_result_t *result = NULL; + if (browse_result) { + _mdns_result_txt_create(data_ptr, data_len, &txt, &txt_value_len, &txt_count); + _mdns_browse_result_add_txt(browse_result, browse_result_instance, browse_result_service, browse_result_proto, + txt, txt_value_len, txt_count, packet->tcpip_if, packet->ip_protocol, ttl, out_sync_browse); + } + if (search_result) { + if (search_result->type == MDNS_TYPE_PTR) { + result = search_result->result; + while (result) { + if (_mdns_get_esp_netif(packet->tcpip_if) == result->esp_netif + && packet->ip_protocol == result->ip_protocol + && result->instance_name && !strcmp(name->host, result->instance_name)) { + break; + } + result = result->next; + } + if (!result) { + result = _mdns_search_result_add_ptr(search_result, name->host, name->service, name->proto, + packet->tcpip_if, packet->ip_protocol, ttl); + if (!result) { + continue;//error + } + } + if (!result->txt) { + _mdns_result_txt_create(data_ptr, data_len, &txt, &txt_value_len, &txt_count); + if (txt_count) { + result->txt = txt; + result->txt_count = txt_count; + result->txt_value_len = txt_value_len; + } + } + } else { + _mdns_result_txt_create(data_ptr, data_len, &txt, &txt_value_len, &txt_count); + if (txt_count) { + _mdns_search_result_add_txt(search_result, txt, txt_value_len, txt_count, packet->tcpip_if, packet->ip_protocol, ttl); + } + } + } else if (ours) { + if (parsed_packet->questions && !parsed_packet->probe && service) { + _mdns_remove_parsed_question(parsed_packet, type, service); + continue; + } + if (!_mdns_name_is_selfhosted(name)) { + continue; + } + //detect collision (-1=won, 0=none, 1=lost) + int col = 0; + if (mdns_class > 1) { + col = 1; + } else if (!mdns_class) { + col = -1; + } else if (service) { // only detect txt collision if service existed + col = _mdns_check_txt_collision(service->service, data_ptr, data_len); + } + if (col && !_mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].probe_running && service) { + do_not_reply = true; + _mdns_init_pcb_probe(packet->tcpip_if, packet->ip_protocol, &service, 1, true); + } else if (ttl > (MDNS_ANSWER_TXT_TTL / 2) && !col && !parsed_packet->authoritative && !parsed_packet->probe && !parsed_packet->questions && !_mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].probe_running) { + _mdns_remove_scheduled_answer(packet->tcpip_if, packet->ip_protocol, type, service); + } + } + + } +#ifdef CONFIG_LWIP_IPV6 + else if (type == MDNS_TYPE_AAAA) {//ipv6 + esp_ip_addr_t ip6; + ip6.type = ESP_IPADDR_TYPE_V6; + memcpy(ip6.u_addr.ip6.addr, data_ptr, MDNS_ANSWER_AAAA_SIZE); + if (browse_result) { + _mdns_browse_result_add_ip(browse_result, name->host, &ip6, packet->tcpip_if, packet->ip_protocol, ttl, out_sync_browse); + } + if (search_result) { + //check for more applicable searches (PTR & A/AAAA at the same time) + while (search_result) { + _mdns_search_result_add_ip(search_result, name->host, &ip6, packet->tcpip_if, packet->ip_protocol, ttl); + search_result = _mdns_search_find_from(search_result->next, name, type, packet->tcpip_if, packet->ip_protocol); + } + } else if (ours) { + if (parsed_packet->questions && !parsed_packet->probe) { + _mdns_remove_parsed_question(parsed_packet, type, NULL); + continue; + } + if (!_mdns_name_is_selfhosted(name)) { + continue; + } + //detect collision (-1=won, 0=none, 1=lost) + int col = 0; + if (mdns_class > 1) { + col = 1; + } else if (!mdns_class) { + col = -1; + } else { + col = _mdns_check_aaaa_collision(&(ip6.u_addr.ip6), packet->tcpip_if); + } + if (col == 2) { + goto clear_rx_packet; + } else if (col == 1) { + do_not_reply = true; + if (_mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].probe_running) { + if (col && (parsed_packet->probe || parsed_packet->authoritative)) { + _mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].failed_probes++; + char *new_host = _mdns_mangle_name((char *)_mdns_server->hostname); + if (new_host) { + _mdns_remap_self_service_hostname(_mdns_server->hostname, new_host); + free((char *)_mdns_server->hostname); + _mdns_server->hostname = new_host; + _mdns_self_host.hostname = new_host; + } + _mdns_restart_all_pcbs(); + } + } else { + _mdns_init_pcb_probe(packet->tcpip_if, packet->ip_protocol, NULL, 0, true); + } + } else if (ttl > 60 && !col && !parsed_packet->authoritative && !parsed_packet->probe && !parsed_packet->questions && !_mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].probe_running) { + _mdns_remove_scheduled_answer(packet->tcpip_if, packet->ip_protocol, type, NULL); + } + } + + } +#endif /* CONFIG_LWIP_IPV6 */ +#ifdef CONFIG_LWIP_IPV4 + else if (type == MDNS_TYPE_A) { + esp_ip_addr_t ip; + ip.type = ESP_IPADDR_TYPE_V4; + memcpy(&(ip.u_addr.ip4.addr), data_ptr, 4); + if (browse_result) { + _mdns_browse_result_add_ip(browse_result, name->host, &ip, packet->tcpip_if, packet->ip_protocol, ttl, out_sync_browse); + } + if (search_result) { + //check for more applicable searches (PTR & A/AAAA at the same time) + while (search_result) { + _mdns_search_result_add_ip(search_result, name->host, &ip, packet->tcpip_if, packet->ip_protocol, ttl); + search_result = _mdns_search_find_from(search_result->next, name, type, packet->tcpip_if, packet->ip_protocol); + } + } else if (ours) { + if (parsed_packet->questions && !parsed_packet->probe) { + _mdns_remove_parsed_question(parsed_packet, type, NULL); + continue; + } + if (!_mdns_name_is_selfhosted(name)) { + continue; + } + //detect collision (-1=won, 0=none, 1=lost) + int col = 0; + if (mdns_class > 1) { + col = 1; + } else if (!mdns_class) { + col = -1; + } else { + col = _mdns_check_a_collision(&(ip.u_addr.ip4), packet->tcpip_if); + } + if (col == 2) { + goto clear_rx_packet; + } else if (col == 1) { + do_not_reply = true; + if (_mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].probe_running) { + if (col && (parsed_packet->probe || parsed_packet->authoritative)) { + _mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].failed_probes++; + char *new_host = _mdns_mangle_name((char *)_mdns_server->hostname); + if (new_host) { + _mdns_remap_self_service_hostname(_mdns_server->hostname, new_host); + free((char *)_mdns_server->hostname); + _mdns_server->hostname = new_host; + _mdns_self_host.hostname = new_host; + } + _mdns_restart_all_pcbs(); + } + } else { + _mdns_init_pcb_probe(packet->tcpip_if, packet->ip_protocol, NULL, 0, true); + } + } else if (ttl > 60 && !col && !parsed_packet->authoritative && !parsed_packet->probe && !parsed_packet->questions && !_mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].probe_running) { + _mdns_remove_scheduled_answer(packet->tcpip_if, packet->ip_protocol, type, NULL); + } + } + + } +#endif /* CONFIG_LWIP_IPV4 */ + } + //end while + if (parsed_packet->authoritative) { + _mdns_search_finish_done(); + } + } + + if (!do_not_reply && _mdns_server->interfaces[packet->tcpip_if].pcbs[packet->ip_protocol].state > PCB_PROBE_3 && (parsed_packet->questions || parsed_packet->discovery)) { + _mdns_create_answer_from_parsed_packet(parsed_packet); + } + if (out_sync_browse) { +#ifdef MDNS_ENABLE_DEBUG + _mdns_dbg_printf("Browse %s%s total result:", out_sync_browse->browse->service, out_sync_browse->browse->proto); + debug_printf_browse_result_all(out_sync_browse->browse->result); +#endif // MDNS_ENABLE_DEBUG + if (out_sync_browse->sync_result) { +#ifdef MDNS_ENABLE_DEBUG + _mdns_dbg_printf("Changed result:"); + debug_printf_browse_result_all(out_sync_browse->sync_result->result); +#endif // MDNS_ENABLE_DEBUG + _mdns_sync_browse_action(ACTION_BROWSE_SYNC, out_sync_browse); + } else { + free(out_sync_browse); + } + } + +clear_rx_packet: + while (parsed_packet->questions) { + mdns_parsed_question_t *question = parsed_packet->questions; + parsed_packet->questions = parsed_packet->questions->next; + if (question->host) { + free(question->host); + } + if (question->service) { + free(question->service); + } + if (question->proto) { + free(question->proto); + } + if (question->domain) { + free(question->domain); + } + free(question); + } + while (parsed_packet->records) { + mdns_parsed_record_t *record = parsed_packet->records; + parsed_packet->records = parsed_packet->records->next; + if (record->host) { + free(record->host); + } + if (record->service) { + free(record->service); + } + if (record->proto) { + free(record->proto); + } + record->next = NULL; + free(record); + } + free(parsed_packet); + if (browse_result_instance) { + free(browse_result_instance); + } + if (browse_result_service) { + free(browse_result_service); + } + if (browse_result_proto) { + free(browse_result_proto); + } +} + +/** + * @brief Enable mDNS interface + */ +void _mdns_enable_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + if (!mdns_is_netif_ready(tcpip_if, ip_protocol)) { + if (_mdns_pcb_init(tcpip_if, ip_protocol)) { + _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].failed_probes = 0; + return; + } + } + _mdns_restart_pcb(tcpip_if, ip_protocol); +} + +/** + * @brief Disable mDNS interface + */ +void _mdns_disable_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + _mdns_clean_netif_ptr(tcpip_if); + + if (mdns_is_netif_ready(tcpip_if, ip_protocol)) { + _mdns_clear_pcb_tx_queue_head(tcpip_if, ip_protocol); + mdns_pcb_deinit_local(tcpip_if, ip_protocol); + mdns_if_t other_if = _mdns_get_other_if (tcpip_if); + if (other_if != MDNS_MAX_INTERFACES && _mdns_server->interfaces[other_if].pcbs[ip_protocol].state == PCB_DUP) { + _mdns_server->interfaces[other_if].pcbs[ip_protocol].state = PCB_OFF; + _mdns_enable_pcb(other_if, ip_protocol); + } + } + _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].state = PCB_OFF; +} + +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES +static inline char nibble_to_hex(int var) +{ + return var > 9 ? var - 10 + 'a' : var + '0'; +} +#endif + +/** + * @brief Performs interface changes based on system events or custom commands + */ +static void perform_event_action(mdns_if_t mdns_if, mdns_event_actions_t action) +{ + if (!_mdns_server || mdns_if >= MDNS_MAX_INTERFACES) { + return; + } + if (action & MDNS_EVENT_ENABLE_IP4) { + _mdns_enable_pcb(mdns_if, MDNS_IP_PROTOCOL_V4); + } + if (action & MDNS_EVENT_ENABLE_IP6) { + _mdns_enable_pcb(mdns_if, MDNS_IP_PROTOCOL_V6); + } + if (action & MDNS_EVENT_DISABLE_IP4) { + _mdns_disable_pcb(mdns_if, MDNS_IP_PROTOCOL_V4); + } + if (action & MDNS_EVENT_DISABLE_IP6) { + _mdns_disable_pcb(mdns_if, MDNS_IP_PROTOCOL_V6); + } + if (action & MDNS_EVENT_ANNOUNCE_IP4) { + _mdns_announce_pcb(mdns_if, MDNS_IP_PROTOCOL_V4, NULL, 0, true); + } + if (action & MDNS_EVENT_ANNOUNCE_IP6) { + _mdns_announce_pcb(mdns_if, MDNS_IP_PROTOCOL_V6, NULL, 0, true); + } + +#ifdef CONFIG_MDNS_RESPOND_REVERSE_QUERIES +#ifdef CONFIG_LWIP_IPV4 + if (action & MDNS_EVENT_IP4_REVERSE_LOOKUP) { + esp_netif_ip_info_t if_ip_info; + if (esp_netif_get_ip_info(_mdns_get_esp_netif(mdns_if), &if_ip_info) == ESP_OK) { + esp_ip4_addr_t *ip = &if_ip_info.ip; + char *reverse_query_name = NULL; + if (asprintf(&reverse_query_name, "%d.%d.%d.%d.in-addr", + esp_ip4_addr4_16(ip), esp_ip4_addr3_16(ip), + esp_ip4_addr2_16(ip), esp_ip4_addr1_16(ip)) > 0 && reverse_query_name) { + ESP_LOGD(TAG, "Registered reverse query: %s.arpa", reverse_query_name); + _mdns_delegate_hostname_add(reverse_query_name, NULL); + } + } + } +#endif /* CONFIG_LWIP_IPV4 */ +#ifdef CONFIG_LWIP_IPV6 + if (action & MDNS_EVENT_IP6_REVERSE_LOOKUP) { + esp_ip6_addr_t addr6; + if (!esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(mdns_if), &addr6) && !_ipv6_address_is_zero(addr6)) { + uint8_t *paddr = (uint8_t *)&addr6.addr; + const char sub[] = "ip6"; + const size_t query_name_size = 4 * sizeof(addr6.addr) /* (2 nibbles + 2 dots)/per byte of IP address */ + sizeof(sub); + char *reverse_query_name = malloc(query_name_size); + if (reverse_query_name) { + char *ptr = &reverse_query_name[query_name_size]; // point to the end + memcpy(ptr - sizeof(sub), sub, sizeof(sub)); // copy the IP sub-domain + ptr -= sizeof(sub) + 1; // move before the sub-domain + while (reverse_query_name < ptr) { // continue populating reverse query from the end + *ptr-- = '.'; // nibble by nibble, until we reach the beginning + *ptr-- = nibble_to_hex(((*paddr) >> 4) & 0x0F); + *ptr-- = '.'; + *ptr-- = nibble_to_hex((*paddr) & 0x0F); + paddr++; + } + ESP_LOGD(TAG, "Registered reverse query: %s.arpa", reverse_query_name); + _mdns_delegate_hostname_add(reverse_query_name, NULL); + } + } + } +#endif /* CONFIG_LWIP_IPV6 */ +#endif /* CONFIG_MDNS_RESPOND_REVERSE_QUERIES */ +} + +/** + * @brief Dispatch interface changes based on system events + */ +static inline void post_mdns_disable_pcb(mdns_predef_if_t preset_if, mdns_ip_protocol_t protocol) +{ + mdns_post_custom_action_tcpip_if(mdns_if_from_preset_if(preset_if), protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_EVENT_DISABLE_IP4 : MDNS_EVENT_DISABLE_IP6); +} + +static inline void post_mdns_enable_pcb(mdns_predef_if_t preset_if, mdns_ip_protocol_t protocol) +{ + mdns_post_custom_action_tcpip_if(mdns_if_from_preset_if(preset_if), protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_EVENT_ENABLE_IP4 : MDNS_EVENT_ENABLE_IP6); +} + +static inline void post_mdns_announce_pcb(mdns_predef_if_t preset_if, mdns_ip_protocol_t protocol) +{ + mdns_post_custom_action_tcpip_if(mdns_if_from_preset_if(preset_if), protocol == MDNS_IP_PROTOCOL_V4 ? MDNS_EVENT_ANNOUNCE_IP4 : MDNS_EVENT_ANNOUNCE_IP6); +} + +#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH +void mdns_preset_if_handle_system_event(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (!_mdns_server) { + return; + } + + esp_netif_dhcp_status_t dcst; +#if MDNS_ESP_WIFI_ENABLED && (CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP) + if (event_base == WIFI_EVENT) { + switch (event_id) { + case WIFI_EVENT_STA_CONNECTED: + if (!esp_netif_dhcpc_get_status(esp_netif_from_preset_if(MDNS_IF_STA), &dcst)) { + if (dcst == ESP_NETIF_DHCP_STOPPED) { + post_mdns_enable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4); + } + } + break; + case WIFI_EVENT_STA_DISCONNECTED: + post_mdns_disable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4); + post_mdns_disable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V6); + break; + case WIFI_EVENT_AP_START: + post_mdns_enable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V4); + break; + case WIFI_EVENT_AP_STOP: + post_mdns_disable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V4); + post_mdns_disable_pcb(MDNS_IF_AP, MDNS_IP_PROTOCOL_V6); + break; + default: + break; + } + } else +#endif +#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH + if (event_base == ETH_EVENT) { + switch (event_id) { + case ETHERNET_EVENT_CONNECTED: + if (!esp_netif_dhcpc_get_status(esp_netif_from_preset_if(MDNS_IF_ETH), &dcst)) { + if (dcst == ESP_NETIF_DHCP_STOPPED) { + post_mdns_enable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4); + } + } + break; + case ETHERNET_EVENT_DISCONNECTED: + post_mdns_disable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4); + post_mdns_disable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V6); + break; + default: + break; + } + } else +#endif + if (event_base == IP_EVENT) { + switch (event_id) { + case IP_EVENT_STA_GOT_IP: + post_mdns_enable_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V4); + post_mdns_announce_pcb(MDNS_IF_STA, MDNS_IP_PROTOCOL_V6); + break; +#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH + case IP_EVENT_ETH_GOT_IP: + post_mdns_enable_pcb(MDNS_IF_ETH, MDNS_IP_PROTOCOL_V4); + break; +#endif + case IP_EVENT_GOT_IP6: { + ip_event_got_ip6_t *event = (ip_event_got_ip6_t *) event_data; + mdns_if_t mdns_if = _mdns_get_if_from_esp_netif(event->esp_netif); + if (mdns_if < MDNS_MAX_INTERFACES) { + post_mdns_enable_pcb(mdns_if, MDNS_IP_PROTOCOL_V6); + post_mdns_announce_pcb(mdns_if, MDNS_IP_PROTOCOL_V4); + } + mdns_browse_t *browse = _mdns_server->browse; + while (browse) { + _mdns_browse_send(browse, mdns_if); + browse = browse->next; + } + } + break; + default: + break; + } + } +} +#endif /* CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH */ + +/* + * MDNS Search + * */ + +/** + * @brief Free search structure (except the results) + */ +static void _mdns_search_free(mdns_search_once_t *search) +{ + free(search->instance); + free(search->service); + free(search->proto); + vSemaphoreDelete(search->done_semaphore); + free(search); +} + +/** + * @brief Allocate new search structure + */ +static mdns_search_once_t *_mdns_search_init(const char *name, const char *service, const char *proto, uint16_t type, bool unicast, + uint32_t timeout, uint8_t max_results, mdns_query_notify_t notifier) +{ + mdns_search_once_t *search = (mdns_search_once_t *)malloc(sizeof(mdns_search_once_t)); + if (!search) { + HOOK_MALLOC_FAILED; + return NULL; + } + memset(search, 0, sizeof(mdns_search_once_t)); + + search->done_semaphore = xSemaphoreCreateBinary(); + if (!search->done_semaphore) { + free(search); + return NULL; + } + + if (!_str_null_or_empty(name)) { + search->instance = strndup(name, MDNS_NAME_BUF_LEN - 1); + if (!search->instance) { + _mdns_search_free(search); + return NULL; + } + } + + if (!_str_null_or_empty(service)) { + search->service = strndup(service, MDNS_NAME_BUF_LEN - 1); + if (!search->service) { + _mdns_search_free(search); + return NULL; + } + } + + if (!_str_null_or_empty(proto)) { + search->proto = strndup(proto, MDNS_NAME_BUF_LEN - 1); + if (!search->proto) { + _mdns_search_free(search); + return NULL; + } + } + + search->type = type; + search->unicast = unicast; + search->timeout = timeout; + search->num_results = 0; + search->max_results = max_results; + search->result = NULL; + search->state = SEARCH_INIT; + search->sent_at = 0; + search->started_at = xTaskGetTickCount() * portTICK_PERIOD_MS; + search->notifier = notifier; + search->next = NULL; + + return search; +} + +/** + * @brief Mark search as finished and remove it from search chain + */ +static void _mdns_search_finish(mdns_search_once_t *search) +{ + search->state = SEARCH_OFF; + queueDetach(mdns_search_once_t, _mdns_server->search_once, search); + if (search->notifier) { + search->notifier(search); + } + xSemaphoreGive(search->done_semaphore); +} + +/** + * @brief Add new search to the search chain + */ +static void _mdns_search_add(mdns_search_once_t *search) +{ + search->next = _mdns_server->search_once; + _mdns_server->search_once = search; +} + +/** + * @brief Called from parser to finish any searches that have reached maximum results + */ +static void _mdns_search_finish_done(void) +{ + mdns_search_once_t *search = _mdns_server->search_once; + mdns_search_once_t *s = NULL; + while (search) { + s = search; + search = search->next; + if (s->max_results && s->num_results >= s->max_results) { + _mdns_search_finish(s); + } + } +} + +/** + * @brief Create linked IP (copy) from parsed one + */ +static mdns_ip_addr_t *_mdns_result_addr_create_ip(esp_ip_addr_t *ip) +{ + mdns_ip_addr_t *a = (mdns_ip_addr_t *)malloc(sizeof(mdns_ip_addr_t)); + if (!a) { + HOOK_MALLOC_FAILED; + return NULL; + } + memset(a, 0, sizeof(mdns_ip_addr_t)); + a->addr.type = ip->type; + if (ip->type == ESP_IPADDR_TYPE_V6) { + memcpy(a->addr.u_addr.ip6.addr, ip->u_addr.ip6.addr, 16); + } else { + a->addr.u_addr.ip4.addr = ip->u_addr.ip4.addr; + } + return a; +} + +static inline void _mdns_result_update_ttl(mdns_result_t *r, uint32_t ttl) +{ + r->ttl = r->ttl < ttl ? r->ttl : ttl; +} + +/** + * @brief Chain new IP to search result + */ +static void _mdns_result_add_ip(mdns_result_t *r, esp_ip_addr_t *ip) +{ + mdns_ip_addr_t *a = r->addr; + while (a) { + if (a->addr.type == ip->type) { +#ifdef CONFIG_LWIP_IPV4 + if (a->addr.type == ESP_IPADDR_TYPE_V4 && a->addr.u_addr.ip4.addr == ip->u_addr.ip4.addr) { + return; + } +#endif +#ifdef CONFIG_LWIP_IPV6 + if (a->addr.type == ESP_IPADDR_TYPE_V6 && !memcmp(a->addr.u_addr.ip6.addr, ip->u_addr.ip6.addr, 16)) { + return; + } +#endif + } + a = a->next; + } + a = _mdns_result_addr_create_ip(ip); + if (!a) { + return; + } + a->next = r->addr; + r->addr = a; +} + +/** + * @brief Called from parser to add A/AAAA data to search result + */ +static void _mdns_search_result_add_ip(mdns_search_once_t *search, const char *hostname, esp_ip_addr_t *ip, + mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint32_t ttl) +{ + mdns_result_t *r = NULL; + mdns_ip_addr_t *a = NULL; + + if ((search->type == MDNS_TYPE_A && ip->type == ESP_IPADDR_TYPE_V4) + || (search->type == MDNS_TYPE_AAAA && ip->type == ESP_IPADDR_TYPE_V6) + || search->type == MDNS_TYPE_ANY) { + r = search->result; + while (r) { + if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol) { + _mdns_result_add_ip(r, ip); + _mdns_result_update_ttl(r, ttl); + return; + } + r = r->next; + } + if (!search->max_results || search->num_results < search->max_results) { + r = (mdns_result_t *)malloc(sizeof(mdns_result_t)); + if (!r) { + HOOK_MALLOC_FAILED; + return; + } + + memset(r, 0, sizeof(mdns_result_t)); + + a = _mdns_result_addr_create_ip(ip); + if (!a) { + free(r); + return; + } + a->next = r->addr; + r->hostname = strdup(hostname); + r->addr = a; + r->esp_netif = _mdns_get_esp_netif(tcpip_if); + r->ip_protocol = ip_protocol; + r->next = search->result; + r->ttl = ttl; + search->result = r; + search->num_results++; + } + } else if (search->type == MDNS_TYPE_PTR || search->type == MDNS_TYPE_SRV) { + r = search->result; + while (r) { + if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) { + _mdns_result_add_ip(r, ip); + _mdns_result_update_ttl(r, ttl); + break; + } + r = r->next; + } + } +} + +/** + * @brief Called from parser to add PTR data to search result + */ +static mdns_result_t *_mdns_search_result_add_ptr(mdns_search_once_t *search, const char *instance, + const char *service_type, const char *proto, mdns_if_t tcpip_if, + mdns_ip_protocol_t ip_protocol, uint32_t ttl) +{ + mdns_result_t *r = search->result; + while (r) { + if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->instance_name) && !strcasecmp(instance, r->instance_name)) { + _mdns_result_update_ttl(r, ttl); + return r; + } + r = r->next; + } + if (!search->max_results || search->num_results < search->max_results) { + r = (mdns_result_t *)malloc(sizeof(mdns_result_t)); + if (!r) { + HOOK_MALLOC_FAILED; + return NULL; + } + + memset(r, 0, sizeof(mdns_result_t)); + r->instance_name = strdup(instance); + r->service_type = strdup(service_type); + r->proto = strdup(proto); + if (!r->instance_name) { + free(r); + return NULL; + } + + r->esp_netif = _mdns_get_esp_netif(tcpip_if); + r->ip_protocol = ip_protocol; + r->ttl = ttl; + r->next = search->result; + search->result = r; + search->num_results++; + return r; + } + return NULL; +} + +/** + * @brief Called from parser to add SRV data to search result + */ +static void _mdns_search_result_add_srv(mdns_search_once_t *search, const char *hostname, uint16_t port, + mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint32_t ttl) +{ + mdns_result_t *r = search->result; + while (r) { + if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) { + _mdns_result_update_ttl(r, ttl); + return; + } + r = r->next; + } + if (!search->max_results || search->num_results < search->max_results) { + r = (mdns_result_t *)malloc(sizeof(mdns_result_t)); + if (!r) { + HOOK_MALLOC_FAILED; + return; + } + + memset(r, 0, sizeof(mdns_result_t)); + r->hostname = strdup(hostname); + if (!r->hostname) { + free(r); + return; + } + if (search->instance) { + r->instance_name = strdup(search->instance); + } + r->service_type = strdup(search->service); + r->proto = strdup(search->proto); + r->port = port; + r->esp_netif = _mdns_get_esp_netif(tcpip_if); + r->ip_protocol = ip_protocol; + r->ttl = ttl; + r->next = search->result; + search->result = r; + search->num_results++; + } +} + +/** + * @brief Called from parser to add TXT data to search result + */ +static void _mdns_search_result_add_txt(mdns_search_once_t *search, mdns_txt_item_t *txt, uint8_t *txt_value_len, + size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, + uint32_t ttl) +{ + mdns_result_t *r = search->result; + while (r) { + if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol) { + if (r->txt) { + goto free_txt; + } + r->txt = txt; + r->txt_value_len = txt_value_len; + r->txt_count = txt_count; + _mdns_result_update_ttl(r, ttl); + return; + } + r = r->next; + } + if (!search->max_results || search->num_results < search->max_results) { + r = (mdns_result_t *)malloc(sizeof(mdns_result_t)); + if (!r) { + HOOK_MALLOC_FAILED; + goto free_txt; + } + + memset(r, 0, sizeof(mdns_result_t)); + r->txt = txt; + r->txt_value_len = txt_value_len; + r->txt_count = txt_count; + r->esp_netif = _mdns_get_esp_netif(tcpip_if); + r->ip_protocol = ip_protocol; + r->ttl = ttl; + r->next = search->result; + search->result = r; + search->num_results++; + } + return; + +free_txt: + for (size_t i = 0; i < txt_count; i++) { + free((char *)(txt[i].key)); + free((char *)(txt[i].value)); + } + free(txt); + free(txt_value_len); +} + +/** + * @brief Called from packet parser to find matching running search + */ +static mdns_search_once_t *_mdns_search_find_from(mdns_search_once_t *s, mdns_name_t *name, uint16_t type, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_result_t *r = NULL; + while (s) { + if (s->state == SEARCH_OFF) { + s = s->next; + continue; + } + + if (type == MDNS_TYPE_A || type == MDNS_TYPE_AAAA) { + if ((s->type == MDNS_TYPE_ANY && s->service != NULL) + || (s->type != MDNS_TYPE_ANY && s->type != type && s->type != MDNS_TYPE_PTR && s->type != MDNS_TYPE_SRV)) { + s = s->next; + continue; + } + if (s->type != MDNS_TYPE_PTR && s->type != MDNS_TYPE_SRV) { + if (!strcasecmp(name->host, s->instance)) { + return s; + } + s = s->next; + continue; + } + r = s->result; + while (r) { + if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(name->host, r->hostname)) { + return s; + } + r = r->next; + } + s = s->next; + continue; + } + + if (type == MDNS_TYPE_SRV || type == MDNS_TYPE_TXT) { + if ((s->type == MDNS_TYPE_ANY && s->service == NULL) + || (s->type != MDNS_TYPE_ANY && s->type != type && s->type != MDNS_TYPE_PTR)) { + s = s->next; + continue; + } + if (strcasecmp(name->service, s->service) + || strcasecmp(name->proto, s->proto)) { + s = s->next; + continue; + } + if (s->type != MDNS_TYPE_PTR) { + if (s->instance && strcasecmp(name->host, s->instance) == 0) { + return s; + } + s = s->next; + continue; + } + return s; + } + + if (type == MDNS_TYPE_PTR && type == s->type && !strcasecmp(name->service, s->service) && !strcasecmp(name->proto, s->proto)) { + return s; + } + + s = s->next; + } + + return NULL; +} + +/** + * @brief Create search packet for particular interface + */ +static mdns_tx_packet_t *_mdns_create_search_packet(mdns_search_once_t *search, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_result_t *r = NULL; + mdns_tx_packet_t *packet = _mdns_alloc_packet_default(tcpip_if, ip_protocol); + if (!packet) { + return NULL; + } + + mdns_out_question_t *q = (mdns_out_question_t *)malloc(sizeof(mdns_out_question_t)); + if (!q) { + HOOK_MALLOC_FAILED; + _mdns_free_tx_packet(packet); + return NULL; + } + q->next = NULL; + q->unicast = search->unicast; + q->type = search->type; + q->host = search->instance; + q->service = search->service; + q->proto = search->proto; + q->domain = MDNS_DEFAULT_DOMAIN; + q->own_dynamic_memory = false; + queueToEnd(mdns_out_question_t, packet->questions, q); + + if (search->type == MDNS_TYPE_PTR) { + r = search->result; + while (r) { + //full record on the same interface is available + if (r->esp_netif != _mdns_get_esp_netif(tcpip_if) || r->ip_protocol != ip_protocol || r->instance_name == NULL || r->hostname == NULL || r->addr == NULL) { + r = r->next; + continue; + } + mdns_out_answer_t *a = (mdns_out_answer_t *)malloc(sizeof(mdns_out_answer_t)); + if (!a) { + HOOK_MALLOC_FAILED; + _mdns_free_tx_packet(packet); + return NULL; + } + a->type = MDNS_TYPE_PTR; + a->service = NULL; + a->custom_instance = r->instance_name; + a->custom_service = search->service; + a->custom_proto = search->proto; + a->bye = false; + a->flush = false; + a->next = NULL; + queueToEnd(mdns_out_answer_t, packet->answers, a); + r = r->next; + } + } + + return packet; +} + +/** + * @brief Send search packet to particular interface + */ +static void _mdns_search_send_pcb(mdns_search_once_t *search, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_tx_packet_t *packet = NULL; + if (mdns_is_netif_ready(tcpip_if, ip_protocol) && _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].state > PCB_INIT) { + packet = _mdns_create_search_packet(search, tcpip_if, ip_protocol); + if (!packet) { + return; + } + _mdns_dispatch_tx_packet(packet); + _mdns_free_tx_packet(packet); + } +} + +/** + * @brief Send search packet to all available interfaces + */ +static void _mdns_search_send(mdns_search_once_t *search) +{ + mdns_search_once_t *queue = _mdns_server->search_once; + bool found = false; + // looking for this search in active searches + while (queue) { + if (queue == search) { + found = true; + break; + } + queue = queue->next; + } + + if (!found) { + // no longer active -> skip sending this search + return; + } + + uint8_t i, j; + for (i = 0; i < MDNS_MAX_INTERFACES; i++) { + for (j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) { + _mdns_search_send_pcb(search, (mdns_if_t)i, (mdns_ip_protocol_t)j); + } + } +} + +static void _mdns_tx_handle_packet(mdns_tx_packet_t *p) +{ + mdns_tx_packet_t *a = NULL; + mdns_out_question_t *q = NULL; + mdns_pcb_t *pcb = &_mdns_server->interfaces[p->tcpip_if].pcbs[p->ip_protocol]; + uint32_t send_after = 1000; + + if (pcb->state == PCB_OFF) { + _mdns_free_tx_packet(p); + return; + } + _mdns_dispatch_tx_packet(p); + + switch (pcb->state) { + case PCB_PROBE_1: + q = p->questions; + while (q) { + q->unicast = false; + q = q->next; + } + //fallthrough + case PCB_PROBE_2: + _mdns_schedule_tx_packet(p, 250); + pcb->state = (mdns_pcb_state_t)((uint8_t)(pcb->state) + 1); + break; + case PCB_PROBE_3: + a = _mdns_create_announce_from_probe(p); + if (!a) { + _mdns_schedule_tx_packet(p, 250); + break; + } + pcb->probe_running = false; + pcb->probe_ip = false; + pcb->probe_services_len = 0; + pcb->failed_probes = 0; + free(pcb->probe_services); + pcb->probe_services = NULL; + _mdns_free_tx_packet(p); + p = a; + send_after = 250; + //fallthrough + case PCB_ANNOUNCE_1: + //fallthrough + case PCB_ANNOUNCE_2: + _mdns_schedule_tx_packet(p, send_after); + pcb->state = (mdns_pcb_state_t)((uint8_t)(pcb->state) + 1); + break; + case PCB_ANNOUNCE_3: + pcb->state = PCB_RUNNING; + _mdns_free_tx_packet(p); + break; + default: + _mdns_free_tx_packet(p); + break; + } +} + +static void _mdns_remap_self_service_hostname(const char *old_hostname, const char *new_hostname) +{ + mdns_srv_item_t *service = _mdns_server->services; + + while (service) { + if (service->service->hostname && + strcmp(service->service->hostname, old_hostname) == 0) { + free((char *)service->service->hostname); + service->service->hostname = strdup(new_hostname); + } + service = service->next; + } +} + +static void _mdns_sync_browse_result_link_free(mdns_browse_sync_t *browse_sync) +{ + mdns_browse_result_sync_t *current = browse_sync->sync_result; + mdns_browse_result_sync_t *need_free; + while (current) { + need_free = current; + current = current->next; + free(need_free); + } + free(browse_sync); +} + +/** + * @brief Free action data + */ +static void _mdns_free_action(mdns_action_t *action) +{ + switch (action->type) { + case ACTION_HOSTNAME_SET: + free(action->data.hostname_set.hostname); + break; + case ACTION_INSTANCE_SET: + free(action->data.instance); + break; + case ACTION_SEARCH_ADD: + //fallthrough + case ACTION_SEARCH_SEND: + //fallthrough + case ACTION_SEARCH_END: + _mdns_search_free(action->data.search_add.search); + break; + case ACTION_BROWSE_ADD: + //fallthrough + case ACTION_BROWSE_END: + _mdns_browse_item_free(action->data.browse_add.browse); + break; + case ACTION_BROWSE_SYNC: + _mdns_sync_browse_result_link_free(action->data.browse_sync.browse_sync); + break; + case ACTION_TX_HANDLE: + _mdns_free_tx_packet(action->data.tx_handle.packet); + break; + case ACTION_RX_HANDLE: + _mdns_packet_free(action->data.rx_handle.packet); + break; + case ACTION_DELEGATE_HOSTNAME_SET_ADDR: + case ACTION_DELEGATE_HOSTNAME_ADD: + free((char *)action->data.delegate_hostname.hostname); + free_address_list(action->data.delegate_hostname.address_list); + break; + case ACTION_DELEGATE_HOSTNAME_REMOVE: + free((char *)action->data.delegate_hostname.hostname); + break; + default: + break; + } + free(action); +} + +/** + * @brief Called from service thread to execute given action + */ +static void _mdns_execute_action(mdns_action_t *action) +{ + switch (action->type) { + case ACTION_SYSTEM_EVENT: + perform_event_action(action->data.sys_event.interface, action->data.sys_event.event_action); + break; + case ACTION_HOSTNAME_SET: + _mdns_send_bye_all_pcbs_no_instance(true); + _mdns_remap_self_service_hostname(_mdns_server->hostname, action->data.hostname_set.hostname); + free((char *)_mdns_server->hostname); + _mdns_server->hostname = action->data.hostname_set.hostname; + _mdns_self_host.hostname = action->data.hostname_set.hostname; + _mdns_restart_all_pcbs(); + xSemaphoreGive(_mdns_server->action_sema); + break; + case ACTION_INSTANCE_SET: + _mdns_send_bye_all_pcbs_no_instance(false); + free((char *)_mdns_server->instance); + _mdns_server->instance = action->data.instance; + _mdns_restart_all_pcbs_no_instance(); + + break; + case ACTION_SEARCH_ADD: + _mdns_search_add(action->data.search_add.search); + break; + case ACTION_SEARCH_SEND: + _mdns_search_send(action->data.search_add.search); + break; + case ACTION_SEARCH_END: + _mdns_search_finish(action->data.search_add.search); + break; + + case ACTION_BROWSE_ADD: + _mdns_browse_add(action->data.browse_add.browse); + break; + case ACTION_BROWSE_SYNC: + _mdns_browse_sync(action->data.browse_sync.browse_sync); + _mdns_sync_browse_result_link_free(action->data.browse_sync.browse_sync); + break; + case ACTION_BROWSE_END: + _mdns_browse_finish(action->data.browse_add.browse); + break; + + case ACTION_TX_HANDLE: { + mdns_tx_packet_t *p = _mdns_server->tx_queue_head; + // packet to be handled should be at tx head, but must be consistent with the one pushed to action queue + if (p && p == action->data.tx_handle.packet && p->queued) { + p->queued = false; // clearing, as the packet might be reused (pushed and transmitted again) + _mdns_server->tx_queue_head = p->next; + _mdns_tx_handle_packet(p); + } else { + ESP_LOGD(TAG, "Skipping transmit of an unexpected packet!"); + } + } + break; + case ACTION_RX_HANDLE: + mdns_parse_packet(action->data.rx_handle.packet); + _mdns_packet_free(action->data.rx_handle.packet); + break; + case ACTION_DELEGATE_HOSTNAME_ADD: + if (!_mdns_delegate_hostname_add(action->data.delegate_hostname.hostname, + action->data.delegate_hostname.address_list)) { + free((char *)action->data.delegate_hostname.hostname); + free_address_list(action->data.delegate_hostname.address_list); + } + xSemaphoreGive(_mdns_server->action_sema); + break; + case ACTION_DELEGATE_HOSTNAME_SET_ADDR: + if (!_mdns_delegate_hostname_set_address(action->data.delegate_hostname.hostname, + action->data.delegate_hostname.address_list)) { + free_address_list(action->data.delegate_hostname.address_list); + } + free((char *)action->data.delegate_hostname.hostname); + break; + case ACTION_DELEGATE_HOSTNAME_REMOVE: + _mdns_delegate_hostname_remove(action->data.delegate_hostname.hostname); + free((char *)action->data.delegate_hostname.hostname); + break; + default: + break; + } + free(action); +} + +/** + * @brief Queue search action + */ +static esp_err_t _mdns_send_search_action(mdns_action_type_t type, mdns_search_once_t *search) +{ + mdns_action_t *action = NULL; + + action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + return ESP_ERR_NO_MEM; + } + + action->type = type; + action->data.search_add.search = search; + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(action); + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} + +/** + * @brief Called from timer task to run mDNS responder + * + * periodically checks first unqueued packet (from tx head). + * if it is scheduled to be transmitted, then pushes the packet to action queue to be handled. + * + */ +static void _mdns_scheduler_run(void) +{ + MDNS_SERVICE_LOCK(); + mdns_tx_packet_t *p = _mdns_server->tx_queue_head; + mdns_action_t *action = NULL; + + // find first unqueued packet + while (p && p->queued) { + p = p->next; + } + if (!p) { + MDNS_SERVICE_UNLOCK(); + return; + } + while (p && (int32_t)(p->send_at - (xTaskGetTickCount() * portTICK_PERIOD_MS)) < 0) { + action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (action) { + action->type = ACTION_TX_HANDLE; + action->data.tx_handle.packet = p; + p->queued = true; + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(action); + p->queued = false; + } + } else { + HOOK_MALLOC_FAILED; + break; + } + //Find the next unqued packet + p = p->next; + } + MDNS_SERVICE_UNLOCK(); +} + +/** + * @brief Called from timer task to run active searches + */ +static void _mdns_search_run(void) +{ + MDNS_SERVICE_LOCK(); + mdns_search_once_t *s = _mdns_server->search_once; + uint32_t now = xTaskGetTickCount() * portTICK_PERIOD_MS; + if (!s) { + MDNS_SERVICE_UNLOCK(); + return; + } + while (s) { + if (s->state != SEARCH_OFF) { + if (now > (s->started_at + s->timeout)) { + s->state = SEARCH_OFF; + if (_mdns_send_search_action(ACTION_SEARCH_END, s) != ESP_OK) { + s->state = SEARCH_RUNNING; + } + } else if (s->state == SEARCH_INIT || (now - s->sent_at) > 1000) { + s->state = SEARCH_RUNNING; + s->sent_at = now; + if (_mdns_send_search_action(ACTION_SEARCH_SEND, s) != ESP_OK) { + s->sent_at -= 1000; + } + } + } + s = s->next; + } + MDNS_SERVICE_UNLOCK(); +} + +/** + * @brief the main MDNS service task. Packets are received and parsed here + */ +static void _mdns_service_task(void *pvParameters) +{ + mdns_action_t *a = NULL; + for (;;) { + if (_mdns_server && _mdns_server->action_queue) { + if (xQueueReceive(_mdns_server->action_queue, &a, portMAX_DELAY) == pdTRUE) { + if (a && a->type == ACTION_TASK_STOP) { + break; + } + MDNS_SERVICE_LOCK(); + _mdns_execute_action(a); + MDNS_SERVICE_UNLOCK(); + } + } else { + vTaskDelay(500 * portTICK_PERIOD_MS); + } + } + _mdns_service_task_handle = NULL; + vTaskDelete(NULL); +} + +static void _mdns_timer_cb(void *arg) +{ + _mdns_scheduler_run(); + _mdns_search_run(); +} + +static esp_err_t _mdns_start_timer(void) +{ + esp_timer_create_args_t timer_conf = { + .callback = _mdns_timer_cb, + .arg = NULL, + .dispatch_method = ESP_TIMER_TASK, + .name = "mdns_timer" + }; + esp_err_t err = esp_timer_create(&timer_conf, &(_mdns_server->timer_handle)); + if (err) { + return err; + } + return esp_timer_start_periodic(_mdns_server->timer_handle, MDNS_TIMER_PERIOD_US); +} + +static esp_err_t _mdns_stop_timer(void) +{ + esp_err_t err = ESP_OK; + if (_mdns_server->timer_handle) { + err = esp_timer_stop(_mdns_server->timer_handle); + if (err) { + return err; + } + err = esp_timer_delete(_mdns_server->timer_handle); + } + return err; +} + +/** + * @brief Start the service thread if not running + * + * @return + * - ESP_OK on success + * - ESP_FAIL on error + */ +static esp_err_t _mdns_service_task_start(void) +{ + if (!_mdns_service_semaphore) { + _mdns_service_semaphore = xSemaphoreCreateMutex(); + if (!_mdns_service_semaphore) { + return ESP_FAIL; + } + } + MDNS_SERVICE_LOCK(); + if (_mdns_start_timer()) { + MDNS_SERVICE_UNLOCK(); + return ESP_FAIL; + } + if (!_mdns_service_task_handle) { + xTaskCreatePinnedToCore(_mdns_service_task, "mdns", MDNS_SERVICE_STACK_DEPTH, NULL, MDNS_TASK_PRIORITY, + (TaskHandle_t *const)(&_mdns_service_task_handle), MDNS_TASK_AFFINITY); + if (!_mdns_service_task_handle) { + _mdns_stop_timer(); + MDNS_SERVICE_UNLOCK(); + vSemaphoreDelete(_mdns_service_semaphore); + _mdns_service_semaphore = NULL; + return ESP_FAIL; + } + } + MDNS_SERVICE_UNLOCK(); + return ESP_OK; +} + +/** + * @brief Stop the service thread + * + * @return + * - ESP_OK + */ +static esp_err_t _mdns_service_task_stop(void) +{ + _mdns_stop_timer(); + if (_mdns_service_task_handle) { + mdns_action_t action; + mdns_action_t *a = &action; + action.type = ACTION_TASK_STOP; + if (xQueueSend(_mdns_server->action_queue, &a, (TickType_t)0) != pdPASS) { + vTaskDelete(_mdns_service_task_handle); + _mdns_service_task_handle = NULL; + } + while (_mdns_service_task_handle) { + vTaskDelay(10 / portTICK_PERIOD_MS); + } + } + vSemaphoreDelete(_mdns_service_semaphore); + _mdns_service_semaphore = NULL; + return ESP_OK; +} + +static esp_err_t mdns_post_custom_action_tcpip_if(mdns_if_t mdns_if, mdns_event_actions_t event_action) +{ + if (!_mdns_server || mdns_if >= MDNS_MAX_INTERFACES) { + return ESP_ERR_INVALID_STATE; + } + + mdns_action_t *action = (mdns_action_t *)calloc(1, sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + return ESP_ERR_NO_MEM; + } + action->type = ACTION_SYSTEM_EVENT; + action->data.sys_event.event_action = event_action; + action->data.sys_event.interface = mdns_if; + + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(action); + } + return ESP_OK; +} + +static inline void set_default_duplicated_interfaces(void) +{ + mdns_if_t wifi_sta_if = MDNS_MAX_INTERFACES; + mdns_if_t eth_if = MDNS_MAX_INTERFACES; + for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; i++) { + if (s_esp_netifs[i].predefined && s_esp_netifs[i].predef_if == MDNS_IF_STA) { + wifi_sta_if = i; + } + if (s_esp_netifs[i].predefined && s_esp_netifs[i].predef_if == MDNS_IF_ETH) { + eth_if = i; + } + } + if (wifi_sta_if != MDNS_MAX_INTERFACES && eth_if != MDNS_MAX_INTERFACES) { + s_esp_netifs[wifi_sta_if].duplicate = eth_if; + s_esp_netifs[eth_if].duplicate = wifi_sta_if; + } +} + +static inline void unregister_predefined_handlers(void) +{ +#if MDNS_ESP_WIFI_ENABLED && (CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP) + esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, mdns_preset_if_handle_system_event); +#endif +#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH + esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, mdns_preset_if_handle_system_event); +#endif +#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH + esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, mdns_preset_if_handle_system_event); +#endif +} + +/* + * Public Methods + * */ + +esp_err_t mdns_netif_action(esp_netif_t *esp_netif, mdns_event_actions_t event_action) +{ + return mdns_post_custom_action_tcpip_if(_mdns_get_if_from_esp_netif(esp_netif), event_action); +} + +esp_err_t mdns_register_netif(esp_netif_t *esp_netif) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + + esp_err_t err = ESP_ERR_NO_MEM; + MDNS_SERVICE_LOCK(); + for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; ++i) { + if (s_esp_netifs[i].netif == esp_netif) { + MDNS_SERVICE_UNLOCK(); + return ESP_ERR_INVALID_STATE; + } + } + + for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; ++i) { + if (!s_esp_netifs[i].predefined && s_esp_netifs[i].netif == NULL) { + s_esp_netifs[i].netif = esp_netif; + err = ESP_OK; + break; + } + } + MDNS_SERVICE_UNLOCK(); + return err; +} + +esp_err_t mdns_unregister_netif(esp_netif_t *esp_netif) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + + esp_err_t err = ESP_ERR_NOT_FOUND; + MDNS_SERVICE_LOCK(); + for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; ++i) { + if (!s_esp_netifs[i].predefined && s_esp_netifs[i].netif == esp_netif) { + s_esp_netifs[i].netif = NULL; + err = ESP_OK; + break; + } + } + MDNS_SERVICE_UNLOCK(); + return err; +} + + +esp_err_t mdns_init(void) +{ + esp_err_t err = ESP_OK; + + if (_mdns_server) { + return err; + } + + _mdns_server = (mdns_server_t *)malloc(sizeof(mdns_server_t)); + if (!_mdns_server) { + HOOK_MALLOC_FAILED; + return ESP_ERR_NO_MEM; + } + memset((uint8_t *)_mdns_server, 0, sizeof(mdns_server_t)); + // zero-out local copy of netifs to initiate a fresh search by interface key whenever a netif ptr is needed + for (mdns_if_t i = 0; i < MDNS_MAX_INTERFACES; ++i) { + s_esp_netifs[i].netif = NULL; + } + + _mdns_server->action_queue = xQueueCreate(MDNS_ACTION_QUEUE_LEN, sizeof(mdns_action_t *)); + if (!_mdns_server->action_queue) { + err = ESP_ERR_NO_MEM; + goto free_server; + } + + _mdns_server->action_sema = xSemaphoreCreateBinary(); + if (!_mdns_server->action_sema) { + err = ESP_ERR_NO_MEM; + goto free_queue; + } + +#if MDNS_ESP_WIFI_ENABLED && (CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP) + if ((err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, mdns_preset_if_handle_system_event, NULL)) != ESP_OK) { + goto free_event_handlers; + } +#endif +#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH + if ((err = esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, mdns_preset_if_handle_system_event, NULL)) != ESP_OK) { + goto free_event_handlers; + } +#endif +#if CONFIG_ETH_ENABLED && CONFIG_MDNS_PREDEF_NETIF_ETH + if ((err = esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, mdns_preset_if_handle_system_event, NULL)) != ESP_OK) { + goto free_event_handlers; + } +#endif + +#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH + set_default_duplicated_interfaces(); +#endif + + uint8_t i; +#ifdef CONFIG_LWIP_IPV6 + esp_ip6_addr_t tmp_addr6; +#endif +#ifdef CONFIG_LWIP_IPV4 + esp_netif_ip_info_t if_ip_info; +#endif + + for (i = 0; i < MDNS_MAX_INTERFACES; i++) { +#ifdef CONFIG_LWIP_IPV6 + if (!esp_netif_get_ip6_linklocal(_mdns_get_esp_netif(i), &tmp_addr6) && !_ipv6_address_is_zero(tmp_addr6)) { + _mdns_enable_pcb(i, MDNS_IP_PROTOCOL_V6); + } +#endif +#ifdef CONFIG_LWIP_IPV4 + if (!esp_netif_get_ip_info(_mdns_get_esp_netif(i), &if_ip_info) && if_ip_info.ip.addr) { + _mdns_enable_pcb(i, MDNS_IP_PROTOCOL_V4); + } +#endif + } + if (_mdns_service_task_start()) { + //service start failed! + err = ESP_FAIL; + goto free_all_and_disable_pcbs; + } + + return ESP_OK; + +free_all_and_disable_pcbs: + for (i = 0; i < MDNS_MAX_INTERFACES; i++) { + _mdns_disable_pcb(i, MDNS_IP_PROTOCOL_V6); + _mdns_disable_pcb(i, MDNS_IP_PROTOCOL_V4); + s_esp_netifs[i].duplicate = MDNS_MAX_INTERFACES; + } +#if CONFIG_MDNS_PREDEF_NETIF_STA || CONFIG_MDNS_PREDEF_NETIF_AP || CONFIG_MDNS_PREDEF_NETIF_ETH +free_event_handlers: + unregister_predefined_handlers(); +#endif + vSemaphoreDelete(_mdns_server->action_sema); +free_queue: + vQueueDelete(_mdns_server->action_queue); +free_server: + free(_mdns_server); + _mdns_server = NULL; + return err; +} + +void mdns_free(void) +{ + uint8_t i, j; + if (!_mdns_server) { + return; + } + + // Unregister handlers before destroying the mdns internals to avoid receiving async events while deinit + unregister_predefined_handlers(); + + mdns_service_remove_all(); + free_delegated_hostnames(); + _mdns_service_task_stop(); + for (i = 0; i < MDNS_MAX_INTERFACES; i++) { + for (j = 0; j < MDNS_IP_PROTOCOL_MAX; j++) { + mdns_pcb_deinit_local(i, j); + } + } + free((char *)_mdns_server->hostname); + free((char *)_mdns_server->instance); + if (_mdns_server->action_queue) { + mdns_action_t *c; + while (xQueueReceive(_mdns_server->action_queue, &c, 0) == pdTRUE) { + _mdns_free_action(c); + } + vQueueDelete(_mdns_server->action_queue); + } + _mdns_clear_tx_queue_head(); + while (_mdns_server->search_once) { + mdns_search_once_t *h = _mdns_server->search_once; + _mdns_server->search_once = h->next; + free(h->instance); + free(h->service); + free(h->proto); + vSemaphoreDelete(h->done_semaphore); + if (h->result) { + _mdns_query_results_free(h->result); + } + free(h); + } + while (_mdns_server->browse) { + mdns_browse_t *b = _mdns_server->browse; + _mdns_server->browse = _mdns_server->browse->next; + _mdns_browse_item_free(b); + + } + vSemaphoreDelete(_mdns_server->action_sema); + free(_mdns_server); + _mdns_server = NULL; +} + +esp_err_t mdns_hostname_set(const char *hostname) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_ARG; + } + if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) { + return ESP_ERR_INVALID_ARG; + } + char *new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1); + if (!new_hostname) { + return ESP_ERR_NO_MEM; + } + + mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + free(new_hostname); + return ESP_ERR_NO_MEM; + } + action->type = ACTION_HOSTNAME_SET; + action->data.hostname_set.hostname = new_hostname; + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(new_hostname); + free(action); + return ESP_ERR_NO_MEM; + } + xSemaphoreTake(_mdns_server->action_sema, portMAX_DELAY); + return ESP_OK; +} + +esp_err_t mdns_hostname_get(char *hostname) +{ + if (!hostname) { + return ESP_ERR_INVALID_ARG; + } + + if (!_mdns_server || !_mdns_server->hostname) { + return ESP_ERR_INVALID_STATE; + } + + MDNS_SERVICE_LOCK(); + size_t len = strnlen(_mdns_server->hostname, MDNS_NAME_BUF_LEN - 1); + strncpy(hostname, _mdns_server->hostname, len); + hostname[len] = 0; + MDNS_SERVICE_UNLOCK(); + return ESP_OK; +} + +esp_err_t mdns_delegate_hostname_add(const char *hostname, const mdns_ip_addr_t *address_list) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) { + return ESP_ERR_INVALID_ARG; + } + char *new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1); + if (!new_hostname) { + return ESP_ERR_NO_MEM; + } + + mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + free(new_hostname); + return ESP_ERR_NO_MEM; + } + action->type = ACTION_DELEGATE_HOSTNAME_ADD; + action->data.delegate_hostname.hostname = new_hostname; + action->data.delegate_hostname.address_list = copy_address_list(address_list); + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(new_hostname); + free(action); + return ESP_ERR_NO_MEM; + } + xSemaphoreTake(_mdns_server->action_sema, portMAX_DELAY); + return ESP_OK; +} + +esp_err_t mdns_delegate_hostname_remove(const char *hostname) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) { + return ESP_ERR_INVALID_ARG; + } + char *new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1); + if (!new_hostname) { + return ESP_ERR_NO_MEM; + } + + mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + free(new_hostname); + return ESP_ERR_NO_MEM; + } + action->type = ACTION_DELEGATE_HOSTNAME_REMOVE; + action->data.delegate_hostname.hostname = new_hostname; + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(new_hostname); + free(action); + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} + +esp_err_t mdns_delegate_hostname_set_address(const char *hostname, const mdns_ip_addr_t *address_list) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + if (_str_null_or_empty(hostname) || strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) { + return ESP_ERR_INVALID_ARG; + } + char *new_hostname = strndup(hostname, MDNS_NAME_BUF_LEN - 1); + if (!new_hostname) { + return ESP_ERR_NO_MEM; + } + + mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + free(new_hostname); + return ESP_ERR_NO_MEM; + } + action->type = ACTION_DELEGATE_HOSTNAME_SET_ADDR; + action->data.delegate_hostname.hostname = new_hostname; + action->data.delegate_hostname.address_list = copy_address_list(address_list); + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(new_hostname); + free(action); + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} + +bool mdns_hostname_exists(const char *hostname) +{ + bool ret = false; + MDNS_SERVICE_LOCK(); + ret = _hostname_is_ours(hostname); + MDNS_SERVICE_UNLOCK(); + return ret; +} + +esp_err_t mdns_instance_name_set(const char *instance) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + if (_str_null_or_empty(instance) || _mdns_server->hostname == NULL || strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) { + return ESP_ERR_INVALID_ARG; + } + char *new_instance = strndup(instance, MDNS_NAME_BUF_LEN - 1); + if (!new_instance) { + return ESP_ERR_NO_MEM; + } + + mdns_action_t *action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + free(new_instance); + return ESP_ERR_NO_MEM; + } + action->type = ACTION_INSTANCE_SET; + action->data.instance = new_instance; + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(new_instance); + free(action); + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} + +/* + * MDNS SERVICES + * */ + +esp_err_t mdns_service_add_for_host(const char *instance, const char *service, const char *proto, const char *host, + uint16_t port, mdns_txt_item_t txt[], size_t num_items) +{ + if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto) || !port || !_mdns_server->hostname) { + return ESP_ERR_INVALID_ARG; + } + + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + const char *hostname = host ? host : _mdns_server->hostname; + mdns_service_t *s = NULL; + + ESP_GOTO_ON_FALSE(_mdns_can_add_more_services(), ESP_ERR_NO_MEM, err, TAG, "Cannot add more services"); + + mdns_srv_item_t *item = _mdns_get_service_item_instance(instance, service, proto, hostname); + ESP_GOTO_ON_FALSE(!item, ESP_ERR_INVALID_ARG, err, TAG, "Service already exists"); + + s = _mdns_create_service(service, proto, hostname, port, instance, num_items, txt); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NO_MEM, err, TAG, "Cannot create service: Out of memory"); + + item = (mdns_srv_item_t *)malloc(sizeof(mdns_srv_item_t)); + ESP_GOTO_ON_FALSE(item, ESP_ERR_NO_MEM, err, TAG, "Cannot create service: Out of memory"); + + item->service = s; + item->next = NULL; + + item->next = _mdns_server->services; + _mdns_server->services = item; + _mdns_probe_all_pcbs(&item, 1, false, false); + MDNS_SERVICE_UNLOCK(); + return ESP_OK; + +err: + MDNS_SERVICE_UNLOCK(); + _mdns_free_service(s); + if (ret == ESP_ERR_NO_MEM) { + HOOK_MALLOC_FAILED; + } + return ret; +} + +esp_err_t mdns_service_add(const char *instance, const char *service, const char *proto, uint16_t port, + mdns_txt_item_t txt[], size_t num_items) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + return mdns_service_add_for_host(instance, service, proto, NULL, port, txt, num_items); +} + +bool mdns_service_exists(const char *service_type, const char *proto, const char *hostname) +{ + bool ret = false; + MDNS_SERVICE_LOCK(); + ret = _mdns_get_service_item(service_type, proto, hostname) != NULL; + MDNS_SERVICE_UNLOCK(); + return ret; +} + +bool mdns_service_exists_with_instance(const char *instance, const char *service_type, const char *proto, + const char *hostname) +{ + bool ret = false; + MDNS_SERVICE_LOCK(); + ret = _mdns_get_service_item_instance(instance, service_type, proto, hostname) != NULL; + MDNS_SERVICE_UNLOCK(); + return ret; +} + +static mdns_txt_item_t *_copy_mdns_txt_items(mdns_txt_linked_item_t *items, uint8_t **txt_value_len, size_t *txt_count) +{ + mdns_txt_item_t *ret = NULL; + size_t ret_index = 0; + for (mdns_txt_linked_item_t *tmp = items; tmp != NULL; tmp = tmp->next) { + ret_index++; + } + *txt_count = ret_index; + if (ret_index == 0) { // handle empty TXT + *txt_value_len = NULL; + return NULL; + } + ret = (mdns_txt_item_t *)calloc(ret_index, sizeof(mdns_txt_item_t)); + *txt_value_len = (uint8_t *)calloc(ret_index, sizeof(uint8_t)); + if (!ret || !(*txt_value_len)) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + ret_index = 0; + for (mdns_txt_linked_item_t *tmp = items; tmp != NULL; tmp = tmp->next) { + size_t key_len = strlen(tmp->key); + char *key = (char *)malloc(key_len + 1); + if (!key) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + memcpy(key, tmp->key, key_len); + key[key_len] = 0; + ret[ret_index].key = key; + char *value = (char *)malloc(tmp->value_len + 1); + if (!value) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + memcpy(value, tmp->value, tmp->value_len); + value[tmp->value_len] = 0; + ret[ret_index].value = value; + (*txt_value_len)[ret_index] = tmp->value_len; + ret_index++; + } + return ret; + +handle_error: + for (size_t y = 0; y < ret_index + 1 && ret != NULL; y++) { + mdns_txt_item_t *t = &ret[y]; + free((char *)t->key); + free((char *)t->value); + } + free(*txt_value_len); + free(ret); + return NULL; +} + +static mdns_ip_addr_t *_copy_delegated_host_address_list(char *hostname) +{ + mdns_host_item_t *host = _mdns_host_list; + while (host) { + if (strcasecmp(host->hostname, hostname) == 0) { + return copy_address_list(host->address_list); + } + host = host->next; + } + return NULL; +} + +static mdns_result_t *_mdns_lookup_service(const char *instance, const char *service, const char *proto, size_t max_results, bool selfhost) +{ + if (_str_null_or_empty(service) || _str_null_or_empty(proto)) { + return NULL; + } + mdns_result_t *results = NULL; + size_t num_results = 0; + mdns_srv_item_t *s = _mdns_server->services; + while (s) { + mdns_service_t *srv = s->service; + if (!srv || !srv->hostname) { + s = s->next; + continue; + } + bool is_service_selfhosted = !_str_null_or_empty(_mdns_server->hostname) && !strcasecmp(_mdns_server->hostname, srv->hostname); + bool is_service_delegated = _str_null_or_empty(_mdns_server->hostname) || strcasecmp(_mdns_server->hostname, srv->hostname); + if ((selfhost && is_service_selfhosted) || (!selfhost && is_service_delegated)) { + if (!strcasecmp(srv->service, service) && !strcasecmp(srv->proto, proto) && + (_str_null_or_empty(instance) || _mdns_instance_name_match(srv->instance, instance))) { + mdns_result_t *item = (mdns_result_t *)malloc(sizeof(mdns_result_t)); + if (!item) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + item->next = results; + results = item; + item->esp_netif = NULL; + item->ttl = _str_null_or_empty(instance) ? MDNS_ANSWER_PTR_TTL : MDNS_ANSWER_SRV_TTL; + item->ip_protocol = MDNS_IP_PROTOCOL_MAX; + if (srv->instance) { + item->instance_name = strndup(srv->instance, MDNS_NAME_BUF_LEN - 1); + if (!item->instance_name) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + } else { + item->instance_name = NULL; + } + item->service_type = strndup(srv->service, MDNS_NAME_BUF_LEN - 1); + if (!item->service_type) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + item->proto = strndup(srv->proto, MDNS_NAME_BUF_LEN - 1); + if (!item->proto) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + item->hostname = strndup(srv->hostname, MDNS_NAME_BUF_LEN - 1); + if (!item->hostname) { + HOOK_MALLOC_FAILED; + goto handle_error; + } + item->port = srv->port; + item->txt = _copy_mdns_txt_items(srv->txt, &(item->txt_value_len), &(item->txt_count)); + // We should not append addresses for selfhost lookup result as we don't know which interface's address to append. + if (selfhost) { + item->addr = NULL; + } else { + item->addr = _copy_delegated_host_address_list(item->hostname); + if (!item->addr) { + goto handle_error; + } + } + if (num_results < max_results) { + num_results++; + } + if (num_results >= max_results) { + break; + } + } + } + s = s->next; + } + return results; +handle_error: + _mdns_query_results_free(results); + return NULL; +} + +esp_err_t mdns_service_port_set_for_host(const char *instance, const char *service, const char *proto, const char *host, uint16_t port) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + const char *hostname = host ? host : _mdns_server->hostname; + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && port, + ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance, service, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + s->service->port = port; + _mdns_announce_all_pcbs(&s, 1, true); + +err: + MDNS_SERVICE_UNLOCK(); + return ret; +} + +esp_err_t mdns_service_port_set(const char *service, const char *proto, uint16_t port) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + return mdns_service_port_set_for_host(NULL, service, proto, NULL, port); +} + +esp_err_t mdns_service_txt_set_for_host(const char *instance, const char *service, const char *proto, const char *host, + mdns_txt_item_t txt_items[], uint8_t num_items) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + const char *hostname = host ? host : _mdns_server->hostname; + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && !(num_items && txt_items == NULL), + ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance, service, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + mdns_txt_linked_item_t *new_txt = NULL; + if (num_items) { + new_txt = _mdns_allocate_txt(num_items, txt_items); + if (!new_txt) { + return ESP_ERR_NO_MEM; + } + } + mdns_service_t *srv = s->service; + mdns_txt_linked_item_t *txt = srv->txt; + srv->txt = NULL; + _mdns_free_linked_txt(txt); + srv->txt = new_txt; + _mdns_announce_all_pcbs(&s, 1, false); + +err: + MDNS_SERVICE_UNLOCK(); + return ret; +} + +esp_err_t mdns_service_txt_set(const char *service, const char *proto, mdns_txt_item_t txt[], uint8_t num_items) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + return mdns_service_txt_set_for_host(NULL, service, proto, NULL, txt, num_items); +} + +esp_err_t mdns_service_txt_item_set_for_host_with_explicit_value_len(const char *instance, const char *service, const char *proto, + const char *host, const char *key, const char *value_arg, uint8_t value_len) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + char *value = NULL; + mdns_txt_linked_item_t *new_txt = NULL; + const char *hostname = host ? host : _mdns_server->hostname; + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && !_str_null_or_empty(key) && + !((!value_arg && value_len)), ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance, service, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + mdns_service_t *srv = s->service; + if (value_len > 0) { + value = (char *) malloc(value_len); + ESP_GOTO_ON_FALSE(value, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory"); + memcpy(value, value_arg, value_len); + } else { + value_len = 0; + } + mdns_txt_linked_item_t *txt = srv->txt; + while (txt) { + if (strcmp(txt->key, key) == 0) { + free((char *)txt->value); + txt->value = value; + txt->value_len = value_len; + break; + } + txt = txt->next; + } + if (!txt) { + new_txt = (mdns_txt_linked_item_t *)malloc(sizeof(mdns_txt_linked_item_t)); + ESP_GOTO_ON_FALSE(new_txt, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory"); + new_txt->key = strdup(key); + ESP_GOTO_ON_FALSE(new_txt->key, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory"); + new_txt->value = value; + new_txt->value_len = value_len; + new_txt->next = srv->txt; + srv->txt = new_txt; + } + + _mdns_announce_all_pcbs(&s, 1, false); + +err: + MDNS_SERVICE_UNLOCK(); + return ret; +out_of_mem: + MDNS_SERVICE_UNLOCK(); + HOOK_MALLOC_FAILED; + free(value); + free(new_txt); + return ret; +} + +esp_err_t mdns_service_txt_item_set_for_host(const char *instance, const char *service, const char *proto, const char *hostname, + const char *key, const char *value) +{ + return mdns_service_txt_item_set_for_host_with_explicit_value_len(instance, service, proto, hostname, key, value, + strlen(value)); +} + + +esp_err_t mdns_service_txt_item_set(const char *service, const char *proto, const char *key, const char *value) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + return mdns_service_txt_item_set_for_host_with_explicit_value_len(NULL, service, proto, NULL, key, + value, strlen(value)); +} + +esp_err_t mdns_service_txt_item_set_with_explicit_value_len(const char *service, const char *proto, const char *key, + const char *value, uint8_t value_len) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + return mdns_service_txt_item_set_for_host_with_explicit_value_len(NULL, service, proto, NULL, key, value, value_len); +} + +esp_err_t mdns_service_txt_item_remove_for_host(const char *instance, const char *service, const char *proto, const char *host, + const char *key) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + const char *hostname = host ? host : _mdns_server->hostname; + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && !_str_null_or_empty(key), + ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance, service, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + mdns_service_t *srv = s->service; + mdns_txt_linked_item_t *txt = srv->txt; + if (!txt) { + goto err; + } + if (strcmp(txt->key, key) == 0) { + srv->txt = txt->next; + free((char *)txt->key); + free((char *)txt->value); + free(txt); + } else { + while (txt->next) { + if (strcmp(txt->next->key, key) == 0) { + mdns_txt_linked_item_t *t = txt->next; + txt->next = t->next; + free((char *)t->key); + free((char *)t->value); + free(t); + break; + } else { + txt = txt->next; + } + } + } + + _mdns_announce_all_pcbs(&s, 1, false); + +err: + MDNS_SERVICE_UNLOCK(); + if (ret == ESP_ERR_NO_MEM) { + HOOK_MALLOC_FAILED; + } + return ret; +} + +esp_err_t mdns_service_txt_item_remove(const char *service, const char *proto, const char *key) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + return mdns_service_txt_item_remove_for_host(NULL, service, proto, NULL, key); +} + +static esp_err_t _mdns_service_subtype_remove_for_host(mdns_srv_item_t *service, const char *subtype) +{ + esp_err_t ret = ESP_ERR_NOT_FOUND; + mdns_subtype_t *srv_subtype = service->service->subtype; + mdns_subtype_t *pre = service->service->subtype; + while (srv_subtype) { + if (strcmp(srv_subtype->subtype, subtype) == 0) { + // Target subtype is found. + if (srv_subtype == service->service->subtype) { + // The first node needs to be removed + service->service->subtype = service->service->subtype->next; + } else { + pre->next = srv_subtype->next; + } + free((char *)srv_subtype->subtype); + free(srv_subtype); + ret = ESP_OK; + break; + } + pre = srv_subtype; + srv_subtype = srv_subtype->next; + } + if (ret == ESP_ERR_NOT_FOUND) { + ESP_LOGE(TAG, "Subtype : %s doesn't exist", subtype); + } + + return ret; +} + +esp_err_t mdns_service_subtype_remove_for_host(const char *instance_name, const char *service, const char *proto, + const char *hostname, const char *subtype) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && + !_str_null_or_empty(subtype), ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance_name, service, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + ret = _mdns_service_subtype_remove_for_host(s, subtype); + ESP_GOTO_ON_ERROR(ret, err, TAG, "Failed to remove the subtype: %s", subtype); + + // TODO: Need to transmit a sendbye message for the removed subtype. + // TODO: Need to remove this subtype answer from the scheduled answer list. +err: + MDNS_SERVICE_UNLOCK(); + return ret; +} + +static esp_err_t _mdns_service_subtype_add_for_host(mdns_srv_item_t *service, const char *subtype) +{ + esp_err_t ret = ESP_OK; + mdns_subtype_t *srv_subtype = service->service->subtype; + while (srv_subtype) { + ESP_GOTO_ON_FALSE(strcmp(srv_subtype->subtype, subtype) != 0, ESP_ERR_INVALID_ARG, err, TAG, "Subtype: %s has already been added", subtype); + srv_subtype = srv_subtype->next; + } + + mdns_subtype_t *subtype_item = (mdns_subtype_t *)malloc(sizeof(mdns_subtype_t)); + ESP_GOTO_ON_FALSE(subtype_item, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory"); + subtype_item->subtype = strdup(subtype); + ESP_GOTO_ON_FALSE(subtype_item->subtype, ESP_ERR_NO_MEM, out_of_mem, TAG, "Out of memory"); + subtype_item->next = service->service->subtype; + service->service->subtype = subtype_item; + +err: + return ret; +out_of_mem: + HOOK_MALLOC_FAILED; + free(subtype_item); + return ret; +} + +esp_err_t mdns_service_subtype_add_multiple_items_for_host(const char *instance_name, const char *service, const char *proto, + const char *hostname, mdns_subtype_item_t subtype[], uint8_t num_items) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + int cur_index = 0; + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && + (num_items > 0), ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance_name, service, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + for (; cur_index < num_items; cur_index++) { + ret = _mdns_service_subtype_add_for_host(s, subtype[cur_index].subtype); + if (ret == ESP_OK) { + continue; + } else if (ret == ESP_ERR_NO_MEM) { + ESP_LOGE(TAG, "Out of memory"); + goto err; + } else { + ESP_LOGE(TAG, "Failed to add subtype: %s", subtype[cur_index].subtype); + goto exit; + } + } + + _mdns_announce_all_pcbs(&s, 1, false); +err: + if (ret == ESP_ERR_NO_MEM) { + for (int idx = 0; idx < cur_index; idx++) { + _mdns_service_subtype_remove_for_host(s, subtype[idx].subtype); + } + } +exit: + MDNS_SERVICE_UNLOCK(); + return ret; +} + +esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, const char *subtype) +{ + mdns_subtype_item_t _subtype[1]; + _subtype[0].subtype = subtype; + return mdns_service_subtype_add_multiple_items_for_host(instance_name, service_type, proto, hostname, _subtype, 1); +} + +esp_err_t mdns_service_subtype_update_multiple_items_for_host(const char *instance_name, const char *service_type, const char *proto, + const char *hostname, mdns_subtype_item_t subtype[], uint8_t num_items) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + int cur_index = 0; + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service_type) && !_str_null_or_empty(proto), + ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance_name, service_type, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + // TODO: find subtype needs to say sendbye + _mdns_free_service_subtype(s->service); + + for (; cur_index < num_items; cur_index++) { + ret = _mdns_service_subtype_add_for_host(s, subtype[cur_index].subtype); + if (ret == ESP_OK) { + continue; + } else if (ret == ESP_ERR_NO_MEM) { + ESP_LOGE(TAG, "Out of memory"); + goto err; + } else { + ESP_LOGE(TAG, "Failed to add subtype: %s", subtype[cur_index].subtype); + goto exit; + } + } + if (num_items) { + _mdns_announce_all_pcbs(&s, 1, false); + } +err: + if (ret == ESP_ERR_NO_MEM) { + for (int idx = 0; idx < cur_index; idx++) { + _mdns_service_subtype_remove_for_host(s, subtype[idx].subtype); + } + } +exit: + MDNS_SERVICE_UNLOCK(); + return ret; +} + +esp_err_t mdns_service_instance_name_set_for_host(const char *instance_old, const char *service, const char *proto, const char *host, + const char *instance) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + const char *hostname = host ? host : _mdns_server->hostname; + + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto) && + !_str_null_or_empty(instance) && strlen(instance) <= (MDNS_NAME_BUF_LEN - 1), ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance_old, service, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + if (s->service->instance) { + _mdns_send_bye(&s, 1, false); + free((char *)s->service->instance); + } + s->service->instance = strndup(instance, MDNS_NAME_BUF_LEN - 1); + ESP_GOTO_ON_FALSE(s->service->instance, ESP_ERR_NO_MEM, err, TAG, "Out of memory"); + _mdns_probe_all_pcbs(&s, 1, false, false); + +err: + MDNS_SERVICE_UNLOCK(); + return ret; +} + +esp_err_t mdns_service_instance_name_set(const char *service, const char *proto, const char *instance) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + return mdns_service_instance_name_set_for_host(NULL, service, proto, NULL, instance); +} + +esp_err_t mdns_service_remove_for_host(const char *instance, const char *service, const char *proto, const char *host) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + const char *hostname = host ? host : _mdns_server->hostname; + ESP_GOTO_ON_FALSE(_mdns_server && _mdns_server->services && !_str_null_or_empty(service) && !_str_null_or_empty(proto), + ESP_ERR_INVALID_ARG, err, TAG, "Invalid state or arguments"); + mdns_srv_item_t *s = _mdns_get_service_item_instance(instance, service, proto, hostname); + ESP_GOTO_ON_FALSE(s, ESP_ERR_NOT_FOUND, err, TAG, "Service doesn't exist"); + + mdns_srv_item_t *a = _mdns_server->services; + mdns_srv_item_t *b = a; + if (instance) { + while (a) { + if (_mdns_service_match_instance(a->service, instance, service, proto, hostname)) { + if (_mdns_server->services != a) { + b->next = a->next; + } else { + _mdns_server->services = a->next; + } + _mdns_send_bye(&a, 1, false); + _mdns_remove_scheduled_service_packets(a->service); + _mdns_free_service(a->service); + free(a); + break; + } + b = a; + a = a->next; + } + } else { + while (a) { + if (_mdns_service_match(a->service, service, proto, hostname)) { + if (_mdns_server->services != a) { + b->next = a->next; + } else { + _mdns_server->services = a->next; + } + _mdns_send_bye(&a, 1, false); + _mdns_remove_scheduled_service_packets(a->service); + _mdns_free_service(a->service); + free(a); + break; + } + b = a; + a = a->next; + } + } + +err: + MDNS_SERVICE_UNLOCK(); + return ret; +} + +esp_err_t mdns_service_remove(const char *service_type, const char *proto) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + return mdns_service_remove_for_host(NULL, service_type, proto, NULL); +} + +esp_err_t mdns_service_remove_all(void) +{ + MDNS_SERVICE_LOCK(); + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE(_mdns_server, ESP_ERR_INVALID_ARG, done, TAG, "Invalid state"); + if (!_mdns_server->services) { + goto done; + } + + _mdns_send_final_bye(false); + mdns_srv_item_t *services = _mdns_server->services; + _mdns_server->services = NULL; + while (services) { + mdns_srv_item_t *s = services; + services = services->next; + _mdns_remove_scheduled_service_packets(s->service); + _mdns_free_service(s->service); + free(s); + } + +done: + MDNS_SERVICE_UNLOCK(); + return ret; +} + +/* + * MDNS QUERY + * */ +void mdns_query_results_free(mdns_result_t *results) +{ + MDNS_SERVICE_LOCK(); + _mdns_query_results_free(results); + MDNS_SERVICE_UNLOCK(); +} + +static void _mdns_query_results_free(mdns_result_t *results) +{ + mdns_result_t *r; + mdns_ip_addr_t *a; + + while (results) { + r = results; + + free((char *)(r->hostname)); + free((char *)(r->instance_name)); + free((char *)(r->service_type)); + free((char *)(r->proto)); + + for (size_t i = 0; i < r->txt_count; i++) { + free((char *)(r->txt[i].key)); + free((char *)(r->txt[i].value)); + } + free(r->txt); + free(r->txt_value_len); + + while (r->addr) { + a = r->addr; + r->addr = r->addr->next; + free(a); + } + + results = results->next; + free(r); + } +} + +esp_err_t mdns_query_async_delete(mdns_search_once_t *search) +{ + if (!search) { + return ESP_ERR_INVALID_ARG; + } + if (search->state != SEARCH_OFF) { + return ESP_ERR_INVALID_STATE; + } + + MDNS_SERVICE_LOCK(); + _mdns_search_free(search); + MDNS_SERVICE_UNLOCK(); + + return ESP_OK; +} + +bool mdns_query_async_get_results(mdns_search_once_t *search, uint32_t timeout, mdns_result_t **results, uint8_t *num_results) +{ + if (xSemaphoreTake(search->done_semaphore, pdMS_TO_TICKS(timeout)) == pdTRUE) { + if (results) { + *results = search->result; + } + if (num_results) { + *num_results = search->num_results; + } + return true; + } + return false; +} + +mdns_search_once_t *mdns_query_async_new(const char *name, const char *service, const char *proto, uint16_t type, + uint32_t timeout, size_t max_results, mdns_query_notify_t notifier) +{ + mdns_search_once_t *search = NULL; + + if (!_mdns_server || !timeout || _str_null_or_empty(service) != _str_null_or_empty(proto)) { + return NULL; + } + + search = _mdns_search_init(name, service, proto, type, type != MDNS_TYPE_PTR, timeout, max_results, notifier); + if (!search) { + return NULL; + } + + if (_mdns_send_search_action(ACTION_SEARCH_ADD, search)) { + _mdns_search_free(search); + return NULL; + } + + return search; +} + +esp_err_t mdns_query_generic(const char *name, const char *service, const char *proto, uint16_t type, mdns_query_transmission_type_t transmission_type, uint32_t timeout, size_t max_results, mdns_result_t **results) +{ + mdns_search_once_t *search = NULL; + + *results = NULL; + + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + + if (!timeout || _str_null_or_empty(service) != _str_null_or_empty(proto)) { + return ESP_ERR_INVALID_ARG; + } + + search = _mdns_search_init(name, service, proto, type, transmission_type == MDNS_QUERY_UNICAST, timeout, max_results, NULL); + if (!search) { + return ESP_ERR_NO_MEM; + } + + if (_mdns_send_search_action(ACTION_SEARCH_ADD, search)) { + _mdns_search_free(search); + return ESP_ERR_NO_MEM; + } + xSemaphoreTake(search->done_semaphore, portMAX_DELAY); + + *results = search->result; + _mdns_search_free(search); + + return ESP_OK; +} + +esp_err_t mdns_query(const char *name, const char *service_type, const char *proto, uint16_t type, uint32_t timeout, size_t max_results, mdns_result_t **results) +{ + return mdns_query_generic(name, service_type, proto, type, type != MDNS_TYPE_PTR, timeout, max_results, results); +} + +esp_err_t mdns_query_ptr(const char *service, const char *proto, uint32_t timeout, size_t max_results, mdns_result_t **results) +{ + if (_str_null_or_empty(service) || _str_null_or_empty(proto)) { + return ESP_ERR_INVALID_ARG; + } + + return mdns_query(NULL, service, proto, MDNS_TYPE_PTR, timeout, max_results, results); +} + +esp_err_t mdns_query_srv(const char *instance, const char *service, const char *proto, uint32_t timeout, mdns_result_t **result) +{ + if (_str_null_or_empty(instance) || _str_null_or_empty(service) || _str_null_or_empty(proto)) { + return ESP_ERR_INVALID_ARG; + } + + return mdns_query(instance, service, proto, MDNS_TYPE_SRV, timeout, 1, result); +} + +esp_err_t mdns_query_txt(const char *instance, const char *service, const char *proto, uint32_t timeout, mdns_result_t **result) +{ + if (_str_null_or_empty(instance) || _str_null_or_empty(service) || _str_null_or_empty(proto)) { + return ESP_ERR_INVALID_ARG; + } + + return mdns_query(instance, service, proto, MDNS_TYPE_TXT, timeout, 1, result); +} + +esp_err_t mdns_lookup_delegated_service(const char *instance, const char *service, const char *proto, size_t max_results, + mdns_result_t **result) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + if (!result || _str_null_or_empty(service) || _str_null_or_empty(proto)) { + return ESP_ERR_INVALID_ARG; + } + MDNS_SERVICE_LOCK(); + *result = _mdns_lookup_service(instance, service, proto, max_results, false); + MDNS_SERVICE_UNLOCK(); + return ESP_OK; +} + +esp_err_t mdns_lookup_selfhosted_service(const char *instance, const char *service, const char *proto, size_t max_results, + mdns_result_t **result) +{ + if (!_mdns_server) { + return ESP_ERR_INVALID_STATE; + } + if (!result || _str_null_or_empty(service) || _str_null_or_empty(proto)) { + return ESP_ERR_INVALID_ARG; + } + MDNS_SERVICE_LOCK(); + *result = _mdns_lookup_service(instance, service, proto, max_results, true); + MDNS_SERVICE_UNLOCK(); + return ESP_OK; +} + +#ifdef CONFIG_LWIP_IPV4 +esp_err_t mdns_query_a(const char *name, uint32_t timeout, esp_ip4_addr_t *addr) +{ + mdns_result_t *result = NULL; + esp_err_t err; + + if (_str_null_or_empty(name)) { + return ESP_ERR_INVALID_ARG; + } + + if (strstr(name, ".local")) { + ESP_LOGW(TAG, "Please note that hostname must not contain domain name, as mDNS uses '.local' domain"); + } + + err = mdns_query(name, NULL, NULL, MDNS_TYPE_A, timeout, 1, &result); + + if (err) { + return err; + } + + if (!result) { + return ESP_ERR_NOT_FOUND; + } + + mdns_ip_addr_t *a = result->addr; + while (a) { + if (a->addr.type == ESP_IPADDR_TYPE_V4) { + addr->addr = a->addr.u_addr.ip4.addr; + mdns_query_results_free(result); + return ESP_OK; + } + a = a->next; + } + + mdns_query_results_free(result); + return ESP_ERR_NOT_FOUND; +} +#endif /* CONFIG_LWIP_IPV4 */ + +#ifdef CONFIG_LWIP_IPV6 +esp_err_t mdns_query_aaaa(const char *name, uint32_t timeout, esp_ip6_addr_t *addr) +{ + mdns_result_t *result = NULL; + esp_err_t err; + + if (_str_null_or_empty(name)) { + return ESP_ERR_INVALID_ARG; + } + + if (strstr(name, ".local")) { + ESP_LOGW(TAG, "Please note that hostname must not contain domain name, as mDNS uses '.local' domain"); + } + + err = mdns_query(name, NULL, NULL, MDNS_TYPE_AAAA, timeout, 1, &result); + + if (err) { + return err; + } + + if (!result) { + return ESP_ERR_NOT_FOUND; + } + + mdns_ip_addr_t *a = result->addr; + while (a) { + if (a->addr.type == ESP_IPADDR_TYPE_V6) { + memcpy(addr->addr, a->addr.u_addr.ip6.addr, 16); + mdns_query_results_free(result); + return ESP_OK; + } + a = a->next; + } + + mdns_query_results_free(result); + return ESP_ERR_NOT_FOUND; +} +#endif /* CONFIG_LWIP_IPV6 */ + +#ifdef MDNS_ENABLE_DEBUG + +void mdns_debug_packet(const uint8_t *data, size_t len) +{ + static mdns_name_t n; + mdns_header_t header; + const uint8_t *content = data + MDNS_HEAD_LEN; + uint32_t t = xTaskGetTickCount() * portTICK_PERIOD_MS; + mdns_name_t *name = &n; + memset(name, 0, sizeof(mdns_name_t)); + + _mdns_dbg_printf("Packet[%" PRIu32 "]: ", t); + + header.id = _mdns_read_u16(data, MDNS_HEAD_ID_OFFSET); + header.flags = _mdns_read_u16(data, MDNS_HEAD_FLAGS_OFFSET); + header.questions = _mdns_read_u16(data, MDNS_HEAD_QUESTIONS_OFFSET); + header.answers = _mdns_read_u16(data, MDNS_HEAD_ANSWERS_OFFSET); + header.servers = _mdns_read_u16(data, MDNS_HEAD_SERVERS_OFFSET); + header.additional = _mdns_read_u16(data, MDNS_HEAD_ADDITIONAL_OFFSET); + + _mdns_dbg_printf("%s", + (header.flags == MDNS_FLAGS_QR_AUTHORITATIVE) ? "AUTHORITATIVE\n" : + (header.flags == MDNS_FLAGS_DISTRIBUTED) ? "DISTRIBUTED\n" : + (header.flags == 0) ? "\n" : " " + ); + if (header.flags && header.flags != MDNS_FLAGS_QR_AUTHORITATIVE) { + _mdns_dbg_printf("0x%04X\n", header.flags); + } + + if (header.questions) { + uint8_t qs = header.questions; + + while (qs--) { + content = _mdns_parse_fqdn(data, content, name, len); + if (!content || content + MDNS_CLASS_OFFSET + 1 >= data + len) { + header.answers = 0; + header.additional = 0; + header.servers = 0; + _mdns_dbg_printf("ERROR: parse header questions\n"); + break; + } + + uint16_t type = _mdns_read_u16(content, MDNS_TYPE_OFFSET); + uint16_t mdns_class = _mdns_read_u16(content, MDNS_CLASS_OFFSET); + bool unicast = !!(mdns_class & 0x8000); + mdns_class &= 0x7FFF; + content = content + 4; + + _mdns_dbg_printf(" Q: "); + if (unicast) { + _mdns_dbg_printf("*U* "); + } + if (type == MDNS_TYPE_PTR) { + _mdns_dbg_printf("%s.%s%s.%s.%s. PTR ", name->host, name->sub ? "_sub." : "", name->service, name->proto, name->domain); + } else if (type == MDNS_TYPE_SRV) { + _mdns_dbg_printf("%s.%s%s.%s.%s. SRV ", name->host, name->sub ? "_sub." : "", name->service, name->proto, name->domain); + } else if (type == MDNS_TYPE_TXT) { + _mdns_dbg_printf("%s.%s%s.%s.%s. TXT ", name->host, name->sub ? "_sub." : "", name->service, name->proto, name->domain); + } else if (type == MDNS_TYPE_A) { + _mdns_dbg_printf("%s.%s. A ", name->host, name->domain); + } else if (type == MDNS_TYPE_AAAA) { + _mdns_dbg_printf("%s.%s. AAAA ", name->host, name->domain); + } else if (type == MDNS_TYPE_NSEC) { + _mdns_dbg_printf("%s.%s%s.%s.%s. NSEC ", name->host, name->sub ? "_sub." : "", name->service, name->proto, name->domain); + } else if (type == MDNS_TYPE_ANY) { + _mdns_dbg_printf("%s.%s%s.%s.%s. ANY ", name->host, name->sub ? "_sub." : "", name->service, name->proto, name->domain); + } else { + _mdns_dbg_printf("%s.%s%s.%s.%s. %04X ", name->host, name->sub ? "_sub." : "", name->service, name->proto, name->domain, type); + } + + if (mdns_class == 0x0001) { + _mdns_dbg_printf("IN"); + } else { + _mdns_dbg_printf("%04X", mdns_class); + } + _mdns_dbg_printf("\n"); + } + } + + if (header.answers || header.servers || header.additional) { + uint16_t recordIndex = 0; + + while (content < (data + len)) { + + content = _mdns_parse_fqdn(data, content, name, len); + if (!content) { + _mdns_dbg_printf("ERROR: parse mdns records\n"); + break; + } + + uint16_t type = _mdns_read_u16(content, MDNS_TYPE_OFFSET); + uint16_t mdns_class = _mdns_read_u16(content, MDNS_CLASS_OFFSET); + uint32_t ttl = _mdns_read_u32(content, MDNS_TTL_OFFSET); + uint16_t data_len = _mdns_read_u16(content, MDNS_LEN_OFFSET); + const uint8_t *data_ptr = content + MDNS_DATA_OFFSET; + bool flush = !!(mdns_class & 0x8000); + mdns_class &= 0x7FFF; + + content = data_ptr + data_len; + if (content > (data + len)) { + _mdns_dbg_printf("ERROR: content length overflow\n"); + break; + } + + mdns_parsed_record_type_t record_type = MDNS_ANSWER; + + if (recordIndex >= (header.answers + header.servers)) { + record_type = MDNS_EXTRA; + } else if (recordIndex >= (header.answers)) { + record_type = MDNS_NS; + } + recordIndex++; + + if (record_type == MDNS_EXTRA) { + _mdns_dbg_printf(" X"); + } else if (record_type == MDNS_NS) { + _mdns_dbg_printf(" S"); + } else { + _mdns_dbg_printf(" A"); + } + + if (type == MDNS_TYPE_PTR) { + _mdns_dbg_printf(": %s%s%s.%s.%s. PTR ", name->host, name->host[0] ? "." : "", name->service, name->proto, name->domain); + } else if (type == MDNS_TYPE_SRV) { + _mdns_dbg_printf(": %s.%s.%s.%s. SRV ", name->host, name->service, name->proto, name->domain); + } else if (type == MDNS_TYPE_TXT) { + _mdns_dbg_printf(": %s.%s.%s.%s. TXT ", name->host, name->service, name->proto, name->domain); + } else if (type == MDNS_TYPE_A) { + _mdns_dbg_printf(": %s.%s. A ", name->host, name->domain); + } else if (type == MDNS_TYPE_AAAA) { + _mdns_dbg_printf(": %s.%s. AAAA ", name->host, name->domain); + } else if (type == MDNS_TYPE_NSEC) { + _mdns_dbg_printf(": %s.%s.%s.%s. NSEC ", name->host, name->service, name->proto, name->domain); + } else if (type == MDNS_TYPE_ANY) { + _mdns_dbg_printf(": %s.%s.%s.%s. ANY ", name->host, name->service, name->proto, name->domain); + } else if (type == MDNS_TYPE_OPT) { + _mdns_dbg_printf(": . OPT "); + } else { + _mdns_dbg_printf(": %s.%s.%s.%s. %04X ", name->host, name->service, name->proto, name->domain, type); + } + + if (mdns_class == 0x0001) { + _mdns_dbg_printf("IN "); + } else { + _mdns_dbg_printf("%04X ", mdns_class); + } + if (flush) { + _mdns_dbg_printf("FLUSH "); + } + _mdns_dbg_printf("%" PRIu32, ttl); + _mdns_dbg_printf("[%u] ", data_len); + if (type == MDNS_TYPE_PTR) { + if (!_mdns_parse_fqdn(data, data_ptr, name, len)) { + _mdns_dbg_printf("ERROR: parse PTR\n"); + continue; + } + _mdns_dbg_printf("%s.%s.%s.%s.\n", name->host, name->service, name->proto, name->domain); + } else if (type == MDNS_TYPE_SRV) { + if (!_mdns_parse_fqdn(data, data_ptr + MDNS_SRV_FQDN_OFFSET, name, len)) { + _mdns_dbg_printf("ERROR: parse SRV\n"); + continue; + } + uint16_t priority = _mdns_read_u16(data_ptr, MDNS_SRV_PRIORITY_OFFSET); + uint16_t weight = _mdns_read_u16(data_ptr, MDNS_SRV_WEIGHT_OFFSET); + uint16_t port = _mdns_read_u16(data_ptr, MDNS_SRV_PORT_OFFSET); + _mdns_dbg_printf("%u %u %u %s.%s.\n", priority, weight, port, name->host, name->domain); + } else if (type == MDNS_TYPE_TXT) { + uint16_t i = 0, y; + while (i < data_len) { + uint8_t partLen = data_ptr[i++]; + if ((i + partLen) > data_len) { + _mdns_dbg_printf("ERROR: parse TXT\n"); + break; + } + char txt[partLen + 1]; + for (y = 0; y < partLen; y++) { + char d = data_ptr[i++]; + txt[y] = d; + } + txt[partLen] = 0; + _mdns_dbg_printf("%s", txt); + if (i < data_len) { + _mdns_dbg_printf("; "); + } + } + _mdns_dbg_printf("\n"); + } else if (type == MDNS_TYPE_AAAA) { + esp_ip6_addr_t ip6; + memcpy(&ip6, data_ptr, sizeof(esp_ip6_addr_t)); + _mdns_dbg_printf(IPV6STR "\n", IPV62STR(ip6)); + } else if (type == MDNS_TYPE_A) { + esp_ip4_addr_t ip; + memcpy(&ip, data_ptr, sizeof(esp_ip4_addr_t)); + _mdns_dbg_printf(IPSTR "\n", IP2STR(&ip)); + } else if (type == MDNS_TYPE_NSEC) { + const uint8_t *old_ptr = data_ptr; + const uint8_t *new_ptr = _mdns_parse_fqdn(data, data_ptr, name, len); + if (new_ptr) { + _mdns_dbg_printf("%s.%s.%s.%s. ", name->host, name->service, name->proto, name->domain); + size_t diff = new_ptr - old_ptr; + data_len -= diff; + data_ptr = new_ptr; + } + size_t i; + for (i = 0; i < data_len; i++) { + _mdns_dbg_printf(" %02x", data_ptr[i]); + } + _mdns_dbg_printf("\n"); + } else if (type == MDNS_TYPE_OPT) { + uint16_t opCode = _mdns_read_u16(data_ptr, 0); + uint16_t opLen = _mdns_read_u16(data_ptr, 2); + _mdns_dbg_printf(" Code: %04x Data[%u]:", opCode, opLen); + size_t i; + for (i = 4; i < data_len; i++) { + _mdns_dbg_printf(" %02x", data_ptr[i]); + } + _mdns_dbg_printf("\n"); + } else { + size_t i; + for (i = 0; i < data_len; i++) { + _mdns_dbg_printf(" %02x", data_ptr[i]); + } + _mdns_dbg_printf("\n"); + } + } + } +} +#endif /* MDNS_ENABLE_DEBUG */ + +/** + * @brief Browse sync result action + */ +static esp_err_t _mdns_sync_browse_action(mdns_action_type_t type, mdns_browse_sync_t *browse_sync) +{ + mdns_action_t *action = NULL; + + action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + if (!action) { + HOOK_MALLOC_FAILED; + return ESP_ERR_NO_MEM; + } + + action->type = type; + action->data.browse_sync.browse_sync = browse_sync; + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(action); + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} + +/** + * @brief Browse action + */ +static esp_err_t _mdns_send_browse_action(mdns_action_type_t type, mdns_browse_t *browse) +{ + mdns_action_t *action = NULL; + + action = (mdns_action_t *)malloc(sizeof(mdns_action_t)); + + if (!action) { + HOOK_MALLOC_FAILED; + return ESP_ERR_NO_MEM; + } + + action->type = type; + action->data.browse_add.browse = browse; + if (xQueueSend(_mdns_server->action_queue, &action, (TickType_t)0) != pdPASS) { + free(action); + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} + +/** + * @brief Free a browse item (Not free the list). + */ +static void _mdns_browse_item_free(mdns_browse_t *browse) +{ + free(browse->service); + free(browse->proto); + if (browse->result) { + _mdns_query_results_free(browse->result); + } + free(browse); +} + +/** + * @brief Allocate new browse structure + */ +static mdns_browse_t *_mdns_browse_init(const char *service, const char *proto, mdns_browse_notify_t notifier) +{ + mdns_browse_t *browse = (mdns_browse_t *)malloc(sizeof(mdns_browse_t)); + + if (!browse) { + HOOK_MALLOC_FAILED; + return NULL; + } + memset(browse, 0, sizeof(mdns_browse_t)); + + browse->state = BROWSE_INIT; + if (!_str_null_or_empty(service)) { + browse->service = strndup(service, MDNS_NAME_BUF_LEN - 1); + if (!browse->service) { + _mdns_browse_item_free(browse); + return NULL; + } + } + + if (!_str_null_or_empty(proto)) { + browse->proto = strndup(proto, MDNS_NAME_BUF_LEN - 1); + if (!browse->proto) { + _mdns_browse_item_free(browse); + return NULL; + } + } + + browse->notifier = notifier; + return browse; +} + +mdns_browse_t *mdns_browse_new(const char *service, const char *proto, mdns_browse_notify_t notifier) +{ + mdns_browse_t *browse = NULL; + + if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto)) { + return NULL; + } + + browse = _mdns_browse_init(service, proto, notifier); + if (!browse) { + return NULL; + } + + if (_mdns_send_browse_action(ACTION_BROWSE_ADD, browse)) { + _mdns_browse_item_free(browse); + return NULL; + } + + return browse; +} + +esp_err_t mdns_browse_delete(const char *service, const char *proto) +{ + mdns_browse_t *browse = NULL; + + if (!_mdns_server || _str_null_or_empty(service) || _str_null_or_empty(proto)) { + return ESP_FAIL; + } + + browse = _mdns_browse_init(service, proto, NULL); + if (!browse) { + return ESP_ERR_NO_MEM; + } + + if (_mdns_send_browse_action(ACTION_BROWSE_END, browse)) { + _mdns_browse_item_free(browse); + return ESP_ERR_NO_MEM; + } + return ESP_OK; +} + +/** + * @brief Mark browse as finished, remove and free it from browse chain + */ +static void _mdns_browse_finish(mdns_browse_t *browse) +{ + browse->state = BROWSE_OFF; + mdns_browse_t *b = _mdns_server->browse; + mdns_browse_t *target_free = NULL; + while (b) { + if (strlen(b->service) == strlen(browse->service) && memcmp(b->service, browse->service, strlen(b->service)) == 0 && + strlen(b->proto) == strlen(browse->proto) && memcmp(b->proto, browse->proto, strlen(b->proto)) == 0) { + target_free = b; + b = b->next; + queueDetach(mdns_browse_t, _mdns_server->browse, target_free); + _mdns_browse_item_free(target_free); + } else { + b = b->next; + } + } + _mdns_browse_item_free(browse); +} + +/** + * @brief Add new browse to the browse chain + */ +static void _mdns_browse_add(mdns_browse_t *browse) +{ + browse->state = BROWSE_RUNNING; + mdns_browse_t *queue = _mdns_server->browse; + bool found = false; + // looking for this browse in active browses + while (queue) { + if (strlen(queue->service) == strlen(browse->service) && memcmp(queue->service, browse->service, strlen(queue->service)) == 0 && + strlen(queue->proto) == strlen(browse->proto) && memcmp(queue->proto, browse->proto, strlen(queue->proto)) == 0) { + found = true; + break; + } + queue = queue->next; + } + if (!found) { + browse->next = _mdns_server->browse; + _mdns_server->browse = browse; + } + for (uint8_t interface_idx = 0; interface_idx < MDNS_MAX_INTERFACES; interface_idx++) { + _mdns_browse_send(browse, (mdns_if_t)interface_idx); + } + if (found) { + _mdns_browse_item_free(browse); + } +} + +/** + * @brief Send PTR query packet to all available interfaces for browsing. + */ +static void _mdns_browse_send(mdns_browse_t *browse, mdns_if_t interface) +{ + // Using search once for sending the PTR query + mdns_search_once_t search = {0}; + + search.instance = NULL; + search.service = browse->service; + search.proto = browse->proto; + search.type = MDNS_TYPE_PTR; + search.unicast = false; + search.result = NULL; + search.next = NULL; + + for (uint8_t protocol_idx = 0; protocol_idx < MDNS_IP_PROTOCOL_MAX; protocol_idx++) { + _mdns_search_send_pcb(&search, interface, (mdns_ip_protocol_t)protocol_idx); + } +} + +/** + * @brief Add result to browse, only add when the result is a new one. + */ +static esp_err_t _mdns_add_browse_result(mdns_browse_sync_t *sync_browse, mdns_result_t *r) +{ + mdns_browse_result_sync_t *sync_r = sync_browse->sync_result; + while (sync_r) { + if (sync_r->result == r) { + break; + } + sync_r = sync_r->next; + } + if (!sync_r) { + // Do not find, need to add the result to the list + mdns_browse_result_sync_t *new = (mdns_browse_result_sync_t *)malloc(sizeof(mdns_browse_result_sync_t)); + + if (!new) { + HOOK_MALLOC_FAILED; + return ESP_ERR_NO_MEM; + } + new->result = r; + new->next = sync_browse->sync_result; + sync_browse->sync_result = new; + } + return ESP_OK; +} + +/** + * @brief Called from parser to add A/AAAA data to search result + */ +static void _mdns_browse_result_add_ip(mdns_browse_t *browse, const char *hostname, esp_ip_addr_t *ip, + mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint32_t ttl, mdns_browse_sync_t *out_sync_browse) +{ + if (out_sync_browse->browse == NULL) { + return; + } else { + if (out_sync_browse->browse != browse) { + return; + } + } + mdns_result_t *r = NULL; + mdns_ip_addr_t *r_a = NULL; + if (browse) { + r = browse->result; + while (r) { + if (r->ip_protocol == ip_protocol) { + // Find the target result in browse result. + if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && !_str_null_or_empty(r->hostname) && !strcasecmp(hostname, r->hostname)) { + r_a = r->addr; + // Check if the address has already added in result. + while (r_a) { +#ifdef CONFIG_LWIP_IPV4 + if (r_a->addr.type == ip->type && r_a->addr.type == ESP_IPADDR_TYPE_V4 && r_a->addr.u_addr.ip4.addr == ip->u_addr.ip4.addr) { + break; + } +#endif +#ifdef CONFIG_LWIP_IPV6 + if (r_a->addr.type == ip->type && r_a->addr.type == ESP_IPADDR_TYPE_V6 && !memcmp(r_a->addr.u_addr.ip6.addr, ip->u_addr.ip6.addr, 16)) { + break; + } +#endif + r_a = r_a->next; + } + if (!r_a) { + // The current IP is a new one, add it to the link list. + mdns_ip_addr_t *a = NULL; + a = _mdns_result_addr_create_ip(ip); + if (!a) { + return; + } + a->next = r->addr; + r->addr = a; + if (r->ttl != ttl) { + if (r->ttl == 0) { + r->ttl = ttl; + } else { + _mdns_result_update_ttl(r, ttl); + } + } + if (_mdns_add_browse_result(out_sync_browse, r) != ESP_OK) { + return; + } + break; + } + } + } + r = r->next; + } + } + return; +} + +/** + * @brief Called from packet parser to find matching running search + */ +static mdns_browse_t *_mdns_browse_find_from(mdns_browse_t *b, mdns_name_t *name, uint16_t type, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + // For browse, we only care about the SRV, TXT, A and AAAA + if (type != MDNS_TYPE_SRV && type != MDNS_TYPE_A && type != MDNS_TYPE_AAAA && type != MDNS_TYPE_TXT) { + return NULL; + } + mdns_result_t *r = NULL; + while (b) { + if (type == MDNS_TYPE_SRV || type == MDNS_TYPE_TXT) { + if (strcasecmp(name->service, b->service) + || strcasecmp(name->proto, b->proto)) { + b = b->next; + continue; + } + return b; + } else if (type == MDNS_TYPE_A || type == MDNS_TYPE_AAAA) { + r = b->result; + while (r) { + if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && !_str_null_or_empty(r->hostname) && !strcasecmp(name->host, r->hostname)) { + return b; + } + r = r->next; + } + b = b->next; + continue; + } + } + return b; +} + +static bool is_txt_item_in_list(mdns_txt_item_t txt, uint8_t txt_value_len, mdns_txt_item_t *txt_list, uint8_t *txt_value_len_list, size_t txt_count) +{ + for (size_t i = 0; i < txt_count; i++) { + if (strcmp(txt.key, txt_list[i].key) == 0) { + if (txt_value_len == txt_value_len_list[i] && memcmp(txt.value, txt_list[i].value, txt_value_len) == 0) { + return true; + } else { + // The key value is unique, so there is no need to continue searching. + return false; + } + } + } + return false; +} + +/** + * @brief Called from parser to add TXT data to search result + */ +static void _mdns_browse_result_add_txt(mdns_browse_t *browse, const char *instance, const char *service, const char *proto, + mdns_txt_item_t *txt, uint8_t *txt_value_len, size_t txt_count, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, + uint32_t ttl, mdns_browse_sync_t *out_sync_browse) +{ + if (out_sync_browse->browse == NULL) { + return; + } else { + if (out_sync_browse->browse != browse) { + return; + } + } + mdns_result_t *r = browse->result; + while (r) { + if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && + !_str_null_or_empty(r->instance_name) && !strcasecmp(instance, r->instance_name) && + !_str_null_or_empty(r->service_type) && !strcasecmp(service, r->service_type) && + !_str_null_or_empty(r->proto) && !strcasecmp(proto, r->proto)) { + bool should_update = false; + if (r->txt) { + // Check if txt changed + if (txt_count != r->txt_count) { + should_update = true; + } else { + for (size_t txt_index = 0; txt_index < txt_count; txt_index++) { + if (!is_txt_item_in_list(txt[txt_index], txt_value_len[txt_index], r->txt, r->txt_value_len, r->txt_count)) { + should_update = true; + break; + } + } + } + // If the result has a previous txt entry, we delete it and re-add. + for (size_t i = 0; i < r->txt_count; i++) { + free((char *)(r->txt[i].key)); + free((char *)(r->txt[i].value)); + } + free(r->txt); + free(r->txt_value_len); + } + r->txt = txt; + r->txt_value_len = txt_value_len; + r->txt_count = txt_count; + if (r->ttl != ttl) { + uint32_t previous_ttl = r->ttl; + if (r->ttl == 0) { + r->ttl = ttl; + } else { + _mdns_result_update_ttl(r, ttl); + } + if (previous_ttl != r->ttl) { + should_update = true; + } + } + if (should_update) { + if (_mdns_add_browse_result(out_sync_browse, r) != ESP_OK) { + return; + } + } + return; + } + r = r->next; + } + r = (mdns_result_t *)malloc(sizeof(mdns_result_t)); + if (!r) { + HOOK_MALLOC_FAILED; + goto free_txt; + } + memset(r, 0, sizeof(mdns_result_t)); + r->instance_name = strdup(instance); + r->service_type = strdup(service); + r->proto = strdup(proto); + if (!r->instance_name || !r->service_type || !r->proto) { + free(r->instance_name); + free(r->service_type); + free(r->proto); + free(r); + return; + } + r->txt = txt; + r->txt_value_len = txt_value_len; + r->txt_count = txt_count; + r->esp_netif = _mdns_get_esp_netif(tcpip_if); + r->ip_protocol = ip_protocol; + r->ttl = ttl; + r->next = browse->result; + browse->result = r; + _mdns_add_browse_result(out_sync_browse, r); + return; + +free_txt: + for (size_t i = 0; i < txt_count; i++) { + free((char *)(txt[i].key)); + free((char *)(txt[i].value)); + } + free(txt); + free(txt_value_len); + return; +} + +static esp_err_t _mdns_copy_address_in_previous_result(mdns_result_t *result_list, mdns_result_t *r) +{ + while (result_list) { + if (!_str_null_or_empty(result_list->hostname) && !_str_null_or_empty(r->hostname) && !strcasecmp(result_list->hostname, r->hostname) && + result_list->ip_protocol == r->ip_protocol && result_list->addr && !r->addr) { + // If there is a same hostname in previous result, we need to copy the address here. + r->addr = copy_address_list(result_list->addr); + if (!r->addr) { + return ESP_ERR_NO_MEM; + } + break; + } else { + result_list = result_list->next; + } + } + return ESP_OK; +} + +/** + * @brief Called from parser to add SRV data to search result + */ +static void _mdns_browse_result_add_srv(mdns_browse_t *browse, const char *hostname, const char *instance, const char *service, const char *proto, + uint16_t port, mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, uint32_t ttl, mdns_browse_sync_t *out_sync_browse) +{ + if (out_sync_browse->browse == NULL) { + return; + } else { + if (out_sync_browse->browse != browse) { + return; + } + } + mdns_result_t *r = browse->result; + while (r) { + if (r->esp_netif == _mdns_get_esp_netif(tcpip_if) && r->ip_protocol == ip_protocol && + !_str_null_or_empty(r->instance_name) && !strcasecmp(instance, r->instance_name) && + !_str_null_or_empty(r->service_type) && !strcasecmp(service, r->service_type) && + !_str_null_or_empty(r->proto) && !strcasecmp(proto, r->proto)) { + if (_str_null_or_empty(r->hostname) || strcasecmp(hostname, r->hostname)) { + r->hostname = strdup(hostname); + r->port = port; + if (!r->hostname) { + HOOK_MALLOC_FAILED; + return; + } + if (!r->addr) { + esp_err_t err = _mdns_copy_address_in_previous_result(browse->result, r); + if (err == ESP_ERR_NO_MEM) { + return; + } + } + if (_mdns_add_browse_result(out_sync_browse, r) != ESP_OK) { + return; + } + } + if (r->ttl != ttl) { + uint32_t previous_ttl = r->ttl; + if (r->ttl == 0) { + r->ttl = ttl; + } else { + _mdns_result_update_ttl(r, ttl); + } + if (previous_ttl != r->ttl) { + if (_mdns_add_browse_result(out_sync_browse, r) != ESP_OK) { + return; + } + } + } + return; + } + r = r->next; + } + r = (mdns_result_t *)malloc(sizeof(mdns_result_t)); + if (!r) { + HOOK_MALLOC_FAILED; + return; + } + + memset(r, 0, sizeof(mdns_result_t)); + r->hostname = strdup(hostname); + r->instance_name = strdup(instance); + r->service_type = strdup(service); + r->proto = strdup(proto); + if (!r->hostname || !r->instance_name || !r->service_type || !r->proto) { + HOOK_MALLOC_FAILED; + free(r->hostname); + free(r->instance_name); + free(r->service_type); + free(r->proto); + free(r); + return; + } + r->port = port; + r->esp_netif = _mdns_get_esp_netif(tcpip_if); + r->ip_protocol = ip_protocol; + r->ttl = ttl; + r->next = browse->result; + browse->result = r; + _mdns_add_browse_result(out_sync_browse, r); + return; +} + +static void _mdns_browse_sync(mdns_browse_sync_t *browse_sync) +{ + mdns_browse_t *browse = browse_sync->browse; + mdns_browse_result_sync_t *sync_result = browse_sync->sync_result; + while (sync_result) { + mdns_result_t *result = sync_result->result; +#ifdef MDNS_ENABLE_DEBUG + debug_printf_browse_result(result, browse_sync->browse); +#endif + browse->notifier(result); + if (result->ttl == 0) { + queueDetach(mdns_result_t, browse->result, result); + // Just free current result + result->next = NULL; + mdns_query_results_free(result); + } + sync_result = sync_result->next; + } +} + +#ifdef MDNS_ENABLE_DEBUG +void _debug_printf_result(mdns_result_t *r_t) +{ + mdns_ip_addr_t *r_a = NULL; + int addr_count = 0; + _mdns_dbg_printf("result esp_netif: %p\n", r_t->esp_netif); + _mdns_dbg_printf("result ip_protocol: %d\n", r_t->ip_protocol); + _mdns_dbg_printf("result hostname: %s\n", _str_null_or_empty(r_t->hostname) ? "NULL" : r_t->hostname); + _mdns_dbg_printf("result instance_name: %s\n", _str_null_or_empty(r_t->instance_name) ? "NULL" : r_t->instance_name); + _mdns_dbg_printf("result service_type: %s\n", _str_null_or_empty(r_t->service_type) ? "NULL" : r_t->service_type); + _mdns_dbg_printf("result proto: %s\n", _str_null_or_empty(r_t->proto) ? "NULL" : r_t->proto); + _mdns_dbg_printf("result port: %d\n", r_t->port); + _mdns_dbg_printf("result ttl: %" PRIu32 "\n", r_t->ttl); + for (int i = 0; i < r_t->txt_count; i++) { + _mdns_dbg_printf("result txt item%d, key: %s, value: %s\n", i, r_t->txt[i].key, r_t->txt[i].value); + } + r_a = r_t->addr; + while (r_a) { +#ifdef CONFIG_LWIP_IPV4 + if (r_a->addr.type == ESP_IPADDR_TYPE_V4) { + _mdns_dbg_printf("Addr%d: " IPSTR "\n", addr_count++, IP2STR(&r_a->addr.u_addr.ip4)); + } +#endif +#ifdef CONFIG_LWIP_IPV6 + if (r_a->addr.type == ESP_IPADDR_TYPE_V6) { + _mdns_dbg_printf("Addr%d: " IPV6STR "\n", addr_count++, IPV62STR(r_a->addr.u_addr.ip6)); + } +#endif + r_a = r_a->next; + } +} + +static void debug_printf_browse_result(mdns_result_t *r_t, mdns_browse_t *b_t) +{ + _mdns_dbg_printf("----------------sync browse %s.%s result---------------\n", b_t->service, b_t->proto); + _mdns_dbg_printf("browse pointer: %p\n", b_t); + _debug_printf_result(r_t); +} + +static void debug_printf_browse_result_all(mdns_result_t *r_t) +{ + int count = 0; + while (r_t) { + _mdns_dbg_printf("----------------result %d---------------\n", count++); + _debug_printf_result(r_t); + r_t = r_t->next; + } +} +#endif // MDNS_ENABLE_DEBUG diff --git a/managed_components/espressif__mdns/mdns_console.c b/managed_components/espressif__mdns/mdns_console.c new file mode 100644 index 0000000..80f009a --- /dev/null +++ b/managed_components/espressif__mdns/mdns_console.c @@ -0,0 +1,1451 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "esp_console.h" +#include "argtable3/argtable3.h" +#include "mdns.h" +#include "mdns_private.h" +#include "inttypes.h" + +static const char *ip_protocol_str[] = {"V4", "V6", "MAX"}; + +static void mdns_print_results(mdns_result_t *results) +{ + mdns_result_t *r = results; + mdns_ip_addr_t *a = NULL; + int i = 1; + while (r) { + if (r->esp_netif) { + printf("%d: Interface: %s, Type: %s, TTL: %" PRIu32 "\n", i++, esp_netif_get_ifkey(r->esp_netif), + ip_protocol_str[r->ip_protocol], r->ttl); + } + if (r->instance_name) { + printf(" PTR : %s\n", r->instance_name); + } + if (r->hostname) { + printf(" SRV : %s.local:%u\n", r->hostname, r->port); + } + if (r->txt_count) { + printf(" TXT : [%u] ", (int)r->txt_count); + for (size_t t = 0; t < r->txt_count; t++) { + printf("%s=%s; ", r->txt[t].key, r->txt[t].value); + } + printf("\n"); + } + a = r->addr; + while (a) { + if (a->addr.type == ESP_IPADDR_TYPE_V6) { + printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); + } else { + printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); + } + a = a->next; + } + r = r->next; + } +} + +static struct { + struct arg_str *hostname; + struct arg_int *timeout; + struct arg_end *end; +} mdns_query_a_args; + +#ifdef CONFIG_LWIP_IPV4 +static int cmd_mdns_query_a(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_query_a_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_query_a_args.end, argv[0]); + return 1; + } + + const char *hostname = mdns_query_a_args.hostname->sval[0]; + int timeout = mdns_query_a_args.timeout->ival[0]; + + if (!hostname || !hostname[0]) { + printf("ERROR: Hostname not supplied\n"); + return 1; + } + + if (timeout <= 0) { + timeout = 1000; + } + + printf("Query A: %s.local, Timeout: %d\n", hostname, timeout); + + struct esp_ip4_addr addr; + addr.addr = 0; + + esp_err_t err = mdns_query_a(hostname, timeout, &addr); + if (err) { + if (err == ESP_ERR_NOT_FOUND) { + printf("ERROR: Host was not found!\n"); + return 0; + } + printf("ERROR: Query Failed\n"); + return 1; + } + + printf(IPSTR "\n", IP2STR(&addr)); + + return 0; +} + +static void register_mdns_query_a(void) +{ + mdns_query_a_args.hostname = arg_str1(NULL, NULL, "", "Hostname that is searched for"); + mdns_query_a_args.timeout = arg_int0("t", "timeout", "", "Timeout for this query"); + mdns_query_a_args.end = arg_end(2); + + const esp_console_cmd_t cmd_init = { + .command = "mdns_query_a", + .help = "Query MDNS for IPv4", + .hint = NULL, + .func = &cmd_mdns_query_a, + .argtable = &mdns_query_a_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) ); +} +#endif /* CONFIG_LWIP_IPV4 */ + +#ifdef CONFIG_LWIP_IPV6 +static int cmd_mdns_query_aaaa(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_query_a_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_query_a_args.end, argv[0]); + return 1; + } + + const char *hostname = mdns_query_a_args.hostname->sval[0]; + int timeout = mdns_query_a_args.timeout->ival[0]; + + if (!hostname || !hostname[0]) { + printf("ERROR: Hostname not supplied\n"); + return 1; + } + + if (timeout <= 0) { + timeout = 1000; + } + + printf("Query AAAA: %s.local, Timeout: %d\n", hostname, timeout); + + struct esp_ip6_addr addr; + memset(addr.addr, 0, 16); + + esp_err_t err = mdns_query_aaaa(hostname, timeout, &addr); + if (err) { + if (err == ESP_ERR_NOT_FOUND) { + printf("Host was not found!\n"); + return 0; + } + printf("ERROR: Query Failed\n"); + return 1; + } + + printf(IPV6STR "\n", IPV62STR(addr)); + + return 0; +} + +static void register_mdns_query_aaaa(void) +{ + mdns_query_a_args.hostname = arg_str1(NULL, NULL, "", "Hostname that is searched for"); + mdns_query_a_args.timeout = arg_int0("t", "timeout", "", "Timeout for this query"); + mdns_query_a_args.end = arg_end(2); + + const esp_console_cmd_t cmd_init = { + .command = "mdns_query_aaaa", + .help = "Query MDNS for IPv6", + .hint = NULL, + .func = &cmd_mdns_query_aaaa, + .argtable = &mdns_query_a_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) ); +} +#endif /* CONFIG_LWIP_IPV6 */ + +static struct { + struct arg_str *instance; + struct arg_str *service; + struct arg_str *proto; + struct arg_int *timeout; + struct arg_end *end; +} mdns_query_srv_args; + +static int cmd_mdns_query_srv(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_query_srv_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_query_srv_args.end, argv[0]); + return 1; + } + + const char *instance = mdns_query_srv_args.instance->sval[0]; + const char *service = mdns_query_srv_args.service->sval[0]; + const char *proto = mdns_query_srv_args.proto->sval[0]; + int timeout = mdns_query_srv_args.timeout->ival[0]; + + if (timeout <= 0) { + timeout = 1000; + } + + printf("Query SRV: %s.%s.%s.local, Timeout: %d\n", instance, service, proto, timeout); + + mdns_result_t *results = NULL; + esp_err_t err = mdns_query_srv(instance, service, proto, timeout, &results); + if (err) { + printf("ERROR: Query Failed\n"); + return 1; + } + if (!results) { + printf("No results found!\n"); + return 0; + } + mdns_print_results(results); + mdns_query_results_free(results); + return 0; +} + +static void register_mdns_query_srv(void) +{ + mdns_query_srv_args.instance = arg_str1(NULL, NULL, "", "Instance to search for"); + mdns_query_srv_args.service = arg_str1(NULL, NULL, "", "Service to search for (ex. _http, _smb, etc.)"); + mdns_query_srv_args.proto = arg_str1(NULL, NULL, "", "Protocol to search for (_tcp, _udp, etc.)"); + mdns_query_srv_args.timeout = arg_int0("t", "timeout", "", "Timeout for this query"); + mdns_query_srv_args.end = arg_end(2); + + const esp_console_cmd_t cmd_init = { + .command = "mdns_query_srv", + .help = "Query MDNS for Service SRV", + .hint = NULL, + .func = &cmd_mdns_query_srv, + .argtable = &mdns_query_srv_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) ); +} + +static struct { + struct arg_str *instance; + struct arg_str *service; + struct arg_str *proto; + struct arg_int *timeout; + struct arg_end *end; +} mdns_query_txt_args; + +static int cmd_mdns_query_txt(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_query_txt_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_query_txt_args.end, argv[0]); + return 1; + } + + const char *instance = mdns_query_txt_args.instance->sval[0]; + const char *service = mdns_query_txt_args.service->sval[0]; + const char *proto = mdns_query_txt_args.proto->sval[0]; + int timeout = mdns_query_txt_args.timeout->ival[0]; + + printf("Query TXT: %s.%s.%s.local, Timeout: %d\n", instance, service, proto, timeout); + + if (timeout <= 0) { + timeout = 5000; + } + + mdns_result_t *results = NULL; + esp_err_t err = mdns_query_txt(instance, service, proto, timeout, &results); + if (err) { + printf("ERROR: Query Failed\n"); + return 1; + } + if (!results) { + printf("No results found!\n"); + return 0; + } + + mdns_print_results(results); + mdns_query_results_free(results); + return 0; +} + +static void register_mdns_query_txt(void) +{ + mdns_query_txt_args.instance = arg_str1(NULL, NULL, "", "Instance to search for"); + mdns_query_txt_args.service = arg_str1(NULL, NULL, "", "Service to search for (ex. _http, _smb, etc.)"); + mdns_query_txt_args.proto = arg_str1(NULL, NULL, "", "Protocol to search for (_tcp, _udp, etc.)"); + mdns_query_txt_args.timeout = arg_int0("t", "timeout", "", "Timeout for this query"); + mdns_query_txt_args.end = arg_end(2); + + const esp_console_cmd_t cmd_init = { + .command = "mdns_query_txt", + .help = "Query MDNS for Service TXT", + .hint = NULL, + .func = &cmd_mdns_query_txt, + .argtable = &mdns_query_txt_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) ); +} + +static struct { + struct arg_str *service; + struct arg_str *proto; + struct arg_int *timeout; + struct arg_int *max_results; + struct arg_end *end; +} mdns_query_ptr_args; + +static int cmd_mdns_query_ptr(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_query_ptr_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_query_ptr_args.end, argv[0]); + return 1; + } + + const char *service = mdns_query_ptr_args.service->sval[0]; + const char *proto = mdns_query_ptr_args.proto->sval[0]; + int timeout = mdns_query_ptr_args.timeout->ival[0]; + int max_results = mdns_query_ptr_args.max_results->ival[0]; + + if (timeout <= 0) { + timeout = 5000; + } + + if (max_results <= 0 || max_results > 255) { + max_results = 255; + } + + printf("Query PTR: %s.%s.local, Timeout: %d, Max Results: %d\n", service, proto, timeout, max_results); + + mdns_result_t *results = NULL; + esp_err_t err = mdns_query_ptr(service, proto, timeout, max_results, &results); + if (err) { + printf("ERROR: Query Failed\n"); + return 1; + } + if (!results) { + printf("No results found!\n"); + return 0; + } + + mdns_print_results(results); + mdns_query_results_free(results); + return 0; +} + +static void register_mdns_query_ptr(void) +{ + mdns_query_ptr_args.service = arg_str1(NULL, NULL, "", "Service to search for (ex. _http, _smb, etc.)"); + mdns_query_ptr_args.proto = arg_str1(NULL, NULL, "", "Protocol to search for (_tcp, _udp, etc.)"); + mdns_query_ptr_args.timeout = arg_int0("t", "timeout", "", "Timeout for this query"); + mdns_query_ptr_args.max_results = arg_int0("m", "max_results", "", "Maximum results returned"); + mdns_query_ptr_args.end = arg_end(2); + + const esp_console_cmd_t cmd_init = { + .command = "mdns_query_ptr", + .help = "Query MDNS for Service", + .hint = NULL, + .func = &cmd_mdns_query_ptr, + .argtable = &mdns_query_ptr_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) ); +} + +static struct { + struct arg_str *hostname; + struct arg_int *timeout; + struct arg_int *max_results; + struct arg_end *end; +} mdns_query_ip_args; + +static int cmd_mdns_query_ip(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_query_ip_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_query_ip_args.end, argv[0]); + return 1; + } + + const char *hostname = mdns_query_ip_args.hostname->sval[0]; + int timeout = mdns_query_ip_args.timeout->ival[0]; + int max_results = mdns_query_ip_args.max_results->ival[0]; + + if (!hostname || !hostname[0]) { + printf("ERROR: Hostname not supplied\n"); + return 1; + } + + if (timeout <= 0) { + timeout = 1000; + } + + if (max_results < 0 || max_results > 255) { + max_results = 255; + } + + printf("Query IP: %s.local, Timeout: %d, Max Results: %d\n", hostname, timeout, max_results); + + mdns_result_t *results = NULL; + esp_err_t err = mdns_query(hostname, NULL, NULL, MDNS_TYPE_ANY, timeout, max_results, &results); + if (err) { + printf("ERROR: Query Failed\n"); + return 1; + } + if (!results) { + printf("No results found!\n"); + return 0; + } + mdns_print_results(results); + mdns_query_results_free(results); + + return 0; +} + +static void register_mdns_query_ip(void) +{ + mdns_query_ip_args.hostname = arg_str1(NULL, NULL, "", "Hostname that is searched for"); + mdns_query_ip_args.timeout = arg_int0("t", "timeout", "", "Timeout for this query"); + mdns_query_ip_args.max_results = arg_int0("m", "max_results", "", "Maximum results returned"); + mdns_query_ip_args.end = arg_end(2); + + const esp_console_cmd_t cmd_init = { + .command = "mdns_query_ip", + .help = "Query MDNS for IP", + .hint = NULL, + .func = &cmd_mdns_query_ip, + .argtable = &mdns_query_ip_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) ); +} + +static struct { + struct arg_str *instance; + struct arg_str *service; + struct arg_str *proto; + struct arg_int *timeout; + struct arg_int *max_results; + struct arg_end *end; +} mdns_query_svc_args; + +static int cmd_mdns_query_svc(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_query_svc_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_query_svc_args.end, argv[0]); + return 1; + } + + const char *instance = mdns_query_svc_args.instance->sval[0]; + const char *service = mdns_query_svc_args.service->sval[0]; + const char *proto = mdns_query_svc_args.proto->sval[0]; + int timeout = mdns_query_svc_args.timeout->ival[0]; + int max_results = mdns_query_svc_args.max_results->ival[0]; + + if (timeout <= 0) { + timeout = 5000; + } + + if (max_results < 0 || max_results > 255) { + max_results = 255; + } + + printf("Query SVC: %s.%s.%s.local, Timeout: %d, Max Results: %d\n", instance, service, proto, timeout, max_results); + + mdns_result_t *results = NULL; + esp_err_t err = mdns_query(instance, service, proto, MDNS_TYPE_ANY, timeout, max_results, &results); + if (err) { + printf("ERROR: Query Failed\n"); + return 1; + } + if (!results) { + printf("No results found!\n"); + return 0; + } + + mdns_print_results(results); + mdns_query_results_free(results); + return 0; +} + +static void register_mdns_query_svc(void) +{ + mdns_query_svc_args.instance = arg_str1(NULL, NULL, "", "Instance to search for"); + mdns_query_svc_args.service = arg_str1(NULL, NULL, "", "Service to search for (ex. _http, _smb, etc.)"); + mdns_query_svc_args.proto = arg_str1(NULL, NULL, "", "Protocol to search for (_tcp, _udp, etc.)"); + mdns_query_svc_args.timeout = arg_int0("t", "timeout", "", "Timeout for this query"); + mdns_query_svc_args.max_results = arg_int0("m", "max_results", "", "Maximum results returned"); + mdns_query_svc_args.end = arg_end(2); + + const esp_console_cmd_t cmd_init = { + .command = "mdns_query_svc", + .help = "Query MDNS for Service TXT & SRV", + .hint = NULL, + .func = &cmd_mdns_query_svc, + .argtable = &mdns_query_svc_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) ); +} + +static struct { + struct arg_str *hostname; + struct arg_str *instance; + struct arg_end *end; +} mdns_init_args; + +static int cmd_mdns_init(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_init_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_init_args.end, argv[0]); + return 1; + } + + ESP_ERROR_CHECK( mdns_init() ); + + if (mdns_init_args.hostname->sval[0]) { + ESP_ERROR_CHECK( mdns_hostname_set(mdns_init_args.hostname->sval[0]) ); + printf("MDNS: Hostname: %s\n", mdns_init_args.hostname->sval[0]); + } + + if (mdns_init_args.instance->count) { + ESP_ERROR_CHECK( mdns_instance_name_set(mdns_init_args.instance->sval[0]) ); + printf("MDNS: Instance: %s\n", mdns_init_args.instance->sval[0]); + } + + return 0; +} + +static void register_mdns_init(void) +{ + mdns_init_args.hostname = arg_str0("h", "hostname", "", "Hostname that the server will advertise"); + mdns_init_args.instance = arg_str0("i", "instance", "", "Default instance name for services"); + mdns_init_args.end = arg_end(2); + + const esp_console_cmd_t cmd_init = { + .command = "mdns_init", + .help = "Start MDNS Server", + .hint = NULL, + .func = &cmd_mdns_init, + .argtable = &mdns_init_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) ); +} + +static int cmd_mdns_free(int argc, char **argv) +{ + mdns_free(); + return 0; +} + +static void register_mdns_free(void) +{ + const esp_console_cmd_t cmd_free = { + .command = "mdns_free", + .help = "Stop MDNS Server", + .hint = NULL, + .func = &cmd_mdns_free, + .argtable = NULL + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_free) ); +} + +static struct { + struct arg_str *hostname; + struct arg_end *end; +} mdns_set_hostname_args; + +static int cmd_mdns_set_hostname(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_set_hostname_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_set_hostname_args.end, argv[0]); + return 1; + } + + if (mdns_set_hostname_args.hostname->sval[0] == NULL) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + + ESP_ERROR_CHECK( mdns_hostname_set(mdns_set_hostname_args.hostname->sval[0]) ); + return 0; +} + +static void register_mdns_set_hostname(void) +{ + mdns_set_hostname_args.hostname = arg_str1(NULL, NULL, "", "Hostname that the server will advertise"); + mdns_set_hostname_args.end = arg_end(2); + + const esp_console_cmd_t cmd_set_hostname = { + .command = "mdns_set_hostname", + .help = "Set MDNS Server hostname", + .hint = NULL, + .func = &cmd_mdns_set_hostname, + .argtable = &mdns_set_hostname_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_set_hostname) ); +} + +static struct { + struct arg_str *instance; + struct arg_end *end; +} mdns_set_instance_args; + +static int cmd_mdns_set_instance(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_set_instance_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_set_instance_args.end, argv[0]); + return 1; + } + + if (mdns_set_instance_args.instance->sval[0] == NULL) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + + ESP_ERROR_CHECK( mdns_instance_name_set(mdns_set_instance_args.instance->sval[0]) ); + return 0; +} + +static void register_mdns_set_instance(void) +{ + mdns_set_instance_args.instance = arg_str1(NULL, NULL, "", "Default instance name for services"); + mdns_set_instance_args.end = arg_end(2); + + const esp_console_cmd_t cmd_set_instance = { + .command = "mdns_set_instance", + .help = "Set MDNS Server Istance Name", + .hint = NULL, + .func = &cmd_mdns_set_instance, + .argtable = &mdns_set_instance_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_set_instance) ); +} + +static mdns_txt_item_t *_convert_items(const char **values, int count) +{ + int i = 0, e; + const char *value = NULL; + mdns_txt_item_t *items = (mdns_txt_item_t *) malloc(sizeof(mdns_txt_item_t) * count); + if (!items) { + printf("ERROR: No Memory!\n"); + goto fail; + + } + memset(items, 0, sizeof(mdns_txt_item_t) * count); + + for (i = 0; i < count; i++) { + value = values[i]; + char *esign = strchr(value, '='); + if (!esign) { + printf("ERROR: Equal sign not found in '%s'!\n", value); + goto fail; + } + int var_len = esign - value; + int val_len = strlen(value) - var_len - 1; + char *var = (char *)malloc(var_len + 1); + if (var == NULL) { + printf("ERROR: No Memory!\n"); + goto fail; + } + char *val = (char *)malloc(val_len + 1); + if (val == NULL) { + printf("ERROR: No Memory!\n"); + free(var); + goto fail; + } + memcpy(var, value, var_len); + var[var_len] = 0; + memcpy(val, esign + 1, val_len); + val[val_len] = 0; + + items[i].key = var; + items[i].value = val; + } + + return items; + +fail: + for (e = 0; e < i; e++) { + free((char *)items[e].key); + free((char *)items[e].value); + } + free(items); + return NULL; +} + +static struct { + struct arg_str *service; + struct arg_str *proto; + struct arg_int *port; + struct arg_str *instance; + struct arg_str *host; + struct arg_str *txt; + struct arg_end *end; +} mdns_add_args; + +static int cmd_mdns_service_add(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_add_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_add_args.end, argv[0]); + return 1; + } + + if (!mdns_add_args.service->sval[0] || !mdns_add_args.proto->sval[0] || !mdns_add_args.port->ival[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + const char *instance = NULL; + if (mdns_add_args.instance->sval[0] && mdns_add_args.instance->sval[0][0]) { + instance = mdns_add_args.instance->sval[0]; + printf("MDNS: Service Instance: %s\n", instance); + } + const char *host = NULL; + if (mdns_add_args.host->count && mdns_add_args.host->sval[0]) { + host = mdns_add_args.host->sval[0]; + printf("MDNS: Service for delegated host: %s\n", host); + } + mdns_txt_item_t *items = NULL; + if (mdns_add_args.txt->count) { + items = _convert_items(mdns_add_args.txt->sval, mdns_add_args.txt->count); + if (!items) { + printf("ERROR: No Memory!\n"); + return 1; + + } + } + + ESP_ERROR_CHECK( mdns_service_add_for_host(instance, mdns_add_args.service->sval[0], mdns_add_args.proto->sval[0], + host, mdns_add_args.port->ival[0], items, mdns_add_args.txt->count) ); + free(items); + return 0; +} + +static void register_mdns_service_add(void) +{ + mdns_add_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_add_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_add_args.port = arg_int1(NULL, NULL, "", "Service Port"); + mdns_add_args.instance = arg_str0("i", "instance", "", "Instance name"); + mdns_add_args.host = arg_str0("h", "host", "", "Service for this (delegated) host"); + mdns_add_args.txt = arg_strn(NULL, NULL, "item", 0, 30, "TXT Items (name=value)"); + mdns_add_args.end = arg_end(2); + + const esp_console_cmd_t cmd_add = { + .command = "mdns_service_add", + .help = "Add service to MDNS", + .hint = NULL, + .func = &cmd_mdns_service_add, + .argtable = &mdns_add_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_add) ); +} + +static struct { + struct arg_str *instance; + struct arg_str *service; + struct arg_str *proto; + struct arg_str *host; + struct arg_end *end; +} mdns_remove_args; + +static int cmd_mdns_service_remove(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_remove_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_remove_args.end, argv[0]); + return 1; + } + + if (!mdns_remove_args.service->sval[0] || !mdns_remove_args.proto->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + + const char *instance = NULL; + if (mdns_remove_args.instance->count && mdns_remove_args.instance->sval[0]) { + instance = mdns_remove_args.instance->sval[0]; + } + const char *host = NULL; + if (mdns_remove_args.host->count && mdns_remove_args.host->sval[0]) { + host = mdns_remove_args.host->sval[0]; + } + + ESP_ERROR_CHECK( mdns_service_remove_for_host(instance, mdns_remove_args.service->sval[0], mdns_remove_args.proto->sval[0], host) ); + return 0; +} + +static void register_mdns_service_remove(void) +{ + mdns_remove_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_remove_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_remove_args.host = arg_str0("h", "host", "", "Service for this (delegated) host"); + mdns_remove_args.instance = arg_str0("i", "instance", "", "Instance name"); + mdns_remove_args.end = arg_end(4); + + const esp_console_cmd_t cmd_remove = { + .command = "mdns_service_remove", + .help = "Remove service from MDNS", + .hint = NULL, + .func = &cmd_mdns_service_remove, + .argtable = &mdns_remove_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_remove) ); +} + +static struct { + struct arg_str *service; + struct arg_str *proto; + struct arg_str *instance; + struct arg_str *host; + struct arg_str *old_instance; + struct arg_end *end; +} mdns_service_instance_set_args; + +static int cmd_mdns_service_instance_set(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_service_instance_set_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_service_instance_set_args.end, argv[0]); + return 1; + } + + if (!mdns_service_instance_set_args.service->sval[0] || !mdns_service_instance_set_args.proto->sval[0] || !mdns_service_instance_set_args.instance->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + const char *host = NULL; + if (mdns_service_instance_set_args.host->count && mdns_service_instance_set_args.host->sval[0]) { + host = mdns_service_instance_set_args.host->sval[0]; + } + const char *old_instance = NULL; + if (mdns_service_instance_set_args.old_instance->count && mdns_service_instance_set_args.old_instance->sval[0]) { + old_instance = mdns_service_instance_set_args.old_instance->sval[0]; + } + esp_err_t err = mdns_service_instance_name_set_for_host(old_instance, mdns_service_instance_set_args.service->sval[0], mdns_service_instance_set_args.proto->sval[0], host, mdns_service_instance_set_args.instance->sval[0]); + if (err != ESP_OK) { + printf("mdns_service_instance_name_set_for_host() failed with %s\n", esp_err_to_name(err)); + return 1; + } + + return 0; +} + +static void register_mdns_service_instance_set(void) +{ + mdns_service_instance_set_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_service_instance_set_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_service_instance_set_args.instance = arg_str1(NULL, NULL, "", "Instance name"); + mdns_service_instance_set_args.host = arg_str0("h", "host", "", "Service for this (delegated) host"); + mdns_service_instance_set_args.old_instance = arg_str0("i", "old_instance", "", "Instance name before update"); + mdns_service_instance_set_args.end = arg_end(4); + + const esp_console_cmd_t cmd_add = { + .command = "mdns_service_instance_set", + .help = "Set MDNS Service Instance Name", + .hint = NULL, + .func = &cmd_mdns_service_instance_set, + .argtable = &mdns_service_instance_set_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_add) ); +} + +static struct { + struct arg_str *service; + struct arg_str *proto; + struct arg_int *port; + struct arg_str *host; + struct arg_str *instance; + struct arg_end *end; +} mdns_service_port_set_args; + +static int cmd_mdns_service_port_set(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_service_port_set_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_service_port_set_args.end, argv[0]); + return 1; + } + + if (!mdns_service_port_set_args.service->sval[0] || !mdns_service_port_set_args.proto->sval[0] || !mdns_service_port_set_args.port->ival[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + + const char *host = NULL; + if (mdns_service_port_set_args.host->count && mdns_service_port_set_args.host->sval[0]) { + host = mdns_service_port_set_args.host->sval[0]; + } + const char *instance = NULL; + if (mdns_service_port_set_args.instance->count && mdns_service_port_set_args.instance->sval[0]) { + instance = mdns_service_port_set_args.instance->sval[0]; + } + esp_err_t err = mdns_service_port_set_for_host(instance, mdns_service_port_set_args.service->sval[0], mdns_service_port_set_args.proto->sval[0], host, mdns_service_port_set_args.port->ival[0]); + if (err != ESP_OK) { + printf("mdns_service_port_set_for_host() failed with %s\n", esp_err_to_name(err)); + return 1; + } + return 0; +} + +static void register_mdns_service_port_set(void) +{ + mdns_service_port_set_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_service_port_set_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_service_port_set_args.port = arg_int1(NULL, NULL, "", "Service Port"); + mdns_service_port_set_args.host = arg_str0("h", "host", "", "Service for this (delegated) host"); + mdns_service_port_set_args.instance = arg_str0("i", "instance", "", "Instance name"); + mdns_service_port_set_args.end = arg_end(2); + + const esp_console_cmd_t cmd_add = { + .command = "mdns_service_port_set", + .help = "Set MDNS Service port", + .hint = NULL, + .func = &cmd_mdns_service_port_set, + .argtable = &mdns_service_port_set_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_add) ); +} + +static struct { + struct arg_str *service; + struct arg_str *proto; + struct arg_str *instance; + struct arg_str *host; + struct arg_str *txt; + struct arg_end *end; +} mdns_txt_replace_args; + +static int cmd_mdns_service_txt_replace(int argc, char **argv) +{ + mdns_txt_item_t *items = NULL; + int nerrors = arg_parse(argc, argv, (void **) &mdns_txt_replace_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_txt_replace_args.end, argv[0]); + return 1; + } + + if (!mdns_txt_replace_args.service->sval[0] || !mdns_txt_replace_args.proto->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + const char *instance = NULL; + if (mdns_txt_replace_args.instance->count && mdns_txt_replace_args.instance->sval[0]) { + instance = mdns_txt_replace_args.instance->sval[0]; + printf("MDNS: Service Instance: %s\n", instance); + } + const char *host = NULL; + if (mdns_txt_replace_args.host->count && mdns_txt_replace_args.host->sval[0]) { + host = mdns_txt_replace_args.host->sval[0]; + printf("MDNS: Service for delegated host: %s\n", host); + } + if (mdns_txt_replace_args.txt->count) { + items = _convert_items(mdns_txt_replace_args.txt->sval, mdns_txt_replace_args.txt->count); + if (!items) { + printf("ERROR: No Memory!\n"); + return 1; + + } + } + ESP_ERROR_CHECK( mdns_service_txt_set_for_host(instance, mdns_txt_replace_args.service->sval[0], mdns_txt_replace_args.proto->sval[0], host, items, mdns_txt_replace_args.txt->count) ); + free(items); + return 0; +} + +static void register_mdns_service_txt_replace(void) +{ + mdns_txt_replace_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_txt_replace_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_txt_replace_args.instance = arg_str0("i", "instance", "", "Instance name"); + mdns_txt_replace_args.host = arg_str0("h", "host", "", "Service for this (delegated) host"); + mdns_txt_replace_args.txt = arg_strn(NULL, NULL, "item", 0, 30, "TXT Items (name=value)"); + mdns_txt_replace_args.end = arg_end(5); + + const esp_console_cmd_t cmd_txt_set = { + .command = "mdns_service_txt_replace", + .help = "Replace MDNS service TXT items", + .hint = NULL, + .func = &cmd_mdns_service_txt_replace, + .argtable = &mdns_txt_replace_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_txt_set) ); +} + +static struct { + struct arg_str *service; + struct arg_str *proto; + struct arg_str *instance; + struct arg_str *host; + struct arg_str *var; + struct arg_str *value; + struct arg_end *end; +} mdns_txt_set_args; + +static int cmd_mdns_service_txt_set(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_txt_set_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_txt_set_args.end, argv[0]); + return 1; + } + + if (!mdns_txt_set_args.service->sval[0] || !mdns_txt_set_args.proto->sval[0] || !mdns_txt_set_args.var->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + const char *instance = NULL; + if (mdns_txt_set_args.instance->count && mdns_txt_set_args.instance->sval[0]) { + instance = mdns_txt_set_args.instance->sval[0]; + printf("MDNS: Service Instance: %s\n", instance); + } + const char *host = NULL; + if (mdns_txt_set_args.host->count && mdns_txt_set_args.host->sval[0]) { + host = mdns_txt_set_args.host->sval[0]; + printf("MDNS: Service for delegated host: %s\n", host); + } + + ESP_ERROR_CHECK( mdns_service_txt_item_set_for_host(instance, mdns_txt_set_args.service->sval[0], mdns_txt_set_args.proto->sval[0], host, mdns_txt_set_args.var->sval[0], mdns_txt_set_args.value->sval[0]) ); + return 0; +} + +static void register_mdns_service_txt_set(void) +{ + mdns_txt_set_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_txt_set_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_txt_set_args.var = arg_str1(NULL, NULL, "", "Item Name"); + mdns_txt_set_args.value = arg_str1(NULL, NULL, "", "Item Value"); + mdns_txt_set_args.instance = arg_str0("i", "instance", "", "Instance name"); + mdns_txt_set_args.host = arg_str0("h", "host", "", "Service for this (delegated) host"); + mdns_txt_set_args.end = arg_end(6); + + const esp_console_cmd_t cmd_txt_set = { + .command = "mdns_service_txt_set", + .help = "Add/Set MDNS service TXT item", + .hint = NULL, + .func = &cmd_mdns_service_txt_set, + .argtable = &mdns_txt_set_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_txt_set) ); +} + +static struct { + struct arg_str *service; + struct arg_str *proto; + struct arg_str *var; + struct arg_str *instance; + struct arg_str *host; + struct arg_end *end; +} mdns_txt_remove_args; + +static int cmd_mdns_service_txt_remove(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_txt_remove_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_txt_remove_args.end, argv[0]); + return 1; + } + + if (!mdns_txt_remove_args.service->sval[0] || !mdns_txt_remove_args.proto->sval[0] || !mdns_txt_remove_args.var->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + const char *instance = NULL; + if (mdns_txt_remove_args.instance->count && mdns_txt_remove_args.instance->sval[0]) { + instance = mdns_txt_remove_args.instance->sval[0]; + } + const char *host = NULL; + if (mdns_txt_remove_args.host->count && mdns_txt_remove_args.host->sval[0]) { + host = mdns_txt_remove_args.host->sval[0]; + } + ESP_ERROR_CHECK( mdns_service_txt_item_remove_for_host(instance, mdns_txt_remove_args.service->sval[0], mdns_txt_remove_args.proto->sval[0], host, mdns_txt_remove_args.var->sval[0]) ); + return 0; +} + +static void register_mdns_service_txt_remove(void) +{ + mdns_txt_remove_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_txt_remove_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_txt_remove_args.var = arg_str1(NULL, NULL, "", "Item Name"); + mdns_txt_remove_args.instance = arg_str0("i", "instance", "", "Instance name"); + mdns_txt_remove_args.host = arg_str0("h", "host", "", "Service for this (delegated) host"); + mdns_txt_remove_args.end = arg_end(2); + + const esp_console_cmd_t cmd_txt_remove = { + .command = "mdns_service_txt_remove", + .help = "Remove MDNS service TXT item", + .hint = NULL, + .func = &cmd_mdns_service_txt_remove, + .argtable = &mdns_txt_remove_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_txt_remove) ); +} + +static int cmd_mdns_service_remove_all(int argc, char **argv) +{ + mdns_service_remove_all(); + return 0; +} + +static void register_mdns_service_remove_all(void) +{ + const esp_console_cmd_t cmd_free = { + .command = "mdns_service_remove_all", + .help = "Remove all MDNS services", + .hint = NULL, + .func = &cmd_mdns_service_remove_all, + .argtable = NULL + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_free) ); +} + +#define MDNS_MAX_LOOKUP_RESULTS CONFIG_MDNS_MAX_SERVICES + +static struct { + struct arg_str *instance; + struct arg_str *service; + struct arg_str *proto; + struct arg_lit *delegated; + struct arg_end *end; +} mdns_lookup_service_args; + +static esp_err_t lookup_service(const char *instance, const char *service, const char *proto, size_t max_results, + mdns_result_t **result, bool delegated) +{ + if (delegated) { + return mdns_lookup_delegated_service(instance, service, proto, max_results, result); + } + return mdns_lookup_selfhosted_service(instance, service, proto, max_results, result); +} + +static int cmd_mdns_lookup_service(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_lookup_service_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_lookup_service_args.end, argv[0]); + return 1; + } + + if (!mdns_lookup_service_args.instance->sval[0] || !mdns_lookup_service_args.service->sval[0] || !mdns_lookup_service_args.proto->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + mdns_result_t *results = NULL; + esp_err_t err = lookup_service(mdns_lookup_service_args.instance->count ? mdns_lookup_service_args.instance->sval[0] : NULL, + mdns_lookup_service_args.service->sval[0], mdns_lookup_service_args.proto->sval[0], + MDNS_MAX_LOOKUP_RESULTS, &results, mdns_lookup_service_args.delegated->count); + if (err) { + printf("Service lookup failed\n"); + return 1; + } + if (!results) { + printf("No results found!\n"); + return 0; + } + mdns_print_results(results); + mdns_query_results_free(results); + return 0; +} + +static void register_mdns_lookup_service(void) +{ + mdns_lookup_service_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_lookup_service_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_lookup_service_args.instance = arg_str0("i", "instance", "", "Instance name"); + mdns_lookup_service_args.delegated = arg_lit0("d", "delegated", "Lookup delegated services"); + mdns_lookup_service_args.end = arg_end(4); + + const esp_console_cmd_t cmd_lookup_service = { + .command = "mdns_service_lookup", + .help = "Lookup registered service", + .hint = NULL, + .func = &cmd_mdns_lookup_service, + .argtable = &mdns_lookup_service_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_lookup_service) ); +} + +static struct { + struct arg_str *hostname; + struct arg_str *address; + struct arg_end *end; +} mdns_delegate_host_args; + +static int cmd_mdns_delegate_host(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_delegate_host_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_delegate_host_args.end, argv[0]); + return 1; + } + + if (!mdns_delegate_host_args.hostname->sval[0] || !mdns_delegate_host_args.address->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + + mdns_ip_addr_t addr = { .next = NULL}; + esp_netif_str_to_ip4(mdns_delegate_host_args.address->sval[0], &addr.addr.u_addr.ip4); + addr.addr.type = ESP_IPADDR_TYPE_V4; + + esp_err_t err = mdns_delegate_hostname_add(mdns_delegate_host_args.hostname->sval[0], &addr); + if (err) { + printf("mdns_delegate_hostname_add() failed\n"); + return 1; + } + return 0; +} + +static void register_mdns_delegate_host(void) +{ + mdns_delegate_host_args.hostname = arg_str1(NULL, NULL, "", "Delegated hostname"); + mdns_delegate_host_args.address = arg_str1(NULL, NULL, "
", "Delegated hosts address"); + mdns_delegate_host_args.end = arg_end(2); + + const esp_console_cmd_t cmd_delegate_host = { + .command = "mdns_delegate_host", + .help = "Add delegated hostname", + .hint = NULL, + .func = &cmd_mdns_delegate_host, + .argtable = &mdns_delegate_host_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_delegate_host) ); +} + +static struct { + struct arg_str *hostname; + struct arg_end *end; +} mdns_undelegate_host_args; + +static int cmd_mdns_undelegate_host(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_undelegate_host_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_undelegate_host_args.end, argv[0]); + return 1; + } + + if (!mdns_undelegate_host_args.hostname->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + + if (mdns_delegate_hostname_remove(mdns_undelegate_host_args.hostname->sval[0]) != ESP_OK) { + printf("mdns_delegate_hostname_remove() failed\n"); + return 1; + } + return 0; +} + +static void register_mdns_undelegate_host(void) +{ + mdns_undelegate_host_args.hostname = arg_str1(NULL, NULL, "", "Delegated hostname"); + mdns_undelegate_host_args.end = arg_end(2); + + const esp_console_cmd_t cmd_undelegate_host = { + .command = "mdns_undelegate_host", + .help = "Remove delegated hostname", + .hint = NULL, + .func = &cmd_mdns_undelegate_host, + .argtable = &mdns_undelegate_host_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_undelegate_host) ); +} + +static struct { + struct arg_str *service; + struct arg_str *proto; + struct arg_str *sub; + struct arg_str *instance; + struct arg_str *host; + struct arg_end *end; +} mdns_service_subtype_args; + +static int cmd_mdns_service_subtype(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_service_subtype_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_service_subtype_args.end, argv[0]); + return 1; + } + + if (!mdns_service_subtype_args.service->sval[0] || !mdns_service_subtype_args.proto->sval[0] || !mdns_service_subtype_args.sub->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + const char *instance = NULL; + if (mdns_service_subtype_args.instance->count && mdns_service_subtype_args.instance->sval[0]) { + instance = mdns_service_subtype_args.instance->sval[0]; + } + const char *host = NULL; + if (mdns_service_subtype_args.host->count && mdns_service_subtype_args.host->sval[0]) { + host = mdns_service_subtype_args.host->sval[0]; + } + ESP_ERROR_CHECK( mdns_service_subtype_add_for_host(instance, mdns_service_subtype_args.service->sval[0], mdns_service_subtype_args.proto->sval[0], host, mdns_service_subtype_args.sub->sval[0]) ); + return 0; +} + +static void register_mdns_service_subtype_set(void) +{ + mdns_service_subtype_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_service_subtype_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_service_subtype_args.sub = arg_str1(NULL, NULL, "", "Subtype"); + mdns_service_subtype_args.instance = arg_str0("i", "instance", "", "Instance name"); + mdns_service_subtype_args.host = arg_str0("h", "host", "", "Service for this (delegated) host"); + mdns_service_subtype_args.end = arg_end(5); + + const esp_console_cmd_t cmd_service_sub = { + .command = "mdns_service_subtype", + .help = "Adds subtype for service", + .hint = NULL, + .func = &cmd_mdns_service_subtype, + .argtable = &mdns_service_subtype_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_service_sub) ); +} + +static struct { + struct arg_str *service; + struct arg_str *proto; + struct arg_end *end; +} mdns_browse_args; + +static void mdns_browse_notifier(mdns_result_t *result) +{ + if (result) { + mdns_print_results(result); + } +} + +static int cmd_mdns_browse(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_browse_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_browse_args.end, argv[0]); + return 1; + } + + if (!mdns_browse_args.service->sval[0] || !mdns_browse_args.proto->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + mdns_browse_t *handle = mdns_browse_new(mdns_browse_args.service->sval[0], mdns_browse_args.proto->sval[0], mdns_browse_notifier); + return handle ? 0 : 1; +} + +static void register_mdns_browse(void) +{ + mdns_browse_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_browse_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_browse_args.end = arg_end(2); + + const esp_console_cmd_t cmd_browse = { + .command = "mdns_browse", + .help = "Start browsing", + .hint = NULL, + .func = &cmd_mdns_browse, + .argtable = &mdns_browse_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_browse) ); +} + +static int cmd_mdns_browse_del(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **) &mdns_browse_args); + if (nerrors != 0) { + arg_print_errors(stderr, mdns_browse_args.end, argv[0]); + return 1; + } + + if (!mdns_browse_args.service->sval[0] || !mdns_browse_args.proto->sval[0]) { + printf("ERROR: Bad arguments!\n"); + return 1; + } + esp_err_t err = mdns_browse_delete(mdns_browse_args.service->sval[0], mdns_browse_args.proto->sval[0]); + return err == ESP_OK ? 0 : 1; +} + +static void register_mdns_browse_del(void) +{ + mdns_browse_args.service = arg_str1(NULL, NULL, "", "MDNS Service"); + mdns_browse_args.proto = arg_str1(NULL, NULL, "", "IP Protocol"); + mdns_browse_args.end = arg_end(2); + + const esp_console_cmd_t cmd_browse_del = { + .command = "mdns_browse_del", + .help = "Stop browsing", + .hint = NULL, + .func = &cmd_mdns_browse_del, + .argtable = &mdns_browse_args + }; + + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_browse_del) ); +} + +void mdns_console_register(void) +{ + register_mdns_init(); + register_mdns_free(); + register_mdns_set_hostname(); + register_mdns_set_instance(); + register_mdns_service_add(); + register_mdns_service_remove(); + register_mdns_service_instance_set(); + register_mdns_service_port_set(); + register_mdns_service_txt_replace(); + register_mdns_service_txt_set(); + register_mdns_service_txt_remove(); + register_mdns_service_remove_all(); + + register_mdns_lookup_service(); + register_mdns_delegate_host(); + register_mdns_undelegate_host(); + register_mdns_service_subtype_set(); + + register_mdns_browse(); + register_mdns_browse_del(); + +#ifdef CONFIG_LWIP_IPV4 + register_mdns_query_a(); +#endif +#ifdef CONFIG_LWIP_IPV6 + register_mdns_query_aaaa(); +#endif + register_mdns_query_txt(); + register_mdns_query_srv(); + register_mdns_query_ptr(); + + register_mdns_query_ip(); + register_mdns_query_svc(); +} diff --git a/managed_components/espressif__mdns/mdns_networking_lwip.c b/managed_components/espressif__mdns/mdns_networking_lwip.c new file mode 100644 index 0000000..635f7e3 --- /dev/null +++ b/managed_components/espressif__mdns/mdns_networking_lwip.c @@ -0,0 +1,397 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * MDNS Server Networking + * + */ +#include +#include "esp_log.h" +#include "lwip/ip_addr.h" +#include "lwip/pbuf.h" +#include "lwip/igmp.h" +#include "lwip/udp.h" +#include "lwip/mld6.h" +#include "lwip/priv/tcpip_priv.h" +#include "esp_system.h" +#include "esp_event.h" +#include "mdns_networking.h" +#include "esp_netif_net_stack.h" + +/* + * MDNS Server Networking + * + */ +enum interface_protocol { + PROTO_IPV4 = 1 << MDNS_IP_PROTOCOL_V4, + PROTO_IPV6 = 1 << MDNS_IP_PROTOCOL_V6 +}; + +typedef struct interfaces { + bool ready; + int proto; +} interfaces_t; + +static interfaces_t s_interfaces[MDNS_MAX_INTERFACES]; + +static struct udp_pcb *_pcb_main = NULL; + +static const char *TAG = "mdns_networking"; + +static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport); + +/** + * @brief Low level UDP PCB Initialize + */ +static esp_err_t _udp_pcb_main_init(void) +{ + if (_pcb_main) { + return ESP_OK; + } + _pcb_main = udp_new(); + if (!_pcb_main) { + return ESP_ERR_NO_MEM; + } + if (udp_bind(_pcb_main, IP_ANY_TYPE, MDNS_SERVICE_PORT) != 0) { + udp_remove(_pcb_main); + _pcb_main = NULL; + return ESP_ERR_INVALID_STATE; + } + _pcb_main->mcast_ttl = 255; + _pcb_main->remote_port = MDNS_SERVICE_PORT; + ip_addr_copy(_pcb_main->remote_ip, *(IP_ANY_TYPE)); + udp_recv(_pcb_main, &_udp_recv, NULL); + return ESP_OK; +} + +/** + * @brief Low level UDP PCB Free + */ +static void _udp_pcb_main_deinit(void) +{ + if (_pcb_main) { + udp_recv(_pcb_main, NULL, NULL); + udp_disconnect(_pcb_main); + udp_remove(_pcb_main); + _pcb_main = NULL; + } +} + +/** + * @brief Low level UDP Multicast membership control + */ +static esp_err_t _udp_join_group(mdns_if_t if_inx, mdns_ip_protocol_t ip_protocol, bool join) +{ + struct netif *netif = NULL; + esp_netif_t *tcpip_if = _mdns_get_esp_netif(if_inx); + + if (!esp_netif_is_netif_up(tcpip_if)) { + // Network interface went down before event propagated, skipping IGMP config + return ESP_ERR_INVALID_STATE; + } + + netif = esp_netif_get_netif_impl(tcpip_if); + assert(netif); + +#if LWIP_IPV4 + if (ip_protocol == MDNS_IP_PROTOCOL_V4) { + ip4_addr_t multicast_addr; + IP4_ADDR(&multicast_addr, 224, 0, 0, 251); + + if (join) { + if (igmp_joingroup_netif(netif, &multicast_addr)) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (igmp_leavegroup_netif(netif, &multicast_addr)) { + return ESP_ERR_INVALID_STATE; + } + } + } +#endif // LWIP_IPV4 +#if LWIP_IPV6 + if (ip_protocol == MDNS_IP_PROTOCOL_V6) { + ip_addr_t multicast_addr = IPADDR6_INIT(0x000002ff, 0, 0, 0xfb000000); + + if (join) { + if (mld6_joingroup_netif(netif, ip_2_ip6(&multicast_addr))) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (mld6_leavegroup_netif(netif, ip_2_ip6(&multicast_addr))) { + return ESP_ERR_INVALID_STATE; + } + } + } +#endif // LWIP_IPV6 + return ESP_OK; +} + +/** + * @brief the receive callback of the raw udp api. Packets are received here + * + */ +static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport) +{ + + uint8_t i; + while (pb != NULL) { + struct pbuf *this_pb = pb; + pb = pb->next; + this_pb->next = NULL; + + mdns_rx_packet_t *packet = (mdns_rx_packet_t *)malloc(sizeof(mdns_rx_packet_t)); + if (!packet) { + HOOK_MALLOC_FAILED; + //missed packet - no memory + pbuf_free(this_pb); + continue; + } + + packet->tcpip_if = MDNS_MAX_INTERFACES; + packet->pb = this_pb; + packet->src_port = rport; +#if LWIP_IPV4 && LWIP_IPV6 + packet->src.type = raddr->type; + memcpy(&packet->src.u_addr, &raddr->u_addr, sizeof(raddr->u_addr)); +#elif LWIP_IPV4 + packet->src.type = IPADDR_TYPE_V4; + packet->src.u_addr.ip4.addr = raddr->addr; +#elif LWIP_IPV6 + packet->src.type = IPADDR_TYPE_V6; + memcpy(&packet->src.u_addr.ip6, raddr, sizeof(ip_addr_t)); +#endif + packet->dest.type = packet->src.type; + +#if LWIP_IPV4 + if (packet->src.type == IPADDR_TYPE_V4) { + packet->ip_protocol = MDNS_IP_PROTOCOL_V4; + struct ip_hdr *iphdr = (struct ip_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP_HLEN); + packet->dest.u_addr.ip4.addr = iphdr->dest.addr; + packet->multicast = ip4_addr_ismulticast(&(packet->dest.u_addr.ip4)); + } +#endif // LWIP_IPV4 +#if LWIP_IPV6 + if (packet->src.type == IPADDR_TYPE_V6) { + packet->ip_protocol = MDNS_IP_PROTOCOL_V6; + struct ip6_hdr *ip6hdr = (struct ip6_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP6_HLEN); + memcpy(&packet->dest.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16); + packet->multicast = ip6_addr_ismulticast(&(packet->dest.u_addr.ip6)); + } +#endif // LWIP_IPV6 + + //lwip does not return the proper pcb if you have more than one for the same multicast address (but different interfaces) + struct netif *netif = NULL; + bool found = false; + for (i = 0; i < MDNS_MAX_INTERFACES; i++) { + netif = esp_netif_get_netif_impl(_mdns_get_esp_netif(i)); + if (s_interfaces[i].proto && netif && netif == ip_current_input_netif ()) { +#if LWIP_IPV4 + if (packet->src.type == IPADDR_TYPE_V4) { + if ((packet->src.u_addr.ip4.addr & ip_2_ip4(&netif->netmask)->addr) != (ip_2_ip4(&netif->ip_addr)->addr & ip_2_ip4(&netif->netmask)->addr)) { + //packet source is not in the same subnet + break; + } + } +#endif // LWIP_IPV4 + packet->tcpip_if = i; + found = true; + break; + } + } + + if (!found || _mdns_send_rx_action(packet) != ESP_OK) { + pbuf_free(this_pb); + free(packet); + } + } + +} + +bool mdns_is_netif_ready(mdns_if_t netif, mdns_ip_protocol_t ip_proto) +{ + return s_interfaces[netif].ready && + s_interfaces[netif].proto & (ip_proto == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6); +} + +/** + * @brief Check if any of the interfaces is up + */ +static bool _udp_pcb_is_in_use(void) +{ + int i, p; + for (i = 0; i < MDNS_MAX_INTERFACES; i++) { + for (p = 0; p < MDNS_IP_PROTOCOL_MAX; p++) { + if (mdns_is_netif_ready(i, p)) { + return true; + } + } + } + return false; +} + +/** + * @brief Stop PCB Main code + */ +static void _udp_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + s_interfaces[tcpip_if].proto &= ~(ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6); + if (s_interfaces[tcpip_if].proto == 0) { + s_interfaces[tcpip_if].ready = false; + _udp_join_group(tcpip_if, ip_protocol, false); + if (!_udp_pcb_is_in_use()) { + _udp_pcb_main_deinit(); + } + } +} + +/** + * @brief Start PCB Main code + */ +static esp_err_t _udp_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + if (mdns_is_netif_ready(tcpip_if, ip_protocol)) { + return ESP_ERR_INVALID_STATE; + } + + esp_err_t err = _udp_join_group(tcpip_if, ip_protocol, true); + if (err) { + return err; + } + + err = _udp_pcb_main_init(); + if (err) { + return err; + } + s_interfaces[tcpip_if].proto |= (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6); + s_interfaces[tcpip_if].ready = true; + + return ESP_OK; +} + +typedef struct { + struct tcpip_api_call_data call; + mdns_if_t tcpip_if; + mdns_ip_protocol_t ip_protocol; + struct pbuf *pbt; + const ip_addr_t *ip; + uint16_t port; + esp_err_t err; +} mdns_api_call_t; + +/** + * @brief Start PCB from LwIP thread + */ +static err_t _mdns_pcb_init_api(struct tcpip_api_call_data *api_call_msg) +{ + mdns_api_call_t *msg = (mdns_api_call_t *)api_call_msg; + msg->err = _udp_pcb_init(msg->tcpip_if, msg->ip_protocol); + return msg->err; +} + +/** + * @brief Stop PCB from LwIP thread + */ +static err_t _mdns_pcb_deinit_api(struct tcpip_api_call_data *api_call_msg) +{ + mdns_api_call_t *msg = (mdns_api_call_t *)api_call_msg; + _udp_pcb_deinit(msg->tcpip_if, msg->ip_protocol); + msg->err = ESP_OK; + return ESP_OK; +} + +/* + * Non-static functions below are + * - _mdns prefixed + * - commented in mdns_networking.h header + */ +esp_err_t _mdns_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_api_call_t msg = { + .tcpip_if = tcpip_if, + .ip_protocol = ip_protocol + }; + tcpip_api_call(_mdns_pcb_init_api, &msg.call); + return msg.err; +} + +esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + mdns_api_call_t msg = { + .tcpip_if = tcpip_if, + .ip_protocol = ip_protocol + }; + tcpip_api_call(_mdns_pcb_deinit_api, &msg.call); + return msg.err; +} + +static err_t _mdns_udp_pcb_write_api(struct tcpip_api_call_data *api_call_msg) +{ + void *nif = NULL; + mdns_api_call_t *msg = (mdns_api_call_t *)api_call_msg; + nif = esp_netif_get_netif_impl(_mdns_get_esp_netif(msg->tcpip_if)); + if (!nif || !mdns_is_netif_ready(msg->tcpip_if, msg->ip_protocol) || _pcb_main == NULL) { + pbuf_free(msg->pbt); + msg->err = ERR_IF; + return ERR_IF; + } + esp_err_t err = udp_sendto_if (_pcb_main, msg->pbt, msg->ip, msg->port, (struct netif *)nif); + pbuf_free(msg->pbt); + msg->err = err; + return err; +} + +size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const esp_ip_addr_t *ip, uint16_t port, uint8_t *data, size_t len) +{ + struct pbuf *pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (pbt == NULL) { + return 0; + } + memcpy((uint8_t *)pbt->payload, data, len); + + ip_addr_t ip_add_copy; +#if LWIP_IPV6 && LWIP_IPV4 + ip_add_copy.type = ip->type; + memcpy(&(ip_add_copy.u_addr), &(ip->u_addr), sizeof(ip_add_copy.u_addr)); +#elif LWIP_IPV4 + ip_add_copy.addr = ip->u_addr.ip4.addr; +#elif LWIP_IPV6 +#if LWIP_IPV6_SCOPES + ip_add_copy.zone = ip->u_addr.ip6.zone; +#endif // LWIP_IPV6_SCOPES + memcpy(ip_add_copy.addr, ip->u_addr.ip6.addr, sizeof(ip_add_copy.addr)); +#endif + + mdns_api_call_t msg = { + .tcpip_if = tcpip_if, + .ip_protocol = ip_protocol, + .pbt = pbt, + .ip = &ip_add_copy, + .port = port + }; + tcpip_api_call(_mdns_udp_pcb_write_api, &msg.call); + + if (msg.err) { + return 0; + } + return len; +} + +void *_mdns_get_packet_data(mdns_rx_packet_t *packet) +{ + return packet->pb->payload; +} + +size_t _mdns_get_packet_len(mdns_rx_packet_t *packet) +{ + return packet->pb->len; +} + +void _mdns_packet_free(mdns_rx_packet_t *packet) +{ + pbuf_free(packet->pb); + free(packet); +} diff --git a/managed_components/espressif__mdns/mdns_networking_socket.c b/managed_components/espressif__mdns/mdns_networking_socket.c new file mode 100644 index 0000000..a99a9cc --- /dev/null +++ b/managed_components/espressif__mdns/mdns_networking_socket.c @@ -0,0 +1,498 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief MDNS Server Networking module implemented using BSD sockets + */ + +#include +#include "esp_event.h" +#include "mdns_networking.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "esp_log.h" + +#if defined(CONFIG_IDF_TARGET_LINUX) +#include +#include +#endif + +enum interface_protocol { + PROTO_IPV4 = 1 << MDNS_IP_PROTOCOL_V4, + PROTO_IPV6 = 1 << MDNS_IP_PROTOCOL_V6 +}; + +typedef struct interfaces { + int sock; + int proto; +} interfaces_t; + +static interfaces_t s_interfaces[MDNS_MAX_INTERFACES]; + +static const char *TAG = "mdns_networking"; +static bool s_run_sock_recv_task = false; +static int create_socket(esp_netif_t *netif); +static int join_mdns_multicast_group(int sock, esp_netif_t *netif, mdns_ip_protocol_t ip_protocol); + +#if defined(CONFIG_IDF_TARGET_LINUX) +// Need to define packet buffer struct on linux +struct pbuf { + struct pbuf *next; + void *payload; + size_t tot_len; + size_t len; +}; +#else +// Compatibility define to access sock-addr struct the same way for lwip and linux +#define s6_addr32 un.u32_addr +#endif // CONFIG_IDF_TARGET_LINUX + +static void __attribute__((constructor)) ctor_networking_socket(void) +{ + for (int i = 0; i < sizeof(s_interfaces) / sizeof(s_interfaces[0]); ++i) { + s_interfaces[i].sock = -1; + s_interfaces[i].proto = 0; + } +} + +static void delete_socket(int sock) +{ + close(sock); +} + +bool mdns_is_netif_ready(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + return s_interfaces[tcpip_if].proto & (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6); +} + +void *_mdns_get_packet_data(mdns_rx_packet_t *packet) +{ + return packet->pb->payload; +} + +size_t _mdns_get_packet_len(mdns_rx_packet_t *packet) +{ + return packet->pb->len; +} + +void _mdns_packet_free(mdns_rx_packet_t *packet) +{ + free(packet->pb->payload); + free(packet->pb); + free(packet); +} + +esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + s_interfaces[tcpip_if].proto &= ~(ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6); + if (s_interfaces[tcpip_if].proto == 0) { + // if the interface for both protocols uninitialized, close the interface socket + if (s_interfaces[tcpip_if].sock >= 0) { + delete_socket(s_interfaces[tcpip_if].sock); + } + } + + for (int i = 0; i < MDNS_MAX_INTERFACES; i++) { + if (s_interfaces[i].sock >= 0) { + // If any of the interfaces initialized + return ESP_OK; + } + } + + // no interface alive, stop the rx task + s_run_sock_recv_task = false; + vTaskDelay(pdMS_TO_TICKS(500)); + return ESP_OK; +} + +#if defined(CONFIG_IDF_TARGET_LINUX) +#ifdef CONFIG_LWIP_IPV6 +static char *inet6_ntoa_r(struct in6_addr addr, char *ptr, size_t size) +{ + inet_ntop(AF_INET6, &(addr.s6_addr32[0]), ptr, size); + return ptr; +} +#endif // CONFIG_LWIP_IPV6 +static char *inet_ntoa_r(struct in_addr addr, char *ptr, size_t size) +{ + char *res = inet_ntoa(addr); + if (res && strlen(res) < size) { + strcpy(ptr, res); + } + return res; +} +#endif // CONFIG_IDF_TARGET_LINUX + +static inline char *get_string_address(struct sockaddr_storage *source_addr) +{ + static char address_str[40]; // 40=(8*4+7+term) is the max size of ascii IPv6 addr "XXXX:XX...XX:XXXX" + char *res = NULL; + // Convert ip address to string +#ifdef CONFIG_LWIP_IPV4 + if (source_addr->ss_family == PF_INET) { + res = inet_ntoa_r(((struct sockaddr_in *)source_addr)->sin_addr, address_str, sizeof(address_str)); + } +#endif +#ifdef CONFIG_LWIP_IPV6 + if (source_addr->ss_family == PF_INET6) { + res = inet6_ntoa_r(((struct sockaddr_in6 *)source_addr)->sin6_addr, address_str, sizeof(address_str)); + } +#endif + if (!res) { + address_str[0] = '\0'; // Returns empty string if conversion didn't succeed + } + return address_str; +} + + +static inline size_t espaddr_to_inet(const esp_ip_addr_t *addr, const uint16_t port, const mdns_ip_protocol_t ip_protocol, struct sockaddr_storage *in_addr) +{ + size_t ss_addr_len = 0; + memset(in_addr, 0, sizeof(struct sockaddr_storage)); +#ifdef CONFIG_LWIP_IPV4 + if (ip_protocol == MDNS_IP_PROTOCOL_V4 && addr->type == ESP_IPADDR_TYPE_V4) { + in_addr->ss_family = PF_INET; +#if !defined(CONFIG_IDF_TARGET_LINUX) + in_addr->s2_len = sizeof(struct sockaddr_in); +#endif + ss_addr_len = sizeof(struct sockaddr_in); + struct sockaddr_in *in_addr_ip4 = (struct sockaddr_in *) in_addr; + in_addr_ip4->sin_port = port; + in_addr_ip4->sin_addr.s_addr = addr->u_addr.ip4.addr; + } +#endif // CONFIG_LWIP_IPV4 +#ifdef CONFIG_LWIP_IPV6 + if (ip_protocol == MDNS_IP_PROTOCOL_V6 && addr->type == ESP_IPADDR_TYPE_V6) { + memset(in_addr, 0, sizeof(struct sockaddr_storage)); + in_addr->ss_family = PF_INET6; +#if !defined(CONFIG_IDF_TARGET_LINUX) + in_addr->s2_len = sizeof(struct sockaddr_in6); +#endif + ss_addr_len = sizeof(struct sockaddr_in6); + struct sockaddr_in6 *in_addr_ip6 = (struct sockaddr_in6 *)in_addr; + uint32_t *u32_addr = in_addr_ip6->sin6_addr.s6_addr32; + in_addr_ip6->sin6_port = port; + u32_addr[0] = addr->u_addr.ip6.addr[0]; + u32_addr[1] = addr->u_addr.ip6.addr[1]; + u32_addr[2] = addr->u_addr.ip6.addr[2]; + u32_addr[3] = addr->u_addr.ip6.addr[3]; + } +#endif // CONFIG_LWIP_IPV6 + return ss_addr_len; +} + +size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const esp_ip_addr_t *ip, uint16_t port, uint8_t *data, size_t len) +{ + if (!(s_interfaces[tcpip_if].proto & (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6))) { + return 0; + } + int sock = s_interfaces[tcpip_if].sock; + if (sock < 0) { + return 0; + } + struct sockaddr_storage in_addr; + size_t ss_size = espaddr_to_inet(ip, htons(port), ip_protocol, &in_addr); + if (!ss_size) { + ESP_LOGE(TAG, "espaddr_to_inet() failed: Mismatch of IP protocols"); + return 0; + } + ESP_LOGD(TAG, "[sock=%d]: Sending to IP %s port %d", sock, get_string_address(&in_addr), port); + ssize_t actual_len = sendto(sock, data, len, 0, (struct sockaddr *)&in_addr, ss_size); + if (actual_len < 0) { + ESP_LOGE(TAG, "[sock=%d]: _mdns_udp_pcb_write sendto() has failed\n errno=%d: %s", sock, errno, strerror(errno)); + } + return actual_len; +} + +static inline void inet_to_espaddr(const struct sockaddr_storage *in_addr, esp_ip_addr_t *addr, uint16_t *port) +{ +#ifdef CONFIG_LWIP_IPV4 + if (in_addr->ss_family == PF_INET) { + struct sockaddr_in *in_addr_ip4 = (struct sockaddr_in *)in_addr; + memset(addr, 0, sizeof(esp_ip_addr_t)); + *port = in_addr_ip4->sin_port; + addr->u_addr.ip4.addr = in_addr_ip4->sin_addr.s_addr; + addr->type = ESP_IPADDR_TYPE_V4; + } +#endif /* CONFIG_LWIP_IPV4 */ +#ifdef CONFIG_LWIP_IPV6 + if (in_addr->ss_family == PF_INET6) { + struct sockaddr_in6 *in_addr_ip6 = (struct sockaddr_in6 *)in_addr; + memset(addr, 0, sizeof(esp_ip_addr_t)); + *port = in_addr_ip6->sin6_port; + uint32_t *u32_addr = in_addr_ip6->sin6_addr.s6_addr32; + if (u32_addr[0] == 0 && u32_addr[1] == 0 && u32_addr[2] == esp_netif_htonl(0x0000FFFFUL)) { + // Mapped IPv4 address, convert directly to IPv4 + addr->type = ESP_IPADDR_TYPE_V4; + addr->u_addr.ip4.addr = u32_addr[3]; + } else { + addr->type = ESP_IPADDR_TYPE_V6; + addr->u_addr.ip6.addr[0] = u32_addr[0]; + addr->u_addr.ip6.addr[1] = u32_addr[1]; + addr->u_addr.ip6.addr[2] = u32_addr[2]; + addr->u_addr.ip6.addr[3] = u32_addr[3]; + } + } +#endif // CONFIG_LWIP_IPV6 +} + +void sock_recv_task(void *arg) +{ + while (s_run_sock_recv_task) { + struct timeval tv = { + .tv_sec = 1, + .tv_usec = 0, + }; + fd_set rfds; + FD_ZERO(&rfds); + int max_sock = -1; + for (int i = 0; i < MDNS_MAX_INTERFACES; i++) { + int sock = s_interfaces[i].sock; + if (sock >= 0) { + FD_SET(sock, &rfds); + max_sock = MAX(max_sock, sock); + } + } + if (max_sock < 0) { + vTaskDelay(pdMS_TO_TICKS(1000)); + ESP_LOGI(TAG, "No sock!"); + continue; + } + + int s = select(max_sock + 1, &rfds, NULL, NULL, &tv); + if (s < 0) { + ESP_LOGE(TAG, "Select failed. errno=%d: %s", errno, strerror(errno)); + break; + } else if (s > 0) { + for (int tcpip_if = 0; tcpip_if < MDNS_MAX_INTERFACES; tcpip_if++) { + int sock = s_interfaces[tcpip_if].sock; + if (sock < 0) { + continue; + } + if (FD_ISSET(sock, &rfds)) { + static char recvbuf[MDNS_MAX_PACKET_SIZE]; + uint16_t port = 0; + + struct sockaddr_storage raddr; // Large enough for both IPv4 or IPv6 + socklen_t socklen = sizeof(struct sockaddr_storage); + esp_ip_addr_t addr = {0}; + int len = recvfrom(sock, recvbuf, sizeof(recvbuf), 0, + (struct sockaddr *) &raddr, &socklen); + if (len < 0) { + ESP_LOGE(TAG, "multicast recvfrom failed. errno=%d: %s", errno, strerror(errno)); + break; + } + ESP_LOGD(TAG, "[sock=%d]: Received from IP:%s", sock, get_string_address(&raddr)); + ESP_LOG_BUFFER_HEXDUMP(TAG, recvbuf, len, ESP_LOG_VERBOSE); + inet_to_espaddr(&raddr, &addr, &port); + + // Allocate the packet structure and pass it to the mdns main engine + mdns_rx_packet_t *packet = (mdns_rx_packet_t *) calloc(1, sizeof(mdns_rx_packet_t)); + struct pbuf *packet_pbuf = calloc(1, sizeof(struct pbuf)); + uint8_t *buf = malloc(len); + if (packet == NULL || packet_pbuf == NULL || buf == NULL ) { + free(buf); + free(packet_pbuf); + free(packet); + HOOK_MALLOC_FAILED; + ESP_LOGE(TAG, "Failed to allocate the mdns packet"); + continue; + } + memcpy(buf, recvbuf, len); + packet_pbuf->next = NULL; + packet_pbuf->payload = buf; + packet_pbuf->tot_len = len; + packet_pbuf->len = len; + packet->tcpip_if = tcpip_if; + packet->pb = packet_pbuf; + packet->src_port = ntohs(port); + memcpy(&packet->src, &addr, sizeof(esp_ip_addr_t)); + // TODO(IDF-3651): Add the correct dest addr -- for mdns to decide multicast/unicast + // Currently it's enough to assume the packet is multicast and mdns to check the source port of the packet + memset(&packet->dest, 0, sizeof(esp_ip_addr_t)); + packet->multicast = 1; + packet->dest.type = packet->src.type; + packet->ip_protocol = + packet->src.type == ESP_IPADDR_TYPE_V4 ? MDNS_IP_PROTOCOL_V4 : MDNS_IP_PROTOCOL_V6; + if (_mdns_send_rx_action(packet) != ESP_OK) { + ESP_LOGE(TAG, "_mdns_send_rx_action failed!"); + free(packet->pb->payload); + free(packet->pb); + free(packet); + } + } + } + } + } + vTaskDelete(NULL); +} + +static void mdns_networking_init(void) +{ + if (s_run_sock_recv_task == false) { + s_run_sock_recv_task = true; + xTaskCreate( sock_recv_task, "mdns recv task", 3 * 1024, NULL, 5, NULL ); + } +} + +static bool create_pcb(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + if (s_interfaces[tcpip_if].proto & (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6)) { + return true; + } + int sock = s_interfaces[tcpip_if].sock; + esp_netif_t *netif = _mdns_get_esp_netif(tcpip_if); + if (sock < 0) { + sock = create_socket(netif); + } + if (sock < 0) { + ESP_LOGE(TAG, "Failed to create the socket!"); + return false; + } + int err = join_mdns_multicast_group(sock, netif, ip_protocol); + if (err < 0) { + ESP_LOGE(TAG, "Failed to add ipv6 multicast group for protocol %d", ip_protocol); + } + s_interfaces[tcpip_if].proto |= (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6); + s_interfaces[tcpip_if].sock = sock; + return true; +} + +esp_err_t _mdns_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + ESP_LOGI(TAG, "_mdns_pcb_init(tcpip_if=%lu, ip_protocol=%lu)", (unsigned long)tcpip_if, (unsigned long)ip_protocol); + if (!create_pcb(tcpip_if, ip_protocol)) { + return ESP_FAIL; + } + + mdns_networking_init(); + return ESP_OK; +} + +static int create_socket(esp_netif_t *netif) +{ +#ifdef CONFIG_LWIP_IPV6 + int sock = socket(PF_INET6, SOCK_DGRAM, 0); +#else + int sock = socket(PF_INET, SOCK_DGRAM, 0); +#endif + if (sock < 0) { + ESP_LOGE(TAG, "Failed to create socket. errno=%d: %s", errno, strerror(errno)); + return -1; + } + + int on = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) { + ESP_LOGE(TAG, "Failed setsockopt() to set SO_REUSEADDR. errno=%d: %s\n", errno, strerror(errno)); + } + // Bind the socket to any address +#ifdef CONFIG_LWIP_IPV6 + struct sockaddr_in6 saddr = { INADDR_ANY }; + saddr.sin6_family = AF_INET6; + saddr.sin6_port = htons(5353); + bzero(&saddr.sin6_addr.s6_addr, sizeof(saddr.sin6_addr.s6_addr)); + int err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)); + if (err < 0) { + ESP_LOGE(TAG, "Failed to bind socket. errno=%d: %s", errno, strerror(errno)); + goto err; + } +#else + struct sockaddr_in saddr = { 0 }; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(5353); + bzero(&saddr.sin_addr.s_addr, sizeof(saddr.sin_addr.s_addr)); + int err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)); + if (err < 0) { + ESP_LOGE(TAG, "Failed to bind socket. errno=%d: %s", errno, strerror(errno)); + goto err; + } +#endif // CONFIG_LWIP_IPV6 + struct ifreq ifr; + esp_netif_get_netif_impl_name(netif, ifr.ifr_name); + int ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(struct ifreq)); + if (ret < 0) { + ESP_LOGE(TAG, "\"%s\" Unable to bind socket to specified interface. errno=%d: %s", esp_netif_get_desc(netif), errno, strerror(errno)); + goto err; + } + + return sock; + +err: + close(sock); + return -1; +} + +#ifdef CONFIG_LWIP_IPV6 +static int socket_add_ipv6_multicast_group(int sock, esp_netif_t *netif) +{ + int ifindex = esp_netif_get_netif_impl_index(netif); + int err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)); + if (err < 0) { + ESP_LOGE(TAG, "Failed to set IPV6_MULTICAST_IF. errno=%d: %s", errno, strerror(errno)); + return err; + } + + struct ipv6_mreq v6imreq = { 0 }; + esp_ip_addr_t multi_addr = ESP_IP6ADDR_INIT(0x000002ff, 0, 0, 0xfb000000); + memcpy(&v6imreq.ipv6mr_multiaddr, &multi_addr.u_addr.ip6.addr, sizeof(v6imreq.ipv6mr_multiaddr)); + v6imreq.ipv6mr_interface = ifindex; + err = setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &v6imreq, sizeof(struct ipv6_mreq)); + if (err < 0) { + ESP_LOGE(TAG, "Failed to set IPV6_ADD_MEMBERSHIP. errno=%d: %s", errno, strerror(errno)); + return err; + } + return err; +} +#endif // CONFIG_LWIP_IPV6 + +#ifdef CONFIG_LWIP_IPV4 +static int socket_add_ipv4_multicast_group(int sock, esp_netif_t *netif) +{ + struct ip_mreq imreq = { 0 }; + int err = 0; + esp_netif_ip_info_t ip_info = { 0 }; + + if (esp_netif_get_ip_info(netif, &ip_info) != ESP_OK) { + ESP_LOGE(TAG, "Failed to esp_netif_get_ip_info()"); + goto err; + } + imreq.imr_interface.s_addr = ip_info.ip.addr; + + esp_ip_addr_t multicast_addr = ESP_IP4ADDR_INIT(224, 0, 0, 251); + imreq.imr_multiaddr.s_addr = multicast_addr.u_addr.ip4.addr; + + err = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(struct ip_mreq)); + if (err < 0) { + ESP_LOGE(TAG, "[sock=%d] Failed to set IP_ADD_MEMBERSHIP. errno=%d: %s", sock, errno, strerror(errno)); + goto err; + } + +err: + return err; +} +#endif // CONFIG_LWIP_IPV4 + +static int join_mdns_multicast_group(int sock, esp_netif_t *netif, mdns_ip_protocol_t ip_protocol) +{ +#ifdef CONFIG_LWIP_IPV4 + if (ip_protocol == MDNS_IP_PROTOCOL_V4) { + return socket_add_ipv4_multicast_group(sock, netif); + } +#endif // CONFIG_LWIP_IPV4 +#ifdef CONFIG_LWIP_IPV6 + if (ip_protocol == MDNS_IP_PROTOCOL_V6) { + return socket_add_ipv6_multicast_group(sock, netif); + } +#endif // CONFIG_LWIP_IPV6 + return -1; +} diff --git a/managed_components/espressif__mdns/private_include/mdns_networking.h b/managed_components/espressif__mdns/private_include/mdns_networking.h new file mode 100644 index 0000000..83cbe90 --- /dev/null +++ b/managed_components/espressif__mdns/private_include/mdns_networking.h @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ESP_MDNS_NETWORKING_H_ +#define ESP_MDNS_NETWORKING_H_ + +/* + * MDNS Server Networking -- private include + * + */ +#include "mdns.h" +#include "mdns_private.h" + + +/** + * @brief Queue RX packet action + */ +esp_err_t _mdns_send_rx_action(mdns_rx_packet_t *packet); + +bool mdns_is_netif_ready(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); + +/** + * @brief Start PCB + */ +esp_err_t _mdns_pcb_init(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); + +/** + * @brief Stop PCB + */ +esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol); + +/** + * @brief send packet over UDP + * + * @param server The server + * @param data byte array containing the packet data + * @param len length of the packet data + * + * @return length of sent packet or 0 on error + */ +size_t _mdns_udp_pcb_write(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const esp_ip_addr_t *ip, uint16_t port, uint8_t *data, size_t len); + +/** + * @brief Gets data pointer to the mDNS packet + */ +void *_mdns_get_packet_data(mdns_rx_packet_t *packet); + +/** + * @brief Gets data length of c + */ +size_t _mdns_get_packet_len(mdns_rx_packet_t *packet); + +/** + * @brief Free the mDNS packet + */ +void _mdns_packet_free(mdns_rx_packet_t *packet); + +#endif /* ESP_MDNS_NETWORKING_H_ */ diff --git a/managed_components/espressif__mdns/private_include/mdns_private.h b/managed_components/espressif__mdns/private_include/mdns_private.h new file mode 100644 index 0000000..381bd4b --- /dev/null +++ b/managed_components/espressif__mdns/private_include/mdns_private.h @@ -0,0 +1,474 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef MDNS_PRIVATE_H_ +#define MDNS_PRIVATE_H_ + +#include "sdkconfig.h" +#include "mdns.h" +#include "esp_task.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "esp_timer.h" +#include "esp_system.h" + +#ifdef CONFIG_MDNS_ENABLE_DEBUG_PRINTS +#define MDNS_ENABLE_DEBUG +#define _mdns_dbg_printf(...) printf(__VA_ARGS__) +#endif + +/** Number of predefined interfaces */ +#ifndef CONFIG_MDNS_PREDEF_NETIF_STA +#define CONFIG_MDNS_PREDEF_NETIF_STA 0 +#endif +#ifndef CONFIG_MDNS_PREDEF_NETIF_AP +#define CONFIG_MDNS_PREDEF_NETIF_AP 0 +#endif +#ifndef CONFIG_MDNS_PREDEF_NETIF_ETH +#define CONFIG_MDNS_PREDEF_NETIF_ETH 0 +#endif +#define MDNS_MAX_PREDEF_INTERFACES (CONFIG_MDNS_PREDEF_NETIF_STA + CONFIG_MDNS_PREDEF_NETIF_AP + CONFIG_MDNS_PREDEF_NETIF_ETH) + +#ifdef CONFIG_LWIP_IPV6_NUM_ADDRESSES +#define NETIF_IPV6_MAX_NUMS CONFIG_LWIP_IPV6_NUM_ADDRESSES +#else +#define NETIF_IPV6_MAX_NUMS 3 +#endif + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0) +/* CONFIG_LWIP_IPV4 was introduced in IDF v5.1 */ +/* For IDF v5.0, set CONFIG_LWIP_IPV4 to 1 by default */ +#ifndef CONFIG_LWIP_IPV4 +#define CONFIG_LWIP_IPV4 1 +#endif // CONFIG_LWIP_IPV4 +#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 1, 0) + +/** Number of configured interfaces */ +#if MDNS_MAX_PREDEF_INTERFACES > CONFIG_MDNS_MAX_INTERFACES +#warning Number of configured interfaces is less then number of predefined interfaces. Please update CONFIG_MDNS_MAX_INTERFACES. +#define MDNS_MAX_INTERFACES (MDNS_MAX_PREDEF_INTERFACES) +#else +#define MDNS_MAX_INTERFACES (CONFIG_MDNS_MAX_INTERFACES) +#endif + +/** The maximum number of services */ +#define MDNS_MAX_SERVICES CONFIG_MDNS_MAX_SERVICES + +#define MDNS_ANSWER_PTR_TTL 4500 +#define MDNS_ANSWER_TXT_TTL 4500 +#define MDNS_ANSWER_SRV_TTL 120 +#define MDNS_ANSWER_A_TTL 120 +#define MDNS_ANSWER_AAAA_TTL 120 + +#define MDNS_FLAGS_QUERY_REPSONSE 0x8000 +#define MDNS_FLAGS_AUTHORITATIVE 0x0400 +#define MDNS_FLAGS_QR_AUTHORITATIVE (MDNS_FLAGS_QUERY_REPSONSE | MDNS_FLAGS_AUTHORITATIVE) +#define MDNS_FLAGS_DISTRIBUTED 0x0200 + +#define MDNS_NAME_REF 0xC000 + +//custom type! only used by this implementation +//to help manage service discovery handling +#define MDNS_TYPE_SDPTR 0x0032 + +#define MDNS_CLASS_IN 0x0001 +#define MDNS_CLASS_ANY 0x00FF +#define MDNS_CLASS_IN_FLUSH_CACHE 0x8001 + +#define MDNS_ANSWER_ALL 0x3F +#define MDNS_ANSWER_PTR 0x08 +#define MDNS_ANSWER_TXT 0x04 +#define MDNS_ANSWER_SRV 0x02 +#define MDNS_ANSWER_A 0x01 +#define MDNS_ANSWER_AAAA 0x10 +#define MDNS_ANSWER_NSEC 0x20 +#define MDNS_ANSWER_SDPTR 0x80 +#define MDNS_ANSWER_AAAA_SIZE 16 + +#define MDNS_SERVICE_PORT 5353 // UDP port that the server runs on +#define MDNS_SERVICE_STACK_DEPTH CONFIG_MDNS_TASK_STACK_SIZE +#define MDNS_TASK_PRIORITY CONFIG_MDNS_TASK_PRIORITY +#if (MDNS_TASK_PRIORITY > ESP_TASK_PRIO_MAX) +#error "mDNS task priority is higher than ESP_TASK_PRIO_MAX" +#elif (MDNS_TASK_PRIORITY > ESP_TASKD_EVENT_PRIO) +#warning "mDNS task priority is higher than ESP_TASKD_EVENT_PRIO, mDNS library might not work correctly" +#endif +#define MDNS_TASK_AFFINITY CONFIG_MDNS_TASK_AFFINITY +#define MDNS_SERVICE_ADD_TIMEOUT_MS CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS + +#define MDNS_PACKET_QUEUE_LEN 16 // Maximum packets that can be queued for parsing +#define MDNS_ACTION_QUEUE_LEN CONFIG_MDNS_ACTION_QUEUE_LEN // Maximum actions pending to the server +#define MDNS_TXT_MAX_LEN 1024 // Maximum string length of text data in TXT record +#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES) +#define MDNS_NAME_MAX_LEN (64+4) // Need to account for IPv6 reverse queries (64 char address + ".ip6" ) +#else +#define MDNS_NAME_MAX_LEN 64 // Maximum string length of hostname, instance, service and proto +#endif +#define MDNS_NAME_BUF_LEN (MDNS_NAME_MAX_LEN+1) // Maximum char buffer size to hold hostname, instance, service or proto +#define MDNS_MAX_PACKET_SIZE 1460 // Maximum size of mDNS outgoing packet + +#define MDNS_HEAD_LEN 12 +#define MDNS_HEAD_ID_OFFSET 0 +#define MDNS_HEAD_FLAGS_OFFSET 2 +#define MDNS_HEAD_QUESTIONS_OFFSET 4 +#define MDNS_HEAD_ANSWERS_OFFSET 6 +#define MDNS_HEAD_SERVERS_OFFSET 8 +#define MDNS_HEAD_ADDITIONAL_OFFSET 10 + +#define MDNS_TYPE_OFFSET 0 +#define MDNS_CLASS_OFFSET 2 +#define MDNS_TTL_OFFSET 4 +#define MDNS_LEN_OFFSET 8 +#define MDNS_DATA_OFFSET 10 + +#define MDNS_SRV_PRIORITY_OFFSET 0 +#define MDNS_SRV_WEIGHT_OFFSET 2 +#define MDNS_SRV_PORT_OFFSET 4 +#define MDNS_SRV_FQDN_OFFSET 6 + +#define MDNS_TIMER_PERIOD_US (CONFIG_MDNS_TIMER_PERIOD_MS*1000) + +#define MDNS_SERVICE_LOCK() xSemaphoreTake(_mdns_service_semaphore, portMAX_DELAY) +#define MDNS_SERVICE_UNLOCK() xSemaphoreGive(_mdns_service_semaphore) + +#define queueToEnd(type, queue, item) \ + if (!queue) { \ + queue = item; \ + } else { \ + type * _q = queue; \ + while (_q->next) { _q = _q->next; } \ + _q->next = item; \ + } + +#define queueDetach(type, queue, item) \ + if (queue) { \ + if (queue == item) { \ + queue = queue->next; \ + } else { \ + type * _q = queue; \ + while (_q->next && _q->next != item) { \ + _q = _q->next; \ + } \ + if (_q->next == item) { \ + _q->next = item->next; \ + item->next = NULL; \ + } \ + } \ + } + +#define queueFree(type, queue) while (queue) { type * _q = queue; queue = queue->next; free(_q); } + +#define PCB_STATE_IS_PROBING(s) (s->state > PCB_OFF && s->state < PCB_ANNOUNCE_1) +#define PCB_STATE_IS_ANNOUNCING(s) (s->state > PCB_PROBE_3 && s->state < PCB_RUNNING) +#define PCB_STATE_IS_RUNNING(s) (s->state == PCB_RUNNING) + +#ifndef HOOK_MALLOC_FAILED +#define HOOK_MALLOC_FAILED ESP_LOGE(TAG, "Cannot allocate memory (line: %d, free heap: %" PRIu32 " bytes)", __LINE__, esp_get_free_heap_size()); +#endif + +typedef size_t mdns_if_t; + +typedef enum { + PCB_OFF, PCB_DUP, PCB_INIT, + PCB_PROBE_1, PCB_PROBE_2, PCB_PROBE_3, + PCB_ANNOUNCE_1, PCB_ANNOUNCE_2, PCB_ANNOUNCE_3, + PCB_RUNNING +} mdns_pcb_state_t; + +typedef enum { + MDNS_ANSWER, MDNS_NS, MDNS_EXTRA +} mdns_parsed_record_type_t; + +typedef enum { + ACTION_SYSTEM_EVENT, + ACTION_HOSTNAME_SET, + ACTION_INSTANCE_SET, + ACTION_SEARCH_ADD, + ACTION_SEARCH_SEND, + ACTION_SEARCH_END, + ACTION_BROWSE_ADD, + ACTION_BROWSE_SYNC, + ACTION_BROWSE_END, + ACTION_TX_HANDLE, + ACTION_RX_HANDLE, + ACTION_TASK_STOP, + ACTION_DELEGATE_HOSTNAME_ADD, + ACTION_DELEGATE_HOSTNAME_REMOVE, + ACTION_DELEGATE_HOSTNAME_SET_ADDR, + ACTION_MAX +} mdns_action_type_t; + + +typedef struct { + uint16_t id; + uint16_t flags; + uint16_t questions; //QDCOUNT + uint16_t answers; //ANCOUNT + uint16_t servers; //NSCOUNT + uint16_t additional;//ARCOUNT +} mdns_header_t; + +typedef struct { + char host[MDNS_NAME_BUF_LEN]; // hostname for A/AAAA records, instance name for SRV records + char service[MDNS_NAME_BUF_LEN]; + char proto[MDNS_NAME_BUF_LEN]; + char domain[MDNS_NAME_BUF_LEN]; + uint8_t parts; + uint8_t sub; + bool invalid; +} mdns_name_t; + +typedef struct mdns_parsed_question_s { + struct mdns_parsed_question_s *next; + uint16_t type; + bool sub; + bool unicast; + char *host; + char *service; + char *proto; + char *domain; +} mdns_parsed_question_t; + +typedef struct mdns_parsed_record_s { + struct mdns_parsed_record_s *next; + mdns_parsed_record_type_t record_type; + uint16_t type; + uint16_t clas; + uint8_t flush; + uint32_t ttl; + char *host; + char *service; + char *proto; + char *domain; + uint16_t data_len; + uint8_t *data; +} mdns_parsed_record_t; + +typedef struct { + mdns_if_t tcpip_if; + mdns_ip_protocol_t ip_protocol; + esp_ip_addr_t src; + uint16_t src_port; + uint8_t multicast; + uint8_t authoritative; + uint8_t probe; + uint8_t discovery; + uint8_t distributed; + mdns_parsed_question_t *questions; + mdns_parsed_record_t *records; + uint16_t id; +} mdns_parsed_packet_t; + +typedef struct { + mdns_if_t tcpip_if; + mdns_ip_protocol_t ip_protocol; + struct pbuf *pb; + esp_ip_addr_t src; + esp_ip_addr_t dest; + uint16_t src_port; + uint8_t multicast; +} mdns_rx_packet_t; + +typedef struct mdns_txt_linked_item_s { + const char *key; /*!< item key name */ + char *value; /*!< item value string */ + uint8_t value_len; /*!< item value length */ + struct mdns_txt_linked_item_s *next; /*!< next result, or NULL for the last result in the list */ +} mdns_txt_linked_item_t; + +typedef struct mdns_subtype_s { + const char *subtype; /*!< subtype */ + struct mdns_subtype_s *next; /*!< next result, or NULL for the last result in the list */ +} mdns_subtype_t; + +typedef struct { + const char *instance; + const char *service; + const char *proto; + const char *hostname; + uint16_t priority; + uint16_t weight; + uint16_t port; + mdns_txt_linked_item_t *txt; + mdns_subtype_t *subtype; +} mdns_service_t; + +typedef struct mdns_srv_item_s { + struct mdns_srv_item_s *next; + mdns_service_t *service; +} mdns_srv_item_t; + +typedef struct mdns_out_question_s { + struct mdns_out_question_s *next; + uint16_t type; + bool unicast; + const char *host; + const char *service; + const char *proto; + const char *domain; + bool own_dynamic_memory; +} mdns_out_question_t; + +typedef struct mdns_host_item_t { + const char *hostname; + mdns_ip_addr_t *address_list; + struct mdns_host_item_t *next; +} mdns_host_item_t; + +typedef struct mdns_out_answer_s { + struct mdns_out_answer_s *next; + uint16_t type; + uint8_t bye; + uint8_t flush; + mdns_service_t *service; + mdns_host_item_t *host; + const char *custom_instance; + const char *custom_service; + const char *custom_proto; +} mdns_out_answer_t; + +typedef struct mdns_tx_packet_s { + struct mdns_tx_packet_s *next; + uint32_t send_at; + mdns_if_t tcpip_if; + mdns_ip_protocol_t ip_protocol; + esp_ip_addr_t dst; + uint16_t port; + uint16_t flags; + uint8_t distributed; + mdns_out_question_t *questions; + mdns_out_answer_t *answers; + mdns_out_answer_t *servers; + mdns_out_answer_t *additional; + bool queued; + uint16_t id; +} mdns_tx_packet_t; + +typedef struct { + mdns_pcb_state_t state; + mdns_srv_item_t **probe_services; + uint8_t probe_services_len; + uint8_t probe_ip; + uint8_t probe_running; + uint16_t failed_probes; +} mdns_pcb_t; + +typedef enum { + SEARCH_OFF, + SEARCH_INIT, + SEARCH_RUNNING, + SEARCH_MAX +} mdns_search_once_state_t; + +typedef enum { + BROWSE_OFF, + BROWSE_INIT, + BROWSE_RUNNING, + BROWSE_MAX +} mdns_browse_state_t; + +typedef struct mdns_search_once_s { + struct mdns_search_once_s *next; + + mdns_search_once_state_t state; + uint32_t started_at; + uint32_t sent_at; + uint32_t timeout; + mdns_query_notify_t notifier; + SemaphoreHandle_t done_semaphore; + uint16_t type; + bool unicast; + uint8_t max_results; + uint8_t num_results; + char *instance; + char *service; + char *proto; + mdns_result_t *result; +} mdns_search_once_t; + +typedef struct mdns_browse_s { + struct mdns_browse_s *next; + + mdns_browse_state_t state; + mdns_browse_notify_t notifier; + + char *service; + char *proto; + mdns_result_t *result; +} mdns_browse_t; + +typedef struct mdns_browse_result_sync_t { + mdns_result_t *result; + struct mdns_browse_result_sync_t *next; +} mdns_browse_result_sync_t; + +typedef struct mdns_browse_sync { + mdns_browse_t *browse; + mdns_browse_result_sync_t *sync_result; +} mdns_browse_sync_t; + +typedef struct mdns_server_s { + struct { + mdns_pcb_t pcbs[MDNS_IP_PROTOCOL_MAX]; + } interfaces[MDNS_MAX_INTERFACES]; + const char *hostname; + const char *instance; + mdns_srv_item_t *services; + QueueHandle_t action_queue; + SemaphoreHandle_t action_sema; + mdns_tx_packet_t *tx_queue_head; + mdns_search_once_t *search_once; + esp_timer_handle_t timer_handle; + mdns_browse_t *browse; +} mdns_server_t; + +typedef struct { + mdns_action_type_t type; + union { + struct { + char *hostname; + } hostname_set; + char *instance; + struct { + mdns_if_t interface; + mdns_event_actions_t event_action; + } sys_event; + struct { + mdns_search_once_t *search; + } search_add; + struct { + mdns_tx_packet_t *packet; + } tx_handle; + struct { + mdns_rx_packet_t *packet; + } rx_handle; + struct { + const char *hostname; + mdns_ip_addr_t *address_list; + } delegate_hostname; + struct { + mdns_browse_t *browse; + } browse_add; + struct { + mdns_browse_sync_t *browse_sync; + } browse_sync; + } data; +} mdns_action_t; + +/* + * @brief Convert mnds if to esp-netif handle + * + * @param tcpip_if mdns supported interface as internal enum + * + * @return + * - ptr to esp-netif on success + * - NULL if no available netif for current interface index + */ +esp_netif_t *_mdns_get_esp_netif(mdns_if_t tcpip_if); + + +#endif /* MDNS_PRIVATE_H_ */ diff --git a/managed_components/espressif__mdns/tests/host_test/CMakeLists.txt b/managed_components/espressif__mdns/tests/host_test/CMakeLists.txt new file mode 100644 index 0000000..5f0d7bd --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.5) + + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +if(${IDF_TARGET} STREQUAL "linux") + set(EXTRA_COMPONENT_DIRS "../../../../common_components/linux_compat") + set(COMPONENTS main) +endif() + +project(mdns_host) + +# Enable sanitizers only without console (we'd see some leaks on argtable when console exits) +if(NOT CONFIG_TEST_CONSOLE AND CONFIG_IDF_TARGET_LINUX) +idf_component_get_property(mdns mdns COMPONENT_LIB) +target_link_options(${mdns} INTERFACE -fsanitize=address -fsanitize=undefined) +endif() diff --git a/managed_components/espressif__mdns/tests/host_test/README.md b/managed_components/espressif__mdns/tests/host_test/README.md new file mode 100644 index 0000000..4953f0e --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/README.md @@ -0,0 +1,33 @@ +# Setup dummy network interfaces + +Note: Set two addresses so we could use one as source and another as destination +``` +sudo ip link add eth2 type dummy +sudo ip addr add 192.168.1.200/24 dev eth2 +sudo ip addr add 192.168.1.201/24 dev eth2 +sudo ip link set eth2 up +sudo ifconfig eth2 multicast +``` + +# Dig on a specified interface + +``` +dig +short -b 192.168.1.200 -p 5353 @224.0.0.251 myesp.local +``` + +or a reverse query: +``` +dig +short -b 192.168.2.200 -p 5353 @224.0.0.251 -x 192.168.1.200 +``` + +# Run avahi to browse services + +Avahi needs the netif to have the "multicast" flag set + +```bash +david@david-comp:~/esp/idf (feature/mdns_networking_socket)$ avahi-browse -a -r -p ++;eth2;IPv6;myesp-service2;Web Site;local ++;eth2;IPv4;myesp-service2;Web Site;local +=;eth2;IPv6;myesp-service2;Web Site;local;myesp.local;192.168.1.200;80;"board=esp32" "u=user" "p=password" +=;eth2;IPv4;myesp-service2;Web Site;local;myesp.local;192.168.1.200;80;"board=esp32" "u=user" "p=password" +``` diff --git a/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/CMakeLists.txt b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/CMakeLists.txt new file mode 100644 index 0000000..6f8d51e --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/CMakeLists.txt @@ -0,0 +1,8 @@ +idf_build_get_property(idf_target IDF_TARGET) +if(${IDF_TARGET} STREQUAL "linux") + idf_component_register(SRCS esp_netif_linux.c + INCLUDE_DIRS include $ENV{IDF_PATH}/components/esp_netif/include + REQUIRES esp_event) +else() + idf_component_register() +endif() diff --git a/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/Kconfig b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/Kconfig new file mode 100644 index 0000000..3b3c309 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/Kconfig @@ -0,0 +1,15 @@ +menu "LWIP-MOCK-CONFIG" + + config LWIP_IPV6 + bool "Enable IPv6" + default y + help + Enable/disable IPv6 + + config LWIP_IPV4 + bool "Enable IPv4" + default y + help + Enable/disable IPv4 + +endmenu diff --git a/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/esp_netif_linux.c b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/esp_netif_linux.c new file mode 100644 index 0000000..93e4386 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/esp_netif_linux.c @@ -0,0 +1,197 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#include "esp_netif.h" +#include "esp_err.h" +#include //strlen +#include +#include //inet_addr +#include +#include +#include +#include "esp_netif_types.h" +#include "esp_log.h" + +#define MAX_NETIFS 4 + +static const char *TAG = "esp_netif_linux"; + +static esp_netif_t *s_netif_list[MAX_NETIFS] = { 0 }; + +struct esp_netif_obj { + const char *if_key; + const char *if_desc; +}; + +esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key) +{ + for (int i = 0; i < MAX_NETIFS; ++i) { + if (s_netif_list[i] && strcmp(s_netif_list[i]->if_key, if_key) == 0) { + return s_netif_list[i]; + } + } + return NULL; +} + +esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info) +{ + if (esp_netif == NULL) { + return ESP_ERR_INVALID_STATE; + } + struct ifaddrs *addrs, *tmp; + getifaddrs(&addrs); + tmp = addrs; + + while (tmp) { + if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) { + char addr[20]; + struct sockaddr_in *pAddr = (struct sockaddr_in *) tmp->ifa_addr; + inet_ntop(AF_INET, &pAddr->sin_addr, addr, sizeof(addr) ); + if (strcmp(esp_netif->if_desc, tmp->ifa_name) == 0) { + ESP_LOGD(TAG, "AF_INET4: %s: %s\n", tmp->ifa_name, addr); + memcpy(&ip_info->ip.addr, &pAddr->sin_addr, 4); + } + } + tmp = tmp->ifa_next; + } + freeifaddrs(addrs); + return ESP_OK; +} + +esp_err_t esp_netif_dhcpc_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status) +{ + return ESP_OK; +} + +int esp_netif_get_all_ip6(esp_netif_t *esp_netif, esp_ip6_addr_t if_ip6[]) +{ + if (esp_netif == NULL) { + return 0; + } + struct ifaddrs *addrs, *tmp; + int addr_count = 0; + getifaddrs(&addrs); + tmp = addrs; + + while (tmp) { + if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET6) { + struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)tmp->ifa_addr; + if (strcmp(esp_netif->if_desc, tmp->ifa_name) == 0) { + memcpy(&if_ip6[addr_count++], &pAddr->sin6_addr, 4 * 4); + } + } + tmp = tmp->ifa_next; + } + + freeifaddrs(addrs); + return addr_count; +} + +esp_err_t esp_netif_get_ip6_linklocal(esp_netif_t *esp_netif, esp_ip6_addr_t *if_ip6) +{ + if (esp_netif == NULL) { + return ESP_ERR_INVALID_STATE; + } + struct ifaddrs *addrs, *tmp; + getifaddrs(&addrs); + tmp = addrs; + + while (tmp) { + if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET6) { + char addr[64]; + struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)tmp->ifa_addr; + inet_ntop(AF_INET6, &pAddr->sin6_addr, addr, sizeof(addr) ); + if (strcmp(esp_netif->if_desc, tmp->ifa_name) == 0) { + ESP_LOGD(TAG, "AF_INET6: %s: %s\n", tmp->ifa_name, addr); + memcpy(if_ip6->addr, &pAddr->sin6_addr, 4 * 4); + break; + } + } + tmp = tmp->ifa_next; + } + + freeifaddrs(addrs); + return ESP_OK; +} + + +int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif) +{ + if (esp_netif == NULL) { + return -1; + } + uint32_t interfaceIndex = if_nametoindex(esp_netif->if_desc); + return interfaceIndex; +} + +esp_err_t esp_netif_get_netif_impl_name(esp_netif_t *esp_netif, char *name) +{ + if (esp_netif == NULL) { + return ESP_ERR_INVALID_STATE; + } + strcpy(name, esp_netif->if_desc); + return ESP_OK; +} + +const char *esp_netif_get_desc(esp_netif_t *esp_netif) +{ + if (esp_netif == NULL) { + return NULL; + } + return esp_netif->if_desc; +} + +esp_netif_t *esp_netif_new(const esp_netif_config_t *config) +{ + if (esp_netif_get_handle_from_ifkey(config->base->if_key)) { + return NULL; + } + esp_netif_t *netif = calloc(1, sizeof(struct esp_netif_obj)); + if (netif) { + netif->if_desc = config->base->if_desc; + netif->if_key = config->base->if_key; + } + + for (int i = 0; i < MAX_NETIFS; ++i) { + if (s_netif_list[i] == NULL) { + s_netif_list[i] = netif; + break; + } + } + + return netif; +} + +void esp_netif_destroy(esp_netif_t *esp_netif) +{ + for (int i = 0; i < MAX_NETIFS; ++i) { + if (s_netif_list[i] == esp_netif) { + s_netif_list[i] = NULL; + break; + } + } + free(esp_netif); +} + +const char *esp_netif_get_ifkey(esp_netif_t *esp_netif) +{ + return esp_netif->if_key; +} + +esp_err_t esp_netif_str_to_ip4(const char *src, esp_ip4_addr_t *dst) +{ + if (src == NULL || dst == NULL) { + return ESP_ERR_INVALID_ARG; + } + struct in_addr addr; + if (inet_pton(AF_INET, src, &addr) != 1) { + return ESP_FAIL; + } + dst->addr = addr.s_addr; + return ESP_OK; +} diff --git a/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/include/esp_wifi_types.h b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/include/esp_wifi_types.h new file mode 100644 index 0000000..e878e27 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/include/esp_wifi_types.h @@ -0,0 +1,7 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include "esp_event.h" diff --git a/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/include/machine/endian.h b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/include/machine/endian.h new file mode 100644 index 0000000..488bce0 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/include/machine/endian.h @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include_next "endian.h" diff --git a/managed_components/espressif__mdns/tests/host_test/dnsfixture.py b/managed_components/espressif__mdns/tests/host_test/dnsfixture.py new file mode 100644 index 0000000..6dcf0c9 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/dnsfixture.py @@ -0,0 +1,130 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import logging +import re +import socket +import sys + +import dns.message +import dns.query +import dns.rdataclass +import dns.rdatatype +import dns.resolver + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +class DnsPythonWrapper: + def __init__(self, server='224.0.0.251', port=5353, retries=3): + self.server = server + self.port = port + self.retries = retries + + def send_and_receive_query(self, query, timeout=3): + logger.info(f'Sending DNS query to {self.server}:{self.port}') + try: + # Create a UDP socket + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock: + sock.settimeout(timeout) + + # Send the DNS query + query_data = query.to_wire() + sock.sendto(query_data, (self.server, self.port)) + + # Receive the DNS response + response_data, _ = sock.recvfrom(512) # 512 bytes is the typical size for a DNS response + + # Parse the response + response = dns.message.from_wire(response_data) + + return response + + except socket.timeout as e: + logger.warning(f'DNS query timed out: {e}') + return None + except dns.exception.DNSException as e: + logger.error(f'DNS query failed: {e}') + return None + + def run_query(self, name, query_type='PTR', timeout=3): + logger.info(f'Running DNS query for {name} with type {query_type}') + query = dns.message.make_query(name, dns.rdatatype.from_text(query_type), dns.rdataclass.IN) + + # Print the DNS question section + logger.info(f'DNS question section: {query.question}') + + # Send and receive the DNS query + response = None + for attempt in range(1, self.retries + 1): + logger.info(f'Attempt {attempt}/{self.retries}') + response = self.send_and_receive_query(query, timeout) + if response: + break + + if response: + logger.info(f'DNS query response:\n{response}') + else: + logger.warning('No response received or response was invalid.') + + return response + + def parse_answer_section(self, response, query_type): + answers = [] + if response: + for answer in response.answer: + if dns.rdatatype.to_text(answer.rdtype) == query_type: + for item in answer.items: + full_answer = ( + f'{answer.name} {answer.ttl} ' + f'{dns.rdataclass.to_text(answer.rdclass)} ' + f'{dns.rdatatype.to_text(answer.rdtype)} ' + f'{item.to_text()}' + ) + answers.append(full_answer) + return answers + + def check_record(self, name, query_type, expected=True, expect=None): + output = self.run_query(name, query_type=query_type) + answers = self.parse_answer_section(output, query_type) + logger.info(f'answers: {answers}') + if expect is None: + expect = name + if expected: + assert any(expect in answer for answer in answers), f"Expected record '{expect}' not found in answer section" + else: + assert not any(expect in answer for answer in answers), f"Unexpected record '{expect}' found in answer section" + + +if __name__ == '__main__': + if len(sys.argv) < 3: + print('Usage: python dns_fixture.py ') + sys.exit(1) + + query_type = sys.argv[1] + name = sys.argv[2] + ip_only = len(sys.argv) > 3 and sys.argv[3] == '--ip_only' + if ip_only: + logger.setLevel(logging.WARNING) + + dns_wrapper = DnsPythonWrapper() + if query_type == 'X' and '.' in name: + # Sends an IPv4 reverse query + reversed_ip = '.'.join(reversed(name.split('.'))) + name = f'{reversed_ip}.in-addr.arpa' + query_type = 'PTR' + response = dns_wrapper.run_query(name, query_type=query_type) + answers = dns_wrapper.parse_answer_section(response, query_type) + + if answers: + for answer in answers: + logger.info(f'DNS query response: {answer}') + if ip_only: + ipv4_pattern = re.compile(r'\b(?:\d{1,3}\.){3}\d{1,3}\b') + ipv4_addresses = ipv4_pattern.findall(answer) + if ipv4_addresses: + print(f"{', '.join(ipv4_addresses)}") + else: + logger.info(f'No response for {name} with query type {query_type}') + exit(9) # Same as dig timeout diff --git a/managed_components/espressif__mdns/tests/host_test/main/CMakeLists.txt b/managed_components/espressif__mdns/tests/host_test/main/CMakeLists.txt new file mode 100644 index 0000000..0e6f226 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS + "." + REQUIRES mdns console nvs_flash) diff --git a/managed_components/espressif__mdns/tests/host_test/main/Kconfig.projbuild b/managed_components/espressif__mdns/tests/host_test/main/Kconfig.projbuild new file mode 100644 index 0000000..9bf4bba --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/main/Kconfig.projbuild @@ -0,0 +1,21 @@ +menu "Test Configuration" + + config TEST_HOSTNAME + string "mDNS Hostname" + default "esp32-mdns" + help + mDNS Hostname for example to use + + config TEST_NETIF_NAME + string "Network interface name" + default "eth2" + help + Name/ID if the network interface on which we run the mDNS host test + + config TEST_CONSOLE + bool "Start console" + default n + help + Test uses esp_console for interactive testing. + +endmenu diff --git a/managed_components/espressif__mdns/tests/host_test/main/idf_component.yml b/managed_components/espressif__mdns/tests/host_test/main/idf_component.yml new file mode 100644 index 0000000..e2d4fe9 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/main/idf_component.yml @@ -0,0 +1,7 @@ +dependencies: + idf: ">=5.0" + espressif/mdns: + version: "^1.0.0" + override_path: "../../.." + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/managed_components/espressif__mdns/tests/host_test/main/main.c b/managed_components/espressif__mdns/tests/host_test/main/main.c new file mode 100644 index 0000000..581231f --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/main/main.c @@ -0,0 +1,126 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_console.h" +#include "mdns.h" +#include "mdns_console.h" + +static const char *TAG = "mdns-test"; + +static void mdns_test_app(esp_netif_t *interface); + +#ifdef CONFIG_TEST_CONSOLE +static EventGroupHandle_t s_exit_signal = NULL; + +static int exit_console(int argc, char **argv) +{ + xEventGroupSetBits(s_exit_signal, 1); + return 0; +} + +#else +static void query_mdns_host(const char *host_name) +{ + ESP_LOGI(TAG, "Query A: %s.local", host_name); + + struct esp_ip4_addr addr; + addr.addr = 0; + + esp_err_t err = mdns_query_a(host_name, 2000, &addr); + if (err) { + if (err == ESP_ERR_NOT_FOUND) { + ESP_LOGW(TAG, "%x: Host was not found!", (err)); + return; + } + ESP_LOGE(TAG, "Query Failed: %x", (err)); + return; + } + + ESP_LOGI(TAG, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr)); +} +#endif // TEST_CONSOLE + +#ifndef CONFIG_IDF_TARGET_LINUX +#include "protocol_examples_common.h" +#include "esp_event.h" +#include "nvs_flash.h" + +/** + * @brief This is an entry point for the real target device, + * need to init few components and connect to a network interface + */ +void app_main(void) +{ + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(example_connect()); + + mdns_test_app(EXAMPLE_INTERFACE); + + ESP_ERROR_CHECK(example_disconnect()); +} +#else + +/** + * @brief This is an entry point for the linux target (simulator on host) + * need to create a dummy WiFi station and use it as mdns network interface + */ +int main(int argc, char *argv[]) +{ + setvbuf(stdout, NULL, _IONBF, 0); + const esp_netif_inherent_config_t base_cg = { .if_key = "WIFI_STA_DEF", .if_desc = CONFIG_TEST_NETIF_NAME }; + esp_netif_config_t cfg = { .base = &base_cg }; + esp_netif_t *sta = esp_netif_new(&cfg); + + mdns_test_app(sta); + + esp_netif_destroy(sta); + return 0; +} +#endif + +static void mdns_test_app(esp_netif_t *interface) +{ + ESP_ERROR_CHECK(mdns_init()); + ESP_ERROR_CHECK(mdns_hostname_set(CONFIG_TEST_HOSTNAME)); + ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_TEST_HOSTNAME); + ESP_ERROR_CHECK(mdns_register_netif(interface)); + ESP_ERROR_CHECK(mdns_netif_action(interface, MDNS_EVENT_ENABLE_IP4 /*| MDNS_EVENT_ENABLE_IP6 */ | MDNS_EVENT_IP4_REVERSE_LOOKUP | MDNS_EVENT_IP6_REVERSE_LOOKUP)); + +#ifdef CONFIG_TEST_CONSOLE + esp_console_repl_t *repl = NULL; + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + s_exit_signal = xEventGroupCreate(); + + repl_config.prompt = "mdns>"; + // init console REPL environment + ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl)); + + const esp_console_cmd_t cmd_exit = { + .command = "exit", + .help = "exit mDNS console application", + .hint = NULL, + .func = exit_console, + .argtable = NULL + }; + ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_exit) ); + mdns_console_register(); + ESP_ERROR_CHECK(esp_console_start_repl(repl)); + xEventGroupWaitBits(s_exit_signal, 1, pdTRUE, pdFALSE, portMAX_DELAY); + repl->del(repl); +#else + vTaskDelay(pdMS_TO_TICKS(10000)); + query_mdns_host("david-work"); + vTaskDelay(pdMS_TO_TICKS(1000)); +#endif + mdns_free(); + ESP_LOGI(TAG, "Exit"); +} diff --git a/managed_components/espressif__mdns/tests/host_test/pytest_mdns.py b/managed_components/espressif__mdns/tests/host_test/pytest_mdns.py new file mode 100644 index 0000000..f8b95f5 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/pytest_mdns.py @@ -0,0 +1,180 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import logging + +import pexpect +import pytest +from dnsfixture import DnsPythonWrapper + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) +ipv6_enabled = False + + +class MdnsConsole: + def __init__(self, command): + self.process = pexpect.spawn(command, encoding='utf-8') + self.process.logfile = open('mdns_interaction.log', 'w') # Log all interactions + self.process.expect('mdns> ', timeout=10) + + def send_input(self, input_data): + logger.info(f'Sending to stdin: {input_data}') + self.process.sendline(input_data) + + def get_output(self, expected_data): + logger.info(f'Expecting: {expected_data}') + self.process.expect(expected_data, timeout=10) + output = self.process.before.strip() + logger.info(f'Received from stdout: {output}') + return output + + def terminate(self): + self.send_input('exit') + self.get_output('Exit') + self.process.wait() + self.process.close() + assert self.process.exitstatus == 0 + + +@pytest.fixture(scope='module') +def mdns_console(): + app = MdnsConsole('./build_linux_console/mdns_host.elf') + yield app + app.terminate() + + +@pytest.fixture(scope='module') +def dig_app(): + return DnsPythonWrapper() + + +def test_mdns_init(mdns_console, dig_app): + mdns_console.send_input('mdns_init -h hostname') + mdns_console.get_output('MDNS: Hostname: hostname') + dig_app.check_record('hostname.local', query_type='A', expected=True) + if ipv6_enabled: + dig_app.check_record('hostname.local', query_type='AAAA', expected=True) + + +def test_add_service(mdns_console, dig_app): + mdns_console.send_input('mdns_service_add _http _tcp 80 -i test_service') + mdns_console.get_output('MDNS: Service Instance: test_service') + mdns_console.send_input('mdns_service_lookup _http _tcp') + mdns_console.get_output('PTR : test_service') + dig_app.check_record('_http._tcp.local', query_type='PTR', expected=True) + + +def test_remove_service(mdns_console, dig_app): + mdns_console.send_input('mdns_service_remove _http _tcp') + mdns_console.send_input('mdns_service_lookup _http _tcp') + mdns_console.get_output('No results found!') + dig_app.check_record('_http._tcp.local', query_type='PTR', expected=False) + + +def test_delegate_host(mdns_console, dig_app): + mdns_console.send_input('mdns_delegate_host delegated 1.2.3.4') + dig_app.check_record('delegated.local', query_type='A', expected=True) + + +def test_undelegate_host(mdns_console, dig_app): + mdns_console.send_input('mdns_undelegate_host delegated') + dig_app.check_record('delegated.local', query_type='A', expected=False) + + +def test_add_delegated_service(mdns_console, dig_app): + mdns_console.send_input('mdns_delegate_host delegated 1.2.3.4') + dig_app.check_record('delegated.local', query_type='A', expected=True) + mdns_console.send_input('mdns_service_add _test _tcp 80 -i local') + mdns_console.get_output('MDNS: Service Instance: local') + mdns_console.send_input('mdns_service_add _test2 _tcp 80 -i extern -h delegated') + mdns_console.get_output('MDNS: Service Instance: extern') + mdns_console.send_input('mdns_service_lookup _test _tcp') + mdns_console.get_output('PTR : local') + mdns_console.send_input('mdns_service_lookup _test2 _tcp -d') + mdns_console.get_output('PTR : extern') + dig_app.check_record('_test2._tcp.local', query_type='PTR', expected=True) + dig_app.check_record('extern._test2._tcp.local', query_type='SRV', expected=True) + + +def test_remove_delegated_service(mdns_console, dig_app): + mdns_console.send_input('mdns_service_remove _test2 _tcp -h delegated') + mdns_console.send_input('mdns_service_lookup _test2 _tcp -d') + mdns_console.get_output('No results found!') + dig_app.check_record('_test2._tcp.local', query_type='PTR', expected=False) + # add the delegated service again, would be used in the TXT test + mdns_console.send_input('mdns_service_add _test2 _tcp 80 -i extern -h delegated') + mdns_console.get_output('MDNS: Service Instance: extern') + + +def check_txt_for_service(instance, service, proto, mdns_console, dig_app, host=None, with_inst=False): + for_host_arg = f'-h {host}' if host is not None else '' + for_inst_arg = f'-i {instance}' if with_inst else '' + mdns_console.send_input(f'mdns_service_txt_set {service} {proto} {for_host_arg} {for_inst_arg} key1 value1') + dig_app.check_record(f'{instance}.{service}.{proto}.local', query_type='SRV', expected=True) + dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=True, expect='key1=value1') + mdns_console.send_input(f'mdns_service_txt_set {service} {proto} {for_host_arg} {for_inst_arg} key2 value2') + dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=True, expect='key2=value2') + mdns_console.send_input(f'mdns_service_txt_remove {service} {proto} {for_host_arg} {for_inst_arg} key2') + dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=False, expect='key2=value2') + dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=True, expect='key1=value1') + mdns_console.send_input(f'mdns_service_txt_replace {service} {proto} {for_host_arg} {for_inst_arg} key3=value3 key4=value4') + dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=False, expect='key1=value1') + dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=True, expect='key3=value3') + dig_app.check_record(f'{service}.{proto}.local', query_type='TXT', expected=True, expect='key4=value4') + + +def test_update_txt(mdns_console, dig_app): + check_txt_for_service('local', '_test', '_tcp', mdns_console=mdns_console, dig_app=dig_app) + check_txt_for_service('local', '_test', '_tcp', mdns_console=mdns_console, dig_app=dig_app, with_inst=True) + + +def test_update_delegated_txt(mdns_console, dig_app): + check_txt_for_service('extern', '_test2', '_tcp', mdns_console=mdns_console, dig_app=dig_app, host='delegated') + check_txt_for_service('extern', '_test2', '_tcp', mdns_console=mdns_console, dig_app=dig_app, host='delegated', with_inst=True) + + +def test_service_port_set(mdns_console, dig_app): + dig_app.check_record('local._test._tcp.local', query_type='SRV', expected=True, expect='80') + mdns_console.send_input('mdns_service_port_set _test _tcp 81') + dig_app.check_record('local._test._tcp.local', query_type='SRV', expected=True, expect='81') + mdns_console.send_input('mdns_service_port_set _test2 _tcp -h delegated 82') + dig_app.check_record('extern._test2._tcp.local', query_type='SRV', expected=True, expect='82') + mdns_console.send_input('mdns_service_port_set _test2 _tcp -h delegated -i extern 83') + dig_app.check_record('extern._test2._tcp.local', query_type='SRV', expected=True, expect='83') + mdns_console.send_input('mdns_service_port_set _test2 _tcp -h delegated -i invalid_inst 84') + mdns_console.get_output('ESP_ERR_NOT_FOUND') + dig_app.check_record('extern._test2._tcp.local', query_type='SRV', expected=True, expect='83') + + +def test_service_subtype(mdns_console, dig_app): + dig_app.check_record('local._test._tcp.local', query_type='SRV', expected=True) + mdns_console.send_input('mdns_service_subtype _test _tcp _subtest -i local') + dig_app.check_record('_subtest._sub._test._tcp.local', query_type='PTR', expected=True) + mdns_console.send_input('mdns_service_subtype _test2 _tcp _subtest2 -i extern -h delegated') + dig_app.check_record('_subtest2._sub._test2._tcp.local', query_type='PTR', expected=True) + + +def test_service_set_instance(mdns_console, dig_app): + dig_app.check_record('local._test._tcp.local', query_type='SRV', expected=True) + mdns_console.send_input('mdns_service_instance_set _test _tcp local2') + dig_app.check_record('local2._test._tcp.local', query_type='SRV', expected=True) + mdns_console.send_input('mdns_service_instance_set _test2 _tcp extern2 -h delegated') + mdns_console.send_input('mdns_service_lookup _test2 _tcp -d') + mdns_console.get_output('PTR : extern2') + dig_app.check_record('extern2._test2._tcp.local', query_type='SRV', expected=True) + mdns_console.send_input('mdns_service_instance_set _test2 _tcp extern3 -h delegated -i extern') + mdns_console.get_output('ESP_ERR_NOT_FOUND') + + +def test_service_remove_all(mdns_console, dig_app): + mdns_console.send_input('mdns_service_remove_all') + mdns_console.send_input('mdns_service_lookup _test2 _tcp -d') + mdns_console.get_output('No results found!') + mdns_console.send_input('mdns_service_lookup _test _tcp') + mdns_console.get_output('No results found!') + dig_app.check_record('_test._tcp.local', query_type='PTR', expected=False) + + +if __name__ == '__main__': + pytest.main(['-s', 'test_mdns.py']) diff --git a/managed_components/espressif__mdns/tests/host_test/sdkconfig.ci.app b/managed_components/espressif__mdns/tests/host_test/sdkconfig.ci.app new file mode 100644 index 0000000..809c518 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/sdkconfig.ci.app @@ -0,0 +1,4 @@ +CONFIG_IDF_TARGET="linux" +CONFIG_TEST_HOSTNAME="myesp" +CONFIG_MDNS_ENABLE_DEBUG_PRINTS=y +CONFIG_MDNS_RESPOND_REVERSE_QUERIES=y diff --git a/managed_components/espressif__mdns/tests/host_test/sdkconfig.ci.console b/managed_components/espressif__mdns/tests/host_test/sdkconfig.ci.console new file mode 100644 index 0000000..3b6dcb6 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/sdkconfig.ci.console @@ -0,0 +1,4 @@ +CONFIG_IDF_TARGET="linux" +CONFIG_ESP_EVENT_POST_FROM_ISR=n +CONFIG_MDNS_ENABLE_CONSOLE_CLI=y +CONFIG_TEST_CONSOLE=y diff --git a/managed_components/espressif__mdns/tests/host_test/sdkconfig.ci.target b/managed_components/espressif__mdns/tests/host_test/sdkconfig.ci.target new file mode 100644 index 0000000..2a43df1 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/sdkconfig.ci.target @@ -0,0 +1 @@ +CONFIG_IDF_TARGET="esp32" diff --git a/managed_components/espressif__mdns/tests/host_test/sdkconfig.defaults b/managed_components/espressif__mdns/tests/host_test/sdkconfig.defaults new file mode 100644 index 0000000..7e79ce4 --- /dev/null +++ b/managed_components/espressif__mdns/tests/host_test/sdkconfig.defaults @@ -0,0 +1,6 @@ +CONFIG_TEST_NETIF_NAME="eth0" +CONFIG_ESP_EVENT_POST_FROM_ISR=n +CONFIG_MDNS_NETWORKING_SOCKET=y +CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES=y +CONFIG_MDNS_PREDEF_NETIF_STA=n +CONFIG_MDNS_PREDEF_NETIF_AP=n diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/CMakeLists.txt b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/CMakeLists.txt new file mode 100644 index 0000000..d658451 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/CMakeLists.txt @@ -0,0 +1,7 @@ +# The following four lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +project(fuzz_test_update) diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/Makefile b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/Makefile new file mode 100644 index 0000000..6f45edb --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/Makefile @@ -0,0 +1,82 @@ +TEST_NAME=test +FUZZ=afl-fuzz +COMPONENTS_DIR=$(IDF_PATH)/components +COMPILER_ICLUDE_DIR=$(shell echo `which xtensa-esp32-elf-gcc | xargs dirname | xargs dirname`/xtensa-esp32-elf) + +CFLAGS=-g -Wno-unused-value -Wno-missing-declarations -Wno-pointer-bool-conversion -Wno-macro-redefined -Wno-int-to-void-pointer-cast -DHOOK_MALLOC_FAILED -DESP_EVENT_H_ -D__ESP_LOG_H__ \ + -I. -I../.. -I../../include -I../../private_include -I ./build/config \ + -I$(COMPONENTS_DIR) \ + -I$(COMPONENTS_DIR)/driver/include \ + -I$(COMPONENTS_DIR)/esp_common/include \ + -I$(COMPONENTS_DIR)/esp_event/include \ + -I$(COMPONENTS_DIR)/esp_eth/include \ + -I$(COMPONENTS_DIR)/esp_hw_support/include \ + -I$(COMPONENTS_DIR)/esp_netif/include \ + -I$(COMPONENTS_DIR)/esp_netif/private_include \ + -I$(COMPONENTS_DIR)/esp_netif/lwip \ + -I$(COMPONENTS_DIR)/esp_rom/include \ + -I$(COMPONENTS_DIR)/esp_system/include \ + -I$(COMPONENTS_DIR)/esp_timer/include \ + -I$(COMPONENTS_DIR)/esp_wifi/include \ + -I$(COMPONENTS_DIR)/freertos/FreeRTOS-Kernel \ + -I$(COMPONENTS_DIR)/freertos/FreeRTOS-Kernel/include \ + -I$(COMPONENTS_DIR)/freertos/esp_additions/include/freertos \ + -I$(COMPONENTS_DIR)/hal/include \ + -I$(COMPONENTS_DIR)/hal/esp32/include \ + -I$(COMPONENTS_DIR)/heap/include \ + -I$(COMPONENTS_DIR)/log/include \ + -I$(COMPONENTS_DIR)/lwip/lwip/src/include \ + -I$(COMPONENTS_DIR)/linux/include \ + -I$(COMPONENTS_DIR)/lwip/port/esp32/include \ + -I$(COMPONENTS_DIR)/lwip/lwip/src/include/lwip/apps \ + -I$(COMPONENTS_DIR)/soc/include \ + -I$(COMPONENTS_DIR)/soc/esp32/include \ + -I$(COMPONENTS_DIR)/soc/src/esp32/include \ + -I$(COMPONENTS_DIR)/xtensa/include \ + -I$(COMPONENTS_DIR)/xtensa/esp32/include \ + -I$(COMPILER_ICLUDE_DIR)/include + + +MDNS_C_DEPENDENCY_INJECTION=-include mdns_di.h +ifeq ($(MDNS_NO_SERVICES),on) + CFLAGS+=-DMDNS_NO_SERVICES +endif + +ifeq ($(INSTR),off) + CC=gcc + CFLAGS+=-DINSTR_IS_OFF + TEST_NAME=test_sim +else + CC=afl-clang-fast +endif +CPP=$(CC) +LD=$(CC) +OBJECTS=esp32_mock.o mdns.o test.o esp_netif_mock.o + +OS := $(shell uname) +ifeq ($(OS),Darwin) + LDLIBS= +else + LDLIBS=-lbsd + CFLAGS+=-DUSE_BSD_STRING +endif + +all: $(TEST_NAME) + +%.o: %.c + @echo "[CC] $<" + @$(CC) $(CFLAGS) -c $< -o $@ + +mdns.o: ../../mdns.c + @echo "[CC] $<" + @$(CC) $(CFLAGS) -include mdns_mock.h $(MDNS_C_DEPENDENCY_INJECTION) -c $< -o $@ + +$(TEST_NAME): $(OBJECTS) + @echo "[LD] $@" + @$(LD) $(OBJECTS) -o $@ $(LDLIBS) + +fuzz: $(TEST_NAME) + @$(FUZZ) -i "in" -o "out" -- ./$(TEST_NAME) + +clean: + @rm -rf *.o *.SYM $(TEST_NAME) out diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/README.md b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/README.md new file mode 100644 index 0000000..e22a896 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/README.md @@ -0,0 +1,80 @@ +## Introduction +This test uses [american fuzzy lop](http://lcamtuf.coredump.cx/afl/) to mangle real mdns packets and look for exceptions caused by the parser. + +A few actual packets are collected and exported as bins in the `in` folder, which is then passed as input to AFL when testing. The setup procedure for the test includes all possible services and scenarios that could be used with the given input packets.The output of the parser before fuzzing can be found in [input_packets.txt](input_packets.txt) + +## Building and running the tests using AFL +To build and run the tests using AFL(afl-clang-fast) instrumentation + +```bash +cd $IDF_PATH/components/mdns/test_afl_host +make fuzz +``` + +(Please note you have to install AFL instrumentation first, check `Installing AFL` section) + +## Building the tests using GCC INSTR(off) + +To build the tests without AFL instrumentations and instead of that use GCC compiler(In this case it will only check for compilation issues and will not run AFL tests). + +```bash +cd $IDF_PATH/components/mdns/test_afl_host +make INSTR=off +``` + +Note, that this setup is useful if we want to reproduce issues reported by fuzzer tests executed in the CI, or to simulate how the packet parser treats the input packets on the host machine. + +## Installing AFL +To run the test yourself, you need to download the [latest afl archive](http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz) and extract it to a folder on your computer. + +The rest of the document will refer to that folder as ```PATH_TO_AFL```. + +### Preparation +- On Mac, you will need to install the latest Xcode and llvm support from [Homebrew](https://brew.sh) + + ```bash + /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + brew install --with-clang --with-lld --HEAD llvm + export PATH="/usr/local/opt/llvm/bin:$PATH" + ``` + +- On Ubuntu you need the following packages: + + ```bash + sudo apt-get install make clang-4.0(or <=4.0) llvm-4.0(or <=4.0) libbsd-dev + ``` + +Please note that if specified package version can't be installed(due to system is the latest), you can download, build and install it manually. + +### Compile AFL +Compiling AFL is as easy as running make: + +```bash +cd [PATH_TO_AFL] +make +cd llvm_mode/ +make +``` + +After successful compilation, you can export the following variables to your shell (you can also add them to your profile if you want to use AFL in other projects). + +```bash +export AFL_PATH=[PATH_TO_AFL] +export PATH="$AFL_PATH:$PATH" +``` + +Please note LLVM must be <=4.0.0, otherwise afl does not compile, as there are some limitations with building AFL on MacOS/Linux with the latest LLVM. Also, Windows build on cygwin is not fully supported. + +## Additional info +Apple has a crash reporting service that could interfere with AFLs normal operation. To turn that off, run the following command: + +```bash +launchctl unload -w /System/Library/LaunchAgents/com.apple.ReportCrash.plist +sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.ReportCrash.Root.plist +``` + +Ubuntu has a similar service. To turn that off, run as root: + +```bash +echo core >/proc/sys/kernel/core_pattern +``` diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp32_mock.c b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp32_mock.c new file mode 100644 index 0000000..14b9134 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp32_mock.c @@ -0,0 +1,123 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include +#include +#include +#include "esp32_mock.h" +#include "esp_log.h" + +void *g_queue; +int g_queue_send_shall_fail = 0; +int g_size = 0; + +const char *WIFI_EVENT = "wifi_event"; +const char *ETH_EVENT = "eth_event"; + +esp_err_t esp_event_handler_register(const char *event_base, + int32_t event_id, + void *event_handler, + void *event_handler_arg) +{ + return ESP_OK; +} + +esp_err_t esp_event_handler_unregister(const char *event_base, int32_t event_id, void *event_handler) +{ + return ESP_OK; +} + +esp_err_t esp_timer_delete(esp_timer_handle_t timer) +{ + return ESP_OK; +} + +esp_err_t esp_timer_stop(esp_timer_handle_t timer) +{ + return ESP_OK; +} + +esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period) +{ + return ESP_OK; +} + +esp_err_t esp_timer_create(const esp_timer_create_args_t *create_args, + esp_timer_handle_t *out_handle) +{ + return ESP_OK; +} + +uint32_t xTaskGetTickCount(void) +{ + static uint32_t tick = 0; + return tick++; +} + +/// Queue mock +QueueHandle_t xQueueCreate( uint32_t uxQueueLength, uint32_t uxItemSize ) +{ + g_size = uxItemSize; + g_queue = malloc((uxQueueLength) * (uxItemSize)); + return g_queue; +} + + +void vQueueDelete( QueueHandle_t xQueue ) +{ + free(xQueue); +} + +uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait) +{ + if (g_queue_send_shall_fail) { + return pdFALSE; + } else { + memcpy(xQueue, pvItemToQueue, g_size); + return pdPASS; + } +} + + +uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait) +{ + return pdFALSE; +} + +void GetLastItem(void *pvBuffer) +{ + memcpy(pvBuffer, g_queue, g_size); +} + +void ForceTaskDelete(void) +{ + g_queue_send_shall_fail = 1; +} + +TaskHandle_t xTaskGetCurrentTaskHandle(void) +{ + return NULL; +} + +void xTaskNotifyGive(TaskHandle_t task) +{ + return; +} + +BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time) +{ + return pdTRUE; +} + +void esp_log_write(esp_log_level_t level, const char *tag, const char *format, ...) +{ +} + +uint32_t esp_log_timestamp(void) +{ + return 0; +} diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp32_mock.h b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp32_mock.h new file mode 100644 index 0000000..e8e84ce --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp32_mock.h @@ -0,0 +1,136 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _ESP32_COMPAT_H_ +#define _ESP32_COMPAT_H_ + +// Skip these include files +#define ESP_MDNS_NETWORKING_H_ +#define INC_FREERTOS_H +#define QUEUE_H +#define SEMAPHORE_H +#define _ESP_TASK_H_ + +#ifdef USE_BSD_STRING +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include "esp_timer.h" + +#define ESP_FAIL -1 + +#define ESP_ERR_NO_MEM 0x101 +#define ESP_ERR_INVALID_ARG 0x102 +#define ESP_ERR_INVALID_STATE 0x103 +#define ESP_ERR_INVALID_SIZE 0x104 +#define ESP_ERR_NOT_FOUND 0x105 +#define ESP_ERR_NOT_SUPPORTED 0x106 +#define ESP_ERR_TIMEOUT 0x107 +#define ESP_ERR_INVALID_RESPONSE 0x108 +#define ESP_ERR_INVALID_CRC 0x109 + +#define pdTRUE true +#define pdFALSE false +#define pdPASS ( pdTRUE ) +#define pdFAIL ( pdFALSE ) + +#define portMAX_DELAY 0xFFFFFFFF +#define portTICK_PERIOD_MS 1 +#define LWIP_HDR_PBUF_H +#define __ESP_RANDOM_H__ +#define INC_TASK_H + +#define pdMS_TO_TICKS(a) a +#define xSemaphoreTake(s,d) true +#define xTaskDelete(a) +#define vTaskDelete(a) free(a) +#define xSemaphoreGive(s) +#define xQueueCreateMutex(s) +#define _mdns_pcb_init(a,b) true +#define _mdns_pcb_deinit(a,b) true +#define xSemaphoreCreateMutex() malloc(1) +#define xSemaphoreCreateBinary() malloc(1) +#define vSemaphoreDelete(s) free(s) +#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U +#define xTaskCreatePinnedToCore(a,b,c,d,e,f,g) *(f) = malloc(1) +#define vTaskDelay(m) usleep((m)*0) +#define esp_random() (rand()%UINT32_MAX) + + +#define ESP_TASK_PRIO_MAX 25 +#define ESP_TASKD_EVENT_PRIO 5 +#define _mdns_udp_pcb_write(tcpip_if, ip_protocol, ip, port, data, len) len +#define TaskHandle_t TaskHandle_t + + +typedef int32_t esp_err_t; + +typedef void *SemaphoreHandle_t; +typedef void *QueueHandle_t; +typedef void *TaskHandle_t; +typedef int BaseType_t; +typedef uint32_t TickType_t; + + +struct udp_pcb { + uint8_t dummy; +}; + +struct ip4_addr { + uint32_t addr; +}; +typedef struct ip4_addr ip4_addr_t; + +struct ip6_addr { + uint32_t addr[4]; +}; +typedef struct ip6_addr ip6_addr_t; + +typedef void *system_event_t; + +struct pbuf { + struct pbuf *next; + void *payload; + uint16_t tot_len; + uint16_t len; + uint8_t /*pbuf_type*/ type; + uint8_t flags; + uint16_t ref; +}; + +uint32_t xTaskGetTickCount(void); +typedef void (*esp_timer_cb_t)(void *arg); + +// Queue mock +QueueHandle_t xQueueCreate( uint32_t uxQueueLength, + uint32_t uxItemSize ); + +void vQueueDelete( QueueHandle_t xQueue ); + +uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait); + +uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait); + +void GetLastItem(void *pvBuffer); + +void ForceTaskDelete(void); + +esp_err_t esp_event_handler_register(const char *event_base, int32_t event_id, void *event_handler, void *event_handler_arg); + +esp_err_t esp_event_handler_unregister(const char *event_base, int32_t event_id, void *event_handler); + + +TaskHandle_t xTaskGetCurrentTaskHandle(void); +void xTaskNotifyGive(TaskHandle_t task); +BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time ); + +#endif //_ESP32_COMPAT_H_ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp_attr.h b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp_attr.h new file mode 100644 index 0000000..75b6678 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp_attr.h @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#pragma once +#define IRAM_ATTR +#define FLAG_ATTR(TYPE) +#define QUEUE_H +#define __ARCH_CC_H__ +#define __XTENSA_API_H__ +#define SSIZE_MAX INT_MAX +#define LWIP_HDR_IP6_ADDR_H +#define LWIP_HDR_IP4_ADDR_H diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp_netif_mock.c b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp_netif_mock.c new file mode 100644 index 0000000..80629ad --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp_netif_mock.c @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "esp32_mock.h" + +typedef struct esp_netif_s esp_netif_t; +typedef struct esp_netif_ip_info esp_netif_ip_info_t; +typedef struct esp_netif_dhcp_status esp_netif_dhcp_status_t; + + +const char *IP_EVENT = "IP_EVENT"; + + +esp_err_t esp_netif_add_to_list(esp_netif_t *netif) +{ + return ESP_OK; +} + +esp_err_t esp_netif_remove_from_list(esp_netif_t *netif) +{ + return ESP_ERR_NOT_FOUND; +} + +esp_netif_t *esp_netif_next(esp_netif_t *netif) +{ + return NULL; +} + +esp_netif_t *esp_netif_next_unsafe(esp_netif_t *netif) +{ + return NULL; +} + +esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key) +{ + return NULL; +} + +esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_dhcpc_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status) +{ + return ESP_ERR_NOT_SUPPORTED; +} diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/file2.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/file2.bin new file mode 100644 index 0000000..a7ce859 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/file2.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_4a_txt.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_4a_txt.bin new file mode 100644 index 0000000..37f2803 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_4a_txt.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_aaaa.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_aaaa.bin new file mode 100644 index 0000000..6ddb7ac Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_aaaa.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_any.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_any.bin new file mode 100644 index 0000000..99a6d18 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_any.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_disc.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_disc.bin new file mode 100644 index 0000000..5f3ba62 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_disc.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_ptr.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_ptr.bin new file mode 100644 index 0000000..67da5ed Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_ptr.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_query.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_query.bin new file mode 100644 index 0000000..d21c0d2 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_query.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_query2.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_query2.bin new file mode 100644 index 0000000..986118d Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_query2.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/sub_fritz_m.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/sub_fritz_m.bin new file mode 100644 index 0000000..68e1d75 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/sub_fritz_m.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/telnet_ptr.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/telnet_ptr.bin new file mode 100644 index 0000000..1cd8e85 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/telnet_ptr.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-14.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-14.bin new file mode 100644 index 0000000..b9d059d Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-14.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-15.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-15.bin new file mode 100644 index 0000000..3250de5 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-15.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-16.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-16.bin new file mode 100644 index 0000000..19915d8 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-16.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-28.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-28.bin new file mode 100644 index 0000000..537352a Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-28.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-29.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-29.bin new file mode 100644 index 0000000..837737b Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-29.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-31.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-31.bin new file mode 100644 index 0000000..690b735 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-31.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-53.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-53.bin new file mode 100644 index 0000000..73181ea Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-53.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-56.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-56.bin new file mode 100644 index 0000000..980b651 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-56.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-63.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-63.bin new file mode 100644 index 0000000..883d444 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-63.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-83.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-83.bin new file mode 100644 index 0000000..c6cc159 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-83.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-88.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-88.bin new file mode 100644 index 0000000..fcbb384 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-88.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-89.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-89.bin new file mode 100644 index 0000000..d60a987 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-89.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-95.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-95.bin new file mode 100644 index 0000000..2655309 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-95.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-96.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-96.bin new file mode 100644 index 0000000..fabf8b7 Binary files /dev/null and b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-96.bin differ diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/input_packets.txt b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/input_packets.txt new file mode 100644 index 0000000..15c5df2 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/input_packets.txt @@ -0,0 +1,166 @@ +Input: in/test-14.bin +Packet Length: 568 +Questions: 18 + Q: _airport._tcp.local. PTR IN + Q: _http._tcp.local. PTR IN + Q: _printer._tcp.local. PTR IN + Q: _sub._http._tcp.local. PTR IN + Q: _airplay._tcp.local. PTR IN + Q: _raop._tcp.local. PTR IN + Q: _uscan._tcp.local. PTR IN + Q: _uscans._tcp.local. PTR IN + Q: _ippusb._tcp.local. PTR IN + Q: _scanner._tcp.local. PTR IN + Q: _ipp._tcp.local. PTR IN + Q: _ipps._tcp.local. PTR IN + Q: _pdl-datastream._tcp.local. PTR IN + Q: _ptp._tcp.local. PTR IN + Q: _sleep-proxy._udp.local. PTR IN + Q: 9801A7E58FA1@Hristo's AirPort Express._raop._tcp.local. TXT IN + Q: Hristo's AirPort Express._airport._tcp.local. TXT IN + Q: Hristo's Time Capsule._airport._tcp.local. TXT IN +Answers: 7 + 0 + A: _airport._tcp.local. PTR IN 2272 [2] Hristo's AirPort Express._airport._tcp.local. + A: _airport._tcp.local. PTR IN 2272 [2] Hristo's Time Capsule._airport._tcp.local. + A: _http._tcp.local. PTR IN 2535 [23] HP LaserJet CP1025nw._http._tcp.local. + A: _printer._tcp.local. PTR IN 2535 [23] HP LaserJet CP1025nw._printer._tcp.local. + A: _ipp._tcp.local. PTR IN 2535 [23] HP LaserJet CP1025nw._ipp._tcp.local. + A: _pdl-datastream._tcp.local. PTR IN 2535 [23] HP LaserJet CP1025nw._pdl-datastream._tcp.local. + A: _sleep-proxy._udp.local. PTR IN 2535 [38] 50-34-10-70.1 Hristo's Time Capsule._sleep-proxy._udp.local. + +Input: in/test-15.bin +Packet Length: 524 +Answers: 3 + 3 + A: Hristo's AirPort Express._airport._tcp.local. TXT IN FLUSH 4500 [166] waMA=98-01-A7-E5-8F-A1,raMA=98-01-A7-E8-C2-2E,raM2=98-01-A7-E8-C2-2F,raNm=your-ssid,raCh=1,rCh2=52,raSt=0,raNA=1,syFl=0x8A0C,syAP=115,syVs=7.6.8,srcv=76800.1,bjSd=23 + A: 9801A7E58FA1@Hristo's AirPort Express._raop._tcp.local. TXT IN FLUSH 4500 [134] txtvers=1; ch=2; cn=0,1; et=0,4; sv=false; da=true; sr=44100; ss=16; pw=false; vn=65537; tp=TCP,UDP; vs=105.1; am=AirPort10,115; fv=76800.1; sf=0x1 + A: _raop._tcp.local. PTR IN 4500 [2] 9801A7E58FA1@Hristo's AirPort Express._raop._tcp.local. + A: 9801A7E58FA1@Hristo's AirPort Express._raop._tcp.local. SRV IN FLUSH 120 [32] 5000 Hristos-AirPort-Express.local. + A: Hristo's AirPort Express.local. NSEC IN FLUSH 4500 [9] Hristo's AirPort Express._airport._tcp.local. 00 05 00 00 80 00 40 + A: 9801A7E58FA1@Hristo's AirPort Express.local. NSEC IN FLUSH 4500 [9] 9801A7E58FA1@Hristo's AirPort Express._raop._tcp.local. 00 05 00 00 80 00 40 + +Input: in/test-16.bin +Packet Length: 254 +Answers: 1 + 1 + A: Hristo's Time Capsule._airport._tcp.local. TXT IN FLUSH 4500 [168] waMA=70-73-CB-B4-C9-B3,raMA=70-73-CB-BB-04-E7,raM2=70-73-CB-BB-04-E8,raNm=nbis-test,raCh=11,rCh2=132,raSt=0,raNA=0,syFl=0x820C,syAP=116,syVs=7.6.8,srcv=76800.1,bjSd=30 + A: Hristo's Time Capsule.local. NSEC IN FLUSH 4500 [9] Hristo's Time Capsule._airport._tcp.local. 00 05 00 00 80 00 40 + +Input: in/test-28.bin +Packet Length: 62 +Questions: 1 + Q: Hristo's Time Capsule._afpovertcp._tcp.local. SRV IN FLUSH + +Input: in/test-29.bin +Packet Length: 39 +Questions: 2 + Q: minifritz.local. A IN FLUSH + Q: minifritz.local. AAAA IN FLUSH + +Input: in/test-31.bin +Packet Length: 91 +Answers: 2 + 1 + A: minifritz.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:142e:54ff:b8c4:fd09 + A: minifritz.local. A IN FLUSH 120 [4] 192.168.254.16 + A: minifritz.local. NSEC IN FLUSH 120 [8] minifritz...local. 00 04 40 00 00 08 + +Input: in/test-53.bin +Packet Length: 140 +Questions: 2 + Q: _smb._tcp.local. PTR IN + Q: Sofiya-Ivanovas-MacBook.local. A IN +Answers: 2 + 0 + A: _smb._tcp.local. PTR IN 3061 [29] Sofiya Ivanova’s MacBook._smb._tcp.local. + A: _smb._tcp.local. PTR IN 3062 [24] Hristo's Time Capsule._smb._tcp.local. + +Input: in/test-56.bin +Packet Length: 262 +Answers: 2 + 6 + A: Hristo’s Mac mini._device-info._tcp.local. TXT IN 4500 [28] model=Macmini6,2; osxvers=16 + A: _smb._tcp.local. PTR IN 4500 [22] Hristo’s Mac mini._smb._tcp.local. + A: Hristo’s Mac mini._smb._tcp.local. TXT IN FLUSH 4500 [1] + A: Hristo’s Mac mini._smb._tcp.local. SRV IN FLUSH 120 [18] 445 minifritz.local. + A: minifritz.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:142e:54ff:b8c4:fd09 + A: minifritz.local. A IN FLUSH 120 [4] 192.168.254.16 + A: Hristo’s Mac mini.local. NSEC IN FLUSH 4500 [9] Hristo’s Mac mini._smb._tcp.local. 00 05 00 00 80 00 40 + A: minifritz.local. NSEC IN FLUSH 120 [8] minifritz...local. 00 04 40 00 00 08 + +Input: in/test-63.bin +Packet Length: 147 +Questions: 2 + Q: _afpovertcp._tcp.local. PTR IN + Q: Sofiya-Ivanovas-MacBook.local. A IN +Answers: 2 + 0 + A: _afpovertcp._tcp.local. PTR IN 2881 [29] Sofiya Ivanova’s MacBook._afpovertcp._tcp.local. + A: _afpovertcp._tcp.local. PTR IN 2881 [24] Hristo's Time Capsule._afpovertcp._tcp.local. + +Input: in/test-66.bin +Packet Length: 269 +Answers: 2 + 6 + A: Hristo’s Mac mini._device-info._tcp.local. TXT IN 4500 [28] model=Macmini6,2; osxvers=16 + A: _afpovertcp._tcp.local. PTR IN 4500 [22] Hristo’s Mac mini._afpovertcp._tcp.local. + A: Hristo’s Mac mini._afpovertcp._tcp.local. TXT IN FLUSH 4500 [1] + A: Hristo’s Mac mini._afpovertcp._tcp.local. SRV IN FLUSH 120 [18] 548 minifritz.local. + A: minifritz.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:142e:54ff:b8c4:fd09 + A: minifritz.local. A IN FLUSH 120 [4] 192.168.254.16 + A: Hristo’s Mac mini.local. NSEC IN FLUSH 4500 [9] Hristo’s Mac mini._afpovertcp._tcp.local. 00 05 00 00 80 00 40 + A: minifritz.local. NSEC IN FLUSH 120 [8] minifritz...local. 00 04 40 00 00 08 + +Input: in/test-83.bin +Packet Length: 105 +Answers: 1 + 2 + A: Sofiya-Ivanovas-MacBook.local. A IN FLUSH 120 [4] 192.168.254.20 + A: Sofiya-Ivanovas-MacBook.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:021c:b3ff:feb2:72a3 + A: Sofiya-Ivanovas-MacBook.local. NSEC IN FLUSH 120 [8] Sofiya-Ivanovas-MacBook...local. 00 04 40 00 00 08 + +Input: in/test-88.bin +Packet Length: 48 +Questions: 2 + Q: _rfb._tcp.local. PTR IN + Q: _airport._tcp.local. PTR IN + +Input: in/test-89.bin +Packet Length: 459 +Answers: 2 + 7 + A: _airport._tcp.local. PTR IN 4500 [24] Hristo's Time Capsule._airport._tcp.local. + A: Hristo's Time Capsule._device-info._tcp.local. TXT IN 4500 [23] model=TimeCapsule6,116 + A: Hristos-Time-Capsule.local. A IN FLUSH 120 [4] 192.168.254.49 + A: Hristo's Time Capsule._airport._tcp.local. TXT IN FLUSH 4500 [168] waMA=70-73-CB-B4-C9-B3,raMA=70-73-CB-BB-04-E7,raM2=70-73-CB-BB-04-E8,raNm=nbis-test,raCh=11,rCh2=132,raSt=0,raNA=0,syFl=0x820C,syAP=116,syVs=7.6.8,srcv=76800.1,bjSd=30 + A: Hristos-Time-Capsule.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:7273:cbff:feb4:c9b3 + A: Hristo's Time Capsule._airport._tcp.local. SRV IN FLUSH 120 [8] 5009 Hristos-Time-Capsule.local. + A: Hristos-Time-Capsule.local. A IN FLUSH 120 [4] 169.254.23.40 + A: Hristos-Time-Capsule.local. NSEC IN FLUSH 120 [8] Hristos-Time-Capsule...local. 00 04 40 00 00 08 + A: Hristo's Time Capsule.local. NSEC IN FLUSH 4500 [9] Hristo's Time Capsule._airport._tcp.local. 00 05 00 00 80 00 40 + +Input: in/test-91.bin +Packet Length: 279 +Answers: 2 + 6 + A: Sofiya Ivanova’s MacBook._device-info._tcp.local. TXT IN 4500 [17] model=Macmini2,1 + A: _rfb._tcp.local. PTR IN 4500 [29] Sofiya Ivanova’s MacBook._rfb._tcp.local. + A: Sofiya Ivanova’s MacBook._rfb._tcp.local. TXT IN FLUSH 4500 [1] + A: Sofiya Ivanova’s MacBook._rfb._tcp.local. SRV IN FLUSH 120 [32] 5900 Sofiya-Ivanovas-MacBook.local. + A: Sofiya-Ivanovas-MacBook.local. AAAA IN FLUSH 120 [16] fe80:0000:0000:0000:021c:b3ff:feb2:72a3 + A: Sofiya-Ivanovas-MacBook.local. A IN FLUSH 120 [4] 192.168.254.20 + A: Sofiya Ivanova’s MacBook.local. NSEC IN FLUSH 4500 [9] Sofiya Ivanova’s MacBook._rfb._tcp.local. 00 05 00 00 80 00 40 + A: Sofiya-Ivanovas-MacBook.local. NSEC IN FLUSH 120 [8] Sofiya-Ivanovas-MacBook...local. 00 04 40 00 00 08 + +Input: in/test-95.bin +Packet Length: 286 +Questions: 3 + Q: _afpovertcp._tcp.local. PTR IN + Q: _smb._tcp.local. PTR IN + Q: _adisk._tcp.local. PTR IN +Answers: 6 + 0 + A: _afpovertcp._tcp.local. PTR IN 2353 [29] Sofiya Ivanova’s MacBook._afpovertcp._tcp.local. + A: _afpovertcp._tcp.local. PTR IN 3973 [22] Hristo’s Mac mini._afpovertcp._tcp.local. + A: _afpovertcp._tcp.local. PTR IN 2353 [24] Hristo's Time Capsule._afpovertcp._tcp.local. + A: _smb._tcp.local. PTR IN 2353 [29] Sofiya Ivanova’s MacBook._smb._tcp.local. + A: _smb._tcp.local. PTR IN 3792 [22] Hristo’s Mac mini._smb._tcp.local. + A: _smb._tcp.local. PTR IN 2353 [24] Hristo's Time Capsule._smb._tcp.local. + +Input: in/test-96.bin +Packet Length: 319 +Answers: 2 + 3 + A: Hristo's Time Capsule._device-info._tcp.local. TXT IN 4500 [23] model=TimeCapsule6,116 + A: _adisk._tcp.local. PTR IN 4500 [24] Hristo's Time Capsule._adisk._tcp.local. + A: Hristo's Time Capsule._adisk._tcp.local. TXT IN FLUSH 4500 [110] sys=waMA=70:73:CB:B4:C9:B3,adVF=0x1000; dk2=adVF=0x1083,adVN=Capsule,adVU=55fabb8b-a63b-5441-9874-6edb504eb30a + A: Hristo's Time Capsule._adisk._tcp.local. SRV IN FLUSH 120 [29] 9 Hristos-Time-Capsule.local. + A: Hristo's Time Capsule.local. NSEC IN FLUSH 4500 [9] Hristo's Time Capsule._adisk._tcp.local. 00 05 00 00 80 00 40 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/mdns_di.h b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/mdns_di.h new file mode 100644 index 0000000..ed56960 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/mdns_di.h @@ -0,0 +1,61 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* + * MDNS Dependecy injection -- preincluded to inject interface test functions into static variables + * + */ + +#include "mdns.h" +#include "mdns_private.h" + +void (*mdns_test_static_execute_action)(mdns_action_t *) = NULL; +mdns_srv_item_t *(*mdns_test_static_mdns_get_service_item)(const char *service, const char *proto, const char *hostname) = NULL; +mdns_search_once_t *(*mdns_test_static_search_init)(const char *name, const char *service, const char *proto, uint16_t type, bool unicast, + uint32_t timeout, uint8_t max_results, + mdns_query_notify_t notifier) = NULL; +esp_err_t (*mdns_test_static_send_search_action)(mdns_action_type_t type, mdns_search_once_t *search) = NULL; +void (*mdns_test_static_search_free)(mdns_search_once_t *search) = NULL; + +static void _mdns_execute_action(mdns_action_t *action); +static mdns_srv_item_t *_mdns_get_service_item(const char *service, const char *proto, const char *hostname); +static mdns_search_once_t *_mdns_search_init(const char *name, const char *service, const char *proto, uint16_t type, bool unicast, + uint32_t timeout, uint8_t max_results, mdns_query_notify_t notifier); +static esp_err_t _mdns_send_search_action(mdns_action_type_t type, mdns_search_once_t *search); +static void _mdns_search_free(mdns_search_once_t *search); + +void mdns_test_init_di(void) +{ + mdns_test_static_execute_action = _mdns_execute_action; + mdns_test_static_mdns_get_service_item = _mdns_get_service_item; + mdns_test_static_search_init = _mdns_search_init; + mdns_test_static_send_search_action = _mdns_send_search_action; + mdns_test_static_search_free = _mdns_search_free; +} + +void mdns_test_execute_action(void *action) +{ + mdns_test_static_execute_action((mdns_action_t *)action); +} + +void mdns_test_search_free(mdns_search_once_t *search) +{ + return mdns_test_static_search_free(search); +} + +esp_err_t mdns_test_send_search_action(mdns_action_type_t type, mdns_search_once_t *search) +{ + return mdns_test_static_send_search_action(type, search); +} + +mdns_search_once_t *mdns_test_search_init(const char *name, const char *service, const char *proto, uint16_t type, uint32_t timeout, uint8_t max_results) +{ + return mdns_test_static_search_init(name, service, proto, type, timeout, type != MDNS_TYPE_PTR, max_results, NULL); +} + +mdns_srv_item_t *mdns_test_mdns_get_service_item(const char *service, const char *proto) +{ + return mdns_test_static_mdns_get_service_item(service, proto, NULL); +} diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/mdns_mock.h b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/mdns_mock.h new file mode 100644 index 0000000..d37da92 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/mdns_mock.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#pragma once +#include "esp32_mock.h" +#include "mdns.h" +#include "mdns_private.h" + + +static inline void *_mdns_get_packet_data(mdns_rx_packet_t *packet) +{ + return packet->pb->payload; +} + +static inline size_t _mdns_get_packet_len(mdns_rx_packet_t *packet) +{ + return packet->pb->len; +} + +static inline void _mdns_packet_free(mdns_rx_packet_t *packet) +{ + free(packet->pb); + free(packet); +} + +static inline bool mdns_is_netif_ready(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol) +{ + return true; +} diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/sdkconfig.h b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/sdkconfig.h new file mode 100644 index 0000000..da75d14 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/sdkconfig.h @@ -0,0 +1,424 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* + * This config file commited in order to not run `idf.py reconfigure` each time when running fuzzer test. You can modify it manually or run `idf.py reconfigure` to generate new one if needed. + * Espressif IoT Development Framework (ESP-IDF) Configuration Header + */ +#pragma once +#define CONFIG_IDF_TARGET "esp32" +#define CONFIG_IDF_TARGET_ESP32 1 +#define CONFIG_IDF_FIRMWARE_CHIP_ID 0x0000 +#define CONFIG_SDK_TOOLPREFIX "xtensa-esp32-elf-" +#define CONFIG_APP_BUILD_TYPE_APP_2NDBOOT 1 +#define CONFIG_APP_BUILD_GENERATE_BINARIES 1 +#define CONFIG_APP_BUILD_BOOTLOADER 1 +#define CONFIG_APP_BUILD_USE_FLASH_SECTIONS 1 +#define CONFIG_APP_COMPILE_TIME_DATE 1 +#define CONFIG_APP_RETRIEVE_LEN_ELF_SHA 16 +#define CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE 1 +#define CONFIG_BOOTLOADER_LOG_LEVEL_INFO 1 +#define CONFIG_BOOTLOADER_LOG_LEVEL 3 +#define CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V 1 +#define CONFIG_BOOTLOADER_WDT_ENABLE 1 +#define CONFIG_BOOTLOADER_WDT_TIME_MS 9000 +#define CONFIG_BOOTLOADER_RESERVE_RTC_SIZE 0x0 +#define CONFIG_ESPTOOLPY_WITH_STUB 1 +#define CONFIG_ESPTOOLPY_FLASHMODE_DIO 1 +#define CONFIG_ESPTOOLPY_FLASHMODE "dio" +#define CONFIG_ESPTOOLPY_FLASHFREQ_40M 1 +#define CONFIG_ESPTOOLPY_FLASHFREQ "40m" +#define CONFIG_ESPTOOLPY_FLASHSIZE_2MB 1 +#define CONFIG_ESPTOOLPY_FLASHSIZE "2MB" +#define CONFIG_ESPTOOLPY_FLASHSIZE_DETECT 1 +#define CONFIG_ESPTOOLPY_BEFORE_RESET 1 +#define CONFIG_ESPTOOLPY_BEFORE "default_reset" +#define CONFIG_ESPTOOLPY_AFTER_RESET 1 +#define CONFIG_ESPTOOLPY_AFTER "hard_reset" +#define CONFIG_PARTITION_TABLE_SINGLE_APP 1 +#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv" +#define CONFIG_PARTITION_TABLE_FILENAME "partitions_singleapp.csv" +#define CONFIG_PARTITION_TABLE_OFFSET 0x8000 +#define CONFIG_PARTITION_TABLE_MD5 1 +#define CONFIG_COMPILER_OPTIMIZATION_DEFAULT 1 +#define CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE 1 +#define CONFIG_COMPILER_STACK_CHECK_MODE_NONE 1 +#define CONFIG_APPTRACE_DEST_NONE 1 +#define CONFIG_APPTRACE_LOCK_ENABLE 1 +#define CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF 0 +#define CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF 0 +#define CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF 0 +#define CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF 0 +#define CONFIG_BTDM_CTRL_PINNED_TO_CORE 0 +#define CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF 1 +#define CONFIG_BTDM_RESERVE_DRAM 0x0 +#define CONFIG_COAP_MBEDTLS_PSK 1 +#define CONFIG_COAP_LOG_DEFAULT_LEVEL 0 +#define CONFIG_ADC_DISABLE_DAC 1 +#define CONFIG_SPI_MASTER_ISR_IN_IRAM 1 +#define CONFIG_SPI_SLAVE_ISR_IN_IRAM 1 +#define CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4 1 +#define CONFIG_EFUSE_MAX_BLK_LEN 192 +#define CONFIG_ESP_TLS_USING_MBEDTLS 1 +#define CONFIG_ESP32_REV_MIN_0 1 +#define CONFIG_ESP32_REV_MIN 0 +#define CONFIG_ESP32_DPORT_WORKAROUND 1 +#define CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160 1 +#define CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ 160 +#define CONFIG_ESP32_TRACEMEM_RESERVE_DRAM 0x0 +#define CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR 1 +#define CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES 4 +#define CONFIG_ULP_COPROC_RESERVE_MEM 0 +#define CONFIG_ESP_DEBUG_OCDAWARE 1 +#define CONFIG_ESP_BROWNOUT_DET 1 +#define CONFIG_ESP_BROWNOUT_DET_LVL_SEL_0 1 +#define CONFIG_ESP_BROWNOUT_DET_LVL 0 +#define CONFIG_ESP32_REDUCE_PHY_TX_POWER 1 +#define CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT 1 +#define CONFIG_RTC_CLK_SRC_INT_RC 1 +#define CONFIG_RTC_CLK_CAL_CYCLES 1024 +#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000 +#define CONFIG_ESP32_XTAL_FREQ_40 1 +#define CONFIG_ESP32_XTAL_FREQ 40 +#define CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL 5 +#define CONFIG_ADC_CAL_EFUSE_TP_ENABLE 1 +#define CONFIG_ADC_CAL_EFUSE_VREF_ENABLE 1 +#define CONFIG_ADC_CAL_LUT_ENABLE 1 +#define CONFIG_ESP_ERR_TO_NAME_LOOKUP 1 +#define CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE 32 +#define CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE 2304 +#define CONFIG_ESP_MAIN_TASK_STACK_SIZE 3584 +#define CONFIG_ESP_IPC_TASK_STACK_SIZE 1024 +#define CONFIG_ESP_IPC_USES_CALLERS_PRIORITY 1 +#define CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE 2048 +#define CONFIG_ESP_CONSOLE_UART_DEFAULT 1 +#define CONFIG_ESP_CONSOLE_UART_NUM 0 +#define CONFIG_ESP_CONSOLE_UART_TX_GPIO 1 +#define CONFIG_ESP_CONSOLE_UART_RX_GPIO 3 +#define CONFIG_ESP_CONSOLE_UART_BAUDRATE 115200 +#define CONFIG_ESP_INT_WDT 1 +#define CONFIG_ESP_INT_WDT_TIMEOUT_MS 300 +#define CONFIG_ESP_INT_WDT_CHECK_CPU1 1 +#define CONFIG_ESP_TASK_WDT 1 +#define CONFIG_ESP_TASK_WDT_TIMEOUT_S 5 +#define CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 1 +#define CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 1 +#define CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA 1 +#define CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP 1 +#define CONFIG_ESP_MAC_ADDR_UNIVERSE_BT 1 +#define CONFIG_ESP_MAC_ADDR_UNIVERSE_BT_OFFSET 2 +#define CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH 1 +#define CONFIG_ETH_ENABLED 1 +#define CONFIG_ETH_USE_ESP32_EMAC 1 +#define CONFIG_ETH_PHY_INTERFACE_RMII 1 +#define CONFIG_ETH_RMII_CLK_INPUT 1 +#define CONFIG_ETH_RMII_CLK_IN_GPIO 0 +#define CONFIG_ETH_DMA_BUFFER_SIZE 512 +#define CONFIG_ETH_DMA_RX_BUFFER_NUM 10 +#define CONFIG_ETH_DMA_TX_BUFFER_NUM 10 +#define CONFIG_ETH_USE_SPI_ETHERNET 1 +#define CONFIG_ESP_EVENT_POST_FROM_ISR 1 +#define CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR 1 +#define CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS 1 +#define CONFIG_HTTPD_MAX_REQ_HDR_LEN 512 +#define CONFIG_HTTPD_MAX_URI_LEN 512 +#define CONFIG_HTTPD_ERR_RESP_NO_DELAY 1 +#define CONFIG_HTTPD_PURGE_BUF_LEN 32 +#define CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL 120 +#define CONFIG_ESP_NETIF_TCPIP_LWIP 1 +#define CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT 1 +#define CONFIG_ESP_TIMER_TASK_STACK_SIZE 3584 +#define CONFIG_ESP_TIMER_IMPL_TG0_LAC 1 +#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 10 +#define CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM 32 +#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER 1 +#define CONFIG_ESP32_WIFI_TX_BUFFER_TYPE 1 +#define CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM 32 +#define CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED 1 +#define CONFIG_ESP32_WIFI_TX_BA_WIN 6 +#define CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED 1 +#define CONFIG_ESP32_WIFI_RX_BA_WIN 6 +#define CONFIG_ESP32_WIFI_NVS_ENABLED 1 +#define CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0 1 +#define CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN 752 +#define CONFIG_ESP32_WIFI_MGMT_SBUF_NUM 32 +#define CONFIG_ESP32_WIFI_IRAM_OPT 1 +#define CONFIG_ESP32_WIFI_RX_IRAM_OPT 1 +#define CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE 1 +#define CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE 1 +#define CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER 20 +#define CONFIG_ESP32_PHY_MAX_TX_POWER 20 +#define CONFIG_ESP_COREDUMP_ENABLE_TO_NONE 1 +#define CONFIG_FATFS_CODEPAGE_437 1 +#define CONFIG_FATFS_CODEPAGE 437 +#define CONFIG_FATFS_LFN_NONE 1 +#define CONFIG_FATFS_FS_LOCK 0 +#define CONFIG_FATFS_TIMEOUT_MS 10000 +#define CONFIG_FATFS_PER_FILE_CACHE 1 +#define CONFIG_FMB_COMM_MODE_RTU_EN 1 +#define CONFIG_FMB_COMM_MODE_ASCII_EN 1 +#define CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND 150 +#define CONFIG_FMB_MASTER_DELAY_MS_CONVERT 200 +#define CONFIG_FMB_QUEUE_LENGTH 20 +#define CONFIG_FMB_SERIAL_TASK_STACK_SIZE 2048 +#define CONFIG_FMB_SERIAL_BUF_SIZE 256 +#define CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB 8 +#define CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS 1000 +#define CONFIG_FMB_SERIAL_TASK_PRIO 10 +#define CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT 20 +#define CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE 20 +#define CONFIG_FMB_CONTROLLER_STACK_SIZE 4096 +#define CONFIG_FMB_EVENT_QUEUE_TIMEOUT 20 +#define CONFIG_FMB_TIMER_PORT_ENABLED 1 +#define CONFIG_FMB_TIMER_GROUP 0 +#define CONFIG_FMB_TIMER_INDEX 0 +#define CONFIG_FREERTOS_NO_AFFINITY 0x7FFFFFFF +#define CONFIG_FREERTOS_CORETIMER_0 1 +#define CONFIG_FREERTOS_HZ 100 +#define CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 1 +#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY 1 +#define CONFIG_FREERTOS_INTERRUPT_BACKTRACE 1 +#define CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS 1 +#define CONFIG_FREERTOS_IDLE_TASK_STACKSIZE 1536 +#define CONFIG_FREERTOS_ISR_STACKSIZE 1536 +#define CONFIG_FREERTOS_MAX_TASK_NAME_LEN 16 +#define CONFIG_FREERTOS_TIMER_TASK_PRIORITY 1 +#define CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH 2048 +#define CONFIG_FREERTOS_TIMER_QUEUE_LENGTH 10 +#define CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE 0 +#define CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER 1 +#define CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER 1 +#define CONFIG_FREERTOS_DEBUG_OCDAWARE 1 +#define CONFIG_HEAP_POISONING_DISABLED 1 +#define CONFIG_HEAP_TRACING_OFF 1 +#define CONFIG_LOG_DEFAULT_LEVEL_INFO 1 +#define CONFIG_LOG_DEFAULT_LEVEL 3 +#define CONFIG_LOG_MAXIMUM_LEVEL 3 +#define CONFIG_LOG_COLORS 1 +#define CONFIG_LOG_TIMESTAMP_SOURCE_RTOS 1 +#define CONFIG_LWIP_LOCAL_HOSTNAME "espressif" +#define CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES 1 +#define CONFIG_LWIP_TIMERS_ONDEMAND 1 +#define CONFIG_LWIP_MAX_SOCKETS 10 +#define CONFIG_LWIP_SO_REUSE 1 +#define CONFIG_LWIP_SO_REUSE_RXTOALL 1 +#define CONFIG_LWIP_IP_FRAG 1 +#define CONFIG_LWIP_ESP_GRATUITOUS_ARP 1 +#define CONFIG_LWIP_GARP_TMR_INTERVAL 60 +#define CONFIG_LWIP_TCPIP_RECVMBOX_SIZE 32 +#define CONFIG_LWIP_DHCP_DOES_ARP_CHECK 1 +#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60 +#define CONFIG_LWIP_DHCPS_MAX_STATION_NUM 8 +#define CONFIG_LWIP_NETIF_LOOPBACK 1 +#define CONFIG_LWIP_LOOPBACK_MAX_PBUFS 8 +#define CONFIG_LWIP_MAX_ACTIVE_TCP 16 +#define CONFIG_LWIP_MAX_LISTENING_TCP 16 +#define CONFIG_LWIP_TCP_MAXRTX 12 +#define CONFIG_LWIP_TCP_SYNMAXRTX 6 +#define CONFIG_LWIP_TCP_MSS 1440 +#define CONFIG_LWIP_TCP_TMR_INTERVAL 250 +#define CONFIG_LWIP_TCP_MSL 60000 +#define CONFIG_LWIP_TCP_SND_BUF_DEFAULT 5744 +#define CONFIG_LWIP_TCP_WND_DEFAULT 5744 +#define CONFIG_LWIP_TCP_RECVMBOX_SIZE 6 +#define CONFIG_LWIP_TCP_QUEUE_OOSEQ 1 +#define CONFIG_LWIP_TCP_OVERSIZE_MSS 1 +#define CONFIG_LWIP_MAX_UDP_PCBS 16 +#define CONFIG_LWIP_UDP_RECVMBOX_SIZE 6 +#define CONFIG_LWIP_TCPIP_TASK_STACK_SIZE 3072 +#define CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY 1 +#define CONFIG_LWIP_TCPIP_TASK_AFFINITY 0x7FFFFFFF +#define CONFIG_LWIP_MAX_RAW_PCBS 16 +#define CONFIG_LWIP_DHCP_MAX_NTP_SERVERS 1 +#define CONFIG_LWIP_SNTP_UPDATE_DELAY 3600000 +#define CONFIG_LWIP_ESP_LWIP_ASSERT 1 +#define CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC 1 +#define CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN 1 +#define CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN 16384 +#define CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN 4096 +#define CONFIG_MBEDTLS_CERTIFICATE_BUNDLE 1 +#define CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL 1 +#define CONFIG_MBEDTLS_HARDWARE_AES 1 +#define CONFIG_MBEDTLS_HARDWARE_MPI 1 +#define CONFIG_MBEDTLS_HARDWARE_SHA 1 +#define CONFIG_MBEDTLS_HAVE_TIME 1 +#define CONFIG_MBEDTLS_ECDSA_DETERMINISTIC 1 +#define CONFIG_MBEDTLS_SHA512_C 1 +#define CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT 1 +#define CONFIG_MBEDTLS_TLS_SERVER 1 +#define CONFIG_MBEDTLS_TLS_CLIENT 1 +#define CONFIG_MBEDTLS_TLS_ENABLED 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA 1 +#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA 1 +#define CONFIG_MBEDTLS_SSL_RENEGOTIATION 1 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1 1 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_1 1 +#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_2 1 +#define CONFIG_MBEDTLS_SSL_ALPN 1 +#define CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS 1 +#define CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS 1 +#define CONFIG_MBEDTLS_AES_C 1 +#define CONFIG_MBEDTLS_RC4_DISABLED 1 +#define CONFIG_MBEDTLS_CCM_C 1 +#define CONFIG_MBEDTLS_GCM_C 1 +#define CONFIG_MBEDTLS_PEM_PARSE_C 1 +#define CONFIG_MBEDTLS_PEM_WRITE_C 1 +#define CONFIG_MBEDTLS_X509_CRL_PARSE_C 1 +#define CONFIG_MBEDTLS_X509_CSR_PARSE_C 1 +#define CONFIG_MBEDTLS_ECP_C 1 +#define CONFIG_MBEDTLS_ECDH_C 1 +#define CONFIG_MBEDTLS_ECDSA_C 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED 1 +#define CONFIG_MBEDTLS_ECP_NIST_OPTIM 1 +#define CONFIG_MDNS_MAX_SERVICES 25 +#define CONFIG_MDNS_MAX_INTERFACES 3 +#define CONFIG_MDNS_TASK_PRIORITY 1 +#define CONFIG_MDNS_ACTION_QUEUE_LEN 16 +#define CONFIG_MDNS_TASK_STACK_SIZE 4096 +#define CONFIG_MDNS_TASK_AFFINITY_CPU0 1 +#define CONFIG_MDNS_TASK_AFFINITY 0x0 +#define CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS 1 +#define CONFIG_MDNS_TIMER_PERIOD_MS 100 +#define CONFIG_MQTT_PROTOCOL_311 1 +#define CONFIG_MQTT_TRANSPORT_SSL 1 +#define CONFIG_MQTT_TRANSPORT_WEBSOCKET 1 +#define CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE 1 +#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF 1 +#define CONFIG_NEWLIB_STDIN_LINE_ENDING_CR 1 +#define CONFIG_OPENSSL_ASSERT_EXIT 1 +#define CONFIG_PTHREAD_TASK_PRIO_DEFAULT 5 +#define CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT 3072 +#define CONFIG_PTHREAD_STACK_MIN 768 +#define CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY 1 +#define CONFIG_PTHREAD_TASK_CORE_DEFAULT -1 +#define CONFIG_PTHREAD_TASK_NAME_DEFAULT "pthread" +#define CONFIG_SPI_FLASH_ROM_DRIVER_PATCH 1 +#define CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS 1 +#define CONFIG_SPI_FLASH_YIELD_DURING_ERASE 1 +#define CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS 20 +#define CONFIG_SPI_FLASH_ERASE_YIELD_TICKS 1 +#define CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP 1 +#define CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP 1 +#define CONFIG_SPI_FLASH_SUPPORT_GD_CHIP 1 +#define CONFIG_SPIFFS_MAX_PARTITIONS 3 +#define CONFIG_SPIFFS_CACHE 1 +#define CONFIG_SPIFFS_CACHE_WR 1 +#define CONFIG_SPIFFS_PAGE_CHECK 1 +#define CONFIG_SPIFFS_GC_MAX_RUNS 10 +#define CONFIG_SPIFFS_PAGE_SIZE 256 +#define CONFIG_SPIFFS_OBJ_NAME_LEN 32 +#define CONFIG_SPIFFS_USE_MAGIC 1 +#define CONFIG_SPIFFS_USE_MAGIC_LENGTH 1 +#define CONFIG_SPIFFS_META_LENGTH 4 +#define CONFIG_SPIFFS_USE_MTIME 1 +#define CONFIG_USB_DESC_CUSTOM_VID 0x1234 +#define CONFIG_USB_DESC_CUSTOM_PID 0x5678 +#define CONFIG_UNITY_ENABLE_FLOAT 1 +#define CONFIG_UNITY_ENABLE_DOUBLE 1 +#define CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER 1 +#define CONFIG_VFS_SUPPORT_IO 1 +#define CONFIG_VFS_SUPPORT_DIR 1 +#define CONFIG_VFS_SUPPORT_SELECT 1 +#define CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT 1 +#define CONFIG_VFS_SUPPORT_TERMIOS 1 +#define CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS 1 +#define CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN 128 +#define CONFIG_WL_SECTOR_SIZE_4096 1 +#define CONFIG_WL_SECTOR_SIZE 4096 +#define CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES 16 +#define CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT 30 +#define CONFIG_WPA_MBEDTLS_CRYPTO 1 + +/* List of deprecated options */ +#define CONFIG_ADC2_DISABLE_DAC CONFIG_ADC_DISABLE_DAC +#define CONFIG_BROWNOUT_DET CONFIG_ESP_BROWNOUT_DET +#define CONFIG_BROWNOUT_DET_LVL_SEL_0 CONFIG_ESP_BROWNOUT_DET_LVL_SEL_0 +#define CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG CONFIG_COMPILER_OPTIMIZATION_DEFAULT +#define CONFIG_CONSOLE_UART_BAUDRATE CONFIG_ESP_CONSOLE_UART_BAUDRATE +#define CONFIG_CONSOLE_UART_DEFAULT CONFIG_ESP_CONSOLE_UART_DEFAULT +#define CONFIG_CONSOLE_UART_RX_GPIO CONFIG_ESP_CONSOLE_UART_RX_GPIO +#define CONFIG_CONSOLE_UART_TX_GPIO CONFIG_ESP_CONSOLE_UART_TX_GPIO +#define CONFIG_ESP32S2_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT +#define CONFIG_ESP32_APPTRACE_DEST_NONE CONFIG_APPTRACE_DEST_NONE +#define CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY +#define CONFIG_ESP32_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT +#define CONFIG_ESP32_PTHREAD_STACK_MIN CONFIG_PTHREAD_STACK_MIN +#define CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT CONFIG_PTHREAD_TASK_NAME_DEFAULT +#define CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT CONFIG_PTHREAD_TASK_PRIO_DEFAULT +#define CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT +#define CONFIG_ESP_GRATUITOUS_ARP CONFIG_LWIP_ESP_GRATUITOUS_ARP +#define CONFIG_FLASHMODE_DIO CONFIG_ESPTOOLPY_FLASHMODE_DIO +#define CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR +#define CONFIG_GARP_TMR_INTERVAL CONFIG_LWIP_GARP_TMR_INTERVAL +#define CONFIG_INT_WDT CONFIG_ESP_INT_WDT +#define CONFIG_INT_WDT_CHECK_CPU1 CONFIG_ESP_INT_WDT_CHECK_CPU1 +#define CONFIG_INT_WDT_TIMEOUT_MS CONFIG_ESP_INT_WDT_TIMEOUT_MS +#define CONFIG_IPC_TASK_STACK_SIZE CONFIG_ESP_IPC_TASK_STACK_SIZE +#define CONFIG_LOG_BOOTLOADER_LEVEL_INFO CONFIG_BOOTLOADER_LOG_LEVEL_INFO +#define CONFIG_MAIN_TASK_STACK_SIZE CONFIG_ESP_MAIN_TASK_STACK_SIZE +#define CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE +#define CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT +#define CONFIG_MB_CONTROLLER_STACK_SIZE CONFIG_FMB_CONTROLLER_STACK_SIZE +#define CONFIG_MB_EVENT_QUEUE_TIMEOUT CONFIG_FMB_EVENT_QUEUE_TIMEOUT +#define CONFIG_MB_MASTER_DELAY_MS_CONVERT CONFIG_FMB_MASTER_DELAY_MS_CONVERT +#define CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND +#define CONFIG_MB_QUEUE_LENGTH CONFIG_FMB_QUEUE_LENGTH +#define CONFIG_MB_SERIAL_BUF_SIZE CONFIG_FMB_SERIAL_BUF_SIZE +#define CONFIG_MB_SERIAL_TASK_PRIO CONFIG_FMB_SERIAL_TASK_PRIO +#define CONFIG_MB_SERIAL_TASK_STACK_SIZE CONFIG_FMB_SERIAL_TASK_STACK_SIZE +#define CONFIG_MB_TIMER_GROUP CONFIG_FMB_TIMER_GROUP +#define CONFIG_MB_TIMER_INDEX CONFIG_FMB_TIMER_INDEX +#define CONFIG_MB_TIMER_PORT_ENABLED CONFIG_FMB_TIMER_PORT_ENABLED +#define CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE +#define CONFIG_OPTIMIZATION_LEVEL_DEBUG CONFIG_COMPILER_OPTIMIZATION_DEFAULT +#define CONFIG_POST_EVENTS_FROM_IRAM_ISR CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR +#define CONFIG_POST_EVENTS_FROM_ISR CONFIG_ESP_EVENT_POST_FROM_ISR +#define CONFIG_REDUCE_PHY_TX_POWER CONFIG_ESP32_REDUCE_PHY_TX_POWER +#define CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN +#define CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS +#define CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS +#define CONFIG_STACK_CHECK_NONE CONFIG_COMPILER_STACK_CHECK_MODE_NONE +#define CONFIG_SUPPORT_TERMIOS CONFIG_VFS_SUPPORT_TERMIOS +#define CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT +#define CONFIG_SYSTEM_EVENT_QUEUE_SIZE CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE +#define CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE +#define CONFIG_TASK_WDT CONFIG_ESP_TASK_WDT +#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 +#define CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 +#define CONFIG_TASK_WDT_TIMEOUT_S CONFIG_ESP_TASK_WDT_TIMEOUT_S +#define CONFIG_TCPIP_RECVMBOX_SIZE CONFIG_LWIP_TCPIP_RECVMBOX_SIZE +#define CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY +#define CONFIG_TCPIP_TASK_STACK_SIZE CONFIG_LWIP_TCPIP_TASK_STACK_SIZE +#define CONFIG_TCP_MAXRTX CONFIG_LWIP_TCP_MAXRTX +#define CONFIG_TCP_MSL CONFIG_LWIP_TCP_MSL +#define CONFIG_TCP_MSS CONFIG_LWIP_TCP_MSS +#define CONFIG_TCP_OVERSIZE_MSS CONFIG_LWIP_TCP_OVERSIZE_MSS +#define CONFIG_TCP_QUEUE_OOSEQ CONFIG_LWIP_TCP_QUEUE_OOSEQ +#define CONFIG_TCP_RECVMBOX_SIZE CONFIG_LWIP_TCP_RECVMBOX_SIZE +#define CONFIG_TCP_SND_BUF_DEFAULT CONFIG_LWIP_TCP_SND_BUF_DEFAULT +#define CONFIG_TCP_SYNMAXRTX CONFIG_LWIP_TCP_SYNMAXRTX +#define CONFIG_TCP_WND_DEFAULT CONFIG_LWIP_TCP_WND_DEFAULT +#define CONFIG_TIMER_QUEUE_LENGTH CONFIG_FREERTOS_TIMER_QUEUE_LENGTH +#define CONFIG_TIMER_TASK_PRIORITY CONFIG_FREERTOS_TIMER_TASK_PRIORITY +#define CONFIG_TIMER_TASK_STACK_DEPTH CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH +#define CONFIG_TIMER_TASK_STACK_SIZE CONFIG_ESP_TIMER_TASK_STACK_SIZE +#define CONFIG_TOOLPREFIX CONFIG_SDK_TOOLPREFIX +#define CONFIG_UDP_RECVMBOX_SIZE CONFIG_LWIP_UDP_RECVMBOX_SIZE diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/test.c b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/test.c new file mode 100644 index 0000000..5556c56 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/test.c @@ -0,0 +1,276 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "esp32_mock.h" +#include "mdns.h" +#include "mdns_private.h" + +// +// Global stuctures containing packet payload, search +mdns_rx_packet_t g_packet; +struct pbuf mypbuf; +mdns_search_once_t *search = NULL; + +// +// Dependency injected test functions +void mdns_test_execute_action(void *action); +mdns_srv_item_t *mdns_test_mdns_get_service_item(const char *service, const char *proto); +mdns_search_once_t *mdns_test_search_init(const char *name, const char *service, const char *proto, uint16_t type, uint32_t timeout, uint8_t max_results); +esp_err_t mdns_test_send_search_action(mdns_action_type_t type, mdns_search_once_t *search); +void mdns_test_search_free(mdns_search_once_t *search); +void mdns_test_init_di(void); +extern mdns_server_t *_mdns_server; + +// +// mdns function wrappers for mdns setup in test mode +static int mdns_test_hostname_set(const char *mdns_hostname) +{ + for (int i = 0; i < MDNS_MAX_INTERFACES; i++) { + _mdns_server->interfaces[i].pcbs[MDNS_IP_PROTOCOL_V4].state = PCB_RUNNING; // mark the PCB running to exercise mdns in fully operational mode + _mdns_server->interfaces[i].pcbs[MDNS_IP_PROTOCOL_V6].state = PCB_RUNNING; + } + int ret = mdns_hostname_set(mdns_hostname); + mdns_action_t *a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return ret; +} + +static int mdns_test_add_delegated_host(const char *mdns_hostname) +{ + mdns_ip_addr_t addr = { .addr = { .u_addr = ESP_IPADDR_TYPE_V4 } }; + addr.addr.u_addr.ip4.addr = 0x11111111; + int ret = mdns_delegate_hostname_add(mdns_hostname, &addr); + mdns_action_t *a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return ret; +} + + +static int mdns_test_service_instance_name_set(const char *service, const char *proto, const char *instance) +{ + int ret = mdns_service_instance_name_set(service, proto, instance); + mdns_action_t *a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return ret; +} + +static int mdns_test_service_txt_set(const char *service, const char *proto, uint8_t num_items, mdns_txt_item_t txt[]) +{ + int ret = mdns_service_txt_set(service, proto, txt, num_items); + mdns_action_t *a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return ret; +} + +static int mdns_test_sub_service_add(const char *sub_name, const char *service_name, const char *proto, uint32_t port) +{ + if (mdns_service_add(NULL, service_name, proto, port, NULL, 0)) { + // This is expected failure as the service thread is not running + } + mdns_action_t *a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + + if (mdns_test_mdns_get_service_item(service_name, proto) == NULL) { + return ESP_FAIL; + } + int ret = mdns_service_subtype_add_for_host(NULL, service_name, proto, NULL, sub_name); + a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return ret; +} + +static int mdns_test_service_add(const char *service_name, const char *proto, uint32_t port) +{ + if (mdns_service_add(NULL, service_name, proto, port, NULL, 0)) { + // This is expected failure as the service thread is not running + } + mdns_action_t *a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + + if (mdns_test_mdns_get_service_item(service_name, proto) == NULL) { + return ESP_FAIL; + } + return ESP_OK; +} + +static mdns_result_t *mdns_test_query(const char *name, const char *service, const char *proto, uint16_t type) +{ + search = mdns_test_search_init(name, service, proto, type, 3000, 20); + if (!search) { + abort(); + } + + if (mdns_test_send_search_action(ACTION_SEARCH_ADD, search)) { + mdns_test_search_free(search); + abort(); + } + + mdns_action_t *a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); + return NULL; +} + +static void mdns_test_query_free(void) +{ + mdns_test_search_free(search); +} + +// +// function "under test" where afl-mangled packets passed +// +void mdns_parse_packet(mdns_rx_packet_t *packet); + +// +// Test starts here +// +int main(int argc, char **argv) +{ + int i; + const char *mdns_hostname = "minifritz"; + const char *mdns_instance = "Hristo's Time Capsule"; + mdns_txt_item_t arduTxtData[4] = { + {"board", "esp32"}, + {"tcp_check", "no"}, + {"ssh_upload", "no"}, + {"auth_upload", "no"} + }; + + const uint8_t mac[6] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x32}; + + uint8_t buf[1460]; + char winstance[21 + strlen(mdns_hostname)]; + + sprintf(winstance, "%s [%02x:%02x:%02x:%02x:%02x:%02x]", mdns_hostname, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + // Init depencency injected methods + mdns_test_init_di(); + + if (mdns_init()) { + abort(); + } + + if (mdns_test_hostname_set(mdns_hostname)) { + abort(); + } + + if (mdns_test_add_delegated_host(mdns_hostname) || mdns_test_add_delegated_host("megafritz")) { + abort(); + } + +#ifndef MDNS_NO_SERVICES + + if (mdns_test_sub_service_add("_server", "_fritz", "_tcp", 22)) { + abort(); + } + + if (mdns_test_service_add("_telnet", "_tcp", 22)) { + abort(); + } + + if (mdns_test_service_add("_workstation", "_tcp", 9)) { + abort(); + } + if (mdns_test_service_instance_name_set("_workstation", "_tcp", winstance)) { + abort(); + } + + if (mdns_test_service_add("_arduino", "_tcp", 3232)) { + abort(); + } + + if (mdns_test_service_txt_set("_arduino", "_tcp", 4, arduTxtData)) { + abort(); + } + + if (mdns_test_service_add("_http", "_tcp", 80)) { + abort(); + } + + if (mdns_test_service_instance_name_set("_http", "_tcp", "ESP WebServer")) { + abort(); + } + + if ( + mdns_test_service_add("_afpovertcp", "_tcp", 548) + || mdns_test_service_add("_rfb", "_tcp", 885) + || mdns_test_service_add("_smb", "_tcp", 885) + || mdns_test_service_add("_adisk", "_tcp", 885) + || mdns_test_service_add("_airport", "_tcp", 885) + || mdns_test_service_add("_printer", "_tcp", 885) + || mdns_test_service_add("_airplay", "_tcp", 885) + || mdns_test_service_add("_raop", "_tcp", 885) + || mdns_test_service_add("_uscan", "_tcp", 885) + || mdns_test_service_add("_uscans", "_tcp", 885) + || mdns_test_service_add("_ippusb", "_tcp", 885) + || mdns_test_service_add("_scanner", "_tcp", 885) + || mdns_test_service_add("_ipp", "_tcp", 885) + || mdns_test_service_add("_ipps", "_tcp", 885) + || mdns_test_service_add("_pdl-datastream", "_tcp", 885) + || mdns_test_service_add("_ptp", "_tcp", 885) + || mdns_test_service_add("_sleep-proxy", "_udp", 885)) { + abort(); + } +#endif + mdns_result_t *results = NULL; + FILE *file; + size_t nread; + +#ifdef INSTR_IS_OFF + size_t len = 1460; + memset(buf, 0, 1460); + + if (argc != 2) { + printf("Non-instrumentation mode: please supply a file name created by AFL to reproduce crash\n"); + return 1; + } else { + // + // Note: parameter1 is a file (mangled packet) which caused the crash + file = fopen(argv[1], "r"); + assert(file >= 0 ); + len = fread(buf, 1, 1460, file); + fclose(file); + } + + for (i = 0; i < 1; i++) { +#else + while (__AFL_LOOP(1000)) { + memset(buf, 0, 1460); + size_t len = read(0, buf, 1460); +#endif + mypbuf.payload = malloc(len); + memcpy(mypbuf.payload, buf, len); + mypbuf.len = len; + g_packet.pb = &mypbuf; + mdns_test_query("minifritz", "_fritz", "_tcp", MDNS_TYPE_ANY); + mdns_test_query(NULL, "_fritz", "_tcp", MDNS_TYPE_PTR); + mdns_test_query(NULL, "_afpovertcp", "_tcp", MDNS_TYPE_PTR); + mdns_parse_packet(&g_packet); + free(mypbuf.payload); + } +#ifndef MDNS_NO_SERVICES + mdns_service_remove_all(); + mdns_action_t *a = NULL; + GetLastItem(&a); + mdns_test_execute_action(a); +#endif + ForceTaskDelete(); + mdns_free(); + return 0; +} diff --git a/managed_components/espressif__mdns/tests/test_apps/CMakeLists.txt b/managed_components/espressif__mdns/tests/test_apps/CMakeLists.txt new file mode 100644 index 0000000..62d1565 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_apps/CMakeLists.txt @@ -0,0 +1,7 @@ +# The following four lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +project(mdns_test_app) diff --git a/managed_components/espressif__mdns/tests/test_apps/README.md b/managed_components/espressif__mdns/tests/test_apps/README.md new file mode 100644 index 0000000..96b76dc --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_apps/README.md @@ -0,0 +1,49 @@ +| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 | +| ----------------- | ----- | -------- | -------- | + +# mDNS test project + +Main purpose of this application is to test the mDNS library to correctly advertise, lookup services and hosts. +The "app_test.py" logically separated from two sets of test cases 1. "ESP32 board sends queries -> Host sends answers" and 2. "Host sends queries" -> "ESP32 board sends answers". +Two first sets of test cases are starting by 'test_query_' and the second ones by 'start_case'. + +## Runtime settings + +1. For first sets of test cases python creates and sends dns queries using "dpkt" library +2. For the second sets of test cases this app waits for user input to provide test case(e.g. CONFIG_TEST_QUERY_HOST, CONFIG_TEST_QUERY_HOST_ASYNC or CONFIG_TEST_QUERY_SERVICE) +In order to run both of them just needed to set up the project and run by 'python app_test.py' + +## Test app workflow + +- mDNS is initialized with hostname and instance name defined through the project configuration and `_http._tcp` service is added to be advertised +- A delegated host `esp32-delegated._local` is added and another `_http._tcp` service is added for this host. +- WiFi STA is started and tries to connect to the access point defined through the project configuration + +### Configure the project + +* Open the project configuration menu (`idf.py menuconfig`) + +* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. + +* Set `mDNS Hostname` as host name prefix for the device and its instance name in `mDNS Instance Name` + +### Build and Flash + +Build the project and flash it to the board, then run the monitor tool to view the serial output: + +``` +idf.py -p PORT flash monitor +``` + +- Wait for WiFi to connect to your access point +- You can now ping the device at `[board-hostname].local`, where `[board-hostname]` is preconfigured hostname, `esp32-mdns` by default. +- You can also browse for `_http._tcp` on the same network to find the advertised service +- Note that for purpose of CI tests, configuration options of `MDNS_RESOLVE_TEST_SERVICES` and `MDNS_ADD_MAC_TO_HOSTNAME` are available, but disabled by default. If enabled, then the hostname suffix of last 3 bytes from device MAC address is added, e.g. `esp32-mdns-80FFFF`, and a query for test service is issued. + + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Hardware Required +This test-app can be executed on any ESP32 board, the only required interface is WiFi and connection to a local network and tls server. diff --git a/managed_components/espressif__mdns/tests/test_apps/main/CMakeLists.txt b/managed_components/espressif__mdns/tests/test_apps/main/CMakeLists.txt new file mode 100644 index 0000000..b5902d5 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_apps/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" "mdns_test.c" + INCLUDE_DIRS ".") diff --git a/managed_components/espressif__mdns/tests/test_apps/main/Kconfig.projbuild b/managed_components/espressif__mdns/tests/test_apps/main/Kconfig.projbuild new file mode 100644 index 0000000..a1c0d72 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_apps/main/Kconfig.projbuild @@ -0,0 +1,40 @@ +menu "Example Configuration" + + config TEST_MDNS_HOSTNAME + string "mDNS Hostname" + default "esp32-mdns" + help + mDNS Hostname for example to use + + config TEST_MDNS_INSTANCE + string "mDNS Instance Name" + default "ESP32 with mDNS" + help + mDNS Instance Name for example to use + + config TEST_MDNS_PUBLISH_DELEGATE_HOST + bool "Publish a delegated host" + help + Enable publishing a delegated host other than ESP32. + The example will also add a mock service for this host. + + config TEST_MDNS_ADD_MAC_TO_HOSTNAME + bool "Add mac suffix to hostname" + default n + help + If enabled, a portion of MAC address is added to the hostname, this is used + for evaluation of tests in CI + config MDNS_ADD_MAC_TO_HOSTNAME + bool "Add mac suffix to hostname" + default n + help + If enabled, a portion of MAC address is added to the hostname, this is used + for evaluation of tests in CI + config MDNS_PUBLISH_DELEGATE_HOST + bool "Publish a delegated host" + help + Enable publishing a delegated host other than ESP32. + The example will also add a mock service for this host. + + +endmenu diff --git a/managed_components/espressif__mdns/tests/test_apps/main/idf_component.yml b/managed_components/espressif__mdns/tests/test_apps/main/idf_component.yml new file mode 100644 index 0000000..e9277df --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_apps/main/idf_component.yml @@ -0,0 +1,8 @@ +dependencies: + ## Required IDF version + idf: ">=5.0" + espressif/mdns: + version: "^1.0.0" + override_path: "../../../" + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/managed_components/espressif__mdns/tests/test_apps/main/main.c b/managed_components/espressif__mdns/tests/test_apps/main/main.c new file mode 100644 index 0000000..e67014c --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_apps/main/main.c @@ -0,0 +1,117 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "esp_mac.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_log.h" +#include "protocol_examples_common.h" +#include "mdns.h" + +static const char *TAG = "mdns_test"; +void mdns_test(char *line); + +static void get_string(char *line, size_t size) +{ + int count = 0; + while (count < size) { + int c = fgetc(stdin); + if (c == '\n') { + line[count] = '\0'; + break; + } else if (c > 0 && c < 127) { + line[count] = c; + ++count; + } + vTaskDelay(20 / portTICK_PERIOD_MS); + } +} + +/** Generate host name based on sdkconfig, optionally adding a portion of MAC address to it. + * @return host name string allocated from the heap + */ +static char *generate_hostname(void) +{ +#ifndef CONFIG_TEST_MDNS_ADD_MAC_TO_HOSTNAME + return strdup(CONFIG_TEST_MDNS_HOSTNAME); +#else + uint8_t mac[6]; + char *hostname; + esp_read_mac(mac, ESP_MAC_WIFI_STA); + if (-1 == asprintf(&hostname, "%s-%02X%02X%02X", CONFIG_TEST_MDNS_HOSTNAME, mac[3], mac[4], mac[5])) { + abort(); + } + return hostname; +#endif +} + +static void initialise_mdns(void) +{ + char *hostname = generate_hostname(); + + //initialize mDNS + ESP_ERROR_CHECK( mdns_init() ); + + //set mDNS hostname (required if you want to advertise services) + ESP_ERROR_CHECK( mdns_hostname_set(hostname) ); + + ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname); + //set default mDNS instance name + ESP_ERROR_CHECK( mdns_instance_name_set(CONFIG_TEST_MDNS_INSTANCE) ); + + //initialize service + ESP_ERROR_CHECK( mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, NULL, 0) ); + +#if CONFIG_TEST_MDNS_PUBLISH_DELEGATE_HOST + char *delegated_hostname; + if (-1 == asprintf(&delegated_hostname, "%s-delegated", hostname)) { + abort(); + } + + mdns_ip_addr_t addr4, addr6; + esp_netif_str_to_ip4("10.0.0.1", &addr4.addr.u_addr.ip4); + addr4.addr.type = ESP_IPADDR_TYPE_V4; + esp_netif_str_to_ip6("fd11:22::1", &addr6.addr.u_addr.ip6); + addr6.addr.type = ESP_IPADDR_TYPE_V6; + addr4.next = &addr6; + addr6.next = NULL; + ESP_ERROR_CHECK( mdns_delegate_hostname_add(delegated_hostname, &addr4) ); + ESP_ERROR_CHECK( mdns_service_add_for_host("test0", "_http", "_tcp", delegated_hostname, 1234, NULL, 0) ); + free(delegated_hostname); +#endif // CONFIG_TEST_MDNS_PUBLISH_DELEGATE_HOST + + ESP_ERROR_CHECK( mdns_service_subtype_add_for_host("ESP32-WebServer", "_http", "_tcp", NULL, "_server") ); + + free(hostname); +} + +void app_main(void) +{ + ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size()); + ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); + + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + initialise_mdns(); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + + while (1) { + char line[256]; + + get_string(line, sizeof(line)); + mdns_test(line); + continue; + } +} diff --git a/managed_components/espressif__mdns/tests/test_apps/main/mdns_test.c b/managed_components/espressif__mdns/tests/test_apps/main/mdns_test.c new file mode 100644 index 0000000..06df424 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_apps/main/mdns_test.c @@ -0,0 +1,189 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "mdns.h" +#include "esp_log.h" +#include "esp_netif.h" + +static const char *TAG = "mdns_test_app"; +static const int RETRY_COUNT = 10; + +static void mdns_print_results(mdns_result_t *results) +{ + mdns_result_t *r = results; + mdns_ip_addr_t *a = NULL; + int t; + while (r) { + if (r->instance_name) { + printf("PTR:%s.%s.%s\n", r->instance_name, r->service_type, r->proto); + } + if (r->hostname) { + printf("SRV:%s.local:%u\n", r->hostname, r->port); + } + if (r->txt_count) { + printf("TXT:[%zu] ", r->txt_count); + for (t = 0; t < r->txt_count; t++) { + printf("%s=%s(%d); ", r->txt[t].key, r->txt[t].value ? r->txt[t].value : "NULL", r->txt_value_len[t]); + } + printf("\n"); + } + a = r->addr; + while (a) { + if (a->addr.type == ESP_IPADDR_TYPE_V6) { + printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); + } else { + printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); + } + a = a->next; + } + r = r->next; + } +} + +static bool check_and_print_result(mdns_search_once_t *search) +{ + // Check if any result is available + mdns_result_t *result = NULL; + if (!mdns_query_async_get_results(search, 0, &result, NULL)) { + return false; + } + + if (!result) { // search timeout, but no result + return false; + } + + // If yes, print the result + mdns_ip_addr_t *a = result->addr; + while (a) { + if (a->addr.type == ESP_IPADDR_TYPE_V6) { + printf("Async query resolved to AAAA:" IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); + } else { + printf("Async query resolved to A:" IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); + } + a = a->next; + } + // and free the result + mdns_query_results_free(result); + return true; +} + +static bool query_mdns_hosts_async(const char *host_name) +{ + ESP_LOGI(TAG, "Query both A and AAA: %s.local", host_name); + bool res = false; + + mdns_search_once_t *s_a = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_A, 1000, 1, NULL); + mdns_query_async_delete(s_a); + mdns_search_once_t *s_aaaa = mdns_query_async_new(host_name, NULL, NULL, MDNS_TYPE_AAAA, 1000, 1, NULL); + while (s_a || s_aaaa) { + if (s_a && check_and_print_result(s_a)) { + ESP_LOGI(TAG, "Query A %s.local finished", host_name); + mdns_query_async_delete(s_a); + s_a = NULL; + res = true; + } + if (s_aaaa && check_and_print_result(s_aaaa)) { + ESP_LOGI(TAG, "Query AAAA %s.local finished", host_name); + mdns_query_async_delete(s_aaaa); + s_aaaa = NULL; + res = true; + } + } + return res; +} + +static esp_err_t query_mdns_host(const char *host_name) +{ + ESP_LOGI(TAG, "Query A: %s.local", host_name); + + struct esp_ip4_addr addr; + addr.addr = 0; + + esp_err_t err = mdns_query_a(host_name, 2000, &addr); + if (err) { + if (err == ESP_ERR_NOT_FOUND) { + ESP_LOGW(TAG, "%s: Host was not found!", esp_err_to_name(err)); + } + ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); + return err; + } + + ESP_LOGI(TAG, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr)); + return ESP_OK; +} + +static esp_err_t query_mdns_service(const char *instance, const char *service_name, const char *proto) +{ + ESP_LOGI(TAG, "Query SRV: %s.%s.local", service_name, proto); + + mdns_result_t *results = NULL; + esp_err_t err = mdns_query_srv(instance, service_name, proto, 3000, &results); + if (err) { + ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); + return err; + } + if (!results) { + ESP_LOGW(TAG, "No results found!"); + } + + mdns_print_results(results); + mdns_query_results_free(results); + return ESP_OK; +} + +void query_mdns_service_sub_type(const char *subtype, const char *service_name, const char *proto) +{ + ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto); + + mdns_result_t *results = NULL; + esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results); + if (err) { + ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err)); + } + if (!results) { + ESP_LOGW(TAG, "No results found!"); + } + + mdns_print_results(results); + mdns_query_results_free(results); +} + +void mdns_test(const char *line) +{ + char test_case[32]; + int i = 0; + const TickType_t xDelay = 1000 / portTICK_PERIOD_MS; + + sscanf(line, "%s", test_case); + ESP_LOGI(TAG, "test case = %s", test_case); + + if (strcmp(test_case, "CONFIG_TEST_QUERY_HOST") == 0) { + i = 0; + while (query_mdns_host("tinytester") != ESP_OK && i != RETRY_COUNT) { + query_mdns_host("tinytester"); + i++; + vTaskDelay(xDelay); + } + } else if (strcmp(test_case, "CONFIG_TEST_QUERY_HOST_ASYNC") == 0) { + i = 0; + while (query_mdns_hosts_async("tinytester") == false && i != RETRY_COUNT) { + query_mdns_hosts_async("tinytester"); + i++; + vTaskDelay(xDelay); + } + } else if (strcmp(test_case, "CONFIG_TEST_QUERY_SERVICE") == 0) { + i = 0; + while (query_mdns_service("ESP32", "_http", "_tcp") != ESP_OK && i != RETRY_COUNT) { + query_mdns_service("ESP32", "_http", "_tcp"); + i++; + vTaskDelay(xDelay); + } + } else { + ESP_LOGE(TAG, "%s: No such test case", test_case); + } +} diff --git a/managed_components/espressif__mdns/tests/test_apps/pytest_mdns_app.py b/managed_components/espressif__mdns/tests/test_apps/pytest_mdns_app.py new file mode 100644 index 0000000..2b04cb7 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_apps/pytest_mdns_app.py @@ -0,0 +1,320 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +import re +import select +import socket +import struct +import time +from threading import Event, Thread + +import dpkt +import dpkt.dns +import pytest + +UDP_PORT = 5353 +MCAST_GRP = '224.0.0.251' + +# This service is created from esp board startup +SERVICE_NAME = u'ESP32-WebServer._http._tcp.local' +SUB_SERVICE_NAME = u'_server._sub._http._tcp.local' + +# This host name answer sent by host, when there is query from board +HOST_NAME = u'tinytester.local' + +# This servce answer sent by host, when there is query from board +MDNS_HOST_SERVICE = u'ESP32._http._tcp.local' + +# Number of retries to receive mdns answear +RETRY_COUNT = 10 + +stop_mdns_listener = Event() +start_mdns_listener = Event() +esp_service_answered = Event() +esp_sub_service_answered = Event() +esp_host_answered = Event() +esp_delegated_host_answered = Event() + + +@pytest.mark.skip +# Get query of ESP32-WebServer._http._tcp.local service +def get_mdns_service_query(service): # type:(str) -> dpkt.dns.Msg + dns = dpkt.dns.DNS() + dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA + dns.rcode = dpkt.dns.DNS_RCODE_NOERR + arr = dpkt.dns.DNS.RR() + arr.cls = dpkt.dns.DNS_IN + arr.type = dpkt.dns.DNS_SRV + arr.name = service + arr.target = socket.inet_aton('127.0.0.1') + arr.srvname = service + dns.qd.append(arr) + print('Created mdns service query: {} '.format(dns.__repr__())) + return dns.pack() + + +@pytest.mark.skip +# Get query of _server_.sub._http._tcp.local sub service +def get_mdns_sub_service_query(sub_service): # type:(str) -> dpkt.dns.Msg + dns = dpkt.dns.DNS() + dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA + dns.rcode = dpkt.dns.DNS_RCODE_NOERR + arr = dpkt.dns.DNS.RR() + arr.cls = dpkt.dns.DNS_IN + arr.type = dpkt.dns.DNS_PTR + arr.name = sub_service + arr.target = socket.inet_aton('127.0.0.1') + arr.ptrname = sub_service + dns.qd.append(arr) + print('Created mdns subtype service query: {} '.format(dns.__repr__())) + return dns.pack() + + +@pytest.mark.skip +# Get query for host resolution +def get_dns_query_for_esp(esp_host): # type:(str) -> dpkt.dns.Msg + dns = dpkt.dns.DNS() + arr = dpkt.dns.DNS.RR() + arr.cls = dpkt.dns.DNS_IN + arr.name = esp_host + u'.local' + dns.qd.append(arr) + print('Created query for esp host: {} '.format(dns.__repr__())) + return dns.pack() + + +@pytest.mark.skip +# Get mdns answer for host resoloution +def get_dns_answer_to_mdns(tester_host): # type:(str) -> dpkt.dns.Msg + dns = dpkt.dns.DNS() + dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA + dns.rcode = dpkt.dns.DNS_RCODE_NOERR + arr = dpkt.dns.DNS.RR() + arr.cls = dpkt.dns.DNS_IN + arr.type = dpkt.dns.DNS_A + arr.name = tester_host + arr.ip = socket.inet_aton('127.0.0.1') + dns.an.append(arr) + print('Created answer to mdns query: {} '.format(dns.__repr__())) + return dns.pack() + + +@pytest.mark.skip +# Get mdns answer for service query +def get_dns_answer_to_service_query( + mdns_service): # type:(str) -> dpkt.dns.Msg + dns = dpkt.dns.DNS() + dns.op = dpkt.dns.DNS_QR | dpkt.dns.DNS_AA + dns.rcode = dpkt.dns.DNS_RCODE_NOERR + arr = dpkt.dns.DNS.RR() + arr.name = mdns_service + arr.cls = dpkt.dns.DNS_IN + arr.type = dpkt.dns.DNS_SRV + arr.priority = 0 + arr.weight = 0 + arr.port = 100 + arr.srvname = mdns_service + arr.ip = socket.inet_aton('127.0.0.1') + dns.an.append(arr) + print('Created answer to mdns query: {} '.format(dns.__repr__())) + return dns.pack() + + +@pytest.mark.skip +def mdns_listener(esp_host): # type:(str) -> None + print('mdns_listener thread started') + + UDP_IP = '0.0.0.0' + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + sock.setblocking(False) + sock.bind((UDP_IP, UDP_PORT)) + mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY) + sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) + last_query_timepoint = time.time() + QUERY_TIMEOUT = 0.2 + while not stop_mdns_listener.is_set(): + try: + start_mdns_listener.set() + current_time = time.time() + if current_time - last_query_timepoint > QUERY_TIMEOUT: + last_query_timepoint = current_time + timeout = max( + 0, QUERY_TIMEOUT - (current_time - last_query_timepoint)) + read_socks, _, _ = select.select([sock], [], [], timeout) + if not read_socks: + continue + data, _ = sock.recvfrom(1024) + dns = dpkt.dns.DNS(data) + # Receives queries from esp board and sends answers + if len(dns.qd) > 0: + if dns.qd[0].name == HOST_NAME: + print('Received query: {} '.format(dns.__repr__())) + sock.sendto(get_dns_answer_to_mdns(HOST_NAME), + (MCAST_GRP, UDP_PORT)) + if dns.qd[0].name == HOST_NAME: + print('Received query: {} '.format(dns.__repr__())) + sock.sendto(get_dns_answer_to_mdns(HOST_NAME), + (MCAST_GRP, UDP_PORT)) + if dns.qd[0].name == MDNS_HOST_SERVICE: + print('Received query: {} '.format(dns.__repr__())) + sock.sendto( + get_dns_answer_to_service_query(MDNS_HOST_SERVICE), + (MCAST_GRP, UDP_PORT)) + # Receives answers from esp board and sets event flags for python test cases + if len(dns.an) == 1: + if dns.an[0].name.startswith(SERVICE_NAME): + print('Received answer to service query: {}'.format( + dns.__repr__())) + esp_service_answered.set() + if len(dns.an) > 1: + if dns.an[1].name.startswith(SUB_SERVICE_NAME): + print('Received answer for sub service query: {}'.format( + dns.__repr__())) + esp_sub_service_answered.set() + if len(dns.an) > 0 and dns.an[0].type == dpkt.dns.DNS_A: + if dns.an[0].name == esp_host + u'.local': + print('Received answer to esp32-mdns query: {}'.format( + dns.__repr__())) + esp_host_answered.set() + if dns.an[0].name == esp_host + u'-delegated.local': + print('Received answer to esp32-mdns-delegate query: {}'. + format(dns.__repr__())) + esp_delegated_host_answered.set() + except socket.timeout: + break + except dpkt.UnpackError: + continue + + +@pytest.mark.skip +def create_socket(): # type:() -> socket.socket + UDP_IP = '0.0.0.0' + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + sock.setblocking(False) + sock.bind((UDP_IP, UDP_PORT)) + mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY) + sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) + return sock + + +@pytest.mark.skip +def test_query_dns_http_service(service): # type: (str) -> None + print('SRV: Query {}'.format(service)) + sock = create_socket() + packet = get_mdns_service_query(service) + for _ in range(RETRY_COUNT): + if esp_service_answered.wait(timeout=25): + break + sock.sendto(packet, (MCAST_GRP, UDP_PORT)) + else: + raise RuntimeError( + 'Test has failed: did not receive mdns answer within timeout') + + +@pytest.mark.skip +def test_query_dns_sub_service(sub_service): # type: (str) -> None + print('PTR: Query {}'.format(sub_service)) + sock = create_socket() + packet = get_mdns_sub_service_query(sub_service) + for _ in range(RETRY_COUNT): + if esp_sub_service_answered.wait(timeout=25): + break + sock.sendto(packet, (MCAST_GRP, UDP_PORT)) + else: + raise RuntimeError( + 'Test has failed: did not receive mdns answer within timeout') + + +@pytest.mark.skip +def test_query_dns_host(esp_host): # type: (str) -> None + print('A: {}'.format(esp_host)) + sock = create_socket() + packet = get_dns_query_for_esp(esp_host) + for _ in range(RETRY_COUNT): + if esp_host_answered.wait(timeout=25): + break + sock.sendto(packet, (MCAST_GRP, UDP_PORT)) + else: + raise RuntimeError( + 'Test has failed: did not receive mdns answer within timeout') + + +@pytest.mark.skip +def test_query_dns_host_delegated(esp_host): # type: (str) -> None + print('A: {}'.format(esp_host)) + sock = create_socket() + packet = get_dns_query_for_esp(esp_host + '-delegated') + for _ in range(RETRY_COUNT): + if esp_delegated_host_answered.wait(timeout=25): + break + sock.sendto(packet, (MCAST_GRP, UDP_PORT)) + else: + raise RuntimeError( + 'Test has failed: did not receive mdns answer within timeout') + + +@pytest.mark.esp32 +@pytest.mark.esp32s2 +@pytest.mark.esp32c3 +@pytest.mark.generic +def test_app_esp_mdns(dut): + + # 1. get the dut host name (and IP address) + specific_host = dut.expect( + re.compile(b'mdns hostname set to: \[([^\]]+)\]'), # noqa: W605 + timeout=30).group(1).decode() + + esp_ip = dut.expect( + re.compile( + b' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), # noqa: W605 + timeout=30).group(1).decode() + print('Got IP={}'.format(esp_ip)) + + mdns_responder = Thread(target=mdns_listener, args=(str(specific_host), )) + + def start_case(case, desc, result): # type: (str, str, str) -> None + print('Starting {}: {}'.format(case, desc)) + dut.write(case) + res = bytes(result, encoding='utf8') + dut.expect(re.compile(res), timeout=30) + + try: + # start dns listener thread + mdns_responder.start() + + # wait untill mdns listener thred started + if not start_mdns_listener.wait(timeout=5): + raise ValueError( + 'Test has failed: mdns listener thread did not start') + + # query dns service from host, answer should be received from esp board + test_query_dns_http_service(SERVICE_NAME) + + # query dns sub-service from host, answer should be received from esp board + test_query_dns_sub_service(SUB_SERVICE_NAME) + + # query dns host name, answer should be received from esp board + test_query_dns_host(specific_host) + + # query dns host name delegated, answer should be received from esp board + test_query_dns_host_delegated(specific_host) + + # query service from esp board, answer should be received from host + start_case('CONFIG_TEST_QUERY_SERVICE', + 'Query SRV ESP32._http._tcp.local', 'SRV:ESP32') + + # query dns-host from esp board, answer should be received from host + start_case('CONFIG_TEST_QUERY_HOST', 'Query tinytester.local', + 'tinytester.local resolved to: 127.0.0.1') + + # query dns-host aynchrounusely from esp board, answer should be received from host + start_case('CONFIG_TEST_QUERY_HOST_ASYNC', + 'Query tinytester.local async', + 'Async query resolved to A:127.0.0.1') + + finally: + stop_mdns_listener.set() + mdns_responder.join() diff --git a/managed_components/espressif__mdns/tests/test_apps/sdkconfig.ci b/managed_components/espressif__mdns/tests/test_apps/sdkconfig.ci new file mode 100644 index 0000000..d89171d --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_apps/sdkconfig.ci @@ -0,0 +1,13 @@ +CONFIG_IDF_TARGET="esp32" +CONFIG_MDNS_ADD_MAC_TO_HOSTNAME=y +CONFIG_MDNS_PUBLISH_DELEGATE_HOST=y +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +CONFIG_EXAMPLE_CONNECT_ETHERNET=y +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y +CONFIG_EXAMPLE_ETH_PHY_IP101=y +CONFIG_EXAMPLE_ETH_MDC_GPIO=23 +CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 +CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 +CONFIG_EXAMPLE_ETH_PHY_ADDR=1 +CONFIG_EXAMPLE_CONNECT_IPV6=y diff --git a/managed_components/espressif__mdns/tests/test_apps/sdkconfig.defaults b/managed_components/espressif__mdns/tests/test_apps/sdkconfig.defaults new file mode 100644 index 0000000..0c4ffe9 --- /dev/null +++ b/managed_components/espressif__mdns/tests/test_apps/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_TEST_MDNS_ADD_MAC_TO_HOSTNAME=y +CONFIG_TEST_MDNS_PUBLISH_DELEGATE_HOST=y diff --git a/managed_components/espressif__mdns/tests/unit_test/CMakeLists.txt b/managed_components/espressif__mdns/tests/unit_test/CMakeLists.txt new file mode 100644 index 0000000..450d475 --- /dev/null +++ b/managed_components/espressif__mdns/tests/unit_test/CMakeLists.txt @@ -0,0 +1,7 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS ../.. "$ENV{IDF_PATH}/tools/unit-test-app/components") + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(mdns_test) diff --git a/managed_components/espressif__mdns/tests/unit_test/main/CMakeLists.txt b/managed_components/espressif__mdns/tests/unit_test/main/CMakeLists.txt new file mode 100644 index 0000000..d04d217 --- /dev/null +++ b/managed_components/espressif__mdns/tests/unit_test/main/CMakeLists.txt @@ -0,0 +1,5 @@ + +idf_component_register(SRCS "test_mdns.c" + REQUIRES test_utils + INCLUDE_DIRS "." + PRIV_REQUIRES unity mdns) diff --git a/managed_components/espressif__mdns/tests/unit_test/main/test_mdns.c b/managed_components/espressif__mdns/tests/unit_test/main/test_mdns.c new file mode 100644 index 0000000..ff024e2 --- /dev/null +++ b/managed_components/espressif__mdns/tests/unit_test/main/test_mdns.c @@ -0,0 +1,299 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include "mdns.h" +#include "esp_event.h" +#include "unity.h" +#include "test_utils.h" + +#include "unity_fixture.h" +#include "memory_checks.h" + +#define MDNS_HOSTNAME "test-hostname" +#define MDNS_DELEGATE_HOSTNAME "delegate-hostname" +#define MDNS_INSTANCE "test-instance" +#define MDNS_SERVICE_NAME "_http" +#define MDNS_SERVICE_PROTO "_tcp" +#define MDNS_SERVICE_PORT 80 + +TEST_GROUP(mdns); + +TEST_SETUP(mdns) +{ + test_utils_record_free_mem(); + TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL)); +} + +TEST_TEAR_DOWN(mdns) +{ + test_utils_finish_and_evaluate_leaks(32, 64); +} + +static void yield_to_all_priorities(void) +{ + // Lower the test-task priority before testing to ensure other tasks got executed on forced context switch + size_t test_task_prio_before = uxTaskPriorityGet(NULL); + vTaskPrioritySet(NULL, tskIDLE_PRIORITY); + taskYIELD(); // Let the RTOS to switch context + vTaskPrioritySet(NULL, test_task_prio_before); +} + + +TEST(mdns, api_fails_with_invalid_state) +{ + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_init() ); + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME) ); + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_instance_name_set(MDNS_INSTANCE) ); + TEST_ASSERT_NOT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0) ); +} + +TEST(mdns, init_deinit) +{ + test_case_uses_tcpip(); + TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default()); + TEST_ASSERT_EQUAL(ESP_OK, mdns_init() ); + yield_to_all_priorities(); // Make sure that mdns task has executed to complete initialization + mdns_free(); + esp_event_loop_delete_default(); +} + +TEST(mdns, api_fails_with_expected_err) +{ + mdns_txt_item_t serviceTxtData[CONFIG_MDNS_MAX_SERVICES] = { {NULL, NULL}, + }; + mdns_ip_addr_t addr; + addr.addr.type = ESP_IPADDR_TYPE_V4; + addr.addr.u_addr.ip4.addr = esp_ip4addr_aton("127.0.0.1"); + addr.next = NULL; + for (int i = 0; i < CONFIG_MDNS_MAX_SERVICES; ++i) { + serviceTxtData[i].key = "Key"; + serviceTxtData[i].value = "Value"; + } + test_case_uses_tcpip(); + TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default()); + + TEST_ASSERT_EQUAL(ESP_OK, mdns_init() ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME) ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_delegate_hostname_add(MDNS_DELEGATE_HOSTNAME, &addr) ); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_TRUE(mdns_hostname_exists(MDNS_DELEGATE_HOSTNAME) ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_instance_name_set(MDNS_INSTANCE) ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, serviceTxtData, CONFIG_MDNS_MAX_SERVICES) ); + TEST_ASSERT_FALSE(mdns_service_exists(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME) ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add_for_host(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME, + MDNS_SERVICE_PORT, serviceTxtData, CONFIG_MDNS_MAX_SERVICES) ); + TEST_ASSERT_TRUE(mdns_service_exists(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME) ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, serviceTxtData, CONFIG_MDNS_MAX_SERVICES) ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_item_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, "key1", "value1") ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_item_remove(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, "key1") ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_port_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 8080) ); + yield_to_all_priorities(); // to remove the service with the updated txt records + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_remove(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO) ); + yield_to_all_priorities(); // Make sure that mdns task has executed to remove the service + + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0) ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_delegate_hostname_remove(MDNS_DELEGATE_HOSTNAME) ); + yield_to_all_priorities(); // Make sure that mdns task has executed to remove the hostname + TEST_ASSERT_FALSE(mdns_service_exists(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME) ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_remove_all() ); + yield_to_all_priorities(); // Make sure that mdns task has executed to remove all services + + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, mdns_service_port_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 8080) ); + + mdns_free(); + esp_event_loop_delete_default(); +} + +TEST(mdns, query_api_fails_with_expected_err) +{ + mdns_result_t *results = NULL; + esp_ip6_addr_t addr6; + esp_ip4_addr_t addr4; + test_case_uses_tcpip(); + TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default()); + + TEST_ASSERT_EQUAL(ESP_OK, mdns_init() ); + // check it is not possible to register a service or set an instance without configuring the hostname + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, mdns_instance_name_set(MDNS_INSTANCE)); + TEST_ASSERT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME)); + // hostname is set, now adding a service and instance should succeed + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0)); + TEST_ASSERT_EQUAL(ESP_OK, mdns_instance_name_set(MDNS_INSTANCE)); + + TEST_ASSERT_EQUAL(ESP_OK, mdns_query_ptr(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 10, CONFIG_MDNS_MAX_SERVICES, &results) ); + mdns_query_results_free(results); + + TEST_ASSERT_EQUAL(ESP_OK, mdns_query_srv(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 10, &results) ); + mdns_query_results_free(results); + + TEST_ASSERT_EQUAL(ESP_OK, mdns_query_txt(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 10, &results) ); + mdns_query_results_free(results); + + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, mdns_query_a(MDNS_HOSTNAME, 10, &addr4) ); + mdns_query_results_free(results); + + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, mdns_query_aaaa(MDNS_HOSTNAME, 10, &addr6) ); + mdns_query_results_free(results); + + mdns_free(); + esp_event_loop_delete_default(); +} + +TEST(mdns, add_remove_service) +{ + mdns_result_t *results = NULL; + test_case_uses_tcpip(); + TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default()); + TEST_ASSERT_EQUAL(ESP_OK, mdns_init() ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME)); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT, NULL, 0)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_selfhosted_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL_STRING(MDNS_INSTANCE, results->instance_name); + TEST_ASSERT_EQUAL_STRING(MDNS_SERVICE_NAME, results->service_type); + TEST_ASSERT_EQUAL(MDNS_SERVICE_PORT, results->port); + TEST_ASSERT_EQUAL(NULL, results->txt); + mdns_query_results_free(results); + + // Update service properties: port + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_port_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_SERVICE_PORT + 1)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_selfhosted_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL(MDNS_SERVICE_PORT + 1, results->port); + mdns_query_results_free(results); + + // Update service properties: instance + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_instance_name_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_INSTANCE "1" )); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_selfhosted_service(MDNS_INSTANCE "1", MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL_STRING(MDNS_INSTANCE "1", results->instance_name); + mdns_query_results_free(results); + + // Update service properties: txt + mdns_txt_item_t txt_data[] = { + {"key1", "esp32"}, + {"key2", "value"}, + {"key3", "value3"}, + }; + const size_t txt_data_cout = sizeof(txt_data) / sizeof(txt_data[0]); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_set(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, txt_data, txt_data_cout)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_selfhosted_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_NOT_EQUAL(NULL, results->txt); + TEST_ASSERT_EQUAL(txt_data_cout, results->txt_count); + // compare txt values by keys + size_t matches = 0; + for (int i = 0; i < results->txt_count; ++i) // iterates over the results we get from mdns_lookup() + for (int j = 0; j < txt_data_cout; ++j) // iterates over our test records + if (strcmp(results->txt[i].key, txt_data[j].key) == 0) { // we compare the value only if the key matches + TEST_ASSERT_EQUAL_STRING(results->txt[i].value, txt_data[j].value); + ++matches; + } + TEST_ASSERT_EQUAL(txt_data_cout, matches); // checks that we went over all our txt items + mdns_query_results_free(results); + + // Now remove the service + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_remove(MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_selfhosted_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_EQUAL(NULL, results); + + mdns_free(); + esp_event_loop_delete_default(); +} + +TEST(mdns, add_remove_deleg_service) +{ + mdns_ip_addr_t addr; + addr.addr.type = ESP_IPADDR_TYPE_V4; + addr.addr.u_addr.ip4.addr = esp_ip4addr_aton("127.0.0.1"); + addr.next = NULL; + mdns_result_t *results = NULL; + test_case_uses_tcpip(); + TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create_default()); + TEST_ASSERT_EQUAL(ESP_OK, mdns_init() ); + TEST_ASSERT_EQUAL(ESP_OK, mdns_hostname_set(MDNS_HOSTNAME)); + TEST_ASSERT_EQUAL(ESP_OK, mdns_delegate_hostname_add(MDNS_DELEGATE_HOSTNAME, &addr) ); + + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_add_for_host(MDNS_INSTANCE, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME, MDNS_SERVICE_PORT, NULL, 0)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_delegated_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL_STRING(MDNS_INSTANCE, results->instance_name); + TEST_ASSERT_EQUAL_STRING(MDNS_SERVICE_NAME, results->service_type); + TEST_ASSERT_EQUAL(MDNS_SERVICE_PORT, results->port); + TEST_ASSERT_EQUAL(NULL, results->txt); + mdns_query_results_free(results); + + // Update service properties: port + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_port_set_for_host(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME, MDNS_SERVICE_PORT + 1)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_delegated_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL(MDNS_SERVICE_PORT + 1, results->port); + mdns_query_results_free(results); + + // Update service properties: instance + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_instance_name_set_for_host(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME, MDNS_INSTANCE "1" )); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_delegated_service(MDNS_INSTANCE "1", MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_EQUAL_STRING(MDNS_INSTANCE "1", results->instance_name); + mdns_query_results_free(results); + + // Update service properties: txt + mdns_txt_item_t txt_data[] = { + {"key1", "esp32"}, + {"key2", "value"}, + }; + const size_t txt_data_cout = sizeof(txt_data) / sizeof(txt_data[0]); + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_txt_set_for_host(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME, txt_data, txt_data_cout)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_delegated_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_NOT_EQUAL(NULL, results); + TEST_ASSERT_NOT_EQUAL(NULL, results->txt); + TEST_ASSERT_EQUAL(txt_data_cout, results->txt_count); + // compare txt values by keys + size_t matches = 0; + for (int i = 0; i < results->txt_count; ++i) // iterates over the results we get from mdns_lookup() + for (int j = 0; j < txt_data_cout; ++j) // iterates over our test records + if (strcmp(results->txt[i].key, txt_data[j].key) == 0) { // we compare the value only if the key matches + TEST_ASSERT_EQUAL_STRING(results->txt[i].value, txt_data[j].value); + ++matches; + } + TEST_ASSERT_EQUAL(txt_data_cout, matches); // checks that we went over all our txt items + mdns_query_results_free(results); + + // Now remove the service + TEST_ASSERT_EQUAL(ESP_OK, mdns_service_remove_for_host(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, MDNS_DELEGATE_HOSTNAME)); + yield_to_all_priorities(); // Make sure that mdns task has executed to add the hostname + TEST_ASSERT_EQUAL(ESP_OK, mdns_lookup_delegated_service(NULL, MDNS_SERVICE_NAME, MDNS_SERVICE_PROTO, 1, &results)); + TEST_ASSERT_EQUAL(NULL, results); + + mdns_free(); + esp_event_loop_delete_default(); +} +TEST_GROUP_RUNNER(mdns) +{ + RUN_TEST_CASE(mdns, api_fails_with_invalid_state) + RUN_TEST_CASE(mdns, api_fails_with_expected_err) + RUN_TEST_CASE(mdns, query_api_fails_with_expected_err) + RUN_TEST_CASE(mdns, init_deinit) + RUN_TEST_CASE(mdns, add_remove_service) + RUN_TEST_CASE(mdns, add_remove_deleg_service) + +} + +void app_main(void) +{ + UNITY_MAIN(mdns); +} diff --git a/managed_components/espressif__mdns/tests/unit_test/pytest_app_mdns.py b/managed_components/espressif__mdns/tests/unit_test/pytest_app_mdns.py new file mode 100644 index 0000000..5106112 --- /dev/null +++ b/managed_components/espressif__mdns/tests/unit_test/pytest_app_mdns.py @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +from pytest_embedded import Dut + + +def test_mdns(dut: Dut) -> None: + dut.expect_unity_test_output() diff --git a/managed_components/espressif__mdns/tests/unit_test/sdkconfig.ci b/managed_components/espressif__mdns/tests/unit_test/sdkconfig.ci new file mode 100644 index 0000000..9660719 --- /dev/null +++ b/managed_components/espressif__mdns/tests/unit_test/sdkconfig.ci @@ -0,0 +1,3 @@ +CONFIG_IDF_TARGET="esp32" +CONFIG_UNITY_ENABLE_FIXTURE=y +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n diff --git a/managed_components/espressif__mdns/tests/unit_test/sdkconfig.defaults b/managed_components/espressif__mdns/tests/unit_test/sdkconfig.defaults new file mode 100644 index 0000000..168e08d --- /dev/null +++ b/managed_components/espressif__mdns/tests/unit_test/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_UNITY_ENABLE_FIXTURE=y +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n diff --git a/managed_components/espressif__usb_host_msc/.component_hash b/managed_components/espressif__usb_host_msc/.component_hash new file mode 100644 index 0000000..284c214 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/.component_hash @@ -0,0 +1 @@ +efbf44743b0f1f1f808697a671064531ae4661ccbce84632637261f8f670b375 \ No newline at end of file diff --git a/managed_components/espressif__usb_host_msc/CHANGELOG.md b/managed_components/espressif__usb_host_msc/CHANGELOG.md new file mode 100644 index 0000000..0f06c6b --- /dev/null +++ b/managed_components/espressif__usb_host_msc/CHANGELOG.md @@ -0,0 +1,39 @@ +## 1.1.3 + +- Implemented request sense, to get sense data from USB device in case of an error +- Fixed initialization of some flash drives, which require more time to initialize (https://github.com/espressif/esp-idf/issues/14319) + +## 1.1.2 + +- Added support for ESP32-P4 +- Reverted zero-copy bulk transfers. Data are now copied to USB buffers with negligible effect on performance + +## 1.1.1 + +- Fix `msc_host_get_device_info` for devices without Serial Number string descriptor https://github.com/espressif/esp-idf/issues/12163 +- Fix regression from version 1.1.0 that files could not be opened in PSRAM https://github.com/espressif/idf-extra-components/issues/202 +- Fix MSC driver event handling without background task + +## 1.1.0 - yanked + +- Significantly increase performance with Virtual File System by allowing longer transfers +- Optimize used heap memory by reusing the Virtual File System buffer +- Optimize CPU usage by putting the background MSC task to 'Blocked' state indefinitely when there is nothing to do +- Fix MSC commands for devices on interface numbers other than zero +- Replace unsafe debug functions for direct access of MSC sectors with private SCSI commands + +## 1.0.4 + +- Claim support for USB composite devices + +## 1.0.2 + +- Increase transfer timeout to 5 seconds to handle slower flash disks + +## 1.0.1 + +- Fix compatibility with IDF v4.4 + +## 1.0.0 + +- Initial version diff --git a/managed_components/espressif__usb_host_msc/CMakeLists.txt b/managed_components/espressif__usb_host_msc/CMakeLists.txt new file mode 100644 index 0000000..9e0e56c --- /dev/null +++ b/managed_components/espressif__usb_host_msc/CMakeLists.txt @@ -0,0 +1,10 @@ +set(sources src/msc_scsi_bot.c + src/diskio_usb.c + src/msc_host.c + src/msc_host_vfs.c) + +idf_component_register( SRCS ${sources} + INCLUDE_DIRS include include/usb # 'include/usb' is here for backwards compatibility + PRIV_INCLUDE_DIRS private_include include/esp_private + REQUIRES usb fatfs + PRIV_REQUIRES heap ) diff --git a/managed_components/espressif__usb_host_msc/LICENCE b/managed_components/espressif__usb_host_msc/LICENCE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/LICENCE @@ -0,0 +1,202 @@ + + 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 [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 + + 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. diff --git a/managed_components/espressif__usb_host_msc/README.md b/managed_components/espressif__usb_host_msc/README.md new file mode 100644 index 0000000..0910599 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/README.md @@ -0,0 +1,42 @@ +# USB Host MSC (Mass Storage Class) Driver + +[![Component Registry](https://components.espressif.com/components/espressif/usb_host_msc/badge.svg)](https://components.espressif.com/components/espressif/usb_host_msc) + +This directory contains an implementation of a USB Mass Storage Class Driver implemented on top of the [USB Host Library](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/peripherals/usb_host.html). + +MSC driver allows access to USB flash drivers using the BOT (Bulk-Only Transport) protocol and the Transparent SCSI command set. + +## Usage + +- First, usb host library has to be initialized by calling `usb_host_install` +- USB Host Library events have to be handled by invoking `usb_host_lib_handle_events` periodically. + In general, an application should spawn a dedicated task handle USB Host Library events. + However, in order to save RAM, an already existing task can also be used to call `usb_host_lib_handle_events`. +- Mass Storage Class driver is installed by calling `usb_msc_install` function along side with configuration. +- Supplied configuration contains user provided callback function invoked whenever MSC device is connected/disconnected + and optional parameters for creating background task handling MSC related events. + Alternatively, user can call `usb_msc_handle_events` function from already existing task. +- After receiving `MSC_DEVICE_CONNECTED` event, user has to install device with `usb_msc_install_device` function, + obtaining MSC device handle. +- USB descriptors can be printed out with `usb_msc_print_descriptors` and general information about MSC device retrieved + with `from usb_msc_get_device_info` function. +- Obtained device handle is then used in helper function `usb_msc_vfs_register` mounting USB Disk to Virtual filesystem. +- At this point, standard C functions for accessing storage (`fopen`, `fwrite`, `fread`, `mkdir` etc.) can be carried out. +- In order to uninstall the whole USB stack, deinitializing counterparts to functions above has to be called in reverse order. + +## Performance tuning + +The following performance tuning options have significant impact on data throughput in USB HighSpeed implementations. +For original FullSpeed implementations, the effects are negligible. +- By default, Newlib (the implementation of C Standard Library) creates cache for each opened file +- The greater the cache, the better performance for the cost of RAM +- Size of the cache can be set with C STD library function `setvbuf()` +- Sizes over 16kB do not improve the performance any more + +## Known issues + +- Driver only supports flash drives using the BOT (Bulk-Only Transport) protocol and the Transparent SCSI command set + +## Examples + +- For an example, refer to [msc_host_example](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb/host/msc) in ESP-IDF diff --git a/managed_components/espressif__usb_host_msc/idf_component.yml b/managed_components/espressif__usb_host_msc/idf_component.yml new file mode 100644 index 0000000..848be1f --- /dev/null +++ b/managed_components/espressif__usb_host_msc/idf_component.yml @@ -0,0 +1,13 @@ +dependencies: + idf: '>=4.4.1' +description: USB Host MSC driver +repository: git://github.com/espressif/esp-usb.git +repository_info: + commit_sha: 0d5b6e959b2ba6993f27c703f5b26f93557c9066 + path: host/class/msc/usb_host_msc +targets: +- esp32s2 +- esp32s3 +- esp32p4 +url: https://github.com/espressif/esp-usb/tree/master/host/class/msc/usb_host_msc +version: 1.1.3 diff --git a/managed_components/espressif__usb_host_msc/include/esp_private/msc_scsi_bot.h b/managed_components/espressif__usb_host_msc/include/esp_private/msc_scsi_bot.h new file mode 100644 index 0000000..63d8720 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/include/esp_private/msc_scsi_bot.h @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_err.h" +#include "usb/msc_host.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct { + uint8_t key; + uint8_t code; + uint8_t code_q; +} scsi_sense_data_t; + +esp_err_t scsi_cmd_read10(msc_host_device_handle_t device, + uint8_t *data, + uint32_t sector_address, + uint32_t num_sectors, + uint32_t sector_size); + +esp_err_t scsi_cmd_write10(msc_host_device_handle_t device, + const uint8_t *data, + uint32_t sector_address, + uint32_t num_sectors, + uint32_t sector_size); + +esp_err_t scsi_cmd_read_capacity(msc_host_device_handle_t device, + uint32_t *block_size, + uint32_t *block_count); + +esp_err_t scsi_cmd_sense(msc_host_device_handle_t device, scsi_sense_data_t *sense); + +esp_err_t scsi_cmd_unit_ready(msc_host_device_handle_t device); + +esp_err_t scsi_cmd_inquiry(msc_host_device_handle_t device); + +esp_err_t scsi_cmd_prevent_removal(msc_host_device_handle_t device, bool prevent); + +esp_err_t scsi_cmd_mode_sense(msc_host_device_handle_t device); + +#ifdef __cplusplus +} +#endif diff --git a/managed_components/espressif__usb_host_msc/include/usb/msc_host.h b/managed_components/espressif__usb_host_msc/include/usb/msc_host.h new file mode 100644 index 0000000..be46f8d --- /dev/null +++ b/managed_components/espressif__usb_host_msc/include/usb/msc_host.h @@ -0,0 +1,188 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "freertos/FreeRTOS.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_ERR_MSC_HOST_BASE 0x1700 /*!< MSC host error code base */ +#define ESP_ERR_MSC_MOUNT_FAILED (ESP_ERR_MSC_HOST_BASE + 1) /*!< Failed to mount storage */ +#define ESP_ERR_MSC_FORMAT_FAILED (ESP_ERR_MSC_HOST_BASE + 2) /*!< Failed to format storage */ +#define ESP_ERR_MSC_INTERNAL (ESP_ERR_MSC_HOST_BASE + 3) /*!< MSC host internal error */ +#define ESP_ERR_MSC_STALL (ESP_ERR_MSC_HOST_BASE + 4) /*!< USB transfer stalled */ + +#define MSC_STR_DESC_SIZE 32 + +typedef struct msc_host_device *msc_host_device_handle_t; /**< Handle to a Mass Storage Device */ + +/** + * @brief USB Mass Storage event containing event type and associated device handle. +*/ +typedef struct { + enum { + MSC_DEVICE_CONNECTED, /**< MSC device has been connected to the system.*/ + MSC_DEVICE_DISCONNECTED, /**< MSC device has been disconnected from the system.*/ + } event; + union { + uint8_t address; /**< Address of connected MSC device.*/ + msc_host_device_handle_t handle; /**< MSC device handle to disconnected device.*/ + } device; +} msc_host_event_t; + +/** + * @brief USB Mass Storage event callback. + * + * @param[in] event mass storage event +*/ +typedef void (*msc_host_event_cb_t)(const msc_host_event_t *event, void *arg); + +/** + * @brief MSC configuration structure. +*/ +typedef struct { + bool create_backround_task; /**< When set to true, background task handling usb events is created. + Otherwise user has to periodically call msc_host_handle_events function */ + size_t task_priority; /**< Task priority of created background task */ + size_t stack_size; /**< Stack size of created background task */ + BaseType_t core_id; /**< Select core on which background task will run or tskNO_AFFINITY */ + msc_host_event_cb_t callback; /**< Callback invoked when MSC event occurs. Must not be NULL. */ + void *callback_arg; /**< User provided argument passed to callback */ +} msc_host_driver_config_t; + +/** + * @brief MSC device info. +*/ +typedef struct { + uint32_t sector_count; + uint32_t sector_size; + uint16_t idProduct; + uint16_t idVendor; + wchar_t iManufacturer[MSC_STR_DESC_SIZE]; + wchar_t iProduct[MSC_STR_DESC_SIZE]; + wchar_t iSerialNumber[MSC_STR_DESC_SIZE]; +} msc_host_device_info_t; + +/** + * @brief Install USB Host Mass Storage Class driver + * + * @param[in] config configuration structure MSC to create + * @return esp_err_r + */ +esp_err_t msc_host_install(const msc_host_driver_config_t *config); + +/** + * @brief Uninstall Mass Storage Class driver + * @return esp_err_t + */ +esp_err_t msc_host_uninstall(void); + +/** + * @brief Initialization of MSC device. + * + * @param[in] device_address Device address obtained from MSC callback provided upon connection and enumeration + * @param[out] device Mass storage device handle to be used for subsequent calls. + * @return esp_err_t + */ +esp_err_t msc_host_install_device(uint8_t device_address, msc_host_device_handle_t *device); + +/** + * @brief Deinitialization of MSC device. + * + * @param[in] device Device handle obtained from msc_host_install_device function + * @return esp_err_t + */ +esp_err_t msc_host_uninstall_device(msc_host_device_handle_t device); + +/** + * @brief Helper function for reading sector from mass storage device. + * + * @warning This call is not thread safe and should not be combined + * with accesses to storage through file system. + * + * @note Provided sector and size cannot exceed + * sector_count and sector_size obtained from msc_host_device_info_t + * + * @param[in] device Device handle + * @param[in] sector Number of sector to be read + * @param[out] data Buffer into which data will be written + * @param[in] size Number of bytes to be read + * @return esp_err_t + */ +esp_err_t msc_host_read_sector(msc_host_device_handle_t device, size_t sector, void *data, size_t size) +__attribute__((deprecated("use API from esp_private/msc_scsi_bot.h"))); + +/** + * @brief Helper function for writing sector to mass storage device. + * + * @warning This call is not thread safe and should not be combined + * with accesses to storage through file system. + * + * @note Provided sector and size cannot exceed + * sector_count and sector_size obtained from msc_host_device_info_t + * + * @param[in] device Device handle + * @param[in] sector Number of sector to be read + * @param[in] data Data to be written to the sector + * @param[in] size Number of bytes to be written + * @return esp_err_t + */ +esp_err_t msc_host_write_sector(msc_host_device_handle_t device, size_t sector, const void *data, size_t size) +__attribute__((deprecated("use API from esp_private/msc_scsi_bot.h"))); + +/** + * @brief Handle MSC HOST events. + * + * If MSC Host install was called with create_background_task=false configuration, + * application needs to handle USB Host events itself. + * Do not call this function if MSC host install was called with create_background_task=true configuration + * + * @param[in] timeout Timeout in FreeRTOS tick + * @return + * - ESP_OK: All events handled + * - ESP_ERR_TIMEOUT: No events handled within the timeout + * - ESP_FAIL: Event handling finished, driver uninstalled. You do not have to call this function further + */ +esp_err_t msc_host_handle_events(uint32_t timeout); + +/** + * @brief Gets devices information. + * + * @param[in] device Handle to device + * @param[out] info Structure to be populated with device info + * @return esp_err_t + */ +esp_err_t msc_host_get_device_info(msc_host_device_handle_t device, msc_host_device_info_t *info); + +/** + * @brief Print configuration descriptor. + * + * @param[in] device Handle of MSC device + * @return esp_err_t + */ +esp_err_t msc_host_print_descriptors(msc_host_device_handle_t device); + +/** + * @brief MSC Bulk Only Transport Reset Recovery + * + * @see USB Mass Storage Class – Bulk Only Transport, Chapter 5.3.4 + * + * @param[in] device Handle of MSC device + * @return + * - ESP_OK: The device was recovered from reset + * - ESP_FAIL: Recovery unsuccessful, might indicate broken device + */ +esp_err_t msc_host_reset_recovery(msc_host_device_handle_t device); + +#ifdef __cplusplus +} +#endif //__cplusplus diff --git a/managed_components/espressif__usb_host_msc/include/usb/msc_host_vfs.h b/managed_components/espressif__usb_host_msc/include/usb/msc_host_vfs.h new file mode 100644 index 0000000..c116eb7 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/include/usb/msc_host_vfs.h @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_vfs_fat.h" +#include "usb/msc_host.h" +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct msc_host_vfs *msc_host_vfs_handle_t; /**< VFS handle to attached Mass Storage device */ + +/** + * @brief Register MSC device to Virtual filesystem. + * + * @param[in] device Device handle obtained from MSC callback provided upon initialization + * @param[in] base_path Base VFS path to be used to access file storage + * @param[in] mount_config Mount configuration. + * @param[out] vfs_handle Handle to MSC device associated with registered VFS + * @return esp_err_t + */ +esp_err_t msc_host_vfs_register(msc_host_device_handle_t device, + const char *base_path, + const esp_vfs_fat_mount_config_t *mount_config, + msc_host_vfs_handle_t *vfs_handle); + + +/** + * @brief Unregister MSC device from Virtual filesystem. + * + * @param[in] vfs_handle VFS handle obtained from MSC callback provided upon initialization + * @return esp_err_t + */ +esp_err_t msc_host_vfs_unregister(msc_host_vfs_handle_t vfs_handle); + +#ifdef __cplusplus +} +#endif diff --git a/managed_components/espressif__usb_host_msc/private_include/diskio_usb.h b/managed_components/espressif__usb_host_msc/private_include/diskio_usb.h new file mode 100644 index 0000000..6327d6e --- /dev/null +++ b/managed_components/espressif__usb_host_msc/private_include/diskio_usb.h @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Mass storage disk initialization structure + */ +typedef struct { + uint32_t block_size; /**< Block size */ + uint32_t block_count; /**< Block count */ +} usb_disk_t; + +/** + * @brief Register mass storage disk to fat file system + * + * @param[in] pdrv Number of free drive obtained from ff_diskio_get_drive() function + * @param[in] disk usb_disk_t structure + */ +void ff_diskio_register_msc(uint8_t pdrv, usb_disk_t *disk); + +/** + * @brief Obtains number of drive assigned to usb disk upon calling ff_diskio_register_msc() + * + * @param[in] disk usb_disk_t structure + * @return Drive number + */ +uint8_t ff_diskio_get_pdrv_disk(const usb_disk_t *disk); + +#ifdef __cplusplus +} +#endif //__cplusplus diff --git a/managed_components/espressif__usb_host_msc/private_include/msc_common.h b/managed_components/espressif__usb_host_msc/private_include/msc_common.h new file mode 100644 index 0000000..512d85b --- /dev/null +++ b/managed_components/espressif__usb_host_msc/private_include/msc_common.h @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "esp_check.h" +#include "diskio_usb.h" +#include "usb/usb_host.h" +#include "usb/usb_types_stack.h" +#include "freertos/semphr.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef enum { + MSC_EP_OUT, + MSC_EP_IN +} msc_endpoint_t; + +typedef struct { + uint16_t bulk_in_mps; + uint8_t bulk_in_ep; + uint8_t bulk_out_ep; + uint8_t iface_num; +} msc_config_t; + +typedef struct msc_host_device { + STAILQ_ENTRY(msc_host_device) tailq_entry; + SemaphoreHandle_t transfer_done; + usb_device_handle_t handle; + usb_transfer_t *xfer; + msc_config_t config; + usb_disk_t disk; +} msc_device_t; + +/** + * @brief Trigger a BULK transfer to device + * + * Data buffer ownership is transferred to the MSC driver and the application cannot access it before the transfer finishes. + * + * @param[in] device_handle MSC device handle + * @param[inout] data Data buffer. Direction depends on 'ep'. + * @param[in] size Size of buffer in bytes + * @param[in] ep Direction of the transfer + * @return esp_err_t + */ +esp_err_t msc_bulk_transfer(msc_device_t *device_handle, uint8_t *data, size_t size, msc_endpoint_t ep); + +/** + * @brief Trigger a CTRL transfer to device + * + * The request and data must be filled by accessing private device_handle->xfer before calling this function + * + * @param[in] device_handle MSC device handle + * @param[in] len Length of the transfer + * @return esp_err_t + */ +esp_err_t msc_control_transfer(msc_device_t *device_handle, size_t len); + +/** + * @brief Reset endpoint and clear feature + * + * @param[in] device MSC device handle + * @param[in] endpoint Endpoint number + * @return esp_err_t + */ +esp_err_t clear_feature(msc_device_t *device, uint8_t endpoint); + +#define MSC_GOTO_ON_ERROR(exp) ESP_GOTO_ON_ERROR(exp, fail, TAG, "") + +#define MSC_GOTO_ON_FALSE(exp, err) ESP_GOTO_ON_FALSE( (exp), err, fail, TAG, "" ) + +#define MSC_RETURN_ON_ERROR(exp) ESP_RETURN_ON_ERROR((exp), TAG, "") + +#define MSC_RETURN_ON_FALSE(exp, err) ESP_RETURN_ON_FALSE( (exp), (err), TAG, "") + +#define MSC_RETURN_ON_INVALID_ARG(exp) ESP_RETURN_ON_FALSE((exp) != NULL, ESP_ERR_INVALID_ARG, TAG, "") + +#ifdef __cplusplus +} +#endif diff --git a/managed_components/espressif__usb_host_msc/src/diskio_usb.c b/managed_components/espressif__usb_host_msc/src/diskio_usb.c new file mode 100644 index 0000000..76b25f9 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/src/diskio_usb.c @@ -0,0 +1,110 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "diskio_impl.h" +#include "ffconf.h" +#include "ff.h" +#include "esp_log.h" +#include "diskio_usb.h" +#include "msc_scsi_bot.h" +#include "msc_common.h" +#include "usb/usb_types_stack.h" + +static usb_disk_t *s_disks[FF_VOLUMES] = { NULL }; + +static const char *TAG = "diskio_usb"; + +static DSTATUS usb_disk_initialize (BYTE pdrv) +{ + return RES_OK; +} + +static DSTATUS usb_disk_status (BYTE pdrv) +{ + return RES_OK; +} + +static DRESULT usb_disk_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count) +{ + assert(pdrv < FF_VOLUMES); + assert(s_disks[pdrv]); + + usb_disk_t *disk = s_disks[pdrv]; + size_t sector_size = disk->block_size; + msc_device_t *dev = __containerof(disk, msc_device_t, disk); + + esp_err_t err = scsi_cmd_read10(dev, buff, sector, count, sector_size); + if (err != ESP_OK) { + ESP_LOGE(TAG, "scsi_cmd_read10 failed (%d)", err); + return RES_ERROR; + } + + return RES_OK; +} + +static DRESULT usb_disk_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count) +{ + assert(pdrv < FF_VOLUMES); + assert(s_disks[pdrv]); + + usb_disk_t *disk = s_disks[pdrv]; + size_t sector_size = disk->block_size; + msc_device_t *dev = __containerof(disk, msc_device_t, disk); + + esp_err_t err = scsi_cmd_write10(dev, buff, sector, count, sector_size); + if (err != ESP_OK) { + ESP_LOGE(TAG, "scsi_cmd_write10 failed (%d)", err); + return RES_ERROR; + } + return RES_OK; +} + +static DRESULT usb_disk_ioctl (BYTE pdrv, BYTE cmd, void *buff) +{ + assert(pdrv < FF_VOLUMES); + assert(s_disks[pdrv]); + + usb_disk_t *disk = s_disks[pdrv]; + + switch (cmd) { + case CTRL_SYNC: + return RES_OK; + case GET_SECTOR_COUNT: + *((DWORD *) buff) = disk->block_count; + return RES_OK; + case GET_SECTOR_SIZE: + *((WORD *) buff) = disk->block_size; + return RES_OK; + case GET_BLOCK_SIZE: + return RES_ERROR; + } + return RES_ERROR; +} + +void ff_diskio_register_msc(BYTE pdrv, usb_disk_t *disk) +{ + assert(pdrv < FF_VOLUMES); + + static const ff_diskio_impl_t usb_disk_impl = { + .init = &usb_disk_initialize, + .status = &usb_disk_status, + .read = &usb_disk_read, + .write = &usb_disk_write, + .ioctl = &usb_disk_ioctl + }; + s_disks[pdrv] = disk; + ff_diskio_register(pdrv, &usb_disk_impl); +} + +BYTE ff_diskio_get_pdrv_disk(const usb_disk_t *disk) +{ + for (int i = 0; i < FF_VOLUMES; i++) { + if (disk == s_disks[i]) { + return i; + } + } + return 0xff; +} diff --git a/managed_components/espressif__usb_host_msc/src/msc_host.c b/managed_components/espressif__usb_host_msc/src/msc_host.c new file mode 100644 index 0000000..0e49408 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/src/msc_host.c @@ -0,0 +1,698 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "usb/usb_host.h" +#include "diskio_usb.h" +#include "msc_common.h" +#include "usb/msc_host.h" +#include "msc_scsi_bot.h" +#include "usb/usb_types_ch9.h" +#include "usb/usb_helpers.h" +#include "soc/soc_memory_layout.h" + +// MSC driver spin lock +static portMUX_TYPE msc_lock = portMUX_INITIALIZER_UNLOCKED; +#define MSC_ENTER_CRITICAL() portENTER_CRITICAL(&msc_lock) +#define MSC_EXIT_CRITICAL() portEXIT_CRITICAL(&msc_lock) + +#define MSC_GOTO_ON_FALSE_CRITICAL(exp, err) \ + do { \ + if(!(exp)) { \ + MSC_EXIT_CRITICAL(); \ + ret = err; \ + goto fail; \ + } \ + } while(0) + +#define MSC_RETURN_ON_FALSE_CRITICAL(exp, err) \ + do { \ + if(!(exp)) { \ + MSC_EXIT_CRITICAL(); \ + return err; \ + } \ + } while(0) + +// MSC Control requests +#define USB_MASS_REQ_INIT_RESET(ctrl_req_ptr, intf_num) ({ \ + (ctrl_req_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | \ + USB_BM_REQUEST_TYPE_TYPE_CLASS | \ + USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \ + (ctrl_req_ptr)->bRequest = 0xFF; \ + (ctrl_req_ptr)->wValue = 0; \ + (ctrl_req_ptr)->wIndex = (intf_num); \ + (ctrl_req_ptr)->wLength = 0; \ +}) + +#define USB_MASS_REQ_INIT_GET_MAX_LUN(ctrl_req_ptr, intf_num) ({ \ + (ctrl_req_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_IN | \ + USB_BM_REQUEST_TYPE_TYPE_CLASS | \ + USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \ + (ctrl_req_ptr)->bRequest = 0xFE; \ + (ctrl_req_ptr)->wValue = 0; \ + (ctrl_req_ptr)->wIndex = (intf_num); \ + (ctrl_req_ptr)->wLength = 1; \ +}) + +#define FEATURE_SELECTOR_ENDPOINT 0 +#define USB_SETUP_PACKET_INIT_CLEAR_FEATURE_EP(ctrl_req_ptr, ep_num) ({ \ + (ctrl_req_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | \ + USB_BM_REQUEST_TYPE_TYPE_STANDARD | \ + USB_BM_REQUEST_TYPE_RECIP_ENDPOINT; \ + (ctrl_req_ptr)->bRequest = USB_B_REQUEST_CLEAR_FEATURE; \ + (ctrl_req_ptr)->wValue = FEATURE_SELECTOR_ENDPOINT; \ + (ctrl_req_ptr)->wIndex = (ep_num); \ + (ctrl_req_ptr)->wLength = 0; \ +}) + +#define DEFAULT_XFER_SIZE (64) // Transfer size used for all transfers apart from SCSI read/write +#define WAIT_FOR_READY_TIMEOUT_MS 5000 +#define SCSI_COMMAND_SET 0x06 +#define BULK_ONLY_TRANSFER 0x50 +#define MSC_NO_SENSE 0x00 +#define MSC_NOT_READY 0x02 +#define MSC_UNIT_ATTENTION 0x06 + +static const char *TAG = "USB_MSC"; +typedef struct { + usb_host_client_handle_t client_handle; + msc_host_event_cb_t user_cb; + void *user_arg; + SemaphoreHandle_t all_events_handled; + volatile bool end_client_event_handling; + bool event_handling_started; + STAILQ_HEAD(devices, msc_host_device) devices_tailq; +} msc_driver_t; + +static msc_driver_t *s_msc_driver; + + +static const usb_standard_desc_t *next_interface_desc(const usb_standard_desc_t *desc, size_t len, size_t *offset) +{ + return usb_parse_next_descriptor_of_type(desc, len, USB_W_VALUE_DT_INTERFACE, (int *)offset); +} + +static const usb_standard_desc_t *next_endpoint_desc(const usb_standard_desc_t *desc, size_t len, size_t *offset) +{ + return usb_parse_next_descriptor_of_type(desc, len, USB_B_DESCRIPTOR_TYPE_ENDPOINT, (int *)offset); +} + +static inline bool is_in_endpoint(uint8_t endpoint) +{ + return endpoint & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK ? true : false; +} + +static const usb_intf_desc_t *find_msc_interface(const usb_config_desc_t *config_desc, size_t *offset) +{ + size_t total_length = config_desc->wTotalLength; + const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)config_desc; + + next_desc = next_interface_desc(next_desc, total_length, offset); + + while ( next_desc ) { + + const usb_intf_desc_t *ifc_desc = (const usb_intf_desc_t *)next_desc; + + if ( ifc_desc->bInterfaceClass == USB_CLASS_MASS_STORAGE && + ifc_desc->bInterfaceSubClass == SCSI_COMMAND_SET && + ifc_desc->bInterfaceProtocol == BULK_ONLY_TRANSFER ) { + return ifc_desc; + } + + next_desc = next_interface_desc(next_desc, total_length, offset); + }; + return NULL; +} + +esp_err_t clear_feature(msc_device_t *device, uint8_t endpoint) +{ + usb_device_handle_t dev = device->handle; + usb_transfer_t *xfer = device->xfer; + + MSC_RETURN_ON_ERROR( usb_host_endpoint_halt(dev, endpoint) ); + + esp_err_t err = usb_host_endpoint_flush(dev, endpoint); + if (ESP_OK != err ) { + // The endpoint cannot be flushed if it does not have STALL condition + // Return without ESP_LOGE + return err; + } + MSC_RETURN_ON_ERROR( usb_host_endpoint_clear(dev, endpoint) ); + + USB_SETUP_PACKET_INIT_CLEAR_FEATURE_EP((usb_setup_packet_t *)xfer->data_buffer, endpoint); + MSC_RETURN_ON_ERROR( msc_control_transfer(device, USB_SETUP_PACKET_SIZE) ); + + return ESP_OK; +} + +/** + * @brief Bulk-Only Mass Storage Reset + * + * This class-specific request shall ready the device for the next CBW from the host. + * The device shall preserve the value of its bulk data toggle bits and endpoint STALL conditions despite the Bulk-Only Mass Storage Reset. + * + * @see USB Mass Storage Class – Bulk Only Transport, Chapter 3.1 + * + * @param[in] dev MSC device handle + * @return esp_err_t + */ +static esp_err_t msc_mass_reset(msc_host_device_handle_t dev) +{ + msc_device_t *device = (msc_device_t *)dev; + usb_transfer_t *xfer = device->xfer; + + USB_MASS_REQ_INIT_RESET((usb_setup_packet_t *)xfer->data_buffer, device->config.iface_num); + MSC_RETURN_ON_ERROR( msc_control_transfer(device, USB_SETUP_PACKET_SIZE) ); + + return ESP_OK; +} + +/** + * @brief MSC get maximum Logical Unit Number + * + * If the device implements 3 LUNs, the returned value is 2. (LUN0, LUN1, LUN2). + * + * This driver does not support multiple LUNs yet. + * + * @see USB Mass Storage Class – Bulk Only Transport, Chapter 3.2 + * + * @param[in] dev MSC device handle + * @param[out] lun Maximum Logical Unit Number + * @return esp_err_t + */ +__attribute__((unused)) static esp_err_t msc_get_max_lun(msc_host_device_handle_t dev, uint8_t *lun) +{ + msc_device_t *device = (msc_device_t *)dev; + usb_transfer_t *xfer = device->xfer; + + USB_MASS_REQ_INIT_GET_MAX_LUN((usb_setup_packet_t *)xfer->data_buffer, device->config.iface_num); + MSC_RETURN_ON_ERROR( msc_control_transfer(device, USB_SETUP_PACKET_SIZE + 1) ); + + *lun = xfer->data_buffer[USB_SETUP_PACKET_SIZE]; + + return ESP_OK; +} + +/** + * @brief Extracts configuration from configuration descriptor. + * + * @note Passes interface and endpoint descriptors to obtain: + + * - interface number, IN endpoint, OUT endpoint, max. packet size + * + * @param[in] cfg_desc Configuration descriptor + * @param[out] cfg Obtained configuration + * @return esp_err_t + */ +static esp_err_t extract_config_from_descriptor(const usb_config_desc_t *cfg_desc, msc_config_t *cfg) +{ + size_t offset = 0; + size_t total_len = cfg_desc->wTotalLength; + const usb_intf_desc_t *ifc_desc = find_msc_interface(cfg_desc, &offset); + assert(ifc_desc); + const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)ifc_desc; + const usb_ep_desc_t *ep_desc = NULL; + + cfg->iface_num = ifc_desc->bInterfaceNumber; + + next_desc = next_endpoint_desc(next_desc, total_len, &offset); + MSC_RETURN_ON_FALSE(next_desc, ESP_ERR_NOT_SUPPORTED); + ep_desc = (const usb_ep_desc_t *)next_desc; + + if (is_in_endpoint(ep_desc->bEndpointAddress)) { + cfg->bulk_in_ep = ep_desc->bEndpointAddress; + cfg->bulk_in_mps = ep_desc->wMaxPacketSize; + } else { + cfg->bulk_out_ep = ep_desc->bEndpointAddress; + } + + next_desc = next_endpoint_desc(next_desc, total_len, &offset); + MSC_RETURN_ON_FALSE(next_desc, ESP_ERR_NOT_SUPPORTED); + ep_desc = (const usb_ep_desc_t *)next_desc; + + if (is_in_endpoint(ep_desc->bEndpointAddress)) { + cfg->bulk_in_ep = ep_desc->bEndpointAddress; + cfg->bulk_in_mps = ep_desc->wMaxPacketSize; + } else { + cfg->bulk_out_ep = ep_desc->bEndpointAddress; + } + + return ESP_OK; +} + +static esp_err_t msc_deinit_device(msc_device_t *dev, bool install_failed) +{ + MSC_ENTER_CRITICAL(); + MSC_RETURN_ON_FALSE_CRITICAL( dev, ESP_ERR_INVALID_STATE ); + STAILQ_REMOVE(&s_msc_driver->devices_tailq, dev, msc_host_device, tailq_entry); + MSC_EXIT_CRITICAL(); + + if (dev->transfer_done) { + vSemaphoreDelete(dev->transfer_done); + } + if (install_failed) { + // Error code is unchecked, as it's unknown at what point installation failed. + usb_host_interface_release(s_msc_driver->client_handle, dev->handle, dev->config.iface_num); + usb_host_device_close(s_msc_driver->client_handle, dev->handle); + usb_host_transfer_free(dev->xfer); + } else { + MSC_RETURN_ON_ERROR( usb_host_interface_release(s_msc_driver->client_handle, dev->handle, dev->config.iface_num) ); + MSC_RETURN_ON_ERROR( usb_host_device_close(s_msc_driver->client_handle, dev->handle) ); + MSC_RETURN_ON_ERROR( usb_host_transfer_free(dev->xfer) ); + } + + free(dev); + return ESP_OK; +} + +// Some MSC devices requires to change its internal state from non-ready to ready +static esp_err_t msc_wait_for_ready_state(msc_device_t *dev, size_t timeout_ms) +{ + esp_err_t err; + scsi_sense_data_t sense; + uint32_t trials = MAX(1, timeout_ms / 100); + + do { + err = scsi_cmd_unit_ready(dev); + if (err == ESP_OK) { + return ESP_OK; + } else { + // Some MSC devices report 'NOT READY TO READY TRANSITION - MEDIA CHANGED', which isn't cleared until a REQUEST SENSE is performed. + MSC_RETURN_ON_ERROR( scsi_cmd_sense(dev, &sense) ); + if (sense.key != MSC_NOT_READY && + sense.key != MSC_UNIT_ATTENTION && + sense.key != MSC_NO_SENSE) { + return ESP_ERR_MSC_INTERNAL; + } + } + vTaskDelay( pdMS_TO_TICKS(100) ); + } while (trials-- && err); + + return err; +} + +static bool is_mass_storage_device(uint8_t dev_addr) +{ + size_t dummy = 0; + bool is_msc_device = false; + usb_device_handle_t device; + const usb_config_desc_t *config_desc; + + if ( usb_host_device_open(s_msc_driver->client_handle, dev_addr, &device) == ESP_OK) { + if ( usb_host_get_active_config_descriptor(device, &config_desc) == ESP_OK ) { + if ( find_msc_interface(config_desc, &dummy) ) { + is_msc_device = true; + } else { + ESP_LOGD(TAG, "Connected USB device is not MSC"); + } + } + usb_host_device_close(s_msc_driver->client_handle, device); + } + + return is_msc_device; +} + +esp_err_t msc_host_handle_events(uint32_t timeout) +{ + MSC_RETURN_ON_FALSE(s_msc_driver != NULL, ESP_ERR_INVALID_STATE); + + ESP_LOGV(TAG, "USB MSC handling"); + s_msc_driver->event_handling_started = true; + esp_err_t ret = usb_host_client_handle_events(s_msc_driver->client_handle, timeout); + if (s_msc_driver->end_client_event_handling) { + xSemaphoreGive(s_msc_driver->all_events_handled); + return ESP_FAIL; + } + return ret; +} + +/** + * @brief USB Client Event handler + * + * Handle all USB client events such as USB transfers and connections/disconnections + * + * @param[in] arg Argument, not used + */ +static void event_handler_task(void *arg) +{ + ESP_LOGD(TAG, "USB MSC handling start"); + while (msc_host_handle_events(portMAX_DELAY) == ESP_OK) { + } + ESP_LOGD(TAG, "USB MSC handling stop"); + vTaskDelete(NULL); +} + +static msc_device_t *find_msc_device(usb_device_handle_t device_handle) +{ + msc_device_t *iter; + msc_device_t *device_found = NULL; + + MSC_ENTER_CRITICAL(); + STAILQ_FOREACH(iter, &s_msc_driver->devices_tailq, tailq_entry) { + if (device_handle == iter->handle) { + device_found = iter; + break; + } + } + MSC_EXIT_CRITICAL(); + + return device_found; +} + +static void client_event_cb(const usb_host_client_event_msg_t *event, void *arg) +{ + if (event->event == USB_HOST_CLIENT_EVENT_NEW_DEV) { + if (is_mass_storage_device(event->new_dev.address)) { + const msc_host_event_t msc_event = { + .event = MSC_DEVICE_CONNECTED, + .device.address = event->new_dev.address, + }; + s_msc_driver->user_cb(&msc_event, s_msc_driver->user_arg); + } + } else if (event->event == USB_HOST_CLIENT_EVENT_DEV_GONE) { + msc_device_t *msc_device = find_msc_device(event->dev_gone.dev_hdl); + if (msc_device) { + const msc_host_event_t msc_event = { + .event = MSC_DEVICE_DISCONNECTED, + .device.handle = msc_device, + }; + s_msc_driver->user_cb(&msc_event, s_msc_driver->user_arg); + } + } +} + +esp_err_t msc_host_install(const msc_host_driver_config_t *config) +{ + esp_err_t ret; + + MSC_RETURN_ON_INVALID_ARG(config); + MSC_RETURN_ON_INVALID_ARG(config->callback); + if ( config->create_backround_task ) { + MSC_RETURN_ON_FALSE(config->stack_size != 0, ESP_ERR_INVALID_ARG); + MSC_RETURN_ON_FALSE(config->task_priority != 0, ESP_ERR_INVALID_ARG); + } + MSC_RETURN_ON_FALSE(!s_msc_driver, ESP_ERR_INVALID_STATE); + + msc_driver_t *driver = calloc(1, sizeof(msc_driver_t)); + MSC_RETURN_ON_FALSE(driver, ESP_ERR_NO_MEM); + driver->user_cb = config->callback; + driver->user_arg = config->callback_arg; + + usb_host_client_config_t client_config = { + .async.client_event_callback = client_event_cb, + .async.callback_arg = NULL, + .max_num_event_msg = 10, + }; + + driver->end_client_event_handling = false; + driver->all_events_handled = xSemaphoreCreateBinary(); + MSC_GOTO_ON_FALSE(driver->all_events_handled, ESP_ERR_NO_MEM); + + MSC_GOTO_ON_ERROR( usb_host_client_register(&client_config, &driver->client_handle) ); + + MSC_ENTER_CRITICAL(); + MSC_GOTO_ON_FALSE_CRITICAL(!s_msc_driver, ESP_ERR_INVALID_STATE); + s_msc_driver = driver; + STAILQ_INIT(&s_msc_driver->devices_tailq); + MSC_EXIT_CRITICAL(); + + if (config->create_backround_task) { + BaseType_t task_created = xTaskCreatePinnedToCore( + event_handler_task, + "USB MSC", + config->stack_size, + NULL, + config->task_priority, + NULL, + config->core_id); + MSC_GOTO_ON_FALSE(task_created, ESP_ERR_NO_MEM); + } + + return ESP_OK; + +fail: + s_msc_driver = NULL; + usb_host_client_deregister(driver->client_handle); + if (driver->all_events_handled) { + vSemaphoreDelete(driver->all_events_handled); + } + free(driver); + return ret; +} + +esp_err_t msc_host_uninstall(void) +{ + // Make sure msc driver is installed, + // not being uninstalled from other task + // and no msc device is registered + MSC_ENTER_CRITICAL(); + MSC_RETURN_ON_FALSE_CRITICAL( s_msc_driver != NULL, ESP_ERR_INVALID_STATE ); + MSC_RETURN_ON_FALSE_CRITICAL( !s_msc_driver->end_client_event_handling, ESP_ERR_INVALID_STATE ); + MSC_RETURN_ON_FALSE_CRITICAL( STAILQ_EMPTY(&s_msc_driver->devices_tailq), ESP_ERR_INVALID_STATE ); + s_msc_driver->end_client_event_handling = true; + MSC_EXIT_CRITICAL(); + + if (s_msc_driver->event_handling_started) { + ESP_ERROR_CHECK( usb_host_client_unblock(s_msc_driver->client_handle) ); + // In case the event handling started, we must wait until it finishes + xSemaphoreTake(s_msc_driver->all_events_handled, portMAX_DELAY); + } + vSemaphoreDelete(s_msc_driver->all_events_handled); + ESP_ERROR_CHECK( usb_host_client_deregister(s_msc_driver->client_handle) ); + free(s_msc_driver); + s_msc_driver = NULL; + return ESP_OK; +} + +esp_err_t msc_host_install_device(uint8_t device_address, msc_host_device_handle_t *msc_device_handle) +{ + esp_err_t ret; + uint32_t block_size, block_count; + const usb_config_desc_t *config_desc; + msc_device_t *msc_device; + + MSC_GOTO_ON_FALSE( msc_device = calloc(1, sizeof(msc_device_t)), ESP_ERR_NO_MEM ); + + MSC_ENTER_CRITICAL(); + MSC_GOTO_ON_FALSE_CRITICAL( s_msc_driver, ESP_ERR_INVALID_STATE ); + MSC_GOTO_ON_FALSE_CRITICAL( s_msc_driver->client_handle, ESP_ERR_INVALID_STATE ); + STAILQ_INSERT_TAIL(&s_msc_driver->devices_tailq, msc_device, tailq_entry); + MSC_EXIT_CRITICAL(); + + MSC_GOTO_ON_FALSE( msc_device->transfer_done = xSemaphoreCreateBinary(), ESP_ERR_NO_MEM); + MSC_GOTO_ON_ERROR( usb_host_device_open(s_msc_driver->client_handle, device_address, &msc_device->handle) ); + MSC_GOTO_ON_ERROR( usb_host_get_active_config_descriptor(msc_device->handle, &config_desc) ); + MSC_GOTO_ON_ERROR( extract_config_from_descriptor(config_desc, &msc_device->config) ); + MSC_GOTO_ON_ERROR( usb_host_transfer_alloc(DEFAULT_XFER_SIZE, 0, &msc_device->xfer) ); + MSC_GOTO_ON_ERROR( usb_host_interface_claim( + s_msc_driver->client_handle, + msc_device->handle, + msc_device->config.iface_num, 0) ); + + MSC_GOTO_ON_ERROR( scsi_cmd_inquiry(msc_device) ); + MSC_GOTO_ON_ERROR( msc_wait_for_ready_state(msc_device, WAIT_FOR_READY_TIMEOUT_MS) ); + MSC_GOTO_ON_ERROR( scsi_cmd_read_capacity(msc_device, &block_size, &block_count) ); + + msc_device->disk.block_size = block_size; + msc_device->disk.block_count = block_count; + *msc_device_handle = msc_device; + + return ESP_OK; + +fail: + msc_deinit_device(msc_device, true); + return ret; +} + +esp_err_t msc_host_uninstall_device(msc_host_device_handle_t device) +{ + MSC_RETURN_ON_INVALID_ARG(device); + return msc_deinit_device((msc_device_t *)device, false); +} + +esp_err_t msc_host_read_sector(msc_host_device_handle_t device, size_t sector, void *data, size_t size) +{ + MSC_RETURN_ON_INVALID_ARG(device); + msc_device_t *dev = (msc_device_t *)device; + + return scsi_cmd_read10(dev, data, sector, 1, dev->disk.block_size); +} + +esp_err_t msc_host_write_sector(msc_host_device_handle_t device, size_t sector, const void *data, size_t size) +{ + MSC_RETURN_ON_INVALID_ARG(device); + msc_device_t *dev = (msc_device_t *)device; + + return scsi_cmd_write10(dev, data, sector, 1, dev->disk.block_size); +} + +static void copy_string_desc(wchar_t *dest, const usb_str_desc_t *src) +{ + if (dest == NULL) { + return; + } + if (src != NULL) { + size_t len = MIN((src->bLength - USB_STANDARD_DESC_SIZE) / 2, MSC_STR_DESC_SIZE - 1); + for (int i = 0; i < len; i++) { + dest[i] = (wchar_t)src->wData[i]; + } + if (dest != NULL) { // This should be always true, we just check to avoid LoadProhibited exception + dest[len] = 0; + } + } else { + dest[0] = 0; + } +} + +esp_err_t msc_host_get_device_info(msc_host_device_handle_t device, msc_host_device_info_t *info) +{ + MSC_RETURN_ON_INVALID_ARG(device); + MSC_RETURN_ON_INVALID_ARG(info); + + msc_device_t *dev = (msc_device_t *)device; + const usb_device_desc_t *desc; + usb_device_info_t dev_info; + + MSC_RETURN_ON_ERROR( usb_host_get_device_descriptor(dev->handle, &desc) ); + MSC_RETURN_ON_ERROR( usb_host_device_info(dev->handle, &dev_info) ); + + info->idProduct = desc->idProduct; + info->idVendor = desc->idVendor; + info->sector_size = dev->disk.block_size; + info->sector_count = dev->disk.block_count; + + copy_string_desc(info->iManufacturer, dev_info.str_desc_manufacturer); + copy_string_desc(info->iProduct, dev_info.str_desc_product); + copy_string_desc(info->iSerialNumber, dev_info.str_desc_serial_num); + + return ESP_OK; +} + +esp_err_t msc_host_print_descriptors(msc_host_device_handle_t device) +{ + msc_device_t *dev = (msc_device_t *)device; + const usb_device_desc_t *device_desc; + const usb_config_desc_t *config_desc; + MSC_RETURN_ON_ERROR( usb_host_get_device_descriptor(dev->handle, &device_desc) ); + MSC_RETURN_ON_ERROR( usb_host_get_active_config_descriptor(dev->handle, &config_desc) ); + usb_print_device_descriptor(device_desc); + usb_print_config_descriptor(config_desc, NULL); + return ESP_OK; +} + +static void transfer_callback(usb_transfer_t *transfer) +{ + msc_device_t *device = (msc_device_t *)transfer->context; + + if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) { + ESP_LOGE("Transfer failed", "Status %d", transfer->status); + } + + xSemaphoreGive(device->transfer_done); +} + +static usb_transfer_status_t wait_for_transfer_done(usb_transfer_t *xfer) +{ + msc_device_t *device = (msc_device_t *)xfer->context; + BaseType_t received = xSemaphoreTake(device->transfer_done, pdMS_TO_TICKS(xfer->timeout_ms)); + usb_transfer_status_t status = xfer->status; + + if (received != pdTRUE) { + usb_host_endpoint_halt(xfer->device_handle, xfer->bEndpointAddress); + usb_host_endpoint_flush(xfer->device_handle, xfer->bEndpointAddress); + usb_host_endpoint_clear(xfer->device_handle, xfer->bEndpointAddress); + xSemaphoreTake(device->transfer_done, portMAX_DELAY); // Since we flushed the EP, this should return immediately + status = USB_TRANSFER_STATUS_TIMED_OUT; + } + + return status; +} + +esp_err_t msc_bulk_transfer(msc_device_t *device, uint8_t *data, size_t size, msc_endpoint_t ep) +{ + esp_err_t ret = ESP_OK; + usb_transfer_t *xfer = device->xfer; + size_t transfer_size = (ep == MSC_EP_IN) ? usb_round_up_to_mps(size, device->config.bulk_in_mps) : size; + + if (xfer->data_buffer_size < transfer_size) { + // The allocated buffer is not large enough -> realloc + MSC_RETURN_ON_ERROR( usb_host_transfer_free(xfer) ); + MSC_RETURN_ON_ERROR( usb_host_transfer_alloc(transfer_size, 0, &device->xfer) ); + xfer = device->xfer; + } + + if (ep == MSC_EP_IN) { + xfer->bEndpointAddress = device->config.bulk_in_ep; + } else { + xfer->bEndpointAddress = device->config.bulk_out_ep; + memcpy(xfer->data_buffer, data, size); + } + + xfer->num_bytes = transfer_size; + xfer->device_handle = device->handle; + xfer->callback = transfer_callback; + xfer->timeout_ms = 5000; + xfer->context = device; + + MSC_RETURN_ON_ERROR( usb_host_transfer_submit(xfer) ); + const usb_transfer_status_t status = wait_for_transfer_done(xfer); + switch (status) { + case USB_TRANSFER_STATUS_COMPLETED: + if (ep == MSC_EP_IN) { + memcpy(data, xfer->data_buffer, xfer->actual_num_bytes); + } + ret = ESP_OK; + break; + case USB_TRANSFER_STATUS_STALL: + ret = ESP_ERR_MSC_STALL; break; + default: + ret = ESP_ERR_MSC_INTERNAL; break; + } + + return ret; +} + +esp_err_t msc_control_transfer(msc_device_t *device, size_t len) +{ + usb_transfer_t *xfer = device->xfer; + xfer->device_handle = device->handle; + xfer->bEndpointAddress = 0; + xfer->callback = transfer_callback; + xfer->timeout_ms = 5000; + xfer->num_bytes = len; + xfer->context = device; + + MSC_RETURN_ON_ERROR( usb_host_transfer_submit_control(s_msc_driver->client_handle, xfer)); + return wait_for_transfer_done(xfer) == USB_TRANSFER_STATUS_COMPLETED ? ESP_OK : ESP_ERR_MSC_INTERNAL; +} + +esp_err_t msc_host_reset_recovery(msc_host_device_handle_t device) +{ + // USB Mass Storage Class – Bulk Only Transport Revision 1.0 + // 5.3.4 Reset Recovery + // For Reset Recovery the host shall issue in the following order: : + // (a) a Bulk-Only Mass Storage Reset + // (b) a Clear Feature HALT to the Bulk-In endpoint + // (c) a Clear Feature HALT to the Bulk-Out endpoint + + ESP_RETURN_ON_ERROR( msc_mass_reset(device), TAG, "Mass reset failed" ); + // Clear feature will fail if there is not STALL on the endpoint, so we don't check the errors here + clear_feature(device, device->config.bulk_in_ep); + clear_feature(device, device->config.bulk_out_ep); + MSC_RETURN_ON_ERROR( msc_wait_for_ready_state(device, WAIT_FOR_READY_TIMEOUT_MS) ); + return ESP_OK; +} diff --git a/managed_components/espressif__usb_host_msc/src/msc_host_vfs.c b/managed_components/espressif__usb_host_msc/src/msc_host_vfs.c new file mode 100644 index 0000000..eac6bc4 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/src/msc_host_vfs.c @@ -0,0 +1,131 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "msc_common.h" +#include "usb/msc_host_vfs.h" +#include "diskio_impl.h" +#include "ffconf.h" +#include "ff.h" +#include "esp_idf_version.h" + +#define DRIVE_STR_LEN 3 + +typedef struct msc_host_vfs { + char drive[DRIVE_STR_LEN]; + char *base_path; + uint8_t pdrv; +} msc_host_vfs_t; + +static const char *TAG = "MSC VFS"; + +static esp_err_t msc_format_storage(size_t block_size, size_t allocation_size, const char *drv) +{ + void *workbuf = NULL; + const size_t workbuf_size = 4096; + + MSC_RETURN_ON_FALSE( workbuf = ff_memalloc(workbuf_size), ESP_ERR_NO_MEM ); + + // Valid value of cluster size is between sector_size and 128 * sector_size. + size_t cluster_size = MIN(MAX(allocation_size, block_size), 128 * block_size); + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) + FRESULT err = f_mkfs(drv, FM_ANY | FM_SFD, cluster_size, workbuf, workbuf_size); +#else + const MKFS_PARM opt = {(BYTE)(FM_ANY | FM_SFD), 0, 0, 0, cluster_size}; + FRESULT err = f_mkfs(drv, &opt, workbuf, workbuf_size); +#endif + + if (err) { + ESP_LOGE(TAG, "Formatting failed with error: %d", err); + free(workbuf); + return ESP_ERR_MSC_FORMAT_FAILED; + } + + free(workbuf); + return ESP_OK; +} + +static void dealloc_msc_vfs(msc_host_vfs_t *vfs) +{ + free(vfs->base_path); + free(vfs); +} + +esp_err_t msc_host_vfs_register(msc_host_device_handle_t device, + const char *base_path, + const esp_vfs_fat_mount_config_t *mount_config, + msc_host_vfs_handle_t *vfs_handle) +{ + MSC_RETURN_ON_INVALID_ARG(device); + MSC_RETURN_ON_INVALID_ARG(base_path); + MSC_RETURN_ON_INVALID_ARG(mount_config); + MSC_RETURN_ON_INVALID_ARG(vfs_handle); + + FATFS *fs = NULL; + BYTE pdrv; + bool diskio_registered = false; + esp_err_t ret = ESP_ERR_MSC_MOUNT_FAILED; + msc_device_t *dev = (msc_device_t *)device; + size_t block_size = dev->disk.block_size; + size_t alloc_size = mount_config->allocation_unit_size; + + msc_host_vfs_t *vfs = calloc(1, sizeof(msc_host_vfs_t)); + MSC_RETURN_ON_FALSE(vfs != NULL, ESP_ERR_NO_MEM); + + MSC_GOTO_ON_ERROR( ff_diskio_get_drive(&pdrv) ); + + ff_diskio_register_msc(pdrv, &dev->disk); + char drive[DRIVE_STR_LEN] = {(char)('0' + pdrv), ':', 0}; + diskio_registered = true; + + strncpy(vfs->drive, drive, DRIVE_STR_LEN); + MSC_GOTO_ON_FALSE( vfs->base_path = strdup(base_path), ESP_ERR_NO_MEM ); + vfs->pdrv = pdrv; + + MSC_GOTO_ON_ERROR( esp_vfs_fat_register(base_path, drive, mount_config->max_files, &fs) ); + + FRESULT fresult = f_mount(fs, drive, 1); + + if ( fresult != FR_OK) { + if (mount_config->format_if_mount_failed && + (fresult == FR_NO_FILESYSTEM || fresult == FR_INT_ERR)) { + MSC_GOTO_ON_ERROR( msc_format_storage(block_size, alloc_size, drive) ); + MSC_GOTO_ON_FALSE( f_mount(fs, drive, 0) == FR_OK, ESP_ERR_MSC_MOUNT_FAILED ); + } else { + goto fail; + } + } + + *vfs_handle = vfs; + return ESP_OK; + +fail: + if (diskio_registered) { + ff_diskio_unregister(pdrv); + } + esp_vfs_fat_unregister_path(base_path); + if (fs) { + f_mount(NULL, drive, 0); + } + dealloc_msc_vfs(vfs); + return ret; +} + +esp_err_t msc_host_vfs_unregister(msc_host_vfs_handle_t vfs_handle) +{ + MSC_RETURN_ON_INVALID_ARG(vfs_handle); + msc_host_vfs_t *vfs = (msc_host_vfs_t *)vfs_handle; + + f_mount(NULL, vfs->drive, 0); + ff_diskio_unregister(vfs->pdrv); + esp_vfs_fat_unregister_path(vfs->base_path); + dealloc_msc_vfs(vfs); + return ESP_OK; +} diff --git a/managed_components/espressif__usb_host_msc/src/msc_scsi_bot.c b/managed_components/espressif__usb_host_msc/src/msc_scsi_bot.c new file mode 100644 index 0000000..568ccab --- /dev/null +++ b/managed_components/espressif__usb_host_msc/src/msc_scsi_bot.c @@ -0,0 +1,489 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "esp_log.h" +#include "inttypes.h" +#include +#include +#include +#include +#include "esp_check.h" +#include "esp_log.h" +#include "msc_common.h" +#include "msc_scsi_bot.h" +#include "usb/msc_host.h" + +static const char *TAG = "USB_MSC_SCSI"; + +/* --------------------------- SCSI Definitions ----------------------------- */ +#define CMD_SENSE_VALID_BIT (1 << 7) +#define SCSI_FLAG_DPO (1<<4) +#define SCSI_FLAG_FUA (1<<3) + +#define SCSI_CMD_FORMAT_UNIT 0x04 +#define SCSI_CMD_INQUIRY 0x12 +#define SCSI_CMD_MODE_SELECT 0x55 +#define SCSI_CMD_MODE_SENSE 0x5A +#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_CMD_READ10 0x28 +#define SCSI_CMD_READ12 0xA8 +#define SCSI_CMD_READ_CAPACITY 0x25 +#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 +#define SCSI_CMD_REQUEST_SENSE 0x03 +#define SCSI_CMD_REZERO 0x01 +#define SCSI_CMD_SEEK10 0x2B +#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D +#define SCSI_CMD_START_STOP Unit 0x1B +#define SCSI_CMD_TEST_UNIT_READY 0x00 +#define SCSI_CMD_VERIFY 0x2F +#define SCSI_CMD_WRITE10 0x2A +#define SCSI_CMD_WRITE12 0xAA +#define SCSI_CMD_WRITE_AND_VERIFY 0x2E + +#define IN_DIR CWB_FLAG_DIRECTION_IN +#define OUT_DIR 0 + +#define INQUIRY_VID_SIZE 8 +#define INQUIRY_PID_SIZE 16 +#define INQUIRY_REV_SIZE 4 + +#define CBW_CMD_SIZE(cmd) (sizeof(cmd) - sizeof(msc_cbw_t)) + +#define CBW_BASE_INIT(dir, cbw_len, data_len) \ + .base = { \ + .signature = 0x43425355, \ + .tag = ++cbw_tag, \ + .flags = dir, \ + .lun = 0, \ + .data_length = data_len, \ + .cbw_length = cbw_len, \ + } + +#define CSW_SIGNATURE 0x53425355 +#define CBW_SIZE 31 + +#define CWB_FLAG_DIRECTION_IN (1<<7) // device -> host + +/** + * @brief LUT with error codes and descriptions + * + * @see USB Mass Storage Class – UFI Command Specification, Revision 1.0 + * Table 51 - Sense Keys, ASC/ASCQ Listing for All Commands (sorted by Key) + * + */ +typedef struct { + uint8_t sense_key; + uint8_t asc; + uint8_t ascq; + const char *description; +} sense_errors_t; + +const sense_errors_t sense_errors_lut[] = { + {0x00, 0x00, 0x00, "NO SENSE"}, + {0x07, 0x27, 0x00, "WRITE PROTECTED MEDIA"}, + + // add more items as needed +}; + +#define SENSE_ERROR_COUNT (sizeof(sense_errors_lut) / sizeof(sense_errors_t)) + +/** + * @brief Command Block Wrapper structure + * + * @see USB Mass Storage Class – Bulk Only Transport, Table 5.1 + */ +typedef struct __attribute__((packed)) +{ + uint32_t signature; + uint32_t tag; + uint32_t data_length; + uint8_t flags; + uint8_t lun; + uint8_t cbw_length; +} msc_cbw_t; + +/** + * @brief Command Status Wrapper structure + * + * @see USB Mass Storage Class – Bulk Only Transport, Table 5.2 + */ +typedef struct __attribute__((packed)) +{ + uint32_t signature; + uint32_t tag; + uint32_t dataResidue; + uint8_t status; +} msc_csw_t; + +typedef struct __attribute__((packed)) +{ + msc_cbw_t base; + uint8_t opcode; + uint8_t flags; + uint32_t address; + uint8_t reserved1; + uint16_t length; + uint8_t reserved2[3]; +} cbw_read10_t; + +typedef struct __attribute__((packed)) +{ + msc_cbw_t base; + uint8_t opcode; + uint8_t flags; + uint32_t address; + uint8_t reserved1; + uint16_t length; + uint8_t reserved2[1]; +} cbw_write10_t; + +typedef struct __attribute__((packed)) +{ + msc_cbw_t base; + uint8_t opcode; + uint8_t flags; + uint32_t address; + uint8_t reserved[6]; +} cbw_read_capacity_t; + +typedef struct __attribute__((packed)) +{ + uint32_t block_count; + uint32_t block_size; +} cbw_read_capacity_response_t; + +typedef struct __attribute__((packed)) +{ + msc_cbw_t base; + uint8_t opcode; + uint8_t flags; + uint8_t reserved[10]; +} cbw_unit_ready_t; + +typedef struct __attribute__((packed)) +{ + msc_cbw_t base; + uint8_t opcode; + uint8_t flags; + uint8_t reserved_0[2]; + uint8_t allocation_length; + uint8_t reserved_1[7]; +} cbw_sense_t; + +typedef struct __attribute__((packed)) +{ + uint8_t error_code; + uint8_t reserved_0; + uint8_t sense_key; + uint32_t info; + uint8_t sense_len; + uint32_t reserved_1; + uint8_t sense_code; + uint8_t sense_code_qualifier; + uint32_t reserved_2; +} cbw_sense_response_t; + +typedef struct __attribute__((packed)) +{ + msc_cbw_t base; + uint8_t opcode; + uint8_t flags; + uint8_t page_code; + uint8_t reserved_0; + uint8_t allocation_length; + uint8_t reserved_1[7]; +} cbw_inquiry_t; + +typedef struct __attribute__((packed)) +{ + msc_cbw_t base; + uint8_t opcode; + uint8_t flags; + uint8_t pc_page_code; + uint8_t reserved_1[4]; + uint16_t parameter_list_length; + uint8_t reserved_2[3]; +} mode_sense_t; + +typedef struct __attribute__((packed)) +{ + uint8_t data[8]; +} mode_sense_response_t; + +typedef struct __attribute__((packed)) +{ + msc_cbw_t base; + uint8_t opcode; + uint8_t flags; + uint8_t reserved_1[2]; + uint8_t prevent; + uint8_t reserved_2[7]; +} prevent_allow_medium_removal_t; + +typedef struct __attribute__((packed)) +{ + uint8_t data[36]; +} cbw_inquiry_response_t; + +// Unique number based on which MSC protocol pairs request and response +static uint32_t cbw_tag; + +static esp_err_t check_csw(msc_csw_t *csw, uint32_t tag) +{ + const bool csw_ok = csw->signature == CSW_SIGNATURE && csw->tag == tag && + csw->dataResidue == 0 && csw->status == 0; + + if (!csw_ok) { + ESP_LOGV(TAG, "CSW failed: dCSWSignature = 0x%02"PRIx32", dCSWTag = 0x%02"PRIx32", dCSWDataResidue = 0x%02"PRIx32"", + csw->signature, csw->tag, csw->dataResidue); + ESP_LOGD(TAG, "CSW failed: bCSWStatus 0x%02"PRIx8"", csw->status); + } + + return csw_ok ? ESP_OK : ESP_FAIL; +} + +/** + * @brief Execute BOT command + * + * There are multiple stages in BOT command: + * 1. Command transport + * 2. Data transport (optional) + * 3. Status transport + * 3.1. Error recovery (in case of error) + * + * This function is not 'static' so it could be called from unit test + * + * @see USB Mass Storage Class – Bulk Only Transport, Chapter 5.3 + * + * @param[in] device MSC device handle + * @param[in] cbw Command Block Wrapper + * @param[in] data Data (optional) + * @param[in] size Size of data in bytes + * @return esp_err_t + */ +esp_err_t bot_execute_command(msc_device_t *device, msc_cbw_t *cbw, void *data, size_t size) +{ + msc_csw_t csw; + msc_endpoint_t ep = (cbw->flags & CWB_FLAG_DIRECTION_IN) ? MSC_EP_IN : MSC_EP_OUT; + + // 1. Command transport + MSC_RETURN_ON_ERROR( msc_bulk_transfer(device, (uint8_t *)cbw, CBW_SIZE, MSC_EP_OUT) ); + + // 2. Optional data transport + if (data) { + MSC_RETURN_ON_ERROR( msc_bulk_transfer(device, (uint8_t *)data, size, ep) ); + } + + // 3. Status transport + esp_err_t err = msc_bulk_transfer(device, (uint8_t *)&csw, sizeof(msc_csw_t), MSC_EP_IN); + + // 3.1 Error recovery + if (err == ESP_ERR_MSC_STALL) { + // In case of the status transport failure, we can try reading the status again after clearing feature + ESP_RETURN_ON_ERROR( clear_feature(device, device->config.bulk_in_ep), TAG, "Clear feature failed" ); + err = msc_bulk_transfer(device, (uint8_t *)&csw, sizeof(msc_csw_t), MSC_EP_IN); + if (ESP_OK != err) { + // In case the repeated status transport failed we do reset recovery + // We don't check the error code here, the command has already failed. + msc_host_reset_recovery(device); + } + } + + MSC_RETURN_ON_ERROR(err); + + return check_csw(&csw, cbw->tag); +} + +static const char *decode_sense_keys(cbw_sense_response_t *sense_response) +{ + // Only decode WRITE_PROTECTED_MEDIA sense key, other keys are not implemented + for (int i = 0; i < SENSE_ERROR_COUNT; i++) { + if (sense_errors_lut[i].sense_key == sense_response->sense_key && + sense_errors_lut[i].asc == sense_response->sense_code && + sense_errors_lut[i].ascq == sense_response->sense_code_qualifier) { + return sense_errors_lut[i].description; + } + } + + return "not found, refer to USB Mass Storage Class – UFI Command Specification (Table 51)"; +} + + +esp_err_t scsi_cmd_read10(msc_host_device_handle_t dev, + uint8_t *data, + uint32_t sector_address, + uint32_t num_sectors, + uint32_t sector_size) +{ + msc_device_t *device = (msc_device_t *)dev; + cbw_read10_t cbw = { + CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_read10_t), num_sectors * sector_size), + .opcode = SCSI_CMD_READ10, + .flags = 0, // lun + .address = __builtin_bswap32(sector_address), + .length = __builtin_bswap16(num_sectors), + }; + + esp_err_t ret = bot_execute_command(device, &cbw.base, data, num_sectors * sector_size); + + // In case of an error, get an error code + if (unlikely(ret != ESP_OK)) { + MSC_RETURN_ON_ERROR( scsi_cmd_sense(device, NULL)); + } + return ret; +} + +esp_err_t scsi_cmd_write10(msc_host_device_handle_t dev, + const uint8_t *data, + uint32_t sector_address, + uint32_t num_sectors, + uint32_t sector_size) +{ + msc_device_t *device = (msc_device_t *)dev; + cbw_write10_t cbw = { + CBW_BASE_INIT(OUT_DIR, CBW_CMD_SIZE(cbw_write10_t), num_sectors * sector_size), + .opcode = SCSI_CMD_WRITE10, + .address = __builtin_bswap32(sector_address), + .length = __builtin_bswap16(num_sectors), + }; + + esp_err_t ret = bot_execute_command(device, &cbw.base, (void *)data, num_sectors * sector_size); + + // In case of an error, get an error code + if (unlikely(ret != ESP_OK)) { + MSC_RETURN_ON_ERROR( scsi_cmd_sense(device, NULL)); + } + return ret; +} + +esp_err_t scsi_cmd_read_capacity(msc_host_device_handle_t dev, uint32_t *block_size, uint32_t *block_count) +{ + msc_device_t *device = (msc_device_t *)dev; + cbw_read_capacity_response_t response; + + cbw_read_capacity_t cbw = { + CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_read_capacity_t), sizeof(response)), + .opcode = SCSI_CMD_READ_CAPACITY, + }; + + esp_err_t ret = bot_execute_command(device, &cbw.base, &response, sizeof(response)); + + // In case of an error, get an error code + if (unlikely(ret != ESP_OK)) { + MSC_RETURN_ON_ERROR( scsi_cmd_sense(device, NULL)); + } + + *block_count = __builtin_bswap32(response.block_count); + *block_size = __builtin_bswap32(response.block_size); + + return ret; +} + +esp_err_t scsi_cmd_unit_ready(msc_host_device_handle_t dev) +{ + msc_device_t *device = (msc_device_t *)dev; + cbw_unit_ready_t cbw = { + CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_unit_ready_t), 0), + .opcode = SCSI_CMD_TEST_UNIT_READY, + }; + + esp_err_t ret = bot_execute_command(device, &cbw.base, NULL, 0); + + // In case of an error, get an error code + if (unlikely(ret != ESP_OK)) { + MSC_RETURN_ON_ERROR( scsi_cmd_sense(device, NULL)); + } + return ret; +} + +esp_err_t scsi_cmd_sense(msc_host_device_handle_t dev, scsi_sense_data_t *sense) +{ + msc_device_t *device = (msc_device_t *)dev; + cbw_sense_response_t response; + + cbw_sense_t cbw = { + CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_sense_t), sizeof(response)), + .opcode = SCSI_CMD_REQUEST_SENSE, + .allocation_length = sizeof(response), + }; + + MSC_RETURN_ON_ERROR( bot_execute_command(device, &cbw.base, &response, sizeof(response)) ); + + if (sense == NULL) { + ESP_LOGE(TAG, "Sense error codes: Sense Key 0x%02"PRIx8", ASC: 0x%02"PRIx8", ASCQ: 0x%02"PRIx8"", + response.sense_key, response.sense_code, response.sense_code_qualifier); + const char *error_description = decode_sense_keys(&response); + ESP_LOGE(TAG, "Sense error description: %s", error_description); + return ESP_OK; + } + + sense->key = response.sense_key; + sense->code = response.sense_code; + sense->code_q = response.sense_code_qualifier; + + return ESP_OK; +} + +esp_err_t scsi_cmd_inquiry(msc_host_device_handle_t dev) +{ + msc_device_t *device = (msc_device_t *)dev; + cbw_inquiry_response_t response = { 0 }; + + cbw_inquiry_t cbw = { + CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(cbw_inquiry_t), sizeof(response)), + .opcode = SCSI_CMD_INQUIRY, + .allocation_length = sizeof(response), + }; + + esp_err_t ret = bot_execute_command(device, &cbw.base, &response, sizeof(response) ); + + // In case of an error, get an error code + if (unlikely(ret != ESP_OK)) { + MSC_RETURN_ON_ERROR( scsi_cmd_sense(device, NULL)); + } + return ret; +} + +esp_err_t scsi_cmd_mode_sense(msc_host_device_handle_t dev) +{ + msc_device_t *device = (msc_device_t *)dev; + mode_sense_response_t response = { 0 }; + + mode_sense_t cbw = { + CBW_BASE_INIT(IN_DIR, CBW_CMD_SIZE(mode_sense_t), sizeof(response)), + .opcode = SCSI_CMD_MODE_SENSE, + .pc_page_code = 0x3F, + .parameter_list_length = sizeof(response), + }; + + esp_err_t ret = bot_execute_command(device, &cbw.base, &response, sizeof(response) ); + + // In case of an error, get an error code + if (unlikely(ret != ESP_OK)) { + MSC_RETURN_ON_ERROR( scsi_cmd_sense(device, NULL)); + } + return ret; +} + +esp_err_t scsi_cmd_prevent_removal(msc_host_device_handle_t dev, bool prevent) +{ + msc_device_t *device = (msc_device_t *)dev; + prevent_allow_medium_removal_t cbw = { + CBW_BASE_INIT(OUT_DIR, CBW_CMD_SIZE(prevent_allow_medium_removal_t), 0), + .opcode = SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL, + .prevent = (uint8_t) prevent, + }; + + esp_err_t ret = bot_execute_command(device, &cbw.base, NULL, 0); + + // In case of an error, get an error code + if (unlikely(ret != ESP_OK)) { + MSC_RETURN_ON_ERROR( scsi_cmd_sense(device, NULL)); + } + return ret; +} diff --git a/managed_components/espressif__usb_host_msc/test_app/CMakeLists.txt b/managed_components/espressif__usb_host_msc/test_app/CMakeLists.txt new file mode 100644 index 0000000..be769bd --- /dev/null +++ b/managed_components/espressif__usb_host_msc/test_app/CMakeLists.txt @@ -0,0 +1,14 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(EXTRA_COMPONENT_DIRS + ../../usb_host_msc + ../../../../../device/esp_tinyusb + ) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + +project(test_app_usb_host_msc) diff --git a/managed_components/espressif__usb_host_msc/test_app/README.md b/managed_components/espressif__usb_host_msc/test_app/README.md new file mode 100644 index 0000000..7384992 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/test_app/README.md @@ -0,0 +1,14 @@ +| Supported Targets | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | + +# USB: CDC Class test application + +## MSC driver + +Basic functionality such as MSC device install/uninstall, file operations, +raw access to MSC device and sudden disconnect is tested. + +### Hardware Required + +This test requires two ESP32-S2/S3 boards with a interconnected USB peripherals, +one acting as host running MSC host driver and another MSC device driver (tinyusb). \ No newline at end of file diff --git a/managed_components/espressif__usb_host_msc/test_app/main/CMakeLists.txt b/managed_components/espressif__usb_host_msc/test_app/main/CMakeLists.txt new file mode 100644 index 0000000..be5bdb6 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/test_app/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRC_DIRS . + INCLUDE_DIRS . + REQUIRES unity usb usb_host_msc esp_tinyusb + WHOLE_ARCHIVE) diff --git a/managed_components/espressif__usb_host_msc/test_app/main/msc_device.c b/managed_components/espressif__usb_host_msc/test_app/main/msc_device.c new file mode 100644 index 0000000..952ae10 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/test_app/main/msc_device.c @@ -0,0 +1,461 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include "esp_log.h" +#include "tinyusb.h" +#include "esp_idf_version.h" +#include "soc/soc_caps.h" +#include "test_common.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#include "esp_check.h" +#include "driver/gpio.h" +#include "tusb_msc_storage.h" +#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) */ +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED +#include "diskio_impl.h" +#include "diskio_sdmmc.h" +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED */ + +#if SOC_USB_OTG_SUPPORTED + +/* sd-card configuration to be done by user */ +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED +#define SDMMC_BUS_WIDTH 4 /* Select the bus width of SD or MMC interface (4 or 1). + Note that even if 1 line mode is used, D3 pin of the SD card must + have a pull-up resistor connected. Otherwise the card may enter + SPI mode, the only way to recover from which is to cycle power to the card. */ +#define PIN_CMD 35 /* CMD GPIO number */ +#define PIN_CLK 36 /* CLK GPIO number */ +#define PIN_D0 37 /* D0 GPIO number */ +#define PIN_D1 38 /* D1 GPIO number (applicable when width SDMMC_BUS_WIDTH is 4) */ +#define PIN_D2 33 /* D2 GPIO number (applicable when width SDMMC_BUS_WIDTH is 4) */ +#define PIN_D3 34 /* D3 GPIO number (applicable when width SDMMC_BUS_WIDTH is 4) */ +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED */ + +static const char *TAG = "msc_example"; + +/* TinyUSB descriptors + ********************************************************************* */ +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN) + +enum { + ITF_NUM_MSC = 0, + ITF_NUM_TOTAL +}; + +enum { + EDPT_MSC_OUT = 0x01, + EDPT_MSC_IN = 0x81, +}; + +static uint8_t const desc_configuration[] = { + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + + // Interface number, string index, EP Out & EP In address, EP size + TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, TUD_OPT_HIGH_SPEED ? 512 : 64), +}; + +static tusb_desc_device_t descriptor_config = { + .bLength = sizeof(descriptor_config), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .idVendor = 0x303A, // This is Espressif VID. This needs to be changed according to Users / Customers + .idProduct = 0x4002, + .bcdDevice = 0x100, + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + .bNumConfigurations = 0x01 +}; + +static char const *string_desc_arr[] = { + (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) + "TinyUSB", // 1: Manufacturer + "TinyUSB Device", // 2: Product + // We intentionally do not implement Serial String descriptor to make sure that the driver can handle it + //"123456", // 3: Serials + //"Test MSC", // 4. MSC +}; +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) */ +/*********************************************************************** TinyUSB descriptors*/ + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#define VBUS_MONITORING_GPIO_NUM GPIO_NUM_4 +static void configure_vbus_monitoring(void) +{ + // Configure GPIO Pin for vbus monitoring + const gpio_config_t vbus_gpio_config = { + .pin_bit_mask = BIT64(VBUS_MONITORING_GPIO_NUM), + .mode = GPIO_MODE_INPUT, + .intr_type = GPIO_INTR_DISABLE, + .pull_up_en = true, + .pull_down_en = false, + }; + ESP_ERROR_CHECK(gpio_config(&vbus_gpio_config)); +} +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) */ + +static void storage_init(void) +{ + ESP_LOGI(TAG, "USB MSC initialization"); + const tinyusb_config_t tusb_cfg = { + .external_phy = false, +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + .device_descriptor = &descriptor_config, + .configuration_descriptor = desc_configuration, + .string_descriptor = string_desc_arr, + .string_descriptor_count = sizeof(string_desc_arr) / sizeof(string_desc_arr[0]), + .self_powered = true, + .vbus_monitor_io = VBUS_MONITORING_GPIO_NUM +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) */ + }; + ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); + ESP_LOGI(TAG, "USB initialization DONE"); +} + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +static esp_err_t storage_init_spiflash(wl_handle_t *wl_handle) +{ + ESP_LOGI(TAG, "Initializing wear levelling"); + + const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, NULL); + if (data_partition == NULL) { + ESP_LOGE(TAG, "Failed to find FATFS partition. Check the partition table."); + return ESP_ERR_NOT_FOUND; + } + + return wl_mount(data_partition, wl_handle); +} +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) */ + +void device_app(void) +{ + ESP_LOGI(TAG, "Initializing storage..."); +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + configure_vbus_monitoring(); + + static wl_handle_t wl_handle = WL_INVALID_HANDLE; + ESP_ERROR_CHECK(storage_init_spiflash(&wl_handle)); + + tinyusb_msc_spiflash_config_t config_spi; + config_spi.wl_handle = wl_handle; + ESP_ERROR_CHECK(tinyusb_msc_storage_init_spiflash(&config_spi)); +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) */ + storage_init(); + while (1) { + vTaskDelay(100); + } +} + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED +static esp_err_t storage_init_sdmmc(sdmmc_card_t **card) +{ + esp_err_t ret = ESP_OK; + bool host_init = false; + sdmmc_card_t *sd_card; + + ESP_LOGI(TAG, "Initializing SDCard"); + + // By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz) + // For setting a specific frequency, use host.max_freq_khz (range 400kHz - 40MHz for SDMMC) + // Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000; + sdmmc_host_t host = SDMMC_HOST_DEFAULT(); + + // This initializes the slot without card detect (CD) and write protect (WP) signals. + // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + + if (SDMMC_BUS_WIDTH == 4) { + slot_config.width = 4; + } else { + slot_config.width = 1; + } + + // On chips where the GPIOs used for SD card can be configured, set the user defined values +#ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX + slot_config.clk = PIN_CLK; + slot_config.cmd = PIN_CMD; + slot_config.d0 = PIN_D0; + if (SDMMC_BUS_WIDTH == 4) { + slot_config.d1 = PIN_D1; + slot_config.d2 = PIN_D2; + slot_config.d3 = PIN_D3; + } +#endif // CONFIG_SOC_SDMMC_USE_GPIO_MATRIX + + // Enable internal pullups on enabled pins. The internal pullups + // are insufficient however, please make sure 10k external pullups are + // connected on the bus. This is for debug / example purpose only. + slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP; + + // not using ff_memalloc here, as allocation in internal RAM is preferred + sd_card = (sdmmc_card_t *)malloc(sizeof(sdmmc_card_t)); + ESP_GOTO_ON_FALSE(sd_card, ESP_ERR_NO_MEM, clean, TAG, "could not allocate new sdmmc_card_t"); + + ESP_GOTO_ON_ERROR((*host.init)(), clean, TAG, "Host Config Init fail"); + host_init = true; + + ESP_GOTO_ON_ERROR(sdmmc_host_init_slot(host.slot, (const sdmmc_slot_config_t *) &slot_config), + clean, TAG, "Host init slot fail"); + + ESP_GOTO_ON_ERROR(sdmmc_card_init(&host, sd_card), + clean, TAG, "The detection pin of the slot is disconnected"); + + *card = sd_card; + + return ESP_OK; + +clean: + if (host_init) { + if (host.flags & SDMMC_HOST_FLAG_DEINIT_ARG) { + host.deinit_p(host.slot); + } else { + (*host.deinit)(); + } + } + if (sd_card) { + free(sd_card); + sd_card = NULL; + } + return ret; +} + +void device_app_sdmmc(void) +{ + ESP_LOGI(TAG, "Initializing storage..."); + configure_vbus_monitoring(); + static sdmmc_card_t *card = NULL; + ESP_ERROR_CHECK(storage_init_sdmmc(&card)); + + tinyusb_msc_sdmmc_config_t config_sdmmc; + config_sdmmc.card = card; + ESP_ERROR_CHECK(tinyusb_msc_storage_init_sdmmc(&config_sdmmc)); + + storage_init(); + while (1) { + vTaskDelay(100); + } +} +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED */ + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) +// whether host does safe-eject +static bool ejected = false; + +// Some MCU doesn't have enough 8KB SRAM to store the whole disk +// We will use Flash as read-only disk with board that has +// CFG_EXAMPLE_MSC_READONLY defined + +uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { + //------------- Block0: Boot Sector -------------// + // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM; + // sector_per_cluster = 1; reserved_sectors = 1; + // fat_num = 1; fat12_root_entry_num = 16; + // sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0; + // drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29; + // filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC"; + // FAT magic code at offset 510-511 + { + 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00, + 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', + 'S', 'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, + + // Zero up to 2 last bytes of FAT magic code + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 'F', 'A', 'T', '3', '2', ' ', ' ', ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA + }, + + //------------- Block1: FAT12 Table -------------// + { + 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file + }, + + //------------- Block2: Root Directory -------------// + { + // first entry is volume label + 'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // second entry is readme file + 'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6, 0x52, 0x6D, + 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00, + sizeof(README_CONTENTS) - 1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes) + }, + + //------------- Block3: Readme Content -------------// + README_CONTENTS +}; + +// Invoked when received SCSI_CMD_INQUIRY +// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) +{ + (void) lun; + + const char vid[] = "TinyUSB"; + const char pid[] = "Mass Storage"; + const char rev[] = "1.0"; + + memcpy(vendor_id, vid, strlen(vid)); + memcpy(product_id, pid, strlen(pid)); + memcpy(product_rev, rev, strlen(rev)); +} + +// Invoked when received Test Unit Ready command. +// return true allowing host to read/write this LUN e.g SD card inserted +bool tud_msc_test_unit_ready_cb(uint8_t lun) +{ + (void) lun; + + // RAM disk is ready until ejected + if (ejected) { + tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); + return false; + } + + return true; +} + +// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size +// Application update block count and block size +void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) +{ + (void) lun; + + *block_count = DISK_BLOCK_NUM; + *block_size = DISK_BLOCK_SIZE; +} + +// Invoked when received Start Stop Unit command +// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage +// - Start = 1 : active mode, if load_eject = 1 : load disk storage +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) +{ + (void) lun; + (void) power_condition; + + if ( load_eject ) { + if (start) { + // load disk storage + } else { + // unload disk storage + ejected = true; + } + } + + return true; +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) +{ + (void) lun; + + uint8_t const *addr = msc_disk[lba] + offset; + memcpy(buffer, addr, bufsize); + + return bufsize; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and return number of written bytes +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) +{ + (void) lun; + +#ifndef CFG_EXAMPLE_MSC_READONLY + uint8_t *addr = msc_disk[lba] + offset; + memcpy(addr, buffer, bufsize); +#else + (void) lba; (void) offset; (void) buffer; +#endif + + return bufsize; +} + +// Callback invoked when received an SCSI command not in built-in list below +// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE +// - READ10 and WRITE10 has their own callbacks +int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) +{ + // read10 & write10 has their own callback and MUST not be handled here + + void const *response = NULL; + uint16_t resplen = 0; + + // most scsi handled is input + bool in_xfer = true; + + switch (scsi_cmd[0]) { + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + // Host is about to read/write etc ... better not to disconnect disk + resplen = 0; + break; + + default: + // Set Sense = Invalid Command Operation + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + + // negative means error -> tinyusb could stall and/or response with failed status + resplen = -1; + break; + } + + // return resplen must not larger than bufsize + if ( resplen > bufsize ) { + resplen = bufsize; + } + + if ( response && (resplen > 0) ) { + if (in_xfer) { + memcpy(buffer, response, resplen); + } else { + // SCSI output + } + } + + return resplen; +} +#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) */ + +#endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/managed_components/espressif__usb_host_msc/test_app/main/test_app_main.c b/managed_components/espressif__usb_host_msc/test_app/main/test_app_main.c new file mode 100644 index 0000000..b25c8df --- /dev/null +++ b/managed_components/espressif__usb_host_msc/test_app/main/test_app_main.c @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "esp_heap_caps.h" + +static size_t before_free_8bit; +static size_t before_free_32bit; + +#define TEST_MEMORY_LEAK_THRESHOLD (-530) +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); +} + +void app_main(void) +{ + // ____ ___ ___________________ __ __ + // | | \/ _____/\______ \ _/ |_ ____ _______/ |_ + // | | /\_____ \ | | _/ \ __\/ __ \ / ___/\ __\. + // | | / / \ | | \ | | \ ___/ \___ \ | | + // |______/ /_______ / |______ / |__| \___ >____ > |__| + // \/ \/ \/ \/ + printf(" ____ ___ ___________________ __ __ \r\n"); + printf("| | \\/ _____/\\______ \\ _/ |_ ____ _______/ |_ \r\n"); + printf("| | /\\_____ \\ | | _/ \\ __\\/ __ \\ / ___/\\ __\\\r\n"); + printf("| | / / \\ | | \\ | | \\ ___/ \\___ \\ | | \r\n"); + printf("|______/ /_______ / |______ / |__| \\___ >____ > |__| \r\n"); + printf(" \\/ \\/ \\/ \\/ \r\n"); + + UNITY_BEGIN(); + unity_run_menu(); + UNITY_END(); +} + +/* setUp runs before every test */ +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +/* tearDown runs after every test */ +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); +} diff --git a/managed_components/espressif__usb_host_msc/test_app/main/test_common.h b/managed_components/espressif__usb_host_msc/test_app/main/test_common.h new file mode 100644 index 0000000..20a1816 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/test_app/main/test_common.h @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "esp_idf_version.h" + +enum { + // FatFS only allows to format disks with number of blocks greater than 128 + DISK_BLOCK_NUM = 128 + 1, + DISK_BLOCK_SIZE = 512 +}; + +void device_app(void); +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED +void device_app_sdmmc(void); +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED */ + +#define README_CONTENTS \ +"This is tinyusb's MassStorage Class demo.\r\n\r\n\ +If you find any bugs or get any questions, feel free to file an\r\n\ +issue at github.com/hathach/tinyusb" diff --git a/managed_components/espressif__usb_host_msc/test_app/main/test_msc.c b/managed_components/espressif__usb_host_msc/test_app/main/test_msc.c new file mode 100644 index 0000000..32997e8 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/test_app/main/test_msc.c @@ -0,0 +1,549 @@ + +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include +#include +#include +#include "esp_private/usb_phy.h" +#include "esp_private/msc_scsi_bot.h" +#include "usb/usb_host.h" +#include "usb/msc_host_vfs.h" +#include "test_common.h" +#include "esp_idf_version.h" +#include "../private_include/msc_common.h" + +#if SOC_USB_OTG_SUPPORTED + +static const char *TAG = "APP"; + +#define ESP_OK_ASSERT(exp) TEST_ASSERT_EQUAL(ESP_OK, exp) + +static esp_vfs_fat_mount_config_t mount_config = { + .format_if_mount_failed = true, + .max_files = 3, + .allocation_unit_size = 1024, +}; + +static QueueHandle_t app_queue; +static SemaphoreHandle_t ready_to_deinit_usb; +static msc_host_device_handle_t device; +static msc_host_vfs_handle_t vfs_handle; +static volatile bool waiting_for_sudden_disconnect; +static usb_phy_handle_t phy_hdl = NULL; + +static void force_conn_state(bool connected, TickType_t delay_ticks) +{ + TEST_ASSERT(phy_hdl); + if (delay_ticks > 0) { + //Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. + vTaskDelay(delay_ticks); + } + ESP_ERROR_CHECK(usb_phy_action(phy_hdl, (connected) ? USB_PHY_ACTION_HOST_ALLOW_CONN : USB_PHY_ACTION_HOST_FORCE_DISCONN)); +} + +static void msc_event_cb(const msc_host_event_t *event, void *arg) +{ + if (waiting_for_sudden_disconnect) { + waiting_for_sudden_disconnect = false; + TEST_ASSERT_EQUAL(MSC_DEVICE_DISCONNECTED, event->event); + } + + if (event->event == MSC_DEVICE_CONNECTED) { + printf("MSC_DEVICE_CONNECTED\n"); + } else { + printf("MSC_DEVICE_DISCONNECTED\n"); + } + + xQueueSend(app_queue, event, 10); +} + +static const char *TEST_STRING = "Hello World!"; +static const char *FILE_NAME = "/usb/ESP32.txt"; + +static void write_read_file(const char *file_path) +{ + char line[64]; + + ESP_LOGI(TAG, "Writing file"); + FILE *f = fopen(file_path, "w"); + TEST_ASSERT(f); + fprintf(f, TEST_STRING); + fclose(f); + + ESP_LOGI(TAG, "Reading file"); + TEST_ASSERT(fopen(file_path, "r")); + fgets(line, sizeof(line), f); + fclose(f); + // strip newline + char *pos = strchr(line, '\n'); + if (pos) { + *pos = '\0'; + } + TEST_ASSERT_EQUAL_STRING(line, TEST_STRING); + ESP_LOGI(TAG, "Done"); +} + +static bool file_exists(const char *file_path) +{ + return ( access(file_path, F_OK) == 0 ); +} + +// Handles common USB host library events +static void handle_usb_events(void *args) +{ + uint32_t end_flags = 0; + + while (1) { + uint32_t event_flags; + usb_host_lib_handle_events(portMAX_DELAY, &event_flags); + // Release devices once all clients has deregistered + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { + printf("USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS\n"); + usb_host_device_free_all(); + end_flags |= 1; + } + // Give ready_to_deinit_usb semaphore to indicate that USB Host library + // can be deinitialized, and terminate this task. + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { + printf("USB_HOST_LIB_EVENT_FLAGS_ALL_FREE\n"); + end_flags |= 2; + } + + if (end_flags == 3) { + xSemaphoreGive(ready_to_deinit_usb); + break; + } + } + vTaskDelete(NULL); +} + +/** + * @brief MSC driver handling task + * + * This task is only used if the MSC driver was installed with no background task + * + * @param[in] args Not used + */ +static void msc_task(void *args) +{ + ESP_LOGI(TAG, "USB MSC handling start"); + while (msc_host_handle_events(portMAX_DELAY) == ESP_OK) { + } + ESP_LOGI(TAG, "USB MSC handling stop"); + vTaskDelete(NULL); +} + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) +static void check_file_content(const char *file_path, const char *expected) +{ + ESP_LOGI(TAG, "Reading %s:", file_path); + FILE *file = fopen(file_path, "r"); + TEST_ASSERT_NOT_NULL_MESSAGE(file, "Could not open file"); + + char content[200]; + size_t read_cnt = fread(content, 1, sizeof(content), file); + TEST_ASSERT_EQUAL_MESSAGE(strlen(expected), read_cnt, "Error in reading file"); + TEST_ASSERT_EQUAL_STRING(content, expected); + fclose(file); +} +#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) */ + +static void check_sudden_disconnect(void) +{ + uint8_t data[512]; + const size_t DATA_SIZE = sizeof(data); + + ESP_LOGI(TAG, "Creating test.tx"); + FILE *file = fopen("/usb/test.txt", "w"); + TEST_ASSERT(file); + + ESP_LOGI(TAG, "Write data"); + TEST_ASSERT_EQUAL(DATA_SIZE, fwrite(data, 1, DATA_SIZE, file)); + TEST_ASSERT_EQUAL(DATA_SIZE, fwrite(data, 1, DATA_SIZE, file)); + TEST_ASSERT_EQUAL(0, fflush(file)); + + ESP_LOGI(TAG, "Trigger a disconnect"); + //Trigger a disconnect + waiting_for_sudden_disconnect = true; + force_conn_state(false, 0); + + // Make sure flag was leared in callback + vTaskDelay( pdMS_TO_TICKS(100) ); + TEST_ASSERT_FALSE(waiting_for_sudden_disconnect); + + ESP_LOGI(TAG, "Write data after disconnect"); + TEST_ASSERT_NOT_EQUAL( DATA_SIZE, fwrite(data, 1, DATA_SIZE, file)); + + fclose(file); +} + +static void msc_test_init(void) +{ + BaseType_t task_created; + + ready_to_deinit_usb = xSemaphoreCreateBinary(); + + TEST_ASSERT( app_queue = xQueueCreate(5, sizeof(msc_host_event_t)) ); + + //Initialize the internal USB PHY to connect to the USB OTG peripheral. We manually install the USB PHY for testing + usb_phy_config_t phy_config = { + .controller = USB_PHY_CTRL_OTG, + .target = USB_PHY_TARGET_INT, + .otg_mode = USB_OTG_MODE_HOST, + .otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device + }; + ESP_OK_ASSERT(usb_new_phy(&phy_config, &phy_hdl)); + const usb_host_config_t host_config = { + .skip_phy_setup = true, + .intr_flags = ESP_INTR_FLAG_LEVEL1, + }; + ESP_OK_ASSERT( usb_host_install(&host_config) ); + + task_created = xTaskCreatePinnedToCore(handle_usb_events, "usb_events", 2 * 2048, NULL, 2, NULL, 0); + TEST_ASSERT(task_created); +} + +static void msc_test_wait_and_install_device(void) +{ + ESP_LOGI(TAG, "Waiting for USB stick to be connected"); + msc_host_event_t app_event; + xQueueReceive(app_queue, &app_event, portMAX_DELAY); + TEST_ASSERT_EQUAL(MSC_DEVICE_CONNECTED, app_event.event); + uint8_t device_addr = app_event.device.address; + + ESP_OK_ASSERT( msc_host_install_device(device_addr, &device) ); + ESP_OK_ASSERT( msc_host_vfs_register(device, "/usb", &mount_config, &vfs_handle) ); +} + +static void msc_setup(void) +{ + msc_test_init(); + const msc_host_driver_config_t msc_config = { + .create_backround_task = true, + .callback = msc_event_cb, + .stack_size = 4096, + .task_priority = 5, + }; + ESP_OK_ASSERT( msc_host_install(&msc_config) ); + msc_test_wait_and_install_device(); +} + +static void msc_test_uninstall_device(void) +{ + ESP_OK_ASSERT( msc_host_vfs_unregister(vfs_handle) ); + ESP_OK_ASSERT( msc_host_uninstall_device(device) ); +} + +static void msc_test_deinit(void) +{ + ESP_OK_ASSERT( msc_host_uninstall() ); + + xSemaphoreTake(ready_to_deinit_usb, portMAX_DELAY); + vSemaphoreDelete(ready_to_deinit_usb); + vTaskDelay(10); // Wait to finish any ongoing USB operations + ESP_OK_ASSERT( usb_host_uninstall() ); + //Tear down USB PHY + ESP_OK_ASSERT(usb_del_phy(phy_hdl)); + phy_hdl = NULL; + + vQueueDelete(app_queue); + vTaskDelay(10); // Wait for FreeRTOS to clean up deleted tasks +} + +static void msc_teardown(void) +{ + msc_test_uninstall_device(); + msc_test_deinit(); +} + +static void write_read_sectors(void) +{ + uint8_t write_data[DISK_BLOCK_SIZE]; + uint8_t read_data[DISK_BLOCK_SIZE]; + + memset(write_data, 0x55, DISK_BLOCK_SIZE); + memset(read_data, 0, DISK_BLOCK_SIZE); + + scsi_cmd_write10(device, write_data, 10, 1, DISK_BLOCK_SIZE); + scsi_cmd_read10(device, read_data, 10, 1, DISK_BLOCK_SIZE); + + TEST_ASSERT_EQUAL_MEMORY(write_data, read_data, DISK_BLOCK_SIZE); +} + +static void erase_storage(void) +{ + uint8_t data[DISK_BLOCK_SIZE]; + memset(data, 0xFF, DISK_BLOCK_SIZE); + + for (int block = 0; block < DISK_BLOCK_NUM; block++) { + scsi_cmd_write10(device, data, block, 1, DISK_BLOCK_SIZE); + } +} + +TEST_CASE("write_and_read_file", "[usb_msc]") +{ + msc_setup(); + write_read_file(FILE_NAME); + msc_teardown(); +} + +TEST_CASE("sudden_disconnect", "[usb_msc]") +{ + msc_setup(); + check_sudden_disconnect(); + msc_teardown(); +} + +TEST_CASE("sectors_can_be_written_and_read", "[usb_msc]") +{ + msc_setup(); + write_read_sectors(); + msc_teardown(); +} + +/** + * @brief Check README content + * + * This test strictly requires our implementation of USB MSC Mock device. + * This test will fail for usualW flash drives, as they don't have README.TXT file on them. + */ +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) +TEST_CASE("check_README_content", "[usb_msc]") +{ + msc_setup(); + check_file_content("/usb/README.TXT", README_CONTENTS); + msc_teardown(); +} +#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) */ + +esp_err_t bot_execute_command(msc_device_t *device, uint8_t *cbw, void *data, size_t size); +/** + * @brief Error recovery testcase + * + * Various error cases: + * - Accessing non-existent memory + * - Invalid SCSI command + * - USB transfer STALL + */ +TEST_CASE("error_recovery_1", "[usb_msc][ignore]") +{ + msc_setup(); + uint8_t data[DISK_BLOCK_SIZE]; + esp_err_t err; + + // Some flash disks will respond with stall, some with error in CSW, some with timeout + printf("invalid bot command\n"); + uint32_t dummy_cbw[8] = {0x5342555, 2, 0, 0x55555555}; + err = bot_execute_command(device, (uint8_t *)dummy_cbw, data, 31); + TEST_ASSERT_NOT_EQUAL(ESP_OK, err); + + err = msc_host_reset_recovery(device); + TEST_ASSERT_EQUAL(ESP_OK, err); + + // Make sure we can read/write after the error was cleared + printf("read write after reset\n"); + write_read_file(FILE_NAME); + + msc_teardown(); +} + +TEST_CASE("error_recovery_2", "[usb_msc][ignore]") +{ + msc_setup(); + uint8_t data[DISK_BLOCK_SIZE]; + esp_err_t err; + + // Write to and read from invalid sector + // Some flash disks will respond with stall, some with error in CSW, some with timeout + printf("read 10\n"); + err = scsi_cmd_read10(device, data, UINT32_MAX, 1, DISK_BLOCK_SIZE); + TEST_ASSERT_NOT_EQUAL(ESP_OK, err); + err = msc_host_reset_recovery(device); + TEST_ASSERT_EQUAL(ESP_OK, err); + printf("read write after reset\n"); + write_read_file(FILE_NAME); + + msc_teardown(); +} + +#define MAX_BUFFER_SIZE (1024 + 1) // Maximum buffer size for this test +#define SETVBUF_TEST(_size) do { \ + printf("setvbuf %d\n", _size); \ + int err = setvbuf(file, NULL, _IOFBF, _size); \ + TEST_ASSERT_EQUAL_MESSAGE(0, err, "setvbuf failed"); \ + err = fseek(file, SEEK_SET, 0); \ + TEST_ASSERT_EQUAL_MESSAGE(0, err, "fseek failed"); \ + size_t write_cnt = fwrite(write_buf, 1, _size, file); \ + TEST_ASSERT_EQUAL(_size, write_cnt); \ + err = fseek(file, SEEK_SET, 0); \ + TEST_ASSERT_EQUAL_MESSAGE(0, err, "fseek failed"); \ + memset(read_buf, 0, MAX_BUFFER_SIZE + 1); \ + size_t read_cnt = fread(read_buf, 1, _size, file); \ + TEST_ASSERT_EQUAL_MESSAGE(_size, read_cnt, "Error in reading file"); \ + TEST_ASSERT_EQUAL_HEX8_ARRAY(write_buf, read_buf, _size); \ + TEST_ASSERT_EQUAL_MESSAGE(0, read_buf[_size], "Read buffer accessed outside of its boundaries"); \ +} while(0); \ + +/** + * @brief setvbuf testcase + * + * From v1.1.0 the MSC driver reuses buffer from VFS for USB transfers. + * Check that this feature works correctly with various buffer lengths. + */ +TEST_CASE("setvbuf", "[usb_msc]") +{ + msc_setup(); + + FILE *file = fopen("/usb/test", "w+"); + TEST_ASSERT_NOT_NULL_MESSAGE(file, "Could not open file for writing"); + + char *write_buf = malloc(MAX_BUFFER_SIZE); + char *read_buf = malloc(MAX_BUFFER_SIZE + 1); // 1 canary byte + TEST_ASSERT_NOT_NULL(write_buf); + TEST_ASSERT_NOT_NULL(read_buf); + + // Initialize write buffer with some data + for (int i = 0; i < MAX_BUFFER_SIZE; i++) { + write_buf[i] = i & 0xFF; + } + + SETVBUF_TEST(64); + SETVBUF_TEST(128); + SETVBUF_TEST(500); + SETVBUF_TEST(1000); + SETVBUF_TEST(1023); + SETVBUF_TEST(1024); + SETVBUF_TEST(MAX_BUFFER_SIZE); + + fclose(file); + free(write_buf); + free(read_buf); + + msc_teardown(); +} + +/** + * @brief USB MSC format testcase + * @attention This testcase deletes all content on the USB MSC device. + * The device must be reset in order to contain the FILE_NAME again. + */ +TEST_CASE("can_be_formated", "[usb_msc]") +{ + printf("Create file\n"); + msc_setup(); + write_read_file(FILE_NAME); + msc_teardown(); + + printf("File exists after mounting again\n"); + msc_setup(); + TEST_ASSERT(file_exists(FILE_NAME)); + printf("Erase storage device\n"); + erase_storage(); + msc_teardown(); + + printf("Check file does not exist after formatting\n"); + mount_config.format_if_mount_failed = true; + msc_setup(); + TEST_ASSERT_FALSE(file_exists(FILE_NAME)); + msc_teardown(); + mount_config.format_if_mount_failed = false; +} + +static void print_device_info(msc_host_device_info_t *info) +{ + const size_t megabyte = 1024 * 1024; + uint64_t capacity = ((uint64_t)info->sector_size * info->sector_count) / megabyte; + + printf("Device info:\n"); + printf("\t Capacity: %llu MB\n", capacity); + printf("\t Sector size: %"PRIu32"\n", info->sector_size); + printf("\t Sector count: %"PRIu32"\n", info->sector_count); + printf("\t PID: 0x%4X \n", info->idProduct); + printf("\t VID: 0x%4X \n", info->idVendor); + wprintf(L"\t iProduct: %S \n", info->iProduct); + wprintf(L"\t iManufacturer: %S \n", info->iManufacturer); + wprintf(L"\t iSerialNumber: %S \n", info->iSerialNumber); +} + +/** + * @brief USB MSC device_info testcase + * + * Simple testcase that only runs msc_host_get_device_info() + * To make sure that we correctly handle missing string descriptors + */ +TEST_CASE("device_info", "[usb_msc]") +{ + msc_setup(); + msc_host_device_info_t info; + esp_err_t err = msc_host_get_device_info(device, &info); + msc_teardown(); + TEST_ASSERT_EQUAL(ESP_OK, err); + print_device_info(&info); +} + +/** + * @brief USB MSC driver with no background task + * + * Install the driver without background task + * and make sure that everything works + */ +TEST_CASE("no_background_task", "[usb_msc]") +{ + msc_test_init(); + const msc_host_driver_config_t msc_config = { + .create_backround_task = false, + .callback = msc_event_cb, + .stack_size = 4096, + .task_priority = 5, + }; + ESP_OK_ASSERT( msc_host_install(&msc_config) ); + BaseType_t task_created = xTaskCreatePinnedToCore(msc_task, "msc_events", 2 * 2048, NULL, 2, NULL, 0); + TEST_ASSERT(task_created); + msc_test_wait_and_install_device(); + write_read_sectors(); // Do some dummy operations + msc_teardown(); +} + +/** + * @brief USB MSC driver with no background task + * + * Install and uninstall the driver without background task + * without ever calling usb_host_client_handle_events() + */ +TEST_CASE("no_background_task_2", "[usb_msc]") +{ + msc_test_init(); + const msc_host_driver_config_t msc_config = { + .create_backround_task = false, + .callback = msc_event_cb, + }; + ESP_OK_ASSERT( msc_host_install(&msc_config) ); + + vTaskDelay(100); // Give USB Host Library some time for device enumeration + + msc_test_deinit(); +} + +/** + * @brief USB MSC Device Mock + * + * We use this 'testcase' to provide MSC mock device for our DUT + */ +TEST_CASE("mock_device_app", "[usb_msc_device][ignore]") +{ + device_app(); +} + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED +TEST_CASE("mock_device_app", "[usb_msc_device_sdmmc][ignore]") +{ + device_app_sdmmc(); +} +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && SOC_SDMMC_HOST_SUPPORTED */ + +#endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/managed_components/espressif__usb_host_msc/test_app/partitions.csv b/managed_components/espressif__usb_host_msc/test_app/partitions.csv new file mode 100644 index 0000000..1c79321 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/test_app/partitions.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +storage, data, fat, , 1M, diff --git a/managed_components/espressif__usb_host_msc/test_app/pytest_usb_host_msc.py b/managed_components/espressif__usb_host_msc/test_app/pytest_usb_host_msc.py new file mode 100644 index 0000000..3101b93 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/test_app/pytest_usb_host_msc.py @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +from typing import Tuple + +import pytest +from pytest_embedded_idf.dut import IdfDut + + +@pytest.mark.esp32s2 +@pytest.mark.esp32s3 +@pytest.mark.usb_host +@pytest.mark.parametrize('count', [ + 2, +], indirect=True) +def test_usb_host_msc(dut: Tuple[IdfDut, IdfDut]) -> None: + device = dut[0] + host = dut[1] + + # 2.1 Prepare USB device for MSC test + device.expect_exact('Press ENTER to see the list of tests.') + device.write('[usb_msc_device]') + device.expect_exact('USB initialization DONE') + + # 2.2 Run MSC test + host.run_all_single_board_cases(group='usb_msc') diff --git a/managed_components/espressif__usb_host_msc/test_app/sdkconfig.defaults b/managed_components/espressif__usb_host_msc/test_app/sdkconfig.defaults new file mode 100644 index 0000000..84f18f7 --- /dev/null +++ b/managed_components/espressif__usb_host_msc/test_app/sdkconfig.defaults @@ -0,0 +1,27 @@ +# Configure TinyUSB, it will be used to mock USB devices +CONFIG_TINYUSB_MSC_ENABLED=y +CONFIG_TINYUSB_CDC_ENABLED=n +CONFIG_TINYUSB_CDC_COUNT=0 +CONFIG_TINYUSB_HID_COUNT=0 + +# Disable watchdogs, they'd get triggered during unity interactive menu +CONFIG_ESP_INT_WDT=n +CONFIG_ESP_TASK_WDT=n + +# Run-time checks of Heap and Stack +CONFIG_HEAP_POISONING_COMPREHENSIVE=y +CONFIG_COMPILER_STACK_CHECK_MODE_STRONG=y +CONFIG_COMPILER_STACK_CHECK=y + +CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y + +CONFIG_COMPILER_CXX_EXCEPTIONS=y + +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_WL_SECTOR_SIZE_512=y +CONFIG_WL_SECTOR_MODE_PERF=y + +CONFIG_FATFS_LFN_HEAP=y diff --git a/partition_table/partitionTable.bin b/partition_table/partitionTable.bin new file mode 100644 index 0000000..e607580 Binary files /dev/null and b/partition_table/partitionTable.bin differ diff --git a/partition_table/partitionTable.csv b/partition_table/partitionTable.csv new file mode 100644 index 0000000..bfc73fc --- /dev/null +++ b/partition_table/partitionTable.csv @@ -0,0 +1,8 @@ +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs,data,nvs,0x9000,20K, +otadata,data,ota,0xe000,8K, +app0,app,ota_0,0x10000,4608K, +app1,app,ota_1,0x490000,4608K, +spiffs,data,spiffs,0x910000,7040K, +coredump,data,coredump,0xff0000,64K, diff --git a/partitions.csv b/partitions.csv new file mode 100644 index 0000000..92b80b5 --- /dev/null +++ b/partitions.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x480000, +app1, app, ota_1, 0x490000, 0x480000, +spiffs, data, spiffs, 0x910000, 0x6E0000, +coredump, data, coredump, 0xFF0000, 0x10000, \ No newline at end of file diff --git a/sdkconfig b/sdkconfig new file mode 100644 index 0000000..04d56ff --- /dev/null +++ b/sdkconfig @@ -0,0 +1,2682 @@ +# +# Automatically generated file. DO NOT EDIT. +# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Configuration +# +CONFIG_SOC_MPU_MIN_REGION_SIZE=0x20000000 +CONFIG_SOC_MPU_REGIONS_MAX_NUM=8 +CONFIG_SOC_ADC_SUPPORTED=y +CONFIG_SOC_UART_SUPPORTED=y +CONFIG_SOC_PCNT_SUPPORTED=y +CONFIG_SOC_PHY_SUPPORTED=y +CONFIG_SOC_WIFI_SUPPORTED=y +CONFIG_SOC_TWAI_SUPPORTED=y +CONFIG_SOC_GDMA_SUPPORTED=y +CONFIG_SOC_AHB_GDMA_SUPPORTED=y +CONFIG_SOC_GPTIMER_SUPPORTED=y +CONFIG_SOC_LCDCAM_SUPPORTED=y +CONFIG_SOC_LCDCAM_I80_LCD_SUPPORTED=y +CONFIG_SOC_LCDCAM_RGB_LCD_SUPPORTED=y +CONFIG_SOC_MCPWM_SUPPORTED=y +CONFIG_SOC_DEDICATED_GPIO_SUPPORTED=y +CONFIG_SOC_CACHE_SUPPORT_WRAP=y +CONFIG_SOC_ULP_SUPPORTED=y +CONFIG_SOC_ULP_FSM_SUPPORTED=y +CONFIG_SOC_RISCV_COPROC_SUPPORTED=y +CONFIG_SOC_BT_SUPPORTED=y +CONFIG_SOC_USB_OTG_SUPPORTED=y +CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED=y +CONFIG_SOC_CCOMP_TIMER_SUPPORTED=y +CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED=y +CONFIG_SOC_SUPPORTS_SECURE_DL_MODE=y +CONFIG_SOC_EFUSE_KEY_PURPOSE_FIELD=y +CONFIG_SOC_EFUSE_SUPPORTED=y +CONFIG_SOC_SDMMC_HOST_SUPPORTED=y +CONFIG_SOC_RTC_FAST_MEM_SUPPORTED=y +CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED=y +CONFIG_SOC_RTC_MEM_SUPPORTED=y +CONFIG_SOC_PSRAM_DMA_CAPABLE=y +CONFIG_SOC_XT_WDT_SUPPORTED=y +CONFIG_SOC_I2S_SUPPORTED=y +CONFIG_SOC_RMT_SUPPORTED=y +CONFIG_SOC_SDM_SUPPORTED=y +CONFIG_SOC_GPSPI_SUPPORTED=y +CONFIG_SOC_LEDC_SUPPORTED=y +CONFIG_SOC_I2C_SUPPORTED=y +CONFIG_SOC_SYSTIMER_SUPPORTED=y +CONFIG_SOC_SUPPORT_COEXISTENCE=y +CONFIG_SOC_TEMP_SENSOR_SUPPORTED=y +CONFIG_SOC_AES_SUPPORTED=y +CONFIG_SOC_MPI_SUPPORTED=y +CONFIG_SOC_SHA_SUPPORTED=y +CONFIG_SOC_HMAC_SUPPORTED=y +CONFIG_SOC_DIG_SIGN_SUPPORTED=y +CONFIG_SOC_FLASH_ENC_SUPPORTED=y +CONFIG_SOC_SECURE_BOOT_SUPPORTED=y +CONFIG_SOC_MEMPROT_SUPPORTED=y +CONFIG_SOC_TOUCH_SENSOR_SUPPORTED=y +CONFIG_SOC_BOD_SUPPORTED=y +CONFIG_SOC_CLK_TREE_SUPPORTED=y +CONFIG_SOC_MPU_SUPPORTED=y +CONFIG_SOC_WDT_SUPPORTED=y +CONFIG_SOC_SPI_FLASH_SUPPORTED=y +CONFIG_SOC_RNG_SUPPORTED=y +CONFIG_SOC_LIGHT_SLEEP_SUPPORTED=y +CONFIG_SOC_DEEP_SLEEP_SUPPORTED=y +CONFIG_SOC_LP_PERIPH_SHARE_INTERRUPT=y +CONFIG_SOC_PM_SUPPORTED=y +CONFIG_SOC_XTAL_SUPPORT_40M=y +CONFIG_SOC_APPCPU_HAS_CLOCK_GATING_BUG=y +CONFIG_SOC_ADC_RTC_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_DIG_CTRL_SUPPORTED=y +CONFIG_SOC_ADC_ARBITER_SUPPORTED=y +CONFIG_SOC_ADC_DIG_IIR_FILTER_SUPPORTED=y +CONFIG_SOC_ADC_MONITOR_SUPPORTED=y +CONFIG_SOC_ADC_DMA_SUPPORTED=y +CONFIG_SOC_ADC_PERIPH_NUM=2 +CONFIG_SOC_ADC_MAX_CHANNEL_NUM=10 +CONFIG_SOC_ADC_ATTEN_NUM=4 +CONFIG_SOC_ADC_DIGI_CONTROLLER_NUM=2 +CONFIG_SOC_ADC_PATT_LEN_MAX=24 +CONFIG_SOC_ADC_DIGI_MIN_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_DIGI_RESULT_BYTES=4 +CONFIG_SOC_ADC_DIGI_DATA_BYTES_PER_CONV=4 +CONFIG_SOC_ADC_DIGI_IIR_FILTER_NUM=2 +CONFIG_SOC_ADC_DIGI_MONITOR_NUM=2 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_HIGH=83333 +CONFIG_SOC_ADC_SAMPLE_FREQ_THRES_LOW=611 +CONFIG_SOC_ADC_RTC_MIN_BITWIDTH=12 +CONFIG_SOC_ADC_RTC_MAX_BITWIDTH=12 +CONFIG_SOC_ADC_CALIBRATION_V1_SUPPORTED=y +CONFIG_SOC_ADC_SELF_HW_CALI_SUPPORTED=y +CONFIG_SOC_ADC_SHARED_POWER=y +CONFIG_SOC_APB_BACKUP_DMA=y +CONFIG_SOC_BROWNOUT_RESET_SUPPORTED=y +CONFIG_SOC_CACHE_WRITEBACK_SUPPORTED=y +CONFIG_SOC_CACHE_FREEZE_SUPPORTED=y +CONFIG_SOC_CPU_CORES_NUM=2 +CONFIG_SOC_CPU_INTR_NUM=32 +CONFIG_SOC_CPU_HAS_FPU=y +CONFIG_SOC_HP_CPU_HAS_MULTIPLE_CORES=y +CONFIG_SOC_CPU_BREAKPOINTS_NUM=2 +CONFIG_SOC_CPU_WATCHPOINTS_NUM=2 +CONFIG_SOC_CPU_WATCHPOINT_MAX_REGION_SIZE=64 +CONFIG_SOC_DS_SIGNATURE_MAX_BIT_LEN=4096 +CONFIG_SOC_DS_KEY_PARAM_MD_IV_LENGTH=16 +CONFIG_SOC_DS_KEY_CHECK_MAX_WAIT_US=1100 +CONFIG_SOC_AHB_GDMA_VERSION=1 +CONFIG_SOC_GDMA_NUM_GROUPS_MAX=1 +CONFIG_SOC_GDMA_PAIRS_PER_GROUP=5 +CONFIG_SOC_GDMA_PAIRS_PER_GROUP_MAX=5 +CONFIG_SOC_AHB_GDMA_SUPPORT_PSRAM=y +CONFIG_SOC_GPIO_PORT=1 +CONFIG_SOC_GPIO_PIN_COUNT=49 +CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER=y +CONFIG_SOC_GPIO_FILTER_CLK_SUPPORT_APB=y +CONFIG_SOC_GPIO_SUPPORT_RTC_INDEPENDENT=y +CONFIG_SOC_GPIO_SUPPORT_FORCE_HOLD=y +CONFIG_SOC_GPIO_VALID_GPIO_MASK=0x1FFFFFFFFFFFF +CONFIG_SOC_GPIO_IN_RANGE_MAX=48 +CONFIG_SOC_GPIO_OUT_RANGE_MAX=48 +CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0x0001FFFFFC000000 +CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX=y +CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3 +CONFIG_SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP=y +CONFIG_SOC_DEDIC_GPIO_OUT_CHANNELS_NUM=8 +CONFIG_SOC_DEDIC_GPIO_IN_CHANNELS_NUM=8 +CONFIG_SOC_DEDIC_GPIO_OUT_AUTO_ENABLE=y +CONFIG_SOC_I2C_NUM=2 +CONFIG_SOC_HP_I2C_NUM=2 +CONFIG_SOC_I2C_FIFO_LEN=32 +CONFIG_SOC_I2C_CMD_REG_NUM=8 +CONFIG_SOC_I2C_SUPPORT_SLAVE=y +CONFIG_SOC_I2C_SUPPORT_HW_CLR_BUS=y +CONFIG_SOC_I2C_SUPPORT_XTAL=y +CONFIG_SOC_I2C_SUPPORT_RTC=y +CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR=y +CONFIG_SOC_I2C_SLAVE_SUPPORT_BROADCAST=y +CONFIG_SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS=y +CONFIG_SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE=y +CONFIG_SOC_I2S_NUM=2 +CONFIG_SOC_I2S_HW_VERSION_2=y +CONFIG_SOC_I2S_SUPPORTS_XTAL=y +CONFIG_SOC_I2S_SUPPORTS_PLL_F160M=y +CONFIG_SOC_I2S_SUPPORTS_PCM=y +CONFIG_SOC_I2S_SUPPORTS_PDM=y +CONFIG_SOC_I2S_SUPPORTS_PDM_TX=y +CONFIG_SOC_I2S_PDM_MAX_TX_LINES=2 +CONFIG_SOC_I2S_SUPPORTS_PDM_RX=y +CONFIG_SOC_I2S_PDM_MAX_RX_LINES=4 +CONFIG_SOC_I2S_SUPPORTS_TDM=y +CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y +CONFIG_SOC_LEDC_SUPPORT_XTAL_CLOCK=y +CONFIG_SOC_LEDC_TIMER_NUM=4 +CONFIG_SOC_LEDC_CHANNEL_NUM=8 +CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=14 +CONFIG_SOC_LEDC_SUPPORT_FADE_STOP=y +CONFIG_SOC_MCPWM_GROUPS=2 +CONFIG_SOC_MCPWM_TIMERS_PER_GROUP=3 +CONFIG_SOC_MCPWM_OPERATORS_PER_GROUP=3 +CONFIG_SOC_MCPWM_COMPARATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GENERATORS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_TRIGGERS_PER_OPERATOR=2 +CONFIG_SOC_MCPWM_GPIO_FAULTS_PER_GROUP=3 +CONFIG_SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP=y +CONFIG_SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER=3 +CONFIG_SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP=3 +CONFIG_SOC_MCPWM_SWSYNC_CAN_PROPAGATE=y +CONFIG_SOC_MMU_LINEAR_ADDRESS_REGION_NUM=1 +CONFIG_SOC_MMU_PERIPH_NUM=1 +CONFIG_SOC_PCNT_GROUPS=1 +CONFIG_SOC_PCNT_UNITS_PER_GROUP=4 +CONFIG_SOC_PCNT_CHANNELS_PER_UNIT=2 +CONFIG_SOC_PCNT_THRES_POINT_PER_UNIT=2 +CONFIG_SOC_RMT_GROUPS=1 +CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP=4 +CONFIG_SOC_RMT_RX_CANDIDATES_PER_GROUP=4 +CONFIG_SOC_RMT_CHANNELS_PER_GROUP=8 +CONFIG_SOC_RMT_MEM_WORDS_PER_CHANNEL=48 +CONFIG_SOC_RMT_SUPPORT_RX_PINGPONG=y +CONFIG_SOC_RMT_SUPPORT_RX_DEMODULATION=y +CONFIG_SOC_RMT_SUPPORT_TX_ASYNC_STOP=y +CONFIG_SOC_RMT_SUPPORT_TX_LOOP_COUNT=y +CONFIG_SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP=y +CONFIG_SOC_RMT_SUPPORT_TX_SYNCHRO=y +CONFIG_SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY=y +CONFIG_SOC_RMT_SUPPORT_XTAL=y +CONFIG_SOC_RMT_SUPPORT_RC_FAST=y +CONFIG_SOC_RMT_SUPPORT_APB=y +CONFIG_SOC_RMT_SUPPORT_DMA=y +CONFIG_SOC_LCD_I80_SUPPORTED=y +CONFIG_SOC_LCD_RGB_SUPPORTED=y +CONFIG_SOC_LCD_I80_BUSES=1 +CONFIG_SOC_LCD_RGB_PANELS=1 +CONFIG_SOC_LCD_I80_BUS_WIDTH=16 +CONFIG_SOC_LCD_RGB_DATA_WIDTH=16 +CONFIG_SOC_LCD_SUPPORT_RGB_YUV_CONV=y +CONFIG_SOC_LCDCAM_I80_NUM_BUSES=1 +CONFIG_SOC_LCDCAM_I80_BUS_WIDTH=16 +CONFIG_SOC_LCDCAM_RGB_NUM_PANELS=1 +CONFIG_SOC_LCDCAM_RGB_DATA_WIDTH=16 +CONFIG_SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH=128 +CONFIG_SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM=549 +CONFIG_SOC_RTC_CNTL_TAGMEM_PD_DMA_BUS_WIDTH=128 +CONFIG_SOC_RTCIO_PIN_COUNT=22 +CONFIG_SOC_RTCIO_INPUT_OUTPUT_SUPPORTED=y +CONFIG_SOC_RTCIO_HOLD_SUPPORTED=y +CONFIG_SOC_RTCIO_WAKE_SUPPORTED=y +CONFIG_SOC_SDM_GROUPS=y +CONFIG_SOC_SDM_CHANNELS_PER_GROUP=8 +CONFIG_SOC_SDM_CLK_SUPPORT_APB=y +CONFIG_SOC_SPI_PERIPH_NUM=3 +CONFIG_SOC_SPI_MAX_CS_NUM=6 +CONFIG_SOC_SPI_MAXIMUM_BUFFER_SIZE=64 +CONFIG_SOC_SPI_SUPPORT_DDRCLK=y +CONFIG_SOC_SPI_SLAVE_SUPPORT_SEG_TRANS=y +CONFIG_SOC_SPI_SUPPORT_CD_SIG=y +CONFIG_SOC_SPI_SUPPORT_CONTINUOUS_TRANS=y +CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2=y +CONFIG_SOC_SPI_SUPPORT_CLK_APB=y +CONFIG_SOC_SPI_SUPPORT_CLK_XTAL=y +CONFIG_SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUT=y +CONFIG_SOC_MEMSPI_IS_INDEPENDENT=y +CONFIG_SOC_SPI_MAX_PRE_DIVIDER=16 +CONFIG_SOC_SPI_SUPPORT_OCT=y +CONFIG_SOC_SPI_SCT_SUPPORTED=y +CONFIG_SOC_SPI_SCT_REG_NUM=14 +CONFIG_SOC_SPI_SCT_BUFFER_NUM_MAX=y +CONFIG_SOC_SPI_SCT_CONF_BITLEN_MAX=0x3FFFA +CONFIG_SOC_MEMSPI_SRC_FREQ_120M=y +CONFIG_SOC_MEMSPI_SRC_FREQ_80M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED=y +CONFIG_SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED=y +CONFIG_SOC_SPIRAM_SUPPORTED=y +CONFIG_SOC_SPIRAM_XIP_SUPPORTED=y +CONFIG_SOC_SYSTIMER_COUNTER_NUM=2 +CONFIG_SOC_SYSTIMER_ALARM_NUM=3 +CONFIG_SOC_SYSTIMER_BIT_WIDTH_LO=32 +CONFIG_SOC_SYSTIMER_BIT_WIDTH_HI=20 +CONFIG_SOC_SYSTIMER_FIXED_DIVIDER=y +CONFIG_SOC_SYSTIMER_INT_LEVEL=y +CONFIG_SOC_SYSTIMER_ALARM_MISS_COMPENSATE=y +CONFIG_SOC_TIMER_GROUPS=2 +CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2 +CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=54 +CONFIG_SOC_TIMER_GROUP_SUPPORT_XTAL=y +CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y +CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4 +CONFIG_SOC_TOUCH_SENSOR_VERSION=2 +CONFIG_SOC_TOUCH_SENSOR_NUM=15 +CONFIG_SOC_TOUCH_SUPPORT_SLEEP_WAKEUP=y +CONFIG_SOC_TOUCH_SUPPORT_WATERPROOF=y +CONFIG_SOC_TOUCH_SUPPORT_PROX_SENSING=y +CONFIG_SOC_TOUCH_PROXIMITY_CHANNEL_NUM=3 +CONFIG_SOC_TOUCH_PROXIMITY_MEAS_DONE_SUPPORTED=y +CONFIG_SOC_TOUCH_SAMPLE_CFG_NUM=1 +CONFIG_SOC_TWAI_CONTROLLER_NUM=1 +CONFIG_SOC_TWAI_CLK_SUPPORT_APB=y +CONFIG_SOC_TWAI_BRP_MIN=2 +CONFIG_SOC_TWAI_BRP_MAX=16384 +CONFIG_SOC_TWAI_SUPPORTS_RX_STATUS=y +CONFIG_SOC_UART_NUM=3 +CONFIG_SOC_UART_HP_NUM=3 +CONFIG_SOC_UART_FIFO_LEN=128 +CONFIG_SOC_UART_BITRATE_MAX=5000000 +CONFIG_SOC_UART_SUPPORT_FSM_TX_WAIT_SEND=y +CONFIG_SOC_UART_SUPPORT_WAKEUP_INT=y +CONFIG_SOC_UART_SUPPORT_APB_CLK=y +CONFIG_SOC_UART_SUPPORT_RTC_CLK=y +CONFIG_SOC_UART_SUPPORT_XTAL_CLK=y +CONFIG_SOC_USB_OTG_PERIPH_NUM=1 +CONFIG_SOC_SHA_DMA_MAX_BUFFER_SIZE=3968 +CONFIG_SOC_SHA_SUPPORT_DMA=y +CONFIG_SOC_SHA_SUPPORT_RESUME=y +CONFIG_SOC_SHA_GDMA=y +CONFIG_SOC_SHA_SUPPORT_SHA1=y +CONFIG_SOC_SHA_SUPPORT_SHA224=y +CONFIG_SOC_SHA_SUPPORT_SHA256=y +CONFIG_SOC_SHA_SUPPORT_SHA384=y +CONFIG_SOC_SHA_SUPPORT_SHA512=y +CONFIG_SOC_SHA_SUPPORT_SHA512_224=y +CONFIG_SOC_SHA_SUPPORT_SHA512_256=y +CONFIG_SOC_SHA_SUPPORT_SHA512_T=y +CONFIG_SOC_MPI_MEM_BLOCKS_NUM=4 +CONFIG_SOC_MPI_OPERATIONS_NUM=3 +CONFIG_SOC_RSA_MAX_BIT_LEN=4096 +CONFIG_SOC_AES_SUPPORT_DMA=y +CONFIG_SOC_AES_GDMA=y +CONFIG_SOC_AES_SUPPORT_AES_128=y +CONFIG_SOC_AES_SUPPORT_AES_256=y +CONFIG_SOC_PM_SUPPORT_EXT0_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_EXT1_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_EXT_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_WIFI_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_BT_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP=y +CONFIG_SOC_PM_SUPPORT_CPU_PD=y +CONFIG_SOC_PM_SUPPORT_TAGMEM_PD=y +CONFIG_SOC_PM_SUPPORT_RTC_PERIPH_PD=y +CONFIG_SOC_PM_SUPPORT_RC_FAST_PD=y +CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y +CONFIG_SOC_PM_SUPPORT_MAC_BB_PD=y +CONFIG_SOC_PM_SUPPORT_MODEM_PD=y +CONFIG_SOC_CONFIGURABLE_VDDSDIO_SUPPORTED=y +CONFIG_SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY=y +CONFIG_SOC_PM_CPU_RETENTION_BY_RTCCNTL=y +CONFIG_SOC_PM_MODEM_RETENTION_BY_BACKUPDMA=y +CONFIG_SOC_PM_MODEM_PD_BY_SW=y +CONFIG_SOC_CLK_RC_FAST_D256_SUPPORTED=y +CONFIG_SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256=y +CONFIG_SOC_CLK_RC_FAST_SUPPORT_CALIBRATION=y +CONFIG_SOC_CLK_XTAL32K_SUPPORTED=y +CONFIG_SOC_EFUSE_DIS_DOWNLOAD_ICACHE=y +CONFIG_SOC_EFUSE_DIS_DOWNLOAD_DCACHE=y +CONFIG_SOC_EFUSE_HARD_DIS_JTAG=y +CONFIG_SOC_EFUSE_DIS_USB_JTAG=y +CONFIG_SOC_EFUSE_SOFT_DIS_JTAG=y +CONFIG_SOC_EFUSE_DIS_DIRECT_BOOT=y +CONFIG_SOC_EFUSE_DIS_ICACHE=y +CONFIG_SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK=y +CONFIG_SOC_SECURE_BOOT_V2_RSA=y +CONFIG_SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS=3 +CONFIG_SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS=y +CONFIG_SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY=y +CONFIG_SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX=64 +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES=y +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_OPTIONS=y +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128=y +CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_256=y +CONFIG_SOC_MEMPROT_CPU_PREFETCH_PAD_SIZE=16 +CONFIG_SOC_MEMPROT_MEM_ALIGN_SIZE=256 +CONFIG_SOC_PHY_DIG_REGS_MEM_SIZE=21 +CONFIG_SOC_MAC_BB_PD_MEM_SIZE=192 +CONFIG_SOC_WIFI_LIGHT_SLEEP_CLK_WIDTH=12 +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE=y +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND=y +CONFIG_SOC_SPI_MEM_SUPPORT_AUTO_RESUME=y +CONFIG_SOC_SPI_MEM_SUPPORT_SW_SUSPEND=y +CONFIG_SOC_SPI_MEM_SUPPORT_OPI_MODE=y +CONFIG_SOC_SPI_MEM_SUPPORT_TIMING_TUNING=y +CONFIG_SOC_SPI_MEM_SUPPORT_CONFIG_GPIO_BY_EFUSE=y +CONFIG_SOC_SPI_MEM_SUPPORT_WRAP=y +CONFIG_SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY=y +CONFIG_SOC_MEMSPI_CORE_CLK_SHARED_WITH_PSRAM=y +CONFIG_SOC_SPI_MEM_SUPPORT_CACHE_32BIT_ADDR_MAP=y +CONFIG_SOC_COEX_HW_PTI=y +CONFIG_SOC_EXTERNAL_COEX_LEADER_TX_LINE=y +CONFIG_SOC_SDMMC_USE_GPIO_MATRIX=y +CONFIG_SOC_SDMMC_NUM_SLOTS=2 +CONFIG_SOC_SDMMC_SUPPORT_XTAL_CLOCK=y +CONFIG_SOC_SDMMC_DELAY_PHASE_NUM=4 +CONFIG_SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC=y +CONFIG_SOC_WIFI_HW_TSF=y +CONFIG_SOC_WIFI_FTM_SUPPORT=y +CONFIG_SOC_WIFI_GCMP_SUPPORT=y +CONFIG_SOC_WIFI_WAPI_SUPPORT=y +CONFIG_SOC_WIFI_CSI_SUPPORT=y +CONFIG_SOC_WIFI_MESH_SUPPORT=y +CONFIG_SOC_WIFI_SUPPORT_VARIABLE_BEACON_WINDOW=y +CONFIG_SOC_WIFI_PHY_NEEDS_USB_WORKAROUND=y +CONFIG_SOC_BLE_SUPPORTED=y +CONFIG_SOC_BLE_MESH_SUPPORTED=y +CONFIG_SOC_BLE_50_SUPPORTED=y +CONFIG_SOC_BLE_DEVICE_PRIVACY_SUPPORTED=y +CONFIG_SOC_BLUFI_SUPPORTED=y +CONFIG_SOC_ULP_HAS_ADC=y +CONFIG_SOC_PHY_COMBO_MODULE=y +CONFIG_IDF_CMAKE=y +CONFIG_IDF_TOOLCHAIN="gcc" +CONFIG_IDF_TOOLCHAIN_GCC=y +CONFIG_IDF_TARGET_ARCH_XTENSA=y +CONFIG_IDF_TARGET_ARCH="xtensa" +CONFIG_IDF_TARGET="esp32s3" +CONFIG_IDF_INIT_VERSION="5.3.1" +CONFIG_IDF_TARGET_ESP32S3=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0009 + +# +# Build type +# +CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y +# CONFIG_APP_BUILD_TYPE_RAM is not set +CONFIG_APP_BUILD_GENERATE_BINARIES=y +CONFIG_APP_BUILD_BOOTLOADER=y +CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y +# CONFIG_APP_REPRODUCIBLE_BUILD is not set +# CONFIG_APP_NO_BLOBS is not set +# end of Build type + +# +# Bootloader config +# + +# +# Bootloader manager +# +CONFIG_BOOTLOADER_COMPILE_TIME_DATE=y +CONFIG_BOOTLOADER_PROJECT_VER=1 +# end of Bootloader manager + +CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0 +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF=y +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set + +# +# Log +# +# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set +CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set +# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set +CONFIG_BOOTLOADER_LOG_LEVEL=3 + +# +# Format +# +# CONFIG_BOOTLOADER_LOG_COLORS is not set +CONFIG_BOOTLOADER_LOG_TIMESTAMP_SOURCE_CPU_TICKS=y +# end of Format +# end of Log + +# +# Serial Flash Configurations +# +# CONFIG_BOOTLOADER_FLASH_DC_AWARE is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y +# end of Serial Flash Configurations + +CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y +# CONFIG_BOOTLOADER_FACTORY_RESET is not set +# CONFIG_BOOTLOADER_APP_TEST is not set +CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y +CONFIG_BOOTLOADER_WDT_ENABLE=y +# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set +CONFIG_BOOTLOADER_WDT_TIME_MS=9000 +# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 +# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +# end of Bootloader config + +# +# Security features +# +CONFIG_SECURE_BOOT_V2_RSA_SUPPORTED=y +CONFIG_SECURE_BOOT_V2_PREFERRED=y +# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set +# CONFIG_SECURE_BOOT is not set +# CONFIG_SECURE_FLASH_ENC_ENABLED is not set +CONFIG_SECURE_ROM_DL_MODE_ENABLED=y +# end of Security features + +# +# Application manager +# +CONFIG_APP_COMPILE_TIME_DATE=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set +# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 +# end of Application manager + +CONFIG_ESP_ROM_HAS_CRC_LE=y +CONFIG_ESP_ROM_HAS_CRC_BE=y +CONFIG_ESP_ROM_HAS_MZ_CRC32=y +CONFIG_ESP_ROM_HAS_JPEG_DECODE=y +CONFIG_ESP_ROM_UART_CLK_IS_XTAL=y +CONFIG_ESP_ROM_HAS_RETARGETABLE_LOCKING=y +CONFIG_ESP_ROM_USB_OTG_NUM=3 +CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=4 +CONFIG_ESP_ROM_HAS_ERASE_0_REGION_BUG=y +CONFIG_ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV=y +CONFIG_ESP_ROM_GET_CLK_FREQ=y +CONFIG_ESP_ROM_HAS_HAL_WDT=y +CONFIG_ESP_ROM_NEEDS_SWSETUP_WORKAROUND=y +CONFIG_ESP_ROM_HAS_LAYOUT_TABLE=y +CONFIG_ESP_ROM_HAS_SPI_FLASH=y +CONFIG_ESP_ROM_HAS_ETS_PRINTF_BUG=y +CONFIG_ESP_ROM_HAS_NEWLIB=y +CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT=y +CONFIG_ESP_ROM_HAS_NEWLIB_32BIT_TIME=y +CONFIG_ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE=y +CONFIG_ESP_ROM_RAM_APP_NEEDS_MMU_INIT=y +CONFIG_ESP_ROM_HAS_FLASH_COUNT_PAGES_BUG=y +CONFIG_ESP_ROM_HAS_CACHE_SUSPEND_WAITI_BUG=y +CONFIG_ESP_ROM_HAS_CACHE_WRITEBACK_BUG=y +CONFIG_ESP_ROM_HAS_SW_FLOAT=y +CONFIG_ESP_ROM_HAS_VERSION=y +CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y +CONFIG_ESP_ROM_HAS_OUTPUT_PUTC_FUNC=y + +# +# Boot ROM Behavior +# +CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y +# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set +# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set +# end of Boot ROM Behavior + +# +# Serial flasher config +# +# CONFIG_ESPTOOLPY_NO_STUB is not set +# CONFIG_ESPTOOLPY_OCT_FLASH is not set +CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT=y +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set +CONFIG_ESPTOOLPY_FLASHMODE_DIO=y +# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set +CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y +CONFIG_ESPTOOLPY_FLASHMODE="dio" +# CONFIG_ESPTOOLPY_FLASHFREQ_120M is not set +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="16MB" +# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set +CONFIG_ESPTOOLPY_BEFORE_RESET=y +# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE="default_reset" +CONFIG_ESPTOOLPY_AFTER_RESET=y +# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER="hard_reset" +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +# end of Serial flasher config + +# +# Partition Table +# +# CONFIG_PARTITION_TABLE_SINGLE_APP is not set +# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Compiler options +# +# CONFIG_COMPILER_OPTIMIZATION_DEBUG is not set +# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +CONFIG_COMPILER_OPTIMIZATION_PERF=y +# CONFIG_COMPILER_OPTIMIZATION_NONE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +CONFIG_COMPILER_ASSERT_NDEBUG_EVALUATE=y +CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +# CONFIG_COMPILER_CXX_RTTI is not set +CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y +# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set +# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set +# CONFIG_COMPILER_NO_MERGE_CONSTANTS is not set +# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set +CONFIG_COMPILER_DISABLE_DEFAULT_ERRORS=y +# CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set +# CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set +# CONFIG_COMPILER_DISABLE_GCC14_WARNINGS is not set +# CONFIG_COMPILER_DUMP_RTL_FILES is not set +CONFIG_COMPILER_RT_LIB_GCCLIB=y +CONFIG_COMPILER_RT_LIB_NAME="gcc" +# CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set +CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE=y +# CONFIG_COMPILER_STATIC_ANALYZER is not set +# end of Compiler options + +# +# Component config +# + +# +# Application Level Tracing +# +# CONFIG_APPTRACE_DEST_JTAG is not set +CONFIG_APPTRACE_DEST_NONE=y +# CONFIG_APPTRACE_DEST_UART1 is not set +# CONFIG_APPTRACE_DEST_UART2 is not set +# CONFIG_APPTRACE_DEST_USB_CDC is not set +CONFIG_APPTRACE_DEST_UART_NONE=y +CONFIG_APPTRACE_UART_TASK_PRIO=1 +CONFIG_APPTRACE_LOCK_ENABLE=y +# end of Application Level Tracing + +# +# Bluetooth +# +CONFIG_BT_ENABLED=y +# CONFIG_BT_BLUEDROID_ENABLED is not set +CONFIG_BT_NIMBLE_ENABLED=y +# CONFIG_BT_CONTROLLER_ONLY is not set +CONFIG_BT_CONTROLLER_ENABLED=y +# CONFIG_BT_CONTROLLER_DISABLED is not set + +# +# NimBLE Options +# +CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y +# CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL is not set +# CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set +# CONFIG_BT_NIMBLE_LOG_LEVEL_NONE is not set +# CONFIG_BT_NIMBLE_LOG_LEVEL_ERROR is not set +CONFIG_BT_NIMBLE_LOG_LEVEL_WARNING=y +# CONFIG_BT_NIMBLE_LOG_LEVEL_INFO is not set +# CONFIG_BT_NIMBLE_LOG_LEVEL_DEBUG is not set +CONFIG_BT_NIMBLE_LOG_LEVEL=2 +CONFIG_BT_NIMBLE_MAX_CONNECTIONS=3 +CONFIG_BT_NIMBLE_MAX_BONDS=3 +CONFIG_BT_NIMBLE_MAX_CCCDS=8 +CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM=0 +CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=y +# CONFIG_BT_NIMBLE_PINNED_TO_CORE_1 is not set +CONFIG_BT_NIMBLE_PINNED_TO_CORE=0 +CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=4096 +CONFIG_BT_NIMBLE_ROLE_CENTRAL=y +CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=y +CONFIG_BT_NIMBLE_ROLE_BROADCASTER=y +CONFIG_BT_NIMBLE_ROLE_OBSERVER=y +CONFIG_BT_NIMBLE_NVS_PERSIST=y +# CONFIG_BT_NIMBLE_SMP_ID_RESET is not set +CONFIG_BT_NIMBLE_SECURITY_ENABLE=y +CONFIG_BT_NIMBLE_SM_LEGACY=y +CONFIG_BT_NIMBLE_SM_SC=y +# CONFIG_BT_NIMBLE_SM_SC_DEBUG_KEYS is not set +CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_ENCRYPTION=y +CONFIG_BT_NIMBLE_SM_LVL=0 +# CONFIG_BT_NIMBLE_DEBUG is not set +# CONFIG_BT_NIMBLE_DYNAMIC_SERVICE is not set +CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME="KTag 32ESPecial" +CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=31 +CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU=256 +CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE=0 + +# +# Memory Settings +# +CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=12 +CONFIG_BT_NIMBLE_MSYS_1_BLOCK_SIZE=256 +CONFIG_BT_NIMBLE_MSYS_2_BLOCK_COUNT=24 +CONFIG_BT_NIMBLE_MSYS_2_BLOCK_SIZE=320 +CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=24 +CONFIG_BT_NIMBLE_TRANSPORT_ACL_SIZE=255 +CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=70 +CONFIG_BT_NIMBLE_TRANSPORT_EVT_COUNT=30 +CONFIG_BT_NIMBLE_TRANSPORT_EVT_DISCARD_COUNT=8 +CONFIG_BT_NIMBLE_L2CAP_COC_SDU_BUFF_COUNT=1 +# end of Memory Settings + +CONFIG_BT_NIMBLE_GATT_MAX_PROCS=4 +# CONFIG_BT_NIMBLE_HS_FLOW_CTRL is not set +CONFIG_BT_NIMBLE_RPA_TIMEOUT=900 +# CONFIG_BT_NIMBLE_MESH is not set +CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS=y +CONFIG_BT_NIMBLE_HS_STOP_TIMEOUT_MS=2000 +CONFIG_BT_NIMBLE_ENABLE_CONN_REATTEMPT=y +CONFIG_BT_NIMBLE_MAX_CONN_REATTEMPT=3 +CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=y +CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_2M_PHY=y +CONFIG_BT_NIMBLE_LL_CFG_FEAT_LE_CODED_PHY=y +# CONFIG_BT_NIMBLE_EXT_ADV is not set +CONFIG_BT_NIMBLE_EXT_SCAN=y +CONFIG_BT_NIMBLE_ENABLE_PERIODIC_SYNC=y +CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS=0 +# CONFIG_BT_NIMBLE_GATT_CACHING is not set +CONFIG_BT_NIMBLE_WHITELIST_SIZE=12 +# CONFIG_BT_NIMBLE_TEST_THROUGHPUT_TEST is not set +# CONFIG_BT_NIMBLE_BLUFI_ENABLE is not set +CONFIG_BT_NIMBLE_USE_ESP_TIMER=y +CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE=y +# CONFIG_BT_NIMBLE_BLE_GATT_BLOB_TRANSFER is not set + +# +# GAP Service +# + +# +# GAP Appearance write permissions +# +# CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE is not set +# end of GAP Appearance write permissions + +CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM=0 +CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ENC=0 +CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ATHN=0 +CONFIG_BT_NIMBLE_SVC_GAP_APPEAR_WRITE_PERM_ATHR=0 +CONFIG_BT_NIMBLE_SVC_GAP_CAR_CHAR_NOT_SUPP=y +# CONFIG_BT_NIMBLE_SVC_GAP_CAR_NOT_SUPP is not set +# CONFIG_BT_NIMBLE_SVC_GAP_CAR_SUPP is not set +CONFIG_BT_NIMBLE_SVC_GAP_CENT_ADDR_RESOLUTION=-1 + +# +# GAP device name write permissions +# +# CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE is not set +# end of GAP device name write permissions + +CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM=0 +CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_ENC=0 +CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_AUTHEN=0 +CONFIG_BT_NIMBLE_SVC_GAP_NAME_WRITE_PERM_AUTHOR=0 +CONFIG_BT_NIMBLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL=0 +CONFIG_BT_NIMBLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL=0 +CONFIG_BT_NIMBLE_SVC_GAP_PPCP_SLAVE_LATENCY=0 +CONFIG_BT_NIMBLE_SVC_GAP_PPCP_SUPERVISION_TMO=0 +# end of GAP Service + +# +# BLE Services +# +# CONFIG_BT_NIMBLE_HID_SERVICE is not set +# end of BLE Services + +# CONFIG_BT_NIMBLE_VS_SUPPORT is not set +# CONFIG_BT_NIMBLE_ENC_ADV_DATA is not set +CONFIG_BT_NIMBLE_HIGH_DUTY_ADV_ITVL=y +# CONFIG_BT_NIMBLE_HOST_ALLOW_CONNECT_WITH_SCAN is not set +# CONFIG_BT_NIMBLE_HOST_QUEUE_CONG_CHECK is not set + +# +# Host-controller Transport +# +CONFIG_UART_HW_FLOWCTRL_DISABLE=y +# CONFIG_UART_HW_FLOWCTRL_CTS_RTS is not set +CONFIG_BT_NIMBLE_HCI_UART_FLOW_CTRL=0 +CONFIG_BT_NIMBLE_HCI_UART_RTS_PIN=19 +CONFIG_BT_NIMBLE_HCI_UART_CTS_PIN=23 +# end of Host-controller Transport +# end of NimBLE Options + +# +# Controller Options +# +CONFIG_BT_CTRL_MODE_EFF=1 +CONFIG_BT_CTRL_BLE_MAX_ACT=6 +CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=6 +CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=0 +CONFIG_BT_CTRL_PINNED_TO_CORE_0=y +# CONFIG_BT_CTRL_PINNED_TO_CORE_1 is not set +CONFIG_BT_CTRL_PINNED_TO_CORE=0 +CONFIG_BT_CTRL_HCI_MODE_VHCI=y +# CONFIG_BT_CTRL_HCI_MODE_UART_H4 is not set +CONFIG_BT_CTRL_HCI_TL=1 +CONFIG_BT_CTRL_ADV_DUP_FILT_MAX=30 +CONFIG_BT_BLE_CCA_MODE_NONE=y +# CONFIG_BT_BLE_CCA_MODE_HW is not set +# CONFIG_BT_BLE_CCA_MODE_SW is not set +CONFIG_BT_BLE_CCA_MODE=0 +CONFIG_BT_CTRL_HW_CCA_VAL=20 +CONFIG_BT_CTRL_HW_CCA_EFF=0 +CONFIG_BT_CTRL_CE_LENGTH_TYPE_ORIG=y +# CONFIG_BT_CTRL_CE_LENGTH_TYPE_CE is not set +# CONFIG_BT_CTRL_CE_LENGTH_TYPE_SD is not set +CONFIG_BT_CTRL_CE_LENGTH_TYPE_EFF=0 +CONFIG_BT_CTRL_TX_ANTENNA_INDEX_0=y +# CONFIG_BT_CTRL_TX_ANTENNA_INDEX_1 is not set +CONFIG_BT_CTRL_TX_ANTENNA_INDEX_EFF=0 +CONFIG_BT_CTRL_RX_ANTENNA_INDEX_0=y +# CONFIG_BT_CTRL_RX_ANTENNA_INDEX_1 is not set +CONFIG_BT_CTRL_RX_ANTENNA_INDEX_EFF=0 +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N24 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N21 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N18 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N15 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N12 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N9 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N6 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N3 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_N0 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P3 is not set +CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P6=y +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P9 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P12 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P15 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P18 is not set +# CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P20 is not set +CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_EFF=10 +CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y +CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM=100 +CONFIG_BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD=20 +CONFIG_BT_CTRL_BLE_SCAN_DUPL=y +# CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DEVICE is not set +# CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA is not set +CONFIG_BT_CTRL_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BT_CTRL_SCAN_DUPL_TYPE=2 +CONFIG_BT_CTRL_SCAN_DUPL_CACHE_SIZE=100 +CONFIG_BT_CTRL_DUPL_SCAN_CACHE_REFRESH_PERIOD=0 +# CONFIG_BT_CTRL_BLE_MESH_SCAN_DUPL_EN is not set +# CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EN is not set +CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_DIS=y +CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EFF=0 + +# +# MODEM SLEEP Options +# +# CONFIG_BT_CTRL_MODEM_SLEEP is not set +# end of MODEM SLEEP Options + +CONFIG_BT_CTRL_SLEEP_MODE_EFF=0 +CONFIG_BT_CTRL_SLEEP_CLOCK_EFF=0 +CONFIG_BT_CTRL_HCI_TL_EFF=1 +# CONFIG_BT_CTRL_AGC_RECORRECT_EN is not set +CONFIG_BT_CTRL_SCAN_BACKOFF_UPPERLIMITMAX=y +# CONFIG_BT_BLE_ADV_DATA_LENGTH_ZERO_AUX is not set +CONFIG_BT_CTRL_CHAN_ASS_EN=y +CONFIG_BT_CTRL_LE_PING_EN=y + +# +# BLE disconnect when instant passed +# +# CONFIG_BT_CTRL_BLE_LLCP_CONN_UPDATE is not set +# CONFIG_BT_CTRL_BLE_LLCP_CHAN_MAP_UPDATE is not set +# CONFIG_BT_CTRL_BLE_LLCP_PHY_UPDATE is not set +# end of BLE disconnect when instant passed + +# CONFIG_BT_CTRL_RUN_IN_FLASH_ONLY is not set +# end of Controller Options + +# +# Common Options +# +CONFIG_BT_ALARM_MAX_NUM=50 +# end of Common Options + +# CONFIG_BT_HCI_LOG_DEBUG_EN is not set +# end of Bluetooth + +# CONFIG_BLE_MESH is not set + +# +# Console Library +# +# CONFIG_CONSOLE_SORTED_HELP is not set +# end of Console Library + +# +# Driver Configurations +# + +# +# TWAI Configuration +# +# CONFIG_TWAI_ISR_IN_IRAM is not set +CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y +# end of TWAI Configuration + +# +# Legacy ADC Driver Configuration +# +# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set + +# +# Legacy ADC Calibration Configuration +# +# CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy ADC Calibration Configuration +# end of Legacy ADC Driver Configuration + +# +# Legacy MCPWM Driver Configurations +# +# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy MCPWM Driver Configurations + +# +# Legacy Timer Group Driver Configurations +# +# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy Timer Group Driver Configurations + +# +# Legacy RMT Driver Configurations +# +# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy RMT Driver Configurations + +# +# Legacy I2S Driver Configurations +# +# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy I2S Driver Configurations + +# +# Legacy PCNT Driver Configurations +# +# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy PCNT Driver Configurations + +# +# Legacy SDM Driver Configurations +# +# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy SDM Driver Configurations + +# +# Legacy Temperature Sensor Driver Configurations +# +# CONFIG_TEMP_SENSOR_SUPPRESS_DEPRECATE_WARN is not set +# end of Legacy Temperature Sensor Driver Configurations +# end of Driver Configurations + +# +# eFuse Bit Manager +# +# CONFIG_EFUSE_CUSTOM_TABLE is not set +# CONFIG_EFUSE_VIRTUAL is not set +CONFIG_EFUSE_MAX_BLK_LEN=256 +# end of eFuse Bit Manager + +# +# ESP-TLS +# +CONFIG_ESP_TLS_USING_MBEDTLS=y +CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y +# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER_SESSION_TICKETS is not set +# CONFIG_ESP_TLS_SERVER_CERT_SELECT_HOOK is not set +# CONFIG_ESP_TLS_SERVER_MIN_AUTH_MODE_OPTIONAL is not set +# CONFIG_ESP_TLS_PSK_VERIFICATION is not set +# CONFIG_ESP_TLS_INSECURE is not set +# end of ESP-TLS + +# +# ADC and ADC Calibration +# +# CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE is not set +# CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3 is not set +# CONFIG_ADC_ENABLE_DEBUG_LOG is not set +# end of ADC and ADC Calibration + +# +# Wireless Coexistence +# +CONFIG_ESP_COEX_ENABLED=y +CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y +# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set +# CONFIG_ESP_COEX_GPIO_DEBUG is not set +# end of Wireless Coexistence + +# +# Common ESP-related +# +CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +# end of Common ESP-related + +# +# ESP-Driver:GPIO Configurations +# +# CONFIG_GPIO_CTRL_FUNC_IN_IRAM is not set +# end of ESP-Driver:GPIO Configurations + +# +# ESP-Driver:GPTimer Configurations +# +CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y +# CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM is not set +# CONFIG_GPTIMER_ISR_IRAM_SAFE is not set +# CONFIG_GPTIMER_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:GPTimer Configurations + +# +# ESP-Driver:I2C Configurations +# +# CONFIG_I2C_ISR_IRAM_SAFE is not set +# CONFIG_I2C_ENABLE_DEBUG_LOG is not set +# CONFIG_I2C_ENABLE_SLAVE_DRIVER_VERSION_2 is not set +# end of ESP-Driver:I2C Configurations + +# +# ESP-Driver:I2S Configurations +# +# CONFIG_I2S_ISR_IRAM_SAFE is not set +# CONFIG_I2S_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:I2S Configurations + +# +# ESP-Driver:LEDC Configurations +# +# CONFIG_LEDC_CTRL_FUNC_IN_IRAM is not set +# end of ESP-Driver:LEDC Configurations + +# +# ESP-Driver:MCPWM Configurations +# +# CONFIG_MCPWM_ISR_IRAM_SAFE is not set +# CONFIG_MCPWM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_MCPWM_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:MCPWM Configurations + +# +# ESP-Driver:PCNT Configurations +# +# CONFIG_PCNT_CTRL_FUNC_IN_IRAM is not set +# CONFIG_PCNT_ISR_IRAM_SAFE is not set +# CONFIG_PCNT_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:PCNT Configurations + +# +# ESP-Driver:RMT Configurations +# +# CONFIG_RMT_ISR_IRAM_SAFE is not set +# CONFIG_RMT_RECV_FUNC_IN_IRAM is not set +# CONFIG_RMT_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:RMT Configurations + +# +# ESP-Driver:Sigma Delta Modulator Configurations +# +# CONFIG_SDM_CTRL_FUNC_IN_IRAM is not set +# CONFIG_SDM_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:Sigma Delta Modulator Configurations + +# +# ESP-Driver:SPI Configurations +# +# CONFIG_SPI_MASTER_IN_IRAM is not set +CONFIG_SPI_MASTER_ISR_IN_IRAM=y +# CONFIG_SPI_SLAVE_IN_IRAM is not set +CONFIG_SPI_SLAVE_ISR_IN_IRAM=y +# end of ESP-Driver:SPI Configurations + +# +# ESP-Driver:Touch Sensor Configurations +# +# CONFIG_TOUCH_CTRL_FUNC_IN_IRAM is not set +# CONFIG_TOUCH_ISR_IRAM_SAFE is not set +# CONFIG_TOUCH_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:Touch Sensor Configurations + +# +# ESP-Driver:Temperature Sensor Configurations +# +# CONFIG_TEMP_SENSOR_ENABLE_DEBUG_LOG is not set +# end of ESP-Driver:Temperature Sensor Configurations + +# +# ESP-Driver:UART Configurations +# +# CONFIG_UART_ISR_IN_IRAM is not set +# end of ESP-Driver:UART Configurations + +# +# ESP-Driver:USB Serial/JTAG Configuration +# +CONFIG_USJ_ENABLE_USB_SERIAL_JTAG=y +# end of ESP-Driver:USB Serial/JTAG Configuration + +# +# Ethernet +# +CONFIG_ETH_ENABLED=y +CONFIG_ETH_USE_SPI_ETHERNET=y +# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set +# CONFIG_ETH_SPI_ETHERNET_W5500 is not set +# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set +# CONFIG_ETH_USE_OPENETH is not set +# CONFIG_ETH_TRANSMIT_MUTEX is not set +# end of Ethernet + +# +# Event Loop Library +# +# CONFIG_ESP_EVENT_LOOP_PROFILING is not set +CONFIG_ESP_EVENT_POST_FROM_ISR=y +CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y +# end of Event Loop Library + +# +# GDB Stub +# +CONFIG_ESP_GDBSTUB_ENABLED=y +# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set +CONFIG_ESP_GDBSTUB_SUPPORT_TASKS=y +CONFIG_ESP_GDBSTUB_MAX_TASKS=32 +# end of GDB Stub + +# +# ESP HTTP client +# +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y +# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set +# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set +# CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT is not set +CONFIG_ESP_HTTP_CLIENT_EVENT_POST_TIMEOUT=2000 +# end of ESP HTTP client + +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +# CONFIG_HTTPD_WS_SUPPORT is not set +# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set +CONFIG_HTTPD_SERVER_EVENT_POST_TIMEOUT=2000 +# end of HTTP Server + +# +# ESP HTTPS OTA +# +# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set +# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set +CONFIG_ESP_HTTPS_OTA_EVENT_POST_TIMEOUT=2000 +# end of ESP HTTPS OTA + +# +# ESP HTTPS server +# +# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set +CONFIG_ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT=2000 +# end of ESP HTTPS server + +# +# Hardware Settings +# + +# +# Chip revision +# +CONFIG_ESP32S3_REV_MIN_0=y +# CONFIG_ESP32S3_REV_MIN_1 is not set +# CONFIG_ESP32S3_REV_MIN_2 is not set +CONFIG_ESP32S3_REV_MIN_FULL=0 +CONFIG_ESP_REV_MIN_FULL=0 + +# +# Maximum Supported ESP32-S3 Revision (Rev v0.99) +# +CONFIG_ESP32S3_REV_MAX_FULL=99 +CONFIG_ESP_REV_MAX_FULL=99 +CONFIG_ESP_EFUSE_BLOCK_REV_MIN_FULL=0 +CONFIG_ESP_EFUSE_BLOCK_REV_MAX_FULL=199 + +# +# Maximum Supported ESP32-S3 eFuse Block Revision (eFuse Block Rev v1.99) +# +# end of Chip revision + +# +# MAC Config +# +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP_MAC_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC is not set +# end of MAC Config + +# +# Sleep Config +# +CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y +CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND=y +CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU=y +CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y +CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y +CONFIG_ESP_SLEEP_WAIT_FLASH_READY_EXTRA_DELAY=2000 +# CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set +# CONFIG_ESP_SLEEP_DEBUG is not set +CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y +# end of Sleep Config + +# +# RTC Clock Config +# +CONFIG_RTC_CLK_SRC_INT_RC=y +# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_RTC_CLK_CAL_CYCLES=1024 +# end of RTC Clock Config + +# +# Peripheral Control +# +CONFIG_PERIPH_CTRL_FUNC_IN_IRAM=y +# end of Peripheral Control + +# +# GDMA Configurations +# +CONFIG_GDMA_CTRL_FUNC_IN_IRAM=y +# CONFIG_GDMA_ISR_IRAM_SAFE is not set +# CONFIG_GDMA_ENABLE_DEBUG_LOG is not set +# end of GDMA Configurations + +# +# Main XTAL Config +# +CONFIG_XTAL_FREQ_40=y +CONFIG_XTAL_FREQ=40 +# end of Main XTAL Config + +CONFIG_ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM=y +# end of Hardware Settings + +# +# ESP-Driver:LCD Controller Configurations +# +# CONFIG_LCD_ENABLE_DEBUG_LOG is not set +# CONFIG_LCD_RGB_ISR_IRAM_SAFE is not set +# CONFIG_LCD_RGB_RESTART_IN_VSYNC is not set +# end of ESP-Driver:LCD Controller Configurations + +# +# ESP-MM: Memory Management Configurations +# +# CONFIG_ESP_MM_CACHE_MSYNC_C2M_CHUNKED_OPS is not set +# end of ESP-MM: Memory Management Configurations + +# +# ESP NETIF Adapter +# +CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 +# CONFIG_ESP_NETIF_PROVIDE_CUSTOM_IMPLEMENTATION is not set +CONFIG_ESP_NETIF_TCPIP_LWIP=y +# CONFIG_ESP_NETIF_LOOPBACK is not set +CONFIG_ESP_NETIF_USES_TCPIP_WITH_BSD_API=y +CONFIG_ESP_NETIF_REPORT_DATA_TRAFFIC=y +# CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS is not set +# CONFIG_ESP_NETIF_L2_TAP is not set +# CONFIG_ESP_NETIF_BRIDGE_EN is not set +# CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF is not set +# end of ESP NETIF Adapter + +# +# Partition API Configuration +# +# end of Partition API Configuration + +# +# PHY +# +CONFIG_ESP_PHY_ENABLED=y +CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP_PHY_MAX_TX_POWER=20 +# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set +CONFIG_ESP_PHY_ENABLE_USB=y +# CONFIG_ESP_PHY_ENABLE_CERT_TEST is not set +CONFIG_ESP_PHY_RF_CAL_PARTIAL=y +# CONFIG_ESP_PHY_RF_CAL_NONE is not set +# CONFIG_ESP_PHY_RF_CAL_FULL is not set +CONFIG_ESP_PHY_CALIBRATION_MODE=0 +# CONFIG_ESP_PHY_PLL_TRACK_DEBUG is not set +# CONFIG_ESP_PHY_RECORD_USED_TIME is not set +# end of PHY + +# +# Power Management +# +# CONFIG_PM_ENABLE is not set +# CONFIG_PM_SLP_IRAM_OPT is not set +# CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP is not set +# end of Power Management + +# +# ESP PSRAM +# +CONFIG_SPIRAM=y + +# +# SPI RAM config +# +# CONFIG_SPIRAM_MODE_QUAD is not set +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_TYPE_AUTO=y +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_CLK_IO=30 +CONFIG_SPIRAM_CS_IO=26 +# CONFIG_SPIRAM_XIP_FROM_PSRAM is not set +# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set +# CONFIG_SPIRAM_RODATA is not set +CONFIG_SPIRAM_SPEED_80M=y +# CONFIG_SPIRAM_SPEED_40M is not set +CONFIG_SPIRAM_SPEED=80 +# CONFIG_SPIRAM_ECC_ENABLE is not set +CONFIG_SPIRAM_BOOT_INIT=y +# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set +# CONFIG_SPIRAM_USE_MEMMAP is not set +# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set +CONFIG_SPIRAM_USE_MALLOC=y +CONFIG_SPIRAM_MEMTEST=y +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384 +CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 +# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set +# CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set +# end of SPI RAM config +# end of ESP PSRAM + +# +# ESP Ringbuf +# +# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set +# end of ESP Ringbuf + +# +# ESP Security Specific +# +# end of ESP Security Specific + +# +# ESP System Settings +# +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160 is not set +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=240 + +# +# Cache config +# +CONFIG_ESP32S3_INSTRUCTION_CACHE_16KB=y +# CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE=0x4000 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_4WAYS is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_8WAYS=y +CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS=8 +# CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_16B is not set +CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B=y +CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE=32 +# CONFIG_ESP32S3_DATA_CACHE_16KB is not set +CONFIG_ESP32S3_DATA_CACHE_32KB=y +# CONFIG_ESP32S3_DATA_CACHE_64KB is not set +CONFIG_ESP32S3_DATA_CACHE_SIZE=0x8000 +# CONFIG_ESP32S3_DATA_CACHE_4WAYS is not set +CONFIG_ESP32S3_DATA_CACHE_8WAYS=y +CONFIG_ESP32S3_DCACHE_ASSOCIATED_WAYS=8 +# CONFIG_ESP32S3_DATA_CACHE_LINE_16B is not set +CONFIG_ESP32S3_DATA_CACHE_LINE_32B=y +# CONFIG_ESP32S3_DATA_CACHE_LINE_64B is not set +CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE=32 +# end of Cache config + +# +# Memory +# +# CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM is not set +# CONFIG_ESP32S3_USE_FIXED_STATIC_RAM_SIZE is not set +# end of Memory + +# +# Trace memory +# +# CONFIG_ESP32S3_TRAX is not set +CONFIG_ESP32S3_TRACEMEM_RESERVE_DRAM=0x0 +# end of Trace memory + +# 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_PANIC_REBOOT_DELAY_SECONDS=0 +CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y +CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y + +# +# Memory protection +# +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=y +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK=y +# end of Memory protection + +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set +# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_USB_CDC is not set +# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_NONE is not set +# CONFIG_ESP_CONSOLE_SECONDARY_NONE is not set +CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y +CONFIG_ESP_CONSOLE_UART=y +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=0 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=5000 +CONFIG_ESP_INT_WDT_CHECK_CPU1=y +CONFIG_ESP_TASK_WDT_EN=y +CONFIG_ESP_TASK_WDT_INIT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP_DEBUG_OCDAWARE=y +CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y + +# +# Brownout Detector +# +CONFIG_ESP_BROWNOUT_DET=y +CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP_BROWNOUT_DET_LVL_SEL_1 is not set +CONFIG_ESP_BROWNOUT_DET_LVL=7 +# end of Brownout Detector + +CONFIG_ESP_SYSTEM_BROWNOUT_INTR=y +CONFIG_ESP_SYSTEM_BBPLL_RECALIB=y +# end of ESP System Settings + +# +# IPC (Inter-Processor Call) +# +CONFIG_ESP_IPC_TASK_STACK_SIZE=1280 +CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y +CONFIG_ESP_IPC_ISR_ENABLE=y +# end of IPC (Inter-Processor Call) + +# +# ESP Timer (High Resolution Timer) +# +# CONFIG_ESP_TIMER_PROFILING is not set +CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y +CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y +CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1 +# CONFIG_ESP_TIMER_SHOW_EXPERIMENTAL is not set +CONFIG_ESP_TIMER_TASK_AFFINITY=0x0 +CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y +CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y +# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set +CONFIG_ESP_TIMER_IMPL_SYSTIMER=y +# end of ESP Timer (High Resolution Timer) + +# +# Wi-Fi +# +CONFIG_ESP_WIFI_ENABLED=y +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +CONFIG_ESP_WIFI_STATIC_TX_BUFFER=y +CONFIG_ESP_WIFI_TX_BUFFER_TYPE=0 +CONFIG_ESP_WIFI_STATIC_TX_BUFFER_NUM=16 +CONFIG_ESP_WIFI_CACHE_TX_BUFFER_NUM=32 +CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER=y +# CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER is not set +CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=0 +CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF=5 +# CONFIG_ESP_WIFI_CSI_ENABLED is not set +CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP_WIFI_TX_BA_WIN=6 +CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP_WIFI_RX_BA_WIN=6 +# CONFIG_ESP_WIFI_AMSDU_TX_ENABLED is not set +CONFIG_ESP_WIFI_NVS_ENABLED=y +CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_0=y +# CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_1 is not set +CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP_WIFI_IRAM_OPT=y +# CONFIG_ESP_WIFI_EXTRA_IRAM_OPT is not set +CONFIG_ESP_WIFI_RX_IRAM_OPT=y +CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP_WIFI_ENABLE_SAE_PK=y +CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=y +CONFIG_ESP_WIFI_ENABLE_WPA3_OWE_STA=y +# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set +CONFIG_ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME=50 +CONFIG_ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME=10 +CONFIG_ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME=15 +# CONFIG_ESP_WIFI_FTM_ENABLE is not set +CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y +# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set +# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set +CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set +CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7 +CONFIG_ESP_WIFI_MBEDTLS_CRYPTO=y +# CONFIG_ESP_WIFI_WAPI_PSK is not set +# CONFIG_ESP_WIFI_SUITE_B_192 is not set +# CONFIG_ESP_WIFI_11KV_SUPPORT is not set +# CONFIG_ESP_WIFI_MBO_SUPPORT is not set +# CONFIG_ESP_WIFI_DPP_SUPPORT is not set +# CONFIG_ESP_WIFI_11R_SUPPORT is not set +# CONFIG_ESP_WIFI_WPS_SOFTAP_REGISTRAR is not set + +# +# WPS Configuration Options +# +# CONFIG_ESP_WIFI_WPS_STRICT is not set +# CONFIG_ESP_WIFI_WPS_PASSPHRASE is not set +# end of WPS Configuration Options + +# CONFIG_ESP_WIFI_DEBUG_PRINT is not set +# CONFIG_ESP_WIFI_TESTING_OPTIONS is not set +# CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT is not set +# end of Wi-Fi + +# +# Core dump +# +CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_NONE is not set +# CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN is not set +CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y +CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y +# CONFIG_ESP_COREDUMP_CHECKSUM_SHA256 is not set +CONFIG_ESP_COREDUMP_CAPTURE_DRAM=y +CONFIG_ESP_COREDUMP_CHECK_BOOT=y +CONFIG_ESP_COREDUMP_ENABLE=y +CONFIG_ESP_COREDUMP_LOGS=y +CONFIG_ESP_COREDUMP_MAX_TASKS_NUM=64 +# CONFIG_ESP_COREDUMP_FLASH_NO_OVERWRITE is not set +CONFIG_ESP_COREDUMP_USE_STACK_SIZE=y +CONFIG_ESP_COREDUMP_STACK_SIZE=1792 +# end of Core dump + +# +# FAT Filesystem support +# +CONFIG_FATFS_VOLUME_COUNT=2 +CONFIG_FATFS_LFN_NONE=y +# CONFIG_FATFS_LFN_HEAP is not set +# CONFIG_FATFS_LFN_STACK is not set +# CONFIG_FATFS_SECTOR_512 is not set +CONFIG_FATFS_SECTOR_4096=y +# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set +CONFIG_FATFS_CODEPAGE_437=y +# CONFIG_FATFS_CODEPAGE_720 is not set +# CONFIG_FATFS_CODEPAGE_737 is not set +# CONFIG_FATFS_CODEPAGE_771 is not set +# CONFIG_FATFS_CODEPAGE_775 is not set +# CONFIG_FATFS_CODEPAGE_850 is not set +# CONFIG_FATFS_CODEPAGE_852 is not set +# CONFIG_FATFS_CODEPAGE_855 is not set +# CONFIG_FATFS_CODEPAGE_857 is not set +# CONFIG_FATFS_CODEPAGE_860 is not set +# CONFIG_FATFS_CODEPAGE_861 is not set +# CONFIG_FATFS_CODEPAGE_862 is not set +# CONFIG_FATFS_CODEPAGE_863 is not set +# CONFIG_FATFS_CODEPAGE_864 is not set +# CONFIG_FATFS_CODEPAGE_865 is not set +# CONFIG_FATFS_CODEPAGE_866 is not set +# CONFIG_FATFS_CODEPAGE_869 is not set +# CONFIG_FATFS_CODEPAGE_932 is not set +# CONFIG_FATFS_CODEPAGE_936 is not set +# CONFIG_FATFS_CODEPAGE_949 is not set +# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_CODEPAGE=437 +CONFIG_FATFS_FS_LOCK=0 +CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_PER_FILE_CACHE=y +CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y +# CONFIG_FATFS_USE_FASTSEEK is not set +CONFIG_FATFS_USE_STRFUNC_NONE=y +# CONFIG_FATFS_USE_STRFUNC_WITHOUT_CRLF_CONV is not set +# CONFIG_FATFS_USE_STRFUNC_WITH_CRLF_CONV is not set +CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0 +# CONFIG_FATFS_IMMEDIATE_FSYNC is not set +# CONFIG_FATFS_USE_LABEL is not set +CONFIG_FATFS_LINK_LOCK=y +# end of FAT Filesystem support + +# +# FreeRTOS +# + +# +# Kernel +# +# CONFIG_FREERTOS_SMP is not set +# CONFIG_FREERTOS_UNICORE is not set +CONFIG_FREERTOS_HZ=100 +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set +# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y +CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 +CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 +# CONFIG_FREERTOS_USE_IDLE_HOOK is not set +# CONFIG_FREERTOS_USE_TICK_HOOK is not set +CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 +# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set +CONFIG_FREERTOS_USE_TIMERS=y +CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc" +CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0=y +# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU1 is not set +# CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY is not set +CONFIG_FREERTOS_TIMER_SERVICE_TASK_CORE_AFFINITY=0x0 +CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4096 +CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 +CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 +CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1 +# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set +# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set +# end of Kernel + +# +# Port +# +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y +# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set +CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y +# CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK is not set +# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set +CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y +CONFIG_FREERTOS_ISR_STACKSIZE=2096 +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y +# CONFIG_FREERTOS_FPU_IN_ISR is not set +CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y +CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y +# CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set +CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y +# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set +# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set +# end of Port + +# +# Extra +# +CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM=y +# end of Extra + +CONFIG_FREERTOS_PORT=y +CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF +CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y +CONFIG_FREERTOS_DEBUG_OCDAWARE=y +CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y +CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH=y +CONFIG_FREERTOS_NUMBER_OF_CORES=2 +# end of FreeRTOS + +# +# Hardware Abstraction Layer (HAL) and Low Level (LL) +# +CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y +# CONFIG_HAL_ASSERTION_DISABLE is not set +# CONFIG_HAL_ASSERTION_SILENT is not set +# CONFIG_HAL_ASSERTION_ENABLE is not set +CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2 +CONFIG_HAL_WDT_USE_ROM_IMPL=y +CONFIG_HAL_SPI_MASTER_FUNC_IN_IRAM=y +CONFIG_HAL_SPI_SLAVE_FUNC_IN_IRAM=y +# CONFIG_HAL_ECDSA_GEN_SIG_CM is not set +# end of Hardware Abstraction Layer (HAL) and Low Level (LL) + +# +# Heap memory debugging +# +CONFIG_HEAP_POISONING_DISABLED=y +# CONFIG_HEAP_POISONING_LIGHT is not set +# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set +CONFIG_HEAP_TRACING_OFF=y +# CONFIG_HEAP_TRACING_STANDALONE is not set +# CONFIG_HEAP_TRACING_TOHOST is not set +# CONFIG_HEAP_USE_HOOKS is not set +# CONFIG_HEAP_TASK_TRACKING is not set +# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set +# CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH is not set +# end of Heap memory debugging + +# +# Log +# + +# +# Log Level +# +# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=3 +# CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT is not set +CONFIG_LOG_MAXIMUM_LEVEL_DEBUG=y +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=4 + +# +# Level Settings +# +# CONFIG_LOG_MASTER_LEVEL is not set +CONFIG_LOG_DYNAMIC_LEVEL_CONTROL=y +# CONFIG_LOG_TAG_LEVEL_IMPL_NONE is not set +# CONFIG_LOG_TAG_LEVEL_IMPL_LINKED_LIST is not set +CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_AND_LINKED_LIST=y +# CONFIG_LOG_TAG_LEVEL_CACHE_ARRAY is not set +CONFIG_LOG_TAG_LEVEL_CACHE_BINARY_MIN_HEAP=y +CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_SIZE=31 +# end of Level Settings +# end of Log Level + +# +# Format +# +CONFIG_LOG_COLORS=y +CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y +# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set +# end of Format +# end of Log + +# +# LWIP +# +CONFIG_LWIP_ENABLE=y +CONFIG_LWIP_LOCAL_HOSTNAME="ktag" +# CONFIG_LWIP_NETIF_API is not set +CONFIG_LWIP_TCPIP_TASK_PRIO=18 +# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set +# CONFIG_LWIP_CHECK_THREAD_SAFETY is not set +CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y +# CONFIG_LWIP_L2_TO_L3_COPY is not set +# CONFIG_LWIP_IRAM_OPTIMIZATION is not set +# CONFIG_LWIP_EXTRA_IRAM_OPTIMIZATION is not set +CONFIG_LWIP_TIMERS_ONDEMAND=y +CONFIG_LWIP_ND6=y +# CONFIG_LWIP_FORCE_ROUTER_FORWARDING is not set +CONFIG_LWIP_MAX_SOCKETS=10 +# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set +# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_REUSE=y +CONFIG_LWIP_SO_REUSE_RXTOALL=y +# CONFIG_LWIP_SO_RCVBUF is not set +# CONFIG_LWIP_NETBUF_RECVINFO is not set +CONFIG_LWIP_IP_DEFAULT_TTL=64 +CONFIG_LWIP_IP4_FRAG=y +CONFIG_LWIP_IP6_FRAG=y +# CONFIG_LWIP_IP4_REASSEMBLY is not set +# CONFIG_LWIP_IP6_REASSEMBLY is not set +CONFIG_LWIP_IP_REASS_MAX_PBUFS=10 +# CONFIG_LWIP_IP_FORWARD is not set +# CONFIG_LWIP_STATS is not set +CONFIG_LWIP_ESP_GRATUITOUS_ARP=y +CONFIG_LWIP_GARP_TMR_INTERVAL=60 +CONFIG_LWIP_ESP_MLDV6_REPORT=y +CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 +CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y +# CONFIG_LWIP_DHCP_DOES_ACD_CHECK is not set +# CONFIG_LWIP_DHCP_DOES_NOT_CHECK_OFFERED_IP is not set +# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set +CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y +# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set +CONFIG_LWIP_DHCP_OPTIONS_LEN=68 +CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=0 +CONFIG_LWIP_DHCP_COARSE_TIMER_SECS=1 + +# +# DHCP server +# +CONFIG_LWIP_DHCPS=y +CONFIG_LWIP_DHCPS_LEASE_UNIT=60 +CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 +CONFIG_LWIP_DHCPS_STATIC_ENTRIES=y +CONFIG_LWIP_DHCPS_ADD_DNS=y +# end of DHCP server + +# CONFIG_LWIP_AUTOIP is not set +CONFIG_LWIP_IPV4=y +CONFIG_LWIP_IPV6=y +# CONFIG_LWIP_IPV6_AUTOCONFIG is not set +CONFIG_LWIP_IPV6_NUM_ADDRESSES=3 +# CONFIG_LWIP_IPV6_FORWARD is not set +# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set +CONFIG_LWIP_NETIF_LOOPBACK=y +CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 + +# +# TCP +# +CONFIG_LWIP_MAX_ACTIVE_TCP=16 +CONFIG_LWIP_MAX_LISTENING_TCP=16 +CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y +CONFIG_LWIP_TCP_MAXRTX=12 +CONFIG_LWIP_TCP_SYNMAXRTX=12 +CONFIG_LWIP_TCP_MSS=1440 +CONFIG_LWIP_TCP_TMR_INTERVAL=250 +CONFIG_LWIP_TCP_MSL=60000 +CONFIG_LWIP_TCP_FIN_WAIT_TIMEOUT=20000 +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744 +CONFIG_LWIP_TCP_WND_DEFAULT=5744 +CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 +CONFIG_LWIP_TCP_ACCEPTMBOX_SIZE=6 +CONFIG_LWIP_TCP_QUEUE_OOSEQ=y +CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6 +CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4 +# CONFIG_LWIP_TCP_SACK_OUT is not set +CONFIG_LWIP_TCP_OVERSIZE_MSS=y +# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set +# CONFIG_LWIP_WND_SCALE is not set +CONFIG_LWIP_TCP_RTO_TIME=1500 +# end of TCP + +# +# UDP +# +CONFIG_LWIP_MAX_UDP_PCBS=16 +CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 +# end of UDP + +# +# Checksums +# +# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set +# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set +CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y +# end of Checksums + +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF +CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 +CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 +CONFIG_LWIP_IPV6_ND6_NUM_PREFIXES=5 +CONFIG_LWIP_IPV6_ND6_NUM_ROUTERS=3 +CONFIG_LWIP_IPV6_ND6_NUM_DESTINATIONS=10 +# CONFIG_LWIP_PPP_SUPPORT is not set +# CONFIG_LWIP_SLIP_SUPPORT is not set + +# +# ICMP +# +CONFIG_LWIP_ICMP=y +# CONFIG_LWIP_MULTICAST_PING is not set +# CONFIG_LWIP_BROADCAST_PING is not set +# end of ICMP + +# +# LWIP RAW API +# +CONFIG_LWIP_MAX_RAW_PCBS=16 +# end of LWIP RAW API + +# +# SNTP +# +CONFIG_LWIP_SNTP_MAX_SERVERS=1 +# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set +CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 +CONFIG_LWIP_SNTP_STARTUP_DELAY=y +CONFIG_LWIP_SNTP_MAXIMUM_STARTUP_DELAY=5000 +# end of SNTP + +# +# DNS +# +CONFIG_LWIP_DNS_MAX_HOST_IP=1 +CONFIG_LWIP_DNS_MAX_SERVERS=3 +# CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT is not set +# CONFIG_LWIP_DNS_SETSERVER_WITH_NETIF is not set +# end of DNS + +CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7 +CONFIG_LWIP_ESP_LWIP_ASSERT=y + +# +# Hooks +# +# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set +CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y +# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y +# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set +CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y +# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set +# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_NONE=y +# CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM is not set +CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set +# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set +CONFIG_LWIP_HOOK_DNS_EXT_RESOLVE_NONE=y +# CONFIG_LWIP_HOOK_DNS_EXT_RESOLVE_CUSTOM is not set +CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y +# CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set +# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set +# end of Hooks + +# CONFIG_LWIP_DEBUG is not set +# end of LWIP + +# +# mbedTLS +# +CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set +# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set +# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set +# CONFIG_MBEDTLS_DEBUG is not set + +# +# mbedTLS v3.x related +# +# CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 is not set +# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set +CONFIG_MBEDTLS_ECDH_LEGACY_CONTEXT=y +# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set +# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set +CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y +CONFIG_MBEDTLS_PKCS7_C=y +# end of mbedTLS v3.x related + +# +# Certificate Bundle +# +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set +# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEPRECATED_LIST is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200 +# end of Certificate Bundle + +CONFIG_MBEDTLS_ECP_RESTARTABLE=y +CONFIG_MBEDTLS_CMAC_C=y +CONFIG_MBEDTLS_HARDWARE_AES=y +CONFIG_MBEDTLS_AES_USE_INTERRUPT=y +CONFIG_MBEDTLS_AES_INTERRUPT_LEVEL=0 +# CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER is not set +CONFIG_MBEDTLS_HARDWARE_MPI=y +# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set +CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y +CONFIG_MBEDTLS_MPI_INTERRUPT_LEVEL=0 +CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_ROM_MD5=y +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set +# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_PLATFORM_TIME_ALT is not set +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y +CONFIG_MBEDTLS_SHA512_C=y +# CONFIG_MBEDTLS_SHA3_C is not set +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set +# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set +# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER=y +CONFIG_MBEDTLS_TLS_CLIENT=y +CONFIG_MBEDTLS_TLS_ENABLED=y + +# +# TLS Key Exchange Methods +# +# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y +CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y +# end of TLS Key Exchange Methods + +CONFIG_MBEDTLS_SSL_RENEGOTIATION=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set +# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_ALPN=y +CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y +CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y + +# +# Symmetric Ciphers +# +CONFIG_MBEDTLS_AES_C=y +# CONFIG_MBEDTLS_CAMELLIA_C is not set +# CONFIG_MBEDTLS_DES_C is not set +# CONFIG_MBEDTLS_BLOWFISH_C is not set +# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_CCM_C=y +CONFIG_MBEDTLS_GCM_C=y +# CONFIG_MBEDTLS_NIST_KW_C is not set +# end of Symmetric Ciphers + +# CONFIG_MBEDTLS_RIPEMD160_C is not set + +# +# Certificates +# +CONFIG_MBEDTLS_PEM_PARSE_C=y +CONFIG_MBEDTLS_PEM_WRITE_C=y +CONFIG_MBEDTLS_X509_CRL_PARSE_C=y +CONFIG_MBEDTLS_X509_CSR_PARSE_C=y +# end of Certificates + +CONFIG_MBEDTLS_ECP_C=y +CONFIG_MBEDTLS_PK_PARSE_EC_EXTENDED=y +CONFIG_MBEDTLS_PK_PARSE_EC_COMPRESSED=y +# CONFIG_MBEDTLS_DHM_C is not set +CONFIG_MBEDTLS_ECDH_C=y +CONFIG_MBEDTLS_ECDSA_C=y +# CONFIG_MBEDTLS_ECJPAKE_C is not set +CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y +CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y +CONFIG_MBEDTLS_ECP_NIST_OPTIM=y +CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM=y +# CONFIG_MBEDTLS_POLY1305_C is not set +# CONFIG_MBEDTLS_CHACHA20_C is not set +# CONFIG_MBEDTLS_HKDF_C is not set +# CONFIG_MBEDTLS_THREADING_C is not set +CONFIG_MBEDTLS_ERROR_STRINGS=y +CONFIG_MBEDTLS_FS_IO=y +# end of mbedTLS + +# +# ESP-MQTT Configurations +# +CONFIG_MQTT_PROTOCOL_311=y +# CONFIG_MQTT_PROTOCOL_5 is not set +CONFIG_MQTT_TRANSPORT_SSL=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations + +# +# Newlib +# +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set +# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set +# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y +# CONFIG_NEWLIB_NANO_FORMAT is not set +CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y +# CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT is not set +# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set +# end of Newlib + +CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND=y + +# +# NVS +# +# CONFIG_NVS_ENCRYPTION is not set +# CONFIG_NVS_ASSERT_ERROR_CHECK is not set +# CONFIG_NVS_LEGACY_DUP_KEYS_COMPATIBILITY is not set +# CONFIG_NVS_ALLOCATE_CACHE_IN_SPIRAM is not set +# end of NVS + +# +# OpenThread +# +# CONFIG_OPENTHREAD_ENABLED is not set + +# +# OpenThread Spinel +# +# CONFIG_OPENTHREAD_SPINEL_ONLY is not set +# end of OpenThread Spinel +# end of OpenThread + +# +# Protocomm +# +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y +CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y +# end of Protocomm + +# +# PThreads +# +CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_PTHREAD_STACK_MIN=768 +CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y +# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set +# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set +CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" +# end of PThreads + +# +# MMU Config +# +CONFIG_MMU_PAGE_SIZE_64KB=y +CONFIG_MMU_PAGE_MODE="64KB" +CONFIG_MMU_PAGE_SIZE=0x10000 +# end of MMU Config + +# +# Main Flash configuration +# + +# +# SPI Flash behavior when brownout +# +CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC=y +CONFIG_SPI_FLASH_BROWNOUT_RESET=y +# end of SPI Flash behavior when brownout + +# +# Optional and Experimental Features (READ DOCS FIRST) +# + +# +# Features here require specific hardware (READ DOCS FIRST!) +# +# CONFIG_SPI_FLASH_HPM_ENA is not set +CONFIG_SPI_FLASH_HPM_AUTO=y +# CONFIG_SPI_FLASH_HPM_DIS is not set +CONFIG_SPI_FLASH_HPM_ON=y +CONFIG_SPI_FLASH_HPM_DC_AUTO=y +# CONFIG_SPI_FLASH_HPM_DC_DISABLE is not set +# CONFIG_SPI_FLASH_AUTO_SUSPEND is not set +CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50 +# CONFIG_SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND is not set +# end of Optional and Experimental Features (READ DOCS FIRST) +# end of Main Flash configuration + +# +# SPI Flash driver +# +# CONFIG_SPI_FLASH_VERIFY_WRITE is not set +# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +# CONFIG_SPI_FLASH_ROM_IMPL is not set +CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set +# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set +# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set +CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y +CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 +CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 +CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 +# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set +# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set +# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set + +# +# Auto-detect flash chips +# +CONFIG_SPI_FLASH_VENDOR_XMC_SUPPORTED=y +CONFIG_SPI_FLASH_VENDOR_GD_SUPPORTED=y +CONFIG_SPI_FLASH_VENDOR_ISSI_SUPPORTED=y +CONFIG_SPI_FLASH_VENDOR_MXIC_SUPPORTED=y +CONFIG_SPI_FLASH_VENDOR_WINBOND_SUPPORTED=y +CONFIG_SPI_FLASH_VENDOR_BOYA_SUPPORTED=y +CONFIG_SPI_FLASH_VENDOR_TH_SUPPORTED=y +CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y +CONFIG_SPI_FLASH_SUPPORT_MXIC_OPI_CHIP=y +# end of Auto-detect flash chips + +CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y +# end of SPI Flash driver + +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +# CONFIG_SPIFFS_CACHE_STATS is not set +# end of SPIFFS Cache Configuration + +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +# CONFIG_SPIFFS_GC_STATS is not set +CONFIG_SPIFFS_PAGE_SIZE=256 +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y +CONFIG_SPIFFS_META_LENGTH=4 +CONFIG_SPIFFS_USE_MTIME=y + +# +# Debug Configuration +# +# CONFIG_SPIFFS_DBG is not set +# CONFIG_SPIFFS_API_DBG is not set +# CONFIG_SPIFFS_GC_DBG is not set +# CONFIG_SPIFFS_CACHE_DBG is not set +# CONFIG_SPIFFS_CHECK_DBG is not set +# CONFIG_SPIFFS_TEST_VISUALISATION is not set +# end of Debug Configuration +# end of SPIFFS Configuration + +# +# TCP Transport +# + +# +# Websocket +# +CONFIG_WS_TRANSPORT=y +CONFIG_WS_BUFFER_SIZE=1024 +# CONFIG_WS_DYNAMIC_BUFFER is not set +# end of Websocket +# end of TCP Transport + +# +# Ultra Low Power (ULP) Co-processor +# +# CONFIG_ULP_COPROC_ENABLED is not set + +# +# ULP Debugging Options +# +# end of ULP Debugging Options +# end of Ultra Low Power (ULP) Co-processor + +# +# Unity unit testing library +# +CONFIG_UNITY_ENABLE_FLOAT=y +CONFIG_UNITY_ENABLE_DOUBLE=y +# CONFIG_UNITY_ENABLE_64BIT is not set +# CONFIG_UNITY_ENABLE_COLOR is not set +CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +# CONFIG_UNITY_ENABLE_FIXTURE is not set +# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set +# end of Unity unit testing library + +# +# USB-OTG +# +CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE=256 +CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED=y +# CONFIG_USB_HOST_HW_BUFFER_BIAS_IN is not set +# CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT is not set + +# +# Hub Driver Configuration +# + +# +# Root Port configuration +# +CONFIG_USB_HOST_DEBOUNCE_DELAY_MS=250 +CONFIG_USB_HOST_RESET_HOLD_MS=30 +CONFIG_USB_HOST_RESET_RECOVERY_MS=30 +CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS=10 +# end of Root Port configuration + +# CONFIG_USB_HOST_HUBS_SUPPORTED is not set +# end of Hub Driver Configuration + +# CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK is not set +CONFIG_USB_OTG_SUPPORTED=y +# end of USB-OTG + +# +# Virtual file system +# +CONFIG_VFS_SUPPORT_IO=y +CONFIG_VFS_SUPPORT_DIR=y +CONFIG_VFS_SUPPORT_SELECT=y +CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +# CONFIG_VFS_SELECT_IN_RAM is not set +CONFIG_VFS_SUPPORT_TERMIOS=y +CONFIG_VFS_MAX_COUNT=8 + +# +# Host File System I/O (Semihosting) +# +CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# end of Host File System I/O (Semihosting) + +CONFIG_VFS_INITIALIZE_DEV_NULL=y +# end of Virtual file system + +# +# Wear Levelling +# +# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_4096=y +CONFIG_WL_SECTOR_SIZE=4096 +# end of Wear Levelling + +# +# Wi-Fi Provisioning Manager +# +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +# CONFIG_WIFI_PROV_BLE_BONDING is not set +CONFIG_WIFI_PROV_BLE_SEC_CONN=y +# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set +# CONFIG_WIFI_PROV_BLE_NOTIFY is not set +# CONFIG_WIFI_PROV_KEEP_BLE_ON_AFTER_PROV is not set +CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y +# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set +# end of Wi-Fi Provisioning Manager + +# +# KTag SystemK +# +CONFIG_KTAG_N_NEOPIXEL_CHANNELS=4 +CONFIG_KTAG_MAX_NEOPIXELS_PER_CHANNEL=8 +CONFIG_KTAG_ANIMATION_STEP_TIME_IN_ms=10 +CONFIG_KTAG_T_DEFAULT_START_GAME_in_ms=30000 +CONFIG_KTAG_MAX_AUDIO_VOLUME=100 +CONFIG_KTAG_MIN_AUDIO_VOLUME=0 +# end of KTag SystemK + +# +# Audio playback +# +CONFIG_AUDIO_PLAYER_ENABLE_MP3=y +CONFIG_AUDIO_PLAYER_ENABLE_WAV=y +CONFIG_AUDIO_PLAYER_LOG_LEVEL=0 +# end of Audio playback + +# +# IoT Button +# +CONFIG_BUTTON_PERIOD_TIME_MS=5 +CONFIG_BUTTON_DEBOUNCE_TICKS=2 +CONFIG_BUTTON_SHORT_PRESS_TIME_MS=180 +CONFIG_BUTTON_LONG_PRESS_TIME_MS=1500 +CONFIG_BUTTON_SERIAL_TIME_MS=20 +# CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE is not set +CONFIG_ADC_BUTTON_MAX_CHANNEL=3 +CONFIG_ADC_BUTTON_MAX_BUTTON_PER_CHANNEL=8 +CONFIG_ADC_BUTTON_SAMPLE_TIMES=1 +# end of IoT Button + +# +# CMake Utilities +# +# CONFIG_CU_RELINKER_ENABLE is not set +# CONFIG_CU_DIAGNOSTICS_COLOR_NEVER is not set +CONFIG_CU_DIAGNOSTICS_COLOR_ALWAYS=y +# CONFIG_CU_DIAGNOSTICS_COLOR_AUTO is not set +# CONFIG_CU_GCC_LTO_ENABLE is not set +# CONFIG_CU_GCC_STRING_1BYTE_ALIGN is not set +# end of CMake Utilities + +# +# mDNS +# +CONFIG_MDNS_MAX_INTERFACES=3 +CONFIG_MDNS_MAX_SERVICES=10 +CONFIG_MDNS_TASK_PRIORITY=1 +CONFIG_MDNS_ACTION_QUEUE_LEN=16 +CONFIG_MDNS_TASK_STACK_SIZE=4096 +# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_MDNS_TASK_AFFINITY_CPU0=y +# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set +CONFIG_MDNS_TASK_AFFINITY=0x0 +CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 +CONFIG_MDNS_TIMER_PERIOD_MS=100 +# CONFIG_MDNS_NETWORKING_SOCKET is not set +# CONFIG_MDNS_SKIP_SUPPRESSING_OWN_QUERIES is not set +# CONFIG_MDNS_ENABLE_DEBUG_PRINTS is not set +CONFIG_MDNS_ENABLE_CONSOLE_CLI=y +# CONFIG_MDNS_RESPOND_REVERSE_QUERIES is not set +CONFIG_MDNS_MULTIPLE_INSTANCE=y + +# +# MDNS Predefined interfaces +# +CONFIG_MDNS_PREDEF_NETIF_STA=y +CONFIG_MDNS_PREDEF_NETIF_AP=y +CONFIG_MDNS_PREDEF_NETIF_ETH=y +# end of MDNS Predefined interfaces +# end of mDNS +# end of Component config + +# CONFIG_IDF_EXPERIMENTAL_FEATURES is not set + +# Deprecated options for backward compatibility +# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set +# CONFIG_NO_BLOBS is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set +CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set +# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL=3 +# CONFIG_APP_ROLLBACK_ENABLE is not set +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_FLASHMODE_QIO is not set +# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_DIO=y +# CONFIG_FLASHMODE_DOUT is not set +CONFIG_MONITOR_BAUD=115200 +# CONFIG_OPTIMIZATION_LEVEL_DEBUG is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set +# CONFIG_COMPILER_OPTIMIZATION_DEFAULT is not set +# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set +# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set +# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2 +# CONFIG_CXX_EXCEPTIONS is not set +CONFIG_STACK_CHECK_NONE=y +# CONFIG_STACK_CHECK_NORM is not set +# CONFIG_STACK_CHECK_STRONG is not set +# CONFIG_STACK_CHECK_ALL is not set +# CONFIG_WARN_WRITE_STRINGS is not set +# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_NONE=y +CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y +# CONFIG_BLUEDROID_ENABLED is not set +CONFIG_NIMBLE_ENABLED=y +CONFIG_NIMBLE_MEM_ALLOC_MODE_INTERNAL=y +# CONFIG_NIMBLE_MEM_ALLOC_MODE_EXTERNAL is not set +# CONFIG_NIMBLE_MEM_ALLOC_MODE_DEFAULT is not set +CONFIG_NIMBLE_MAX_CONNECTIONS=3 +CONFIG_NIMBLE_MAX_BONDS=3 +CONFIG_NIMBLE_MAX_CCCDS=8 +CONFIG_NIMBLE_L2CAP_COC_MAX_NUM=0 +CONFIG_NIMBLE_PINNED_TO_CORE_0=y +# CONFIG_NIMBLE_PINNED_TO_CORE_1 is not set +CONFIG_NIMBLE_PINNED_TO_CORE=0 +CONFIG_NIMBLE_TASK_STACK_SIZE=4096 +CONFIG_BT_NIMBLE_TASK_STACK_SIZE=4096 +CONFIG_NIMBLE_ROLE_CENTRAL=y +CONFIG_NIMBLE_ROLE_PERIPHERAL=y +CONFIG_NIMBLE_ROLE_BROADCASTER=y +CONFIG_NIMBLE_ROLE_OBSERVER=y +CONFIG_NIMBLE_NVS_PERSIST=y +CONFIG_NIMBLE_SM_LEGACY=y +CONFIG_NIMBLE_SM_SC=y +# CONFIG_NIMBLE_SM_SC_DEBUG_KEYS is not set +CONFIG_BT_NIMBLE_SM_SC_LVL=0 +# CONFIG_NIMBLE_DEBUG is not set +CONFIG_NIMBLE_SVC_GAP_DEVICE_NAME="KTag 32ESPecial" +CONFIG_NIMBLE_GAP_DEVICE_NAME_MAX_LEN=31 +CONFIG_NIMBLE_ATT_PREFERRED_MTU=256 +CONFIG_NIMBLE_SVC_GAP_APPEARANCE=0 +CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT=12 +CONFIG_BT_NIMBLE_ACL_BUF_COUNT=24 +CONFIG_BT_NIMBLE_ACL_BUF_SIZE=255 +CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 +CONFIG_BT_NIMBLE_HCI_EVT_HI_BUF_COUNT=30 +CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT=8 +# CONFIG_NIMBLE_HS_FLOW_CTRL is not set +CONFIG_NIMBLE_RPA_TIMEOUT=900 +# CONFIG_NIMBLE_MESH is not set +CONFIG_NIMBLE_CRYPTO_STACK_MBEDTLS=y +# CONFIG_BT_NIMBLE_COEX_PHY_CODED_TX_RX_TLIM_EN is not set +CONFIG_BT_NIMBLE_COEX_PHY_CODED_TX_RX_TLIM_DIS=y +CONFIG_SW_COEXIST_ENABLE=y +CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y +CONFIG_ESP_WIFI_SW_COEXIST_ENABLE=y +# CONFIG_MCPWM_ISR_IN_IRAM is not set +# CONFIG_EVENT_LOOP_PROFILING is not set +CONFIG_POST_EVENTS_FROM_ISR=y +CONFIG_POST_EVENTS_FROM_IRAM_ISR=y +CONFIG_GDBSTUB_SUPPORT_TASKS=y +CONFIG_GDBSTUB_MAX_TASKS=32 +# CONFIG_OTA_ALLOW_HTTP is not set +CONFIG_ESP32S3_DEEP_SLEEP_WAKEUP_DELAY=2000 +CONFIG_ESP_SLEEP_DEEP_SLEEP_WAKEUP_DELAY=2000 +CONFIG_ESP32S3_RTC_CLK_SRC_INT_RC=y +# CONFIG_ESP32S3_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32S3_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32S3_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_ESP32S3_RTC_CLK_CAL_CYCLES=1024 +CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y +# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 +CONFIG_ESP32_PHY_MAX_TX_POWER=20 +# CONFIG_REDUCE_PHY_TX_POWER is not set +# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set +# CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU is not set +CONFIG_ESP32S3_SPIRAM_SUPPORT=y +CONFIG_DEFAULT_PSRAM_CLK_IO=30 +CONFIG_DEFAULT_PSRAM_CS_IO=26 +# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_80 is not set +# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160 is not set +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y +CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=240 +CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_CONSOLE_UART_DEFAULT=y +# CONFIG_CONSOLE_UART_CUSTOM is not set +# CONFIG_CONSOLE_UART_NONE is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART=y +CONFIG_CONSOLE_UART_NUM=0 +CONFIG_CONSOLE_UART_BAUDRATE=115200 +CONFIG_INT_WDT=y +CONFIG_INT_WDT_TIMEOUT_MS=5000 +CONFIG_INT_WDT_CHECK_CPU1=y +CONFIG_TASK_WDT=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_TASK_WDT_PANIC is not set +CONFIG_TASK_WDT_TIMEOUT_S=5 +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set +CONFIG_ESP32S3_DEBUG_OCDAWARE=y +CONFIG_BROWNOUT_DET=y +CONFIG_ESP32S3_BROWNOUT_DET=y +CONFIG_ESP32S3_BROWNOUT_DET=y +CONFIG_BROWNOUT_DET_LVL_SEL_7=y +CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_7=y +# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_1 is not set +CONFIG_BROWNOUT_DET_LVL=7 +CONFIG_ESP32S3_BROWNOUT_DET_LVL=7 +CONFIG_IPC_TASK_STACK_SIZE=1280 +CONFIG_TIMER_TASK_STACK_SIZE=3584 +CONFIG_ESP32_WIFI_ENABLED=y +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 +CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32 +# CONFIG_ESP32_WIFI_CSI_ENABLED is not set +CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y +CONFIG_ESP32_WIFI_TX_BA_WIN=6 +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +CONFIG_ESP32_WIFI_RX_BA_WIN=6 +# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set +CONFIG_ESP32_WIFI_NVS_ENABLED=y +CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y +# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set +CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 +CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 +CONFIG_ESP32_WIFI_IRAM_OPT=y +CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y +CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y +CONFIG_WPA_MBEDTLS_CRYPTO=y +# CONFIG_WPA_WAPI_PSK is not set +# CONFIG_WPA_SUITE_B_192 is not set +# CONFIG_WPA_11KV_SUPPORT is not set +# CONFIG_WPA_MBO_SUPPORT is not set +# CONFIG_WPA_DPP_SUPPORT is not set +# CONFIG_WPA_11R_SUPPORT is not set +# CONFIG_WPA_WPS_SOFTAP_REGISTRAR is not set +# CONFIG_WPA_WPS_STRICT is not set +# CONFIG_WPA_DEBUG_PRINT is not set +# CONFIG_WPA_TESTING_OPTIONS is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH=y +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE is not set +# CONFIG_ESP32_COREDUMP_DATA_FORMAT_BIN is not set +CONFIG_ESP32_COREDUMP_DATA_FORMAT_ELF=y +CONFIG_ESP32_COREDUMP_CHECKSUM_CRC32=y +# CONFIG_ESP32_COREDUMP_CHECKSUM_SHA256 is not set +CONFIG_ESP32_ENABLE_COREDUMP=y +CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM=64 +CONFIG_ESP32_CORE_DUMP_STACK_SIZE=1792 +CONFIG_TIMER_TASK_PRIORITY=1 +CONFIG_TIMER_TASK_STACK_DEPTH=4096 +CONFIG_TIMER_QUEUE_LENGTH=10 +# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set +CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y +# CONFIG_HAL_ASSERTION_SILIENT is not set +# CONFIG_L2_TO_L3_COPY is not set +CONFIG_ESP_GRATUITOUS_ARP=y +CONFIG_GARP_TMR_INTERVAL=60 +CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_TCP_MAXRTX=12 +CONFIG_TCP_SYNMAXRTX=12 +CONFIG_TCP_MSS=1440 +CONFIG_TCP_MSL=60000 +CONFIG_TCP_SND_BUF_DEFAULT=5744 +CONFIG_TCP_WND_DEFAULT=5744 +CONFIG_TCP_RECVMBOX_SIZE=6 +CONFIG_TCP_QUEUE_OOSEQ=y +CONFIG_TCP_OVERSIZE_MSS=y +# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set +# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_UDP_RECVMBOX_SIZE=6 +CONFIG_TCPIP_TASK_STACK_SIZE=3072 +CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y +# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set +# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set +CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF +# CONFIG_PPP_SUPPORT is not set +CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC_SYSTIMER=y +CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC_FRC1=y +# CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32S3_TIME_SYSCALL_USE_SYSTIMER is not set +# CONFIG_ESP32S3_TIME_SYSCALL_USE_FRC1 is not set +# CONFIG_ESP32S3_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 +CONFIG_ESP32_PTHREAD_STACK_MIN=768 +CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set +# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set +CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 +CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" +CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set +# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set +CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +CONFIG_SUPPORT_TERMIOS=y +CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 +# End of deprecated options diff --git a/spiffs_image/KTagInitialized.mp3 b/spiffs_image/KTagInitialized.mp3 new file mode 100644 index 0000000..54f1a2f Binary files /dev/null and b/spiffs_image/KTagInitialized.mp3 differ diff --git a/spiffs_image/bad.wav b/spiffs_image/bad.wav new file mode 100644 index 0000000..d3158ad Binary files /dev/null and b/spiffs_image/bad.wav differ diff --git a/spiffs_image/boot_message.txt b/spiffs_image/boot_message.txt new file mode 100644 index 0000000..4966100 --- /dev/null +++ b/spiffs_image/boot_message.txt @@ -0,0 +1 @@ +Welcome to KTag! SPIFFS version 00.37 \ No newline at end of file diff --git a/spiffs_image/default_config.txt b/spiffs_image/default_config.txt new file mode 100644 index 0000000..03a2c0a --- /dev/null +++ b/spiffs_image/default_config.txt @@ -0,0 +1,27 @@ +; Example configuration file for the KTag 2024A. +; +; 🛡️ 🃞 + +; Metadata +Config_Version=1 +Model=2024A + +; Game Settings +Player_ID=1 +Team_ID=1 +Weapon_ID=10 + +; Hardware Settings +Is_Right_Handed=1 +Audio_Volume=30 +T_Start_Game_in_ms=30000 + +; WiFi +; SSID and password of the network this device should connect to when it is in range. +STA_SSID= +STA_Password= + +; SSID and password that can be used to connect to this device, if the above network is not detected. +AP_SSID= +AP_Password= + diff --git a/spiffs_image/good.wav b/spiffs_image/good.wav new file mode 100644 index 0000000..682acfa Binary files /dev/null and b/spiffs_image/good.wav differ