/* * 模块名称:假内核实现(net_socket 主机侧单测专用) * 模块功能:实现 ns_rtos.h 声明的假队列/假通知/假时基。由测试单元 #include 使用。 * ⚠ 仅供 test/host/net_socket/ 使用,不参与 MCU 构建。 * 创建日期:2026-10-24 */ #include #include #include #include "ns_rtos.h" #include "net_socket.h" int g_ns_task_caller; int g_ns_task_net; TaskHandle_t g_ns_cur_task; ns_pump_fn g_ns_pump; ns_poll_hook_fn g_ns_on_poll; int g_ns_pump_calls; int g_ns_block_waits; int g_ns_notify_calls; uint32_t g_ns_notify_last_val; TaskHandle_t g_ns_notify_last_to; int g_ns_put_calls; int g_ns_get_calls; int g_ns_crit_enter; int g_ns_crit_exit; uint32_t g_ns_tick; osKernelState_t g_ns_kernel_state = osKernelRunning; /* 通知槽:按句柄区分(只服务上面两个假任务,超出的句柄一律现场分配不了→报错) */ typedef struct { TaskHandle_t h; uint32_t val; int pending; } ns_notify_slot_t; static ns_notify_slot_t s_slot[2]; /* 假队列:定长环形,存 net_msg_t 按值拷贝(与真队列语义一致) */ static net_msg_t s_q[NS_Q_CAP]; static int s_q_head; static int s_q_count; void ns_rtos_reset(void) { (void)memset(s_slot, 0, sizeof(s_slot)); s_slot[0].h = (TaskHandle_t)&g_ns_task_caller; s_slot[1].h = (TaskHandle_t)&g_ns_task_net; (void)memset(s_q, 0, sizeof(s_q)); s_q_head = 0; s_q_count = 0; g_ns_cur_task = (TaskHandle_t)&g_ns_task_caller; g_ns_pump = NULL; g_ns_on_poll = NULL; g_ns_pump_calls = 0; g_ns_block_waits = 0; g_ns_notify_calls = 0; g_ns_notify_last_val = 0U; g_ns_notify_last_to = NULL; g_ns_put_calls = 0; g_ns_get_calls = 0; g_ns_crit_enter = 0; g_ns_crit_exit = 0; g_ns_tick = 0U; g_ns_kernel_state = osKernelRunning; g_ns_int_pin_set = 1; g_ns_poll_tick_inc = 1U; g_ns_poll_calls = 0U; } void ns_rtos_q_flush(void) { s_q_head = 0; s_q_count = 0; } int ns_rtos_q_count(void) { return s_q_count; } void ns_rtos_q_fill(int n) { int i; for (i = 0; (i < n) && ((uint32_t)s_q_count < NS_Q_CAP); i++) { (void)memset(&s_q[(s_q_head + s_q_count) % (int)NS_Q_CAP], 0, sizeof(net_msg_t)); s_q_count++; } } int ns_rtos_q_put_raw(const net_msg_t *msg) { if (msg == NULL || (uint32_t)s_q_count >= NS_Q_CAP) { return -1; } (void)memcpy(&s_q[(s_q_head + s_q_count) % (int)NS_Q_CAP], msg, sizeof(net_msg_t)); s_q_count++; return 0; } /* 假内核里的"另一次通知发出":与 xTaskNotify 共用同一套观测计数, * 这样"谁发了几次通知"在测试里只有一个口径(挂起完成/取消走的就是这条) */ void ns_rtos_post_notify(TaskHandle_t to, uint32_t v) { int i; g_ns_notify_calls++; g_ns_notify_last_val = v; g_ns_notify_last_to = to; for (i = 0; i < 2; i++) { if (s_slot[i].h == to) { s_slot[i].val = v; s_slot[i].pending = 1; return; } } printf("FATAL: ns_rtos_post_notify got an unknown task handle\n"); exit(2); } static ns_notify_slot_t *slot_of(TaskHandle_t h) { int i; for (i = 0; i < 2; i++) { if (s_slot[i].h == h) { return &s_slot[i]; } } return NULL; } /* —— CMSIS-RTOS2 侧(原型逐字取自真实 cmsis_os2.h:689/697/298/459)—— */ osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout) { (void)mq_id; (void)msg_prio; (void)timeout; g_ns_put_calls++; if (msg_ptr == NULL) { return osErrorParameter; } if ((uint32_t)s_q_count >= NS_Q_CAP) { return osErrorResource; /* 队列满(真机是 osWaitForever 阻塞,测试里用满队列测 BUSY 分支) */ } (void)memcpy(&s_q[(s_q_head + s_q_count) % (int)NS_Q_CAP], msg_ptr, sizeof(net_msg_t)); s_q_count++; return osOK; } osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout) { (void)mq_id; (void)msg_prio; g_ns_get_calls++; if (s_q_count == 0) { (void)timeout; return osErrorTimeout; } if (msg_ptr != NULL) { (void)memcpy(msg_ptr, &s_q[s_q_head], sizeof(net_msg_t)); } s_q_head = (s_q_head + 1) % (int)NS_Q_CAP; s_q_count--; return osOK; } osKernelState_t osKernelGetState(void) { return g_ns_kernel_state; } osStatus_t osDelay(uint32_t ticks) { static int guard; g_ns_tick += ticks; if (++guard > 20000) { printf("FATAL: osDelay runaway (%d calls) - the wait condition is never met\n", guard); exit(2); } if (guard > 0) { /* 每次 osDelay 也让 HAL_GetTick 往前走,600ms 复位上限才量得到 */ g_ns_tick += 0U; } return osOK; } /* —— FreeRTOS 侧(桩 task.h 声明)—— */ TaskHandle_t xTaskGetCurrentTaskHandle(void) { return g_ns_cur_task; } BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction) { ns_notify_slot_t *p = slot_of(xTaskToNotify); (void)eAction; /* 本测试只用 eSetValueWithOverwrite,语义相同 */ g_ns_notify_calls++; g_ns_notify_last_val = ulValue; g_ns_notify_last_to = xTaskToNotify; if (p == NULL) { printf("FATAL: xTaskNotify got an unknown task handle\n"); exit(2); } p->val = ulValue; p->pending = 1; return pdTRUE; } BaseType_t xTaskNotifyWait(uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait) { ns_notify_slot_t *p = slot_of(g_ns_cur_task); if (p == NULL) { printf("FATAL: xTaskNotifyWait current task handle unknown\n"); exit(2); } if (pulNotificationValue != NULL) { *pulNotificationValue = p->val & (~ulBitsToClearOnEntry); } if (p->pending != 0) { if (pulNotificationValue != NULL) { *pulNotificationValue = p->val; } p->val = p->val & (~ulBitsToClearOnExit); p->pending = 0; return pdTRUE; } if (xTicksToWait == 0U) { return pdFALSE; /* 零等待拾取:没有就是没有 */ } /* 阻塞分支:这就是"睡到 netTask 回执"的调度点 → 驱动一轮 netTask 再拾取 */ g_ns_block_waits++; if (g_ns_pump == NULL) { printf("FATAL: reached the blocking wait but the test installed no pump hook\n"); exit(2); } { TaskHandle_t save = g_ns_cur_task; int rounds = 0; while (rounds < NS_PUMP_MAX) { rounds++; g_ns_pump_calls++; g_ns_cur_task = (TaskHandle_t)&g_ns_task_net; /* 以 netTask 身份跑 */ g_ns_pump(); g_ns_cur_task = save; if (p->pending != 0) { break; } } if (p->pending == 0) { printf("FATAL: blocking wait still got no receipt after %d rounds (a missing notify would hang real hardware)\n", rounds); exit(2); } } if (pulNotificationValue != NULL) { *pulNotificationValue = p->val; } p->val = p->val & (~ulBitsToClearOnExit); p->pending = 0; return pdTRUE; } uint32_t xTaskGetTickCount(void) { return g_ns_tick; } int ns_os_crit_depth(void) { return g_ns_crit_enter - g_ns_crit_exit; } void ns_os_enter_critical(void) { g_ns_crit_enter++; } void ns_os_exit_critical(void) { g_ns_crit_exit++; } /* —— main.h 桩:时基 + INT# 引脚 —— */ uint32_t HAL_GetTick(void) { return g_ns_tick; } /* INT# 电平可注入:默认 SET(无中断)——net_poll 默认走"引脚高即退出"的短路分支 */ int g_ns_int_pin_set = 1; uint32_t g_ns_poll_tick_inc = 1U; uint32_t g_ns_poll_calls; /* 读 INT# 就是"net_poll 又轮了一轮"的天然计数点: * - 时基自走 g_ns_poll_tick_inc 毫秒(默认 1ms),NET_SEND_SPIN_MS=2 这种 * "有界自旋"预算才有可量测的时间轴; * - 跑飞保险:轮询次数超阈值直接 exit(2)。net_send_locked / net_recvfrom 的 * 等待环里没有 osDelay,光靠 osDelay 的保险挡不住死循环(实测过一次挂门禁)。 */ GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin) { (void)GPIOx; (void)GPIO_Pin; g_ns_poll_calls++; g_ns_tick += g_ns_poll_tick_inc; if (g_ns_on_poll != NULL) { g_ns_on_poll(); /* 并发事件注入点(在时间推进之后,超时判定才量得到) */ } if (g_ns_poll_calls > 400000U) { printf("FATAL: net_poll still not converged after %lu rounds (wait condition never met)\n", (unsigned long)g_ns_poll_calls); exit(2); } return (g_ns_int_pin_set != 0) ? GPIO_PIN_SET : GPIO_PIN_RESET; }