Bluetooth: CCP: Introduce new CCP API
The CCP API for the Call Control Profile works on top of the TBS API, and will eventually replace parts of the TBS API. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
05c167e0b8
commit
e45830893f
48 changed files with 1758 additions and 230 deletions
|
|
@ -401,6 +401,7 @@ Bluetooth Host:
|
||||||
- doc/connectivity/bluetooth/shell/audio/
|
- doc/connectivity/bluetooth/shell/audio/
|
||||||
- samples/bluetooth/bap*/
|
- samples/bluetooth/bap*/
|
||||||
- samples/bluetooth/cap*/
|
- samples/bluetooth/cap*/
|
||||||
|
- samples/bluetooth/ccp*/
|
||||||
- samples/bluetooth/hap*/
|
- samples/bluetooth/hap*/
|
||||||
- samples/bluetooth/hci_*/
|
- samples/bluetooth/hci_*/
|
||||||
- samples/bluetooth/pbp*/
|
- samples/bluetooth/pbp*/
|
||||||
|
|
@ -484,6 +485,7 @@ Bluetooth Audio:
|
||||||
- doc/connectivity/bluetooth/shell/audio/
|
- doc/connectivity/bluetooth/shell/audio/
|
||||||
- samples/bluetooth/bap*/
|
- samples/bluetooth/bap*/
|
||||||
- samples/bluetooth/cap*/
|
- samples/bluetooth/cap*/
|
||||||
|
- samples/bluetooth/ccp*/
|
||||||
- samples/bluetooth/hap*/
|
- samples/bluetooth/hap*/
|
||||||
- samples/bluetooth/pbp*/
|
- samples/bluetooth/pbp*/
|
||||||
- samples/bluetooth/tmap*/
|
- samples/bluetooth/tmap*/
|
||||||
|
|
|
||||||
|
|
@ -294,6 +294,7 @@ GAF and the top layer profiles gave been implemented in Zephyr with the followin
|
||||||
cluster=true;
|
cluster=true;
|
||||||
label="CCP";
|
label="CCP";
|
||||||
style=solid;
|
style=solid;
|
||||||
|
CCP_H [label="ccp.h"];
|
||||||
TBS_H [label="tbs.h"];
|
TBS_H [label="tbs.h"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -331,6 +332,7 @@ GAF and the top layer profiles gave been implemented in Zephyr with the followin
|
||||||
CAP_H -> MCS_H;
|
CAP_H -> MCS_H;
|
||||||
CAP_H -> MCC_H;
|
CAP_H -> MCC_H;
|
||||||
CAP_H -> MP_H;
|
CAP_H -> MP_H;
|
||||||
|
CAP_H -> CCP_H;
|
||||||
CAP_H -> TBS_H;
|
CAP_H -> TBS_H;
|
||||||
CAP_H -> BAP_H;
|
CAP_H -> BAP_H;
|
||||||
CAP_H -> BAP_PRESET_H;
|
CAP_H -> BAP_PRESET_H;
|
||||||
|
|
@ -341,6 +343,7 @@ GAF and the top layer profiles gave been implemented in Zephyr with the followin
|
||||||
CSIP_H -> MCS_H;
|
CSIP_H -> MCS_H;
|
||||||
CSIP_H -> MCC_H;
|
CSIP_H -> MCC_H;
|
||||||
CSIP_H -> MP_H;
|
CSIP_H -> MP_H;
|
||||||
|
CSIP_H -> CCP_H;
|
||||||
CSIP_H -> TBS_H;
|
CSIP_H -> TBS_H;
|
||||||
CSIP_H -> BAP_H;
|
CSIP_H -> BAP_H;
|
||||||
CSIP_H -> BAP_PRESET_H;
|
CSIP_H -> BAP_PRESET_H;
|
||||||
|
|
@ -719,8 +722,8 @@ Bluetooth Audio Stack.
|
||||||
| | | | | - Shell Module | |
|
| | | | | - Shell Module | |
|
||||||
| | | | | - BSIM test | |
|
| | | | | - BSIM test | |
|
||||||
+--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+
|
+--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+
|
||||||
| CCP | Call Control Server | 1.0 | 3.0 | - Feature complete | - API refactor |
|
| CCP | Call Control Server | 1.0 | 3.0 | - Feature complete | - API refactor (in progress) |
|
||||||
| | | | | - Shell Module | - Sample Application |
|
| | | | | - Shell Module | - Sample Application (in progress) |
|
||||||
| | | | | - BSIM test | |
|
| | | | | - BSIM test | |
|
||||||
| +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+
|
| +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+
|
||||||
| | Call Control Client | 1.0 | 3.0 | - Feature complete | - API refactor |
|
| | Call Control Client | 1.0 | 3.0 | - Feature complete | - API refactor |
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ For specific Bluetooth functionality see also the following shell documentation
|
||||||
shell/audio/csip.rst
|
shell/audio/csip.rst
|
||||||
shell/audio/gmap.rst
|
shell/audio/gmap.rst
|
||||||
shell/audio/mcp.rst
|
shell/audio/mcp.rst
|
||||||
|
shell/audio/tbs.rst
|
||||||
shell/audio/tmap.rst
|
shell/audio/tmap.rst
|
||||||
shell/audio/pbp.rst
|
shell/audio/pbp.rst
|
||||||
shell/classic/a2dp.rst
|
shell/classic/a2dp.rst
|
||||||
|
|
|
||||||
|
|
@ -1,208 +1,24 @@
|
||||||
Bluetooth: Call Control Profile Shell
|
Bluetooth: Call Control Profile Shell
|
||||||
#####################################
|
#####################################
|
||||||
|
|
||||||
This document describes how to run the call control functionality, both as
|
Call Control Server
|
||||||
a client and as a (telephone bearer service (TBS)) server. Note that in the
|
*******************
|
||||||
examples below, some lines of debug have been removed to make this shorter
|
The Call Control Server is a role that typically resides on devices that can make calls,
|
||||||
and provide a better overview.
|
including calls from apps such as Skype, e.g. (smart)phones and PCs,
|
||||||
|
which are typically GAP Central devices.
|
||||||
|
|
||||||
Telephone Bearer Service Client
|
Using the Call Control Server
|
||||||
*******************************
|
=============================
|
||||||
|
The Server can be controlled locally, or by a remote device (when in a call). For
|
||||||
The telephone bearer service client will typically exist on a resource
|
example a remote device may initiate a call to the server,
|
||||||
restricted device, such as headphones, but may also exist on e.g. phones or
|
or the Server may initiate a call to remote device, without a client.
|
||||||
laptops. The call control client will also thus typically be the advertiser.
|
|
||||||
The client can control the states of calls on a server using the call control
|
|
||||||
point.
|
|
||||||
|
|
||||||
It is necessary to have :kconfig:option:`CONFIG_BT_TBS_CLIENT_LOG_LEVEL_DBG`
|
|
||||||
enabled for using the client interactively.
|
|
||||||
|
|
||||||
Using the telephone bearer service client
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
When the Bluetooth stack has been initialized (:code:`bt init`),
|
|
||||||
and a device has been connected, the telephone bearer service client can
|
|
||||||
discover TBS on the connected device calling :code:`tbs_client discover`, which
|
|
||||||
will start a discovery for the TBS UUIDs and store the handles, and optionally
|
|
||||||
subscribe to all notifications (default is to subscribe to all).
|
|
||||||
|
|
||||||
Since a server may have multiple TBS instances, most of the tbs_client commands
|
|
||||||
will take an index (starting from 0) as input. Joining calls require at least 2
|
|
||||||
call IDs, and all call indexes shall be on the same TBS instance.
|
|
||||||
|
|
||||||
A server will also have a GTBS instance, which is an abstraction layer for all
|
|
||||||
the telephone bearers on the server. If the server has both GTBS and TBS,
|
|
||||||
the client may subscribe and use either when sending requests if
|
|
||||||
:code:`BT_TBS_CLIENT_GTBS` is enabled.
|
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
tbs_client --help
|
ccp_call_control_server --help
|
||||||
tbs_client - Bluetooth TBS_CLIENT shell commands
|
ccp_call_control_server - Bluetooth CCP Call Control Server shell commands
|
||||||
Subcommands:
|
Subcommands:
|
||||||
discover :Discover TBS [subscribe]
|
init : Initialize CCP Call Control Server
|
||||||
set_signal_reporting_interval :Set the signal reporting interval
|
|
||||||
[<{instance_index, gtbs}>] <interval>
|
|
||||||
originate :Originate a call [<{instance_index, gtbs}>]
|
|
||||||
<uri>
|
|
||||||
terminate :terminate a call [<{instance_index, gtbs}>]
|
|
||||||
<id>
|
|
||||||
accept :Accept a call [<{instance_index, gtbs}>] <id>
|
|
||||||
hold :Place a call on hold [<{instance_index,
|
|
||||||
gtbs}>] <id>
|
|
||||||
retrieve :Retrieve a held call [<{instance_index,
|
|
||||||
gtbs}>] <id>
|
|
||||||
read_provider_name :Read the bearer name [<{instance_index,
|
|
||||||
gtbs}>]
|
|
||||||
read_bearer_uci :Read the bearer UCI [<{instance_index, gtbs}>]
|
|
||||||
read_technology :Read the bearer technology [<{instance_index,
|
|
||||||
gtbs}>]
|
|
||||||
read_uri_list :Read the bearer's supported URI list
|
|
||||||
[<{instance_index, gtbs}>]
|
|
||||||
read_signal_strength :Read the bearer signal strength
|
|
||||||
[<{instance_index, gtbs}>]
|
|
||||||
read_signal_interval :Read the bearer signal strength reporting
|
|
||||||
interval [<{instance_index, gtbs}>]
|
|
||||||
read_current_calls :Read the current calls [<{instance_index,
|
|
||||||
gtbs}>]
|
|
||||||
read_ccid :Read the CCID [<{instance_index, gtbs}>]
|
|
||||||
read_status_flags :Read the in feature and status value
|
|
||||||
[<{instance_index, gtbs}>]
|
|
||||||
read_uri :Read the incoming call target URI
|
|
||||||
[<{instance_index, gtbs}>]
|
|
||||||
read_call_state :Read the call state [<{instance_index, gtbs}>]
|
|
||||||
read_remote_uri :Read the incoming remote URI
|
|
||||||
[<{instance_index, gtbs}>]
|
|
||||||
read_friendly_name :Read the friendly name of an incoming call
|
|
||||||
[<{instance_index, gtbs}>]
|
|
||||||
read_optional_opcodes :Read the optional opcodes [<{instance_index,
|
|
||||||
gtbs}>]
|
|
||||||
|
|
||||||
|
|
||||||
In the following examples, notifications from GTBS is ignored, unless otherwise
|
|
||||||
specified.
|
|
||||||
|
|
||||||
Example usage
|
|
||||||
=============
|
|
||||||
|
|
||||||
Setup
|
|
||||||
-----
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uart:~$ bt init
|
|
||||||
uart:~$ bt advertise on
|
|
||||||
Advertising started
|
|
||||||
|
|
||||||
When connected
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Placing a call:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uart:~$ tbs_client discover
|
|
||||||
<dbg> bt_tbs_client.primary_discover_func: Discover complete, found 1 instances (GTBS found)
|
|
||||||
<dbg> bt_tbs_client.discover_func: Setup complete for 1 / 1 TBS
|
|
||||||
<dbg> bt_tbs_client.discover_func: Setup complete GTBS
|
|
||||||
uart:~$ tbs_client originate 0 tel:123
|
|
||||||
<dbg> bt_tbs_client.notify_handler: Index 0
|
|
||||||
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the dialing state with URI tel:123
|
|
||||||
<dbg> bt_tbs_client.call_cp_notify_handler: Status: success for the originate opcode for call 0x00
|
|
||||||
<dbg> bt_tbs_client.notify_handler: Index 0
|
|
||||||
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the alerting state with URI tel:123
|
|
||||||
<call answered by peer device, and status notified by TBS server>
|
|
||||||
<dbg> bt_tbs_client.notify_handler: Index 0
|
|
||||||
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the active state with URI tel:123
|
|
||||||
|
|
||||||
Placing a call on GTBS:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uart:~$ tbs_client originate 0 tel:123
|
|
||||||
<dbg> bt_tbs_client.notify_handler: Index 0
|
|
||||||
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the dialing state with URI tel:123
|
|
||||||
<dbg> bt_tbs_client.call_cp_notify_handler: Status: success for the originate opcode for call 0x00
|
|
||||||
<dbg> bt_tbs_client.notify_handler: Index 0
|
|
||||||
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the alerting state with URI tel:123
|
|
||||||
<call answered by peer device, and status notified by TBS server>
|
|
||||||
<dbg> bt_tbs_client.notify_handler: Index 0
|
|
||||||
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the active state with URI tel:123
|
|
||||||
|
|
||||||
It is necessary to set an outgoing caller ID before placing a call.
|
|
||||||
|
|
||||||
Accepting incoming call from peer device:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
<dbg> bt_tbs_client.incoming_uri_notify_handler: tel:123
|
|
||||||
<dbg> bt_tbs_client.in_call_notify_handler: tel:456
|
|
||||||
<dbg> bt_tbs_client.friendly_name_notify_handler: Peter
|
|
||||||
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x05 is in the incoming state with URI tel:456
|
|
||||||
uart:~$ tbs_client accept 0 5
|
|
||||||
<dbg> bt_tbs_client.call_cp_callback_handler: Status: success for the accept opcode for call 0x05
|
|
||||||
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x05 is in the active state with URI tel
|
|
||||||
|
|
||||||
|
|
||||||
Terminate call:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uart:~$ tbs_client terminate 0 5
|
|
||||||
<dbg> bt_tbs_client.termination_reason_notify_handler: ID 0x05, reason 0x06
|
|
||||||
<dbg> bt_tbs_client.call_cp_notify_handler: Status: success for the terminate opcode for call 0x05
|
|
||||||
<dbg> bt_tbs_client.current_calls_notify_handler:
|
|
||||||
|
|
||||||
Telephone Bearer Service (TBS)
|
|
||||||
******************************
|
|
||||||
The telephone bearer service is a service that typically resides on devices that
|
|
||||||
can make calls, including calls from apps such as Skype, e.g. (smart)phones and
|
|
||||||
PCs.
|
|
||||||
|
|
||||||
It is necessary to have :kconfig:option:`CONFIG_BT_TBS_LOG_LEVEL_DBG` enabled
|
|
||||||
for using the TBS server interactively.
|
|
||||||
|
|
||||||
Using the telephone bearer service
|
|
||||||
==================================
|
|
||||||
TBS can be controlled locally, or by a remote device (when in a call). For
|
|
||||||
example a remote device may initiate a call to the device with the TBS server,
|
|
||||||
or the TBS server may initiate a call to remote device, without a TBS_CLIENT client.
|
|
||||||
The TBS implementation is capable of fully controlling any call.
|
|
||||||
Omitting an index for commands where a :code:`<instance_index>` can be supplied, defaults to the
|
|
||||||
GTBS bearer.
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
tbs --help
|
|
||||||
tbs - Bluetooth TBS shell commands
|
|
||||||
Subcommands:
|
|
||||||
init :Initialize TBS
|
|
||||||
authorize :Authorize the current connection
|
|
||||||
accept :Accept call <call_index>
|
|
||||||
terminate :Terminate call <call_index>
|
|
||||||
hold :Hold call <call_index>
|
|
||||||
retrieve :Retrieve call <call_index>
|
|
||||||
originate :Originate call [<instance_index>] <uri>
|
|
||||||
join :Join calls <id> <id> [<id> [<id> [...]]]
|
|
||||||
incoming :Simulate incoming remote call [<{instance_index,
|
|
||||||
gtbs}>] <local_uri> <remote_uri>
|
|
||||||
<remote_friendly_name>
|
|
||||||
remote_answer :Simulate remote answer outgoing call <call_index>
|
|
||||||
remote_retrieve :Simulate remote retrieve <call_index>
|
|
||||||
remote_terminate :Simulate remote terminate <call_index>
|
|
||||||
remote_hold :Simulate remote hold <call_index>
|
|
||||||
set_bearer_provider_name :Set the bearer provider name [<{instance_index,
|
|
||||||
gtbs}>] <name>
|
|
||||||
set_bearer_technology :Set the bearer technology [<{instance_index,
|
|
||||||
gtbs}>] <technology>
|
|
||||||
set_bearer_signal_strength :Set the bearer signal strength [<{instance_index,
|
|
||||||
gtbs}>] <strength>
|
|
||||||
set_status_flags :Set the bearer feature and status value
|
|
||||||
[<{instance_index, gtbs}>] <feature_and_status>
|
|
||||||
set_uri_scheme :Set the URI prefix list <bearer_idx> <uri1 [uri2
|
|
||||||
[uri3 [...]]]>
|
|
||||||
print_calls :Output all calls in the debug log
|
|
||||||
|
|
||||||
Example Usage
|
Example Usage
|
||||||
=============
|
=============
|
||||||
|
|
@ -213,26 +29,7 @@ Setup
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
uart:~$ bt init
|
uart:~$ bt init
|
||||||
|
uart:~$ ccp_call_control_server init
|
||||||
|
Registered GTBS bearer
|
||||||
|
Registered bearer[1]
|
||||||
uart:~$ bt connect xx:xx:xx:xx:xx:xx public
|
uart:~$ bt connect xx:xx:xx:xx:xx:xx public
|
||||||
|
|
||||||
When connected
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Answering a call for a peer device originated by a client:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
<dbg> bt_tbs.write_call_cp: Index 0: Processing the originate opcode
|
|
||||||
<dbg> bt_tbs.originate_call: New call with call index 1
|
|
||||||
<dbg> bt_tbs.write_call_cp: Index 0: Processed the originate opcode with status success for call index 1
|
|
||||||
uart:~$ tbs remote_answer 1
|
|
||||||
TBS succeeded for call_id: 1
|
|
||||||
|
|
||||||
Incoming call from a peer device, accepted by client:
|
|
||||||
|
|
||||||
.. code-block:: console
|
|
||||||
|
|
||||||
uart:~$ tbs incoming 0 tel:123 tel:456 Peter
|
|
||||||
TBS succeeded for call_id: 4
|
|
||||||
<dbg> bt_tbs.bt_tbs_remote_incoming: New call with call index 4
|
|
||||||
<dbg> bt_tbs.write_call_cp: Index 0: Processed the accept opcode with status success for call index 4
|
|
||||||
|
|
|
||||||
237
doc/connectivity/bluetooth/shell/audio/tbs.rst
Normal file
237
doc/connectivity/bluetooth/shell/audio/tbs.rst
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
Bluetooth: Telephone Bearer Service Shell
|
||||||
|
#########################################
|
||||||
|
|
||||||
|
This document describes how to run the call control functionality, both as
|
||||||
|
a client and as a (telephone bearer service (TBS)) server. Note that in the
|
||||||
|
examples below, some lines of debug have been removed to make this shorter
|
||||||
|
and provide a better overview.
|
||||||
|
|
||||||
|
Telephone Bearer Service Client
|
||||||
|
*******************************
|
||||||
|
|
||||||
|
The telephone bearer service client will typically exist on a resource
|
||||||
|
restricted device, such as headphones, but may also exist on e.g. phones or
|
||||||
|
laptops. The call control client will also thus typically be the advertiser.
|
||||||
|
The client can control the states of calls on a server using the call control
|
||||||
|
point.
|
||||||
|
|
||||||
|
It is necessary to have :kconfig:option:`CONFIG_BT_TBS_CLIENT_LOG_LEVEL_DBG`
|
||||||
|
enabled for using the client interactively.
|
||||||
|
|
||||||
|
Using the telephone bearer service client
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
When the Bluetooth stack has been initialized (:code:`bt init`),
|
||||||
|
and a device has been connected, the telephone bearer service client can
|
||||||
|
discover TBS on the connected device calling :code:`tbs_client discover`, which
|
||||||
|
will start a discovery for the TBS UUIDs and store the handles, and optionally
|
||||||
|
subscribe to all notifications (default is to subscribe to all).
|
||||||
|
|
||||||
|
Since a server may have multiple TBS instances, most of the tbs_client commands
|
||||||
|
will take an index (starting from 0) as input. Joining calls require at least 2
|
||||||
|
call IDs, and all call indexes shall be on the same TBS instance.
|
||||||
|
|
||||||
|
A server will also have a GTBS instance, which is an abstraction layer for all
|
||||||
|
the telephone bearers on the server. If the server has both GTBS and TBS,
|
||||||
|
the client may subscribe and use either when sending requests if
|
||||||
|
:code:`BT_TBS_CLIENT_GTBS` is enabled.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
tbs_client --help
|
||||||
|
tbs_client - Bluetooth TBS_CLIENT shell commands
|
||||||
|
Subcommands:
|
||||||
|
discover :Discover TBS [subscribe]
|
||||||
|
set_signal_reporting_interval :Set the signal reporting interval
|
||||||
|
[<{instance_index, gtbs}>] <interval>
|
||||||
|
originate :Originate a call [<{instance_index, gtbs}>]
|
||||||
|
<uri>
|
||||||
|
terminate :terminate a call [<{instance_index, gtbs}>]
|
||||||
|
<id>
|
||||||
|
accept :Accept a call [<{instance_index, gtbs}>] <id>
|
||||||
|
hold :Place a call on hold [<{instance_index,
|
||||||
|
gtbs}>] <id>
|
||||||
|
retrieve :Retrieve a held call [<{instance_index,
|
||||||
|
gtbs}>] <id>
|
||||||
|
read_provider_name :Read the bearer name [<{instance_index,
|
||||||
|
gtbs}>]
|
||||||
|
read_bearer_uci :Read the bearer UCI [<{instance_index, gtbs}>]
|
||||||
|
read_technology :Read the bearer technology [<{instance_index,
|
||||||
|
gtbs}>]
|
||||||
|
read_uri_list :Read the bearer's supported URI list
|
||||||
|
[<{instance_index, gtbs}>]
|
||||||
|
read_signal_strength :Read the bearer signal strength
|
||||||
|
[<{instance_index, gtbs}>]
|
||||||
|
read_signal_interval :Read the bearer signal strength reporting
|
||||||
|
interval [<{instance_index, gtbs}>]
|
||||||
|
read_current_calls :Read the current calls [<{instance_index,
|
||||||
|
gtbs}>]
|
||||||
|
read_ccid :Read the CCID [<{instance_index, gtbs}>]
|
||||||
|
read_status_flags :Read the in feature and status value
|
||||||
|
[<{instance_index, gtbs}>]
|
||||||
|
read_uri :Read the incoming call target URI
|
||||||
|
[<{instance_index, gtbs}>]
|
||||||
|
read_call_state :Read the call state [<{instance_index, gtbs}>]
|
||||||
|
read_remote_uri :Read the incoming remote URI
|
||||||
|
[<{instance_index, gtbs}>]
|
||||||
|
read_friendly_name :Read the friendly name of an incoming call
|
||||||
|
[<{instance_index, gtbs}>]
|
||||||
|
read_optional_opcodes :Read the optional opcodes [<{instance_index,
|
||||||
|
gtbs}>]
|
||||||
|
|
||||||
|
|
||||||
|
In the following examples, notifications from GTBS are ignored, unless otherwise specified.
|
||||||
|
|
||||||
|
Example usage
|
||||||
|
=============
|
||||||
|
|
||||||
|
Setup
|
||||||
|
-----
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uart:~$ bt init
|
||||||
|
uart:~$ bt advertise on
|
||||||
|
Advertising started
|
||||||
|
|
||||||
|
When connected
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Placing a call:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uart:~$ tbs_client discover
|
||||||
|
<dbg> bt_tbs_client.primary_discover_func: Discover complete, found 1 instances (GTBS found)
|
||||||
|
<dbg> bt_tbs_client.discover_func: Setup complete for 1 / 1 TBS
|
||||||
|
<dbg> bt_tbs_client.discover_func: Setup complete GTBS
|
||||||
|
uart:~$ tbs_client originate 0 tel:123
|
||||||
|
<dbg> bt_tbs_client.notify_handler: Index 0
|
||||||
|
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the dialing state with URI tel:123
|
||||||
|
<dbg> bt_tbs_client.call_cp_notify_handler: Status: success for the originate opcode for call 0x00
|
||||||
|
<dbg> bt_tbs_client.notify_handler: Index 0
|
||||||
|
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the alerting state with URI tel:123
|
||||||
|
<call answered by peer device, and status notified by TBS server>
|
||||||
|
<dbg> bt_tbs_client.notify_handler: Index 0
|
||||||
|
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the active state with URI tel:123
|
||||||
|
|
||||||
|
Placing a call on GTBS:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uart:~$ tbs_client originate 0 tel:123
|
||||||
|
<dbg> bt_tbs_client.notify_handler: Index 0
|
||||||
|
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the dialing state with URI tel:123
|
||||||
|
<dbg> bt_tbs_client.call_cp_notify_handler: Status: success for the originate opcode for call 0x00
|
||||||
|
<dbg> bt_tbs_client.notify_handler: Index 0
|
||||||
|
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the alerting state with URI tel:123
|
||||||
|
<call answered by peer device, and status notified by TBS server>
|
||||||
|
<dbg> bt_tbs_client.notify_handler: Index 0
|
||||||
|
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x01 is in the active state with URI tel:123
|
||||||
|
|
||||||
|
It is necessary to set an outgoing caller ID before placing a call.
|
||||||
|
|
||||||
|
Accepting incoming call from peer device:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
<dbg> bt_tbs_client.incoming_uri_notify_handler: tel:123
|
||||||
|
<dbg> bt_tbs_client.in_call_notify_handler: tel:456
|
||||||
|
<dbg> bt_tbs_client.friendly_name_notify_handler: Peter
|
||||||
|
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x05 is in the incoming state with URI tel:456
|
||||||
|
uart:~$ tbs_client accept 0 5
|
||||||
|
<dbg> bt_tbs_client.call_cp_callback_handler: Status: success for the accept opcode for call 0x05
|
||||||
|
<dbg> bt_tbs_client.current_calls_notify_handler: Call 0x05 is in the active state with URI tel
|
||||||
|
|
||||||
|
|
||||||
|
Terminate call:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uart:~$ tbs_client terminate 0 5
|
||||||
|
<dbg> bt_tbs_client.termination_reason_notify_handler: ID 0x05, reason 0x06
|
||||||
|
<dbg> bt_tbs_client.call_cp_notify_handler: Status: success for the terminate opcode for call 0x05
|
||||||
|
<dbg> bt_tbs_client.current_calls_notify_handler:
|
||||||
|
|
||||||
|
Telephone Bearer Service (TBS)
|
||||||
|
******************************
|
||||||
|
The telephone bearer service is a service that typically resides on devices that
|
||||||
|
can make calls, including calls from apps such as Skype, e.g. (smart)phones and
|
||||||
|
PCs.
|
||||||
|
|
||||||
|
It is necessary to have :kconfig:option:`CONFIG_BT_TBS_LOG_LEVEL_DBG` enabled
|
||||||
|
for using the TBS server interactively.
|
||||||
|
|
||||||
|
Using the telephone bearer service
|
||||||
|
==================================
|
||||||
|
TBS can be controlled locally, or by a remote device (when in a call). For
|
||||||
|
example a remote device may initiate a call to the device with the TBS server,
|
||||||
|
or the TBS server may initiate a call to remote device, without a TBS_CLIENT client.
|
||||||
|
The TBS implementation is capable of fully controlling any call.
|
||||||
|
Omitting an index for commands where a :code:`<instance_index>` can be supplied, defaults to the
|
||||||
|
GTBS bearer.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
tbs --help
|
||||||
|
tbs - Bluetooth TBS shell commands
|
||||||
|
Subcommands:
|
||||||
|
init :Initialize TBS
|
||||||
|
authorize :Authorize the current connection
|
||||||
|
accept :Accept call <call_index>
|
||||||
|
terminate :Terminate call <call_index>
|
||||||
|
hold :Hold call <call_index>
|
||||||
|
retrieve :Retrieve call <call_index>
|
||||||
|
originate :Originate call [<instance_index>] <uri>
|
||||||
|
join :Join calls <id> <id> [<id> [<id> [...]]]
|
||||||
|
incoming :Simulate incoming remote call [<{instance_index,
|
||||||
|
gtbs}>] <local_uri> <remote_uri>
|
||||||
|
<remote_friendly_name>
|
||||||
|
remote_answer :Simulate remote answer outgoing call <call_index>
|
||||||
|
remote_retrieve :Simulate remote retrieve <call_index>
|
||||||
|
remote_terminate :Simulate remote terminate <call_index>
|
||||||
|
remote_hold :Simulate remote hold <call_index>
|
||||||
|
set_bearer_provider_name :Set the bearer provider name [<{instance_index,
|
||||||
|
gtbs}>] <name>
|
||||||
|
set_bearer_technology :Set the bearer technology [<{instance_index,
|
||||||
|
gtbs}>] <technology>
|
||||||
|
set_bearer_signal_strength :Set the bearer signal strength [<{instance_index,
|
||||||
|
gtbs}>] <strength>
|
||||||
|
set_status_flags :Set the bearer feature and status value
|
||||||
|
[<{instance_index, gtbs}>] <feature_and_status>
|
||||||
|
set_uri_scheme :Set the URI prefix list <bearer_idx> <uri1 [uri2
|
||||||
|
[uri3 [...]]]>
|
||||||
|
print_calls :Output all calls in the debug log
|
||||||
|
|
||||||
|
Example Usage
|
||||||
|
=============
|
||||||
|
|
||||||
|
Setup
|
||||||
|
-----
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uart:~$ bt init
|
||||||
|
uart:~$ bt connect xx:xx:xx:xx:xx:xx public
|
||||||
|
|
||||||
|
When connected
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Answering a call for a peer device originated by a client:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
<dbg> bt_tbs.write_call_cp: Index 0: Processing the originate opcode
|
||||||
|
<dbg> bt_tbs.originate_call: New call with call index 1
|
||||||
|
<dbg> bt_tbs.write_call_cp: Index 0: Processed the originate opcode with status success for call index 1
|
||||||
|
uart:~$ tbs remote_answer 1
|
||||||
|
TBS succeeded for call_id: 1
|
||||||
|
|
||||||
|
Incoming call from a peer device, accepted by client:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
uart:~$ tbs incoming 0 tel:123 tel:456 Peter
|
||||||
|
TBS succeeded for call_id: 4
|
||||||
|
<dbg> bt_tbs.bt_tbs_remote_incoming: New call with call index 4
|
||||||
|
<dbg> bt_tbs.write_call_cp: Index 0: Processed the accept opcode with status success for call index 4
|
||||||
101
include/zephyr/bluetooth/audio/ccp.h
Normal file
101
include/zephyr/bluetooth/audio/ccp.h
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Bluetooth Call Control Profile (CCP) APIs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CCP_H_
|
||||||
|
#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CCP_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Call Control Profile (CCP)
|
||||||
|
*
|
||||||
|
* @defgroup bt_ccp Call Control Profile (CCP)
|
||||||
|
*
|
||||||
|
* @since 3.7
|
||||||
|
* @version 0.1.0
|
||||||
|
*
|
||||||
|
* @ingroup bluetooth
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* Call Control Profile (CCP) provides procedures to initiate and control calls.
|
||||||
|
* It provides the Call Control Client and the Call Control Server roles,
|
||||||
|
* where the former is usually placed on resource constrained devices like headphones,
|
||||||
|
* and the latter placed on more powerful devices like phones and PCs.
|
||||||
|
*
|
||||||
|
* The profile is not limited to carrier phone calls and can be used with common applications like
|
||||||
|
* Discord and Teams.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/bluetooth/audio/tbs.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @defgroup bt_ccp_call_control_server CCP Call Control Server APIs
|
||||||
|
* @ingroup bt_ccp
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** @brief Abstract Call Control Server Telephone Bearer structure. */
|
||||||
|
struct bt_ccp_call_control_server_bearer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register a Telephone Bearer
|
||||||
|
*
|
||||||
|
* This will register a Telephone Bearer Service (TBS) (or a Generic Telephone Bearer service
|
||||||
|
* (GTBS)) with the provided parameters.
|
||||||
|
*
|
||||||
|
* As per the TBS specification, the GTBS shall be instantiated for the feature,
|
||||||
|
* and as such a GTBS shall always be registered before any TBS can be registered.
|
||||||
|
* Similarly, all TBS shall be unregistered before the GTBS can be unregistered with
|
||||||
|
* bt_ccp_call_control_server_unregister_bearer().
|
||||||
|
*
|
||||||
|
* @param[in] param The parameters to initialize the bearer.
|
||||||
|
* @param[out] bearer Pointer to the initialized bearer.
|
||||||
|
*
|
||||||
|
* @retval 0 Success
|
||||||
|
* @retval -EINVAL @p param contains invalid data
|
||||||
|
* @retval -EALREADY @p param.gtbs is true and GTBS has already been registered
|
||||||
|
* @retval -EAGAIN @p param.gtbs is false and GTBS has not been registered
|
||||||
|
* @retval -ENOMEM @p param.gtbs is false and no more TBS can be registered (see
|
||||||
|
* @kconfig{CONFIG_BT_TBS_BEARER_COUNT})
|
||||||
|
* @retval -ENOEXEC The service failed to be registered
|
||||||
|
*/
|
||||||
|
int bt_ccp_call_control_server_register_bearer(const struct bt_tbs_register_param *param,
|
||||||
|
struct bt_ccp_call_control_server_bearer **bearer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregister a Telephone Bearer
|
||||||
|
*
|
||||||
|
* This will unregister a Telephone Bearer Service (TBS) (or a Generic Telephone Bearer service
|
||||||
|
* (GTBS)) with the provided parameters. The bearer shall be registered first by
|
||||||
|
* bt_ccp_call_control_server_register_bearer() before it can be unregistered.
|
||||||
|
*
|
||||||
|
* All TBS shall be unregistered before the GTBS can be unregistered with.
|
||||||
|
*
|
||||||
|
* @param bearer The bearer to unregister.
|
||||||
|
*
|
||||||
|
* @retval 0 Success
|
||||||
|
* @retval -EINVAL @p bearer is NULL
|
||||||
|
* @retval -EALREADY The bearer is not registered
|
||||||
|
* @retval -ENOEXEC The service failed to be unregistered
|
||||||
|
*/
|
||||||
|
int bt_ccp_call_control_server_unregister_bearer(struct bt_ccp_call_control_server_bearer *bearer);
|
||||||
|
|
||||||
|
/** @} */ /* End of group bt_ccp_call_control_server */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_CCP_H_ */
|
||||||
11
samples/bluetooth/ccp_call_control_server/CMakeLists.txt
Normal file
11
samples/bluetooth/ccp_call_control_server/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
project(ccp_call_control_server)
|
||||||
|
|
||||||
|
target_sources(app PRIVATE
|
||||||
|
src/main.c
|
||||||
|
)
|
||||||
|
|
||||||
|
zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)
|
||||||
15
samples/bluetooth/ccp_call_control_server/Kconfig.sysbuild
Normal file
15
samples/bluetooth/ccp_call_control_server/Kconfig.sysbuild
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Copyright 2023 Nordic Semiconductor ASA
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
source "share/sysbuild/Kconfig"
|
||||||
|
|
||||||
|
config NET_CORE_BOARD
|
||||||
|
string
|
||||||
|
default "nrf5340dk/nrf5340/cpunet" if "$(BOARD)" = "nrf5340dk"
|
||||||
|
default "nrf5340_audio_dk/nrf5340/cpunet" if "$(BOARD)" = "nrf5340_audio_dk"
|
||||||
|
default "nrf5340bsim/nrf5340/cpunet" if $(BOARD_TARGET_STRING) = "NRF5340BSIM_NRF5340_CPUAPP"
|
||||||
|
|
||||||
|
config NET_CORE_IMAGE_HCI_IPC
|
||||||
|
bool "HCI IPC image on network core"
|
||||||
|
default y
|
||||||
|
depends on NET_CORE_BOARD != ""
|
||||||
77
samples/bluetooth/ccp_call_control_server/README.rst
Normal file
77
samples/bluetooth/ccp_call_control_server/README.rst
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
.. zephyr:code-sample:: bluetooth_ccp_call_control_server
|
||||||
|
:name: Call Control Profile (CCP) Call Control Server
|
||||||
|
:relevant-api: bluetooth bt_ccp bt_tbs
|
||||||
|
|
||||||
|
CCP Call Control Server sample that registers one or more TBS bearers and advertises the
|
||||||
|
TBS UUID(s).
|
||||||
|
|
||||||
|
Overview
|
||||||
|
********
|
||||||
|
|
||||||
|
Application demonstrating the CCP Call Control Server functionality.
|
||||||
|
Starts by advertising for CCP Call Control Clients to connect and set up calls.
|
||||||
|
|
||||||
|
The profile works for both GAP Central and GAP Peripheral devices, but this sample only assumes the
|
||||||
|
GAP Peripheral role.
|
||||||
|
|
||||||
|
This sample can be found under :zephyr_file:`samples/bluetooth/ccp_call_control_server` in the Zephyr tree.
|
||||||
|
|
||||||
|
Check the :zephyr:code-sample-category:`bluetooth` samples for general information.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
************
|
||||||
|
|
||||||
|
* BlueZ running on the host, or
|
||||||
|
* A board with Bluetooth Low Energy 5.2 support
|
||||||
|
|
||||||
|
Building and Running
|
||||||
|
********************
|
||||||
|
|
||||||
|
When building targeting an nrf52 series board with the Zephyr Bluetooth Controller,
|
||||||
|
use ``-DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf`` to enable the required feature support.
|
||||||
|
|
||||||
|
Building for an nrf5340dk
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
You can build both the application core image and an appropriate controller image for the network
|
||||||
|
core with:
|
||||||
|
|
||||||
|
.. zephyr-app-commands::
|
||||||
|
:zephyr-app: samples/bluetooth/ccp_call_control_server/
|
||||||
|
:board: nrf5340dk/nrf5340/cpuapp
|
||||||
|
:goals: build
|
||||||
|
:west-args: --sysbuild
|
||||||
|
|
||||||
|
If you prefer to only build the application core image, you can do so by doing instead:
|
||||||
|
|
||||||
|
.. zephyr-app-commands::
|
||||||
|
:zephyr-app: samples/bluetooth/ccp_call_control_server/
|
||||||
|
:board: nrf5340dk/nrf5340/cpuapp
|
||||||
|
:goals: build
|
||||||
|
|
||||||
|
In that case you can pair this application core image with the
|
||||||
|
:zephyr:code-sample:`bluetooth_hci_ipc` sample
|
||||||
|
:zephyr_file:`samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf` configuration.
|
||||||
|
|
||||||
|
Building for a simulated nrf5340bsim
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Similarly to how you would for real HW, you can do:
|
||||||
|
|
||||||
|
.. zephyr-app-commands::
|
||||||
|
:zephyr-app: samples/bluetooth/ccp_call_control_server/
|
||||||
|
:board: nrf5340bsim/nrf5340/cpuapp
|
||||||
|
:goals: build
|
||||||
|
:west-args: --sysbuild
|
||||||
|
|
||||||
|
Note this will produce a Linux executable in :file:`./build/zephyr/zephyr.exe`.
|
||||||
|
For more information, check :ref:`this board documentation <nrf5340bsim>`.
|
||||||
|
|
||||||
|
Building for a simulated nrf52_bsim
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
.. zephyr-app-commands::
|
||||||
|
:zephyr-app: samples/bluetooth/ccp_call_control_server/
|
||||||
|
:board: nrf52_bsim
|
||||||
|
:goals: build
|
||||||
|
:gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
CONFIG_BT_BUF_EVT_RX_SIZE=255
|
||||||
|
CONFIG_BT_BUF_ACL_RX_SIZE=255
|
||||||
|
CONFIG_BT_BUF_ACL_TX_SIZE=251
|
||||||
|
CONFIG_BT_BUF_CMD_TX_SIZE=255
|
||||||
|
|
||||||
|
CONFIG_BT_SEND_ECC_EMULATION=y
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
CONFIG_BT_BUF_EVT_RX_SIZE=255
|
||||||
|
CONFIG_BT_BUF_ACL_RX_SIZE=255
|
||||||
|
CONFIG_BT_BUF_ACL_TX_SIZE=251
|
||||||
|
CONFIG_BT_BUF_CMD_TX_SIZE=255
|
||||||
|
|
||||||
|
CONFIG_BT_SEND_ECC_EMULATION=y
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Zephyr Bluetooth Controller
|
||||||
|
CONFIG_BT_LL_SW_SPLIT=y
|
||||||
|
|
||||||
|
# Zephyr Controller tested maximum advertising data that can be set in a single HCI command
|
||||||
|
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191
|
||||||
18
samples/bluetooth/ccp_call_control_server/prj.conf
Normal file
18
samples/bluetooth/ccp_call_control_server/prj.conf
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
CONFIG_BT=y
|
||||||
|
CONFIG_LOG=y
|
||||||
|
CONFIG_BT_PERIPHERAL=y
|
||||||
|
CONFIG_BT_AUDIO=y
|
||||||
|
CONFIG_BT_EXT_ADV=y
|
||||||
|
CONFIG_BT_SMP=y
|
||||||
|
CONFIG_BT_GATT_DYNAMIC_DB=y
|
||||||
|
CONFIG_BT_DEVICE_NAME="CCP Call Control Server"
|
||||||
|
|
||||||
|
CONFIG_BT_SMP=y
|
||||||
|
CONFIG_BT_KEYS_OVERWRITE_OLDEST=y
|
||||||
|
|
||||||
|
# CCP support
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER=y
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT=2
|
||||||
|
CONFIG_BT_TBS=y
|
||||||
|
CONFIG_BT_TBS_BEARER_COUNT=1
|
||||||
|
CONFIG_UTF8=y
|
||||||
30
samples/bluetooth/ccp_call_control_server/sample.yaml
Normal file
30
samples/bluetooth/ccp_call_control_server/sample.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
sample:
|
||||||
|
description: Bluetooth Low Energy Call Control Profile Call Control Server sample
|
||||||
|
name: Bluetooth Low Energy Call Control Profile Call Control Server sample
|
||||||
|
tests:
|
||||||
|
sample.bluetooth.ccp_call_control_server:
|
||||||
|
harness: bluetooth
|
||||||
|
platform_allow:
|
||||||
|
- qemu_cortex_m3
|
||||||
|
- qemu_x86
|
||||||
|
- nrf5340dk/nrf5340/cpuapp
|
||||||
|
- nrf5340bsim/nrf5340/cpuapp
|
||||||
|
integration_platforms:
|
||||||
|
- qemu_x86
|
||||||
|
- nrf5340dk/nrf5340/cpuapp
|
||||||
|
tags: bluetooth
|
||||||
|
sysbuild: true
|
||||||
|
sample.bluetooth.ccp_call_control_server.bt_ll_sw_split:
|
||||||
|
harness: bluetooth
|
||||||
|
platform_allow:
|
||||||
|
- nrf52_bsim
|
||||||
|
- nrf52833dk/nrf52833
|
||||||
|
- nrf52840dk/nrf52840
|
||||||
|
- nrf52840dongle/nrf52840
|
||||||
|
integration_platforms:
|
||||||
|
- nrf52_bsim
|
||||||
|
- nrf52833dk/nrf52833
|
||||||
|
- nrf52840dk/nrf52840
|
||||||
|
- nrf52840dongle/nrf52840
|
||||||
|
extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf
|
||||||
|
tags: bluetooth
|
||||||
256
samples/bluetooth/ccp_call_control_server/src/main.c
Normal file
256
samples/bluetooth/ccp_call_control_server/src/main.c
Normal file
|
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <zephyr/autoconf.h>
|
||||||
|
#include <zephyr/bluetooth/addr.h>
|
||||||
|
#include <zephyr/bluetooth/audio/tbs.h>
|
||||||
|
#include <zephyr/bluetooth/audio/ccp.h>
|
||||||
|
#include <zephyr/bluetooth/bluetooth.h>
|
||||||
|
#include <zephyr/bluetooth/conn.h>
|
||||||
|
#include <zephyr/bluetooth/gap.h>
|
||||||
|
#include <zephyr/bluetooth/hci_types.h>
|
||||||
|
#include <zephyr/bluetooth/uuid.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
#include <zephyr/sys/util_macro.h>
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(ccp_call_control_server, CONFIG_LOG_DEFAULT_LEVEL);
|
||||||
|
|
||||||
|
#define SEM_TIMEOUT K_SECONDS(5)
|
||||||
|
|
||||||
|
static const struct bt_data ad[] = {
|
||||||
|
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
|
||||||
|
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||||
|
BT_DATA_BYTES(BT_DATA_UUID16_SOME, BT_UUID_16_ENCODE(BT_UUID_GTBS_VAL)),
|
||||||
|
BT_DATA_BYTES(BT_DATA_SVC_DATA16, BT_UUID_16_ENCODE(BT_UUID_GTBS_VAL)),
|
||||||
|
IF_ENABLED(CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT > 1,
|
||||||
|
(BT_DATA_BYTES(BT_DATA_UUID16_SOME, BT_UUID_16_ENCODE(BT_UUID_TBS_VAL)),
|
||||||
|
BT_DATA_BYTES(BT_DATA_SVC_DATA16, BT_UUID_16_ENCODE(BT_UUID_TBS_VAL))))};
|
||||||
|
|
||||||
|
static struct bt_le_ext_adv *adv;
|
||||||
|
static struct bt_conn *peer_conn;
|
||||||
|
static struct bt_ccp_call_control_server_bearer
|
||||||
|
*bearers[CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT];
|
||||||
|
|
||||||
|
static K_SEM_DEFINE(sem_state_change, 0, 1);
|
||||||
|
|
||||||
|
static void connected_cb(struct bt_conn *conn, uint8_t err)
|
||||||
|
{
|
||||||
|
char addr[BT_ADDR_LE_STR_LEN];
|
||||||
|
|
||||||
|
(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||||
|
LOG_INF("Connected: %s", addr);
|
||||||
|
|
||||||
|
peer_conn = bt_conn_ref(conn);
|
||||||
|
k_sem_give(&sem_state_change);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
|
||||||
|
{
|
||||||
|
char addr[BT_ADDR_LE_STR_LEN];
|
||||||
|
|
||||||
|
if (conn != peer_conn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||||
|
LOG_INF("Disconnected: %s (reason 0x%02x)", addr, reason);
|
||||||
|
|
||||||
|
bt_conn_unref(peer_conn);
|
||||||
|
peer_conn = NULL;
|
||||||
|
k_sem_give(&sem_state_change);
|
||||||
|
}
|
||||||
|
|
||||||
|
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||||
|
.connected = connected_cb,
|
||||||
|
.disconnected = disconnected_cb,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int advertise(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, NULL, &adv);
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to create advertising set: %d", err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to set advertising data: %d", err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to start advertising set: %d", err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INF("Advertising successfully started");
|
||||||
|
|
||||||
|
/* Wait for connection*/
|
||||||
|
err = k_sem_take(&sem_state_change, K_FOREVER);
|
||||||
|
if (err != 0) {
|
||||||
|
LOG_ERR("Failed to take sem_state_change: err %d", err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int reset_ccp_call_control_server(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
LOG_INF("Resetting");
|
||||||
|
|
||||||
|
if (peer_conn != NULL) {
|
||||||
|
err = bt_conn_disconnect(peer_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||||
|
if (err != 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = k_sem_take(&sem_state_change, K_FOREVER);
|
||||||
|
if (err != 0) {
|
||||||
|
LOG_ERR("Failed to take sem_state_change: %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adv != NULL) {
|
||||||
|
err = bt_le_ext_adv_stop(adv);
|
||||||
|
if (err != 0) {
|
||||||
|
LOG_ERR("Failed to stop advertiser: %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_le_ext_adv_delete(adv);
|
||||||
|
if (err != 0) {
|
||||||
|
LOG_ERR("Failed to delete advertiser: %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
adv = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_sem_reset(&sem_state_change);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_ccp_call_control_server(void)
|
||||||
|
{
|
||||||
|
const struct bt_tbs_register_param gtbs_param = {
|
||||||
|
.provider_name = "Generic TBS",
|
||||||
|
.uci = "un000",
|
||||||
|
.uri_schemes_supported = "tel,skype",
|
||||||
|
.gtbs = true,
|
||||||
|
.authorization_required = false,
|
||||||
|
.technology = BT_TBS_TECHNOLOGY_3G,
|
||||||
|
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_enable(NULL);
|
||||||
|
if (err != 0) {
|
||||||
|
LOG_ERR("Bluetooth enable failed (err %d)", err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Bluetooth initialized");
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(>bs_param, &bearers[0]);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG_ERR("Failed to register GTBS (err %d)", err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INF("Registered GTBS bearer");
|
||||||
|
|
||||||
|
for (int i = 1; i < CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT; i++) {
|
||||||
|
char prov_name[22]; /* Enough to store "Telephone Bearer #255" */
|
||||||
|
const struct bt_tbs_register_param tbs_param = {
|
||||||
|
.provider_name = prov_name,
|
||||||
|
.uci = "un000",
|
||||||
|
.uri_schemes_supported = "tel,skype",
|
||||||
|
.gtbs = false,
|
||||||
|
.authorization_required = false,
|
||||||
|
/* Set different technologies per bearer */
|
||||||
|
.technology = (i % BT_TBS_TECHNOLOGY_WCDMA) + 1,
|
||||||
|
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
|
||||||
|
};
|
||||||
|
|
||||||
|
snprintf(prov_name, sizeof(prov_name), "Telephone Bearer #%d", i);
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(&tbs_param, &bearers[i]);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG_ERR("Failed to register bearer[%d]: %d", i, err);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INF("Registered bearer[%d]", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = init_ccp_call_control_server();
|
||||||
|
if (err != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INF("CCP Call Control Server initialized");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
err = reset_ccp_call_control_server();
|
||||||
|
if (err != 0) {
|
||||||
|
LOG_ERR("Failed to reset");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start advertising as a CCP Call Control Server, which includes setting the
|
||||||
|
* required advertising data based on the roles we support.
|
||||||
|
*/
|
||||||
|
err = advertise();
|
||||||
|
if (err != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* After advertising we expect CCP Call Control Clients to connect to us and
|
||||||
|
* eventually disconnect again. As a CCP Call Control Server we just react to their
|
||||||
|
* requests and not do anything else.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Reset if disconnected */
|
||||||
|
err = k_sem_take(&sem_state_change, K_FOREVER);
|
||||||
|
if (err != 0) {
|
||||||
|
LOG_ERR("Failed to take sem_state_change: err %d", err);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
24
samples/bluetooth/ccp_call_control_server/sysbuild.cmake
Normal file
24
samples/bluetooth/ccp_call_control_server/sysbuild.cmake
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC)
|
||||||
|
# For builds in the nrf5340, we build the netcore image with the controller
|
||||||
|
|
||||||
|
set(NET_APP hci_ipc)
|
||||||
|
set(NET_APP_SRC_DIR ${ZEPHYR_BASE}/samples/bluetooth/${NET_APP})
|
||||||
|
|
||||||
|
ExternalZephyrProject_Add(
|
||||||
|
APPLICATION ${NET_APP}
|
||||||
|
SOURCE_DIR ${NET_APP_SRC_DIR}
|
||||||
|
BOARD ${SB_CONFIG_NET_CORE_BOARD}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(${NET_APP}_CONF_FILE
|
||||||
|
${NET_APP_SRC_DIR}/nrf5340_cpunet_iso-bt_ll_sw_split.conf
|
||||||
|
CACHE INTERNAL ""
|
||||||
|
)
|
||||||
|
|
||||||
|
native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
native_simulator_set_final_executable(${DEFAULT_IMAGE})
|
||||||
|
|
@ -8,7 +8,7 @@ target_sources(app PRIVATE
|
||||||
src/main.c
|
src/main.c
|
||||||
src/mcp_server.c
|
src/mcp_server.c
|
||||||
src/vcp_vol_ctlr.c
|
src/vcp_vol_ctlr.c
|
||||||
src/ccp_server.c
|
src/ccp_call_control_server.c
|
||||||
src/cap_initiator.c
|
src/cap_initiator.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ CONFIG_MCTL_LOCAL_PLAYER_CONTROL=y
|
||||||
CONFIG_MCTL=y
|
CONFIG_MCTL=y
|
||||||
|
|
||||||
# CCP support
|
# CCP support
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER=y
|
||||||
CONFIG_BT_TBS=y
|
CONFIG_BT_TBS=y
|
||||||
CONFIG_BT_TBS_SUPPORTED_FEATURES=3
|
CONFIG_BT_TBS_SUPPORTED_FEATURES=3
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ static struct bt_tbs_cb tbs_cbs = {
|
||||||
.authorize = NULL,
|
.authorize = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
int ccp_server_init(void)
|
int ccp_call_control_server_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
|
@ -306,8 +306,8 @@ int main(void)
|
||||||
}
|
}
|
||||||
printk("MCP initialized\n");
|
printk("MCP initialized\n");
|
||||||
|
|
||||||
/* Initialize CCP Server */
|
/* Initialize CCP Call Control Server */
|
||||||
err = ccp_server_init();
|
err = ccp_call_control_server_init();
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@
|
||||||
int mcp_server_init(void);
|
int mcp_server_init(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize the CCP Server role
|
* @brief Initialize the CCP Call Control Server role
|
||||||
*
|
*
|
||||||
* @return 0 if success, errno on failure.
|
* @return 0 if success, errno on failure.
|
||||||
*/
|
*/
|
||||||
int ccp_server_init(void);
|
int ccp_call_control_server_init(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize the VCP Volume Controller role
|
* @brief Initialize the VCP Volume Controller role
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ CONFIG_BT_PAC_SNK_LOC=y
|
||||||
# Source PAC Location Support
|
# Source PAC Location Support
|
||||||
CONFIG_BT_PAC_SRC_LOC=y
|
CONFIG_BT_PAC_SRC_LOC=y
|
||||||
|
|
||||||
# CCP Client Support
|
# CCP Call Control Client Support
|
||||||
CONFIG_BT_TBS_CLIENT_GTBS=y
|
CONFIG_BT_TBS_CLIENT_GTBS=y
|
||||||
CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL=y
|
CONFIG_BT_TBS_CLIENT_ORIGINATE_CALL=y
|
||||||
CONFIG_BT_TBS_CLIENT_TERMINATE_CALL=y
|
CONFIG_BT_TBS_CLIENT_TERMINATE_CALL=y
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_BAP_BROADCAST_SOURCE bap_broadcast_source
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_BAP_BROADCAST_SINK bap_broadcast_sink.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_BAP_BROADCAST_SINK bap_broadcast_sink.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_BAP_SCAN_DELEGATOR bap_scan_delegator.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_BAP_SCAN_DELEGATOR bap_scan_delegator.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_BAP_BROADCAST_ASSISTANT bap_broadcast_assistant.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_BAP_BROADCAST_ASSISTANT bap_broadcast_assistant.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_BT_CCP_CALL_CONTROL_SERVER ccp_call_control_server.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_HAS has.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_HAS has.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_HAS_CLIENT has_client.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_HAS_CLIENT has_client.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_CAP cap_stream.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_CAP cap_stream.c)
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ config BT_AUDIO_NOTIFY_RETRY_DELAY
|
||||||
available.
|
available.
|
||||||
|
|
||||||
rsource "Kconfig.bap"
|
rsource "Kconfig.bap"
|
||||||
|
rsource "Kconfig.ccp"
|
||||||
rsource "Kconfig.vocs"
|
rsource "Kconfig.vocs"
|
||||||
rsource "Kconfig.aics"
|
rsource "Kconfig.aics"
|
||||||
rsource "Kconfig.vcp"
|
rsource "Kconfig.vcp"
|
||||||
|
|
|
||||||
34
subsys/bluetooth/audio/Kconfig.ccp
Normal file
34
subsys/bluetooth/audio/Kconfig.ccp
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Bluetooth Audio - Call Control Profile (CCP) configuration options
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
if BT_AUDIO
|
||||||
|
|
||||||
|
config BT_CCP_CALL_CONTROL_SERVER
|
||||||
|
bool "Call Control Profile Call Control Server Support"
|
||||||
|
depends on BT_EXT_ADV
|
||||||
|
depends on BT_TBS
|
||||||
|
depends on BT_BONDABLE
|
||||||
|
help
|
||||||
|
This option enables support for the Call Control Profile Call Control Server which uses
|
||||||
|
the Telephone Bearer Service (TBS) to hold and control calls on a device.
|
||||||
|
|
||||||
|
if BT_CCP_CALL_CONTROL_SERVER
|
||||||
|
|
||||||
|
config BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT
|
||||||
|
int "Telephone bearer count"
|
||||||
|
default 1
|
||||||
|
range 1 $(UINT8_MAX)
|
||||||
|
help
|
||||||
|
The number of supported telephone bearers on the CCP Call Control Server
|
||||||
|
|
||||||
|
module = BT_CCP_CALL_CONTROL_SERVER
|
||||||
|
module-str = "Call Control Profile Call Control Server"
|
||||||
|
source "subsys/logging/Kconfig.template.log_config"
|
||||||
|
|
||||||
|
endif # BT_CCP_CALL_CONTROL_SERVER
|
||||||
|
|
||||||
|
endif # BT_AUDIO
|
||||||
106
subsys/bluetooth/audio/ccp_call_control_server.c
Normal file
106
subsys/bluetooth/audio/ccp_call_control_server.c
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
/* Bluetooth CCP - Call Control Profile Call Control Server
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <zephyr/autoconf.h>
|
||||||
|
#include <zephyr/bluetooth/audio/tbs.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/sys/check.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(bt_ccp_call_control_server, CONFIG_BT_CCP_CALL_CONTROL_SERVER_LOG_LEVEL);
|
||||||
|
|
||||||
|
/* A service instance can either be a GTBS or a TBS instance */
|
||||||
|
struct bt_ccp_call_control_server_bearer {
|
||||||
|
uint8_t tbs_index;
|
||||||
|
bool registered;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct bt_ccp_call_control_server_bearer
|
||||||
|
bearers[CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT];
|
||||||
|
|
||||||
|
static struct bt_ccp_call_control_server_bearer *get_free_bearer(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE(bearers); i++) {
|
||||||
|
if (!bearers[i].registered) {
|
||||||
|
return &bearers[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_ccp_call_control_server_register_bearer(const struct bt_tbs_register_param *param,
|
||||||
|
struct bt_ccp_call_control_server_bearer **bearer)
|
||||||
|
{
|
||||||
|
struct bt_ccp_call_control_server_bearer *free_bearer;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
CHECKIF(bearer == NULL) {
|
||||||
|
LOG_DBG("bearer is NULL");
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_bearer = get_free_bearer();
|
||||||
|
if (free_bearer == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bt_tbs_register_bearer(param);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_DBG("Failed to register TBS bearer: %d", ret);
|
||||||
|
|
||||||
|
/* Return known errors */
|
||||||
|
if (ret == -EINVAL || ret == -EALREADY || ret == -EAGAIN || ret == -ENOMEM) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_bearer->registered = true;
|
||||||
|
free_bearer->tbs_index = (uint8_t)ret;
|
||||||
|
*bearer = free_bearer;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_ccp_call_control_server_unregister_bearer(struct bt_ccp_call_control_server_bearer *bearer)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
CHECKIF(bearer == NULL) {
|
||||||
|
LOG_DBG("bearer is NULL");
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bearer->registered) {
|
||||||
|
LOG_DBG("Bearer %p already unregistered", bearer);
|
||||||
|
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_tbs_unregister_bearer(bearer->tbs_index);
|
||||||
|
if (err != 0) {
|
||||||
|
/* Return known errors */
|
||||||
|
if (err == -EINVAL || err == -EALREADY) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
bearer->registered = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
zephyr_library()
|
zephyr_library()
|
||||||
zephyr_library_link_libraries(subsys__bluetooth)
|
zephyr_library_link_libraries(subsys__bluetooth)
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER
|
||||||
|
ccp_call_control_server.c
|
||||||
|
)
|
||||||
zephyr_library_sources_ifdef(
|
zephyr_library_sources_ifdef(
|
||||||
CONFIG_BT_VCP_VOL_REND
|
CONFIG_BT_VCP_VOL_REND
|
||||||
vcp_vol_rend.c
|
vcp_vol_rend.c
|
||||||
|
|
|
||||||
100
subsys/bluetooth/audio/shell/ccp_call_control_server.c
Normal file
100
subsys/bluetooth/audio/shell/ccp_call_control_server.c
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
/** @file
|
||||||
|
* @brief Bluetooth Call Control Profile Call Control Server shell
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <zephyr/autoconf.h>
|
||||||
|
#include <zephyr/bluetooth/audio/tbs.h>
|
||||||
|
#include <zephyr/bluetooth/audio/ccp.h>
|
||||||
|
#include <zephyr/shell/shell.h>
|
||||||
|
|
||||||
|
static struct bt_ccp_call_control_server_bearer
|
||||||
|
*bearers[CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT];
|
||||||
|
|
||||||
|
static int cmd_ccp_call_control_server_init(const struct shell *sh, size_t argc, char *argv[])
|
||||||
|
{
|
||||||
|
static bool registered;
|
||||||
|
|
||||||
|
if (registered) {
|
||||||
|
shell_info(sh, "Already initialized");
|
||||||
|
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct bt_tbs_register_param gtbs_param = {
|
||||||
|
.provider_name = "Generic TBS",
|
||||||
|
.uci = "un000",
|
||||||
|
.uri_schemes_supported = "tel,skype",
|
||||||
|
.gtbs = true,
|
||||||
|
.authorization_required = false,
|
||||||
|
.technology = BT_TBS_TECHNOLOGY_3G,
|
||||||
|
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(>bs_param, &bearers[0]);
|
||||||
|
if (err != 0) {
|
||||||
|
shell_error(sh, "Failed to register GTBS bearer: %d", err);
|
||||||
|
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_info(sh, "Registered GTBS bearer");
|
||||||
|
|
||||||
|
for (int i = 1; i < CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT; i++) {
|
||||||
|
char prov_name[22]; /* Enough to store "Telephone Bearer #255" */
|
||||||
|
const struct bt_tbs_register_param tbs_param = {
|
||||||
|
.provider_name = prov_name,
|
||||||
|
.uci = "un000",
|
||||||
|
.uri_schemes_supported = "tel,skype",
|
||||||
|
.gtbs = false,
|
||||||
|
.authorization_required = false,
|
||||||
|
/* Set different technologies per bearer */
|
||||||
|
.technology = (i % BT_TBS_TECHNOLOGY_WCDMA) + 1,
|
||||||
|
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
|
||||||
|
};
|
||||||
|
|
||||||
|
snprintf(prov_name, sizeof(prov_name), "Telephone Bearer #%d", i);
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(&tbs_param, &bearers[i]);
|
||||||
|
if (err != 0) {
|
||||||
|
shell_error(sh, "Failed to register bearer[%d]: %d", i, err);
|
||||||
|
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell_info(sh, "Registered bearer[%d]", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
registered = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_ccp_call_control_server(const struct shell *sh, size_t argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc > 1) {
|
||||||
|
shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
|
||||||
|
} else {
|
||||||
|
shell_error(sh, "%s Missing subcommand", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_STATIC_SUBCMD_SET_CREATE(ccp_call_control_server_cmds,
|
||||||
|
SHELL_CMD_ARG(init, NULL, "Initialize CCP Call Control Server",
|
||||||
|
cmd_ccp_call_control_server_init, 1, 0),
|
||||||
|
SHELL_SUBCMD_SET_END);
|
||||||
|
|
||||||
|
SHELL_CMD_ARG_REGISTER(ccp_call_control_server, &ccp_call_control_server_cmds,
|
||||||
|
"Bluetooth CCP Call Control Server shell commands",
|
||||||
|
cmd_ccp_call_control_server, 1, 1);
|
||||||
17
tests/bluetooth/audio/ccp_call_control_server/CMakeLists.txt
Normal file
17
tests/bluetooth/audio/ccp_call_control_server/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
|
|
||||||
|
project(bluetooth_ccp)
|
||||||
|
find_package(Zephyr COMPONENTS unittest HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
|
||||||
|
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/audio/ccp_call_control_server/uut uut)
|
||||||
|
|
||||||
|
target_link_libraries(testbinary PRIVATE uut)
|
||||||
|
|
||||||
|
target_include_directories(testbinary PRIVATE include)
|
||||||
|
|
||||||
|
target_sources(testbinary
|
||||||
|
PRIVATE
|
||||||
|
src/main.c
|
||||||
|
)
|
||||||
21
tests/bluetooth/audio/ccp_call_control_server/prj.conf
Normal file
21
tests/bluetooth/audio/ccp_call_control_server/prj.conf
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
CONFIG_ZTEST=y
|
||||||
|
|
||||||
|
CONFIG_BT=y
|
||||||
|
CONFIG_BT_SMP=y
|
||||||
|
CONFIG_BT_PERIPHERAL=y
|
||||||
|
CONFIG_BT_EXT_ADV=y
|
||||||
|
CONFIG_BT_GATT_DYNAMIC_DB=y
|
||||||
|
CONFIG_BT_AUDIO=y
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER=y
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT=2
|
||||||
|
CONFIG_BT_TBS=y
|
||||||
|
CONFIG_BT_TBS_BEARER_COUNT=1
|
||||||
|
CONFIG_UTF8=y
|
||||||
|
|
||||||
|
CONFIG_ASSERT=y
|
||||||
|
CONFIG_ASSERT_LEVEL=2
|
||||||
|
CONFIG_ASSERT_VERBOSE=y
|
||||||
|
|
||||||
|
CONFIG_LOG=y
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER_LOG_LEVEL_DBG=y
|
||||||
|
CONFIG_BT_TBS_LOG_LEVEL_DBG=y
|
||||||
264
tests/bluetooth/audio/ccp_call_control_server/src/main.c
Normal file
264
tests/bluetooth/audio/ccp_call_control_server/src/main.c
Normal file
|
|
@ -0,0 +1,264 @@
|
||||||
|
/* main.c - Application main entry point */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <zephyr/autoconf.h>
|
||||||
|
#include <zephyr/bluetooth/audio/ccp.h>
|
||||||
|
#include <zephyr/bluetooth/audio/tbs.h>
|
||||||
|
#include <zephyr/bluetooth/gatt.h>
|
||||||
|
#include <zephyr/bluetooth/uuid.h>
|
||||||
|
#include <zephyr/fff.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
#include <zephyr/sys/util_macro.h>
|
||||||
|
|
||||||
|
#include <ztest_test.h>
|
||||||
|
#include <ztest_assert.h>
|
||||||
|
|
||||||
|
DEFINE_FFF_GLOBALS;
|
||||||
|
|
||||||
|
struct ccp_call_control_server_test_suite_fixture {
|
||||||
|
/** Need 1 additional bearer than the max to trigger some corner cases */
|
||||||
|
struct bt_ccp_call_control_server_bearer
|
||||||
|
*bearers[CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT + 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *ccp_call_control_server_test_suite_setup(void)
|
||||||
|
{
|
||||||
|
struct ccp_call_control_server_test_suite_fixture *fixture;
|
||||||
|
|
||||||
|
fixture = malloc(sizeof(*fixture));
|
||||||
|
zassert_not_null(fixture);
|
||||||
|
|
||||||
|
return fixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ccp_call_control_server_test_suite_before(void *f)
|
||||||
|
{
|
||||||
|
memset(f, 0, sizeof(struct ccp_call_control_server_test_suite_fixture));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ccp_call_control_server_test_suite_after(void *f)
|
||||||
|
{
|
||||||
|
struct ccp_call_control_server_test_suite_fixture *fixture = f;
|
||||||
|
|
||||||
|
/* We unregister from largest to lowest index, as GTBS shall be unregistered last and is
|
||||||
|
* always at index 0
|
||||||
|
*/
|
||||||
|
for (size_t i = ARRAY_SIZE(fixture->bearers); i > 0; i--) {
|
||||||
|
/* Since size_t cannot be negative, we cannot use the regular i >= 0 when counting
|
||||||
|
* downwards as that will always be true, so we use an additional index variable
|
||||||
|
*/
|
||||||
|
const size_t index_to_unreg = i - 1;
|
||||||
|
|
||||||
|
if (fixture->bearers[index_to_unreg] != NULL) {
|
||||||
|
bt_ccp_call_control_server_unregister_bearer(
|
||||||
|
fixture->bearers[index_to_unreg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fixture->bearers[index_to_unreg] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ccp_call_control_server_test_suite_teardown(void *f)
|
||||||
|
{
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZTEST_SUITE(ccp_call_control_server_test_suite, NULL, ccp_call_control_server_test_suite_setup,
|
||||||
|
ccp_call_control_server_test_suite_before, ccp_call_control_server_test_suite_after,
|
||||||
|
ccp_call_control_server_test_suite_teardown);
|
||||||
|
|
||||||
|
static void register_default_bearer(struct ccp_call_control_server_test_suite_fixture *fixture)
|
||||||
|
{
|
||||||
|
const struct bt_tbs_register_param register_param = {
|
||||||
|
.provider_name = "test",
|
||||||
|
.uci = "un999",
|
||||||
|
.uri_schemes_supported = "tel",
|
||||||
|
.gtbs = true,
|
||||||
|
.authorization_required = false,
|
||||||
|
.technology = BT_TBS_TECHNOLOGY_3G,
|
||||||
|
.supported_features = 0,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(®ister_param, &fixture->bearers[0]);
|
||||||
|
zassert_equal(err, 0, "Unexpected return value %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZTEST_F(ccp_call_control_server_test_suite, test_ccp_call_control_server_register_bearer)
|
||||||
|
{
|
||||||
|
register_default_bearer(fixture);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZTEST_F(ccp_call_control_server_test_suite,
|
||||||
|
test_ccp_call_control_server_register_multiple_bearers)
|
||||||
|
{
|
||||||
|
if (CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT == 1) {
|
||||||
|
ztest_test_skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
register_default_bearer(fixture);
|
||||||
|
|
||||||
|
for (int i = 1; i < CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT; i++) {
|
||||||
|
struct bt_tbs_register_param register_param = {
|
||||||
|
.provider_name = "test",
|
||||||
|
.uci = "un999",
|
||||||
|
.uri_schemes_supported = "tel",
|
||||||
|
.gtbs = false,
|
||||||
|
.authorization_required = false,
|
||||||
|
.technology = BT_TBS_TECHNOLOGY_3G,
|
||||||
|
.supported_features = 0,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(®ister_param,
|
||||||
|
&fixture->bearers[i]);
|
||||||
|
zassert_equal(err, 0, "Unexpected return value %d", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZTEST_F(ccp_call_control_server_test_suite,
|
||||||
|
test_ccp_call_control_server_register_bearer_inval_null_param)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(NULL, &fixture->bearers[0]);
|
||||||
|
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZTEST_F(ccp_call_control_server_test_suite,
|
||||||
|
test_ccp_call_control_server_register_bearer_inval_null_bearer)
|
||||||
|
{
|
||||||
|
const struct bt_tbs_register_param register_param = {
|
||||||
|
.provider_name = "test",
|
||||||
|
.uci = "un999",
|
||||||
|
.uri_schemes_supported = "tel",
|
||||||
|
.gtbs = true,
|
||||||
|
.authorization_required = false,
|
||||||
|
.technology = BT_TBS_TECHNOLOGY_3G,
|
||||||
|
.supported_features = 0,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(®ister_param, NULL);
|
||||||
|
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZTEST_F(ccp_call_control_server_test_suite,
|
||||||
|
test_ccp_call_control_server_register_bearer_inval_no_gtbs)
|
||||||
|
{
|
||||||
|
const struct bt_tbs_register_param register_param = {
|
||||||
|
.provider_name = "test",
|
||||||
|
.uci = "un999",
|
||||||
|
.uri_schemes_supported = "tel",
|
||||||
|
.gtbs = false,
|
||||||
|
.authorization_required = false,
|
||||||
|
.technology = BT_TBS_TECHNOLOGY_3G,
|
||||||
|
.supported_features = 0,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(®ister_param, &fixture->bearers[0]);
|
||||||
|
zassert_equal(err, -EAGAIN, "Unexpected return value %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZTEST_F(ccp_call_control_server_test_suite,
|
||||||
|
test_ccp_call_control_server_register_bearer_inval_double_gtbs)
|
||||||
|
{
|
||||||
|
const struct bt_tbs_register_param register_param = {
|
||||||
|
.provider_name = "test",
|
||||||
|
.uci = "un999",
|
||||||
|
.uri_schemes_supported = "tel",
|
||||||
|
.gtbs = true,
|
||||||
|
.authorization_required = false,
|
||||||
|
.technology = BT_TBS_TECHNOLOGY_3G,
|
||||||
|
.supported_features = 0,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT == 1) {
|
||||||
|
ztest_test_skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
register_default_bearer(fixture);
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(®ister_param, &fixture->bearers[1]);
|
||||||
|
zassert_equal(err, -EALREADY, "Unexpected return value %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZTEST_F(ccp_call_control_server_test_suite,
|
||||||
|
test_ccp_call_control_server_register_bearer_inval_cnt)
|
||||||
|
{
|
||||||
|
const struct bt_tbs_register_param register_param = {
|
||||||
|
.provider_name = "test",
|
||||||
|
.uci = "un999",
|
||||||
|
.uri_schemes_supported = "tel",
|
||||||
|
.gtbs = false,
|
||||||
|
.authorization_required = false,
|
||||||
|
.technology = BT_TBS_TECHNOLOGY_3G,
|
||||||
|
.supported_features = 0,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT == 1) {
|
||||||
|
ztest_test_skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
register_default_bearer(fixture);
|
||||||
|
|
||||||
|
for (int i = 1; i < CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT; i++) {
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(®ister_param,
|
||||||
|
&fixture->bearers[i]);
|
||||||
|
zassert_equal(err, 0, "Unexpected return value %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(
|
||||||
|
®ister_param, &fixture->bearers[CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT]);
|
||||||
|
zassert_equal(err, -ENOMEM, "Unexpected return value %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZTEST_F(ccp_call_control_server_test_suite, test_ccp_call_control_server_unregister_bearer)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
register_default_bearer(fixture);
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_unregister_bearer(fixture->bearers[0]);
|
||||||
|
zassert_equal(err, 0, "Unexpected return value %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZTEST_F(ccp_call_control_server_test_suite,
|
||||||
|
test_ccp_call_control_server_unregister_bearer_inval_double_unregister)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
register_default_bearer(fixture);
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_unregister_bearer(fixture->bearers[0]);
|
||||||
|
zassert_equal(err, 0, "Unexpected return value %d", err);
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_unregister_bearer(fixture->bearers[0]);
|
||||||
|
zassert_equal(err, -EALREADY, "Unexpected return value %d", err);
|
||||||
|
|
||||||
|
fixture->bearers[0] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ZTEST_F(ccp_call_control_server_test_suite,
|
||||||
|
test_ccp_call_control_server_unregister_bearer_inval_null_bearer)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_unregister_bearer(NULL);
|
||||||
|
zassert_equal(err, -EINVAL, "Unexpected return value %d", err);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
common:
|
||||||
|
tags:
|
||||||
|
- bluetooth
|
||||||
|
- bluetooth_audio
|
||||||
|
tests:
|
||||||
|
bluetooth.audio.ccp_call_control_server.test:
|
||||||
|
type: unit
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
# CMakeLists.txt file for creating of uut library.
|
||||||
|
#
|
||||||
|
|
||||||
|
add_library(uut STATIC
|
||||||
|
${ZEPHYR_BASE}/subsys/bluetooth/audio/audio.c
|
||||||
|
${ZEPHYR_BASE}/subsys/bluetooth/audio/ccid.c
|
||||||
|
${ZEPHYR_BASE}/subsys/bluetooth/audio/ccp_call_control_server.c
|
||||||
|
${ZEPHYR_BASE}/subsys/bluetooth/audio/tbs.c
|
||||||
|
${ZEPHYR_BASE}/lib/net_buf/buf_simple.c
|
||||||
|
${ZEPHYR_BASE}/lib/utils/utf8.c
|
||||||
|
)
|
||||||
|
|
||||||
|
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/audio/mocks mocks)
|
||||||
|
|
||||||
|
target_link_libraries(uut PUBLIC test_interface mocks)
|
||||||
|
|
||||||
|
target_compile_options(uut PRIVATE -std=c11 -include ztest.h)
|
||||||
|
|
@ -130,7 +130,9 @@ CONFIG_BT_MPL_MAX_OBJ_SIZE=600
|
||||||
CONFIG_BT_MPL_ICON_BITMAP_SIZE=321
|
CONFIG_BT_MPL_ICON_BITMAP_SIZE=321
|
||||||
CONFIG_BT_MPL_TRACK_MAX_SIZE=50
|
CONFIG_BT_MPL_TRACK_MAX_SIZE=50
|
||||||
|
|
||||||
# Telephone bearer service
|
# Call Control
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER=y
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT=2
|
||||||
CONFIG_BT_TBS=y
|
CONFIG_BT_TBS=y
|
||||||
CONFIG_BT_TBS_BEARER_COUNT=1
|
CONFIG_BT_TBS_BEARER_COUNT=1
|
||||||
CONFIG_BT_TBS_SUPPORTED_FEATURES=3
|
CONFIG_BT_TBS_SUPPORTED_FEATURES=3
|
||||||
|
|
|
||||||
|
|
@ -324,6 +324,7 @@ tests:
|
||||||
extra_args: CONF_FILE="audio.conf"
|
extra_args: CONF_FILE="audio.conf"
|
||||||
build_only: true
|
build_only: true
|
||||||
extra_configs:
|
extra_configs:
|
||||||
|
- CONFIG_BT_CCP_CALL_CONTROL_SERVER=n
|
||||||
- CONFIG_BT_TBS=n
|
- CONFIG_BT_TBS=n
|
||||||
tags: bluetooth
|
tags: bluetooth
|
||||||
bluetooth.shell.audio.only_gtbs:
|
bluetooth.shell.audio.only_gtbs:
|
||||||
|
|
@ -431,3 +432,9 @@ tests:
|
||||||
- nrf52_bsim
|
- nrf52_bsim
|
||||||
integration_platforms:
|
integration_platforms:
|
||||||
- nrf52_bsim
|
- nrf52_bsim
|
||||||
|
bluetooth.shell.audio.no_ccp_call_control_server:
|
||||||
|
extra_args: CONF_FILE="audio.conf"
|
||||||
|
build_only: true
|
||||||
|
extra_configs:
|
||||||
|
- CONFIG_BT_CCP_CALL_CONTROL_SERVER=n
|
||||||
|
tags: bluetooth
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ CONFIG_BT_CSIP_SET_COORDINATOR=y
|
||||||
CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES=3
|
CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES=3
|
||||||
|
|
||||||
# CCP
|
# CCP
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER=y
|
||||||
CONFIG_BT_ATT_TX_COUNT=12
|
CONFIG_BT_ATT_TX_COUNT=12
|
||||||
CONFIG_BT_TBS_CLIENT_GTBS=y
|
CONFIG_BT_TBS_CLIENT_GTBS=y
|
||||||
CONFIG_BT_TBS_CLIENT_TBS=y
|
CONFIG_BT_TBS_CLIENT_TBS=y
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,8 @@ CONFIG_BT_CSIP_SET_MEMBER_NOTIFIABLE=y
|
||||||
CONFIG_BT_CSIP_SET_COORDINATOR=y
|
CONFIG_BT_CSIP_SET_COORDINATOR=y
|
||||||
CONFIG_BT_CSIP_SET_COORDINATOR_TEST_SAMPLE_DATA=y
|
CONFIG_BT_CSIP_SET_COORDINATOR_TEST_SAMPLE_DATA=y
|
||||||
|
|
||||||
# Telephone bearer service
|
# Call control
|
||||||
|
CONFIG_BT_CCP_CALL_CONTROL_SERVER=y
|
||||||
CONFIG_BT_TBS=y
|
CONFIG_BT_TBS=y
|
||||||
CONFIG_BT_TBS_BEARER_COUNT=1
|
CONFIG_BT_TBS_BEARER_COUNT=1
|
||||||
CONFIG_BT_TBS_CLIENT_TBS=y
|
CONFIG_BT_TBS_CLIENT_TBS=y
|
||||||
|
|
|
||||||
171
tests/bsim/bluetooth/audio/src/ccp_call_control_server_test.c
Normal file
171
tests/bsim/bluetooth/audio/src/ccp_call_control_server_test.c
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <zephyr/autoconf.h>
|
||||||
|
#include <zephyr/bluetooth/addr.h>
|
||||||
|
#include <zephyr/bluetooth/audio/tbs.h>
|
||||||
|
#include <zephyr/bluetooth/audio/ccp.h>
|
||||||
|
#include <zephyr/bluetooth/bluetooth.h>
|
||||||
|
#include <zephyr/bluetooth/conn.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
#include "bstests.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_BT_CCP_CALL_CONTROL_SERVER
|
||||||
|
LOG_MODULE_REGISTER(ccp_call_control_server, CONFIG_LOG_DEFAULT_LEVEL);
|
||||||
|
|
||||||
|
extern enum bst_result_t bst_result;
|
||||||
|
|
||||||
|
static struct bt_ccp_call_control_server_bearer
|
||||||
|
*bearers[CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT];
|
||||||
|
|
||||||
|
CREATE_FLAG(is_connected);
|
||||||
|
static void connected(struct bt_conn *conn, uint8_t err)
|
||||||
|
{
|
||||||
|
char addr[BT_ADDR_LE_STR_LEN];
|
||||||
|
|
||||||
|
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||||
|
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Failed to connect to %s (%u)\n", addr, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Connected to %s", addr);
|
||||||
|
|
||||||
|
default_conn = bt_conn_ref(conn);
|
||||||
|
SET_FLAG(is_connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init(void)
|
||||||
|
{
|
||||||
|
static struct bt_conn_cb conn_callbacks = {
|
||||||
|
.connected = connected,
|
||||||
|
.disconnected = disconnected,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct bt_tbs_register_param gtbs_param = {
|
||||||
|
.provider_name = "Generic TBS",
|
||||||
|
.uci = "un000",
|
||||||
|
.uri_schemes_supported = "tel,skype",
|
||||||
|
.gtbs = true,
|
||||||
|
.authorization_required = false,
|
||||||
|
.technology = BT_TBS_TECHNOLOGY_3G,
|
||||||
|
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_enable(NULL);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Bluetooth enable failed (err %d)\n", err);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Bluetooth initialized");
|
||||||
|
|
||||||
|
err = bt_conn_cb_register(&conn_callbacks);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Failed to register conn CBs (err %d)\n", err);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_le_scan_cb_register(&common_scan_cb);
|
||||||
|
if (err != 0) {
|
||||||
|
FAIL("Failed to register scan CBs (err %d)\n", err);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(>bs_param, &bearers[0]);
|
||||||
|
if (err < 0) {
|
||||||
|
FAIL("Failed to register GTBS (err %d)\n", err);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INF("Registered GTBS bearer");
|
||||||
|
|
||||||
|
for (int i = 1; i < CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT; i++) {
|
||||||
|
char prov_name[22]; /* Enough to store "Telephone Bearer #255" */
|
||||||
|
const struct bt_tbs_register_param tbs_param = {
|
||||||
|
.provider_name = prov_name,
|
||||||
|
.uci = "un000",
|
||||||
|
.uri_schemes_supported = "tel,skype",
|
||||||
|
.gtbs = false,
|
||||||
|
.authorization_required = false,
|
||||||
|
/* Set different technologies per bearer */
|
||||||
|
.technology = (i % BT_TBS_TECHNOLOGY_WCDMA) + 1,
|
||||||
|
.supported_features = CONFIG_BT_TBS_SUPPORTED_FEATURES,
|
||||||
|
};
|
||||||
|
|
||||||
|
snprintf(prov_name, sizeof(prov_name), "Telephone Bearer #%d", i);
|
||||||
|
|
||||||
|
err = bt_ccp_call_control_server_register_bearer(&tbs_param, &bearers[i]);
|
||||||
|
if (err < 0) {
|
||||||
|
FAIL("Failed to register bearer[%d]: %d\n", i, err);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INF("Registered bearer[%d]", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unregister_bearers(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < CONFIG_BT_CCP_CALL_CONTROL_SERVER_BEARER_COUNT; i++) {
|
||||||
|
if (bearers[i] != NULL) {
|
||||||
|
const int err = bt_ccp_call_control_server_unregister_bearer(bearers[i]);
|
||||||
|
|
||||||
|
if (err < 0) {
|
||||||
|
FAIL("Failed to unregister bearer[%d]: %d\n", i, err);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Unregistered bearer[%d]", i);
|
||||||
|
|
||||||
|
bearers[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_main(void)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
|
||||||
|
unregister_bearers();
|
||||||
|
|
||||||
|
PASS("CCP Call Control Server Passed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct bst_test_instance test_ccp_call_control_server[] = {
|
||||||
|
{
|
||||||
|
.test_id = "ccp_call_control_server",
|
||||||
|
.test_pre_init_f = test_init,
|
||||||
|
.test_tick_f = test_tick,
|
||||||
|
.test_main_f = test_main,
|
||||||
|
},
|
||||||
|
BSTEST_END_MARKER,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bst_test_list *test_ccp_call_control_server_install(struct bst_test_list *tests)
|
||||||
|
{
|
||||||
|
return bst_add_tests(tests, test_ccp_call_control_server);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
struct bst_test_list *test_ccp_call_control_server_install(struct bst_test_list *tests)
|
||||||
|
{
|
||||||
|
return tests;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_BT_TBS */
|
||||||
|
|
@ -44,6 +44,7 @@ extern struct bst_test_list *test_csip_notify_client_install(struct bst_test_lis
|
||||||
extern struct bst_test_list *test_csip_notify_server_install(struct bst_test_list *tests);
|
extern struct bst_test_list *test_csip_notify_server_install(struct bst_test_list *tests);
|
||||||
extern struct bst_test_list *test_gmap_ugg_install(struct bst_test_list *tests);
|
extern struct bst_test_list *test_gmap_ugg_install(struct bst_test_list *tests);
|
||||||
extern struct bst_test_list *test_gmap_ugt_install(struct bst_test_list *tests);
|
extern struct bst_test_list *test_gmap_ugt_install(struct bst_test_list *tests);
|
||||||
|
extern struct bst_test_list *test_ccp_call_control_server_install(struct bst_test_list *tests);
|
||||||
|
|
||||||
bst_test_install_t test_installers[] = {
|
bst_test_install_t test_installers[] = {
|
||||||
test_vcp_install,
|
test_vcp_install,
|
||||||
|
|
@ -82,6 +83,7 @@ bst_test_install_t test_installers[] = {
|
||||||
test_csip_notify_server_install,
|
test_csip_notify_server_install,
|
||||||
test_gmap_ugg_install,
|
test_gmap_ugg_install,
|
||||||
test_gmap_ugt_install,
|
test_gmap_ugt_install,
|
||||||
|
test_ccp_call_control_server_install,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
22
tests/bsim/bluetooth/audio/test_scripts/ccp.sh
Executable file
22
tests/bsim/bluetooth/audio/test_scripts/ccp.sh
Executable file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
|
||||||
|
|
||||||
|
VERBOSITY_LEVEL=2
|
||||||
|
|
||||||
|
cd ${BSIM_OUT_PATH}/bin
|
||||||
|
|
||||||
|
SIMULATION_ID="ccp"
|
||||||
|
|
||||||
|
Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_audio_prj_conf \
|
||||||
|
-v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=0 -testid=ccp_call_control_server -rs=1 -D=1
|
||||||
|
|
||||||
|
# Simulation time should be larger than the WAIT_TIME in common.h
|
||||||
|
Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} \
|
||||||
|
-D=1 -sim_length=60e6 $@
|
||||||
|
|
||||||
|
wait_for_background_jobs
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
|
|
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
project(ccp_call_control_server_self_tets)
|
||||||
|
|
||||||
|
set(ccp_call_control_server_path ${ZEPHYR_BASE}/samples/bluetooth/ccp_call_control_server)
|
||||||
|
|
||||||
|
target_sources(app PRIVATE
|
||||||
|
${ccp_call_control_server_path}/src/main.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(app PRIVATE
|
||||||
|
src/test_main.c
|
||||||
|
)
|
||||||
|
|
||||||
|
zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth)
|
||||||
|
|
||||||
|
zephyr_include_directories(
|
||||||
|
${BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||||
|
${BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Copyright (c) 2023-2024 Nordic Semiconductor ASA
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
source "${ZEPHYR_BASE}/samples/bluetooth/ccp_call_control_server/Kconfig.sysbuild"
|
||||||
|
|
||||||
|
config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX
|
||||||
|
int
|
||||||
|
# Let's pass the test arguments to the application MCU test
|
||||||
|
# otherwise by default they would have gone to the net core.
|
||||||
|
default 0 if $(BOARD_TARGET_STRING) = "NRF5340BSIM_NRF5340_CPUAPP"
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Please build using the sample configuration file:
|
||||||
|
# ${ZEPHYR_BASE}/samples/bluetooth/ccp_call_control_server/prj.conf
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "bs_types.h"
|
||||||
|
#include "bs_tracing.h"
|
||||||
|
#include "bs_utils.h"
|
||||||
|
#include "bstests.h"
|
||||||
|
|
||||||
|
#define WAIT_TIME 10 /* Seconds */
|
||||||
|
|
||||||
|
#define PASS_THRESHOLD 100 /* Audio packets */
|
||||||
|
|
||||||
|
extern enum bst_result_t bst_result;
|
||||||
|
|
||||||
|
#define FAIL(...) \
|
||||||
|
do { \
|
||||||
|
bst_result = Failed; \
|
||||||
|
bs_trace_error_time_line(__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define PASS(...) \
|
||||||
|
do { \
|
||||||
|
bst_result = Passed; \
|
||||||
|
bs_trace_info_time(1, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void test_ccp_call_control_server_sample_init(void)
|
||||||
|
{
|
||||||
|
bst_ticker_set_next_tick_absolute(WAIT_TIME * 1e6);
|
||||||
|
bst_result = In_progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_ccp_call_control_server_sample_tick(bs_time_t HW_device_time)
|
||||||
|
{
|
||||||
|
/* TODO: Once the sample is more complete we can expand the pass criteria */
|
||||||
|
PASS("CCP Call Control Server sample PASSED\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct bst_test_instance test_sample[] = {
|
||||||
|
{
|
||||||
|
.test_id = "ccp_call_control_server",
|
||||||
|
.test_descr = "Test based on the CCP Call Control Server sample. "
|
||||||
|
"It expects to be connected to a compatible CCP Call Control Client, "
|
||||||
|
"waits for " STR(
|
||||||
|
WAIT_TIME) " seconds, and checks how "
|
||||||
|
"many audio packets have been received correctly",
|
||||||
|
.test_post_init_f = test_ccp_call_control_server_sample_init,
|
||||||
|
.test_tick_f = test_ccp_call_control_server_sample_tick,
|
||||||
|
},
|
||||||
|
BSTEST_END_MARKER,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct bst_test_list *
|
||||||
|
test_ccp_call_control_server_sample_install(struct bst_test_list *tests)
|
||||||
|
{
|
||||||
|
tests = bst_add_tests(tests, test_sample);
|
||||||
|
return tests;
|
||||||
|
}
|
||||||
|
|
||||||
|
bst_test_install_t test_installers[] = {test_ccp_call_control_server_sample_install, NULL};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Copyright (c) 2023-2024 Nordic Semiconductor ASA
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
include(${ZEPHYR_BASE}/samples/bluetooth/ccp_call_control_server/sysbuild.cmake)
|
||||||
|
|
||||||
|
native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP})
|
||||||
26
tests/bsim/bluetooth/audio_samples/ccp/compile.sh
Executable file
26
tests/bsim/bluetooth/audio_samples/ccp/compile.sh
Executable file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright 2023 Nordic Semiconductor ASA
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#set -x #uncomment this line for debugging
|
||||||
|
set -ue
|
||||||
|
|
||||||
|
: "${ZEPHYR_BASE:?ZEPHYR_BASE must be set to point to the zephyr root directory}"
|
||||||
|
|
||||||
|
source ${ZEPHYR_BASE}/tests/bsim/compile.source
|
||||||
|
|
||||||
|
if [ "${BOARD_TS}" == "nrf5340bsim_nrf5340_cpuapp" ]; then
|
||||||
|
app=tests/bsim/bluetooth/audio_samples/ccp/call_control_server \
|
||||||
|
sample=${ZEPHYR_BASE}/samples/bluetooth/ccp_call_control_server \
|
||||||
|
conf_file=${sample}/prj.conf \
|
||||||
|
conf_overlay=${sample}/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf \
|
||||||
|
exe_name=bs_${BOARD_TS}_${app}_prj_conf sysbuild=1 compile
|
||||||
|
else
|
||||||
|
app=tests/bsim/bluetooth/audio_samples/ccp/call_control_server \
|
||||||
|
sample=${ZEPHYR_BASE}/samples/bluetooth/ccp_call_control_server \
|
||||||
|
conf_file=${sample}/prj.conf \
|
||||||
|
conf_overlay=${sample}/overlay-bt_ll_sw_split.conf \
|
||||||
|
exe_name=bs_${BOARD_TS}_${app}_prj_conf sysbuild=1 compile
|
||||||
|
fi
|
||||||
|
|
||||||
|
wait_for_background_jobs
|
||||||
20
tests/bsim/bluetooth/audio_samples/ccp/tests_scripts/ccp.sh
Executable file
20
tests/bsim/bluetooth/audio_samples/ccp/tests_scripts/ccp.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright 2023-2024 Nordic Semiconductor ASA
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# Simple selfchecking test for the CCP samples.
|
||||||
|
|
||||||
|
simulation_id="ccp_samples_test"
|
||||||
|
verbosity_level=2
|
||||||
|
|
||||||
|
source ${ZEPHYR_BASE}/tests/bsim/sh_common.source
|
||||||
|
|
||||||
|
cd ${BSIM_OUT_PATH}/bin
|
||||||
|
|
||||||
|
Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_audio_samples_ccp_call_control_server_prj_conf \
|
||||||
|
-v=${verbosity_level} -s=${simulation_id} -d=0 -RealEncryption=1 -testid=ccp_call_control_server
|
||||||
|
|
||||||
|
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} \
|
||||||
|
-D=1 -sim_length=20e6 $@ -argschannel -at=40
|
||||||
|
|
||||||
|
wait_for_background_jobs #Wait for all programs in background and return != 0 if any fails
|
||||||
|
|
@ -14,5 +14,6 @@ source ${ZEPHYR_BASE}/tests/bsim/compile.source
|
||||||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/bap_broadcast_sink/compile.sh
|
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/bap_broadcast_sink/compile.sh
|
||||||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/bap_unicast_client/compile.sh
|
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/bap_unicast_client/compile.sh
|
||||||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/cap/compile.sh
|
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/cap/compile.sh
|
||||||
|
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/audio_samples/ccp/compile.sh
|
||||||
|
|
||||||
wait_for_background_jobs
|
wait_for_background_jobs
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue