一、新增源檔案
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. 增加頭檔案
- 在
目錄下建立檔案夾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
- 在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
。
- 在
目錄下的[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中添加使用者自定義的應用程式了。
二、應用程式的調用
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 | 開發環境搭建及固件更新》中提到的方法編譯程式并下載下傳固件到模組中,重新上電後可看到如下序列槽資訊:
說明應用程式已成功調用。