#ifdef SUPPORT_MS_EXTENSIONS #pragma bss_seg(".reference_time.data.bss") #pragma data_seg(".reference_time.data") #pragma const_seg(".reference_time.text.const") #pragma code_seg(".reference_time.text") #endif /*************************************************************************************************/ /*! * \file reference_time.c * * \brief 提供音频参考时钟选择的接口函数实体与管理 * * Copyright (c) 2011-2022 ZhuHai Jieli Technology Co.,Ltd. * */ /*************************************************************************************************/ #include "reference_time.h" #include "system/includes.h" /* #include "le_audio_stream.h" */ /* * 关于优先级选择: * 手机的网络时钟优先级最高,无手机网络的情况下选择TWS网络 */ static LIST_HEAD(reference_head); static u8 local_network = 0xff; static u8 local_net_addr[6]; static u8 local_network_id = 1; extern const int LE_AUDIO_TIME_ENABLE; struct reference_clock { u8 id; u8 network; union { u8 net_addr[6]; void *le_addr; }; struct list_head entry; }; extern void bt_audio_reference_clock_select(void *addr, u8 network); extern u32 bt_audio_reference_clock_time(u8 network); extern u32 bt_audio_reference_clock_remapping(void *src_addr, u8 src_network, void *dst_addr, u8 dst_network, u32 clock); extern u8 bt_audio_reference_link_exist(void *addr, u8 network); //le audio相关函数弱定义 __attribute__((weak)) int le_audio_stream_clock_select(void *le_audio) { printf("empty fun %s\n", __FUNCTION__); return 0; } __attribute__((weak)) u32 le_audio_stream_current_time(void *le_audio) { printf("empty fun %s\n", __FUNCTION__); return 0; } __attribute__((weak)) int le_audio_stream_get_latch_time(void *le_audio, u32 *time, u16 *us_1_12th, u32 *event) { printf("empty fun %s\n", __FUNCTION__); return 0; } __attribute__((weak)) void le_audio_stream_latch_time_enable(void *le_audio) { printf("empty fun %s\n", __FUNCTION__); } int audio_reference_clock_select(void *addr, u8 network) { struct reference_clock *reference_clock = (struct reference_clock *)zalloc(sizeof(struct reference_clock)); struct reference_clock *clk; u8 reset_clock = 1; local_irq_disable(); if (network > 2) { local_irq_enable(); free(reference_clock); return 0; } if (list_empty(&reference_head) || network == 0) { reference_clock->network = network; if (LE_AUDIO_TIME_ENABLE && network == 2) { reference_clock->le_addr = addr; } else { if (addr == NULL) { memset(reference_clock->net_addr, 0x0, sizeof(reference_clock->net_addr)); } else { memcpy(reference_clock->net_addr, addr, sizeof(reference_clock->net_addr)); } } } else { clk = list_first_entry(&reference_head, struct reference_clock, entry); if (clk->network == 0 && bt_audio_reference_link_exist(clk->net_addr, clk->network)) { reference_clock->network = clk->network; memcpy(reference_clock->net_addr, clk->net_addr, sizeof(reference_clock->net_addr)); reset_clock = 0; } else { reference_clock->network = network; if (LE_AUDIO_TIME_ENABLE && network == 2) { reference_clock->le_addr = addr; } else { if (addr == NULL) { memset(reference_clock->net_addr, 0x0, sizeof(reference_clock->net_addr)); } else { memcpy(reference_clock->net_addr, addr, sizeof(reference_clock->net_addr)); } } } } list_add(&reference_clock->entry, &reference_head); reference_clock->id = local_network_id; if (++local_network_id == 0) { local_network_id++; } local_irq_enable(); if (reset_clock) { if (LE_AUDIO_TIME_ENABLE && reference_clock->network == 2) { le_audio_stream_clock_select(reference_clock->le_addr); } else { bt_audio_reference_clock_select(reference_clock->net_addr, reference_clock->network); } } return reference_clock->id; } u32 audio_reference_clock_time(void) { if (!list_empty(&reference_head)) { struct reference_clock *clk; clk = list_first_entry(&reference_head, struct reference_clock, entry); if (LE_AUDIO_TIME_ENABLE && clk->network == 2) { return le_audio_stream_current_time(clk->le_addr); } return bt_audio_reference_clock_time(clk->network); } return bt_audio_reference_clock_time(local_network); } u32 audio_reference_network_clock_time(u8 network) { return bt_audio_reference_clock_time(network); } u8 audio_reference_network_exist(u8 id) { struct reference_clock *clk; local_irq_disable(); list_for_each_entry(clk, &reference_head, entry) { if (clk->id == id) { goto exist_detect; } } local_irq_enable(); return 0; exist_detect: local_irq_enable(); return bt_audio_reference_link_exist(clk->net_addr, clk->network); } int le_audio_get_reference_latch_time(u32 *time, u16 *us_1_12th, u32 *event) { if (!LE_AUDIO_TIME_ENABLE) { return 0; } if (!list_empty(&reference_head)) { struct reference_clock *clk; clk = list_first_entry(&reference_head, struct reference_clock, entry); if (clk->network == 2) { le_audio_stream_get_latch_time(clk->le_addr, time, us_1_12th, event); } } return 0; } void le_audio_reference_time_latch_enable(void) { if (!LE_AUDIO_TIME_ENABLE) { return; } if (!list_empty(&reference_head)) { struct reference_clock *clk; clk = list_first_entry(&reference_head, struct reference_clock, entry); if (clk->network == 2) { le_audio_stream_latch_time_enable(clk->le_addr); } } } u8 is_audio_reference_clock_enable(void) { return 0; /*return local_network == 0xff ? 0 : 1;*/ } u8 audio_reference_clock_network(void *addr) { struct reference_clock *clk; if (list_empty(&reference_head)) { return -1; } clk = list_first_entry(&reference_head, struct reference_clock, entry); if (clk->network != 2 && addr) { memcpy(addr, clk->net_addr, 6); } return clk->network; } u8 audio_reference_clock_match(void *addr, u8 network) { struct reference_clock *clk; if (list_empty(&reference_head)) { return 0; } clk = list_first_entry(&reference_head, struct reference_clock, entry); if (clk->network == network) { if (network == 0) { if (addr && memcmp(clk->net_addr, addr, 6) == 0) { return 1; } return 0; } return 1; } return 0; } u32 audio_reference_clock_remapping(u8 now_network, u8 dst_network, u32 clock) { void *now_addr = NULL; void *dst_addr = NULL; struct reference_clock *clk; local_irq_disable(); list_for_each_entry(clk, &reference_head, entry) { if (!now_addr && clk->network == now_network) { now_addr = clk->net_addr; } if (!dst_addr && clk->network == dst_network) { dst_addr = clk->net_addr; } } local_irq_enable(); return bt_audio_reference_clock_remapping(now_addr, now_network, dst_addr, dst_network, clock); } void audio_reference_clock_exit(u8 id) { struct reference_clock *clk; local_irq_disable(); list_for_each_entry(clk, &reference_head, entry) { if (clk->id == id) { goto delete; } } local_irq_enable(); return; delete: list_del(&clk->entry); free(clk); if (!list_empty(&reference_head)) { /*clk = list_first_entry(&reference_head, struct reference_clock, entry);*/ /*bt_audio_reference_clock_select(clk->net_addr, clk->network);*/ } local_irq_enable(); }