Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 766498be5a | |||
| 9ea485abc0 | |||
| 1b12e5151d | |||
| 4d6e6b8962 | |||
| bcb2bf3694 | |||
| 2120f9b188 | |||
| a70bf09bfa | |||
| 9647a07598 |
@@ -1,3 +1,5 @@
|
||||
*.pyc
|
||||
|
||||
# editors
|
||||
*.swp
|
||||
*~
|
||||
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"broadcast_source.h": "c",
|
||||
"bit": "c"
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@ zephyr_library_include_directories(app PRIVATE
|
||||
${ZEPHYR_NRF_MODULE_DIR}/applications/nrf5340_audio/src/modules
|
||||
${ZEPHYR_NRF_MODULE_DIR}/applications/nrf5340_audio/src/utils/macros
|
||||
)
|
||||
include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake)
|
||||
|
||||
|
||||
add_subdirectory(${ZEPHYR_NRF_MODULE_DIR}/applications/nrf5340_audio/src/bluetooth bluetooth_build)
|
||||
|
||||
|
||||
@@ -11,6 +11,81 @@ rsource "${ZEPHYR_NRF_MODULE_DIR}/applications/nrf5340_audio/src/utils/Kconfig"
|
||||
|
||||
#----------------------------------------------------------------------------#
|
||||
|
||||
# USB mass storage device
|
||||
menu "MSC sample options"
|
||||
|
||||
config APP_WIPE_STORAGE
|
||||
bool "Option to clear the flash area before mounting"
|
||||
help
|
||||
Use this to force an existing file system to be created.
|
||||
|
||||
choice
|
||||
prompt "Storage and file system type used by the application"
|
||||
default APP_MSC_STORAGE_NONE
|
||||
help
|
||||
Specify the type of storage and file system.
|
||||
|
||||
config APP_MSC_STORAGE_NONE
|
||||
bool "Use RAM disk as block device"
|
||||
|
||||
config APP_MSC_STORAGE_RAM
|
||||
bool "Use RAM disk and FAT file system"
|
||||
imply FILE_SYSTEM
|
||||
imply FAT_FILESYSTEM_ELM
|
||||
|
||||
config APP_MSC_STORAGE_FLASH_FATFS
|
||||
bool "Use FLASH disk and FAT file system"
|
||||
imply DISK_DRIVER_FLASH
|
||||
imply FILE_SYSTEM
|
||||
imply FAT_FILESYSTEM_ELM
|
||||
|
||||
config APP_MSC_STORAGE_FLASH_LITTLEFS
|
||||
bool "Use FLASH disk and LittleFS"
|
||||
imply DISK_DRIVER_FLASH
|
||||
imply FILE_SYSTEM
|
||||
imply FILE_SYSTEM_LITTLEFS
|
||||
|
||||
config APP_MSC_STORAGE_SDCARD
|
||||
bool "Use SDHC and FAT file system"
|
||||
imply DISK_DRIVER_SDMMC
|
||||
imply FILE_SYSTEM
|
||||
imply FAT_FILESYSTEM_ELM
|
||||
|
||||
endchoice
|
||||
|
||||
config MASS_STORAGE_DISK_NAME
|
||||
default "NAND" if DISK_DRIVER_FLASH
|
||||
default "RAM" if DISK_DRIVER_RAM
|
||||
default "SD" if DISK_DRIVER_SDMMC
|
||||
|
||||
if DISK_DRIVER_FLASH
|
||||
|
||||
config FLASH_MAP
|
||||
default y
|
||||
|
||||
config FLASH_PAGE_LAYOUT
|
||||
default y
|
||||
|
||||
config FLASH_LOG_LEVEL
|
||||
default 3
|
||||
|
||||
if NORDIC_QSPI_NOR
|
||||
|
||||
config NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE
|
||||
default 4096
|
||||
|
||||
endif # NORDIC_QSPI_NOR
|
||||
|
||||
endif # DISK_DRIVER_FLASH
|
||||
|
||||
endmenu
|
||||
|
||||
# Source common USB sample options used to initialize new experimental USB
|
||||
# device stack. The scope of these options is limited to USB samples in project
|
||||
# tree, you cannot use them in your own application.
|
||||
source "samples/subsys/usb/common/Kconfig.sample_usbd"
|
||||
|
||||
# Auraconfig
|
||||
config TRANSPORT_BIS
|
||||
bool "Use BIS (Broadcast Isochronous Stream)"
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
nac preset 24_2_1 0
|
||||
nac file select left-channel_24kHz_left_48kbps_10ms.lc3 0 0 0
|
||||
nac file select left-channel_24kHz_left_48kbps_10ms.lc3 0 0 1
|
||||
nac broadcast_name broadcast1 0
|
||||
|
||||
nac preset 24_2_1 1
|
||||
nac file select right-channel_24kHz_left_48kbps_10ms.lc3 1 0 0
|
||||
nac file select right-channel_24kHz_left_48kbps_10ms.lc3 1 0 1
|
||||
nac broadcast_name broadcast2 1
|
||||
|
||||
nac start
|
||||
@@ -0,0 +1,29 @@
|
||||
from config_broadcaster import write_to_serial_read_respone
|
||||
import time
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
serial_port = "/dev/ttyACM0"
|
||||
broadcast_config = {
|
||||
"broadcast1": "left24kHz_48kbps.lc3",
|
||||
"broadcast2": "right-channel_24kHz_left_48kbps_10ms.lc3"
|
||||
}
|
||||
broadcast_ch = 0
|
||||
file = "announcement_de.lc3"
|
||||
|
||||
ret = write_to_serial_read_respone(serial_port, f"nac file stream_close {broadcast_ch} 0 0", timeout=0.1)
|
||||
print("\n".join(ret))
|
||||
|
||||
ret = write_to_serial_read_respone(serial_port, f"nac file select_play_once {file} {broadcast_ch} 0 0", timeout=0.1)
|
||||
print("\n".join(ret))
|
||||
|
||||
time.sleep(1)
|
||||
broadcast_ch = 1
|
||||
file = "announcement_en.lc3"
|
||||
|
||||
ret = write_to_serial_read_respone(serial_port, f"nac stream_close {broadcast_ch} 0 0", timeout=0.1)
|
||||
print("\n".join(ret))
|
||||
|
||||
ret = write_to_serial_read_respone(serial_port, f"nac file select_play_once {file} {broadcast_ch} 0 0", timeout=0.1)
|
||||
print("\n".join(ret))
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import serial
|
||||
import time
|
||||
|
||||
|
||||
def write_to_serial_read_respone(port, cmd, timeout = 2):
|
||||
# Initialize serial connection
|
||||
ser = serial.Serial(timeout = timeout)
|
||||
ser.port = port
|
||||
ser.baudrate = 115200
|
||||
ser.bytesize = serial.EIGHTBITS
|
||||
ser.parity = serial.PARITY_NONE
|
||||
ser.stopbits = serial.STOPBITS_ONE
|
||||
|
||||
try:
|
||||
# Try to open the serial connection
|
||||
#if not ser.is_open:
|
||||
ser.open()
|
||||
|
||||
# Send string to serial port and get response
|
||||
command = f"{cmd.strip()}\r\n"
|
||||
ser.write(command.encode())
|
||||
time.sleep(1) # wait a bit for response
|
||||
|
||||
readlines = []
|
||||
for _ in range(20):
|
||||
line = ser.readline().decode('utf-8').strip()
|
||||
if not line:
|
||||
ser.close()
|
||||
break
|
||||
else:
|
||||
readlines.append(line)
|
||||
|
||||
except serial.SerialException as e:
|
||||
print(f"Error communicating with serial port: {e}")
|
||||
finally:
|
||||
# Close serial connection before returning
|
||||
if ser.is_open:
|
||||
ser.close()
|
||||
return readlines
|
||||
|
||||
|
||||
|
||||
def gen_broadcast_config_cmd(preset, broadcast_config: dict):
|
||||
"""
|
||||
Writes broadcaster configuration to the given serial port.
|
||||
|
||||
Args:
|
||||
serial_port (str): Device path of the serial port (e.g., '/dev/ttyACM0')
|
||||
preset (str): Preset string used in nac preset line
|
||||
broadcast_names (list): List of names for each broadcast group
|
||||
"""
|
||||
cmds = []
|
||||
for ch, file_name in broadcast_config.items():
|
||||
|
||||
cmds.append(f"nac preset {preset} {ch}")
|
||||
cmds.append(f"nac broadcast_name broadcast{ch} {ch}")
|
||||
cmds.append(f"nac file select {file_name} {ch} 0 0")
|
||||
cmds.append(f"nac num_bises 1 {ch} 0")
|
||||
|
||||
return cmds
|
||||
|
||||
if __name__ == "__main__":
|
||||
import subprocess
|
||||
|
||||
PORT = "/dev/ttyACM0"
|
||||
|
||||
SAMPLING_RATE_KHZ = 16
|
||||
FRAME_DUR_MS = 10
|
||||
PRESET = f'{SAMPLING_RATE_KHZ}_2_1'
|
||||
|
||||
if SAMPLING_RATE_KHZ == 8:
|
||||
BITRATE_KBPS = 16
|
||||
elif SAMPLING_RATE_KHZ == 16:
|
||||
BITRATE_KBPS = 32
|
||||
elif SAMPLING_RATE_KHZ == 24:
|
||||
BITRATE_KBPS = 48
|
||||
else:
|
||||
raise NotImplemented()
|
||||
|
||||
# TODO: Advertising interval wird ungelmäßig bei mehr als 3 broadcasts 10ms -> 1s< bei 24kHz sampling rat. Wie ist die load ?
|
||||
# TODO: stop the lc3 streamer, setup all files and then start the streamer, should work for up to 4 streams
|
||||
broadcast_config = {
|
||||
0: f"announcement_{SAMPLING_RATE_KHZ}_{FRAME_DUR_MS}_{BITRATE_KBPS}_de.lc3",
|
||||
1: f"announcement_{SAMPLING_RATE_KHZ}_{FRAME_DUR_MS}_{BITRATE_KBPS}_en.lc3",
|
||||
2: f"announcement_{SAMPLING_RATE_KHZ}_{FRAME_DUR_MS}_{BITRATE_KBPS}_fr.lc3",
|
||||
3: f"announcement_{SAMPLING_RATE_KHZ}_{FRAME_DUR_MS}_{BITRATE_KBPS}_es.lc3",
|
||||
#4: f"announcement_{SAMPLING_RATE_KHZ}_{FRAME_DUR_MS}_{BITRATE_KBPS}_it.lc3"
|
||||
}
|
||||
|
||||
cmds = gen_broadcast_config_cmd(PRESET, broadcast_config)
|
||||
|
||||
subprocess.run(["nrfjprog", "--reset", "-s", "1050109484"], check=True)
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
for cmd in cmds:
|
||||
ret = write_to_serial_read_respone(PORT, cmd, timeout=0.1)
|
||||
print("\n".join(ret))
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
for i in broadcast_config.keys():
|
||||
ret = write_to_serial_read_respone(PORT, f"nac start_idx {i}", timeout=0.1)
|
||||
print("\n".join(ret))
|
||||
time.sleep(0.2)
|
||||
@@ -3,7 +3,16 @@
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
# USB mass storage
|
||||
CONFIG_APP_MSC_STORAGE_SDCARD=y
|
||||
CONFIG_USB_DEVICE_STACK=y
|
||||
CONFIG_USB_DEVICE_PRODUCT="Zephyr MSC sample"
|
||||
CONFIG_USB_DEVICE_PID=0x0008
|
||||
CONFIG_LOG=y
|
||||
CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y
|
||||
CONFIG_USB_MASS_STORAGE=y
|
||||
CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y
|
||||
CONFIG_USB_MASS_STORAGE_LOG_LEVEL_ERR=y
|
||||
|
||||
# General
|
||||
CONFIG_REBOOT=y
|
||||
@@ -15,9 +24,9 @@ CONFIG_THREAD_RUNTIME_STATS=y
|
||||
CONFIG_MAIN_THREAD_PRIORITY=10
|
||||
CONFIG_STACK_SENTINEL=y
|
||||
CONFIG_INIT_STACKS=y
|
||||
CONFIG_MAIN_STACK_SIZE=12000
|
||||
CONFIG_MAIN_STACK_SIZE=18000
|
||||
CONFIG_THREAD_NAME=y
|
||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1200
|
||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2000
|
||||
|
||||
# Uart driver
|
||||
CONFIG_SERIAL=y
|
||||
@@ -28,7 +37,7 @@ CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
|
||||
CONFIG_LOG_TAG_MAX_LEN=2
|
||||
CONFIG_LOG_TAG_DEFAULT="--"
|
||||
|
||||
CONFIG_LOG_BUFFER_SIZE=4096
|
||||
CONFIG_LOG_BUFFER_SIZE=16384
|
||||
CONFIG_USE_SEGGER_RTT=n
|
||||
CONFIG_LOG_BACKEND_RTT=n
|
||||
|
||||
@@ -82,7 +91,6 @@ CONFIG_ADC=y
|
||||
CONFIG_WATCHDOG=y
|
||||
CONFIG_TASK_WDT=y
|
||||
|
||||
|
||||
# Use this for debugging thread usage
|
||||
#CONFIG_LOG_THREAD_ID_PREFIX=y
|
||||
|
||||
@@ -96,8 +104,8 @@ CONFIG_KERNEL_SHELL=y
|
||||
CONFIG_SHELL_BACKEND_SERIAL=y
|
||||
CONFIG_SHELL_VT100_COMMANDS=y
|
||||
CONFIG_SHELL_VT100_COLORS=y
|
||||
CONFIG_SHELL_STACK_SIZE=8096
|
||||
CONFIG_SHELL_CMD_BUFF_SIZE=128
|
||||
CONFIG_SHELL_STACK_SIZE=16384
|
||||
CONFIG_SHELL_CMD_BUFF_SIZE=512
|
||||
## Reduce shell memory usage
|
||||
CONFIG_SHELL_WILDCARD=n
|
||||
CONFIG_SHELL_HELP_ON_WRONG_ARGUMENT_COUNT=n
|
||||
@@ -125,16 +133,16 @@ CONFIG_BT_DEVICE_NAME_DYNAMIC=y
|
||||
CONFIG_BT_CAP_INITIATOR=y
|
||||
|
||||
CONFIG_BT_ISO_BROADCASTER=y
|
||||
CONFIG_BT_ISO_MAX_BIG=2
|
||||
CONFIG_BT_ISO_MAX_BIG=5
|
||||
CONFIG_BT_ISO_MAX_CHAN=8
|
||||
# Should be twice that of BT_ISO_MAX_CHAN
|
||||
CONFIG_BT_ISO_TX_BUF_COUNT=16
|
||||
|
||||
CONFIG_BT_BAP_BROADCAST_SOURCE=y
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_COUNT=2
|
||||
CONFIG_BT_EXT_ADV_MAX_ADV_SET=2
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=4
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=8
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_COUNT=5
|
||||
CONFIG_BT_EXT_ADV_MAX_ADV_SET=5
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1
|
||||
CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=1
|
||||
|
||||
# Broadcasting Device - 0x0885
|
||||
CONFIG_BT_DEVICE_APPEARANCE=2181
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# TODO:
|
||||
- stoppen von streams während advertising weiter läuft
|
||||
- 16kHz mit 16kbps (nur 32 kbps möglich)
|
||||
- cpu usage debuggen
|
||||
- 5 streams oder mehr parallel
|
||||
- mehr als 4 streams erzeugen file open error
|
||||
+399
-36
@@ -22,10 +22,57 @@
|
||||
#include "sd_card.h"
|
||||
#include "lc3_streamer.h"
|
||||
#include "led.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(main, CONFIG_MAIN_LOG_LEVEL);
|
||||
|
||||
#include <sample_usbd.h>
|
||||
#include <zephyr/usb/usb_device.h>
|
||||
#include <zephyr/usb/usbd.h>
|
||||
#include <zephyr/usb/class/usbd_msc.h>
|
||||
#include <zephyr/fs/fs.h>
|
||||
|
||||
#if CONFIG_FAT_FILESYSTEM_ELM
|
||||
#include <ff.h>
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_DISK_DRIVER_FLASH) && \
|
||||
!defined(CONFIG_DISK_DRIVER_RAM) && \
|
||||
!defined(CONFIG_DISK_DRIVER_SDMMC)
|
||||
#error No supported disk driver enabled
|
||||
#endif
|
||||
|
||||
#define STORAGE_PARTITION storage_partition
|
||||
#define STORAGE_PARTITION_ID FIXED_PARTITION_ID(STORAGE_PARTITION)
|
||||
|
||||
static struct fs_mount_t fs_mnt;
|
||||
|
||||
static int mount_app_fs(struct fs_mount_t *mnt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if CONFIG_FAT_FILESYSTEM_ELM
|
||||
static FATFS fat_fs;
|
||||
|
||||
mnt->type = FS_FATFS;
|
||||
mnt->fs_data = &fat_fs;
|
||||
if (IS_ENABLED(CONFIG_DISK_DRIVER_RAM)) {
|
||||
mnt->mnt_point = "/RAM:";
|
||||
} else if (IS_ENABLED(CONFIG_DISK_DRIVER_SDMMC)) {
|
||||
mnt->mnt_point = "/SD:";
|
||||
} else {
|
||||
mnt->mnt_point = "/NAND:";
|
||||
}
|
||||
|
||||
#elif CONFIG_FILE_SYSTEM_LITTLEFS
|
||||
mnt->type = FS_LITTLEFS;
|
||||
mnt->mnt_point = "/lfs";
|
||||
mnt->fs_data = &storage;
|
||||
#endif
|
||||
rc = fs_mount(mnt);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
ZBUS_CHAN_DECLARE(bt_mgmt_chan);
|
||||
ZBUS_CHAN_DECLARE(sdu_ref_chan);
|
||||
ZBUS_CHAN_DECLARE(le_audio_chan);
|
||||
@@ -44,11 +91,17 @@ struct bt_le_ext_adv *ext_adv;
|
||||
#define EXT_ADV_UUID_BUF_SIZE (128)
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(uuid_data0, EXT_ADV_UUID_BUF_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(uuid_data1, EXT_ADV_UUID_BUF_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(uuid_data2, EXT_ADV_UUID_BUF_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(uuid_data3, EXT_ADV_UUID_BUF_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(uuid_data4, EXT_ADV_UUID_BUF_SIZE);
|
||||
|
||||
/* Buffer for periodic advertising BASE data. */
|
||||
#define BASE_DATA_BUF_SIZE (256)
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(base_data0, BASE_DATA_BUF_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(base_data1, BASE_DATA_BUF_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(base_data2, BASE_DATA_BUF_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(base_data3, BASE_DATA_BUF_SIZE);
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(base_data4, BASE_DATA_BUF_SIZE);
|
||||
|
||||
/* Extended advertising buffer. */
|
||||
static struct bt_data ext_adv_buf[CONFIG_BT_ISO_MAX_BIG][CONFIG_EXT_ADV_BUF_MAX];
|
||||
@@ -80,13 +133,28 @@ static struct broadcast_source_ext_adv_data ext_adv_data[] = {
|
||||
.pba_buf = pba_data[0]},
|
||||
{.uuid_buf = &uuid_data1,
|
||||
.pba_metadata_vacant_cnt = BROADCAST_SOURCE_PBA_METADATA_VACANT,
|
||||
.pba_buf = pba_data[1]}};
|
||||
.pba_buf = pba_data[1]},
|
||||
{.uuid_buf = &uuid_data2,
|
||||
.pba_metadata_vacant_cnt = BROADCAST_SOURCE_PBA_METADATA_VACANT,
|
||||
.pba_buf = pba_data[2]},
|
||||
{.uuid_buf = &uuid_data3,
|
||||
.pba_metadata_vacant_cnt = BROADCAST_SOURCE_PBA_METADATA_VACANT,
|
||||
.pba_buf = pba_data[3]},
|
||||
{.uuid_buf = &uuid_data1,
|
||||
.pba_metadata_vacant_cnt = BROADCAST_SOURCE_PBA_METADATA_VACANT,
|
||||
.pba_buf = pba_data[4]}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Broadcast source static periodic advertising data.
|
||||
*/
|
||||
static struct broadcast_source_per_adv_data per_adv_data[] = {{.base_buf = &base_data0},
|
||||
{.base_buf = &base_data1}};
|
||||
static struct broadcast_source_per_adv_data per_adv_data[] = {
|
||||
{.base_buf = &base_data0},
|
||||
{.base_buf = &base_data1},
|
||||
{.base_buf = &base_data2},
|
||||
{.base_buf = &base_data3},
|
||||
{.base_buf = &base_data4}
|
||||
};
|
||||
|
||||
static struct broadcast_source_big broadcast_param[CONFIG_BT_ISO_MAX_BIG];
|
||||
static struct subgroup_config subgroups[CONFIG_BT_ISO_MAX_BIG]
|
||||
@@ -287,24 +355,33 @@ static void stream_frame_get_and_send(struct stream_index stream_idx)
|
||||
|
||||
ret = lc3_streamer_next_frame_get(
|
||||
stream_file_idx, (const uint8_t **const)&(bis_info->frame_ptrs[stream_idx.lvl3]));
|
||||
if (ret == -ENODATA) {
|
||||
LOG_WRN("No more frames to read");
|
||||
ret = lc3_streamer_stream_close(stream_file_idx);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to close stream: %d", ret);
|
||||
}
|
||||
|
||||
bis_info->lc3_streamer_idx[stream_idx.lvl3] = LC3_STREAMER_INDEX_UNUSED;
|
||||
|
||||
return;
|
||||
} else if (ret == -ENOMSG) {
|
||||
LOG_DBG("Frame from SD card not ready for stream %d, using zero packet",
|
||||
stream_idx.lvl3);
|
||||
bis_info->frame_ptrs[stream_idx.lvl3] = NULL;
|
||||
} else if (ret) {
|
||||
LOG_ERR("Failed to get next frame: %d", ret);
|
||||
return;
|
||||
|
||||
if (ret != 0){
|
||||
bis_info->frame_ptrs[stream_idx.lvl3] = NULL; // use zero packet
|
||||
//ret = lc3_streamer_stream_close(stream_file_idx);
|
||||
// if (ret) {
|
||||
// LOG_ERR("Failed to close stream: %d", ret);
|
||||
// }
|
||||
}
|
||||
|
||||
// if (ret == -ENODATA) {
|
||||
// LOG_WRN("No more frames to read");
|
||||
// ret = lc3_streamer_stream_close(stream_file_idx);
|
||||
// if (ret) {
|
||||
// LOG_ERR("Failed to close stream: %d", ret);
|
||||
// }
|
||||
|
||||
// bis_info->lc3_streamer_idx[stream_idx.lvl3] = LC3_STREAMER_INDEX_UNUSED;
|
||||
|
||||
// return;
|
||||
// } else if (ret == -ENOMSG) {
|
||||
// LOG_DBG("Frame from SD card not ready for stream %d, using zero packet",
|
||||
// stream_idx.lvl3);
|
||||
// bis_info->frame_ptrs[stream_idx.lvl3] = NULL;
|
||||
// } else if (ret) {
|
||||
// LOG_ERR("Failed to get next frame: %d", ret);
|
||||
// return;
|
||||
// }
|
||||
|
||||
bis_info->frame_loaded[stream_idx.lvl3] = true;
|
||||
|
||||
@@ -490,13 +567,16 @@ static int ext_adv_populate(uint8_t big_index, struct broadcast_source_ext_adv_d
|
||||
ext_adv_buf[ext_adv_buf_cnt].data = ext_adv_data->uuid_buf->data;
|
||||
ext_adv_buf_cnt++;
|
||||
|
||||
ret = bt_mgmt_manufacturer_uuid_populate(ext_adv_data->uuid_buf,
|
||||
CONFIG_BT_DEVICE_MANUFACTURER_ID);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to add adv data with manufacturer ID: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
//TODO: populating the manufacturer id fails with crash for more than 2 big
|
||||
// LOG_INF("populating manufacurer id for %d", big_index);
|
||||
// ret = bt_mgmt_manufacturer_uuid_populate(ext_adv_data->uuid_buf,
|
||||
// CONFIG_BT_DEVICE_MANUFACTURER_ID);
|
||||
// if (ret) {
|
||||
// LOG_ERR("Failed to add adv data with manufacturer ID: %d", ret);
|
||||
// return ret;
|
||||
// }
|
||||
|
||||
LOG_INF("Populating ext adv broadcast source %d", big_index);
|
||||
ret = broadcast_source_ext_adv_populate(big_index, broadcast_param[big_index].fixed_id,
|
||||
broadcast_param[big_index].broadcast_id,
|
||||
ext_adv_data, &ext_adv_buf[ext_adv_buf_cnt],
|
||||
@@ -511,7 +591,7 @@ static int ext_adv_populate(uint8_t big_index, struct broadcast_source_ext_adv_d
|
||||
/* Add the number of UUIDs */
|
||||
ext_adv_buf[0].data_len = ext_adv_data->uuid_buf->len;
|
||||
|
||||
LOG_DBG("Size of adv data: %d, num_elements: %d", sizeof(struct bt_data) * ext_adv_buf_cnt,
|
||||
LOG_INF("Size of adv data: %d, num_elements: %d", sizeof(struct bt_data) * ext_adv_buf_cnt,
|
||||
ext_adv_buf_cnt);
|
||||
|
||||
*ext_adv_count = ext_adv_buf_cnt;
|
||||
@@ -560,7 +640,7 @@ static int per_adv_populate(uint8_t big_index, struct broadcast_source_per_adv_d
|
||||
static void broadcast_create(uint8_t big_index)
|
||||
{
|
||||
if (big_index >= CONFIG_BT_ISO_MAX_BIG) {
|
||||
LOG_ERR("BIG index out of range");
|
||||
LOG_ERR("BIG index %d out of range", big_index);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -654,7 +734,7 @@ int main(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOG_DBG("Main started");
|
||||
LOG_INF("Main started");
|
||||
|
||||
ret = nrfx_clock_divider_set(NRF_CLOCK_DOMAIN_HFCLK, NRF_CLOCK_HFCLK_DIV_1);
|
||||
ret -= NRFX_ERROR_BASE_NUM;
|
||||
@@ -689,14 +769,15 @@ int main(void)
|
||||
}
|
||||
}
|
||||
|
||||
ret = zbus_subscribers_create();
|
||||
ERR_CHK_MSG(ret, "Failed to create zbus subscriber threads");
|
||||
|
||||
if (sd_card_present) {
|
||||
ret = sd_card_toc_gen();
|
||||
ERR_CHK_MSG(ret, "Failed to generate SD card table");
|
||||
}
|
||||
|
||||
ret = zbus_subscribers_create();
|
||||
ERR_CHK_MSG(ret, "Failed to create zbus subscriber threads");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -874,6 +955,18 @@ static void nrf_auraconfig_print(const struct shell *shell, uint8_t group_index)
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_usb_mass_enable(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
ret = usb_enable(NULL);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to enable USB");
|
||||
return -1;
|
||||
}
|
||||
LOG_INF("The device is put in USB mass storage mode.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_list(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
ARG_UNUSED(argc);
|
||||
@@ -892,12 +985,15 @@ static int adv_create_and_start(const struct shell *shell, uint8_t big_index)
|
||||
|
||||
size_t ext_adv_buf_cnt = 0;
|
||||
size_t per_adv_buf_cnt = 0;
|
||||
LOG_INF("Starting Ext Advertising for big %d", big_index);
|
||||
|
||||
if (big_index >= CONFIG_BT_ISO_MAX_BIG) {
|
||||
shell_error(shell, "BIG index out of range");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOG_INF("Starting Ext Advertising for big %d", big_index);
|
||||
|
||||
if (broadcast_param[big_index].broadcast_name[0] == '\0') {
|
||||
/* Name not set, using default */
|
||||
size_t brdcst_name_size = sizeof(CONFIG_BT_AUDIO_BROADCAST_NAME) - 1;
|
||||
@@ -931,6 +1027,7 @@ static int adv_create_and_start(const struct shell *shell, uint8_t big_index)
|
||||
|
||||
bt_set_name(broadcast_param[big_index].adv_name);
|
||||
|
||||
LOG_INF("Populating Ext Advertising for big %d", big_index);
|
||||
/* Get advertising set for BIG0 */
|
||||
ret = ext_adv_populate(big_index, &ext_adv_data[big_index], ext_adv_buf[big_index],
|
||||
ARRAY_SIZE(ext_adv_buf[big_index]), &ext_adv_buf_cnt);
|
||||
@@ -938,6 +1035,7 @@ static int adv_create_and_start(const struct shell *shell, uint8_t big_index)
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_INF("Populating periodic Advertising for big %d", big_index);
|
||||
ret = per_adv_populate(big_index, &per_adv_data[big_index], &per_adv_buf[big_index], 1,
|
||||
&per_adv_buf_cnt);
|
||||
if (ret) {
|
||||
@@ -945,6 +1043,7 @@ static int adv_create_and_start(const struct shell *shell, uint8_t big_index)
|
||||
}
|
||||
|
||||
/* Start broadcaster */
|
||||
LOG_INF("Starting the Advertiser for big %d", big_index);
|
||||
ret = bt_mgmt_adv_start(big_index, ext_adv_buf[big_index], ext_adv_buf_cnt,
|
||||
&per_adv_buf[big_index], per_adv_buf_cnt, false);
|
||||
if (ret) {
|
||||
@@ -1053,12 +1152,13 @@ static int big_enable(const struct shell *shell, uint8_t big_index)
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_INF("starting advertising for BIG %d", big_index);
|
||||
ret = adv_create_and_start(shell, big_index);
|
||||
if (ret) {
|
||||
shell_error(shell, "Failed to start advertising for BIG%d: %d", big_index, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_INF("Advertising started for BIG %d", big_index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1096,6 +1196,103 @@ static int cmd_start(const struct shell *shell, size_t argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_start_idx(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
uint8_t big_index;
|
||||
|
||||
big_index = (uint8_t)atoi(argv[1]);
|
||||
LOG_INF("Enable big %d", big_index);
|
||||
ret = big_enable(shell, big_index);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
led_blink(LED_APP_RGB, LED_COLOR_GREEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enable_broadcast_source_only(const struct shell *shell, uint8_t big_index)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (big_index >= CONFIG_BT_ISO_MAX_BIG) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((broadcast_param[big_index].subgroups == NULL) ||
|
||||
(broadcast_param[big_index].num_subgroups == 0)) {
|
||||
LOG_ERR("No subgroups defined for BIG%d", big_index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (broadcast_source_is_streaming(big_index)) {
|
||||
LOG_WRN("BIG %d is already streaming", big_index);
|
||||
/* Do not return error code as this might be called from a for-loop */
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = broadcast_source_enable(&broadcast_param[big_index], big_index);
|
||||
if (ret) {
|
||||
shell_error(shell, "Failed to enable broadcaster: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_broadcast_source_enable(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (argc == 2) {
|
||||
uint8_t big_index;
|
||||
|
||||
ret = argv_to_indexes(shell, argc, argv, &big_index, 1, NULL, 0);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = enable_broadcast_source_only(shell, big_index);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < CONFIG_BT_ISO_MAX_BIG; i++) {
|
||||
if (broadcast_param[i].subgroups != NULL ||
|
||||
broadcast_param[i].num_subgroups > 0) {
|
||||
ret = enable_broadcast_source_only(shell, i);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
led_blink(LED_APP_RGB, LED_COLOR_GREEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broadcaster_source_disable(const struct shell *shell, uint8_t big_index)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!broadcast_source_is_streaming(big_index)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = broadcast_source_disable(big_index);
|
||||
if (ret) {
|
||||
shell_error(shell, "Failed to stop broadcaster(s) %d", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int broadcaster_stop(const struct shell *shell, uint8_t big_index)
|
||||
{
|
||||
int ret;
|
||||
@@ -1121,14 +1318,24 @@ static int broadcaster_stop(const struct shell *shell, uint8_t big_index)
|
||||
shell_error(shell, "Failed to stop extended advertiser");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (big_index == 0) {
|
||||
net_buf_simple_reset(&base_data0);
|
||||
net_buf_simple_reset(&uuid_data0);
|
||||
} else if (big_index == 1) {
|
||||
net_buf_simple_reset(&base_data1);
|
||||
net_buf_simple_reset(&uuid_data1);
|
||||
} else {
|
||||
} else if (big_index == 2) {
|
||||
net_buf_simple_reset(&base_data2);
|
||||
net_buf_simple_reset(&uuid_data2);
|
||||
} else if (big_index == 3) {
|
||||
net_buf_simple_reset(&base_data3);
|
||||
net_buf_simple_reset(&uuid_data3);
|
||||
} else if (big_index == 4) {
|
||||
net_buf_simple_reset(&base_data4);
|
||||
net_buf_simple_reset(&uuid_data4);
|
||||
}
|
||||
else {
|
||||
LOG_ERR("Stopping the broadcast source failed, big index %d out of range", big_index);
|
||||
shell_error(shell, "BIG index out of range");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1146,6 +1353,38 @@ static int broadcaster_stop(const struct shell *shell, uint8_t big_index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_broadcast_source_disable(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (argc == 2) {
|
||||
uint8_t big_index;
|
||||
|
||||
ret = argv_to_indexes(shell, argc, argv, &big_index, 1, NULL, 0);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = broadcaster_source_disable(shell, big_index);
|
||||
|
||||
} else {
|
||||
for (size_t i = 0; i < CONFIG_BT_ISO_MAX_BIG; i++) {
|
||||
if (broadcast_param[i].subgroups != NULL) {
|
||||
ret = broadcaster_source_disable(shell, i);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
led_on(LED_APP_RGB, LED_COLOR_GREEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_stop(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
@@ -1780,7 +2019,120 @@ static int cmd_file_select(const struct shell *shell, size_t argc, char **argv)
|
||||
|
||||
ret = lc3_streamer_stream_register(
|
||||
file_name, &lc3_stream_infos[big_index][sub_index].lc3_streamer_idx[bis_index],
|
||||
true);
|
||||
true); // TODO: set this to false and only loop once with a dedicated command
|
||||
if (ret) {
|
||||
shell_error(shell, "Failed to register stream: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
lc3_stream_infos[big_index][sub_index].frame_size =
|
||||
broadcast_param[big_index].subgroups[sub_index].group_lc3_preset.qos.sdu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_stream_close(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
uint8_t big_index;
|
||||
uint8_t sub_index;
|
||||
uint8_t bis_index;
|
||||
|
||||
ret = argv_to_indexes(shell, argc, argv, &big_index, 1, &sub_index, 2);
|
||||
if (ret) {
|
||||
shell_error(shell, "Failed to get indexes: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
bis_index = (uint8_t)atoi(argv[3]);
|
||||
|
||||
ret = lc3_streamer_stream_close(lc3_stream_infos[big_index][sub_index].lc3_streamer_idx[bis_index]);
|
||||
|
||||
}
|
||||
static int cmd_file_select_play_once(const struct shell *shell, size_t argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
uint8_t big_index;
|
||||
uint8_t sub_index;
|
||||
uint8_t bis_index;
|
||||
|
||||
if (!sd_card_present) {
|
||||
shell_error(shell, "No SD card present: files cannot be selected");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (argc != 5) {
|
||||
shell_error(shell,
|
||||
"Usage: nac file select <file path> <BIG index> <subgroup index> "
|
||||
"<BIS index>");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = argv_to_indexes(shell, argc, argv, &big_index, 2, &sub_index, 3);
|
||||
if (ret) {
|
||||
shell_error(shell, "Failed to get indexes: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// bis_index = (uint8_t)atoi(argv[4]);
|
||||
// ret = lc3_streamer_stream_close(lc3_stream_infos[big_index][sub_index].lc3_streamer_idx[bis_index]);
|
||||
// if (ret) {
|
||||
// shell_error(shell, "Failed to close stream: %d", ret);
|
||||
// return ret;
|
||||
// }
|
||||
|
||||
if (!is_number(argv[4])) {
|
||||
shell_error(shell, "BIS index must be a digit");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bis_index = (uint8_t)atoi(argv[4]);
|
||||
|
||||
if ((bis_index >= CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT) ||
|
||||
(bis_index >= broadcast_param[big_index].subgroups[sub_index].num_bises)) {
|
||||
shell_error(shell, "BIS index %d is out of range (max %d)", bis_index,
|
||||
broadcast_param[big_index].subgroups[sub_index].num_bises - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
char *file_name = argv[1];
|
||||
|
||||
LOG_DBG("Selecting file %s for stream big: %d sub: %d bis: %d", file_name, big_index,
|
||||
sub_index, bis_index);
|
||||
|
||||
struct bt_audio_codec_cfg *codec_cfg =
|
||||
&broadcast_param[big_index].subgroups[sub_index].group_lc3_preset.codec_cfg;
|
||||
|
||||
struct lc3_stream_cfg cfg;
|
||||
|
||||
ret = le_audio_freq_hz_get(codec_cfg, &cfg.sample_rate_hz);
|
||||
if (ret) {
|
||||
shell_error(shell, "Failed to get frequency: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = le_audio_duration_us_get(codec_cfg, &cfg.frame_duration_us);
|
||||
if (ret) {
|
||||
shell_error(shell, "Failed to get frame duration: %d", ret);
|
||||
}
|
||||
|
||||
ret = le_audio_bitrate_get(codec_cfg, &cfg.bit_rate_bps);
|
||||
if (ret) {
|
||||
shell_error(shell, "Failed to get bit rate: %d", ret);
|
||||
}
|
||||
|
||||
/* Verify that the file header matches the stream configurationn */
|
||||
/* NOTE: This will not abort the streamer if the file is not valid, only give a warning */
|
||||
bool header_valid = lc3_streamer_file_compatible_check(file_name, &cfg);
|
||||
|
||||
if (!header_valid) {
|
||||
shell_warn(shell, "File header verification failed. File may not be compatible "
|
||||
"with stream config.");
|
||||
}
|
||||
|
||||
ret = lc3_streamer_stream_register(
|
||||
file_name, &lc3_stream_infos[big_index][sub_index].lc3_streamer_idx[bis_index],
|
||||
false); // TODO: set this to false and only loop once with a dedicated command
|
||||
if (ret) {
|
||||
shell_error(shell, "Failed to register stream: %d", ret);
|
||||
return ret;
|
||||
@@ -2603,6 +2955,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_file_cmd,
|
||||
/* 5 required arguments */
|
||||
SHELL_CMD_ARG(select, &folder_names, "Select file on SD card",
|
||||
cmd_file_select, 5, 0),
|
||||
SHELL_CMD_ARG(select_play_once, &folder_names, "Select file on SD card",
|
||||
cmd_file_select_play_once, 5, 0),
|
||||
SHELL_CMD_ARG(stream_close, &folder_names, "Select file on SD card",
|
||||
cmd_stream_close, 4, 0),
|
||||
SHELL_SUBCMD_SET_END);
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(
|
||||
@@ -2617,6 +2973,13 @@ SHELL_STATIC_SUBCMD_SET_CREATE(
|
||||
configuration_cmd, SHELL_COND_CMD(CONFIG_SHELL, list, NULL, "List presets", cmd_list),
|
||||
SHELL_COND_CMD(CONFIG_SHELL, start, NULL, "Start broadcaster", cmd_start),
|
||||
SHELL_COND_CMD(CONFIG_SHELL, stop, NULL, "Stop broadcaster", cmd_stop),
|
||||
SHELL_COND_CMD(CONFIG_SHELL, start_idx, NULL, "Start broadcaster with index", cmd_start_idx),
|
||||
SHELL_COND_CMD(CONFIG_SHELL, source_disable, NULL, "Disable broadcast source", cmd_broadcast_source_disable),
|
||||
SHELL_COND_CMD(CONFIG_SHELL, source_enable, NULL, "Enable broadcast source", cmd_broadcast_source_enable),
|
||||
SHELL_COND_CMD(CONFIG_SHELL, stream_close, NULL, "Close lc3 stream", cmd_stream_close),
|
||||
SHELL_COND_CMD(CONFIG_SHELL, en_usb_mass, NULL, "Enable usb mass storage device", cmd_usb_mass_enable),
|
||||
|
||||
|
||||
SHELL_COND_CMD(CONFIG_SHELL, show, NULL, "Show current configuration", cmd_show),
|
||||
SHELL_COND_CMD(CONFIG_SHELL, packing, NULL, "Set type of packing", cmd_packing),
|
||||
SHELL_COND_CMD(CONFIG_SHELL, preset, NULL, "Set preset", cmd_preset),
|
||||
|
||||
@@ -19,9 +19,9 @@ CONFIG_BT_ISO_BROADCASTER=y
|
||||
CONFIG_BT_ISO_SYNC_RECEIVER=n
|
||||
CONFIG_BT_EXT_ADV=y
|
||||
|
||||
CONFIG_BT_CTLR_ADV_SET=2
|
||||
CONFIG_BT_EXT_ADV_MAX_ADV_SET=2
|
||||
CONFIG_BT_CTLR_ADV_ISO_SET=2
|
||||
CONFIG_BT_CTLR_ADV_SET=5
|
||||
CONFIG_BT_EXT_ADV_MAX_ADV_SET=5
|
||||
CONFIG_BT_CTLR_ADV_ISO_SET=5
|
||||
CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=8
|
||||
|
||||
CONFIG_BT_MAX_CONN=1
|
||||
|
||||
Reference in New Issue
Block a user