Skip to content

Commit ffebb32

Browse files
committed
Merge branch 'feat/add_callback_to_switch_buffer_in_parlio_tx' into 'master'
feat(parlio_tx): support buffer switched callback Closes IDF-12903 See merge request espressif/esp-idf!39692
2 parents d2b6f83 + 05c2ebc commit ffebb32

File tree

12 files changed

+231
-55
lines changed

12 files changed

+231
-55
lines changed

components/esp_driver_parlio/include/driver/parlio_tx.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ esp_err_t parlio_tx_unit_disable(parlio_tx_unit_handle_t unit);
115115
*/
116116
typedef struct {
117117
parlio_tx_done_callback_t on_trans_done; /*!< Event callback, invoked when one transmission is finished */
118+
parlio_tx_buffer_switched_callback_t on_buffer_switched; /*!< Event callback, invoked when the buffer is switched in loop transmission */
118119
} parlio_tx_event_callbacks_t;
119120

120121
/**

components/esp_driver_parlio/include/driver/parlio_types.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ typedef struct parlio_rx_delimiter_t *parlio_rx_delimiter_handle_t;
3737
typedef struct {
3838
} parlio_tx_done_event_data_t;
3939

40+
/**
41+
* @brief Type of Parallel IO TX buffer switched event data
42+
*/
43+
typedef struct {
44+
void *old_buffer_addr; /*!< Address of the previous buffer used before switching */
45+
void *new_buffer_addr; /*!< Address of the new buffer switched to */
46+
} parlio_tx_buffer_switched_event_data_t;
47+
4048
/**
4149
* @brief Prototype of parlio tx event callback
4250
* @param[in] tx_unit Parallel IO TX unit that created by `parlio_new_tx_unit`
@@ -48,6 +56,17 @@ typedef struct {
4856
*/
4957
typedef bool (*parlio_tx_done_callback_t)(parlio_tx_unit_handle_t tx_unit, const parlio_tx_done_event_data_t *edata, void *user_ctx);
5058

59+
/**
60+
* @brief Prototype of parlio tx buffer switched event callback
61+
* @param[in] tx_unit Parallel IO TX unit that created by `parlio_new_tx_unit`
62+
* @param[in] edata Point to Parallel IO TX event data. The lifecycle of this pointer memory is inside this function,
63+
* user should copy it into static memory if used outside this function.
64+
* @param[in] user_ctx User registered context, passed from `parlio_tx_unit_register_event_callbacks`
65+
*
66+
* @return Whether a high priority task has been waken up by this callback function
67+
*/
68+
typedef bool (*parlio_tx_buffer_switched_callback_t)(parlio_tx_unit_handle_t tx_unit, const parlio_tx_buffer_switched_event_data_t *edata, void *user_ctx);
69+
5170
#ifdef __cplusplus
5271
}
5372
#endif

components/esp_driver_parlio/linker.lf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ entries:
55
parlio_tx: parlio_tx_default_isr (noflash)
66
parlio_tx: parlio_tx_do_transaction (noflash)
77
parlio_tx: parlio_mount_buffer (noflash)
8+
9+
if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION = y:
10+
parlio_tx: parlio_tx_gdma_eof_callback (noflash)
11+
812
if PARLIO_RX_ISR_HANDLER_IN_IRAM = y:
913
parlio_rx: parlio_rx_default_eof_callback (noflash)
1014
parlio_rx: parlio_rx_default_desc_done_callback (noflash)
@@ -18,3 +22,6 @@ entries:
1822
gdma_link: gdma_link_mount_buffers (noflash)
1923
gdma_link: gdma_link_concat (noflash)
2024
gdma_link: gdma_link_get_head_addr (noflash)
25+
26+
if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION = y:
27+
gdma_link: gdma_link_get_buffer (noflash)

components/esp_driver_parlio/src/parlio_priv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,9 @@ typedef struct parlio_tx_unit_t {
187187
parlio_tx_trans_desc_t *cur_trans; // points to current transaction
188188
uint32_t idle_value_mask; // mask of idle value
189189
_Atomic parlio_tx_fsm_t fsm; // Driver FSM state
190+
_Atomic bool buffer_need_switch; // whether the buffer need to be switched
190191
parlio_tx_done_callback_t on_trans_done; // callback function when the transmission is done
192+
parlio_tx_buffer_switched_callback_t on_buffer_switched; // callback function when the buffer is switched in loop transmission
191193
void *user_data; // user data passed to the callback function
192194
bitscrambler_handle_t bs_handle; // bitscrambler handle
193195
parlio_tx_bs_enable_fn_t bs_enable_fn; // bitscrambler enable function

components/esp_driver_parlio/src/parlio_tx.c

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
#include "driver/parlio_tx.h"
1111
#include "parlio_priv.h"
1212

13+
#if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
14+
static bool parlio_tx_gdma_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
15+
#endif
1316
static void parlio_tx_default_isr(void *args);
1417

1518
static esp_err_t parlio_tx_create_trans_queue(parlio_tx_unit_t *tx_unit, const parlio_tx_unit_config_t *config)
@@ -342,14 +345,6 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
342345
// set sample clock edge
343346
parlio_ll_tx_set_sample_clock_edge(hal->regs, config->sample_edge);
344347

345-
#if SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
346-
// always use DMA EOF as the Parlio TX EOF if supported
347-
parlio_ll_tx_set_eof_condition(hal->regs, PARLIO_LL_TX_EOF_COND_DMA_EOF);
348-
#else
349-
// In default, use DATA LEN EOF as the Parlio TX EOF
350-
parlio_ll_tx_set_eof_condition(hal->regs, PARLIO_LL_TX_EOF_COND_DATA_LEN);
351-
#endif // SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
352-
353348
// clear any pending interrupt
354349
parlio_ll_clear_interrupt_status(hal->regs, PARLIO_LL_EVENT_TX_MASK);
355350

@@ -364,6 +359,7 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
364359

365360
portMUX_INITIALIZE(&unit->spinlock);
366361
atomic_init(&unit->fsm, PARLIO_TX_FSM_INIT);
362+
atomic_init(&unit->buffer_need_switch, false);
367363
// return TX unit handle
368364
*ret_unit = unit;
369365
ESP_LOGD(TAG, "new tx unit(%d,%d) at %p, out clk=%"PRIu32"Hz, queue_depth=%zu, idle_mask=%"PRIx32,
@@ -426,12 +422,30 @@ esp_err_t parlio_tx_unit_register_event_callbacks(parlio_tx_unit_handle_t tx_uni
426422
if (cbs->on_trans_done) {
427423
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_done), ESP_ERR_INVALID_ARG, TAG, "on_trans_done callback not in IRAM");
428424
}
425+
if (cbs->on_buffer_switched) {
426+
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_buffer_switched), ESP_ERR_INVALID_ARG, TAG, "on_buffer_switched callback not in IRAM");
427+
}
429428
if (user_data) {
430429
ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
431430
}
432431
#endif
433432

433+
if (cbs->on_buffer_switched) {
434+
#if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
435+
// workaround for DIG-559
436+
ESP_RETURN_ON_FALSE(tx_unit->data_width > 1, ESP_ERR_NOT_SUPPORTED, TAG, "on_buffer_switched callback is not supported for 1-bit data width");
437+
438+
gdma_tx_event_callbacks_t gdma_cbs = {
439+
.on_trans_eof = parlio_tx_gdma_eof_callback,
440+
};
441+
ESP_RETURN_ON_ERROR(gdma_register_tx_event_callbacks(tx_unit->dma_chan, &gdma_cbs, tx_unit), TAG, "install DMA callback failed");
442+
#else
443+
ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "on_buffer_switched callback is not supported");
444+
#endif
445+
}
446+
434447
tx_unit->on_trans_done = cbs->on_trans_done;
448+
tx_unit->on_buffer_switched = cbs->on_buffer_switched;
435449
tx_unit->user_data = user_data;
436450
return ESP_OK;
437451
}
@@ -443,8 +457,8 @@ static void parlio_mount_buffer(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_
443457
.buffer = (void *)t->payload,
444458
.length = (t->payload_bits + 7) / 8,
445459
.flags = {
446-
// if transmission is loop, we don't need to generate the EOF, as well as the final mark
447-
.mark_eof = !t->flags.loop_transmission,
460+
// if transmission is loop, we don't need to generate the EOF for 1-bit data width, DIG-559
461+
.mark_eof = tx_unit->data_width == 1 ? !t->flags.loop_transmission : true,
448462
.mark_final = !t->flags.loop_transmission,
449463
}
450464
};
@@ -462,13 +476,6 @@ static void parlio_mount_buffer(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_
462476
static void parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_t *t)
463477
{
464478
parlio_hal_context_t *hal = &tx_unit->base.group->hal;
465-
466-
if (t->flags.loop_transmission) {
467-
// Once a loop transmission is started, it cannot be stopped until it is disabled
468-
// If SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA is supported, setting the eof condition to PARLIO_LL_TX_EOF_COND_DMA_EOF again is harmless
469-
parlio_ll_tx_set_eof_condition(hal->regs, PARLIO_LL_TX_EOF_COND_DMA_EOF);
470-
}
471-
472479
tx_unit->cur_trans = t;
473480

474481
// If the external clock is a non-free-running clock, it needs to be switched to the internal free-running clock first.
@@ -497,7 +504,30 @@ static void parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio_tx_trans_
497504
// reset tx fifo after disabling tx core clk to avoid unexpected rempty interrupt
498505
parlio_ll_tx_reset_fifo(hal->regs);
499506
parlio_ll_tx_set_idle_data_value(hal->regs, t->idle_value);
500-
parlio_ll_tx_set_trans_bit_len(hal->regs, t->payload_bits);
507+
508+
// set EOF condition
509+
if (t->flags.loop_transmission) {
510+
if (tx_unit->data_width == 1) {
511+
// for 1-bit data width, we need to set the EOF condition to DMA EOF
512+
parlio_ll_tx_set_eof_condition(hal->regs, PARLIO_LL_TX_EOF_COND_DMA_EOF);
513+
} else {
514+
// for other data widths, we still use the data length EOF condition,
515+
// but let the `bit counter` + `data width` for each cycle is never equal to the configured bit lens.
516+
// Thus, we can skip the exact match, prevents EOF
517+
parlio_ll_tx_set_eof_condition(hal->regs, PARLIO_LL_TX_EOF_COND_DATA_LEN);
518+
parlio_ll_tx_set_trans_bit_len(hal->regs, 0x01);
519+
}
520+
} else {
521+
// non-loop transmission
522+
#if SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
523+
// for DMA EOF supported target, we need to set the EOF condition to DMA EOF
524+
parlio_ll_tx_set_eof_condition(hal->regs, PARLIO_LL_TX_EOF_COND_DMA_EOF);
525+
#else
526+
// for DMA EOF not supported target, we need to set the bit length to the configured bit lens
527+
parlio_ll_tx_set_eof_condition(hal->regs, PARLIO_LL_TX_EOF_COND_DATA_LEN);
528+
parlio_ll_tx_set_trans_bit_len(hal->regs, t->payload_bits);
529+
#endif // SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
530+
}
501531

502532
if (tx_unit->bs_handle) {
503533
// load the bitscrambler program and start it
@@ -592,12 +622,6 @@ esp_err_t parlio_tx_unit_disable(parlio_tx_unit_handle_t tx_unit)
592622
parlio_ll_tx_start(hal->regs, false);
593623
parlio_ll_enable_interrupt(hal->regs, PARLIO_LL_EVENT_TX_MASK, false);
594624

595-
#if !SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
596-
// Once a loop teansmission transaction is started, it can only be stopped in disable function
597-
// change the EOF condition to be the data length, so the EOF will be triggered normally in the following transaction
598-
parlio_ll_tx_set_eof_condition(hal->regs, PARLIO_LL_TX_EOF_COND_DATA_LEN);
599-
#endif // !SOC_PARLIO_TX_SUPPORT_EOF_FROM_DMA
600-
601625
#if CONFIG_PM_ENABLE
602626
// release power management lock
603627
if (tx_unit->pm_lock) {
@@ -622,7 +646,8 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
622646

623647
#if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
624648
if (config->flags.loop_transmission) {
625-
ESP_RETURN_ON_FALSE(parlio_ll_tx_support_dma_eof(NULL), ESP_ERR_NOT_SUPPORTED, TAG, "loop transmission is not supported by this chip revision");
649+
ESP_RETURN_ON_FALSE(parlio_ll_tx_support_dma_eof(NULL) || tx_unit->data_width > 1, ESP_ERR_NOT_SUPPORTED, TAG,
650+
"1-bit data width loop transmission is not supported by this chip revision");
626651
}
627652
#else
628653
ESP_RETURN_ON_FALSE(config->flags.loop_transmission == false, ESP_ERR_NOT_SUPPORTED, TAG, "loop transmission is not supported on this chip");
@@ -653,6 +678,7 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
653678
tx_unit->cur_trans->payload = payload;
654679
tx_unit->cur_trans->payload_bits = payload_bits;
655680
parlio_mount_buffer(tx_unit, tx_unit->cur_trans);
681+
atomic_store(&tx_unit->buffer_need_switch, true);
656682
} else {
657683
TickType_t queue_wait_ticks = portMAX_DELAY;
658684
if (config->flags.queue_nonblocking) {
@@ -701,6 +727,31 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
701727
return ESP_OK;
702728
}
703729

730+
#if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
731+
static bool parlio_tx_gdma_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
732+
{
733+
parlio_tx_unit_t *tx_unit = (parlio_tx_unit_t *) user_data;
734+
bool need_yield = false;
735+
bool expected_state = true;
736+
// invoke callback to notify the application
737+
parlio_tx_buffer_switched_callback_t on_buffer_switched = tx_unit->on_buffer_switched;
738+
if (on_buffer_switched) {
739+
if (atomic_compare_exchange_strong(&tx_unit->buffer_need_switch, &expected_state, false)) {
740+
parlio_tx_buffer_switched_event_data_t edata = {
741+
// we use 2 dma links to do the buffer switch in loop transmission
742+
.old_buffer_addr = gdma_link_get_buffer(tx_unit->dma_link[1 - tx_unit->cur_trans->dma_link_idx], 0),
743+
.new_buffer_addr = gdma_link_get_buffer(tx_unit->dma_link[tx_unit->cur_trans->dma_link_idx], 0),
744+
};
745+
if (on_buffer_switched(tx_unit, &edata, tx_unit->user_data)) {
746+
need_yield = true;
747+
}
748+
}
749+
}
750+
751+
return need_yield;
752+
}
753+
#endif // SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
754+
704755
static void parlio_tx_default_isr(void *args)
705756
{
706757
parlio_tx_unit_t *tx_unit = (parlio_tx_unit_t *)args;

components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,22 @@ TEST_CASE("parallel tx unit use external non-free running clock", "[parlio_tx]")
518518
};
519519

520520
#if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION
521+
typedef struct {
522+
uint32_t switch_count;
523+
void *old_buffer_addr[5];
524+
void *new_buffer_addr[5];
525+
} test_parlio_tx_buffer_switched_context_t;
526+
527+
TEST_PARLIO_CALLBACK_ATTR
528+
static bool test_parlio_tx_buffer_switched_callback(parlio_tx_unit_handle_t tx_unit, const parlio_tx_buffer_switched_event_data_t *edata, void *user_ctx)
529+
{
530+
test_parlio_tx_buffer_switched_context_t *context = (test_parlio_tx_buffer_switched_context_t *)user_ctx;
531+
context->old_buffer_addr[context->switch_count] = edata->old_buffer_addr;
532+
context->new_buffer_addr[context->switch_count] = edata->new_buffer_addr;
533+
context->switch_count++;
534+
return false;
535+
}
536+
521537
TEST_CASE("parlio_tx_loop_transmission", "[parlio_tx]")
522538
{
523539
printf("install parlio tx unit\r\n");
@@ -545,6 +561,16 @@ TEST_CASE("parlio_tx_loop_transmission", "[parlio_tx]")
545561
.sample_edge = PARLIO_SAMPLE_EDGE_POS,
546562
};
547563
TEST_ESP_OK(parlio_new_tx_unit(&config, &tx_unit));
564+
565+
printf("register trans_done event callback\r\n");
566+
parlio_tx_event_callbacks_t cbs = {
567+
.on_buffer_switched = test_parlio_tx_buffer_switched_callback,
568+
};
569+
test_parlio_tx_buffer_switched_context_t context = {
570+
.switch_count = 0,
571+
};
572+
TEST_ESP_OK(parlio_tx_unit_register_event_callbacks(tx_unit, &cbs, &context));
573+
548574
TEST_ESP_OK(parlio_tx_unit_enable(tx_unit));
549575

550576
printf("send packets and check event is fired\r\n");
@@ -560,37 +586,48 @@ TEST_CASE("parlio_tx_loop_transmission", "[parlio_tx]")
560586
payload_loop2[i] = 255 - i;
561587
payload_oneshot[i] = i * 2 + 1;
562588
}
563-
if (parlio_ll_tx_support_dma_eof(NULL)) { // for some chips, only support in particular ECO version
564-
transmit_config.flags.loop_transmission = true;
565-
int lopp_count = 3;
566-
while (lopp_count--) {
567-
TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload_loop1, 256 * sizeof(uint8_t) * 8, &transmit_config));
568-
vTaskDelay(pdMS_TO_TICKS(10));
569-
// Should be sent after the previous frame has been completely sent
570-
TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload_loop2, 256 * sizeof(uint8_t) * 8, &transmit_config));
571-
vTaskDelay(pdMS_TO_TICKS(10));
572-
}
573589

574-
transmit_config.flags.loop_transmission = false;
575-
// should be pending in queue
576-
TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload_oneshot, 256 * sizeof(uint8_t) * 8, &transmit_config));
577-
transmit_config.flags.loop_transmission = true;
578-
// there is a oneshot trans in queue, should also be pending in queue
590+
transmit_config.flags.loop_transmission = true;
591+
int lopp_count = 3;
592+
while (lopp_count--) {
579593
TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload_loop1, 256 * sizeof(uint8_t) * 8, &transmit_config));
594+
vTaskDelay(pdMS_TO_TICKS(10));
595+
// Should be sent after the previous frame has been completely sent
596+
TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload_loop2, 256 * sizeof(uint8_t) * 8, &transmit_config));
597+
vTaskDelay(pdMS_TO_TICKS(10));
598+
}
580599

581-
TEST_ESP_ERR(ESP_ERR_TIMEOUT, parlio_tx_unit_wait_all_done(tx_unit, 50));
600+
transmit_config.flags.loop_transmission = false;
601+
// should be pending in queue
602+
TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload_oneshot, 256 * sizeof(uint8_t) * 8, &transmit_config));
603+
transmit_config.flags.loop_transmission = true;
604+
// there is a oneshot trans in queue, should also be pending in queue
605+
TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload_loop1, 256 * sizeof(uint8_t) * 8, &transmit_config));
582606

583-
// stop infinite loop transmission
584-
parlio_tx_unit_disable(tx_unit);
585-
// We should see 1 oneshot frame and 1 loop transmission (both pending in queue)
586-
parlio_tx_unit_enable(tx_unit);
607+
TEST_ESP_ERR(ESP_ERR_TIMEOUT, parlio_tx_unit_wait_all_done(tx_unit, 50));
587608

588-
vTaskDelay(pdMS_TO_TICKS(10));
589-
// stop the second infinite loop transmission
590-
parlio_tx_unit_disable(tx_unit);
591-
parlio_tx_unit_enable(tx_unit);
592-
} else {
593-
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, parlio_tx_unit_transmit(tx_unit, payload_loop1, 256 * sizeof(uint8_t) * 8, &transmit_config));
609+
// stop infinite loop transmission
610+
parlio_tx_unit_disable(tx_unit);
611+
// We should see 1 oneshot frame and 1 loop transmission (both pending in queue)
612+
parlio_tx_unit_enable(tx_unit);
613+
614+
vTaskDelay(pdMS_TO_TICKS(10));
615+
// stop the second infinite loop transmission
616+
parlio_tx_unit_disable(tx_unit);
617+
parlio_tx_unit_enable(tx_unit);
618+
619+
// total 5 switch events
620+
TEST_ASSERT_EQUAL(5, context.switch_count);
621+
for (int i = 0; i < context.switch_count; i++) {
622+
void *old_buffer_addr = context.old_buffer_addr[i];
623+
void *new_buffer_addr = context.new_buffer_addr[i];
624+
if (i % 2 == 0) {
625+
TEST_ASSERT_EQUAL(payload_loop1, old_buffer_addr);
626+
TEST_ASSERT_EQUAL(payload_loop2, new_buffer_addr);
627+
} else {
628+
TEST_ASSERT_EQUAL(payload_loop2, old_buffer_addr);
629+
TEST_ASSERT_EQUAL(payload_loop1, new_buffer_addr);
630+
}
594631
}
595632

596633
TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1));

components/esp_hw_support/dma/gdma_link.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,27 @@ size_t gdma_link_count_buffer_size_till_eof(gdma_link_list_handle_t list, int st
283283
}
284284
return buf_size;
285285
}
286+
287+
void *gdma_link_get_buffer(gdma_link_list_handle_t list, int item_index)
288+
{
289+
if (!list) {
290+
return NULL;
291+
}
292+
int num_items = list->num_items;
293+
// ensure the item_index is between 0 and `num_items - 1`
294+
item_index = (item_index % num_items + num_items) % num_items;
295+
gdma_link_list_item_t *lli = (gdma_link_list_item_t *)(list->items_nc + item_index * list->item_size);
296+
return lli->buffer;
297+
}
298+
299+
size_t gdma_link_get_length(gdma_link_list_handle_t list, int item_index)
300+
{
301+
if (!list) {
302+
return 0;
303+
}
304+
int num_items = list->num_items;
305+
// ensure the item_index is between 0 and `num_items - 1`
306+
item_index = (item_index % num_items + num_items) % num_items;
307+
gdma_link_list_item_t *lli = (gdma_link_list_item_t *)(list->items_nc + item_index * list->item_size);
308+
return lli->dw0.length;
309+
}

0 commit comments

Comments
 (0)