594 lines
12 KiB
C
594 lines
12 KiB
C
/***************************************************************************
|
|
*
|
|
* Copyright 2015-2019 BES.
|
|
* All rights reserved. All unpublished rights reserved.
|
|
*
|
|
* No part of this work may be used or reproduced in any form or by any
|
|
* means, or stored in a database or retrieval system, without prior written
|
|
* permission of BES.
|
|
*
|
|
* Use of this work is governed by a license granted by BES.
|
|
* This work contains confidential and proprietary information of
|
|
* BES. which is protected by copyright, trade secret,
|
|
* trademark and other intellectual property rights.
|
|
*
|
|
****************************************************************************/
|
|
#ifdef A2DP_CP_ACCEL
|
|
|
|
#include "a2dp_decoder_cp.h"
|
|
#include "a2dp_decoder_internal.h"
|
|
#include "cp_accel.h"
|
|
#include "hal_location.h"
|
|
#include "hal_timer.h"
|
|
#include "hal_trace.h"
|
|
#include "heap_api.h"
|
|
#include "norflash_api.h"
|
|
|
|
#define CP_IN_FRAME_CNT 100
|
|
#define CP_OUT_FRAME_CNT 3
|
|
|
|
#define CP_IN_CACHE_SIZE (1024 * 10)
|
|
|
|
#if defined(A2DP_LHDC_V3)
|
|
#define CP_HEAP_SIZE (1024 * 64)
|
|
#else
|
|
#define CP_HEAP_SIZE (1024 * 32)
|
|
#endif
|
|
|
|
enum CP_DEC_STATE_T {
|
|
CP_DEC_STATE_IDLE,
|
|
CP_DEC_STATE_WORKING,
|
|
CP_DEC_STATE_DONE,
|
|
CP_DEC_STATE_INIT_DONE,
|
|
};
|
|
|
|
struct CP_IN_FRAME_INFO_T {
|
|
uint32_t pos;
|
|
uint32_t len;
|
|
};
|
|
|
|
struct CP_OUT_FRAME_INFO_T {
|
|
enum CP_DEC_STATE_T state;
|
|
uint32_t pos;
|
|
uint32_t len;
|
|
};
|
|
|
|
static CP_BSS_LOC uint32_t cp_heap_buf[CP_HEAP_SIZE / 4];
|
|
static CP_BSS_LOC heap_handle_t cp_heap;
|
|
|
|
static CP_BSS_LOC uint16_t cp_in_widx;
|
|
static CP_BSS_LOC uint16_t cp_in_ridx;
|
|
|
|
static CP_BSS_LOC uint8_t cp_out_widx;
|
|
static CP_BSS_LOC uint8_t cp_out_ridx;
|
|
|
|
static CP_BSS_LOC struct CP_IN_FRAME_INFO_T *in_frames;
|
|
static CP_BSS_LOC struct CP_OUT_FRAME_INFO_T *out_frames;
|
|
|
|
static CP_BSS_LOC uint8_t *cp_in_cache;
|
|
static CP_BSS_LOC uint8_t *cp_out_cache;
|
|
|
|
static CP_BSS_LOC bool reset_frames;
|
|
|
|
#ifdef A2DP_TRACE_CP_DEC_TIME
|
|
static CP_BSS_LOC uint32_t cp_last_dec_time;
|
|
#endif
|
|
|
|
static uint8_t max_buffer_frames = 2;
|
|
static bool mcu_dec_inited;
|
|
static A2DP_CP_DECODE_T decode_frame;
|
|
static enum CP_PROC_DELAY_T proc_delay;
|
|
|
|
static bool cp_need_reset;
|
|
|
|
CP_TEXT_SRAM_LOC
|
|
unsigned int set_cp_reset_flag(uint8_t evt) {
|
|
cp_need_reset = true;
|
|
return 0;
|
|
}
|
|
|
|
bool is_cp_need_reset(void) {
|
|
bool ret = cp_need_reset;
|
|
cp_need_reset = false;
|
|
return ret;
|
|
}
|
|
|
|
bool is_cp_init_done(void) { return cp_accel_init_done(); }
|
|
|
|
CP_TEXT_SRAM_LOC
|
|
static void reset_frame_info(void) {
|
|
uint32_t idle_cnt;
|
|
int i;
|
|
|
|
if (proc_delay == CP_PROC_DELAY_0_FRAME) {
|
|
idle_cnt = CP_OUT_FRAME_CNT;
|
|
} else if (proc_delay == CP_PROC_DELAY_1_FRAME) {
|
|
idle_cnt = CP_OUT_FRAME_CNT - 1;
|
|
} else {
|
|
idle_cnt = CP_OUT_FRAME_CNT - 2;
|
|
}
|
|
|
|
for (i = 0; i < CP_OUT_FRAME_CNT; i++) {
|
|
if (i < idle_cnt) {
|
|
out_frames[i].state = CP_DEC_STATE_IDLE;
|
|
} else {
|
|
out_frames[i].state = CP_DEC_STATE_INIT_DONE;
|
|
}
|
|
}
|
|
|
|
cp_in_widx = 0;
|
|
cp_in_ridx = 0;
|
|
cp_out_widx = 0;
|
|
cp_out_ridx = idle_cnt;
|
|
|
|
reset_frames = false;
|
|
}
|
|
|
|
CP_TEXT_SRAM_LOC
|
|
static unsigned int cp_a2dp_main(uint8_t event) {
|
|
int ret;
|
|
#ifdef A2DP_TRACE_CP_DEC_TIME
|
|
uint32_t stime;
|
|
uint32_t etime;
|
|
#endif
|
|
|
|
if (!mcu_dec_inited) {
|
|
return 0;
|
|
}
|
|
|
|
if (decode_frame) {
|
|
do {
|
|
#ifdef A2DP_TRACE_CP_DEC_TIME
|
|
stime = hal_fast_sys_timer_get();
|
|
#endif
|
|
|
|
ret = decode_frame();
|
|
|
|
#ifdef A2DP_TRACE_CP_DEC_TIME
|
|
etime = hal_fast_sys_timer_get();
|
|
TRACE_A2DP_DECODER_I("cp_decode: %5u us in %5u us",
|
|
FAST_TICKS_TO_US(etime - stime),
|
|
FAST_TICKS_TO_US(etime - cp_last_dec_time));
|
|
cp_last_dec_time = etime;
|
|
#endif
|
|
} while (ret == 0);
|
|
}
|
|
|
|
if (reset_frames) {
|
|
reset_frame_info();
|
|
#ifdef A2DP_TRACE_CP_ACCEL
|
|
TRACE_A2DP_DECODER_I("%s: Reset frames", __func__);
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct cp_task_desc TASK_DESC_A2DP = {
|
|
CP_ACCEL_STATE_CLOSED, cp_a2dp_main, NULL, NULL, set_cp_reset_flag};
|
|
int a2dp_cp_init(A2DP_CP_DECODE_T decode_func, enum CP_PROC_DELAY_T delay) {
|
|
if (delay >= CP_PROC_DELAY_QTY) {
|
|
return 1;
|
|
}
|
|
mcu_dec_inited = false;
|
|
decode_frame = decode_func;
|
|
proc_delay = delay;
|
|
#ifdef A2DP_TRACE_CP_DEC_TIME
|
|
cp_last_dec_time = hal_fast_sys_timer_get();
|
|
#endif
|
|
|
|
norflash_api_flush_disable(NORFLASH_API_USER_CP,
|
|
(uint32_t)cp_accel_init_done);
|
|
cp_accel_open(CP_TASK_A2DP_DECODE, &TASK_DESC_A2DP);
|
|
while (cp_accel_init_done() == false) {
|
|
hal_sys_timer_delay_us(100);
|
|
}
|
|
norflash_api_flush_enable(NORFLASH_API_USER_CP);
|
|
return 0;
|
|
}
|
|
int a2dp_cp_deinit(void) {
|
|
cp_accel_close(CP_TASK_A2DP_DECODE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
SRAM_TEXT_LOC
|
|
int a2dp_cp_decoder_init(uint32_t out_frame_len, uint8_t max_frames) {
|
|
uint32_t i;
|
|
max_buffer_frames = max_frames;
|
|
if (!mcu_dec_inited) {
|
|
#ifdef A2DP_TRACE_CP_ACCEL
|
|
TRACE_A2DP_DECODER_I("%s: Decoder init", __func__);
|
|
#endif
|
|
if (cp_accel_init_done() == false) {
|
|
TRACE_A2DP_DECODER_I("%s: CP ACCEL not init yet", __func__);
|
|
return 6;
|
|
}
|
|
|
|
cp_heap = heap_register(cp_heap_buf, sizeof(cp_heap_buf));
|
|
if (cp_heap == NULL) {
|
|
return 1;
|
|
}
|
|
|
|
in_frames = heap_malloc(cp_heap, sizeof(in_frames[0]) * CP_IN_FRAME_CNT);
|
|
if (in_frames == NULL) {
|
|
return 2;
|
|
}
|
|
|
|
out_frames = heap_malloc(cp_heap, sizeof(out_frames[0]) * CP_OUT_FRAME_CNT);
|
|
if (out_frames == NULL) {
|
|
return 3;
|
|
}
|
|
|
|
cp_in_cache = heap_malloc(cp_heap, CP_IN_CACHE_SIZE);
|
|
if (cp_in_cache == NULL) {
|
|
return 4;
|
|
}
|
|
|
|
cp_out_cache = heap_malloc(cp_heap, out_frame_len * CP_OUT_FRAME_CNT);
|
|
if (cp_out_cache == NULL) {
|
|
return 5;
|
|
}
|
|
|
|
for (i = 0; i < CP_OUT_FRAME_CNT; i++) {
|
|
out_frames[i].pos = out_frame_len * i;
|
|
out_frames[i].len = out_frame_len;
|
|
}
|
|
reset_frame_info();
|
|
|
|
mcu_dec_inited = true;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
CP_TEXT_SRAM_LOC
|
|
static uint32_t get_in_frame_cnt(uint32_t in_widx, uint32_t in_ridx) {
|
|
uint32_t cnt;
|
|
|
|
if (in_widx >= in_ridx) {
|
|
cnt = in_widx - in_ridx;
|
|
} else {
|
|
cnt = CP_IN_FRAME_CNT - in_ridx + in_widx;
|
|
}
|
|
|
|
return cnt;
|
|
}
|
|
|
|
uint32_t get_in_cp_frame_cnt(void) {
|
|
return get_in_frame_cnt(cp_in_widx, cp_in_ridx);
|
|
}
|
|
|
|
uint32_t get_in_cp_frame_delay(void) { return proc_delay; }
|
|
|
|
SRAM_TEXT_LOC
|
|
static uint32_t get_in_frame_free_cnt(uint32_t in_widx, uint32_t in_ridx) {
|
|
uint32_t free_cnt;
|
|
|
|
if (in_widx >= in_ridx) {
|
|
free_cnt = CP_IN_FRAME_CNT - in_widx + in_ridx;
|
|
} else {
|
|
free_cnt = in_ridx - in_widx;
|
|
}
|
|
free_cnt -= 1;
|
|
|
|
return free_cnt;
|
|
}
|
|
|
|
SRAM_TEXT_LOC
|
|
int a2dp_cp_put_in_frame(const void *buf1, uint32_t len1, const void *buf2,
|
|
uint32_t len2) {
|
|
uint16_t free_cnt;
|
|
uint16_t in_widx;
|
|
uint16_t in_ridx;
|
|
uint16_t prev_in_widx;
|
|
uint32_t free_len;
|
|
uint32_t in_wpos;
|
|
uint32_t in_rpos;
|
|
uint32_t aligned_len;
|
|
|
|
if (reset_frames) {
|
|
return -1;
|
|
}
|
|
|
|
in_widx = cp_in_widx;
|
|
in_ridx = cp_in_ridx;
|
|
|
|
if (max_buffer_frames < get_in_cp_frame_cnt()) {
|
|
return 1;
|
|
}
|
|
|
|
free_cnt = get_in_frame_free_cnt(in_widx, in_ridx);
|
|
if (free_cnt == 0) {
|
|
return 1;
|
|
}
|
|
|
|
if (in_widx == in_ridx) {
|
|
in_wpos = 0;
|
|
in_rpos = 0;
|
|
} else {
|
|
if (in_widx == 0) {
|
|
prev_in_widx = CP_IN_FRAME_CNT - 1;
|
|
} else {
|
|
prev_in_widx = in_widx - 1;
|
|
}
|
|
in_wpos = in_frames[prev_in_widx].pos + in_frames[prev_in_widx].len;
|
|
if (in_wpos >= CP_IN_CACHE_SIZE) {
|
|
in_wpos -= CP_IN_CACHE_SIZE;
|
|
}
|
|
in_rpos = in_frames[in_ridx].pos;
|
|
}
|
|
|
|
// Align to word boundary
|
|
in_wpos = (in_wpos + 3) & ~3;
|
|
if (in_wpos >= CP_IN_CACHE_SIZE) {
|
|
in_wpos -= CP_IN_CACHE_SIZE;
|
|
}
|
|
aligned_len = (len1 + len2 + 3) & ~3;
|
|
|
|
if (in_wpos >= in_rpos) {
|
|
free_len = CP_IN_CACHE_SIZE - in_wpos;
|
|
if (in_rpos == 0) {
|
|
free_len -= 1;
|
|
}
|
|
if (free_len < aligned_len) {
|
|
free_len = (in_rpos > 0) ? (in_rpos - 1) : 0;
|
|
if (free_len < aligned_len) {
|
|
return 2;
|
|
}
|
|
in_wpos = 0;
|
|
}
|
|
} else {
|
|
free_len = in_rpos - in_wpos - 1;
|
|
if (free_len < aligned_len) {
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
in_frames[in_widx].pos = in_wpos;
|
|
in_frames[in_widx].len = len1 + len2;
|
|
|
|
if (len1) {
|
|
memcpy(&cp_in_cache[in_wpos], buf1, len1);
|
|
in_wpos += len1;
|
|
}
|
|
if (len2) {
|
|
memcpy(&cp_in_cache[in_wpos], buf2, len2);
|
|
in_wpos += len2;
|
|
}
|
|
|
|
in_widx += 1;
|
|
if (in_widx >= CP_IN_FRAME_CNT) {
|
|
in_widx -= CP_IN_FRAME_CNT;
|
|
}
|
|
cp_in_widx = in_widx;
|
|
|
|
return 0;
|
|
}
|
|
|
|
CP_TEXT_SRAM_LOC
|
|
int a2dp_cp_get_in_frame(void **p_buf, uint32_t *p_len) {
|
|
uint16_t in_widx;
|
|
uint16_t in_ridx;
|
|
uint32_t in_rpos;
|
|
|
|
if (reset_frames) {
|
|
return -1;
|
|
}
|
|
|
|
in_widx = cp_in_widx;
|
|
in_ridx = cp_in_ridx;
|
|
|
|
if (in_widx == in_ridx) {
|
|
return 1;
|
|
}
|
|
|
|
in_rpos = in_frames[in_ridx].pos;
|
|
|
|
if (p_buf) {
|
|
*p_buf = &cp_in_cache[in_rpos];
|
|
}
|
|
if (p_len) {
|
|
*p_len = in_frames[in_ridx].len;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
CP_TEXT_SRAM_LOC
|
|
int a2dp_cp_consume_in_frame(void) {
|
|
uint16_t in_widx;
|
|
uint16_t in_ridx;
|
|
|
|
if (reset_frames) {
|
|
return 0;
|
|
}
|
|
|
|
in_widx = cp_in_widx;
|
|
in_ridx = cp_in_ridx;
|
|
|
|
if (in_widx == in_ridx) {
|
|
return 1;
|
|
}
|
|
|
|
in_ridx += 1;
|
|
if (in_ridx >= CP_IN_FRAME_CNT) {
|
|
in_ridx -= CP_IN_FRAME_CNT;
|
|
}
|
|
cp_in_ridx = in_ridx;
|
|
|
|
return 0;
|
|
}
|
|
|
|
CP_TEXT_SRAM_LOC
|
|
uint32_t a2dp_cp_get_in_frame_index(void) { return cp_in_ridx; }
|
|
|
|
SRAM_TEXT_LOC
|
|
uint32_t a2dp_cp_get_in_frame_cnt_by_index(uint32_t ridx) {
|
|
return get_in_frame_cnt(cp_in_widx, ridx);
|
|
}
|
|
|
|
SRAM_TEXT_LOC
|
|
void a2dp_cp_reset_frame(void) {
|
|
#ifdef A2DP_TRACE_CP_ACCEL
|
|
TRACE_A2DP_DECODER_I("%s: Reset frames", __func__);
|
|
#endif
|
|
|
|
reset_frames = true;
|
|
|
|
// Notify CP to work again
|
|
cp_accel_send_event_mcu2cp(1);
|
|
}
|
|
|
|
SRAM_TEXT_LOC
|
|
bool a2dp_cp_get_frame_reset_status(void) { return reset_frames; }
|
|
|
|
CP_TEXT_SRAM_LOC
|
|
enum CP_EMPTY_OUT_FRM_T a2dp_cp_get_emtpy_out_frame(void **p_buf,
|
|
uint32_t *p_len) {
|
|
enum CP_EMPTY_OUT_FRM_T ret;
|
|
uint8_t out_widx;
|
|
uint32_t out_wpos;
|
|
enum CP_DEC_STATE_T state;
|
|
|
|
if (reset_frames) {
|
|
return CP_EMPTY_OUT_FRM_ERR;
|
|
}
|
|
|
|
out_widx = cp_out_widx;
|
|
state = out_frames[out_widx].state;
|
|
|
|
if (state != CP_DEC_STATE_IDLE && state != CP_DEC_STATE_WORKING) {
|
|
return CP_EMPTY_OUT_FRM_ERR;
|
|
}
|
|
|
|
if (state == CP_DEC_STATE_WORKING) {
|
|
ret = CP_EMPTY_OUT_FRM_WORKING;
|
|
} else {
|
|
out_frames[out_widx].state = CP_DEC_STATE_WORKING;
|
|
ret = CP_EMPTY_OUT_FRM_OK;
|
|
}
|
|
|
|
out_wpos = out_frames[out_widx].pos;
|
|
|
|
if (p_buf) {
|
|
*p_buf = &cp_out_cache[out_wpos];
|
|
}
|
|
if (p_len) {
|
|
*p_len = out_frames[out_widx].len;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
CP_TEXT_SRAM_LOC
|
|
int a2dp_cp_consume_emtpy_out_frame(void) {
|
|
uint8_t out_widx;
|
|
|
|
if (reset_frames) {
|
|
return 0;
|
|
}
|
|
|
|
out_widx = cp_out_widx;
|
|
|
|
if (out_frames[out_widx].state != CP_DEC_STATE_WORKING) {
|
|
return 1;
|
|
}
|
|
|
|
out_frames[out_widx].state = CP_DEC_STATE_DONE;
|
|
|
|
#ifdef A2DP_TRACE_CP_ACCEL
|
|
TRACE_A2DP_DECODER_I("AD2P-CP out frame W[%d]", out_widx);
|
|
#endif
|
|
|
|
out_widx += 1;
|
|
if (out_widx >= CP_OUT_FRAME_CNT) {
|
|
out_widx -= CP_OUT_FRAME_CNT;
|
|
}
|
|
cp_out_widx = out_widx;
|
|
|
|
return 0;
|
|
}
|
|
|
|
SRAM_TEXT_LOC
|
|
int a2dp_cp_get_full_out_frame(void **p_buf, uint32_t *p_len) {
|
|
uint8_t out_ridx;
|
|
uint32_t out_rpos;
|
|
enum CP_DEC_STATE_T state;
|
|
|
|
if (reset_frames) {
|
|
return -1;
|
|
}
|
|
|
|
out_ridx = cp_out_ridx;
|
|
state = out_frames[out_ridx].state;
|
|
|
|
if (state != CP_DEC_STATE_DONE && state != CP_DEC_STATE_INIT_DONE) {
|
|
// Notify CP to work again
|
|
cp_accel_send_event_mcu2cp(
|
|
CP_BUILD_ID(CP_TASK_A2DP_DECODE, CP_EVENT_A2DP_DECODE));
|
|
if (state == CP_DEC_STATE_WORKING) {
|
|
return CP_EMPTY_OUT_FRM_WORKING;
|
|
} else {
|
|
return (10 + state);
|
|
}
|
|
}
|
|
|
|
out_rpos = out_frames[out_ridx].pos;
|
|
|
|
if (state == CP_DEC_STATE_DONE) {
|
|
if (p_buf) {
|
|
*p_buf = &cp_out_cache[out_rpos];
|
|
}
|
|
if (p_len) {
|
|
*p_len = out_frames[out_ridx].len;
|
|
}
|
|
} else {
|
|
if (p_buf) {
|
|
*p_buf = NULL;
|
|
}
|
|
if (p_len) {
|
|
*p_len = 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
SRAM_TEXT_LOC
|
|
int a2dp_cp_consume_full_out_frame(void) {
|
|
uint8_t out_ridx;
|
|
enum CP_DEC_STATE_T state;
|
|
|
|
if (reset_frames) {
|
|
return 0;
|
|
}
|
|
|
|
out_ridx = cp_out_ridx;
|
|
state = out_frames[out_ridx].state;
|
|
|
|
if (state != CP_DEC_STATE_DONE && state != CP_DEC_STATE_INIT_DONE) {
|
|
return 1;
|
|
}
|
|
|
|
#ifdef A2DP_TRACE_CP_ACCEL
|
|
TRACE_A2DP_DECODER_I("AD2P-CP out frame R[%d]", out_ridx);
|
|
#endif
|
|
|
|
out_frames[out_ridx].state = CP_DEC_STATE_IDLE;
|
|
|
|
out_ridx += 1;
|
|
if (out_ridx >= CP_OUT_FRAME_CNT) {
|
|
out_ridx -= CP_OUT_FRAME_CNT;
|
|
}
|
|
cp_out_ridx = out_ridx;
|
|
|
|
// Notify CP to work again
|
|
cp_accel_send_event_mcu2cp(
|
|
CP_BUILD_ID(CP_TASK_A2DP_DECODE, CP_EVENT_A2DP_DECODE));
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|