#define CONN_TASK_STACK_SIZE 384int conn_task_create(void *data, u8 RS485_num, u8 max_conncet, u16 timeout,u8 model)
{
int i,q;
u8 err;
void (*task_entryTCP)(void *p_arg); /* 函数指针 */
void (*task_entryRS485)(void *p_arg); /* 函数指针 */
/* 1. 检查是否已达上限 */
if (create_number[RS485_num - 1] >= max_conncet)
{
return -1; // 返回特殊错误码:达到上限
}
/* 从0开始查找网络空闲项 */
for (i = 0; i < MAX_CONN_TASK; i++)
{
if (task[i].prio == OS_ERR_PRIO_INVALID)
{
break;
}
}
if (i >= MAX_CONN_TASK) // 没有空闲任务
{
return -1;
}
/* 从0开始查找串口空闲项 */
for (q = 0; q < MAX_UART_TASK; q++)
{
if (UartTask[q].prio == OS_ERR_PRIO_INVALID)
{
break;
}
}
if (q >= MAX_UART_TASK) // 没有空闲任务
{
return -1;
}
/* 申请共享结构体 */
TcpServer_pair_t *pair = (TcpServer_pair_t *)mymalloc(SRAMEX, sizeof(TcpServer_pair_t));
if (!pair)
return -1;
pair->conn = data;
pair->exit_flag[0] = 0;
pair->exit_flag[1] = 0;
pair->ref_count = 2; // 两个线程共享
pair->timeout_ms = timeout;
pair->rs485_num = RS485_num;
/* 分配栈并创建任务1:TCP→RS485 */
task[i].stk = mymalloc(SRAMEX, CONN_TASK_STACK_SIZE * 4);
if (!task[i].stk)
goto fail;
err = OSTaskCreate(child_task, pair, &task[i].stk[CONN_TASK_STACK_SIZE - 1], CONN_TASK_PRIO_BASE + i);
if (err != OS_NO_ERR)
goto fail;
task[i].prio = CONN_TASK_PRIO_BASE + i;
task[i].data = pair;
pair->prio0 = CONN_TASK_PRIO_BASE + i;
/* 分配栈并创建任务2:RS485→TCP */
UartTask[q].stk = mymalloc(SRAMEX, CONN_TASK_STACK_SIZE * 4);
if (!UartTask[q].stk)
goto fail;
err = OSTaskCreate(TTPchild_task_rs485, pair, &UartTask[q].stk[CONN_TASK_STACK_SIZE - 1], UART_TASK_PRIO_BASE + q);
if (err != OS_NO_ERR)
goto fail;
UartTask[q].prio = UART_TASK_PRIO_BASE + q;
UartTask[q].rs485_now = RS485_num;
pair->prio1 = UART_TASK_PRIO_BASE + q;
/* 4. 成功创建后,增加计数器 */
create_number[RS485_num - 1]++;
pair->timenow = sys_now(); // 初始化活动时间
return 0;
fail:
if (pair)
myfree(SRAMEX, pair);
if (task[i].stk)
myfree(SRAMEX, task[i].stk);
if (UartTask[q].stk)
myfree(SRAMEX, UartTask[q].stk);
return -1;
}void child_task(void *arg)
{
TcpServer_pair_t *pair = (TcpServer_pair_t *)arg;
struct netconn *conn = pair->conn;
struct netbuf *recvbuf;
err_t err;
u32_t now;
INT8U err1;
u8 rs485 = pair->rs485_num - 1;
ClientAdd(pair->rs485_num, conn);
while (!pair->exit_flag[1])
{
err = netconn_recv(conn, &recvbuf);
if (err == ERR_OK)
{
for (struct pbuf *q = recvbuf->p; q != NULL; q = q->next)
{
u8 dropped = 1; /* 先假定要丢包 */
for(u8 i = 0;i < shengdu;i++)
{
if(SerialSendCtx[rs485][i].style == 0)//有空闲缓冲区
{
if (q->len > SerialSendCtx[rs485][i].len)
{
/* 缓存太小,直接当作丢包 */
break;
}
mymemcpy(SerialSendCtx[rs485][i].buf, (u8 *)q->payload, q->len);
SerialSendCtx[rs485][i].usedlen = q->len;
SerialSendCtx[rs485][i].style = 1;
dropped = 0;
break;
}
}
if (dropped) /* 10 个槽全忙 */
{
dropSend_cnt[rs485]++;
}
}
netbuf_delete(recvbuf);
}
else if (err == ERR_TIMEOUT)
{
now = sys_now();
if (now - pair->timenow > pair->timeout_ms)
{
break;
}
}
else
{
break;
}
}
/* 通知伙伴线程退出 */
pair->exit_flag[0] = 1;
if (--pair->ref_count == 0)
{
ClientDel(pair->rs485_num, conn);
netconn_close(conn);
netconn_delete(conn);
myfree(SRAMEX, pair);
if (create_number > 0)
{
create_number[pair->rs485_num - 1]--;
}
}
conn_task_del(pair->prio0);
}void child_task_rs4851(void *arg)
{
TcpServer_pair_t *pair = (TcpServer_pair_t *)arg;
struct netconn *conn = pair->conn;
INT8U err;
u8 id;
u8 rs485 = pair->rs485_num;
id = Getenabled_Server(pair->rs485_num);
UART_PORT_CTX_t *ctx = &gUartCtx[id];
while (!pair->exit_flag[0])
{
FRAME *pf = (FRAME *)OSQPend(ctx->broadQ, 100, &err); // 等待本串口广播
if (err == OS_TIMEOUT)
continue;
if (!pf)
continue;
if(pf->usedlen == 0 || pf->usedlen > 1024)
{
if (--pf->ref == 0)
{
OSFlagPost(FlagSendGrp[rs485 - 1], FLAG_TX_DONE, OS_FLAG_SET, &err);// bit0置位
}
continue;// 转换失败,跳过
}
else
{
if (netconn_write(conn, pf->buf, pf->usedlen, NETCONN_COPY) == ERR_OK)
{
pair->timenow = sys_now();
/* 释放动态内存 */
if (--pf->ref == 0)
{
OSFlagPost(FlagSendGrp[rs485 - 1], FLAG_TX_DONE, OS_FLAG_SET, &err);// bit0置位
}
}
else
{
break;
}
}
OSTimeDlyHMSM(0, 0, 0, 10); // 延时5ms
}
/* 通知伙伴线程退出 */
pair->exit_flag[1] = 1;
if (--pair->ref_count == 0)
{
ClientDel(pair->rs485_num, conn);
netconn_close(conn);
netconn_delete(conn);
myfree(SRAMEX, pair);
if (create_number > 0)
{
create_number[pair->rs485_num - 1]--;
}
}
conn_task_del(pair->prio1); // 收回该线程
}
最终发现如果注释掉这个任务创建 err = OSTaskCreate(TTPchild_task_rs485, pair, &UartTask[q].stk[CONN_TASK_STACK_SIZE - 1], UART_TASK_PRIO_BASE + q);
if (err != OS_NO_ERR)
goto fail;
UartTask[q].prio = UART_TASK_PRIO_BASE + q;
UartTask[q].rs485_now = RS485_num;
pair->prio1 = UART_TASK_PRIO_BASE + q;时可以实现24个客户端不崩溃但是如果不注释的话到第15个客户端就会奔溃但是我这俩个批量创建的任务已经经过了14个客户端读写的长期稳定性测试了啊代码逻辑应该没有问题为什么会出现第15个客户端连接后读写触发硬件复位回溯最后执行在etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
{
s8_t i;
LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
/* non-unicast address? */
if (ip_addr_isany(ipaddr) ||
ip_addr_isbroadcast(ipaddr, netif) ||
ip_addr_ismulticast(ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
return ERR_ARG;
}
/* find or create ARP entry */
i = etharp_find_entry(ipaddr, flags);
/* bail out if no entry could be found */
if (i < 0) {
return (err_t)i;
}
#if ETHARP_SUPPORT_STATIC_ENTRIES
if (flags & ETHARP_FLAG_STATIC_ENTRY) {
/* record static type */
arp_table[i].state = ETHARP_STATE_STATIC;
} else
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
{
/* mark it stable */
arp_table[i].state = ETHARP_STATE_STABLE;
}
/* record network interface */
arp_table[i].netif = netif;
/* insert in SNMP ARP index tree */
snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
/* update address */
ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr);
/* reset time stamp */
arp_table[i].ctime = 0;
/* this is where we will send out queued packets! */
#if ARP_QUEUEING
while (arp_table[i].q != NULL) {
struct pbuf *p;
/* remember remainder of queue */
struct etharp_q_entry *q = arp_table[i].q;
/* pop first item off the queue */
arp_table[i].q = q->next;
/* get the packet pointer */
p = q->p;
/* now queue entry can be freed */
memp_free(MEMP_ARP_QUEUE, q);
#else /* ARP_QUEUEING */
if (arp_table[i].q != NULL) {
struct pbuf *p = arp_table[i].q;
arp_table[i].q = NULL;
#endif /* ARP_QUEUEING */
/* send the queued IP packet */
etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);
/* free the queued IP packet */
pbuf_free(p);
}
return ERR_OK;
}中的 pbuf_free(p);呢同时我也试过把TTPchild_task_rs485 中的所有逻辑都注释掉只剩下一个循环和让出时间片依然到15个客户端触发这个错误