一个sio.c的实现及遇到的多任务执行问题

https://sourceforge.net/p/cadcdev/lwip/ci/491e00038f26dc5d775f120aa49519a066819ebf/tree/kos/sio.c

/* KallistiOS ##version##

   sio.c
   Copyright (C)2004 Dan Potter
*/

#include <dc/scif.h>
#include <kos/thread.h>
#include <lwip/lwip.h>
#include "lwip/sio.h"

/*
  This implements the serial I/O interface for lwIP to use PPP for serial
  connections. This hooks straight to dbgio right now but could easily
  be swapped over to use the modem stuff.
 */

static volatile int sio_abort = 0;

sio_fd_t sio_open(u8_t foo) {
    int i;
    
    sio_abort = 0;

    // Clear out anything in the buffer already
    i = 0;
    while (scif_read() != -1)
        i++;
    if (i)
        printf("sio: cleared %d initial chars
", i);

    return NULL;
}

void sio_send(u8_t ch, sio_fd_t foo) {
    scif_write(ch);
    scif_flush();
}

u8_t sio_recv(sio_fd_t foo) {
    int ch;

    do {
        ch = scif_read();
        if (ch == -1)
            thd_sleep(10);
    } while (ch == -1 && !sio_abort);

    sio_abort = 0;
    return ch;
}

// I *think* this is right, but sio_* seems to be totally
// undocumented like so many things in lwIP.
u32_t sio_read(sio_fd_t foo, u8_t *outbuf, u32_t bufmax) {
    int i, ch;

    for (i=0; i<bufmax && !sio_abort; i++) {
        ch = scif_read();
        if (ch == -1) {
            if (i == 0) {
                thd_sleep(10);
                i--;
                continue;
            } else
                break;
        }
        outbuf[i] = ch;
    }

    sio_abort = 0;
    return i;
}

// Ditto on the comment for sio_read.
u32_t sio_write(sio_fd_t foo, u8_t *buf, u32_t buflen) {
    int i;

    for (i=0; i<buflen && !sio_abort; i++)
        scif_write(buf[i]);
    scif_flush();

    sio_abort = 0;
    return buflen;
}

void sio_read_abort(sio_fd_t foo) {
    sio_abort = 1;
    printf("sio_read_abort called
");
    while (sio_abort)
        thd_sleep(10);
}

 上面这个实现似乎没有实现block

下面的实现,一开始while死循环处没有加Delay(1);,结果,其它任务根本起不来,

后来,加了一个Delay(1);之后,其它任务就能起来了。

即使没有Delay(1);,任务调度不是也应该能调度其它任务吗???

/**
 * Reads from the serial device.
 * 
 * @param fd serial device handle
 * @param data pointer to data buffer for receiving
 * @param len maximum length (in bytes) of data to receive
 * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
 * 
 * @note This function will block until data can be received. The blocking
 * can be cancelled by calling sio_read_abort().
 */
u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)
{
    if(len >= 1)
    {
        if(fd.UartNo == 1)
        {
            while(USART_GetITStatus(USART1, USART_IT_RXNE) == RESET) {Delay(1);}
            {
                *data =(u8)USART_ReceiveData(USART1);
                return 1;
            }
        }
        else if(fd.UartNo == 3)
        {
            while(USART_GetITStatus(USART3, USART_IT_RXNE) == RESET)
            {
                *data =(u8)USART_ReceiveData(USART3);
                return 1;
            }
        }
        else if(fd.UartNo == 5)
        {
            while(USART_GetITStatus(UART5, USART_IT_RXNE) == RESET)
            {
                *data =(u8)USART_ReceiveData(UART5);
                return 1;
            }
        }
        else if(fd.UartNo == 6)
        {
            while(USART_GetITStatus(USART6, USART_IT_RXNE) == RESET)
            {
                *data =(u8)USART_ReceiveData(USART6);
                return 1;
            }
        }
    }
    return 0;
}

 另外,上面没有实现多字节读取,读取len个,也没有实现abort,可以参考最开始的例子。

目前系统中所有任务的优先级分配如下,空闲任务优先级为0,最大优先级是8:

Main_task    1

ToggleLed4   2

tcpip task      6

udp task                 5

eth input       7

slip input       7

slip接收任务如下:

#if SLIP_USE_RX_THREAD
/**
 * The SLIP input thread.
 *
 * Feed the IP layer with incoming packets
 *
 * @param nf the lwip network interface structure for this slipif
 */
static void
slipif_loop_thread(void *nf)
{
  u8_t c;
  struct netif *netif = (struct netif *)nf;
  struct slipif_priv *priv = (struct slipif_priv *)netif->state;

  while (1) {
    if (sio_tryread(priv->sd, &c, 1) > 0) {
      slipif_rxbyte_input(netif, c);
    }
  }
}
#endif /* SLIP_USE_RX_THREAD */

slip接收任务是死循环,没有自动结束,而且优先级是最高的7,因此,slip任务会一直运行,其它任务都无法打断(led、udp任务无法执行)。

在read的while中加Delay(1);可以,而且,这里的Delay(1)得是用的操作系统的delay,如下:

/**
  * @brief  Inserts a delay time.
  * @param  nCount: number of Ticks to delay.
  * @retval None
  */
void Delay(uint32_t nCount)
{
  vTaskDelay(nCount);
}

vTaskDelay就是FreeRTOS操作系统自带的延时函数。因为,操作系统在执行该任务的delay过程中,会去执行其它任务,因此,其它低优先级任务得以继续执行。

如果delay这里用for 100次的这种方式,仍然是不行的,操作系统仍然不能切换到其它任务。

关于vTaskDelay可以看这篇博文http://blog.csdn.net/zhzht19861011/article/details/51705148

需要对整个系统的不同任务、优先级好好了解清楚。

对于高优先级任务,需要执行完就立刻挂起或阻塞,以让其它低优先级任务得以执行。

原文地址:https://www.cnblogs.com/yanhc/p/8476643.html