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
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
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
为了保证新增的代码不影响原有SDK的结构,在Makefile文件中新增一个宏定义USER_APP_SUPPORT
。
[src_root]
目录下的cm_feature.mk
的文件中添加一行定义,用于控制是否新增宏定义:#配置用户自定功能,Add by GuoHua
cm_user_app_on = y
[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中添加用户自定义的应用程序了。
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线程的回调函数,在该回调函数中完成应用程序的开发。
在文件[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 ); // 释放互斥锁
}
}
按照《【LTE CAT1】ML302 OpenCPU | 开发环境搭建及固件更新》中提到的方法编译程序并下载固件到模组中,重新上电后可看到如下串口信息:
说明应用程序已成功调用。