蓝牙遥控器在T2-U上的应用

简介

Tuya beacon 协议是基于 BLE 广播通信技术,完善配对解绑、组包拆包、群组管理、加密解密、安全策略,形成的一种轻量、安全的可接入涂鸦云的蓝牙协议。

蓝牙 beacon 是基于蓝牙 BLE 技术的一种应用,是蓝牙 BLE 的诸多应用之一。BLE 的通信包括两个主要部分:advertising(广播)和connecting(连接),Beacon 设备只使用了广播通信信道,不和任何低功耗蓝牙主机进行连接,正如 beacon(信标、灯塔)的字面意思。当你在 beacon 遥控器上按下按键后 beacon 遥控器便会发送一个对应的数据包。
在这里插入图片描述

优势

  1. 成本低,无需使用任何模组,只需要一个 16 脚的 IC 和少量的外围器件就可以实现遥控器的硬件方案。
  2. 遥控器无需配网,支持被控的设备已激活状态下配对,也支持未激活未配网设备处于低功耗状态下配对。配对成功后,设备离线也仍然可以被遥控器控制。
  3. 控制范围大,无需对准设备即可控制。红外遥控器需要对准产品上的红外接收头才能正确接收。
  4. 最大支持 4 个群组。

配网模式中涉及到的低功耗,是指关闭射频模组,芯片并非进入了睡眠模式。配网模式详细说明可参考:https://developer.tuya.com/cn/docs/iot-device-dev/TuyaOS-iot_abi_network_config_mode?id=Kc67tro6mzaz0

使用流程

  1. 注册蓝牙 beacon 数据接收回调函数。此接口在需要使用蓝牙遥控器功能下必须调用,当用户没有注册蓝牙遥控器数据处理回调函数时,SDK将不启动蓝牙广播扫描,蓝牙遥控器功能不可用。
//callback function for advertisement scanning data processing
typedef VOID (*TUYA_BLE_APP_SCAN_HANDLE)(UCHAR_T *data, UCHAR_T len,  UCHAR_T type, UCHAR_T* mac);

OPERATE_RET tuya_ble_reg_app_scan_adv_cb(TUYA_BLE_APP_SCAN_HANDLE cb);

注:

  1. 使用蓝牙 beacon 遥控器之前需先调用 TuyaOS 联网单品设备初始化,“设备初始化"详细说明可参考:https://developer.tuya.com/cn/docs/iot-device-dev/TuyaOS-iot_abi_device_init?id=Kc67dkj0mxrne。
  1. 注册蓝牙遥控器绑定校验,绑定/解绑通知回调函数,通过注册的两个函数可以进行蓝牙遥控器绑定判断和得到是否成功绑定的结果。
typedef struct {
  BLE_SCAN_ADV_BIND_CHECK_CB    bind_check;
  BLE_SCAN_ADV_BIND_RSLT_NOTIFY_CB bind_notify;
} TUYA_BLE_SCAN_ADV_HANDLE_CBS;

/**
 \* @brief Register callback function for advertisement scanning data processing
 *
 * @param[in] cbs: callback function
 *
 * @note This API is used for registering callback function for advertisement scanning data processing
 *
 * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 */
OPERATE_RET tuya_ble_reg_app_scan_adv_handle_cbs(TUYA_BLE_SCAN_ADV_HANDLE_CBS* cbs);
  • 可在遥控器绑定校验回调中做指令校验,可通过返回 OPRT_OKOPRT_ERR_COMMON 允许/拒绝当前遥控器绑定。
  • 在遥控器绑定/解绑通知回调函数 bind_notify 中做如指示灯状态提示,可帮助产品使用者判断当前遥控器绑定状态。

注:当前函数 tuya_ble_reg_app_scan_adv_handle_cbs() 非必须调用,如未调用该接口,可通过tuya_ble_reg_app_scan_adv_cb() 注册的数据接收回调函数中通过命令字获取绑定/解绑状态。

  1. 蓝牙遥控器绑定窗口时间设置函数。该函数也可以不调用,默认绑定窗口时间为 30s。
/**
 * @brief Set timeout window for binding remote controller
 *
 * @param[in] time_out: time out in second, 0: no window
 *
 * @note This API is used for setting timeout window for binding remote controller
 *
 * @return VOID
 */
VOID_T tuya_ble_set_bind_window(UINT_T time_out);
  1. 手工打开蓝牙遥控器绑定窗口。设备在每次上电后自动开启蓝牙绑定窗口,直至绑定窗口时间超时后关闭。此函数用于在TuyaOS关闭蓝牙遥控器绑定窗口后,手工开启设备绑定窗口,如使用按钮触发使设备再次进入蓝牙遥控器绑定窗口
/**
 * @brief Open window for binding remote controller
 *
 * @param[in] VOID
 *
 * @note This API is used for opening window for binding remote controller
 *
 * @return VOID
 */
VOID_T tuya_ble_open_bind_window(VOID_T);

注:该函数不能用于设备配网状态下,否则会导致设备蓝牙配网失败。

示例代码

遥控器命令表

#define BLE_KEY_TYPE_CMD                0x01   //健值
#define BLE_BIND_CMD                    0x02   //绑定
#define BLE_UNBIND_CMD                  0x03   //解绑
#define BLE_SWITCH_CMD                  0x04   //开关
#define BLE_FAVORITES_CMD               0x05   //喜好收藏
#define BLE_SCHEDULED_CLOSE_CMD         0x06   //倒计时
#define BLE_GROUP_CHECK_CMD             0x07   //一键群组查询

#define BLE_LIGHT_SWITCH_CMD            0x08   //照明开关
#define BLE_LIGHT_BRIGHT_STEP_CMD       0x09   //照明步进调亮度
#define BLE_LIGHT_BRIGHT_STEPLESS_CMD   0x0a   //照明无极调亮度
#define BLE_LIGHT_TEMP_STEP_CMD         0x0b   //照明步进调色温
#define BLE_LIGHT_TEMP_STEPLESS_CMD     0x0c   //照明无极调色温
#define BLE_LIGHT_SEVEN_COLOR_CMD       0x0d   //七彩调节
#define BLE_LIGHT_COLOE_H_STEP_CMD      0x0e   //H 值调节
#define BLE_LIGHT_COLOE_H_DIMMING_CMD   0x0f   //H 值无极调节
#define BLE_LIGHT_COLOE_S_STEP_CMD      0x10   //S 值调节
#define BLE_LIGHT_COLOE_S_DIMMING_CMD   0x11   //S 值无极调节
#define BLE_LIGHT_COLOE_V_STEP_CMD      0x12   //V 值调节
#define BLE_LIGHT_COLOE_V_DIMMING_CMD   0x13   //S 值无极调节
#define BLE_LIGHT_COLOE_HSV_CMD         0x14   //HSV 值调节
#define BLE_LIGHT_SCENE_CHANGE_CMD      0x15   //场景调节
#define BLE_LIGHT_MODE_SET_CMD          0x16   //模式设置
#define BLE_SPECIAL_MODE               0x17   //夜灯模式

#define BLE_RGBY_CONTROL_CMD            0xff   //定制rgby方向调节颜色

遥控器代码实现

/**
* @brief 
*
* @param[in] data: data
* @param[in] len: data len
* @param[in] type: type
* @param[in] mac: device mac
* @return none
*/
STATIC VOID ble_receive_callback(UCHAR_T *data, UCHAR_T len,  UCHAR_T type, UCHAR_T* mac)
{
    INT_T i = 0;

    if(type == 0xff){
        TAL_PR_DEBUG("ble remote(old ver): data len: %d", len);
        for ( i = 0; i < len; i++) {
            TAL_PR_DEBUG("data[%d] : %d", i, data[i]);        
        }
    }else if(type == 0x16){
        TAL_PR_DEBUG("ble remote(new ver): data len: %d", len);
        UCHAR_T *data_cmd = (data + 2);

        //解析控制数据
        switch(data_cmd[2]){
            case BLE_BIND_CMD:
                //do binding operation
                TAL_PR_NOTICE("=====bind success!!!=====");
                break;

            case BLE_UNBIND_CMD:
                //do unbinding operation
                TAL_PR_NOTICE("====unbind success!!!====");
                break;

            default:
                //do ctrl operation
                TAL_PR_DEBUG("====please do ctrl operation!!!==== cmd: [%02x], cmd len: [%02d]", data_cmd[2], len - 2);
                // do_handle(&(data_cmd[2]),len-2); 
                break;
        }
    }

    return;
}

/**
* @brief ble scanf adv bind check callback
*
* @param[in] type: bind type for bluetooth remote controller
* @param[in] data: data
* @param[in] len: data len
* @return OPRT_OK
*/
STATIC OPERATE_RET ble_scan_adv_bind_check_callback(TUYA_BLE_BIND_TYPE type, UCHAR_T *data, UCHAR_T len)
{
    INT_T i = 0;
    
    TAL_PR_DEBUG("----------------scan adv bind check cb-----------------");
    TAL_PR_DEBUG("ble bind type : %d, data len: %d", type, len);
    for(i=0;i<len;i++) {
        TAL_PR_DEBUG("data[%d] : %d", i, data[i]);
    }

    return OPRT_OK;
}

/**
* @brief ble scan adv bind notify callback
*
* @param[in] type: bind type for bluetooth remote controller
* @return none
*/
STATIC VOID_T ble_adv_scan_bind_notify_callback(TUYA_BLE_BIND_TYPE type, int rslt)
{
    TAL_PR_DEBUG("------------------ble scan adv bind notify cb----------------");
    TAL_PR_DEBUG("ble bind type : %s", (type == TUYA_BLE_OP_BIND) ? "bind" : "unbind");
    TAL_PR_DEBUG("result : %s", (rslt == 0) ? "success" : "failed");

    return ;
}

/**
* @brief  ble remote init
*
* @param[in] param: none
* @return none
*/
VOID ble_remote_init(VOID)
{
    OPERATE_RET rt = OPRT_OK;
    TUYA_BLE_SCAN_ADV_HANDLE_CBS ble_scan_cfg = {0};
    ble_scan_cfg.bind_check = ble_scan_adv_bind_check_callback;
    ble_scan_cfg.bind_notify = ble_adv_scan_bind_notify_callback;

    /* Register callback function for advertisement scanning data processing */
    TUYA_CALL_ERR_GOTO(tuya_ble_reg_app_scan_adv_cb(ble_receive_callback), __EXIT);

    /* Register callback function for advertisement scanning data processing */
    TUYA_CALL_ERR_GOTO(tuya_ble_reg_app_scan_adv_handle_cbs(&ble_scan_cfg), __EXIT);

    /* set bind window (s) */
    tuya_ble_set_bind_window(30);

__EXIT:
    return;
}

可根据具体项目情况

  1. ble_scan_adv_bind_check_callback() 回调函数中实现对遥控器数据做判断,如判读正确返回 OPRT_OK表示允许绑定,否则返回 OPRT_COM_ERROR表示不允许绑定。
  2. ble_adv_scan_bind_notify_callback() 回调函数中实现绑定/解绑指示。
  3. ble_receive_callback() 回调函数中实现控制逻辑代码。

开启遥控器配对功能

ble_remote_config() 加入 tuyaos_demo_quickstart 项目,加入到 __soc_device_init() 函数最后。由于设备在未配网状态下同样会开启蓝牙用于配网,如在未配网状态下开启遥控器配对功能会导致蓝牙配网失败。

OPERATE_RET __soc_device_init(VOID_T)
{
    OPERATE_RET rt = OPRT_OK;

#if (defined(UUID) && defined(AUTHKEY))
    ws_db_init_mf();

    /* Set authorization information
     * Note that if you use the default authorization information of the code, there may be problems of multiple users and conflicts, 
     * so try to use all the authorizations purchased from the tuya iot platform.
     * Buying guide: https://developer.tuya.com/cn/docs/iot/lisence-management?id=Kb4qlem97idl0.
     * You can also apply for two authorization codes for free in the five-step hardware development stage of the Tuya IoT platform.
     * Authorization information can also be written through the production testing tool.
     * When the production testing function is started and the authorization is burned with the Tuya Cloud module tool, 
     * please comment out this piece of code.
     */
    WF_GW_PROD_INFO_S prod_info = {UUID, AUTHKEY};
    TUYA_CALL_ERR_RETURN(tuya_iot_set_wf_gw_prod_info(&prod_info));
#else
    // 产测初始化, 注册函数需要应用实现,其中串口驱动不需要应用提供
    MF_IMPORT_INTF_S intf = {0};

    intf.uart_init = mf_uart_init_callback;
    intf.uart_free = mf_uart_free_callback;
    intf.uart_send = mf_uart_send_callback;
    intf.uart_recv = mf_uart_recv_callback;

    intf.gpio_test = mf_gpio_test_cb;
    intf.mf_user_product_test = mf_user_product_test_callback;
    intf.user_callback = mf_user_callback;
    intf.user_enter_mf_callback = mf_user_enter_mf_callback;
    intf.user_pre_gpio_test = mf_pre_gpio_test_cb;

    TAL_PR_ERR("mf_init APP_BIN_NAME[%s] USER_SW_VER[%s]", APP_BIN_NAME, USER_SW_VER);
    
    TUYA_CALL_ERR_RETURN(mf_init(&intf, APP_BIN_NAME, USER_SW_VER, TRUE));
#endif

    /* Initialize TuyaOS product information */
    TY_IOT_CBS_S iot_cbs = {0};
    iot_cbs.gw_status_cb = __soc_dev_status_changed_cb;
    iot_cbs.gw_ug_cb = __soc_dev_rev_upgrade_info_cb;
    iot_cbs.gw_reset_cb = __soc_dev_restart_req_cb;
    iot_cbs.dev_obj_dp_cb = __soc_dev_obj_dp_cmd_cb;
    iot_cbs.dev_raw_dp_cb = __soc_dev_raw_dp_cmd_cb;
    iot_cbs.dev_dp_query_cb = __soc_dev_dp_query_cb;

    TUYA_CALL_ERR_RETURN(tuya_iot_wf_soc_dev_init(GWCM_OLD, WF_START_AP_FIRST, &iot_cbs, PID, USER_SW_VER));

    TUYA_CALL_ERR_RETURN(tuya_iot_reg_get_wf_nw_stat_cb(__soc_dev_net_status_cb));

    /* Network button, LED initialization */
    app_led_init(LED_PIN);
    app_key_init(KEY_PIN);

    ble_remote_init();
    
    return 0;
}

运行

设备重新上电,进入蓝牙 beacon 遥控器配对模式。

同时长按蓝牙遥控器的分组键,(如果你的蓝牙遥控器没有分组键,那么开关键就是默认的分组1),蓝牙遥控器开始和设备配对。

[09-13 16:20:18 TUYA D][example_ble_remote.c:113] ----------------scan adv bind check cb-----------------
[09-13 16:20:18 TUYA D][example_ble_remote.c:114] ble bind type : 1, data len: 12
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[0] : 11
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[1] : 7
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[2] : 1
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[3] : 255
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[4] : 2
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[5] : 1
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[6] : 255
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[7] : 92
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[8] : 139
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[9] : 0
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[10] : 211
[09-13 16:20:18 TUYA D][example_ble_remote.c:116] data[11] : 206

蓝牙状态发送变化,进入蓝牙事件回调函数中。

[09-13 16:20:18 TUYA D][example_ble_remote.c:130] ------------------ble scan adv bind notify cb----------------
[09-13 16:20:18 TUYA D][example_ble_remote.c:131] ble bind type : bind
[09-13 16:20:18 TUYA D][example_ble_remote.c:132] result : success

按下蓝牙遥控器的控制键。进入数据处理回调函数中。

[09-13 16:20:27 TUYA D][example_ble_remote.c:75] ble remote(new ver): data len: 9
[09-13 16:20:27 TUYA D][example_ble_remote.c:92] ====please do ctrl operation!!!==== cmd: [04], cmd len: [07]

同时长按蓝牙遥控器的亮度-和配对时的分组键,开始解绑流程。

设备解绑,状态发生变化,进入蓝牙事件回调函数中。

[09-13 16:24:11 TUYA D][example_ble_remote.c:75] ble remote(new ver): data len: 9
[09-13 16:24:11 TUYA N][example_ble_remote.c:87] ====unbind success!!!====
[09-13 16:24:11 TUYA D][example_ble_remote.c:130] ------------------ble scan adv bind notify cb----------------
[09-13 16:24:11 TUYA D][example_ble_remote.c:131] ble bind type : unbind
[09-13 16:24:11 TUYA D][example_ble_remote.c:132] result : success

示例下载

https://www.tuyaos.com/download/file.php?id=2832

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
时下智能语音交互市场火热,越来越多的设备都开始支持远场AI语音交互。 例如:智能音箱,智能电视等等。但这类产品的识别率和误唤醒率还需再不断的优化提升,以至于日常生活中人们还是离不开各式各样的遥控器。而蓝牙语音遥控器这一产品,作为远场语音交互的一个近场配件,也搭上了这趟语音交互的快速列车,成长速度令人惊讶。基于Actions炬芯的ATB1103芯片的语音遥控器,打造了一个AIoT时代的高性价比精品。 一、遥控器应用总体架构 遥控器总体架构分四层,从上到下依次为应用层、应用框架层、硬件抽象层、底层驱动层 1.1、应用层 • 应用状态机– 事件触发让遥控器应用处理不同的状态 • 应用定时器– 定时触发不同的事件,驱动遥控器正常运行 • 应用输入处理– 处理底层来的不同按键消息 • 应用音频输入处理– 将底层的音频处理消息,进行编码,然后通过蓝牙发送给对端设备 • BLE profile – HID profile,提供按键输入输出接口服务 – BAS service,提供电池服务 – DIS service,提供读取设备基本信息的接口服务 – ota profile,提供OTA 升级服务 1.2、应用框架层 • 输入管理– 按键映射处理、按键过滤机制 • 消息管理– 消息分配和释放、 消息发送和接收 • 内存管理– 动态内存管理 • 闪灯管理– 灯资源分配和释放 • 电池管理– 电量读取、电量管理策略 1.3、硬件抽象层 将应用层和驱动层剥离开的中间件层 1.4、底层驱动层 底层硬件操作接口 二、遥控器模块流程概述 2.1、系统启动 系统相关初始化、板级相关外设初始化、蓝牙协议栈相关初始化、HidApp 应用初始化,并进入Main 主循环,等待消息处理 2.2、遥控器状态机 遥控器在运行过程中,主要靠如下3 种状态维持他的正常运行。 2.2.1. 触发遥控器进去空闲状态的事件: > 广播状态,没有连接成功,出现超时事件,进入idle > 连接状态,断开连接,如无操作主动断开连接,然后进入idle 2.2.2. 触发遥控器进入激活状态的事件: > 空闲状态,有按键、首次上电,进入激活状态 > 连接状态,出现异常断开,需要回连,进入激活状态 2.2.3. 触发遥控器进入工作状态的事件: > 激活状态下,配对成功或者回连成功,进入工作状态。 2.3、按键处理 由于遥控器的键值较多,通常用矩阵键盘方式以节省pin 的使用。当使能Key 模块后,Key 控制器就会处于矩阵扫描状态,当检测到外部按键有值时,就会产生中断,中断就将按键信息上报给应用。 2.4、红外处理 • 在非连接状态下,按下按键,就会发射红外码,进而通过红外操作对端设备,如使用红外进行配对. • IRC 协议上,最短的红外码重发时间为108 ms,而按键的重复上报时间,可能小于108ms,也可能大于108ms,因此按键输入和红外发送模块时间上存在三种可能: 2.4.1. 慢速点按 慢速点按动作特征是在大于Trpc 时间后有多次的按键输入。在Ta 时刻,发出初次按键值,在Tb 时刻,不做任何响应,在Tc 时刻,继续发送检测到的按键值,不会发送重复码. 2.4.2. 快速点按 快速点按的动作特征是用户在Trpc 时间内有两次或者以上的按键按下弹起的动作. 在Ta 时刻,将发送出初次按键,而Tb 时刻并不发送按键值,在Tc 时刻,如果按键仍然是按下状态,将发出按键值,否则将丢掉按键值. 2.4.3. 长按 长按的动作特征是按键按下后,一直不放开。此时CPU 检测到按键的持续按下,则在Ta 时刻发送出初次按键,发送出此时按键对应的红外键码,而在Trpc 时间内没有检测到按键的松开,则在Tb 时间输出重复码,直至检测到按键弹起为止. 2.5、语音采集 • 当启动Voice Key 后,ADC 开始采集 • 采集的数据通过DMA 搬运到应用的循环buffer 中,同时发送消息给Main 线程,让其处理语音数据。 • 如果Main 线程处理速度不够快,audioin 驱动就会因为分不到buffer,而将采集的语音数据丢弃。 2.6、BLE数据传送 • 将audioin 驱动发送上来的数据进行编码压缩。 • 然后将编码后的压缩数据切成几个20byte 的数据包 • 最后通过hid profile notify 接口发送给BLE 协议栈 2.7、应用软件Timer管理模块 2.8、LED管理模块 遥控器定义了几种LED 指示灯,用于指示遥控器的一些状态,如下表所示 通常遥控器只有一个物理的LED 灯用于各种场景的指示,这就需要软件上让其分时复用,如果同时需要显示两种状态,状态需要定义优先级,优先级高的状态先指示。如在配对模式下,处于闪灯状态下,这时候按下按键,那么灯还是处于快闪状态。 2.9、O

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值