MCU SDK 移植

更新时间:2022-03-29 03:55:13下载pdf

MCU SDK 是根据涂鸦 IoT 平台定义的产品功能自动生成的 MCU 代码,能够协助您快速完成 MCU 程序的开发。本文为您介绍移植 MCU SDK 的流程以及注意事项。

SDK 概述

MCU SDK 是根据涂鸦开发平台定义的产品功能,自动生成的 MCU 代码。为了减少您使用涂鸦 Cat.1 IoT 通用串口协议的对接成本,MCU SDK 已搭建通讯及协议解析架构。将 MCU SDK 添加至工程并配置相关信息后,既可以快速的完成 MCU 程序开发。

资源要求

涂鸦 SDK 包对 MCU 的要求如下。资源不足的用户,可自行对接串口协议,SDK 包中的函数可以作为使用参考。

  • 内存:4 KB
  • RAM:与 DP 数据长度有关,约为 100B,如果开启 OTA 功能,则需大于 260B
  • 函数嵌套级数:9 级

文件结构

文件 说明
mcu_api.c 包含可供调用的函数。
mcu_api.h mcu_api.c中的函数声明。
protocol.c 包含协议数据体的内容处理函数。您可以根据项目需求,在相应函数内添加代码,获取 Cat.1 模组向 MCU 发送的数据。
protocol.h protocol.h 包含以下信息:MCU 要发送至 Cat.1 模组初始化所需的参数。SDK 裁剪所定义的宏。用户可根据需要的功能打开相应的宏定义。protocol.c中的函数声明。
system.c 串口通讯协议解析的具体实现。
system.h system.h 包含以下信息:协议命令字的定义。部分全局变量的定义。system.c中的函数声明。
cellular.h 包含 Cat.1相关宏定义。

移植流程

  1. 编写 MCU 基础程序,移植 SDK 文件。
  2. 确认 protocol.h 宏定义。
  3. 移植 protocol.c 文件及函数调用。
  4. 添加 DP 上报下发函数调用。
  5. 添加配网功能及指示灯函数。
  6. 添加产测功能。

编写程序和移植文件

  1. 在原项目工程中,完成 MCU 相关外设初始化,包括:串口、外部中断(按键)、定时器(指示灯闪烁)等。

  2. 将 MCU SDK 文件夹中的 .c.h 文件添加至相应头文件引用路径。

    MCU SDK 移植

确认 protocol.h 宏定义

确认产品信息

  1. 定义 PIDPRODUCT_KEY 为产品 PID 宏定义。PID 即产品 ID,为每个产品的唯一标识,可在涂鸦 IoT 平台的 产品管理页面 获取。

    如果 PRODUCT_KEY 和产品 PID 不一致,请在硬件开发>下载资料下载最新 SDK 开发包后重试。

    #define PRODUCT_KEY "ax23eawjo4np****"
    
  2. 定义版本号MCU_VER 为软件版本,默认为 1.0.0 。若 MCU 需要 OTA 功能,需要添加新的 MCU 版本号。

    #define MCU_VER "1.0.0"
    
  3. 定义功耗模式MODULE_POWER 为功耗定义,默认为 0。若 MCU 需要 Cat.1 模组进入低功耗模式,则定义为 1

  4. 定义模组类型CELLULAR_MODULE_TYPE 为模组类型定义,默认为 0,表示当前模组类型为LZ201,若Cat.1 模组选型为LZ211,且需要gnss功能时,则定义为1

设置 OTA 升级(可选)

  1. 开启 OTA 升级功能。如果需要支持 OTA 固件升级,请定义 SUPPORT_MCU_FIRM_UPDATE,默认关闭。

    //#define         SUPPORT_MCU_FIRM_UPDATE                 //开启MCU固件升级功能(默认关闭)
    
  2. 定义单次发送固件包的大小。

    #ifdef SUPPORT_MCU_FIRM_UPDATE
    #define PACKAGE_SIZE                   0        //包大小为256字节
    //#define PACKAGE_SIZE                   1        //包大小为512字节
    //#define PACKAGE_SIZE                   2        //包大小为1024字节
    #endif
    

    OTA 升级流程参见 OTA 升级说明

使用建议

  • OTA 通常要对 flash 进行读写操作。每次写入 flash 数据后,及时进行数据读取并和写入的数据进行校验,确保写入数据的正确性。
  • 添加 OTA 超时检测,防止 OTA 失败时 MCU 一致处于数据接收状态。
  • 每个 OTA 数据包都有包偏移的信息,利用包偏移检测 OTA 数据包是否存在重包或漏包

收发缓存(可选)

  • 串口接收缓存:大小受到串口数据处理被调用的频率影响。如果 MCU 对串口数据的处理较快,串口接收缓存大小可适当减小。

  • 串口发送缓存:大小要大于数据最长的 DP 数据长度。

  • 串口数据处理缓存:大小需要大于数据最长的 DP 数据长度,还要根据是否需要 OTA 功能和是否需要天气服务、天气服务类型数量和天数来调整大小,需要大于最大数据量的大小。

    /******************************************************************************
                            3:定义收发缓存:
                        如当前使用MCU的RAM不够,可修改为24
    ******************************************************************************/
    #ifndef SUPPORT_MCU_FIRM_UPDATE
    #define CELLULAR_UART_RECV_BUF_LMT          16              //串口数据接收缓存区大小,如MCU的RAM不够,可缩小
    #define CELLULAR_DATA_PROCESS_LMT           24              //串口数据处理缓存区大小,根据用户DP数据大小量定,必须大于24
    #ifdef SUPPORT_WIFI_LOCATION
    #define CELLULAR_DATA_PROCESS_LMT          700
    #endif
    #else
    #define CELLULAR_UART_RECV_BUF_LMT          128             //串口数据接收缓存区大小,如MCU的RAM不够,可缩小
    //请在此处选择合适的串口数据处理缓存大小(根据上面MCU固件升级包选择的大小和是否开启天气服务来选择开启多大的缓存)
    #define CELLULAR_DATA_PROCESS_LMT           300             //串口数据处理缓存大小,如需MCU固件升级,若单包大小选择256
                                                                //则缓存必须大于260,若开启天气服务,则需要更大
    //#define CELLULAR_DATA_PROCESS_LMT           600           //串口数据处理缓存大小,如需MCU固件升级,若单包大小选择512
                                                                //则缓存必须大于520,若开启天气服务,则需要更大
    //#define CELLULAR_DATA_PROCESS_LMT           1200          //串口数据处理缓存大小,如需MCU固件升级,若单包大小选择1024
                                                                //则缓存必须大于1030,若开启天气服务,则需要更大
    #endif
    
    #define CELLULAR_UART_SEND_BUF_LMT         48              //根据用户DP数据大小量定,必须大于48
    #ifdef SUPPORT_WIFI_LOCATION
    #define CELLULAR_UART_SEND_BUF_LMT         256
    #endif
    /******************************************************************************
    

定义模组工作方式(必选)

  • 如果重置按键和 LED 接在 MCU 端模组,即选择模组和 MCU 配合处理工作模式(常用),保持CELLULAR_CONTROL_SELF_MODE宏定义处于被注释状态。

    //#define         CELLULAR_CONTROL_SELF_MODE            //蜂窝自处理按键及LED指示灯;如为MCU外界按键/LED指示灯请关闭该宏
    
  • 如果状态指示灯和按键是接在 Cat.1模组上的,即选择模组自处理工作模式,开启 CELLULAR_CONTROL_SELF_MODE 宏定义,然后根据实际的硬件连接,将按键所连接的 GPIO 脚位填入CELLULAR_RESERT_KEY宏定义。

    模组自处理模式下,状态指示灯需要接到NET_MODE的PIN脚。

    #define     CELLULAR_STATE_KEY            0                    //蜂窝模组状态指示灯固定为NET_MODE灯,所以这个宏配置随意
    #define     CELLULAR_RESERT_KEY           21                   //蜂窝模组重置按键,请根据实际GPIO管脚设置
    

开启 Cat.1模组 产测功能(可选)

Cat.1产测功能默认开启。为保证最终量产效率及品质,建议开启该功能。

#define         CELLULAR_TEST_ENABLE                //开启 Cat.1 产测功能(检查SIM卡是否正常、是否经过授权,RF是否经过校准,及信号强度)

天气服务(可选)

模组成功连上路由之后,定义 WEATHER_ENABLE 即可开通天气服务功能。模组连接上云端后会立即下发天气数据,此后每隔 30 分钟下发 1 次。

  1. 开启天气服务功能。定义 WEATHER_ENABLE

    //#define         WEATHER_ENABLE                  //打开天气功能
    
  2. 选择支持的天气类型。您可以在 protocol.c 文件的 weather_choose 数组中,选择支持天气数据的参数。

    #ifdef WEATHER_ENABLE
    /**
    * @var    weather_choose
    * @brief  天气数据参数选择数组
    * @note   用户可以自定义需要的参数,注释或者取消注释即可,注意更改
    */
    const i8 *weather_choose[WEATHER_CHOOSE_CNT] = {
        "temp",
        "humidity",
        "condition",
        "pm25",
        /*"pressure",
        "realFeel",
        "uvi",
        "tips",
        "windDir",
        "windLevel",
        "windSpeed",
        "sunRise",
        "sunSet",
        "aqi",
        "so2 ",
        "rank",
        "pm10",
        "o3",
        "no2",
        "co",
        "conditionNum",*/
    };
    #endif
    
  3. 设置支持的天气的个数。将支持的参数个数在 WEATHER_CHOOSE_CNT 中定义。

    #define         WEATHER_CHOOSE_CNT              4   //选择的需要天气服务类型的数目
    
  4. 设置预报天数。新版固件的模组将支持最多7天的天气预报功能,预报的天数可以在 WEATHER_FORECAST_DAYS_NUM 宏定义中设置。

    • 1:表示只获取当天的数据。
    • 0 或大于 7 :模组将回复错误信息,天气服务打开失败
    #define         WEATHER_FORECAST_DAYS_NUM       1   //设置天气预报的天数
    

    模组发送的天气数据中带有天数的信息,此时 0 表示当天。

移植 protocol.c 文件及函数调用

  1. 将cellular.h 文件保存至存放 Wi-Fi 相关文件的文件夹中,例如 main.c文件夹。

  2. 在 MCU 串口及其他外设初始化后调用 mcu_api.c 文件中的 cellular_protocol_init() 函数。

  3. 将 MCU 串口单字节发送函数填入 protocol.c 文件中 uart_transmit_output 函数内,并删除 #error。示例如下:

    /**
    * @brief  串口发送数据
    * @param[in] {value} 串口要发送的1字节数据
    * @return Null
    */
    void uart_transmit_output(u8 value)
    {
        #error "请将MCU串口发送函数填入该函数,并删除该行"
    
    /*
        //Example:
        extern void Uart_PutChar(u8 value);
        Uart_PutChar(value);                                    //串口发送函数
    */
    }
    
  4. 在串口接收中断服务函数里面调用 mcu_api.c 文件内的 uart_receive_input 函数,并将接收到的字符作为参数传入。示例如下:

    void USART3_IRQHandler(void)
    {
        unsigned char Res=0;
    
        if((USART3->SR&UART_FLAG_RXNE) != 0)
        {
            Res=USART3->DR;
            uart_receive_input(Res);
        }
    }
    
  5. 单片机进入 while(1) 循环后调用 mcu_api.c 文件内的 cellular_uart_service() 函数。main.c 中示例代码结构如下:

    #include "celluluar.h"
    ...
    void main(void)
    {
        cellular_protocol_init();
        ...
        while(1)
        {
            cellular_uart_service();
            ...
        }
        ...
    }
    

    MCU 必须在 while(1) 中直接调用 mcu_api.c 内的 cellular_uart_service() 函数。程序正常初始化完成后,建议不进行关中断,如必须关中断,关中断时间必须短。关中断会引起串口数据包丢失,请勿在中断内调用上报函数。

调用 DP 数据上报和下发函数调用

详情请参考 Wi-Fi 通用对接中的MCU SDK移植

设备激活及指示灯函数

仅 MCU 与模组配合处理模式工作模式需要设置配网功能及指示灯函数。

移植协议成功后,如果需要设备激活,还需要添加配网指令以及指示灯功能。配合处理模式的 MCU、激活触发方式和指示方式,可以根据实际情况自行决定,通常为按键触发和 LED 快闪/慢闪指示。

激活指令

激活指令可以通过函数实现:mcu_reset_cellular()。通常在按键触发激活后,在按键处理函数中调用。

调用后复位 Cat.1 模组,复位后之前的激活信息全部清除,模组连上运营商网络后,会自动进入待激活状态。

配网指示

通常在 while(1) 调用 mcu_get_cellular_connect_status() 函数获取 Cat.1 模组联网状态。根据 Cat.1 状态,写入相应闪灯的模式。

设备联网状态 描述 状态值 LED 显示
状态 1 SIM卡未插入 0 常亮
状态 2 运营商网搜索中 1 闪烁间隔300ms
状态 3 运营商网注册成功 2 闪烁间隔1000ms
状态 4 设备获取到IP地址 3 闪烁间隔2000ms
状态 5 设备连接云端 4 闪烁间隔3000ms
状态 6 SIM卡拒绝注册 5 闪烁间隔100ms

调用函数 mcu_get_cellular_connect_status() 获取连接状态,函数架构如下:

void main(void)
{
	...
	while(1)
	{
	    ...
	    switch(mcu_get_cellular_connect_status())
	    {
	        case NO_SIM:
	            //设备未检测到SIM卡,即 LED常亮
	        break;
	        case SEARCH_NETWORK:
	            //设备查询运营商网络,即 LED 闪烁间隔300毫秒
	        break;
			case LOGINED_DISCONNECTED:
				//设备运营商注册刚成功,未连接网络 即LED闪烁间隔1秒
	        case CONNECTED_GET_IP:
	            //获取到IP地址,即 LED 闪烁间隔2秒
	        break;
	        case CONNECTED_CLOUD:
	            //云端连接成功,即 LED  闪烁间隔3秒
	        break;
	        default:break;
	    }
	    ...
	}
}

添加产测功能(可选)

产测支持4个测试项检测:

  • SIM卡检测:需要插入SIM卡。
  • RF射频校准:判断Cat.1模组是否经过射频校准。
  • 厂测授权:Cat.1模式是否完成产测授权,如果没有产测授权,无法连接涂鸦云。
  • 信号强度:范围0~31。测试时候需要接上4G天线。

开启产测支持。请定义 SET_FEATURE_TEST_ENABLE,默认关闭。

//#define         SET_FEATURE_TEST_ENABLE                 //开启模组自检功能

使用过程中,MCU 调用 mcu_api.cmcu_set_feature_test()函数,让 Cat.1 模组自检。

/**
 * @brief  开始蜂窝设备自检功能
 * @param  Null
 * @return Null
 * @note   MCU需要自行调用该功能
 */
void mcu_set_feature_test(void)
{
	cellular_uart_write_frame(GET_FEATURE_TEST_CMD, MCU_TX_VER, 0);
}

MCU 收到自检功能的应答后,需要根据收到应答增加处理功能。protocol.c 文件中有 get_feature_test_result() 的实现。

#ifdef SET_FEATURE_TEST_ENABLE
/**
 * @brief  获取模组的自检状态
 * @param[in] {sim_st} SIM卡状态.1:tree,0:fail
 * @param[in] {auth} 是否经过涂鸦授权产测.1:tree,0:fail
 * @param[in] {rf} RF射频是否经过校准. 1:校准完成,0:未校准
 * @param[in] {signal} 获取当前设备的信号强度 0~31
 * @return Null
 * @note   MCU needs to implement this function by itself
 */
void get_feature_test_result(u8 sim_st,u8 auth,u8 rf,u8 signal)
{
	#error "Complete the rssi fetch processing code yourself and delete the line"
}
#endif

MCU 与 Cat.1 模组数据交互

请在初始化完成后再进行数据交互,避免不可预测的问题。

帧格式

帧格式请参考 Cat.1 IoT 通用串口协议

初始化通信

在 MCU 和模组上电后,需要进行初始化配置。初始化通信包括但不限于以下内容:

  • 需要验证 MCU 与模组是否能正常工作
  • 验证通信连接是否正常
  • 获取模组激活所需要数据
  • 获取模组工作方式

心跳包

心跳包是 MCU 和模组之间定时通信的数据,可作为验证 MCU 或者模组是否正常工作的依据。建议将 MCU 和模组上电后的第一次通信的帧作为心跳包。只有在心跳包发送和回复都正常的情况下,才可以进行通信。

查询产品信息

心跳包正常交互后,模组需要查询 MCU 固件以下信息。

  • PID :产品 ID,用于产品激活。
  • 版本号:MCU 版本号,用于 OTA 升级完成后,验证是否升级成功。
  • 配网方式:模组的配网方式。

设定模组的工作方式

用来设置模组工作方式,选择 MCU 与模组配合处理方式或者模组自处理方式。可根据 Cat.1 网络状态指示灯和模组重置按键的硬件连接位置选择。

Cat.1 模组初始化数据交互流程如下图所示:

MCU SDK 移植

DP 上报和网络状态的关系

涂鸦 App 和设备之间能够实现 DP 下发和上报:

Cat.1 模组的网络状态为状态 4:设备连上路由和涂鸦 IoT。此时 DP 可以正常上报。

OTA或文件下载交互问题

MCU 与 Cat.1 模组在进行 OTA 数据交互时,数据包交互的数据量比较多,会出现一些异常情况。本章节介绍 Cat.1 模组的处理逻辑,您可以根据。

文件下载的逻辑和 OTA 实质上一样。可以将本章节中的 OTA 替换成文件下载,作为文件下载逻辑的介绍。

  • OTA 启动

    • 如果 5s 内没有收到 MCU 的回复,会进行重发。若重发 3 次之后 MCU 依旧没有回复,就认为 OTA 失败。
    • 如果固件包总字节数超出了 MCU 的处理范围,MCU 可以不做回复,让 Wi-Fi 模组自行退出 OTA。此时需检查在涂鸦 IoT 平台上传的文件是否正确。
  • OTA 数据传输

    Cat.1 模组在发送一包 OTA 数据之后,如果 5s 内没有收到 MCU 的回复,会进行重发。若重发 3 次之后 MCU 依旧没有回复,就认为 OTA 失败。

    • 如果 MCU 检测到 OTA 数据有误,可以不做回复,让 Cat.1 模组进行重发。此时需要注意包偏移是否正确,防止重发或漏发。
    • 如果 MCU 对 OTA 数据的处理速度太慢,会导致模组频繁重发数据,此时需要注意包偏移是否正确,防止重发或漏发。如果出现这种情况,建议调小固件包传输的大小。
  • OTA 传输完成
    支持以下两种方式判断 OTA 传输是否完成。

    • 帧长度为 0x0004,即 OTA 数据包长度为 0 。

    • 包偏移等于 Cat.1 模组发送升级启动帧时的固件包总长度。

      建议同时使用以上两种方式检测 OTA 传输情况。

蜂窝类特有设备交互

蜂窝类接口定义在protocol.c中的的宏定义CELLULAR_SERVICE_ENABLE

#define CELLULAR_SERVICE_ENABLE                //开启蜂窝服务

蜂窝工作模式

Cat.1模组有2种蜂窝工作模式。模组启动默认为全功能模式。

  • 全功能模式
  • 飞行模式

获取蜂窝工作模式

MCU调用mcu_api.c里的mecu_get_cellular_work_mode()向Cat.1模组发送获取当前蜂窝工作模式。

/**
 * @brief  获取CAT1的工作模式
 * @param  Null
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void mcu_get_cellular_work_mode(void)
{
	u16 length = 0;
	length = set_cellular_uart_byte(length, GET_CELLULAR_WORK_MODE);
	cellular_uart_write_frame(GET_CELLULAR_CMD, MCU_TX_VER, length);
}

MCU通过protocol.c里的get_cellular_work_mode_result()函数获取到蜂窝工作模式。该函数中有 #error,MCU需要去掉,另外需要根据自身需求实现具体功能。

/**
 * @brief  Get the cellular work mode
 * @param[in] {result} work mode
 * @return Null
 * @note   MCU needs to implement this function by itself
 */
void get_cellular_work_mode_result(u8 result)
{
	#error "Complete the work mode fetch processing code yourself and delete the line"

	switch(result) {
	    case 1:
	        //Full funtion mode
	    break;

	    case 4:
	        //Airplane  mode
	    break;

	    default:break;
	}
}

设置蜂窝工作模式

MCU调用mcu_api.c里的mcu_set_cellular_mode()向Cat.1模组发送获取当前蜂窝工作模式。

/**
 * @brief  MCU设置蜂窝通讯工作模式
 * @param[in] {mode} 进入的模式
 * @ref        1:全功能模式
 * @ref        4:飞行模式
 * @return Null
 * @note   1:MCU主动调用
 *         2:成功后,可判断set_cellularmode_flag是否为TRUE;TRUE表示为设置工作模式成功
 *         3:如果为模组自处理模式,MCU无须调用该函数
 */
void mcu_set_cellular_mode(u8 mode)
{
	u8 length = 0;

	set_cellularmode_flag = SET_CELLULARCONFIG_ERROR;

	length = set_cellular_uart_byte(length, mode);

	cellular_uart_write_frame(SET_CELLULAR_WORK_MODE, MCU_TX_VER, length);
}

MCU通过mcu_api.c里的mcu_get_cellular_mode_flag()函数获取到蜂窝工作模式是否成功。

定位功能(可选)

当前的定位功能有三种类型。

  • GNSS设备定位

    LZ201-CN模组需要外挂GNSS设备GUC300。GUC300必须连接到LZ201-CN的UART2上。LZ211-CN模组为内置GNSS设备。GNSS开启后,功耗会升高,平均电流增加30mA。

  • Wi-Fi定位

    Wi-Fi定位一般作为室内定位使用。

  • LBS定位

    LBS定位为基站定位。

如果需要支持定位功能,请定义 GNSS_SERIVCE_ENABLE,默认关闭。

//#define         GNSS_SERIVCE_ENABLE                 //开启地理定位服务(默认关闭)

GNSS定位功能

GNSS设备定位开关

GNSS定位默认为不开启,MCU调用mcu_api.c中的mcu_control_gnss()函数开启或者关闭。

当所选模组为LZ211时,需要注意由于LZ211模组内置gps,当使用gnss服务时,需要通过mcu_control_gnss_power接口给gps供电。在获取电源状态为加载固件完成时,再调用mcu_control_gnss()打开gps定位功能。

实现代码示例:

/**
 * @brief  控制GNSS服务
 * @param  [in] {enable} true:启动,false:关闭
 * @param  [in] {mode} GNSS定位跟踪类型
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void mcu_control_gnss(bool_t enable,GNSS_ATTACH_MODE_e mode)
{
	u16 length = 0;
	u8 cmd[3] = {0};
	cmd[0] = SET_CELLULAR_CTRL_GNSS;
	cmd[1] = enable;
	cmd[2] = mode;
	length = set_cellular_uart_buffer(length, cmd,sizeof(cmd));
	cellular_uart_write_frame(SET_CELLULAR_CMD, MCU_TX_VER, length);
}

在定位控制中,主要考虑enbale参数和mode参数。其中mode参数定义GNSS设备采用何种定位系统。

定位系统的定义在system.h中。

//GNSS的定位跟踪模式
typedef enum{
	GNSS_ATTACH_MODE_GPS_BD,         //GPS+BEIDOU定位模式
	GNSS_ATTACH_MODE_GPS_GL,         //GPS+GLONASS定位模式
	GNSS_ATTACH_MODE_GPS,            //GPS定位模式
	GNSS_ATTACH_MODE_BD,             //北斗定位模式
	GNSS_ATTACH_MODE_GL,             //GLONASS定位模式
	GNSS_ATTACH_MODE_GPS_GA,         //GPS+伽利略定位模式
}GNSS_ATTACH_MODE_e;

系统默认为GNSS_ATTACH_MODE_GPS_BD模式。当前GUC300/LZ211不支持GNSS_ATTACH_MODE_GL,GNSS_ATTACH_MODE_GPS_GA
控制的返回处理在protocl.cget_set_gnss_result()函数中。用户需要自行处理。

/**
 * @brief  获取设置GNSS开启或关闭的结果
 * @param[in] {gnss_status} 设置GNSS状态返回值
 * @param[in] {gnss_mode} GNSS定位模式状态返回
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_set_gnss_result(u8 gnss_status, u8 gnss_mode)
{
	#error "请自行实现设置GNSS定位功能处理代码,完成后请删除该行"
	if (!gnss_status) {
	    //设置失败
	}
       else {
             if (!gnss_mode) {
                 //设置失败
             }
            else {
                //设置成功
            }
        }
}
复位GNSS设备

MCU调用mcu_api.c里的mcu_reset_gnss()函数,发送复位命令给Cat.1模组,复位GNSS设备。

一般MCU开机或者复位,建议调用此命令,复位GNSS设备。该复位是GNSS硬件复位。另:复位功能仅适用于LZ201这种可以外挂GNSS的模组,LZ211不适用。

/**
 * @brief  复位GNSS设备
 * @param  [in] {pin} 蜂窝设备连接到GNSS设备RST的PIN脚
 * @return [in] {level} tree:高电平复位,false:低电平复位
 * @note   MCU需要自行实现该功能
 */
void mcu_reset_gnss(u8 pin,bool_t level)
{
	u16 length = 0;
	u8 cmd[3] = {0};
	cmd[0] = SET_CELLULAR_RESET_GNSS;
	cmd[1] = pin;
	cmd[2] = level;
	length = set_cellular_uart_buffer(length, cmd,sizeof(cmd));
	cellular_uart_write_frame(SET_CELLULAR_CMD, MCU_TX_VER, length);
}

复位结果获取查看protocl.c中的reset_gnss_result()函数,用户需要自行实现。

实现代码示例:

/**
 * @brief  复位GNSS设置
 * @param[in] {result} 设置状态返回值
 * @param[in] {data_len} 数据长度
 * @return Null
 * @note   MCU需要自行实现该功能
 */
static void reset_gnss_result(u8 result)
{
	#error "请自行实现设置蜂窝设备的定位功能处理代码,完成后请删除该行"
	if (!result) {
	    //设置失败
	}
	else {
	    //设置成功
	}
}
获取定位信息

MCU调用mcu_api.c里的mcu_get_gnss_location()函数,发送获取GNSS定位信息命令给Cat.1模组。

为确保能成功获取定位信息,建议在获取定位信息前,先获取一下GNSS设备信号强度。由于GNSS搜星需要一定的时间。冷启动关机时间超过2小时,搜星时间在2分钟左右。

在’protocol.c’中get_gnss_location_result()函数等待获取定位信息结果。

/**
 * @brief  获取设备GNSS定位信息
 * @param[in] {location} gnss定位信息,字符串类型:如“120.661,32.221”(经度、纬度)
 * @param[in] {data_len} 数据长度
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_gnss_location_result(u8 location[], u16 data_len)
{
	#error "请自行实现获取GNSS定位信息处理代码,完成后请删除该行"
	u8 ret = location[0];
	if (!ret) {
	    //获取失败
	}
	else {
	    //获取成功
	}
}

函数get_gnss_location_result()中,在获取成功中,返回的定位信息为字符串类型,内容为经纬度信息。MCU可以直接把字符串中的信息,通过DP上报。

获取GNSS设备信号强度

MCU自己调用mcu_api.c中的mcu_get_gnss_rssi()函数,发送获取信号强度命令。

获取信号强度的解析函数在’protocol.c’中的get_gnss_rssi_result()函数。

/**
 * @brief  获取设备GNSS当前信号强度
 * @param[in] {rssi} gnss设备的当前信号强度
 * @param[in] {data_len} 数据长度
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_gnss_rssi_result(u8 rssi[], u16 data_len)
{
	#error "请自行实现获取GNSS定位信息处理代码,完成后请删除该行"
	u8 ret = rssi[0];
	u8 rssi = rssi[1];
	if (!ret) {
	    //获取失败
	}
	else {
	    //获取成功
	}
}

信号强度范围0~100,一般只要信号超过30即可。GNSS设备3D定位没有成功情况下,返回失败。

获取设备速度

MCU自己调用mcu_api.c中的mcu_get_gnss_speed()函数,发送获取信号强度命令。

获取信号强度的解析函数在’protocol.c’中的get_gnss_rssi_result()函数。

/**
 * @brief  获取设备GNSS当前速度
 * @param[in] {speed} gnss设备的当前速度,单位100m/H
 * @param[in] {data_len} 数据长度
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_gnss_speed_result(u8 speed[], u16 data_len)
{
	#error "请自行实现获取GNSS定位信息处理代码,完成后请删除该行"
	u8 ret = speed[0];
	u16 u16speed = speed[1] << 8 | speed[2];
	if (!ret) {
	    //获取失败
	}
	else {
	    //获取成功
	}
}

获取到速度后,可以直接通过DP上报。

GNSS纬经度查询

MCU自己调用mcu_api.c中的mcu_set_gnss_lat_lg_location()函数,发送查询纬经度信息的命令。

获取纬经度信息的函数在’protocol.c’中的get_gnss_location_lat_lg_result()函数。

/**
 * @brief  获取设备GNSS纬经度定位信息
 * @param[in] {location} gnss定位信息,字符串类型:如“32.221,120.661”(纬度、经度)
 * @param[in] {data_len} 数据长度
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_gnss_location_lat_lg_result(u8 location[], u16 data_len)
{
    #error "请自行实现获取GNSS定位信息处理代码,完成后请删除该行"
    u8 ret = location[0];
    if (!ret) {
        //获取失败
    }
    else {
        //获取成功
    }
}
设置GNSS定位信息周期性上报

MCU自己调用mcu_api.c中的mcu_set_cellular_auto_rpt_gps(u16 period, u8 dpid)函数,设置GNSS定位信息上报的周期,周期参数的含义参看协议文档。

在’protocol.c’中的get_set_cellular_auto_rpt_gps_result()函数查看返回的结果。

/**
 * @brief  获取设置gps定位周期性上报的返回结果
 * @param[in] {result} 设置状态返回值
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_set_cellular_auto_rpt_gps_result(u8 result)
{
    #error "请自行实现获取设置gps定位周期性上报功能返回结果的处理代码,完成后请删除该行"
    if (!result) {
        //设置失败
    }
    else {
        //设置成功
    }
}
LZ211的GNSS设备主电源开关

如果需要支持该功能,请定义 CELLULAR_MODULE_TYPE1,默认为0

#define CELLULAR_MODULE_TYPE    0//蜂窝模组类型配置0:lz201,1:lz211

MCU自己调用mcu_api.c中的mcu_control_gnss_power()函数,控制gnss设备主电源开启和关闭。

设置gnss设备主电源开启或关闭的解析函数在’protocol.c’中的get_set_gnss_power_result()函数。

/**
 * @brief  设置gnss设备主电源开启或关闭
 * @param[in] {result} 设置主电源开启或关闭的返回值
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_set_gnss_power_result(u8 result)
{
	#error "请自行实现设置蜂窝设备的gnss主电源控制功能处理代码,完成后请删除该行"
	if (!result) {
	    //设置失败
	}
	else {
	    //设置成功
	}
}
LZ211的GNSS设备电源状态

如果需要支持该功能,请定义 CELLULAR_MODULE_TYPE1,默认为0

#define CELLULAR_MODULE_TYPE    0//蜂窝模组类型配置0:lz201,1:lz211

MCU自己调用mcu_api.c中的mcu_get_gnss_power_status()函数,获取gnss设备电源状态。

获取gnss设备主电源状态的解析函数在’protocol.c’中的get_gnss_power_status_result()函数。

/**
 * @brief  获取gnss设备主电源状态
 * @param[in] {result} 获取电源状态的结果
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_gnss_power_status_result(u8 result)
{
	#error "请自行实现获取蜂窝设备的主电源状态功能处理代码,完成后请删除该行"
	switch(result) {
	    case 0:
	        //电源关闭
	    break;

	    case 1:
	        //固件加载中
	    break;

	    case 2:
	        //电源开启,固件加载完成
	    break;

	    default:break;
	}
}

Wi-Fi定位

一般Wi-Fi定位功能在室内使用。

控制WiF-Fi定位功能

调用mcu_api.c中的mcu_control_wifi_location()函数,启动或者关闭Wi-Fi定位功能。

启动后,Cat.1模组会每间隔10秒扫描一次AP信息,扫描一次AP持续1秒。Wi-Fi定位启动后,蓝牙会被关闭。

获取执行结果的接口在protocol.c中。具体处理结果用户自行实现。

/**
 * @brief  打开或者关闭WIFI定位功能
 * @param[in] {result} 设置状态返回值
 * @param[in] {data_len} 数据长度
 * @return Null
 * @note   MCU需要自行实现该功能
 */
static void set_cellular_wifi_result(u8 result)
{
	#error "请自行实现设置蜂窝设备的WIFI定位功能处理代码,完成后请删除该行"
	if (!result) {
	    //设置失败
	}
	else {
	    //设置成功
	}
}
获取Wi-Fi定位信息

调用mcu_api.c中的mcu_get_wifi_location()函数,启动或者关闭Wi-Fi定位功能。

获取执行结果的接口在protocol.cget_cellular_wifi_location_result()。具体处理结果用户自行实现。

固件1.0.7版本中获取的定位信息格式为apn_num+"["1900cee08d77",-66],["3a00c0e08c77",-62]...",由于 DP 只支持 apn_num+"xxx,xx" 的格式,所以需要转换信息格式。


/**
 * @brief  获取设备蜂窝设备WIFI定位信息
 * @param[in] {location} gnss定位信息,字符串类型:如0x02["b27e525dc87d",-64],["957e5b5d087d",-64]
 * @param[in] {data_len} 数据长度
 * @return Null
 * @note   MCU需要自行实现该功能
 */
static void get_cellular_wifi_location_result(u8 ap_info[], u16 data_len)
{
   //#error "请自行实现获取蜂窝设备的WIFI定位信息处理代码,完成后请删除该行"
	/**/
   ...
	if (ap_count%MAX_AP_COUNT) {
	    loop_count ++;
	}
	if (data_len < 2 || data_len >= CELLULAR_DATA_PROCESS_LMT) {
	    return;
	}
	if (!ap_count) {
	    //获取失败
	}
	else {
	    //获取成功
	    if (strchr((char*)ap_info+1,'[')) {    //如果是1格式
	        remove_chacator(ap_info+1,wifi_info,'[','"',']');
	    }
	    else {  //格式:112233445566,-XX(-x)
	        memcpy(wifi_info,ap_info+1,data_len -1);
	    }
	    if (strlen(wifi_info) < 200) {
	        //mcu_dp_string_update 直接上传给涂鸦云。客户自行调用
	    }
	   else {
	       ptemp = (char*)wifi_info;
	        for (j = 0; j < loop_count; j ++) {
	            memset(ap_info,0,data_len);
	            psrc = ap_info;
	            if (j < loop_count-1) {
	                send_ap_count = MAX_AP_COUNT;
	            }
	            else {
	                send_ap_count = ap_count%MAX_AP_COUNT;
	            }
	            for ( i = 0; i < send_ap_count; i ++) {
	                sscanf(ptemp,"%[^,],%[^,]",mac,rssi);
	                if (strlen(rssi) && strlen(mac)) {

	                    sprintf(psrc+strlen(psrc),"%s,",mac);
	                    sprintf(psrc+strlen(psrc),"%s",rssi);
						ptemp += strlen(mac);
						ptemp += 1; //‘,’
						ptemp += strlen(rssi);
						if (strchr(ptemp,',')) {
							ptemp += 1;
						}
	                    if (i < send_ap_count -1) {
	                        sprintf(psrc+strlen(psrc),"%s",",");
	                    }
	                }
	                memset(mac,0,sizeof(mac));
	                memset(rssi,0,sizeof(rssi));
	            }
	            //mcu_dp_string_update(dip,psrc,strlen(psrc));
	        }
	    }
设置Wi-Fi定位信息周期性上报

调用mcu_api.c中的mcu_set_cellular_auto_rpt_wifi(u16 period, u8 dpid)函数,设置Wi-Fi定位信息上报的周期,周期参数含义参看协议文档。

获取执行结果的接口在protocol.c中。具体处理结果用户自行实现。

/**
 * @brief  获取设置Wi-Fi定位周期性上报的返回结果
 * @param[in] {result} 设置状态返回值
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_set_cellular_auto_rpt_wifi_result(u8 result)
{
    #error "请自行实现获取设置Wi-Fi定位周期性上报功能返回结果的处理代码,完成后请删除该行"
    if (!result) {
        //设置失败
    }
    else {
        //设置成功
    }
}

LBS定位功能

获取LBS定位信息

调用mcu_api.c中的mcu_get_lbs_location()函数,获取LBS定位信息。

获取执行结果的接口在protocol.cget_cellular_lbs_location_result()。具体处理结果用户自行实现。


/**
 * @brief  获取lbs定位信息
 * @param  [in] {location} {lbs_info} lbs定位信息,字符串类型:如"46011,e615,04bafc0a"(运营商编码+位置区域码码+基站编码)
 * @param  [in] {data_len} 数据长度
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_cellular_lbs_location_result(u8 ap_info[], u16 data_len)
{
	#error "请自行实现获取蜂窝设备的lbs定位功能处理代码,完成后请删除该行"
	u8 ret = lbs_info[0];
	if (!ret) {
	    //获取失败
	}
	else {
	    //获取成功
	}
}
设置LBS周期性上报

调用mcu_api.c中的mcu_set_cellular_auto_rpt_lbs(u16 period, u8 dpid)函数,设置LBS定位信息上报的周期。周期参数含义参看协议文档。

获取执行结果的接口在protocol.cget_set_cellular_auto_rpt_lbs_result(u8 result)。具体处理结果用户自行实现。

/**
 * @brief  获取设置lbs定位周期性上报的返回结果
 * @param[in] {result} 设置状态返回值
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_set_cellular_auto_rpt_lbs_result(u8 result)
{
    #error "请自行实现获取设置lbs定位周期性上报功能返回结果的处理代码,完成后请删除该行"
    if (!result) {
        //设置失败
    }
    else {
        //设置成功
    }
}后请删除该行"

}

电池功能(可选)

获取电池电量

调用mcu_api.c中的mcu_get_battery()函数,获取电池电量。

获取执行结果的接口在protocol.cget_cellular_vbat_vol_result()。具体处理结果用户自行实现。


/**
 * @brief  获取电池电量
 * @param  [in] {battery} 电池电量
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_cellular_vbat_vol_result(u8 battery)
{
	#error "请自行实现获取蜂窝设备的电池电量功能处理代码,完成后请删除该行"

}

充电状态查询

调用mcu_api.c中的mcu_get_charging_status()函数,获取蜂窝模组充电状态。

获取执行结果的接口在protocol.cget_vbat_charging_status_result()。具体处理结果用户自行实现。


/**
 * @brief  获取充电状态
 * @param  [in] {status} 充电状态
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_vbat_charging_status_result(u8 status)
{
	#error "请自行实现获取蜂窝设备的充电状态功能处理代码,完成后请删除该行"
	if (status == 1) {
	    //开始充电
	}
	else if (status == 2) {
	    //充电结束
	}
	else if (status == 3) {
	    //电量低
	}
	else if (status == 4) {
	    //电量超低
	}
	else if (status == 5) {
	    //电池拔出
	}
	else if (status == 6) {
	    //充电器故障
	}
	else if (status == 7) {
	    //充电故障
	}
	else {
	    return;
	}
}

音频功能(可选)

音量设置

调用mcu_api.c中的mcu_control_set_volume()函数,控制蜂窝模组音量设置。

获取执行结果的接口在protocol.cget_set_cellular_volume_result()。具体处理结果用户自行实现。


/**
 * @brief  获取音量设置结果
 * @param  [in] {cmd} 1:本地音量 2:通话音量
 * @param  [in] {result} 音量设置结果
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_set_cellular_volume_result(u8 cmd, u8 result)
{
	#error "请自行实现获取蜂窝设备的音量设置功能处理代码,完成后请删除该行"
	switch (cmd) {
	    case 1:{
	        if (!result) {
	            //获取成功
	        }
	        else {
	            //获取失败
	        }
	    }
	    break;

	    case 2:{
	        if (!result) {
	            //获取成功
	        }
	        else {
	            //获取失败
	        }
	    }
	    break

	    default:break;
	}
}

音频播放

调用mcu_api.c中的mcu_control_audio_play()函数,控制蜂窝模组sd卡中音频播放。

获取执行结果的接口在protocol.cget_contrl_cellulat_audio_play_result()。具体处理结果用户自行实现。


/**
 * @brief  获取音频播放结果
 * @param  [in] {play_info} 蜂窝模组返回的播放信息
 * @param  [in] {data_len} 数据长度
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_contrl_cellulat_audio_play_result(u8 play_info[], u16 data_len)
{
	#error "请自行实现获取蜂窝设备的音频播放功能处理代码,完成后请删除该行"
	if (data_len < 4) {
	    return;
	}
	u8 result = play_info[3];
	if (!result) {
	    //获取成功
	}
	else {
	    //获取失败
	}
}

播放状态查询

调用mcu_api.c中的mcu_get_audio_play_status()函数,获取本地音频播放状态。

获取执行结果的接口在protocol.cget_voice_play_status_result()。具体处理结果用户自行实现。


/**
 * @brief  获取音频播放状态
 * @param  [in] {cmd} 0:空闲 1:播放中 2:播放中止 3:播放完成
 * @param  [in] {result} 播放设置结果
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_voice_play_status_result(u8 cmd, u8 result)
{
	#error "请自行实现获取蜂窝设备的音频播放状态功能处理代码,完成后请删除该行"
	switch (cmd) {
	    case 0:{
	        if (!result) {
	            //获取成功
	        }
	        else {
	            //获取失败
	        }
	    }
	    break;

	    case 1:{
	        if (!result) {
	            //获取成功
	        }
	        else {
	            //获取失败
	        }
	    }
	    break;

	    case 2:{
	        if (!result) {
	            //获取成功
	        }
	        else {
	            //获取失败
	        }
	    }
	    break

	    case 3:{
	        if (!result) {
	            //获取成功
	        }
	        else {
	            //获取失败
	        }
	    }
	    break

	    default:break;
	}
}

短信功能(可选)

控制接收短信是否成功

当MCU收到模组接收到的短信后,需要调用mcu_api.c中的mcu_control_recv_sms_rsp()函数,控制接收短信是否成功。

调用的接口在protocol.cget_contrl_sms_result()。具体处理结果用户自行实现。


/**
 * @brief  获取短信业务返回结果
 * @param  [in] {sms_info} 短信业务返回信息
 * @param  [in] {data_len} 数据长度
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_contrl_sms_result(u8 sms_info[], u16 data_len)
{
	#error "请自行实现设置蜂窝设备的短信功能处理代码,完成后请删除该行"
	if (data_len < 2) {
	    return;
	}
	u8 result = 0;
	u8 cmd = sms_info[0];
	switch (cmd) {
	    case 0:
	        //接收到短信
	    break;

	    case 1:{
	        //发送短信
	        result = sms_info[1];
	        if (!result) {
	            //发送失败
	        }
	        else {
	            //发送成功
	        }
	    }
	    break;

	    default:break;
	}
}

发送短信

调用mcu_api.c中的mcu_control_send_sms()函数,控制蜂窝模组发送短信。

获取执行结果的接口在protocol.cget_contrl_sms_result()。具体处理结果用户自行实现。

具体代码框架,请参考 控制接收短信是否成功

电话功能(可选)

  • 电话呼入

    当MCU收到模组接收到的电话提醒后,需要调用mcu_api.c中的
    mcu_control_phone_callin_rsp()函数,通知蜂窝模组,收到来电。

    调用的接口在protocol.cget_contrl_phone_result()。具体处理结果用户自行实现。

    /**
    * @brief  获取电话业务返回结果
    * @param  [in] {phone_info} 电话业务返回信息
    * @param  [in] {data_len} 数据长度
    * @return Null
    * @note   MCU需要自行实现该功能
    */
    void get_contrl_phone_result(u8 phone_info[], u16 data_len)
    {
    	#error "请自行实现设置蜂窝设备的电话业务功能处理代码,完成后请删除该行"
    	if (data_len < 2) {
    		return;
    	}
    	u8 result = 0;
    	u8 cmd = phone_info[0];
    	switch (cmd) {
    		case 0:
    			//电话呼入提醒
    			mcu_control_phone_callin_rsp();
    		break;
    
    		case 1:{
    			//电话呼出结果
    			result = phone_info[1];
    			if (!result) {
    				//呼出失败
    			}
    			else {
    				//呼出成功
    			}
    		}
    		break;
    
    		case 2:{
    			//电话接听结果
    			result = phone_info[1];
    			if (!result) {
    				//接听成功
    			}
    			else {
    				//接听失败
    			}
    		}
    		break;
    
    		case 3:{
    			//电话挂断结果
    			result = phone_info[1];
    			if (!result) {
    				//挂断成功
    			}
    			else {
    				//挂断失败
    			}
    		}
    		break;
    
    		case 4:{
    			//电话状态查询结果
    			result = phone_info[1];
    			if (result == 0) {
    				//拨号中
    			}
    			else if(result == 1) {
    				//空闲
    			}
    			else if(result == 2) {
    				//通话失败
    			}
    			else if(result == 3) {
    				//通话中
    			}
    			else {
    				break;
    			}
    		}
    		break;
    
    		default:break;
    	}
    }
    
  • 电话呼出

    调用mcu_api.c中的mcu_control_phone_callout()函数,控制蜂窝模组电话呼出。

    获取执行结果的接口在protocol.cget_contrl_phone_result()。具体处理结果用户自行实现。

    具体代码框架,请参考 电话呼入

  • 电话接听

    调用mcu_api.c中的mcu_control_phone_anwser()函数,控制蜂窝模组电话接听。

    获取执行结果的接口在protocol.cget_contrl_phone_result()。具体处理结果用户自行实现。

    具体代码框架,请参考 电话呼入

  • 电话挂断

    调用mcu_api.c中的mcu_control_phone_hungup()函数,控制蜂窝模组电话挂断。

    获取执行结果的接口在protocol.cget_contrl_phone_result()。具体处理结果用户自行实现。

    具体代码框架,请参考 电话呼入

  • 电话状态查询

    调用mcu_api.c中的mcu_get_phone_status()函数,获取蜂窝模组电话状态。

    获取执行结果的接口在protocol.cget_contrl_phone_result()。具体处理结果用户自行实现。

    具体代码框架,请参考 电话呼入

门锁服务(可选)

如果需要支持门锁功能,请定义 LOCK_SERIVCE_ENABLE,默认关闭。

获取UNIX时区信息

调用mcu_api.c中的mcu_get_unix_time_zone()函数,获取当前UNIX时区信息。

执行结果可以在get_unix_time_zone(u8 time[])函数中获取, 具体处理结果用户自行实现。

/**
 * @brief  获取到的Unix时间
 * @param[in] {time} 获取到的Unix时间数据
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_unix_time_zone(u8 time[])
{
    #error "请自行完成相关代码,并删除该行"
    /*
    time[0] 为是否获取时间成功标志,为 0 表示失败,为 1表示成功
    time[1]-time[4] 为Unix时间戳
    time[5] 为是否获取时区成功标志,为 0 表示失败,为 1表示成功
    time[6] 0:表示东区,1:表示西区
    time[7] 为时区
    time[8] 是否有夏令时 1:表示有夏令时 0:表示没有夏令时
    time[9]-time[12] 进入夏令时时间戳
    time[13]-time[16] 退出夏令时时间戳
    */
    if(time[0] == 1) {
        //正确接收到蜂窝模块返回的unix时区数据

    }else {
        //获取unix时间出错
    }
}

设置密码进制服务

调用mcu_api.c中的mcu_set_pswd_base(u8 pswd_num,u8 start)函数,设置密码进制,具体详情可以参看协议文档。

执行结果可以在get_set_psw_base_result(u8 result)函数中获取, 具体处理结果用户自行实现。

/**
 * @brief  获取密码进制服务设置结果
 * @param[in] {result} 获取到的设置密码进制服务返回的状态
 * @return Null
 * @note   MCU需要自行实现该功能
 */
void get_set_psw_base_result(u8 result)
{
    #error "请自行完成相关代码,并删除该行"
    if(result == 0) {
        //设置成功
        is_setpswd_base = TRUE;
    }else {
        //设置失败
        is_setpswd_base = FALSE;
    }
}

获取云端临时密码(带schedule表)

调用mcu_api.c中的mcu_get_schedule_temp_pass()函数,获取云端临时密码,具体详情可以参看协议文档。
执行结果可以在get_schedule_temp_pass_handle(const u8 data[])函数中获取, 具体处理结果用户自行实现。

/**
 * @brief  MCU请求临时密码(带schedule列表)返回
 * @param[in] {data} 返回数据
 * @return Null
 * @note   Null
 */
void get_schedule_temp_pass_handle(const u8 data[])
{
    u8 i = 0;
    u8 pass_len = 0;
    u8 result = data[0];
    u8 pass_num = data[1];
    if(get_setpassword_base_flag()){
        pass_len = data[3];
    }else{
        pass_len = data[2];
    }

    u8 offset = 4;

    if (result == 1) {
        for (i=0;i<pass_num;i++) {
            schedule_temp_pass_data(result, data[offset], data[offset+1], data[offset+2], data+offset+3,
                               data+offset+9, data+offset+15, pass_len, data[offset+15+pass_len],data+offset+15+pass_len+1);
            offset += 15 + pass_len + 1 + 6*data[offset+15+pass_len];
        }
    }else {
        schedule_temp_pass_data(result, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    }
}

获取离线动态密码

如果需要支持获取离线动态密码功能,请定义 OFFLINE_DYN_PW_ENABLE,默认关闭。

调用mcu_api.c中的mcu_set_offline_dynamic_pswd(u8 green_time[],u8 pw[],u8 pw_len)函数,获取动态离线密码,具体详情可以参看协议文档。

执行结果可以在get_offline_dynamic_pswd_result(u8 result_data[])函数中获取, 具体处理结果用户自行实现。

/**
 * @brief  离线动态密码结果
 * @param[in] {result_data} 结果数据
 * @return Null
 * @note   MCU需要先自行调用mcu_set_offline_dynamic_pswd函数后,在此函数对接收的结果进行处理
 */
void get_offline_dynamic_pswd_result(u8 result_data[])
{
    #error "请自行完成离线动态密码结果处理代码,并删除该行"
    u8 result; //密码正确性
    u8 type; //密码类型
    u8 decode_len; //解密后数据长度
    u8 decode[DECODE_MAX_LEN]; //解密数据

    result = result_data[0];
    if(0 == result) {
        //正确
    }else {
        //错误
        return; //错误时,无后续数据
    }

    type = result_data[1];
    switch(type) {
        case 0:
            //限时开门密码
        break;

        case 1:
            //单次开门密码
        break;

        case 2:
            //清除密码
        break;

        default:break;
    }

    decode_len = result_data[2];
    my_memcpy(decode,&result_data[3],decode_len);

    //可添加解密数据处理
}