【LTE CAT1】ML302 OpenCPU | 应用开发入门

一、新增源文件

1. 增加源文件

  1. sdk_root/src目录下新建文件夹user,并新建源文件user_app.c
/*********************************************************
*  @file    user_app.c
*  @brief   User application Entry File
*  Copyright (c) 2021 羽墨志.
*  All rights reserved.
*  created by 羽墨志 2021/04/02
********************************************************/
#include "user_app.h"

int user_app_main(void)
{
    cm_printf("hello world from [%s]\r\n", __func__);

    return 0;
}

【注】[sdk_root]为SDK的根目录位置。
2. 在Makefile文件中将新增的源文件目录添加到SRC_DIRS变量中,以空格与其他源文件目录分开;

SRC_DIRS := src src\demo\ssl src\user

2. 增加头文件

  1. sdk_root/inc目录下新建文件夹user,并新建头文件文件user_app.h
/*********************************************************
*  @file    user_app.h
*  @brief   User application header file
*  Copyright (c) 2021 羽墨志 Ltd.
*  All rights reserved.
*  created by 羽墨志 2021/04/02
********************************************************/

#ifndef __USER_APP_H__
#define __USER_APP_H__

#include "cm_main.h"

int user_app_main(void);

#endif
  1. 在Makefile文件中将新增的头文件目录添加到INC变量中,以空格与其他头文件目录分开;
INC :=  -I'inc\os' -I'inc\apb' -I'inc\lwip' -Isrc -I. -Iinc  -I'inc\cm'  -Iinc\mbedtls -Iinc\os\include -Iinc\cJSON -Iinc\os\include\sys -Iinc\user

3. 增加宏定义

为了保证新增的代码不影响原有SDK的结构,在Makefile文件中新增一个宏定义USER_APP_SUPPORT

  1. [src_root]目录下的cm_feature.mk的文件中添加一行定义,用于控制是否新增宏定义:
#配置用户自定功能,Add by GuoHua
cm_user_app_on = y
  1. [src_root]目录下的Makefile文件中根据变量的赋值情况决定是否添加宏定义:
ifeq ($(cm_user_app_on),y)
CFLAGS += -DUSER_APP_SUPPORT
endif

当变量cm_user_app_on赋值为y时,则添加宏定义USER_APP_SUPPORT,这样就可以直接在应用程序中使用该宏定义了。
注意在Makefile中添加宏定义时不要忘记了前面的参数-D
最后整理一下,将添加的源文件以及头文件目录的定义包含到这个判断中来:

ifeq ($(cm_user_app_on),y)
CFLAGS += -DUSER_APP_SUPPORT
INC += -Iinc/user
SRC_DIRS += src/user
endif

这样就可以在配合宏定义GH_USER_APP_SUPPORT在应用程序中的使用,并通过变量cm_user_app_on的赋值来决定是否在SDK中添加用户自定义的应用程序了。

二、应用程序的调用

1. 入口函数

ML302 OpenCPU的入口函数是void ML302_OpenCPU_Entry(),位于文件[sdk_root]/src/cm_main.c中。该函数在模组主程序main函数中被调用,用于用户应用线程的建立,因此不能阻塞该函数。

void ML302_OpenCPU_Entry()
{
#ifdef CM_DEMO_SUPPORT
    cm_test_alarm_init();
    cm_test_keypad_init();
    // 定义主线程
    osThreadDef(OC_Main_Task, cm_main_task, osPriorityNormal, 0, 8192);
    // 创建主线程
    OC_Main_TaskHandle = osThreadCreate(osThread(OC_Main_Task), 0);  

#ifdef CM_FOTA_SUPPORT   //启用OneNet FOTA不可删除
    cm_onenet_fota_regcbex();
#endif
#endif
}

函数void ML302_OpenCPU_Entry()的工作是进行基本的初始化,定义并创建用户APP主线程,cm_main_task为APP线程的回调函数,在该回调函数中完成应用程序的开发。

2. 程序调用

在文件[sdk_root]/src/cm_main.c的适当位置添加如下代码以便将用户自定义的头文件包含进来:

#ifdef USER_APP_SUPPORT
#include "user_app.h"
#endif

在APP线程的回调函数void cm_main_task(void *p)中添加用户自定义应用程序的主函数:

#ifdef USER_APP_SUPPORT
    user_app_main();
#endif

宏定义USER_APP_SUPPORT的开关由[sdk_root/cm_feature.mk]文件中的控制变量cm_user_app_on来决定,这样就可以通过cm_user_app_on来控制是否添加用户自定义的应用程序了。修改后的APP线程的回调函数void cm_main_task(void *p)如下所示,主要是添加了user_app_main();函数和部分注释:

void cm_main_task(void *p)
{  
   unsigned char buf[50] = {0};
   int i;
   struct l_tm t;
   cm_test_uart_init(); // 串口初始化
   cm_printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
   cm_printf("ML302 OpenCPU Starts\n");
   cm_printf("Boot Cause:%d\n",cm_sys_get_boot_cause());
   cm_sys_get_sdk_swver(buf,50); // 读取SDK版本号
   cm_printf("SDK VERSION:%s\n",buf);
   cm_sys_get_base_swver(buf,50); // 读取基线版本号
   cm_printf("BASELINE VERSION:%s\n",buf);
   cm_sys_get_hwver(buf,50); // 读取硬件版本号
   cm_printf("HW VERSION:%s-%s\n",buf,CM_HARDWARE_VERSION);  
   cm_printf("waiting for network...\n");
   cm_test_vir_at_init(); // 虚拟AT初始化
   cm_test_network_config(); // 网络初始化配置
   time_to_date(osiEpochSecond()+cm_get_timezone()* 15*60,&t); // 获取当前时间
   cm_printf("Now:%d-%d-%d:%d:%d:%d\n",t.tm_year,t.tm_mon+1,t.tm_mday,t.tm_hour,t.tm_min,t.tm_sec);
   osDelay(1000);
   cm_test_get_imei(); // 读取IMEI
   cm_test_get_imsi(); // 读取IMSI
   cm_test_get_iccid(); // 读取ICCID
   #ifdef CM_FOTA_SUPPORT  
   char *version = NULL;
   onVersion(&version); // 读取OneNet FOTA版本号
   cm_printf("OneNet FOTA version:%s\n", version);
   #endif

#ifdef USER_APP_SUPPORT
    user_app_main(); // 用户应用程序主函数
#endif
    
#ifdef CM_SPIFLASH_FS_SUPPORT
    cm_fsMountSpiFlash();
#endif       
    while(1) // 循环等待串口输入
    {
        cm_printf("\nplease input cmds:\n");
        osSignalWait(0x0004, osWaitForever);

        if((cmd_len < 2))
        {
            cm_printf("CMD NOT DEFINE\n");    
        }
        else
        {
            for(i = 0;i< (sizeof(cmd_vector)/sizeof(cm_cmd_t));i++)
            {                
                if(strcmp(cmd_buf[1],cmd_vector[i].cmdstr) == 0) // 依次寻找是否有匹配的功能
                {
                    (*(cmd_vector[i].cmdfunc))(cmd_buf,cmd_len); // 按照接收到的参数执行相应的功能
                    cm_printf("OK\n");
                    break;
                }
            }
            if( i >=  (sizeof(cmd_vector)/sizeof(cm_cmd_t)))
            {
                cm_printf("CMD NOT DEFINE\n");
            }
        }
		for(i=0;i<cmd_len;i++)
        {
            free(cmd_buf[i]); // 依次释放用于解析命令的串口缓冲区
        }	
        osMutexRelease( cmd_mutex ); // 释放互斥锁
    }
}

3. 结果验证

按照《【LTE CAT1】ML302 OpenCPU | 开发环境搭建及固件更新》中提到的方法编译程序并下载固件到模组中,重新上电后可看到如下串口信息:
【LTE CAT1】ML302 OpenCPU | 应用开发入门_第1张图片
说明应用程序已成功调用。

你可能感兴趣的:(IoT,ML302,OpenCPU,OneMo,4G,LTE)