Files
UniversalCan/OsSample/OsSample.c
T
2026-08-25 22:10:31 -04:00

174 lines
5.0 KiB
C

#include "OsSample.h"
// --- 1. vTaskDelay ---
void vTaskDelay(const TickType_t xTicksToDelay) {
#ifdef _WIN32
Sleep(xTicksToDelay);
#elif defined(__linux__)
struct timespec ts;
ts.tv_sec = xTicksToDelay / 1000;
ts.tv_nsec = (xTicksToDelay % 1000) * 1000000L;
nanosleep(&ts, NULL);
#endif
}
// --- 2. xTaskCreate ---
// 内部包装函数:为了适配系统线程接口并防止任务返回导致进程奔溃
#ifdef _WIN32
DWORD WINAPI prvTaskWrapper(LPVOID lpParam) {
TaskFunction_t pxTask = (TaskFunction_t)(((void**)lpParam)[0]);
void* pvParams = ((void**)lpParam)[1];
free(lpParam);
pxTask(pvParams);
return 0;
}
#else
void* prvTaskWrapper(void* lpParam) {
TaskFunction_t pxTask = (TaskFunction_t)(((void**)lpParam)[0]);
void* pvParams = ((void**)lpParam)[1];
free(lpParam);
pxTask(pvParams);
return NULL;
}
#endif
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask) {
// 准备参数包
void** args = malloc(sizeof(void*) * 2);
args[0] = (void*)pvTaskCode;
args[1] = pvParameters;
#ifdef _WIN32
HANDLE hThread = CreateThread(NULL, usStackDepth, prvTaskWrapper, args, 0, NULL);
if (pxCreatedTask) *pxCreatedTask = (TaskHandle_t)hThread;
return (hThread != NULL) ? pdPASS : pdFAIL;
#elif defined(__linux__)
pthread_t threadId;
int res = pthread_create(&threadId, NULL, prvTaskWrapper, args);
if (pxCreatedTask) *pxCreatedTask = (TaskHandle_t)threadId;
return (res == 0) ? pdPASS : pdFAIL;
#endif
}
// --- 3. xQueueCreate (简易内存模拟) ---
// 注意:实际生产环境建议使用互斥锁保护。这里仅展示逻辑框架。
typedef struct {
uint8_t* storage;
uint32_t length;
uint32_t item_size;
uint32_t write_idx; // 写指针
uint32_t read_idx; // 读指针
uint32_t count; // 当前元素数量
#ifdef _WIN32
HANDLE mutex; // 保护结构体内部数据
HANDLE sem_fill; // 计数信号量:当前有多少数据可读
#else
pthread_mutex_t mutex;
sem_t sem_fill;
#endif
} SimulatedQueue;
// --- xQueueCreate ---
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize) {
SimulatedQueue* q = (SimulatedQueue*)malloc(sizeof(SimulatedQueue));
if (!q) return NULL;
q->storage = (uint8_t*)malloc(uxQueueLength * uxItemSize);
q->length = uxQueueLength;
q->item_size = uxItemSize;
q->write_idx = 0;
q->read_idx = 0;
q->count = 0;
#ifdef _WIN32
q->mutex = CreateMutex(NULL, FALSE, NULL);
q->sem_fill = CreateSemaphore(NULL, 0, uxQueueLength, NULL);
#else
pthread_mutex_init(&q->mutex, NULL);
sem_init(&q->sem_fill, 0, 0);
#endif
return (QueueHandle_t)q;
}
// --- xQueueSend ---
BaseType_t xQueueSend(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait) {
SimulatedQueue* q = (SimulatedQueue*)xQueue;
if (!q) return pdFAIL;
// 1. 进入临界区保护数据
#ifdef _WIN32
WaitForSingleObject(q->mutex, INFINITE);
#else
pthread_mutex_lock(&q->mutex);
#endif
// 检查队列是否已满
if (q->count >= q->length) {
#ifdef _WIN32
ReleaseMutex(q->mutex);
#else
pthread_mutex_unlock(&q->mutex);
#endif
return errQUEUE_FULL;
}
// 2. 拷贝数据到环形缓冲区
memcpy(q->storage + (q->write_idx * q->item_size), pvItemToQueue, q->item_size);
q->write_idx = (q->write_idx + 1) % q->length;
q->count++;
// 3. 释放信号量通知接收方,退出临界区
#ifdef _WIN32
ReleaseSemaphore(q->sem_fill, 1, NULL);
ReleaseMutex(q->mutex);
#else
sem_post(&q->sem_fill);
pthread_mutex_unlock(&q->mutex);
#endif
return pdPASS;
}
// --- xQueueReceive ---
BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait) {
SimulatedQueue* q = (SimulatedQueue*)xQueue;
if (!q) return pdFAIL;
// 1. 等待信号量(是否有数据可读)
#ifdef _WIN32
DWORD res = WaitForSingleObject(q->sem_fill, (xTicksToWait == portMAX_DELAY) ? INFINITE : xTicksToWait);
if (res != WAIT_OBJECT_0) return pdFAIL;
WaitForSingleObject(q->mutex, INFINITE); // 进入临界区
#else
// Linux 简化处理,直接阻塞等
sem_wait(&q->sem_fill);
pthread_mutex_lock(&q->mutex);
#endif
// 2. 拷贝数据
memcpy(pvBuffer, q->storage + (q->read_idx * q->item_size), q->item_size);
q->read_idx = (q->read_idx + 1) % q->length;
q->count--;
// 3. 退出临界区
#ifdef _WIN32
ReleaseMutex(q->mutex);
#else
pthread_mutex_unlock(&q->mutex);
#endif
return pdPASS;
}
// 在 OsSample.c 中实现
void vTaskStartScheduler(void) {
#ifdef _WIN32
// Windows: 挂起主线程,直到进程结束
Sleep(INFINITE);
#elif defined(__linux__)
// Linux: 使用 pause() 挂起,等待信号,或者用死循环
while(1) {
pause();
}
#endif
}