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


#include <stdio.h>
#include <string.h>
#include <portaudio.h>
#include <audio_dev.h>
#include <pthread.h>
#include <zephyr_i2s_dev.h>
#include <zephyr_audio_dev.h>

#include <zephyr/kernel.h>
#include <zephyr/drivers/i2s.h>
#include <zephyr/audio/codec.h>

#if DT_NODE_EXISTS(DT_NODELABEL(i2s_rxtx))
#define I2S_RX_NODE  DT_NODELABEL(i2s_rxtx)
#define I2S_TX_NODE  I2S_RX_NODE
#else
#define I2S_RX_NODE  DT_NODELABEL(i2s0_rx)
#define I2S_TX_NODE  DT_NODELABEL(i2s0_tx)
#endif

#define AUDIO_MCLK_FREQ 12288000
#define TIMEOUT             1000

#ifndef MY_CODE
#define I2S_THREAD_PRIORITY 8
#else
#define I2S_THREAD_PRIORITY 12
#endif

/* !!! DYNAMIC RATE CHANGE: Выделяем память Слэбов по МАКСИМАЛЬНОМУ размеру блока */
#ifdef MY_CODE
K_MEM_SLAB_DEFINE_IN_SECT_STATIC(mem_slab_rx, __dtcm_noinit_section, MAX_ZEPHYR_AUDIO_BLOCK_SIZE, ZEPHYR_AUDIO_BLOCK_COUNT, 4);
K_MEM_SLAB_DEFINE_IN_SECT_STATIC(mem_slab_tx, __dtcm_noinit_section, MAX_ZEPHYR_AUDIO_BLOCK_SIZE, ZEPHYR_AUDIO_BLOCK_COUNT, 4);
#else
K_MEM_SLAB_DEFINE(mem_slab_rx, MAX_ZEPHYR_AUDIO_BLOCK_SIZE, ZEPHYR_AUDIO_BLOCK_COUNT, 4);
K_MEM_SLAB_DEFINE(mem_slab_tx, MAX_ZEPHYR_AUDIO_BLOCK_SIZE, ZEPHYR_AUDIO_BLOCK_COUNT, 4);
#endif

static const struct device *const i2s_dev_rx = DEVICE_DT_GET(I2S_RX_NODE);
static const struct device *const i2s_dev_tx = DEVICE_DT_GET(I2S_TX_NODE);
static const struct device *const codec_dev  = DEVICE_DT_GET(DT_NODELABEL(audio_codec));

static uint8_t start_stream = 0;
/* Храним текущий рабочий размер блока глобально или внутри структуры, 
   чтобы prepare_transfer знал сколько писать */
static uint32_t current_audio_block_size = ((16000 / 10) * NUMBER_OF_CHANNELS * BYTES_PER_SAMPLE); 

enum zephyr_i2s_state {
    I2S_STREAM_RUNNING,
    I2S_STREAM_CLOSED
};

struct i2s_strm {
    uint8_t alloc;
    uint8_t devid;
    uint8_t *i2s_buf;
    pthread_t i2s_thread;
    pthread_attr_t  threadAttr;
    enum zephyr_i2s_state state;
    /* !!! DYNAMIC RATE CHANGE: Добавляем параметры внутрь контекста стрима */
    uint32_t sample_rate;
    uint32_t block_size;
};

#define MODOPS_I2S_STREAM_COUNT 2
static struct i2s_strm i2s_strm_pool[MODOPS_I2S_STREAM_COUNT] = {0};

static struct i2s_strm *i2s_str_alloc()
{
    struct i2s_strm *i2s_strm_ = NULL;
    for(uint8_t i=0; i < MODOPS_I2S_STREAM_COUNT; i++)
    {
        if(i2s_strm_pool[i].alloc == 0)
        {
            i2s_strm_ = &i2s_strm_pool[i];
            i2s_strm_pool[i].alloc = 1;
            break;
        }
    }
    return i2s_strm_;
}

static void i2s_str_free(struct i2s_strm *i2s_strm_)
{
    if(!i2s_strm_) return;
    for(uint8_t i=0; i < MODOPS_I2S_STREAM_COUNT; i++)
    {
        if(i2s_strm_pool[i].devid == i2s_strm_->devid)
        {
            i2s_strm_pool[i].alloc = 0;
            break;
        }
    }
}

static void i2s_thread_wakeup(struct i2s_strm *strm, enum zephyr_i2s_state state)
{
    if(!strm) return;
    strm->state = state;
}

static void *i2s_thread_in(void *arg)
{
    struct i2s_strm *i2s_stream = (struct i2s_strm *) arg;
    uint32_t block_size;
    uint8_t *buf = NULL;
    uint8_t half_transfer = 1;
    int ret;

    buf = i2s_stream->i2s_buf;
    while (1)
    {
        if(!start_stream) {
            k_sleep(K_MSEC(10));
        }
        else
        {
            ret = i2s_buf_read(i2s_dev_rx, buf, &block_size);
            if (ret < 0) {
                printf("I2S_IN: Failed to read data: %d\n", ret);
            }
            else
            {
                /* !!! DYNAMIC RATE CHANGE: Шагаем по динамическому block_size вместо макроса */
                if(half_transfer)
                {
                    BSP_AUDIO_IN_HalfTransfer_CallBack();
                    buf += i2s_stream->block_size;
                    half_transfer = 0;
                }
                else
                {
                    BSP_AUDIO_IN_TransferComplete_CallBack();
                    buf = i2s_stream->i2s_buf;
                    half_transfer = 1;
                }
            }
        }
        if (i2s_stream->state != I2S_STREAM_RUNNING) {
            printf("Exit i2s_in_thread\n");
            break;
        }
    }
    return NULL;
}

static void *i2s_thread_out(void *arg)
{
    struct i2s_strm *i2s_stream = (struct i2s_strm *) arg;
    uint8_t *buf = NULL;
    uint8_t half_transfer = 1;
    int ret;

    buf = i2s_stream->i2s_buf;
    while (1)
    {
        if(!start_stream) {
            k_sleep(K_MSEC(10));
        }
        else
        {
            /* !!! DYNAMIC RATE CHANGE: Пишем динамический block_size */
            ret = i2s_buf_write(i2s_dev_tx, buf, i2s_stream->block_size);
            if (ret < 0) {
                printf("I2S_OUT: Failed to write data: %d\n", ret);
            }
            else
            {
                if(half_transfer)
                {
                    BSP_AUDIO_OUT_HalfTransfer_CallBack();
                    buf += i2s_stream->block_size;
                    half_transfer = 0;
                }
                else
                {
                    BSP_AUDIO_OUT_TransferComplete_CallBack();
                    buf = i2s_stream->i2s_buf;
                    half_transfer = 1;
                }
            }
        }
        if (i2s_stream->state != I2S_STREAM_RUNNING) {
            printf("Exit i2s_out_thread\n");
            break;
        }
    }
    return NULL;
}

static bool configure_streams(const struct device *i2s_dev_rx,
                              const struct device *i2s_dev_tx,
                              const struct i2s_config *base_config)
{
    int ret;
    struct i2s_config config = *base_config;

    config.mem_slab = &mem_slab_rx;
    ret = i2s_configure(i2s_dev_rx, I2S_DIR_RX, &config);
    if (ret < 0) {
        printf("Failed to configure RX: %d\n", ret);
        return false;
    }

    config.mem_slab = &mem_slab_tx;
    ret = i2s_configure(i2s_dev_tx, I2S_DIR_TX, &config);
    if (ret < 0) {
        printf("Failed to configure TX: %d\n", ret);
        return false;
    }

    return true;
}

static bool prepare_transfer(const struct device *i2s_dev_tx)
{
    int ret;
    for (int i = 0; i < ZEPHYR_AUDIO_INITIAL_BLOCKS; ++i)
    {
        void *mem_block;
        ret = k_mem_slab_alloc(&mem_slab_tx, &mem_block, K_NO_WAIT);
        if (ret < 0) {
            printf("Failed to allocate TX block %d: %d\n", i, ret);
            return false;
        }

        /* !!! DYNAMIC RATE CHANGE: Используем текущий динамический размер */
        memset(mem_block, 0, current_audio_block_size);

        ret = i2s_write(i2s_dev_tx, mem_block, current_audio_block_size);
        if (ret < 0) {
            printf("Failed to write block %d: %d\n", i, ret);
            return false;
        }
    }
    return true;
}

static bool trigger_command(const struct device *i2s_dev_rx,
                            const struct device *i2s_dev_tx,
                            enum i2s_trigger_cmd cmd)
{
    int ret;
    if (i2s_dev_rx == i2s_dev_tx) {
        ret = i2s_trigger(i2s_dev_rx, I2S_DIR_BOTH, cmd);
        if (ret == 0) return true;
        if (ret != -ENOSYS) {
            printf("Failed to trigger command %d: %d\n", cmd, ret);
            return false;
        }
    }

    ret = i2s_trigger(i2s_dev_rx, I2S_DIR_RX, cmd);
    if (ret < 0) {
        printf("Failed to trigger command %d on RX: %d\n", cmd, ret);
        return false;
    }