zoukankan      html  css  js  c++  java
  • 串口转以太(完结)

    一、串口转以太ttl2tcp应用程序

    1、 新建文件夹ttl2tcp

    该文件夹下的Makefile

    #
    # Copyright (C) 2009 OpenWrt.org
    #
    # This is free software, licensed under the GNU General Public License v2.
    # See /LICENSE for more information.
    #
    
    include $(TOPDIR)/rules.mk
    include $(INCLUDE_DIR)/kernel.mk
    
    PKG_NAME:=ttl2tcp
    PKG_RELEASE:=1
    PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
    
    include $(INCLUDE_DIR)/package.mk
    
    define Package/ttl2tcp
      SECTION:=utils
      CATEGORY:=Utilities
      TITLE:=serial to tcp 
      DEPENDS:=+libuci +libpthread
    endef
    
    define Package/ttl2tcp/description
      A client of tcp to serial or serial to tcp
    endef
    
    define Build/Prepare
        mkdir -p $(PKG_BUILD_DIR)
        $(CP) ./src/* $(PKG_BUILD_DIR)/
    endef
    
    define Build/Configure
    endef
    
    define Build/Compile
        $(MAKE) -C $(PKG_BUILD_DIR) 
            CC="$(TARGET_CC)" 
            CFLAGS="$(TARGET_CFLAGS) -Wall -I$(LINUX_DIR)/user_headers/include" 
            LDFLAGS="$(TARGET_LDFLAGS)"
    endef
    
    define Package/ttl2tcp/install
        $(INSTALL_DIR) $(1)/usr/sbin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/ttl2tcp $(1)/usr/sbin/
        $(INSTALL_DIR) $(1)/etc/config
        $(INSTALL_DATA) ./files/$(PKG_NAME).config $(1)/etc/config/$(PKG_NAME)
        $(INSTALL_DIR) $(1)/etc/init.d
        $(INSTALL_BIN) ./files/$(PKG_NAME).init $(1)/etc/init.d/$(PKG_NAME)
    
    endef
    
    $(eval $(call BuildPackage,ttl2tcp))

    2、 ttl2tcpsrc tl2tcp.c

    /*
     * ttl2tcp
     *
     * tingpan<dktingpan@sina.cn> 2015-05-31
     *
     * this is a client of serial translate to tcp or tcp translate to serial.
     * serial read overtime is 1s
     * every server read overtime is 0.5s,and the most server number is 3.
     */
    
    #include    <stdio.h>
    #include    <stdlib.h>
    #include    <string.h>
    #include    <errno.h>
    #include    <sys/types.h>
    #include    <sys/socket.h>
    #include    <netinet/in.h>
    #include     <unistd.h>  
    #include     <fcntl.h> 
    #include     <termios.h>
    #include     <errno.h>
    #include     <strings.h>
    #include     <time.h> 
    #include     <arpa/inet.h>
    #include     <pthread.h>
    #include     <uci.h>
    #include    <semaphore.h>
    
    #define SER_MAXLINE 128
    #define SOCK_MAXLINE 136//为了应对缓存溢出,多分配一个字节
    #define SERVER_MAXNUM 3
    
    struct argument  
    {  
        int fd;
        int sockfd[SERVER_MAXNUM];
    };  
    unsigned char on_max;
    struct _options {
        char name[10];
        unsigned int baudrate;
        //unsigned int data;
        //unsigned int parity;
        //unsigned int stop;    
        unsigned int enabled;    
        struct in_addr ipaddr[SERVER_MAXNUM];    
        unsigned int port[SERVER_MAXNUM];    
    };
    struct _options opt;
    //pthread_mutex_t socket_lock;       //互斥锁
    
    //为了保证用户输入的波特率是个正确的值,所以需要这两个数组验证,对于设置波特率时候,前面要加个B   
    int speed_arr[] = { B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300,  
        B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300, };  
      
    int name_arr[] = {115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300,  
        115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300, };  
      
    /*----------------------------------------------------------------------------- 
      函数名:      set_speed 
      参数:        int fd ,int speed 
      返回值:      void 
      描述:        设置fd表述符的串口波特率 
     *-----------------------------------------------------------------------------*/  
    void set_speed(int fd ,int speed)  
    {  
        struct termios opt;  
        int i;  
        int status;  
      
        tcgetattr(fd,&opt);  
        for(i = 0;i < sizeof(speed_arr)/sizeof(int);i++)  
        {  
            if(speed == name_arr[i])                        //找到标准的波特率与用户一致   
            {  
                tcflush(fd,TCIOFLUSH);                      //清除IO输入和输出缓存   
                cfsetispeed(&opt,speed_arr[i]);         //设置串口输入波特率   
                cfsetospeed(&opt,speed_arr[i]);         //设置串口输出波特率   
      
                status = tcsetattr(fd,TCSANOW,&opt);    //将属性设置到opt的数据结构中,并且立即生效   
                if(status != 0)  
                    perror("tcsetattr fd:");                //设置失败   
                return ;  
            }  
            tcflush(fd,TCIOFLUSH);                          //每次清除IO缓存   
        }  
    }  
    /*----------------------------------------------------------------------------- 
      函数名:      set_parity 
      参数:        int fd 
      返回值:      int 
      描述:        设置fd表述符的奇偶校验 
     *-----------------------------------------------------------------------------*/  
    int set_parity(int fd)  
    {  
        struct termios opt;  
      
        if(tcgetattr(fd,&opt) != 0)                 //或许原先的配置信息   
        {  
            perror("Get opt in parity error:");  
            return -1;  
        }  
      
        /*通过设置opt数据结构,来配置相关功能,以下为八个数据位,不使能奇偶校验*/  
        opt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP  
                    | INLCR | IGNCR | ICRNL | IXON);  
        opt.c_oflag &= ~OPOST;  
        opt.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);  
        opt.c_cflag &= ~(CSIZE | PARENB);  
        opt.c_cflag |= CS8;  
      
        tcflush(fd,TCIFLUSH);                           //清空输入缓存   
      
        if(tcsetattr(fd,TCSANOW,&opt) != 0)  
        {  
            perror("set attr parity error:");  
            return -1;  
        }  
      
        return 0;  
    }  
    /*----------------------------------------------------------------------------- 
      函数名:      serial_init 
      参数:        char *dev_path,int speed,int is_block 
      返回值:      初始化成功返回打开的文件描述符 
      描述:        串口初始化,根据串口文件路径名,串口的速度,和串口是否阻塞,block为1表示阻塞 
     *-----------------------------------------------------------------------------*/  
    int serial_init(char *dev_path,int speed,int is_block)  
    {  
        int fd;  
        int flag;  
      
        flag = 0;  
        flag |= O_RDWR;                     //设置为可读写的串口属性文件   
        if(is_block == 0)  
            flag |=O_NONBLOCK;              //若为0则表示以非阻塞方式打开   
      
        fd = open(dev_path,flag);               //打开设备文件   
        if(fd < 0)  
        {  
            perror("Open device file err:");  
            close(fd);  
            return -1;  
        }  
      
        /*打开设备文件后,下面开始设置波特率*/  
        set_speed(fd,speed);                //考虑到波特率可能被单独设置,所以独立成函数   
      
        /*设置奇偶校验*/  
        if(set_parity(fd) != 0)  
        {  
            perror("set parity error:");  
            close(fd);                      //一定要关闭文件,否则文件一直为打开状态   
            return -1;  
        }  
      
        return fd;  
    }  
    /*----------------------------------------------------------------------------- 
      函数名:      serial_send 
      参数:        int fd,char *str,unsigned int len 
      返回值:      发送成功返回发送长度,否则返回小于0的值 
      描述:        向fd描述符的串口发送数据,长度为len,内容为str 
     *-----------------------------------------------------------------------------*/  
    int serial_send(int fd,char *str,unsigned int len)  
    {  
        int ret;    
        
        if(len > strlen(str))                    //判断长度是否超过str的最大长度   
            len = strlen(str);  
      
        ret = write(fd,str,len);  
        if(ret < 0)  
        {  
            perror("serial send err:");  
            return -1;  
        } 
           
        return ret;  
    }  
      
    /*----------------------------------------------------------------------------- 
      函数名:      serial_read 
      参数:        int fd,char *str,unsigned int len,unsigned int timeout 
      返回值:      在规定的时间内读取数据,超时则退出,超时时间为ms级别 
      描述:        向fd描述符的串口接收数据,长度为len,存入str,timeout 为超时时间 
     *-----------------------------------------------------------------------------*/  
    int serial_read(int fd, char *str, unsigned int len, unsigned int timeout)  
    {  
        fd_set rfds;  
        struct timeval tv;  
        int ret;                                //每次读的结果   
        int sret;                               //select监控结果   
        int readlen = 0;                        //实际读到的字节数   
        char * ptr;  
      
        ptr = str;                          //读指针,每次移动,因为实际读出的长度和传入参数可能存在差异   
      
        FD_ZERO(&rfds);                     //清除文件描述符集合   
        FD_SET(fd,&rfds);                   //将fd加入fds文件描述符,以待下面用select方法监听   
      
        /*传入的timeout是ms级别的单位,这里需要转换为struct timeval 结构的*/  
        tv.tv_sec  = timeout / 1000;  
        tv.tv_usec = (timeout%1000)*1000;  
      
        /*防止读数据长度超过缓冲区*/  
        //if(sizeof(&str) < len)   
        //  len = sizeof(str);   
      
      
        /*开始读*/  
        while(readlen < len)  
        {  
            sret = select(fd+1,&rfds,NULL,NULL,&tv);        //检测串口是否可读   
      
            if(sret == -1)                              //检测失败   
            {  
                perror("select:");  
                break;  
            }  
            else if(sret > 0)                        //<SPAN style="WHITE-SPACE: pre"> </SPAN>//检测成功可读   
            {  
                ret = read(fd,ptr,1); //第三个参数为请求读取的字节数 
                if(ret < 0)  
                {  
                    perror("read err:");  
                    break;  
                }  
                else if(ret == 0)  
                    break;  
      
                readlen += ret;                             //更新读的长度   
                ptr     += ret;                             //更新读的位置   
            }  
            else                                          //超时   sret == 0 ,没填满buf也退出循环
            {  
                printf("timeout!
    ");  
                break;  
            }  
        }  
      
        return readlen;  
    }  
    
    /**
     * socket_read: 读取tcp数据 
     * @fd: socket文件描述符
     * @str:将读到的数据存放在该地址
     * @len:申请读取的字符长度
     * @timeout:超时时间,单位ms
     */ 
    int socket_read(int fd, char *str, unsigned int len, unsigned int timeout)
    {
        fd_set fdsr;
        struct timeval tv;
        int readlen = 0; 
        char * ptr; 
        int ret;
        ptr = str; 
        // initialize file descriptor set
        FD_ZERO(&fdsr);//每次循环都要清空
        FD_SET(fd, &fdsr);
        tv.tv_sec  = timeout / 1000;  
        tv.tv_usec = (timeout%1000)*1000;  
        while(readlen < len){
            ret = select(fd + 1, &fdsr, NULL, NULL, &tv);
            if (ret < 0) {
                perror("select");
                //break;
                exit(-1);
            } else if (ret == 0) {
                printf("timeout
    ");
                break;
              }
            //每次申请读取8个字节,但事实上是按发送端每次发送的字符串长度来确定的,如果长度小于8,则每次读取实际长度,如果大于8,则读取8字节。
            //recv多少就从缓冲区中删除多少,剩下的数据可以在下次recv时得到
            //即使子线程挂起,也一直有数据可以读,数据不丢失,真正的接收数据是协议来完成的,存放在s的接收缓冲中。
            ret = recv(fd, ptr, 8, 0);//申请8个字节         
            if (ret <= 0) {//如果连接已中止,返回0。如果发生错误,返回-1
                printf("client close
    ");
                close(fd);
                FD_CLR(fd, &fdsr);
                fd = 0;
            } else {        
               readlen +=ret;
               ptr += ret; 
               //printf("the ret length is:%d
    ",readlen); 
            }
        }
        return readlen;
    }
    
    /**
     * read_config: 读取配置文件 
     * @popt: 配置信息保存的结构体
     */ 
    static int read_config(struct _options *popt)
    {
        static struct uci_context *ctx;
        struct uci_ptr ptr;
        char a[32];
        char i;
        unsigned char server_num = 0;
        
        ctx = uci_alloc_context();    
    
        //读取设备名称
        //if ((strcpy(a, "ttl2tcp.device.name") == NULL) 
        if ((strncpy(a, "ttl2tcp.device.name", sizeof(a)) == NULL) 
        //if (!snprintf(a,sizeof(a),"ttl2tcp.%s.baudrate",SERNAME)
            || (uci_lookup_ptr(ctx, &ptr, a, true) != UCI_OK)) {
            printf("Read ttl2tcp.device.name failed! exit.
    ");
            exit(-1);
        }
        if (ptr.o) {
            strncpy(popt->name, ptr.o->v.string, sizeof(popt->name));
        } else {
            printf("ttl2tcp.device.name Not found!
    ");
        }
    
        //读取串口波特率
        if ((strncpy(a, "ttl2tcp.device.baudrate", sizeof(a)) == NULL) 
        //if (!snprintf(a,sizeof(a),"ttl2tcp.%s.baudrate",SERNAME)
            || (uci_lookup_ptr(ctx, &ptr, a, true) != UCI_OK)) {
            printf("Read tttl2tcp.device.baudrate failed! exit.
    ");
            exit(-1);
        }
        if (ptr.o) {
            popt->baudrate = strtol(ptr.o->v.string, NULL, 10);
        } else {
            printf("ttl2tcp.device.baudrate Not found!
    ");
        }
    
        //是否使能
        //if (!snprintf(a,sizeof(a),"ttl2tcp.%s.enabled",SERNAME)
        if ((strncpy(a, "ttl2tcp.device.enabled", sizeof(a)) == NULL) 
            || (uci_lookup_ptr(ctx, &ptr, a, true) != UCI_OK)) {
            printf("Read ttl2tcp.device.enabled failed! exit.
    ");
            exit(-1);
        }
        if (ptr.o) {
            popt->enabled = strtol(ptr.o->v.string, NULL, 10);
        } else {
            printf("ttl2tcp.device.enabled Not found!
    ");
        }
            
        for(i=0; i<SERVER_MAXNUM; i++){
            //读取ip地址
            //if ((strncpy(a, "ttl2tcp.@server[0].ipaddr",sizeof(a)) == NULL) 
            if (!snprintf(a,sizeof(a),"ttl2tcp.@server[%d].ipaddr",i)
                || (uci_lookup_ptr(ctx, &ptr, a, true) != UCI_OK)) {
                printf("Read ttl2tcp.@server[%d].ipaddr failed! exit.
    ",i);
                exit(-1);
            }
            if (ptr.o) {
                unsigned int laddr;
                laddr = inet_addr(ptr.o->v.string);//因为ipaddr为网络字节顺序,大端字节序,而输入的为主机字节序
                memcpy(&popt->ipaddr[i], &laddr, 4);    
            } else {
                printf("ttl2tcp.@server[%d].ipaddr Not found!
    ",i);
            }        
            //读取port
            //if ((strcpy(a, "ttl2tcp.@server[0].port") == NULL) 
            if (!snprintf(a,sizeof(a),"ttl2tcp.@server[%d].port",i)
                || (uci_lookup_ptr(ctx, &ptr, a, true) != UCI_OK)) {
                printf("Read ttl2tcp.@server[%d].port failed! exit.
    ",i);
                exit(-1);
            }
            if (ptr.o) {
                popt->port[i] = strtol(ptr.o->v.string, NULL, 10);
                server_num++;
            } else {
                printf("ttl2tcp.@server[%d].port Not found!
    ",i);
            }
        }
        uci_free_context(ctx);    
        return server_num;
    }
    
    /**
     * conn_nonb: 非阻塞connect 
     * @sockfd: socket文件描述符
     * @saptr:指向数据结构sockaddr的指针,其中包括目的端口和IP地址
     * @salen:sockaddr的长度
     * @nsec:超时时间,单位ms
     */ 
    int conn_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, int nsec)
    {
        int flags, n, error, code;
        socklen_t len;
        fd_set wset;
        struct timeval tval;
    
        flags = fcntl(sockfd, F_GETFL, 0);
        fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
    
        error = 0;
        if ((n = connect(sockfd, saptr, salen)) == 0) {    //马上连接成功,可能性小
            printf("conn_nonb success!
    ");
            goto done;
        }else if (n < 0 && errno != EINPROGRESS){    //多次连接或服务端没开启,出错 ,第一次一般执行不到该处。
            printf("conn_nonb error!
    ");
            return (-1);
        }
    
        /* Do whatever we want while the connect is taking place */
        //连接建立已经启动,但是尚未完成
        FD_ZERO(&wset);
        FD_SET(sockfd, &wset);
        tval.tv_sec = nsec;
        tval.tv_usec = 0;
        //printf("conn_nonb select start!
    ");
        if ((n = select(sockfd+1, NULL, &wset, //有连接要处理
                        NULL, nsec ? &tval : NULL)) == 0) {
            close(sockfd);  /* timeout */
            errno = ETIMEDOUT;
            printf("conn_nonb select timeout!
    ");
            return (-1);
        }
    
        if (FD_ISSET(sockfd, &wset)) {
            len = sizeof(error);
            code = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
            /* 如果发生错误,Solaris实现的getsockopt返回-1,
             * 把pending error设置给errno. Berkeley实现的
             * getsockopt返回0, pending error返回给error. 
             * 我们需要处理这两种情况 */
            if (code < 0 || error) {
                close(sockfd);
                if (error) 
                    errno = error;
                printf("conn_nonb getsockopt error!
    ");
                return (-1);
            }
        } else {
            fprintf(stderr, "select error: sockfd not set");
            exit(0);
        }
    
    done:
        fcntl(sockfd, F_SETFL, flags);  /* restore file status flags */
        return (0);
    }
    
    void *socket_thread(void *arg)
    {
        char sockbuf[SOCK_MAXLINE];
        int sreadlen = 0;
        int freadlen = 0;
        unsigned char i;
        struct argument thread_arg;
        thread_arg = *(struct argument *)arg;
        memset(sockbuf, 0, sizeof(sockbuf));
        while(1)
        {
            for    (i=0; i<on_max;i++)
            {
                //pthread_mutex_lock(&socket_lock);//lock        
                sreadlen = socket_read(thread_arg.sockfd[i], sockbuf, SOCK_MAXLINE-8, 500);//为了防止缓存溢出,少读取一个字节
                printf("the sockbuf is:%s
    ", sockbuf);//打印出数据
                printf("the sockbuf length is:%d
    ",sreadlen); 
                freadlen = serial_send(thread_arg.fd,sockbuf,sreadlen); 
                printf("send %d bytes!
    ",freadlen);   
                memset(sockbuf, 0, sizeof(sockbuf));
                //pthread_mutex_unlock(&socket_lock);//unlock
                usleep(1);
            }
        }
    }
    
    int main(int argc, char** argv)
    {
        //串口变量定义
        int fd;    
        char str[]="hello linux serial!"; //字符串初始化 
        char serbuf[SER_MAXLINE]; 
        int readlen;
        char dev_path[20];
        
        // socket变量定义     
        int sockfd[SERVER_MAXNUM];//SERVER_MAXNUM
        struct sockaddr_in servaddr[SERVER_MAXNUM];//SERVER_MAXNUM
        unsigned char i;
        unsigned char on_sockfd[SERVER_MAXNUM] = {0};
        on_max = 0;//最大上线个数
        
        //多线程
        pthread_t thread;
        int mret;
        struct argument arg;
        
        //读取配置文件
        unsigned char server_num;//服务器个数初始化
        server_num = read_config(&opt);
        if (opt.enabled != 1)
        {
            printf("do not enable ttl2tcp!
    ");
            exit(-1);
        }
            
        //串口初始化
        if (!snprintf(dev_path,sizeof(dev_path),"/dev/%s",opt.name)
            || (fd = serial_init(dev_path,opt.baudrate,1)) < 0)
        {
            perror("serial init err:");  
            return -1;  
        } 
        memset(serbuf, 0, sizeof(serbuf));
         
        //socket始化
        for (i=0; i<server_num; i++)
        {
            printf("socket init %d/%d
    ",i,server_num);
            if( (sockfd[i] = socket(AF_INET, SOCK_STREAM, 0)) < 0)
            {
                printf("create socket2 error: %s(errno: %d)
    ", strerror(errno),errno);
                exit(0);
            }
            memset(&servaddr[i], 0, sizeof(servaddr[i]));
            servaddr[i].sin_family = AF_INET;
            servaddr[i].sin_port = htons(opt.port[i]);        
            servaddr[i].sin_addr = opt.ipaddr[i];//与配置文件有关,注意配置文件要正确
            
            //if( connect(sockfd[i], (struct sockaddr*)&servaddr[i], sizeof(servaddr[i])) < 0)
            //非阻塞连接10s,如果前一个sockfd没有connect成功,则下次将建立一样的文件描述符号
            if( conn_nonb(sockfd[i], (struct sockaddr*)&servaddr[i], sizeof(servaddr[i]),10) < 0)
            {
                printf("connect error: %s(errno: %d)
    ",strerror(errno),errno);
                continue;
                //exit(0);
            }  
            on_sockfd[on_max++] = i;    
            printf("send msg to server[%d]: %d
    ",i,on_max-1);//on_max-1为上线客户端的新编号            
            //socket发送
            if( send(sockfd[i], str, strlen(str), 0) < 0)
            {
                printf("send msg error: %s(errno: %d)
    ", strerror(errno), errno);
                exit(0);
            }
        }
        //如果没有一个服务器上线
        if (on_max == 0)
        {
            exit(0);
        }
        
        ////pthread_mutex_init(&socket_lock, NULL);
     
        //创建多线程
        arg.fd=fd;
        for    (i=0; i<on_max;i++)
        {
            arg.sockfd[i]=sockfd[on_sockfd[i]];
        }
        mret = pthread_create(&thread, NULL, socket_thread, (void *)(long)&arg);    
        if (mret != 0) 
        { 
            printf("Create thread failed
    "); 
            exit(mret); 
        }
        printf("Create thread
    "); 
                
        //串口转tcp
        while(1)
        {        
            readlen = serial_read(fd,serbuf,SER_MAXLINE,1000);//1s内如果数据没有装满buf,则读取完毕。 如果数据量大,则读取的速度也越快。 
            printf("the serbuf is :%s
    ",serbuf); 
            printf("the serbuf length is :%d
    ",readlen); 
            for    (i=0; i<on_max;i++)
            {
                printf("sockfd[%d]:%d
    ",i,sockfd[on_sockfd[i]]);
                if( send(sockfd[on_sockfd[i]], serbuf, readlen, 0) < 0)//serbuf中有数据可以发送才会执行这条语句
                {
                    printf("send msg error: %s(errno: %d)
    ", strerror(errno), errno);//服务端断掉,则发送失败。
                    exit(0);
                }
            }
            memset(serbuf, 0, sizeof(serbuf));
            sleep(1);
        }
        //退出
        close(fd); 
        for    (i=0; i<server_num;i++)
        close(sockfd[i]);
        exit(0);
    }

    3、 tl2tcpsrcMakefile

    CC = gcc
    CFLAGS = -Wall
    OBJS = ttl2tcp.o
    
    all: ttl2tcp
    
    %.o: %.c
        $(CC) $(CFLAGS) -c -o $@ $< 
    
    ttl2tcp: $(OBJS)
        $(CC) -o $@ $(OBJS) -luci -lpthread
    
    clean:
        rm -f rbcfg *.o

    4、 ttl2tcpfiles tl2tcp.config

    该文件为关于串口和服务器地址及端口的配置文件,在openwrt下的/etc/config文件夹下的ttl2tcp

    package ttl2tcp
    
    config serial device
        #option name ttyUSB0
        #option name ttyS0
        option name ttyATH0
        option baudrate 115200
        option data 8
        option parity None
        option stop 1
        option enabled 1
        
    config server 
        option ipaddr 172.16.1.165
        option port 10001
    
    config server 
        option ipaddr 172.16.1.139
        option port 10001
    
    config server 
        option ipaddr 172.16.1.235
        option port 10001

    5、 ttl2tcpfiles ttl2tcp.init

    该文件为启动脚本,用于编写Luci时,点击save & Apply之后能够调用到该脚本。

    #!/bin/sh /etc/rc.common
    
    START=99
    
    start()
    {
        logger -s -t fqrouter ttl2tcp has started0.
        sleep 2
        ttl2tcp &
        ttl2tcp_pid=$!
        echo "$ttl2tcp_pid" > /tmp/ttl2tcp_temp
        logger -s -t fqrouter ttl2tcp has started $ttl2tcp_pid.
    }
    
    stop()
    {
        read ttl2tcp_pid < /tmp/ttl2tcp_temp
        logger -s -t fqrouter ttl2tcp has stoped0 $ttl2tcp_pid.
        kill -9  $ttl2tcp_pid
        sleep 1
        logger -s -t fqrouter ttl2tcp has stoped.
    }

    6、 将该文件夹ttl2tcp整个拷贝至barrier_breaker/package/utils文件夹下。

    二、Luci配置界面

    Luci的整个工作过程大致是这样的:当设置好配置文件后,点击Save & Apply之后,就会调用/etc/config/ucitrack文件,在该文件中就可以找到该配置文件对应的启动脚本/etc/init.d/ttl2tcp。调用该启动脚本的时候会先执行stop函数,接着执行start函数,保证关闭之前的进程,避免重复打开多个同样进程。

    1、 新建luci-ttl2tcp文件夹,该文件夹目录下的Makefile文件如下,用于中文翻译

    PO = ttl2tcp
    
    include ../../build/config.mk
    include ../../build/module.mk

    2、 luci-ttl2tcpluasrccontroller ttl2tcp.lua

    该文件为注册一个新的Luci模块

    --[[
    LuCI - Lua Configuration Interface
    
    Copyright 2008 Steven Barth <steven@midlink.org>
    Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
    
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    
        http://www.apache.org/licenses/LICENSE-2.0
    
    $Id$
    ]]--
    
    module("luci.controller.ttl2tcp", package.seeall)
    
    function index()
        --entry({"admin", "services", "ttl_client"}, cbi("ttl_client"), _("serial service"),2)  --位置顺序有待考虑    
        entry({"admin", "services", "ttl2tcp"}, cbi("ttl2tcp"), _("Serial Service")) 
    end

    3、 luci-ttl2tcpluasrcmodelcbi ttl2tcp.lua

    该文件为Luci具体页面的实现

    --[[
    LuCI - Lua Configuration Interface
    
    Copyright 2015 tingpan<dktingpan@sina.cn>
    
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    ]]--
    
    local fs  = require "nixio.fs"
    local sys = require "luci.sys"
    local uci = require "luci.model.uci".cursor()
    
    local m = Map("ttl2tcp", translate("Serial Service"))
    local s = m:section( TypedSection, "serial", translate("Serial Configuration"))
    s.addremove = false
    s.anonymous = true --不显示配置文件的名字
    
    s:option(Flag, "enabled", translate("Enabled")) 
    
    name = s:option(Value, "name", translate("Serial")) 
    local device_suggestions = nixio.fs.glob("/dev/tty[A-Z]*")
    if device_suggestions then
        local node
        for node in device_suggestions do
            --name:value(node)
            name:value(string.sub(node,6,string.len(node))) 
        end
    end
    
    baudrate = s:option(Value, "baudrate", translate("Baudrate"))
    baudrate:value("115200", translate("115200"))
    baudrate:value("57600", translate("57600"))
    baudrate:value("38400", translate("38400"))
    baudrate:value("19200", translate("19200"))
    baudrate:value("9600", translate("9600"))
    baudrate:value("4800", translate("4800"))
    baudrate:value("2400", translate("2400"))
    baudrate:value("1200", translate("1200"))
    baudrate:value("300", translate("300"))
    
    local s = m:section( TypedSection, "server", translate("Servers Configuration"))
    s.addremove = false
    s.anonymous = true --不显示配置文件的名字
    --s.template = "cbi/tblsection" 
    s:option(Value, "ipaddr", translate("IPv4 address")) 
    s:option(Value, "port", translate("Port")) 
    
    return m

    4、 luci-ttl2tcp ootetcuci-defaults luci-ttl2tcp

    该文件用于在openwrt中的/etc/config/ucitrack中加入新的关联,只要配置文件变化了,即点击了Save & Apply之后,就会执行/etc/init.d/ttl2tcp脚本文件。

    #!/bin/sh
    
    uci -q batch <<-EOF >/dev/null
        delete ucitrack.@ttl2tcp[-1]
        add ucitrack ttl2tcp
        set ucitrack.@ttl2tcp[-1].init=ttl2tcp
        commit ucitrack
    EOF
    
    rm -f /tmp/luci-indexcache
    exit 0

    5、 luci-ttl2tcpipkg postinst

    #!/bin/sh
    [ -n "${IPKG_INSTROOT}" ] || {
        ( . /etc/uci-defaults/luci-ttl2tcp ) && rm -f /etc/uci-defaults/luci-ttl2tcp
        /etc/init.d/ttl2tcp enabled || /etc/init.d/ttl2tcp enable
        exit 0
    }

    6、 将整个文件夹拷贝至barrier_breaker/feeds/luci/applications文件夹下

    7、 进入barrier_breaker/feeds/luci/po/templates,新建ttl2tcp.pot文件

    msgid ""
    msgstr "Content-Type: text/plain; charset=UTF-8"
    
    msgid "Serial Service"
    msgstr ""
    
    msgid "Serial"
    msgstr ""
    
    msgid "Baudrate"
    msgstr ""
    
    msgid "Servers Configuration"
    msgstr ""

    8、 进入barrier_breaker/feeds/luci/po/zh_CN文件夹,新建ttl2tcp.po

    msgid "Serial Service"
    msgstr "串口服务"
    
    msgid "Serial"
    msgstr "串口"
    
    msgid "Baudrate"
    msgstr "波特率"
    
    msgid "Servers Configuration"
    msgstr "服务器配置"

    9、 在barrier_breaker/feeds/luci/contrib/package/luci-addons的Makefile文件的### Applications ###栏目下,约215行,添加

    $(eval $(call application,ttl2tcp,LuCI Support for serial service,ttl2tcp))

    三、编译

    1、 make menuconfig,在Utils菜单下选中ttl2tcp应用程序,在Luci菜单下的Application子菜单下选中luci-app-ttl2tcp软件包;

    2、 make V=s

    3、 完成之后就可以重新烧写固件,或者单独安装ttl2tcp和luci-app-ttl2tcp软件包。如果单独安装,会提示缺少一些依赖包,只要根据提示安装对应的依赖包就好。

    四、说明

    对应luci-ttl2tcp文件夹,如果在编译了一次之后又更改了里面的内容,此时要把更改后的内容拷贝至barrier_breaker/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/luci-addons所在目录。或者也可以用make clean重新编译。

    五、使用

    vi /etc/inittab

    修改如下:

    ::sysinit:/etc/init.d/rcS S boot
    ::shutdown:/etc/init.d/rcS K shutdown
    #::askconsole:/bin/ash --login

    参考:

    Linux下串口通讯 - Linux设备驱动编程总结_Linux编程_Linux公社-Linux系统门户网站

    非阻塞connect的实现 - The time is passing - ITeye技术网站

    【Linux开发】Linux下的多线程编程 - gnuhpc - 博客园

    请教Luci Save&Apply 如何工作的? - OPENWRT专版 - 恩山WIFI论坛 - Powered by Discuz!

    代码下载:

    http://pan.baidu.com/s/13DIEi

  • 相关阅读:
    斯坦福CS231n—深度学习与计算机视觉----学习笔记 课时10
    斯坦福CS231n—深度学习与计算机视觉----学习笔记 课时8&&9
    斯坦福CS231n—深度学习与计算机视觉----学习笔记 课时7
    斯坦福CS231n—深度学习与计算机视觉----学习笔记 课时6
    sprintf()函数用法
    openssl生成签名与验证签名
    PHP_EOL换行 与 base64编码
    grep配置颜色显示
    curl发送json格式数据
    sublime text3作为php开发IDE
  • 原文地址:https://www.cnblogs.com/smbx-ztbz/p/4555956.html
Copyright © 2011-2022 走看看