Porting Layer - 跨平台函数接口封装(RTOS/Windows/Linux)- C语言

目录

  • 概述
  • 具体实现
  • 使用说明

概述

在嵌入式开发中,一般会在某个开发板上某个系统上实现某个功能,为了开发模块的移植性更好,因此需要对不同的操作系统有一层封装层。当换一个操作系统时,模块中的code不用修改,只需要根据不同的操作系统将封装层的函数实现即可,起到了模块和操作系统的解耦。同理,类似的还有模块与开发板的库函数(相当于工具模块),如输入输出,Socket,时间日期,内存管理等。如下实现了两个常用操作系统的封装层,以便跑在嵌入式中的功能运行在Window上,以方便调试优化。

具体实现

以下是一个用C语言实现的跨平台函数接口层,可以同时适用于RTOS(如FreeRTOS),Linux和Windows环境。通过宏定义区分不同平台,提供统一的API接口。

/**
 * @file platform_api.h
 * @brief 跨平台接口层(RTOS/Windows/Linux)
 */

#ifndef PLATFORM_API_H
#define PLATFORM_API_H

#include 
#include 

// 平台检测宏
#if defined(_WIN32) || defined(_WIN64)
    #define PLATFORM_WINDOWS 1
    #include 
#elif defined(__linux__)
    #define PLATFORM_LINUX 1
    #include 
    #include 
    #include 
    #include 
    #include 
#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);

void* platform_thread_create(thread_func_t func, void* arg, uint32_t stack_size, int priority);
void platform_thread_destroy(void* thread);
void platform_sleep(uint32_t ms);
uint32_t platform_thread_id(void);

/*---------------------------------
 * 互斥锁接口
 *--------------------------------*/
typedef void* platform_mutex_t;

platform_mutex_t platform_mutex_create(void);
void platform_mutex_destroy(platform_mutex_t mutex);
void platform_mutex_lock(platform_mutex_t mutex);
bool platform_mutex_trylock(platform_mutex_t mutex);
void platform_mutex_unlock(platform_mutex_t mutex);

/*---------------------------------
 * 信号量接口
 *--------------------------------*/
typedef void* platform_sem_t;

platform_sem_t platform_sem_create(uint32_t max_count, uint32_t init_count);
void platform_sem_destroy(platform_sem_t sem);
bool platform_sem_wait(platform_sem_t sem, uint32_t timeout_ms);
void platform_sem_post(platform_sem_t sem);

/*---------------------------------
 * 消息队列接口
 *--------------------------------*/
typedef void* platform_queue_t;

platform_queue_t platform_queue_create(uint32_t item_size, uint32_t queue_size);
void platform_queue_destroy(platform_queue_t queue);
bool platform_queue_send(platform_queue_t queue, const void* item, uint32_t timeout_ms);
bool platform_queue_receive(platform_queue_t queue, void* item, uint32_t timeout_ms);

/*---------------------------------
 * 时间相关接口
 *--------------------------------*/
uint32_t platform_get_tick_count(void);
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 跨平台接口层实现(RTOS/Windows/Linux)
 */

#include "platform_api.h"
#include 
#include 

/*---------------------------------
 * 线程相关实现
 *--------------------------------*/
#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_LINUX

// Linux实现
struct linux_thread_wrapper {
    pthread_t thread;
    thread_func_t func;
    void* arg;
};

static void* linux_thread_entry(void* arg)
{
    struct linux_thread_wrapper* wrapper = (struct linux_thread_wrapper*)arg;
    wrapper->func(wrapper->arg);
    free(wrapper);
    return NULL;
}

void* platform_thread_create(thread_func_t func, void* arg, uint32_t stack_size, int priority)
{
    struct linux_thread_wrapper* wrapper = malloc(sizeof(*wrapper));
    if (!wrapper) return NULL;
    
    wrapper->func = func;
    wrapper->arg = arg;
    
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    if (stack_size > 0) {
        pthread_attr_setstacksize(&attr, stack_size);
    }
    
    if (pthread_create(&wrapper->thread, &attr, linux_thread_entry, wrapper) != 0) {
        free(wrapper);
        return NULL;
    }
    
    // Linux线程优先级设置(需要root权限)
    struct sched_param param;
    param.sched_priority = priority;
    pthread_setschedparam(wrapper->thread, SCHED_OTHER, &param);
    
    pthread_attr_destroy(&attr);
    return wrapper;
}

void platform_thread_destroy(void* thread)
{
    struct linux_thread_wrapper* wrapper = (struct linux_thread_wrapper*)thread;
    if (wrapper) {
        pthread_join(wrapper->thread, NULL);
        free(wrapper);
    }
}

void platform_sleep(uint32_t ms)
{
    usleep(ms * 1000);
}

uint32_t platform_thread_id(void)
{
    return (uint32_t)pthread_self();
}

#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_LINUX

platform_mutex_t platform_mutex_create(void)
{
    pthread_mutex_t* mutex = malloc(sizeof(pthread_mutex_t));
    if (mutex) {
        pthread_mutex_init(mutex, NULL);
    }
    return mutex;
}

void platform_mutex_destroy(platform_mutex_t mutex)
{
    if (mutex) {
        pthread_mutex_destroy((pthread_mutex_t*)mutex);
        free(mutex);
    }
}

void platform_mutex_lock(platform_mutex_t mutex)
{
    pthread_mutex_lock((pthread_mutex_t*)mutex);
}

bool platform_mutex_trylock(platform_mutex_t mutex)
{
    return pthread_mutex_trylock((pthread_mutex_t*)mutex) == 0;
}

void platform_mutex_unlock(platform_mutex_t mutex)
{
    pthread_mutex_unlock((pthread_mutex_t*)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_LINUX

platform_sem_t platform_sem_create(uint32_t max_count, uint32_t init_count)
{
    sem_t* sem = malloc(sizeof(sem_t));
    if (sem) {
        sem_init(sem, 0, init_count);
    }
    return sem;
}

void platform_sem_destroy(platform_sem_t sem)
{
    if (sem) {
        sem_destroy((sem_t*)sem);
        free(sem);
    }
}

bool platform_sem_wait(platform_sem_t sem, uint32_t timeout_ms)
{
    if (timeout_ms == 0xFFFFFFFF) {
        return sem_wait((sem_t*)sem) == 0;
    } else {
        struct timespec ts;
        clock_gettime(CLOCK_REALTIME, &ts);
        ts.tv_sec += timeout_ms / 1000;
        ts.tv_nsec += (timeout_ms % 1000) * 1000000;
        if (ts.tv_nsec >= 1000000000) {
            ts.tv_sec++;
            ts.tv_nsec -= 1000000000;
        }
        return sem_timedwait((sem_t*)sem, &ts) == 0;
    }
}

void platform_sem_post(platform_sem_t sem)
{
    sem_post((sem_t*)sem);
}

#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_LINUX

struct linux_queue {
    uint32_t item_size;
    uint32_t queue_size;
    uint8_t* buffer;
    uint32_t head;
    uint32_t tail;
    uint32_t count;
    sem_t sem_empty;
    sem_t sem_full;
    pthread_mutex_t lock;
};

platform_queue_t platform_queue_create(uint32_t item_size, uint32_t queue_size)
{
    struct linux_queue* queue = malloc(sizeof(struct linux_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;
    
    sem_init(&queue->sem_empty, 0, queue_size);
    sem_init(&queue->sem_full, 0, 0);
    pthread_mutex_init(&queue->lock, NULL);
    
    return (platform_queue_t)queue;
}

void platform_queue_destroy(platform_queue_t queue)
{
    struct linux_queue* q = (struct linux_queue*)queue;
    if (q) {
        pthread_mutex_destroy(&q->lock);
        sem_destroy(&q->sem_empty);
        sem_destroy(&q->sem_full);
        free(q->buffer);
        free(q);
    }
}

bool platform_queue_send(platform_queue_t queue, const void* item, uint32_t timeout_ms)
{
    struct linux_queue* q = (struct linux_queue*)queue;
    
    if (timeout_ms == 0xFFFFFFFF) {
        if (sem_wait(&q->sem_empty) != 0) return false;
    } else {
        struct timespec ts;
        clock_gettime(CLOCK_REALTIME, &ts);
        ts.tv_sec += timeout_ms / 1000;
        ts.tv_nsec += (timeout_ms % 1000) * 1000000;
        if (ts.tv_nsec >= 1000000000) {
            ts.tv_sec++;
            ts.tv_nsec -= 1000000000;
        }
        if (sem_timedwait(&q->sem_empty, &ts) != 0) return false;
    }
    
    pthread_mutex_lock(&q->lock);
    
    memcpy(q->buffer + q->tail * q->item_size, item, q->item_size);
    q->tail = (q->tail + 1) % q->queue_size;
    q->count++;
    
    pthread_mutex_unlock(&q->lock);
    sem_post(&q->sem_full);
    return true;
}

bool platform_queue_receive(platform_queue_t queue, void* item, uint32_t timeout_ms)
{
    struct linux_queue* q = (struct linux_queue*)queue;
    
    if (timeout_ms == 0xFFFFFFFF) {
        if (sem_wait(&q->sem_full) != 0) return false;
    } else {
        struct timespec ts;
        clock_gettime(CLOCK_REALTIME, &ts);
        ts.tv_sec += timeout_ms / 1000;
        ts.tv_nsec += (timeout_ms % 1000) * 1000000;
        if (ts.tv_nsec >= 1000000000) {
            ts.tv_sec++;
            ts.tv_nsec -= 1000000000;
        }
        if (sem_timedwait(&q->sem_full, &ts) != 0) return false;
    }
    
    pthread_mutex_lock(&q->lock);
    
    memcpy(item, q->buffer + q->head * q->item_size, q->item_size);
    q->head = (q->head + 1) % q->queue_size;
    q->count--;
    
    pthread_mutex_unlock(&q->lock);
    sem_post(&q->sem_empty);
    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_LINUX

uint32_t platform_get_tick_count(void)
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
}

void platform_get_time(uint32_t* sec, uint32_t* usec)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    if (sec) *sec = tv.tv_sec;
    if (usec) *usec = tv.tv_usec;
}

#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 

void worker_thread(void* arg)
{
    int id = *(int*)arg;
    platform_mutex_t mutex = platform_mutex_create();
    
    for (int i = 0; i < 5; i++) {
        platform_mutex_lock(mutex);
        printf("Thread %d: Count %d\n", id, i);
        platform_mutex_unlock(mutex);
        platform_sleep(1000);
    }
    
    platform_mutex_destroy(mutex);
}

int main()
{
    int id1 = 1, id2 = 2;
    void* t1 = platform_thread_create(worker_thread, &id1, 4096, 1);
    void* t2 = platform_thread_create(worker_thread, &id2, 4096, 1);
    
    platform_thread_destroy(t1);
    platform_thread_destroy(t2);
    return 0;
}

你可能感兴趣的:(嵌入式,windows,c语言,单片机)