Загрузка данных


static volatile bool is_switching_audio = false;

static void update_device_pointers(uint8_t change_audio)
{
    if(change_audio)
    {
        if(current_audio_path == AUDIO_PATH_0)
        {
            current_audio_path = AUDIO_PATH_1;
            printf("Switching audio to SAI1 (PATH1) on the fly...\n");
        }
        else
        {
            current_audio_path = AUDIO_PATH_0;
            printf("Switching audio to SAI3 (PATH0) on the fly...\n");
        }
    }

    if (current_audio_path == AUDIO_PATH_1) {
        i2s_dev_rx = DEVICE_DT_GET(DT_NODELABEL(i2s1_rx));
        i2s_dev_tx = DEVICE_DT_GET(DT_NODELABEL(i2s1_tx));
        codec_dev  = DEVICE_DT_GET(DT_NODELABEL(rx_audio_codec));
        rx_tx_is_slave = 0;
        codec_is_slave = 1;
    } else {
        i2s_dev_rx = DEVICE_DT_GET(DT_NODELABEL(i2s0_rx));
        i2s_dev_tx = DEVICE_DT_GET(DT_NODELABEL(i2s0_tx));
        codec_dev  = DEVICE_DT_GET(DT_NODELABEL(audio_codec));
        rx_tx_is_slave = 0;
        codec_is_slave = 1;
    }
}    while (1)
    {
        if(!start_stream || is_switching_audio) { // <-- Добавлена проверка флага
            k_sleep(K_MSEC(5));
        }
        else
        {
            ret = i2s_buf_read(i2s_dev_rx, buf, &block_size);
            // ... (остальной код функции без изменений) ...    while (1)
    {
        if(!start_stream || is_switching_audio) { // <-- Добавлена проверка флага
            k_sleep(K_MSEC(5));
        }
        else
        {
            ret = i2s_buf_write(i2s_dev_tx, buf, i2s_stream->block_size);
            // ... (остальной код функции без изменений) ...

void zephyr_change_audio_runtime(void)
{
    // Если стрим закрыт, делаем обычную холодную смену указателей
    if (close_stream == 1) {
        update_device_pointers(1);
        return;
    }

    printf("--- RUNTIME AUDIO SWITCH START ---\n");
    
    // 1. Ставим потоки чтения/записи на паузу
    is_switching_audio = true;
    k_sleep(K_MSEC(15)); // Даем время потокам завершить текущие операции I2S

    // 2. Останавливаем старые аппаратные интерфейсы Zephyr I2S
    // Отправляем команду DROP, чтобы сбросить очереди DMA старого устройства
    trigger_command(i2s_dev_rx, i2s_dev_tx, I2S_TRIGGER_DROP);

    // 3. Меняем указатели устройств на противоположный аудио-путь
    update_device_pointers(1);

    // 4. Проверяем готовность новых девайсов
    if (!device_is_ready(i2s_dev_rx) || !device_is_ready(i2s_dev_tx) || !device_is_ready(codec_dev)) {
        printf("Runtime Switch Error: New devices are not ready!\n");
        is_switching_audio = false; // Возвращаем потоки, чтобы система не зависла окончательно
        return;
    }

    // 5. Конфигурируем новый кодек
    struct audio_codec_cfg audio_cfg;
    audio_cfg.dai_route = AUDIO_ROUTE_PLAYBACK_CAPTURE;
    audio_cfg.dai_type = AUDIO_DAI_TYPE_I2S;
    audio_cfg.dai_cfg.i2s.word_size = SAMPLE_BIT_WIDTH;
    audio_cfg.dai_cfg.i2s.channels = NUMBER_OF_CHANNELS;
    audio_cfg.dai_cfg.i2s.format = I2S_FMT_DATA_FORMAT_I2S;
    audio_cfg.dai_cfg.i2s.options = codec_is_slave ? (I2S_OPT_FRAME_CLK_SLAVE | I2S_OPT_BIT_CLK_SLAVE) : I2S_OPT_FRAME_CLK_MASTER;
    audio_cfg.dai_cfg.i2s.frame_clk_freq = current_sample_rate;
    audio_cfg.dai_cfg.i2s.mem_slab = &mem_slab_tx;
    audio_cfg.dai_cfg.i2s.block_size = current_audio_block_size;
    audio_cfg.mclk_freq = AUDIO_MCLK_FREQ;
    
    audio_codec_configure(codec_dev, &audio_cfg);

    // 6. Конфигурируем новые I2S каналы Zephyr
    struct i2s_config config;
    config.word_size = SAMPLE_BIT_WIDTH;
    config.channels = NUMBER_OF_CHANNELS;
    config.format = I2S_FMT_DATA_FORMAT_I2S;
    config.options = rx_tx_is_slave ? (I2S_OPT_BIT_CLK_SLAVE | I2S_OPT_FRAME_CLK_SLAVE) : (I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER);
    config.frame_clk_freq = current_sample_rate;
    config.block_size = current_audio_block_size;
    config.timeout = TIMEOUT;

    if (!configure_streams(i2s_dev_rx, i2s_dev_tx, &config)) {
        printf("Runtime Switch Error: Failed to configure new I2S streams\n");
        is_switching_audio = false;
        return;
    }

    // Настраиваем громкость и включаем выход нового кодека
    audio_property_value_t vol_val = { .vol = 100 };
    audio_codec_set_property(codec_dev, AUDIO_PROPERTY_OUTPUT_VOLUME, AUDIO_CHANNEL_ALL, vol_val);
    vol_val.vol = 0;
    audio_codec_set_property(codec_dev, AUDIO_PROPERTY_INPUT_VOLUME, AUDIO_CHANNEL_ALL, vol_val);
    audio_property_value_t mute_val = { .mute = false };
    audio_codec_set_property(codec_dev, AUDIO_PROPERTY_OUTPUT_MUTE, AUDIO_CHANNEL_ALL, mute_val);
    audio_codec_set_property(codec_dev, AUDIO_PROPERTY_INPUT_MUTE, AUDIO_CHANNEL_ALL, mute_val);
    
    audio_codec_start_output(codec_dev);

    // 7. Готовим буферы отправки (TX blocks) для нового I2S
    prepare_transfer(i2s_dev_tx);

    // 8. Физически запускаем новые I2S шины контроллера
    trigger_command(i2s_dev_rx, i2s_dev_tx, I2S_TRIGGER_START);

    // 9. Снимаем потоки чтения/записи с паузы
    is_switching_audio = false;

    printf("--- RUNTIME AUDIO SWITCH SUCCESSFUL ---\n");
}