.. _BLE对讲机APP说明:

BLE对讲机APP说明
=======================================

简介
########################

    本章主要介绍基于BLE_TEST接口传输的对讲机应用demo;

    AW30N的对讲机模式目前有三个版本:
            1. 半双工对讲机;(首版SDK即推出)
            2. 全双工对讲机;(aw30n_v1.2.0版本开始推出)
            3. 广播对讲机;(aw30n_v1.3.0版本开始推出)

.. note::
            三个对讲机版本独立使用,打开方式为;

            1. 使用 **半双工对讲机** :
                - **app_modules.h** 文件里打开 **RF_RADIO_EN**;
            2. 使用 **全双工对讲机** :
                - **app_modules.h** 文件里打开 **RF_RADIO_EN** 和 **FULL_DUPLEX_RADIO** 宏;
            3. 使用 **广播对讲机** :
                - **app_modules.h** 文件里打开 **RF_RADIO_EN**;
                - **test_app_config.h** 文件里打开 **PADVB_WL_MODE** 宏;  

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


    对讲机模式应用demo涉及文件位置按模块与方案区分位置如下,
        对讲机模式公共部分代码(半双工对讲机、全双工对讲机以及广播式对讲机都会用到的代码):
            * apps/app/src/mbox_flash/rf_radio/rf_radio_app.c
            * apps/app/src/mbox_flash/rf_radio/rf_radio_app.h
            * apps/app/src/mbox_flash/rf_radio/rf_radio_comm.c
            * apps/app/src/mbox_flash/rf_radio/rf_radio_comm.h
            * apps/app/src/mbox_flash/rf_radio/rf_radio_app_key.c
        
        带连接对讲机方案公共部分代码(半双工对讲机和全双工对讲机所使用的公共部分代码):
            * apps/app/src/mbox_flash/rf_radio/connect_radio/connect_radio.c
            * apps/app/src/mbox_flash/rf_radio/connect_radio/connect_radio.h

        半双工对讲机方案使用的代码:
            * apps/app/src/mbox_flash/rf_radio/connect_radio/half_duplex/rf_half_duplex.c
            * apps/app/src/mbox_flash/rf_radio/connect_radio/half_duplex/rf_half_duplex.h
            * apps/app/src/mbox_flash/rf_radio/connect_radio/half_duplex/rf_half_receive.c
            * apps/app/src/mbox_flash/rf_radio/connect_radio/half_duplex/rf_half_send.c

        全双工对讲机方案使用的代码:
            * apps/app/src/mbox_flash/rf_radio/connect_radio/full_duplex/rf_full_duplex.c
            * apps/app/src/mbox_flash/rf_radio/connect_radio/full_duplex/rf_full_duplex.h

        广播式对讲机方案使用的代码:
            * apps/app/src/mbox_flash/rf_radio/padv/padv_radio.c
            * apps/app/src/mbox_flash/rf_radio/padv/padv_radio.h

    该应用demo依赖以下模块:
        * audio adc / dac;
        * decoder / encoder;
        * audio_rf_trans管理;
        * ble_test传输;

    应用选择说明:
        1. app_modules.h文件打开"RF_RADIO_EN"对讲机宏定义;
            .. image:: rf_radio_app_macro.png
                :alt: "对讲机应用宏定义使能"
                :align: center
            .. centered:: 对讲机应用宏定义使能

            * 如果是使用全双工对讲机模式,还需要打开FULL_DUPLEX_RADIO宏,但是由于全双工对讲机的ram使用比较紧张,需要关闭MP3和WAV等解码才可编译通过
            * v1.3.0版本SDK加入了基于ble周期广播应用的广播式对讲机。使用时除了需要在app_modules.h打开对讲机功能开关,还需要在apps/app/bsp/commom/bt_common/ble_test/test_app_config.h打开PADVB_WL_MODE功能宏才能使用周期广播对讲机模式。V1.3.0版本默认打开广播对讲机功能宏。

            
        2. bt_ble.h文件打开BLE_TEST宏定义;
            .. image:: rf_radio_ble_macro.png
                :alt: "对讲机应用BLE模式选择"
                :align: center
            .. centered:: 对讲机应用BLE模式选择

        3. app.c文件中,work_mode选择RF_RADIO_MODE;
            .. image:: rf_radio_app_sel.png
                :alt: "对讲机应用选择"
                :align: center
            .. centered:: 对讲机应用选择



^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. _BLE对讲机应用流程说明:

半双工以及全双工对讲机应用流程说明
#########################################

    应用简易流程示意图
    
    .. image:: radio_app_simple_process.png
        :alt: "对讲机应用简易流程示意图"
        :align: center
    .. centered:: 对讲机应用简易流程示意图

    应用低功耗策略:
        1. 连接时,连接间隔由主机决定;
        2. 应用处于工作(传输数据)或者空闲时,会调整连接间隔实现数据传输或者低功耗保持;
            - 启动音频传输时,发送方请求更新连接间隔为 **RADIO_WORKING_INTERVAL**,减小连接间隔并开始发送数据;
            - 停止音频传输后,发送方请求更新连接间隔为 **RADIO_STANDBY_INTERVAL**,增大连接间隔并进入standby状态降低功耗并保持低功耗连接;
            - 连接间隔修改需要响应时间,会导致启动延时变大,用户可根据自身需求修改连接间隔时间;
        3. 应用无操作50s后进入软关机休眠;
        4. 近端启动对讲前需要发送start命令包给远端,远端收到后回复接收初始化成功的ack命令后,近端才开始发送数据;

.. note::

        在带连接的对讲机方案里,修改蓝牙 **工作** / **空闲** 时的连接间隔 由 **RADIO_WORKING_INTERVAL** / **RADIO_STANDBY_INTERVAL** 宏控制;

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  


        .. image:: rf_radio_lowpwr.png
            :alt: "对讲机应用低功耗策略说明"
            :align: center
        .. centered:: 对讲机应用低功耗策略说明


    半双工对讲机主从机同时发送数据策略:
        1. 主从机同时发送时,优先响应主机发送的数据,从机会停止发送并切换到接收状态;

    对讲机传输质量和距离建议:
        1. 音频传输质量和距离,与蓝牙连接间隔与重发次数有关;
            - 对讲机默认传输ump2编码数据,以该格式为例;
            - 32k采样率编码Ump2格式,码率80kbps。编码输出包长为120byte,则在该码率下ump2一帧数据编码周期约为12ms,若蓝牙在工作状态下连接间隔为3ms,则两帧数据间有四次发送机会;
            - 采样率改为16k,码率为40kbps。编码输出包长为120byte,则在该码率下一帧数据编码周期约为24ms,若蓝牙在工作状态下连接间隔仍为3ms,则两帧数据有八次发送机会,稳定性和距离都会提升;
        2. 一帧数据编码周期与连接间隔保持倍数关系,可保证重发次数的稳定;
            - 使用其他编码格式时,可根据编码周期调整蓝牙连接间隔;
            - 简易GATT服务支持私有连接间隔配置,可修改蓝牙连接间隔;(相关阅读::ref:`简易GATT服务私有连接间隔说明`)

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. _广播式对讲机应用说明:

广播式对讲机应用说明
##########################################

    v1.3.0 SDK开始加入周期广播式对讲机,支持一个广播端对多个扫描端进行单向通信,扫描端也可通过按键形式切换成广播端。

    此应用使用蓝牙周期广播实现,周期广播具体章节介绍:->”:ref:`周期广播(periodic_advertise)介绍`“;

        
    收发策略:
        1. 发送端在广播包头加上序号(结构体PADV_PACKET_HEADER),编码输出的数据以及其他用户数据直接从 **发送队列** 读取到全局缓存g_adv_data_buf,将排列好的数据一次通过push_data传给蓝牙;
        2. 队列中无数据输出时,直接退出回调,让蓝牙继续广播上一次填入的数据;
        3. 接收端对广播包序号相同的数据进行过滤,序号与上一次接收到相同的包视为接收过的数据,直接抛弃。

    延时优化策略:
        1. 接收端在推出SYNC_SUCCESS事件时,可直接发命令到主循环启动解码(可参考函数padv_radio_post_start_cmd)。该方式需要收发双方提前约定好使用的编解码配置;
        2. 去掉接收端的编码数据缓存门限,收到数据后立刻触发解码;

    .. image:: radio_enc_data_gate.png
        :alt: "接收端编码数据门槛"
        :align: center
    .. centered:: 接收端编码数据门槛

    功耗优化建议:
        周期广播由于通信间隔较短,传输时的功耗比较高。以此建议配置给蓝牙使用的广播包长尽量缩短,通过传输时减少对带宽的占用来降低功耗。

    广播式对讲机传输质量和距离建议:
        音频传输质量和距离,与蓝牙广播间隔(间隔越长重发次数越多)以及广播包长有关(以下以1M PHY来举例);
        
        - 公版SDK的广播对讲机默认使用jla_lw编码传输音频数据,以该格式为例。16k采样率编码jla_lw格式。一帧数据 **编码周期** 约为20ms, **编码输出包长** 为90byte。
            .. note:: 在其他 **采样率、码率以及编码格式** 配置下的编码输出,可以在rf_enc_output函数打印len参数以及翻io口得知 **编码输出包长** 和 **编码周期** ;
       
        - 若蓝牙 **广播间隔** 为20ms, 即两帧数据之间有8次重发机会(蓝牙获取编码输出的数据之后,蓝牙底层自行重发),**重发次数** 越多,接收端越容易收到数据;
            .. note:: 在蓝牙 **广播间隔** 一定的情况下,**重发次数** 2.5ms一次(1M PHY)。例如 **广播间隔** 20ms,最多可以达到的 **重发次数** 为20ms/2.5ms=8次;(相关阅读::ref:`周期广播(periodic_advertise)介绍`)
        
        - 广播包长尽可能缩短,稳定性和距离都会提升。
            .. note:: 用户选择 **仅传输音频时的广播包长** ,需要留意编码数据输出后到蓝牙发送前的数据处理流程。一共有两次处理数据流程:
            
                - 1、编码输出到 **发送队列** 之前会经过一次打包,会加上10个byte的头,用于接收端unpacket时解析。
                - 2、广播事件回调读取 **发送队列** 的数据后会在缓存前添加广播包头,用于接收端过滤序号一样的广播包。
            
             因此在选择广播包长时需要算上每次数据处理加上的数据长度,例如公版SDK传输音频的数据长度2byte(周期广播应用写给蓝牙之前加上的包头)+8byte(数据包头)+90byte(jla_lw编码一次输出)=100byte; 

            如果用户在传输音频的过程中有其他类型数据的传输流程,也需要将其考虑在广播需要达到的码率当中

        - 使用带有 **丢包修复** 的编解码格式,可优化卡音距离,比如jla_lw格式

               
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


应用变量和接口说明
#######################

对讲机模式公共部分接口说明
----------------------------------------


变量u32 app_softoff_jif_cnt
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该变量为关机倒计时变量,当有按键或者接收中断到来会重置关机倒计时时间,用于带连接方案;

变量u32 app_standby_jif_cnt
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该变量为低功耗standby倒计时变量,当有按键或者接收中断到来会重置关机倒计时时间,用于带连接方案;

函数void rf_radio_app_init(void)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该函数为对讲机应用公共模块初始化函数;
        
        1. 初始化按键、解码器等;
        2. 初始化音频模块;
        3. 初始化应用句柄;

函数void rf_radio_app_uninit(void)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该函数为对讲机应用退出函数;

        - 退出步骤分为:
            1. 恢复音频模块;
            2. 注销按键;

函数void rf_radio_app(void)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该函数为对讲机应用入口,函数中包含带连接对讲机和广播式对讲机方案的函数入口,只能选择一个运行;

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

带连接对讲机方案接口说明(仅包含半双工对讲机和全双工对讲机)
------------------------------------------------------------------

带连接对讲机公共变量与接口说明
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

变量audio2rf_send_mge_ops rf_radio_ops
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该变量管理对讲机(带连接方案)发送端接口,包含发送函数、状态查询函数、可发送长度查询函数;

函数int rf_radio_send_api(u8 \*data, u16 len)
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数为对讲机(带连接)发送接口;

        1. data:发送的数据buff;
        2. len:发送的数据长度;
        3. 返回值:0:成功 非0:失败;

函数int rf_radio_check_status_api(void)
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数为对讲机(带连接)无线传输模块状态查询函数;

        1. 返回值:1:可正常发送 0:异常;

函数int rf_radio_get_valid_len_api(void)
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数实现查询你当前无线传输可发送的字节长度,应用用于带连接方案;

        1. 返回值:当前无线传输可发送的字节长度;

函数u32 rra_send_ack_cmd(queue_obj \*p_queue, u8 ack_cmd, u8 ack_data)
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数用于带连接对讲机方案,接收端收到发送端发来的START包后,接收端调用该函数实现对发送端做应答机制,其中参数:

        1. p_queue:发送数据所需要的队列指针;
        2. ack_cmd:发送ack命令的命令类型;
        3. ack_data:命令包包含的数据内容
        4. 返回值:0:ack命令包成功写入发送队列;非0:命令包未能写入发送队列

函数void connect_radio_bt_init()
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数用于带连接对讲机方案,主要包含蓝牙模块的初始化流程;

函数void connect_radio_bt_init()
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数用于带连接对讲机方案,主要包含蓝牙模块的关闭和注销流程;


函数int rrapp_idle(rev_fsm_mge \*p_recv_ops)
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数为半双工对讲机与全双工空闲状态处理函数,用于低功耗保持连接;其中参数:

        1. p_recv_ops:状态机句柄,在该函数中用于轮询是否有收到unpacket拆包流程下发到应用的命令;

函数void rf_radio_connect_app(void)
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数为带连接对讲机方案入口函数,主要流程如下:

        1、蓝牙模块初始化;
        2、音频硬件初始化;
        3、对讲机主循环入口(半双工、全双工对讲机只能运行其中一个);
        4、关闭蓝牙模块;



半双工对讲机变量与接口说明
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

变量connect_rf_mge g_half_rf_mge
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该变量为半双工对讲机应用状态句柄,主要包含收发状态标志和发送音频所使用的队列,以及回复ack所使用的队列;

变量rev_fsm_mge g_half_packet
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该变量为半双工对讲机应用unpacket拆包句柄;

变量rfr_dec g_half_dec
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该变量为半双工对讲机应用解码以及数据流相关句柄;

函数void rf_radio_half_duplex_loop(void)
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数为半双工对讲机应用入口,函数中包含对讲机应用各个句柄初始化、回调注册、缓存注册,以及idle、sending和rrapp_receiving三种对讲机状态。

函数void rfr_half_send_queue_init(void)
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数实现初始化应用回复ack命令所需的队列,注册之后ack命令通过listener_queue队列发给蓝牙;

函数bool rrapp_sending(int active_msg)
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数为半双工对讲机发送状态处理函数;

函数u8 rrapp_receiving(int active_msg)
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数为半双工对讲机接收状态处理函数;


全双工对讲机变量与接口说明
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

变量connect_rf_mge g_full_rf_mge
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该变量为全双工对讲机应用状态句柄,主要包含收发状态标志和发送音频所使用的队列,以及回复ack所使用的队列;

变量rev_fsm_mge g_full_packet
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该变量为半双工对讲机应用unpacket拆包句柄;

变量rfr_dec g_full_dec
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该变量为半双工对讲机应用解码以及数据流相关句柄;

函数u8 fd_rrapp_loop(int active_msg)
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该函数为全双工对讲机发送与接收状态处理函数;


广播式对讲机变量与接口说明
---------------------------------------------------

变量enc_obj \*sp_padv_enc_obj
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该变量为广播式对讲机发送端编码句柄指针,编码成功启动后,可从该变量获取编码相关信息;

变量padv_mge g_padv_radio
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该变量为广播式对讲机应用状态句柄,主要包含收发状态标志和发送音频所使用的队列;

变量queue2vble_tx_send_mge_ops padv_ops
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该变量管理广播式对讲机发送端获取发送端队列句柄接口和读取队列数据接口

变量rfr_dec g_padv_dec
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该变量为广播式对讲机应用解码以及数据流相关句柄;

变量rev_fsm_mge padv_packet
"""""""""""""""""""""""""""""""""""""""""""""""""""""
    .. note:: 该变量为广播式对讲机应用unpacket拆包句柄;

函数void rf_radio_padv_app(void)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该函数为广播式对讲机应用入口。包含初始化,应用主循环和退出流程。

函数void rf_radio_padv_init(void)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该函数为广播式对讲机蓝牙模块初始化接口;

函数void rf_radio_padv_uninit(void)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该函数为广播式对讲机应用关闭蓝牙模块接口;

函数void padv_rapp_loop(void)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    .. note:: 该函数为广播式对讲机应用主循环。收发流程和低功耗都在该函数运行;