Skip to content

Commit

Permalink
Merge pull request #2105 from kholia/cdc_uac2_example
Browse files Browse the repository at this point in the history
Add CDC+UAC2 composite device example for Pico
  • Loading branch information
hathach authored Aug 3, 2023
2 parents e5b1718 + d89fc07 commit d91869a
Show file tree
Hide file tree
Showing 11 changed files with 1,162 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/device/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ family_add_subdirectory(board_test)
family_add_subdirectory(cdc_dual_ports)
family_add_subdirectory(cdc_msc)
family_add_subdirectory(cdc_msc_freertos)
family_add_subdirectory(cdc_uac2)
family_add_subdirectory(dfu)
family_add_subdirectory(dfu_runtime)
family_add_subdirectory(dynamic_configuration)
Expand Down
38 changes: 38 additions & 0 deletions examples/device/cdc_uac2/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
cmake_minimum_required(VERSION 3.17)

include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)

# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})

project(${PROJECT} C CXX ASM)

# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})

# Espressif has its own cmake build system
if(FAMILY STREQUAL "espressif")
return()
endif()

add_executable(${PROJECT})

# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/uac2_app.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
)

# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)

# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
family_configure_device_example(${PROJECT} noos)

# Uncomment me to enable UART based debugging
# pico_enable_stdio_uart(${PROJECT} 1)
16 changes: 16 additions & 0 deletions examples/device/cdc_uac2/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
include ../../make.mk

INC += \
src \
$(TOP)/hw \

# Example source
EXAMPLE_SOURCE += \
src/cdc_app.c \
src/main.c \
src/uac2_app.c \
src/usb_descriptors.c \

SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))

include ../../rules.mk
52 changes: 52 additions & 0 deletions examples/device/cdc_uac2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#### Composite CDC + UAC2 on Pico

This example provides a composite CDC + UAC2 device on top of a Raspberry Pi
Pico board.


#### Use Cases

- The CDC + UAC2 composite device happens to be important, especially in the
amateur radio community.

Modern radios (`rigs`) like Icom IC-7300 + IC-705 expose a sound card and a
serial device (`composite device`) to the computer over a single USB cable.
This allows for Audio I/O and CAT control over a single USB cable which is
very convenient.

By including and maintaining this example in TinyUSB repository, we enable
the amateur radio community to build (`homebrew`) radios with similar
functionality as the (expensive) commercial rigs.

This PR is important in bridging this specific gap between the commercial
rigs and homebrew equipment.

- https://digirig.net/digirig-mobile-rev-1-9/ is a digital interface for
interfacing radios (that lack an inbuilt digital interface) with computers.
Digirig Mobile works brilliantly (is OSS!) and is a big improvement over
traditional digital interfaces (like the SignaLink USB Interface). By using a
Raspberry Pi Pico powered CDC + UAC2 composite device, we can simplify the
Digirig Mobile schematic, drastically reduce the manufacturing cost, and
(again) enable the homebrewers community to homebrew a modern digital interface
with ease themselves.


#### Build Steps

```
cd examples/device/cdc_uac2
export PICO_SDK_PATH=$HOME/pico-sdk
cmake -DFAMILY=rp2040 pico .
cmake -DFAMILY=rp2040 -DCMAKE_BUILD_TYPE=Debug # use this for debugging
make BOARD=raspberry_pi_pico all
```


#### Development Notes

Please try to keep this code synchronized with the `uac2_headset` example
included in this repository.
72 changes: 72 additions & 0 deletions examples/device/cdc_uac2/src/cdc_app.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
* Copyright (c) 2022 Angel Molina ([email protected])
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

#include "bsp/board.h"
#include "tusb.h"
#include "common.h"

// Invoked when cdc when line state changed e.g connected/disconnected
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
{
(void) itf;
(void) rts;

if (dtr)
{
// Terminal connected
}
else
{
// Terminal disconnected
}
}

// Invoked when CDC interface received data from host
void tud_cdc_rx_cb(uint8_t itf)
{
uint8_t buf[64];
uint32_t count;

// connected() check for DTR bit
// Most but not all terminal client set this when making connection
if (tud_cdc_connected())
{
if (tud_cdc_available()) // data is available
{
count = tud_cdc_n_read(itf, buf, sizeof(buf));
(void) count;

tud_cdc_n_write(itf, buf, count);
tud_cdc_n_write_flush(itf);
// dummy code to check that cdc serial is responding
board_led_write(0);
board_delay(50);
board_led_write(1);
board_delay(50);
board_led_write(0);
}
}
}
34 changes: 34 additions & 0 deletions examples/device/cdc_uac2/src/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef __COMMON_H__
#define __COMMON_H__

/* Blink pattern
* - 25 ms : streaming data
* - 250 ms : device not mounted
* - 1000 ms : device mounted
* - 2500 ms : device is suspended
*/
enum
{
BLINK_STREAMING = 25,
BLINK_NOT_MOUNTED = 250,
BLINK_MOUNTED = 1000,
BLINK_SUSPENDED = 2500,
};

enum
{
VOLUME_CTRL_0_DB = 0,
VOLUME_CTRL_10_DB = 2560,
VOLUME_CTRL_20_DB = 5120,
VOLUME_CTRL_30_DB = 7680,
VOLUME_CTRL_40_DB = 10240,
VOLUME_CTRL_50_DB = 12800,
VOLUME_CTRL_60_DB = 15360,
VOLUME_CTRL_70_DB = 17920,
VOLUME_CTRL_80_DB = 20480,
VOLUME_CTRL_90_DB = 23040,
VOLUME_CTRL_100_DB = 25600,
VOLUME_CTRL_SILENCE = 0x8000,
};

#endif
99 changes: 99 additions & 0 deletions examples/device/cdc_uac2/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jerzy Kasenberg
* Copyright (c) 2022 Angel Molina <[email protected]>
* Copyright (c) 2023 Dhiru Kholia <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

#include <stdio.h>
#include <string.h>

#include "bsp/board.h"
#include "tusb.h"
#include "common.h"

extern uint32_t blink_interval_ms;

#if (CFG_TUSB_MCU == OPT_MCU_RP2040)
#include "pico/stdlib.h"
#endif

void led_blinking_task(void);

/*------------- MAIN -------------*/
int main(void)
{
board_init();

// init device stack on configured roothub port
tud_init(BOARD_TUD_RHPORT);

#if (CFG_TUSB_MCU == OPT_MCU_RP2040)
stdio_init_all();
#endif

TU_LOG1("CDC UAC2 example running\r\n");

while (1)
{
tud_task(); // TinyUSB device task
led_blinking_task();

#if (CFG_TUSB_MCU == OPT_MCU_RP2040)
// printf("Hello, world!\n");
#endif
}

return 0;
}

//--------------------------------------------------------------------+
// Device callbacks
//--------------------------------------------------------------------+

// Invoked when device is mounted
void tud_mount_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
}

// Invoked when device is unmounted
void tud_umount_cb(void)
{
blink_interval_ms = BLINK_NOT_MOUNTED;
}

// Invoked when usb bus is suspended
// remote_wakeup_en : if host allow us to perform remote wakeup
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
void tud_suspend_cb(bool remote_wakeup_en)
{
(void)remote_wakeup_en;
blink_interval_ms = BLINK_SUSPENDED;
}

// Invoked when usb bus is resumed
void tud_resume_cb(void)
{
blink_interval_ms = BLINK_MOUNTED;
}
Loading

0 comments on commit d91869a

Please sign in to comment.