Testing and Authorization

Last Updated on : 2024-06-25 04:02:45download

Testing and authorization is the process of writing a license to the non-volatile memory on a device for the purpose of authentication with the Tuya Developer Platform. TuyaOS provides APIs for testing and authorization, with the communication between devices and Tuya’s production software encapsulated.

This topic describes how to implement testing and authorization with TuyaOS Gateway Development Framework.

Background

A license written to a device acts as a credential to authenticate with the Tuya Developer Platform. Each license is unique and can only be used on one device. Otherwise, the connection to the Tuya Developer Platform will fail.

Generally, you write licenses to devices in the production testing process. Tuya offers an integrated solution to help you perform authorization and testing in one place. You can integrate Tuya’s production testing software for the host computer into your production line and implement the corresponding functionality on the device side. This way, authorization can be done in the production testing process.

How to

TuyaOS provides the production testing service API. You can call tuya_testframe_handle_init to enable the production testing service after gateway pre-initialization.

Port number modification

TuyaOS production testing service communicates with the production testing software for the host computer through the TCP protocol. The default port number is 12130. If this port has been occupied, you can call tuya_testframe_set_tcp_port to change the port number.

Testing and authorization

TuyaOS production testing service API includes a set of callbacks. Implement the callback for the production testing function you enabled.

TuyaOS production testing functions consist of common tests on various components, such as buttons, indicators, and speakers. If your existing production testing system already has these test items covered, you can ignore them and only enable writing authorization information.

The following table lists the required callbacks for testing and authorization.

Callback Description
TYTEST_FRAME_CBS_S -> master_firm_frame_cb Read the version of the main firmware.
TYTEST_FRAME_CBS_S -> w_cfg_frame_cb Write authorization information.
TYTEST_FRAME_CBS_S -> r_cfg_frame_cb Read authorization information.

Radio frequency (RF) test

Test the RF performance of Tuya’s modules.

RF test callbacks:

Callback Description
TYTEST_FRAME_CBS_S -> zigbee_rf_frame_cb Test the RF performance of Zigbee modules. During the testing process, the Zigbee module sends N packets to the specified channel of the Zigbee beacon. You determine the RF performance based on the number of packets that the Zigbee module receives from the Zigbee beacon.
TYTEST_FRAME_CBS_S -> ble_rf_frame_cb Test the RF performance of Bluetooth modules. During the testing process, a mobile phone acts as a Bluetooth beacon. The Bluetooth module returns the RSSI after receiving a packet from the mobile phone. You determine the RF performance based on the RSSI.

Example

#include "tuya_testframe_handle.h"

#define M_ENABLE_ZIG_RFTEST 0
#define M_ENABLE_BLE_RFTEST 0

/**
 * @brief Read the version of the main firmware.
 *
 * @param[out] out_buf The version of the main firmware, a JSON string.
 *                     Field      Type      Description
 *                     ret       Boolean   The operation result, true for success and false for failure.
 *                     firmName  String    The firmware name, which must be the same as the one specified in the production work order.
 *                     firmVer   String    The firmware version, which must be the same as the one specified in the production work order.
 *
 * @return 0 for success. Other values for failure.
 */
STATIC INT_T __prod_test_r_master_firmware_info(CHAR_T *out_buf)
{
    if (NULL == out_buf) {
        return OPRT_INVALID_PARM;
    }

    // FIXME: Replace all example values with your own.
    sprintf(out_buf, "{\"ret\":true,\"firmName\":\"tuyaos-gw-integrated\",\"firmVer\":\"%s\"}", "9.9.9");

    return OPRT_OK;
}

/**
 * @brief Write authorization information.
 *
 * @param[in] auzkey   The AUTHKEY.
 * @param[in] uuid     The UUID.
 * @param[in] pid      The product ID (PID).
 * @param[in] prodtest This parameter is deprecated.
 * @param[in] ap_ssid  The SSID of the wireless access point.
 * @param[in] ap_pwd   The password of the wireless access point.
 * @param[in] psk      The pre-shared key (PSK).
 *
 * @return 0 for success. Other values for failure.
 */
STATIC INT_T __prod_test_w_auth_info(CHAR_T *auzkey,
                                     CHAR_T *uuid,
                                     CHAR_T *pid,
                                     INT_T  prodtest,
                                     CHAR_T *ap_ssid,
                                     CHAR_T *ap_pwd,
                                     CHAR_T *psk)
{
    /**
     * If no special requirements exist, you only need to write `auzkey` and `uuid` to the non-volatile memory.
     * Call `tuya_iot_set_gw_prod_info` to set the authorization information to TuyaOS.
     */
    return OPRT_OK;
}

/**
 * @brief Read authorization information.
 * @note To ensure the authorization information is written successfully, verification is required.
 *
 * @param[in] auzkey   The AUTHKEY.
 * @param[in] uuid     The UUID.
 * @param[in] pid      The product ID (PID).
 * @param[in] prodtest This parameter is deprecated.
 * @param[in] ap_ssid  The SSID of the wireless access point.
 * @param[in] ap_pwd   The password of the wireless access point.
 * @param[in] psk      The pre-shared key (PSK).
 *
 * @return 0 for success. Other values for failure.
 */
STATIC INT_T __prod_test_r_auth_info(CHAR_T *auzkey,
                                     CHAR_T *uuid,
                                     CHAR_T *pid,
                                     INT_T  *prodtest,
                                     CHAR_T *ap_ssid,
                                     CHAR_T *ap_pwd,
                                     CHAR_T *psk)
{
    // Read the authorization information from the non-volatile memory and assign it to `auzkey` and `uuid`.
    return OPRT_OK;
}

#if defined(M_ENABLE_ZIG_RFTEST) && (M_ENABLE_ZIG_RFTEST == 1)
STATIC BOOL_T g_zigbee_rf_mode  = FALSE;
STATIC INT_T  g_zigbee_rf_index = 0;

/**
 * @brief The callback for Zigbee RF testing.
 *
 * @param[in] npacket The number of packets received.
 */
STATIC VOID __zigbee_rftest_result(USHORT_T npacket)
{
    if (g_zigbee_rf_mode) {
        // Report the test result asynchronously.
        tuya_testframe_rep_zigbeeRf_event(g_zigbee_rf_index, npacket);
        g_zigbee_rf_mode = FALSE;
    }
}

/**
 * @brief Zigbee RF testing.
 * @note The Zigbee RF testing takes quite some time, so TuyaOS processes it asynchronously, with the `index` used to flag the asynchronous event.
 *      The value of `index` should be included for asynchronous data reporting.
 *
 * @param[in] index  The flag for asynchronous data reporting.
 * @param[in] channel The channel to which the Zigbee module sends packets.
 * @param[in] num  The number of packets transmitted.
 *
 * @return 0 for success. Other values for failure.
 */
STATIC INT_T __prod_test_zigbee_rf_test(INT_T index, INT_T channel, INT_T num)
{
    UCHAR_T rf_data[] = { 0x55, 0xaa, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 }; // Fixed format.

    if (!g_zigbee_rf_mode) {
        PR_DEBUG("zigbee rf test, index: %d, channel: %d, num: %d", index, channel, num);

        g_zigbee_rf_index = index;

        tuya_zigbee_rftest(__zigbee_rftest_result, channel, 13, 12, rf_data, num);

        g_zigbee_rf_mode = TRUE;

        return 0;
    } else {
        PR_WARN("zigbee rf test has run");
        return -1;
    }
}
#endif

#if defined(M_ENABLE_BLE_RFTEST) && (M_ENABLE_BLE_RFTEST == 1)
typedef struct {
    BOOL_T state;
    SCHAR_T rssi;
} PROD_TEST_BT_RSSI_INFO;

STATIC PROD_TEST_BT_RSSI_INFO g_bt_rssi_info = {0};

/**
 * @brief Bluetooth RSSI
 *
 * @param rssi The RSSI value.
 */
STATIC VOID __bt_rssi_cb(SCHAR_T rssi)
{
    PR_DEBUG("rssi: %d", rssi);

    g_bt_rssi_info.state = TRUE;
    g_bt_rssi_info.rssi = rssi;
}

/**
 * @brief Bluetooth RF testing.
 *
 * @param[in] ssid   The name of the Bluetooth beacon.
 * @param[out] rssi  The RSSI value.
 */
STATIC INT_T __prod_test_ble_rf_test(CHAR_T *ssid, INT_T *rssi)
{
    INT_T i = 0;

    PR_ERR("Bluetooth rf test, ssid: %s", ssid);

    memset(&g_bt_rssi_info, 0, SIZEOF(PROD_TEST_BT_RSSI_INFO));

    // Start scanning.
    tuya_bt_rssi_get(TRUE, __bt_rssi_cb, ssid);
    for (i = 0; i < 100; i++) {
        if (g_bt_rssi_info.state) {
            *rssi = g_bt_rssi_info.rssi;

            // Stop scanning.
            tuya_bt_rssi_get(FALSE, NULL, NULL);

            return 0;
        }
        tal_system_sleep(100);
    }
    // Stop scanning.
    tuya_bt_rssi_get(FALSE, NULL, NULL);

    PR_ERR("Bluetooth rf test failed");

    return -1;
}
#endif

OPERATE_RET demo_prod_test(VOID)
{
    OPERATE_RET rt = OPRT_OK;
    TYTEST_FRAME_CBS_S prod_test_cbs = {
        .master_firm_frame_cb  = __prod_test_r_master_firmware_info,
        .w_cfg_frame_cb        = __prod_test_w_auth_info,
        .r_cfg_frame_cb        = __prod_test_r_auth_info,
        #if defined(M_ENABLE_ZIG_RFTEST) && (M_ENABLE_ZIG_RFTEST == 1)
        .zigbee_rf_frame_cb    = __prod_test_zigbee_rf_test,
        #endif
        #if defined(M_ENABLE_BLE_RFTEST) && (M_ENABLE_BLE_RFTEST == 1)
        .ble_rf_frame_cb       = __prod_test_ble_rf_test,
        #endif
    };

    TUYA_CALL_ERR_RETURN(tuya_testframe_handle_init(TPM_TCP, &prod_test_cbs));

    return OPRT_OK;
}

Callback

Read the version of main firmware

/**
 * @brief Read the version of the main firmware.
 *
 * @param[out] out_buf The version of the main firmware, a JSON string.
 *                     Field      Type      Description
 *                     ret       Boolean   The operation result, true for success and false for failure.
 *                     firmName  String    The firmware name, which must be the same as the one specified in the production work order.
 *                     firmVer   String    The firmware version, which must be the same as the one specified in the production work order.
 *
 * @return 0 for success. Other values for failure.
 */
typedef int (*TYTEST_F_WR_HANDL)(char *buf);
typedef struct {
    TYTEST_F_WR_HANDL master_firm_frame_cb;
} TYTEST_FRAME_CBS_S;

Write authorization information

/**
 * @brief Write authorization information.
 *
 * @param[in] auzkey   The AUTHKEY.
 * @param[in] uuid     The UUID.
 * @param[in] pid      The product ID (PID).
 * @param[in] prodtest This parameter is deprecated.
 * @param[in] ap_ssid  The SSID of the wireless access point.
 * @param[in] ap_pwd   The password of the wireless access point.
 * @param[in] psk      The pre-shared key (PSK).
 *
 * @return 0 for success. Other values for failure.
 */
typedef int (*TYTEST_F_W_CFG_HANDL)(char *auzkey,
                                    char *uuid,
                                    char *pid,
                                    int prodtest,
                                    char *ap_ssid,
                                    char *ap_pwd,
                                    char *psk);
typedef struct {
    TYTEST_F_W_CFG_HANDL w_cfg_frame_cb;
} TYTEST_FRAME_CBS_S;

Read authorization information

/**
 * @brief Read authorization information.
 * @note To ensure the authorization information is written successfully, verification is required.
 *
 * @param[in] auzkey   The AUTHKEY.
 * @param[in] uuid     The UUID.
 * @param[in] pid      The product ID (PID).
 * @param[in] prodtest This parameter is deprecated.
 * @param[in] ap_ssid  The SSID of the wireless access point.
 * @param[in] ap_pwd   The password of the wireless access point.
 * @param[in] psk      The pre-shared key (PSK).
 *
 * @return 0 for success. Other values for failure.
 */
typedef int (*TYTEST_F_R_CFG_HANDL)(char *auzkey,
                                    char *uuid,
                                    char *pid,
                                    int *prodtest,
                                    char *ap_ssid,
                                    char *ap_pwd,
                                    char *psk);
typedef struct {
    TYTEST_F_R_CFG_HANDL r_cfg_frame_cb;
} TYTEST_FRAME_CBS_S;

Test Zigbee RF

/**
 * @brief Zigbee RF testing.
 * @note The Zigbee RF testing takes quite some time, so TuyaOS processes it asynchronously, with the `index` used to flag the asynchronous event.
 *       The value of `index` should be included for asynchronous data reporting.
 *
 * @param[in] index   The flag for asynchronous data reporting.
 * @param[in] channel  The channel to which the Zigbee module sends packets.
 * @param[in] num  The number of packets transmitted.
 *
 * @return 0 for success. Other values for failure.
 */
typedef int (*TYTEST_F_ZIGBEE_RF_HANDL)(int index, int channel, int num);
typedef struct {
    TYTEST_F_ZIGBEE_RF_HANDL zigbee_rf_frame_cb;
} TYTEST_FRAME_CBS_S;

Test Bluetooth RF

/**
 * @brief Bluetooth RF testing.
 *
 * @param[in] ssid   The name of the Bluetooth beacon.
 * @param[out] rssi  The RSSI value.
 */
typedef int (*TYTEST_F_WIFIBLE_RF_HANDL)(char *ssid, int *rssi);
typedef struct {
    TYTEST_F_WIFIBLE_RF_HANDL ble_rf_frame_cb;
} TYTEST_FRAME_CBS_S;

API description

Enable production test

/**
 * @brief Production testing initialization.
 *
 * @param[in] mode  Select the protocol. TCP and serial communication are supported.
 * @param[in] cbs   The callback interface. See TYTEST_FRAME_CBS_S.
 *
 * @return OPRT_OK for success. For other error codes, see tuya_error_code.h
 */
int tuya_testframe_handle_init(TUYA_PRODTEST_MODE mode, TYTEST_FRAME_CBS_S *cbs);

Set port number

/**
 * @brief Set the port number.
 *
 * @param[in] tcp_port The port number.
 *
 * @return OPRT_OK for success. For other error codes, see tuya_error_code.h
 */
void tuya_testframe_set_tcp_port(int tcp_port);

Exit production test mode

/**
 * @brief: production test frame handles deinit
 *
 * @return OPRT_OK for success. For other error codes, see tuya_error_code.h
 */
int tuya_testframe_handle_deinit(void);

Report RF test result

/**
 * @brief Report the result of Zigbee RF testing asynchronously.
 *
 * @param[in] index     The flag for asynchronous events.
 * @param[in] receive_num   The number of packets received.
 *
 * @return OPRT_OK for success. For other error codes, see tuya_error_code.h
 */
int tuya_testframe_rep_zigbeeRf_event(int index, unsigned int receive_num);