/* * 模块名称:假内核(net_socket 主机侧单测专用) * 模块功能:给 net_socket.c 一份可在 PC 上跑的 FreeRTOS/CMSIS-RTOS2 薄壳—— * 消息队列(osMessageQueuePut/Get,真实 cmsis_os2.h 的原型)、 * 任务通知(xTaskNotify / xTaskNotifyWait)、当前任务句柄、时基、临界区计数。 * * ⚠ 仅供 test/host/net_socket/ 使用,不参与 MCU 构建。 * * 关键设计:**阻塞等待即调度点**。net_wait_result 的第二段 * xTaskNotifyWait(..., portMAX_DELAY) 在真机上是"睡到 netTask 回执";这里把这一次 * 等待实现成"调用测试装泵的 pump 钩子(= 以 netTask 身份跑一轮 * net_process_messages()),再拾取通知值"。于是单次 net_send()/net_recv() 调用就能 * 把"入队 → 分派 → 通知值回传 → 调用方恢复 errno"整条跨上下文链真实跑完, * 而不是把中间环节假掉。 * * 泵保险:pump 钩子最多跑 NS_PUMP_MAX 轮,超了直接 exit(2)——否则一条"该通知却没通知" * 的缺陷会让门禁挂死而不是报错(本仓假 osDelay 的跑飞保险同一条纪律)。 * * 创建日期:2026-10-24 */ #ifndef NS_RTOS_H #define NS_RTOS_H #include "FreeRTOS.h" #include "cmsis_os2.h" #include "main.h" /* 桩:HAL_GetTick / HAL_GPIO_ReadPin / CH395_INT_* */ #define NS_Q_CAP 8u #define NS_PUMP_MAX 50 /* 两个假任务:调用方任务 + netTask(句柄取地址即唯一) */ extern int g_ns_task_caller; extern int g_ns_task_net; /* 当前任务句柄(测试直接读写:切换"我是调用方"还是"我是 netTask") */ extern TaskHandle_t g_ns_cur_task; /* 阻塞等待时跑的泵(测试装:通常 = 跑一轮 net_process_messages) */ typedef void (*ns_pump_fn)(void); extern ns_pump_fn g_ns_pump; extern int g_ns_pump_calls; /* 泵被驱动的次数 */ extern int g_ns_block_waits; /* 真正走到"阻塞分支"的次数 */ /* 通知/队列观测面 */ extern int g_ns_notify_calls; /* xTaskNotify 总次数 */ extern uint32_t g_ns_notify_last_val; extern TaskHandle_t g_ns_notify_last_to; extern int g_ns_put_calls; extern int g_ns_get_calls; extern int g_ns_crit_enter; extern int g_ns_crit_exit; extern uint32_t g_ns_tick; void ns_rtos_reset(void); void ns_rtos_q_flush(void); int ns_rtos_q_count(void); void ns_rtos_q_fill(int n); /* 预灌 n 条占位消息(把队列灌到满,测 BUSY 分支) */ /* 测试用的显式通知投递(不经队列,直接给某任务置通知值) */ void ns_rtos_post_notify(TaskHandle_t to, uint32_t v); /* 手工投一条原始消息(绕过公开包装器:造未知 type、造 netTask 自调等异常形态) */ int ns_rtos_q_put_raw(const net_msg_t *msg); /* —— 下面是给桩头对接的实现(原型与真实头一致) —— */ osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout); osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout); osKernelState_t osKernelGetState(void); osStatus_t osDelay(uint32_t ticks); /* 每轮 net_poll(= 一次 INT# 读取)都调一下测试回调:用来在"等待发送缓冲/等待数据" * 的循环途中投递并发事件(对端断线、芯片突然可读),而不必自己发明时间 API */ typedef void (*ns_poll_hook_fn)(void); extern ns_poll_hook_fn g_ns_on_poll; /* CH395F INT# 电平(1=SET 无中断,net_poll 走短路分支) */ extern int g_ns_int_pin_set; /* 内核状态可注入(net_errno_slot 靠它判"内核没跑起来"的退化分支) */ extern osKernelState_t g_ns_kernel_state; #endif /* NS_RTOS_H */