Page 1 of 1

【技术干货】TuyaOS(NB-IoT)新平台移植指导:适配tkl_nbiot_misc.c

Posted: 2023年 Sep 21日 14:47
by liujt@tuya.com

本章介绍对tkl_nbiot_misc.c的接口相关适配

  • 芯片信息相关

    • Code: Select all

      /**
       * @brief get the chip type
       * 
       * @param[inout] out_type :output the chip type
       *
       * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
       */
      OPERATE_RET tkl_nbiot_chip_type(TKL_MISC_CHIP_TYPE_E *out_type)
      {
          *out_type = TKL_CHIP_MAX;
          return OPRT_OK;
      }
      

      该接口返回芯片类型:
      typedef enum {
      TKL_CHIP_MTK2625 = 0, //适配涂鸦标准的差分升级流程!!!
      TKL_CHIP_EC616 = 1,
      TKL_CHIP_XY1100 = 2,
      TKL_CHIP_MAX = 3, //支持通用三方芯片FOTA升级流程
      } TKL_MISC_CHIP_TYPE_E;
      默认输出为:TKL_CHIP_MAX,SDK只负责下载固件及获取升级结果

  • AT口操作相关:

    • Code: Select all

      /**
       * @brief if AT serial port is on or off
       * 
       * @param[in] null
       *
       * @return  true: on  Other: off
       */
      BOOL_T tkl_nbiot_is_atcmd_serial_port_on(void)
      {
          // --- BEGIN: user implements ---
          return true;
          // --- END: user implements ---
      }
      

      判断AT口是否打开,已打开状态返回true,否则返回false.

    • Code: Select all

      /**
       * @brief set AT serial port off
       * 
       * @param[in] null
       *
       * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
       */
      OPERATE_RET tkl_nbiot_atcmd_serial_port_off(VOID)
      {
          // --- BEGIN: user implements ---
          return OPRT_NOT_SUPPORTED;
          // --- END: user implements ---
      }
      

      关闭AT口操作,成功关闭返回OPRT_OK,否则返回OPRT_COM_ERROR.

    • Code: Select all

      /**
       * @brief set AT serial port on
       * 
       * @param[in] null
       *
       * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
       */
      OPERATE_RET tkl_nbiot_atcmd_serial_port_on(VOID)
      {
          // --- BEGIN: user implements ---
          return OPRT_NOT_SUPPORTED;
          // --- END: user implements ---
      }
      

      打开AT口操作,成功打开返回OPRT_OK,否则返回OPRT_COM_ERROR.

    • Code: Select all

      typedef void (*serial_port_uart_virtaul_at_cb_t)(char *resp_str, unsigned int str_len);
      /**
       * @brief execute AT common command
       * 
       * @param[in] pbuf: at command string
       * @param[in] len:  at command string length
       * @param[in] cb:   at command executed callback func
       *
       * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
       */
      OPERATE_RET tkl_nbiot_atcmd_common(PCHAR_T pbuf,  UCHAR_T len, serial_port_uart_virtaul_at_cb_t cb)
      {
          // --- BEGIN: user implements ---
          return OPRT_NOT_SUPPORTED;
          // --- END: user implements ---
      }
      

      通用AT指令执行操作,执行成功返回OPRT_OK,否则返回OPRT_COM_ERROR
      (如果硬件平台不支持通用AT指令操作,返回 OPRT_NOT_SUPPORTED)

      • 输入:
        pbuf:标准AT指令字符串内存指针,如"AT+CSQ\r\n",
        len:pbuf字符串的长度,
        输出回调函数定义:
        typedef void (*serial_port_uart_virtaul_at_cb_t)(char *resp_str, unsigned int str_len)
        resp_str:AT执行后输出回显字符串内存指针,
        str_len:resp_str回显字符串长度

  • OTA升级相关

    • Code: Select all

      /**
      * @brief get the offset address of app firmware
      * 
      * @param[inout] out_addr :output the offset address
      *
      * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
      */
      OPERATE_RET tkl_nbiot_get_app_offset(UINT_T *out_addr)
      {
          *out_addr = TUYA_APP_ADDR;
          return OPRT_OK;
      }
      

      返回当前应用固件保存在flash中的起始空间相对地址,如TUYA_APP_ADDR(用户根据平台定义)

    • Code: Select all

      /**
      * @brief get the app firmware space length
      * 
      * @param[inout] out_addr :output the offset address
      *
      * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
      */
      OPERATE_RET tkl_nbiot_get_app_len(UINT_T *out_len)
      {
          *out_len = TUYA_APP_LENGTH;
          return OPRT_OK;
      }
      

      返回当前应用固件所占用的最大flash空间长度TUYA_APP_LENGTH(用户根据平台定义)

    • Code: Select all

      /**
      * @brief notify fota update start, some platform need acquire this info then restart system,such as NX1, others return directly
      * 
      * @param[in] null
      *
      * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
      */
      OPERATE_RET tkl_nbiot_fota_update_start(void)
      {
          return OPRT_OK;
      }
      

      直接返回OPRT_OK,不用做处理。

    • Code: Select all

      /**
      * @brief notify fota update end, some platform need acquire this info to clear update status,such as NX1, others return directly
      * 
      * @param[in] null
      *
      * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
      */
      OPERATE_RET tkl_nbiot_fota_update_end(void)
      {
          return OPRT_OK;
      }
      

      SDK升级完成并已经将升级状态同步到云平台,硬件平台侧此时可以在该功能中清除相关的升级状态(如在ota_get_update_result()中保存的升级状态)信息后,直接返回OPRT_OK。

    • Code: Select all

      /**
      * @brief some upgrade status needs to be obtained from the platform,such as NX1, others return directly
      * 
      * @param[in] null
      *
      * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
      */
      OPERATE_RET tkl_nbiot_fota_status_acquire(void)
      {
          // 获取升级结果,并构造升级信息
          fota_update_info_t up_info = {0};
          UINT_T trigger_addr = 0, upinfo_addr = 0;
          OPERATE_RET ret = OPRT_OK;
          tkl_nbiot_get_fota_update_info_offset(&upinfo_addr);
          tkl_nbiot_get_fota_trigger_flag_offset(&trigger_addr);
      
          ret = tkl_flash_read(trigger_addr, (UCHAR_T *)&up_info, sizeof(fota_update_info_t));
          if ((ret == OPRT_OK) && ((up_info.m_ver & 0x00FFFFFF) == 0x004D4D4D)) {	//已标识升级开始状态!
              ret = ota_get_update_result();		//硬件平台侧实现:获取当前的升级状态
              if (ret == OK) {
                  TAL_PR_DEBUG("fota success");
                  up_info.m_error_code = 0;
              } else {
                 TAL_PR_DEBUG("fota fail");
                  up_info.m_error_code = 1;
              }
              tkl_flash_erase(upinfo_addr, (1 << 12));
              tkl_flash_write(trigger_addr, (const UCHAR_T *)&up_info, sizeof(fota_update_info_t));//将升级信息写入指定flash地址
              return OPRT_OK;
          }
          return OPRT_COM_ERROR;
      }
      

      以下为FOTA升级过程:

      • SDK下载完成FOTA固件包,会将标识0x004D4D4D记录在结构体fota_update_info_t的成员m_ver中,并写入tkl_nbiot_get_fota_trigger_flag_offset指定的地址,同时通过应用层的注册tuya_user_api_fota_notify_register回调event_notify,将事件OTA_EVENT_DOWNLOAD_COMPLETE发送给应用层;

      • 系统重启(SDK会执行系统重启操作,硬件平台侧不要主动重启!!!)

      • 进入bootloader,硬件平台侧可以通过判断tkl_nbiot_get_fota_trigger_flag_offset地址中fota_update_info_t的成员m_ver是否为0x004D4D4D时,决定是否接管固件升级(注意,升级全程不要擦除标识0x004D4D4D)

      • bootloader升级执行结束后,将升级结果保存(以便进入系统后 ota_get_update_result()能够获取),接着跳转到应用程序固件起始地址

      • 初始化期间SDK会调用tkl_nbiot_fota_status_acquire,获取当前升级状态信息(硬件平台侧需要构建在tuya_fota_downloader.h中定义的结构体fota_update_info_t,并写入以下函数tkl_nbiot_get_fota_trigger_flag_offset所指的起始空间),成功返回OPRT_OK,否则返回错误。

      (以上是一个实现例程)SDK中主要通过该接口将升级结果返回给APP,以便同步当前的升级信息。

    • Code: Select all

      /**
      * @brief get the offset address to save firmware
      * 
      * @param[inout] out_addr :output the offset address
      * @param[inout] _1st_data :the first fota data pointer
      * @param[inout] _1st_data_size :the first fota data length
      * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
      */
      OPERATE_RET tkl_nbiot_get_fota_offset(UINT_T *out_addr, UCHAR_T *_1st_data, UINT32_T _1st_data_size)
      {
          *out_addr = TUYA_FOTA_ADDR;
          return OPRT_OK;
      }
      

      (输入形参out_addr,_1st_data, _1st_data_size除芯翼平台外,可以不用处理)
      返回FOTA固件下载后保存在flash中的起始相对地址TUYA_FOTA_ADDR(用户根据平台定义)

    • Code: Select all

      /**
      * @brief get the space legth to save firmware
      * 
      * @param[inout] out_addr :output the offset address
      *
      * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
      */
      OPERATE_RET tkl_nbiot_get_fota_len(UINT_T *out_len)
      {
          *out_len = TUYA_FOTA_LENGTH;
          return OPRT_OK;
      }
      

      返回FOTA固件保存在flash中所占用的最大空间长度

    • Code: Select all

      /**
      * @brief get the offset address to save update info
      * 
      * @param[inout] out_addr :output the offset address
      *
      * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
      */
      OPERATE_RET tkl_nbiot_get_fota_update_info_offset(UINT_T *out_addr)
      {
          *out_addr = TUYA_FOTA_UPDATE_INFO_ADDR;
          return OPRT_OK;
      }
      

      该函数功能返回升级标识相关及升级结果信息在flash中保存扇区的相对起始地址 TUYA_FOTA_UPDATE_INFO_ADDR,长度预留一个扇区大小即1024*4(4KB)

    • Code: Select all

      /**
      * @brief get the offset address to save trigger fota indicator
      * 
      * @param[inout] out_addr :output the offset address
      *
      * @return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
      */
      OPERATE_RET tkl_nbiot_get_fota_trigger_flag_offset(UINT_T *out_addr)
      {
          *out_addr = TUYA_FOTA_TRIGGER_FLAG_ADDR;
          return OPRT_OK;
      }
      

      该函数功能返回升级标识相关及升级结果信息(为fota_update_info_t数据结构)在flash中保存扇区的实际相对起始地址TUYA_FOTA_TRIGGER_FLAG_ADDR

    • 函数tkl_nbiot_get_fota_update_info_offset及tkl_nbiot_get_fota_trigger_flag_offset所返回在flash中所指定的地址建议如下:

      trigger_map.png
  • 硬件周边配置信息

    • Code: Select all

      /**
      * @brief get the AT uart number
      * 
      * @param[] null
      *
      * @return the AT uart number
      */
      UINT_T tkl_nbiot_get_uart_at_number(VOID)
      {
          return 0;               // AT 串口
      }
      

      返回硬件平台侧AT串口号

    • Code: Select all

      /**
      * @brief get the user uart number of communication
      * 
      * @param[] null
      *
      * @return the user uart number
      */
      UINT_T tkl_nbiot_get_uart_user_number(VOID)
      {
          return 1;               // 用户通讯及产测串口
      }
      

      返回硬件平台侧用户通讯及产测串口号

    • Code: Select all

      /**
      * @brief get the log uart number of communication
      * 
      * @param[] null
      *
      * @return the log uart number
      */
      UINT_T tkl_nbiot_get_uart_log_number(VOID)
      {
          return 2;               // 日志串口
      }
      

      返回硬件平台侧日志输出串口

    • Code: Select all

      /**
      * @brief get the net led gpio number
      * 
      * @param[] null
      *
      * @return the number
      */
      UINT_T tkl_nbiot_get_net_led_gpio_number(VOID)
      {
          return 20;               // NET_LED_GPIO
      }
      

      返回硬件平台侧驱动LED对应的GPIO号

    • Code: Select all

      /**
      * @brief get the psm wake up gpio number
      * 
      * @param[] null
      *
      * @return the number
      */
      UINT_T tkl_nbiot_get_psm_wake_up_gpio_number(VOID)
      {
          return 0;               // PSM_WAKE_UP_GPIO
      }
      

      返回硬件平台侧PSM外部唤醒脚对应的GPIO号

    • Code: Select all

      /**
      * @brief get the adc channel number
      * 
      * @param[] null
      *
      * @return the number
      */
      UINT_T tkl_nbiot_get_adc_channel_number(VOID)
      {
          return HAL_ADC_CHANNEL_0;               // TUYA_NB_ADC_CHANNEL
      }
      

      返回硬件平台侧ADC对应的通道号

    • Code: Select all

      /**
      * @brief get the adc channel sample deviation value: mv(单位)
      * 
      * @param[] null
      *
      * @return the val :mv(单位)
      */
      UINT_T tkl_nbiot_get_adc_sample_deviation_val(VOID)
      {
          ////采样容许偏差范围单位:mv
          return 50;               // TUYA_NB_ADC_SAMPLE_DEVIATION
      }
      

      返回ADC采样容许偏差范围

    • Code: Select all

      /**
      * @brief get message ring gpio number
      * 
      * @param[] null
      *
      * @return the number
      */
      UINT_T tkl_nbiot_get_message_ri_gpio_number(VOID)
      {
          // MESSAGE_RI_GPIO
          return 0xff;    //NM1:unsupport!
      }
      

      返回ring对应的GPIO口.(当云端有数据下发时,通过该GPIO口触发200ms的低电平脉冲)不支持则返回0xff.