zoukankan      html  css  js  c++  java
  • 一个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

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

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

  • 相关阅读:
    win2008R2超过激活期,但是一个小时之后就会自动强制关机的问题
    SQL数据库中出现大量用户登录错误怎么解决
    VMware上安装centos 6.3 不能联网问题
    最简单的正则表达式
    双向认证SSL原理
    【虚拟机】在VMware中安装Server2008之后配置网络连接的几种方式
    win7 windows server 2008R2下 https SSL证书安装的搭配(搭配https ssl本地测试环境)
    使用word优雅的添加代码并上传到博客园(附:批量取消图片超链接方法)
    IIS服务器多域证书使用443端口解决方案
    服务器证书安装配置指南(IIS7)
  • 原文地址:https://www.cnblogs.com/yanhc/p/8476643.html
Copyright © 2011-2022 走看看