QuecOpen 开发框架详解
QuecOpen 架构
QuecOpen 是移远为 RTOS 模组提供的嵌入式 C 开发框架,让开发者直接在模组内部运行自定义应用程序。
QuecOpen 软件架构:
┌─────────────────────────────────────────┐
│ 用户应用程序(C 代码) │
│ ql_app_main() 入口函数 │
├─────────────────────────────────────────┤
│ QuecOpen SDK │
│ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ 网络 API │ │ 外设 API │ │ 系统 API│ │
│ └──────────┘ └──────────┘ └─────────┘ │
├─────────────────────────────────────────┤
│ RTOS 内核(ThreadX) │
│ 任务调度 / 信号量 / 消息队列 / 定时器 │
├─────────────────────────────────────────┤
│ 基带固件 │
│ 蜂窝协议栈 / AT 指令处理 │
└─────────────────────────────────────────┘开发环境搭建
工具链安装
bash
# Windows 开发环境
# 1. 下载移远 QuecOpen SDK(从开发者中心)
# 2. 安装 ARM GCC 工具链
# 下载:https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain
# 3. 安装 CMake
# 4. 安装 Python 3(用于构建脚本)
# Linux 开发环境
sudo apt-get install gcc-arm-none-eabi cmake python3
# 验证工具链
arm-none-eabi-gcc --versionSDK 目录结构
QuecOpen_SDK/
├── components/ # 系统组件
│ ├── kernel/ # RTOS 内核
│ ├── net/ # 网络协议栈
│ └── drivers/ # 硬件驱动
├── include/ # 头文件
│ ├── ql_api_common.h
│ ├── ql_api_datacall.h
│ ├── ql_api_http.h
│ └── ...
├── lib/ # 预编译库
├── examples/ # 示例代码
│ ├── hello_world/
│ ├── tcp_client/
│ ├── mqtt_demo/
│ └── ...
└── tools/ # 编译和烧录工具
├── build.py
└── flash.py编译示例
bash
# 进入示例目录
cd QuecOpen_SDK/examples/mqtt_demo
# 编译
python3 ../../tools/build.py
# 输出文件
ls output/
# mqtt_demo.bin # 应用程序固件
# 烧录到模组
python3 ../../tools/flash.py --port COM3 --file output/mqtt_demo.bin任务(Task)管理
QuecOpen 基于 RTOS,支持多任务并发:
c
#include "ql_api_common.h"
#include "ql_rtos.h"
// 任务句柄
ql_task_t sensor_task_handle;
ql_task_t upload_task_handle;
// 共享数据(使用互斥锁保护)
ql_mutex_t data_mutex;
float g_temperature = 0.0f;
// 传感器采集任务
void sensor_task(void *param) {
while (1) {
// 读取传感器
float temp = read_adc_temperature();
// 加锁更新共享数据
ql_rtos_mutex_lock(data_mutex, QL_WAIT_FOREVER);
g_temperature = temp;
ql_rtos_mutex_unlock(data_mutex);
QL_APP_LOG("SENSOR", QL_LOG_LEVEL_INFO, "Temp: %.1f", temp);
// 每5秒采集一次
ql_rtos_task_sleep_ms(5000);
}
}
// 数据上传任务
void upload_task(void *param) {
// 等待网络连接
wait_network_ready();
while (1) {
// 读取共享数据
ql_rtos_mutex_lock(data_mutex, QL_WAIT_FOREVER);
float temp = g_temperature;
ql_rtos_mutex_unlock(data_mutex);
// 上传数据
upload_to_server(temp);
// 每60秒上传一次
ql_rtos_task_sleep_ms(60000);
}
}
// 应用入口
void ql_app_main(void) {
// 创建互斥锁
ql_rtos_mutex_create(&data_mutex);
// 创建任务
ql_rtos_task_create(
&sensor_task_handle,
"sensor_task",
sensor_task,
NULL,
4096, // 栈大小(字节)
5 // 优先级(数字越小优先级越高)
);
ql_rtos_task_create(
&upload_task_handle,
"upload_task",
upload_task,
NULL,
8192,
10
);
}消息队列
c
#include "ql_rtos.h"
// 消息类型定义
typedef struct {
int type;
float value;
uint32_t timestamp;
} SensorMessage;
ql_queue_t msg_queue;
// 生产者:传感器任务
void sensor_producer(void *param) {
while (1) {
SensorMessage msg = {
.type = 1,
.value = read_temperature(),
.timestamp = ql_rtos_get_tick()
};
// 发送消息到队列
ql_rtos_queue_send(msg_queue, &msg, sizeof(msg), 0);
ql_rtos_task_sleep_ms(1000);
}
}
// 消费者:处理任务
void data_consumer(void *param) {
SensorMessage msg;
while (1) {
// 等待消息(阻塞)
if (ql_rtos_queue_recv(msg_queue, &msg, sizeof(msg),
QL_WAIT_FOREVER) == QL_OSI_SUCCESS) {
// 处理消息
process_sensor_data(&msg);
}
}
}
void ql_app_main(void) {
// 创建消息队列(最多 10 条消息)
ql_rtos_queue_create(&msg_queue, sizeof(SensorMessage), 10);
// 创建任务
ql_rtos_task_create(&sensor_task, "sensor", sensor_producer, NULL, 4096, 5);
ql_rtos_task_create(&consumer_task, "consumer", data_consumer, NULL, 8192, 10);
}定时器
c
#include "ql_rtos.h"
ql_timer_t heartbeat_timer;
// 定时器回调(在 RTOS 定时器上下文中执行,不能阻塞)
void heartbeat_callback(void *param) {
// 发送心跳包(通过消息队列通知任务)
int msg = MSG_HEARTBEAT;
ql_rtos_queue_send(cmd_queue, &msg, sizeof(msg), 0);
}
void ql_app_main(void) {
// 创建周期定时器(每30秒触发一次)
ql_rtos_timer_create(
&heartbeat_timer,
"heartbeat",
heartbeat_callback,
NULL,
30000, // 周期(毫秒)
QL_TIMER_AUTO // 自动重载
);
// 启动定时器
ql_rtos_timer_start(heartbeat_timer);
}文件系统操作
c
#include "ql_fs.h"
// 写入配置文件
void save_config(const char *key, const char *value) {
int fd = ql_fopen("config.json", "w");
if (fd < 0) return;
char buf[256];
snprintf(buf, sizeof(buf), "{\"%s\":\"%s\"}", key, value);
ql_fwrite(buf, strlen(buf), 1, fd);
ql_fclose(fd);
}
// 读取配置文件
int load_config(char *buf, int buf_size) {
int fd = ql_fopen("config.json", "r");
if (fd < 0) return -1;
int n = ql_fread(buf, 1, buf_size - 1, fd);
buf[n] = '\0';
ql_fclose(fd);
return n;
}
// 查看文件系统使用情况
void check_storage(void) {
ql_fs_info_t info;
ql_fs_statfs("/", &info);
QL_APP_LOG("FS", QL_LOG_LEVEL_INFO,
"Total: %d KB, Free: %d KB",
info.total_size / 1024,
info.free_size / 1024);
}