Porting Layer - 跨平台函数接口封装(RTOS/Windows)- C语言
目录
- 概述
- 具体实现
- 使用说明
概述
在嵌入式开发中,一般会在某个开发板上某个系统上实现某个功能,为了开发模块的移植性更好,因此需要对不同的操作系统有一层封装层。当换一个操作系统时,模块中的code不用修改,只需要根据不同的操作系统将封装层的函数实现即可,起到了模块和操作系统的解耦。同理,类似的还有模块与开发板的库函数(相当于工具模块),如输入输出,Socket,时间日期,内存管理等。如下实现了两个常用操作系统的封装层,以便跑在嵌入式中的功能运行在Window上,以方便调试优化。
具体实现
以下是一个用C语言实现的跨平台函数接口层,可以同时适用于RTOS(如FreeRTOS)和Windows环境。通过宏定义区分不同平台,提供统一的API接口。
/**
* @file platform_api.h
* @brief 跨平台接口层(RTOS/Windows)
*/
#ifndef PLATFORM_API_H
#define PLATFORM_API_H
#include <stdint.h>
#include <stdbool.h>
// 平台检测宏
#if defined(_WIN32) || defined(_WIN64)
#define PLATFORM_WINDOWS 1
#include <windows.h>
#elif defined(FREERTOS) || defined(RT_THREAD) || defined(UCOSII) || defined(UCOSIII)
#define PLATFORM_RTOS 1
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#else
#error "Unsupported platform!"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------
* 线程相关接口
*--------------------------------*/
typedef void (*thread_func_t)(void* arg);
/**
* @brief 创建线程
* @param func 线程函数
* @param arg 线程参数
* @param stack_size 栈大小(字节)
* @param priority 优先级(RTOS下具体含义取决于实现)
* @return 线程句柄,NULL表示失败
*/
void* platform_thread_create(thread_func_t func, void* arg, uint32_t stack_size, int priority);
/**
* @brief 销毁线程
* @param thread 线程句柄
*/
void platform_thread_destroy(void* thread);
/**
* @brief 当前线程休眠(毫秒)
* @param ms 休眠时间(毫秒)
*/
void platform_sleep(uint32_t ms);
/**
* @brief 获取当前线程ID
* @return 线程ID
*/
uint32_t platform_thread_id(void);
/*---------------------------------
* 互斥锁接口
*--------------------------------*/
typedef void* platform_mutex_t;
/**
* @brief 创建互斥锁
* @return 互斥锁句柄
*/
platform_mutex_t platform_mutex_create(void);
/**
* @brief 销毁互斥锁
* @param mutex 互斥锁句柄
*/
void platform_mutex_destroy(platform_mutex_t mutex);
/**
* @brief 锁定互斥锁
* @param mutex 互斥锁句柄
*/
void platform_mutex_lock(platform_mutex_t mutex);
/**
* @brief 尝试锁定互斥锁
* @param mutex 互斥锁句柄
* @return true-成功锁定,false-锁定失败
*/
bool platform_mutex_trylock(platform_mutex_t mutex);
/**
* @brief 解锁互斥锁
* @param mutex 互斥锁句柄
*/
void platform_mutex_unlock(platform_mutex_t mutex);
/*---------------------------------
* 信号量接口
*--------------------------------*/
typedef void* platform_sem_t;
/**
* @brief 创建信号量
* @param max_count 最大计数值
* @param init_count 初始计数值
* @return 信号量句柄
*/
platform_sem_t platform_sem_create(uint32_t max_count, uint32_t init_count);
/**
* @brief 销毁信号量
* @param sem 信号量句柄
*/
void platform_sem_destroy(platform_sem_t sem);
/**
* @brief 等待信号量
* @param sem 信号量句柄
* @param timeout_ms 超时时间(毫秒),0xFFFFFFFF表示永久等待
* @return true-成功获取,false-超时或失败
*/
bool platform_sem_wait(platform_sem_t sem, uint32_t timeout_ms);
/**
* @brief 释放信号量
* @param sem 信号量句柄
*/
void platform_sem_post(platform_sem_t sem);
/*---------------------------------
* 消息队列接口
*--------------------------------*/
typedef void* platform_queue_t;
/**
* @brief 创建消息队列
* @param item_size 每个消息项的大小(字节)
* @param queue_size 队列容量(消息项数量)
* @return 消息队列句柄
*/
platform_queue_t platform_queue_create(uint32_t item_size, uint32_t queue_size);
/**
* @brief 销毁消息队列
* @param queue 消息队列句柄
*/
void platform_queue_destroy(platform_queue_t queue);
/**
* @brief 发送消息到队列
* @param queue 消息队列句柄
* @param item 消息数据指针
* @param timeout_ms 超时时间(毫秒)
* @return true-成功,false-失败
*/
bool platform_queue_send(platform_queue_t queue, const void* item, uint32_t timeout_ms);
/**
* @brief 从队列接收消息
* @param queue 消息队列句柄
* @param item 接收缓冲区指针
* @param timeout_ms 超时时间(毫秒)
* @return true-成功,false-失败
*/
bool platform_queue_receive(platform_queue_t queue, void* item, uint32_t timeout_ms);
/*---------------------------------
* 时间相关接口
*--------------------------------*/
/**
* @brief 获取系统启动后的毫秒数
* @return 毫秒数
*/
uint32_t platform_get_tick_count(void);
/**
* @brief 获取当前时间(秒和微秒)
* @param sec 存储秒数的指针
* @param usec 存储微秒数的指针
*/
void platform_get_time(uint32_t* sec, uint32_t* usec);
#ifdef __cplusplus
}
#endif
#endif /* PLATFORM_API_H */
下面是实现文件 platform_api.c:
/**
* @file platform_api.c
* @brief 跨平台接口层实现
*/
#include "platform_api.h"
#include <string.h>
/*---------------------------------
* 线程相关实现
*--------------------------------*/
#if PLATFORM_WINDOWS
// Windows实现
struct win_thread_wrapper {
HANDLE handle;
thread_func_t func;
void* arg;
};
static DWORD WINAPI win_thread_entry(LPVOID lpParam)
{
struct win_thread_wrapper* wrapper = (struct win_thread_wrapper*)lpParam;
wrapper->func(wrapper->arg);
free(wrapper);
return 0;
}
void* platform_thread_create(thread_func_t func, void* arg, uint32_t stack_size, int priority)
{
struct win_thread_wrapper* wrapper = malloc(sizeof(*wrapper));
if (!wrapper) return NULL;
wrapper->func = func;
wrapper->arg = arg;
wrapper->handle = CreateThread(NULL, stack_size, win_thread_entry, wrapper, 0, NULL);
if (!wrapper->handle) {
free(wrapper);
return NULL;
}
// Windows线程优先级映射
int win_priority;
if (priority < -2) win_priority = THREAD_PRIORITY_LOWEST;
else if (priority < 0) win_priority = THREAD_PRIORITY_BELOW_NORMAL;
else if (priority == 0) win_priority = THREAD_PRIORITY_NORMAL;
else if (priority <= 2) win_priority = THREAD_PRIORITY_ABOVE_NORMAL;
else win_priority = THREAD_PRIORITY_HIGHEST;
SetThreadPriority(wrapper->handle, win_priority);
return wrapper;
}
void platform_thread_destroy(void* thread)
{
struct win_thread_wrapper* wrapper = (struct win_thread_wrapper*)thread;
if (wrapper) {
WaitForSingleObject(wrapper->handle, INFINITE);
CloseHandle(wrapper->handle);
free(wrapper);
}
}
void platform_sleep(uint32_t ms)
{
Sleep(ms);
}
uint32_t platform_thread_id(void)
{
return (uint32_t)GetCurrentThreadId();
}
#elif PLATFORM_RTOS
// RTOS实现
void* platform_thread_create(thread_func_t func, void* arg, uint32_t stack_size, int priority)
{
TaskHandle_t task = NULL;
// FreeRTOS优先级是数字越大优先级越高,通常配置为0-(configMAX_PRIORITIES-1)
if (priority < 0) priority = 0;
if (priority > configMAX_PRIORITIES - 1) priority = configMAX_PRIORITIES - 1;
xTaskCreate((TaskFunction_t)func, "platform_thread", stack_size/sizeof(StackType_t),
arg, (UBaseType_t)priority, &task);
return task;
}
void platform_thread_destroy(void* thread)
{
if (thread) {
vTaskDelete(thread);
}
}
void platform_sleep(uint32_t ms)
{
vTaskDelay(pdMS_TO_TICKS(ms));
}
uint32_t platform_thread_id(void)
{
return (uint32_t)xTaskGetCurrentTaskHandle();
}
#endif
/*---------------------------------
* 互斥锁实现
*--------------------------------*/
#if PLATFORM_WINDOWS
platform_mutex_t platform_mutex_create(void)
{
CRITICAL_SECTION* cs = malloc(sizeof(CRITICAL_SECTION));
if (cs) {
InitializeCriticalSection(cs);
}
return cs;
}
void platform_mutex_destroy(platform_mutex_t mutex)
{
if (mutex) {
DeleteCriticalSection((CRITICAL_SECTION*)mutex);
free(mutex);
}
}
void platform_mutex_lock(platform_mutex_t mutex)
{
EnterCriticalSection((CRITICAL_SECTION*)mutex);
}
bool platform_mutex_trylock(platform_mutex_t mutex)
{
return TryEnterCriticalSection((CRITICAL_SECTION*)mutex) != 0;
}
void platform_mutex_unlock(platform_mutex_t mutex)
{
LeaveCriticalSection((CRITICAL_SECTION*)mutex);
}
#elif PLATFORM_RTOS
platform_mutex_t platform_mutex_create(void)
{
return (platform_mutex_t)xSemaphoreCreateMutex();
}
void platform_mutex_destroy(platform_mutex_t mutex)
{
vSemaphoreDelete((SemaphoreHandle_t)mutex);
}
void platform_mutex_lock(platform_mutex_t mutex)
{
xSemaphoreTake((SemaphoreHandle_t)mutex, portMAX_DELAY);
}
bool platform_mutex_trylock(platform_mutex_t mutex)
{
return xSemaphoreTake((SemaphoreHandle_t)mutex, 0) == pdTRUE;
}
void platform_mutex_unlock(platform_mutex_t mutex)
{
xSemaphoreGive((SemaphoreHandle_t)mutex);
}
#endif
/*---------------------------------
* 信号量实现
*--------------------------------*/
#if PLATFORM_WINDOWS
platform_sem_t platform_sem_create(uint32_t max_count, uint32_t init_count)
{
HANDLE sem = CreateSemaphore(NULL, init_count, max_count, NULL);
return (platform_sem_t)sem;
}
void platform_sem_destroy(platform_sem_t sem)
{
CloseHandle((HANDLE)sem);
}
bool platform_sem_wait(platform_sem_t sem, uint32_t timeout_ms)
{
DWORD timeout = (timeout_ms == 0xFFFFFFFF) ? INFINITE : timeout_ms;
return WaitForSingleObject((HANDLE)sem, timeout) == WAIT_OBJECT_0;
}
void platform_sem_post(platform_sem_t sem)
{
ReleaseSemaphore((HANDLE)sem, 1, NULL);
}
#elif PLATFORM_RTOS
platform_sem_t platform_sem_create(uint32_t max_count, uint32_t init_count)
{
return (platform_sem_t)xSemaphoreCreateCounting(max_count, init_count);
}
void platform_sem_destroy(platform_sem_t sem)
{
vSemaphoreDelete((SemaphoreHandle_t)sem);
}
bool platform_sem_wait(platform_sem_t sem, uint32_t timeout_ms)
{
TickType_t timeout = (timeout_ms == 0xFFFFFFFF) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
return xSemaphoreTake((SemaphoreHandle_t)sem, timeout) == pdTRUE;
}
void platform_sem_post(platform_sem_t sem)
{
xSemaphoreGive((SemaphoreHandle_t)sem);
}
#endif
/*---------------------------------
* 消息队列实现
*--------------------------------*/
#if PLATFORM_WINDOWS
struct win_queue {
uint32_t item_size;
uint32_t queue_size;
uint8_t* buffer;
uint32_t head;
uint32_t tail;
uint32_t count;
HANDLE sem_empty;
HANDLE sem_full;
CRITICAL_SECTION lock;
};
platform_queue_t platform_queue_create(uint32_t item_size, uint32_t queue_size)
{
struct win_queue* queue = malloc(sizeof(struct win_queue));
if (!queue) return NULL;
queue->item_size = item_size;
queue->queue_size = queue_size;
queue->buffer = malloc(item_size * queue_size);
if (!queue->buffer) {
free(queue);
return NULL;
}
queue->head = 0;
queue->tail = 0;
queue->count = 0;
queue->sem_empty = CreateSemaphore(NULL, queue_size, queue_size, NULL);
queue->sem_full = CreateSemaphore(NULL, 0, queue_size, NULL);
InitializeCriticalSection(&queue->lock);
return (platform_queue_t)queue;
}
void platform_queue_destroy(platform_queue_t queue)
{
struct win_queue* q = (struct win_queue*)queue;
if (q) {
DeleteCriticalSection(&q->lock);
CloseHandle(q->sem_empty);
CloseHandle(q->sem_full);
free(q->buffer);
free(q);
}
}
bool platform_queue_send(platform_queue_t queue, const void* item, uint32_t timeout_ms)
{
struct win_queue* q = (struct win_queue*)queue;
DWORD timeout = (timeout_ms == 0xFFFFFFFF) ? INFINITE : timeout_ms;
if (WaitForSingleObject(q->sem_empty, timeout) != WAIT_OBJECT_0) {
return false;
}
EnterCriticalSection(&q->lock);
memcpy(q->buffer + q->tail * q->item_size, item, q->item_size);
q->tail = (q->tail + 1) % q->queue_size;
q->count++;
LeaveCriticalSection(&q->lock);
ReleaseSemaphore(q->sem_full, 1, NULL);
return true;
}
bool platform_queue_receive(platform_queue_t queue, void* item, uint32_t timeout_ms)
{
struct win_queue* q = (struct win_queue*)queue;
DWORD timeout = (timeout_ms == 0xFFFFFFFF) ? INFINITE : timeout_ms;
if (WaitForSingleObject(q->sem_full, timeout) != WAIT_OBJECT_0) {
return false;
}
EnterCriticalSection(&q->lock);
memcpy(item, q->buffer + q->head * q->item_size, q->item_size);
q->head = (q->head + 1) % q->queue_size;
q->count--;
LeaveCriticalSection(&q->lock);
ReleaseSemaphore(q->sem_empty, 1, NULL);
return true;
}
#elif PLATFORM_RTOS
platform_queue_t platform_queue_create(uint32_t item_size, uint32_t queue_size)
{
return (platform_queue_t)xQueueCreate(queue_size, item_size);
}
void platform_queue_destroy(platform_queue_t queue)
{
vQueueDelete((QueueHandle_t)queue);
}
bool platform_queue_send(platform_queue_t queue, const void* item, uint32_t timeout_ms)
{
TickType_t timeout = (timeout_ms == 0xFFFFFFFF) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
return xQueueSend((QueueHandle_t)queue, item, timeout) == pdTRUE;
}
bool platform_queue_receive(platform_queue_t queue, void* item, uint32_t timeout_ms)
{
TickType_t timeout = (timeout_ms == 0xFFFFFFFF) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
return xQueueReceive((QueueHandle_t)queue, item, timeout) == pdTRUE;
}
#endif
/*---------------------------------
* 时间相关实现
*--------------------------------*/
#if PLATFORM_WINDOWS
uint32_t platform_get_tick_count(void)
{
return GetTickCount();
}
void platform_get_time(uint32_t* sec, uint32_t* usec)
{
FILETIME ft;
ULARGE_INTEGER li;
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
// 从1601年1月1日到1970年1月1日的100纳秒间隔数
li.QuadPart -= 116444736000000000ULL;
if (sec) *sec = (uint32_t)(li.QuadPart / 10000000ULL);
if (usec) *usec = (uint32_t)((li.QuadPart % 10000000ULL) / 10ULL);
}
#elif PLATFORM_RTOS
uint32_t platform_get_tick_count(void)
{
return xTaskGetTickCount() * portTICK_PERIOD_MS;
}
void platform_get_time(uint32_t* sec, uint32_t* usec)
{
// RTOS通常没有标准的时间获取函数,这里简单实现
uint32_t ticks = xTaskGetTickCount();
uint32_t ms = ticks * portTICK_PERIOD_MS;
if (sec) *sec = ms / 1000;
if (usec) *usec = (ms % 1000) * 1000;
}
#endif
使用说明
1.平台选择:
在Windows环境下编译时,会自动使用Windows API实现,在RTOS环境下编译时,会自动使用RTOS API实现,可以通过定义FREERTOS或其他RTOS宏来启用RTOS模式
2.基本功能:
- 线程创建和管理
- 互斥锁
- 信号量
- 消息队列
- 时间相关功能
3.使用示例:
#include "platform_api.h"
#include <stdio.h>
void thread_function(void* arg)
{
int id = *(int*)arg;
for (int i = 0; i < 5; i++) {
printf("Thread %d: count %d\n", id, i);
platform_sleep(1000);
}
}
int main()
{
// 创建线程
int id1 = 1, id2 = 2;
void* thread1 = platform_thread_create(thread_function, &id1, 4096, 1);
void* thread2 = platform_thread_create(thread_function, &id2, 4096, 1);
// 等待线程结束
platform_thread_destroy(thread1);
platform_thread_destroy(thread2);
return 0;
}