Differences

This shows you the differences between two versions of the page.

Link to this comparison view

sdk:scripts:serial-tcp-broadcast [2015/05/05 17:04] (current)
Line 1: Line 1:
 +====== SDK Script serial-tcp-broadcast.are ======
 +<code c serial-tcp-broadcast.are>​
 +/* DESC: This script reads messages coming from the serial port and forwards them via TCP to remote hosts (and vice versa).
 + * Copyright (C) 2014 NetModule AG, Switzerland
 + *
 + * Usage: usage: serial-tcp-broadcast.are <​remote-ip-1> ​ <​remote-ip-2>​ .... <​remote-ip-n>"​
 + * Version: 2.0
 + *
 + */
 +
 +/* 
 + * Options to configure by user
 + */
 +
 +/* Serial Baud Rate 9600, 19200, 38400, 57600, 115200 */
 +SER_SPEED = 115200;
 +/*  number of data bits (5, 6, 7, 8) */
 +SER_DATABIT = 8;
 +/*  number of stop bits (1, 2) */
 +SER_STOPBIT = 1;
 +/* parity (0=no parity, 1=odd parity, 2=even parity) */
 +SER_PARITY = 0;
 +/*  flow control (0=none, 1=xon/xoff, 2=hardware) */
 +SER_FLOW = 0;
 +/*  name of the Serial Interface */
 +DEV = "​SERIAL1";​
 +DEVIDX = ((int) substr(DEV, 6, 1)) - 1;
 +
 +/* TCP Options */
 +/* number of retries when connecting to a slave */
 +RETRY = 3;
 +/* the interval in seconds for each retry */
 +RETRY_INTERVAL = 3;
 +/* recovery interval after slave got disconnected or retries were unsuccessful */
 +RECOVER_INTERVAL = 120;
 +
 +
 +/* 
 + * Only changed things below if you know what you are doing 
 + */
 +
 +POLL_TIMEOUT = 10;  /* seconds */
 +REMOTE_PORT =2000; ​ /* port of the remote serial slaves (default 2000) */ 
 +
 +/* slave template */
 +template slave 
 +{
 +    hostname = "";​
 +    fd = -1;
 +    state = "​down";​
 +    since = 0; 
 +
 +    void slave(string remotehost) ​
 +    { 
 +        nb_syslog("​Creating slave %s",​remotehost);​
 +        if (strlen(remotehost) > 0) {
 +            this.hostname = remotehost;
 +        } else {
 +            nb_syslog("​ERROR:​ no hostname defined, slave could not be created"​);​
 +        }
 +    }
 +
 +    int jiffy()
 +    {
 +        sys = sysinfo();
 +        u = struct_get(sys,​ "​uptime"​);​
 +
 +        if (is_void(u) || u < 1) {
 +            return 0;
 +        } else {
 +            return u;
 +        }
 +    } 
 +
 +    int connect() {
 +        if (this.fd > -1) {
 +            close(this.fd);​
 +            this.fd = -1;
 +        }
 +        nb_syslog("​Connecting to %s", this.hostname);​
 +
 +        /* open TCP socket */
 +        sock = socket(AF_INET,​ SOCK_STREAM,​ IPPROTO_TCP);​
 +        setsockopt(sock,​ SOL_SOCKET, SO_KEEPALIVE,​1);​
 +        setsockopt(sock,​ SOL_TCP, TCP_KEEPIDLE,​1);​
 +        setsockopt(sock,​ SOL_TCP, TCP_KEEPINTVL,​5);​
 +        setsockopt(sock,​ SOL_TCP, TCP_KEEPCNT,​5);​
 +
 +        if (sock < 0) {
 +            nb_syslog("​ERROR:​ unable to open socket"​);​
 +        }
 +        for (i = 0; i < RETRY; i++) {
 +            if (connect(sock,​ this.hostname,​ REMOTE_PORT) < 0){
 +                nb_syslog("​ERROR:​ could not connect to %s:​%d",​ this.hostname,​ REMOTE_PORT);​
 +                nb_syslog("​Retrying to connect (trial #%i, waiting %s sec)", i, RETRY_INTERVAL);​
 +                sleep(RETRY_INTERVAL);​
 +            } else {
 +                nb_syslog("​TCP connection established to host %s:​%d",​ this.hostname,​ REMOTE_PORT);​
 +                this.fd = sock;
 +                this.state = "​up";​
 +                return 0;
 +            }
 +        }
 +        nb_syslog("​ERROR: ​ max. retries reached for %s, giving up", this.hostname);  ​
 +        this.since = this.jiffy();​
 +        this.state = "​down";​
 +        close(this.fd);​
 +        this.fd = -1;
 +
 +        return -1;
 +    }
 +
 +    int disconnect() {
 +        if (this.fd > -1) {
 +            close(this.fd);​
 +            this.fd = -1;
 +        }
 +        this.state = "​down";​
 +        this.since = this.jiffy();​
 +        nb_syslog("​Disconnected host %s", this.hostname);  ​
 +        return 0;
 +    }
 +
 +
 +} /* endof template slave */
 +
 +int start_serial() ​
 +{
 +    /* check serial port config */
 +    status = nb_config_get(sprintf("​serial.%d.status",​ DEVIDX));
 +    if (status != "​2"​) {
 +        nb_syslog("​ERROR:​ serial port %d is not enabled for us", DEVIDX);
 +        exit(1);
 +    }
 +
 +    /* set attributes */
 +    rc = nb_serial_setattr(DEV,​ SER_SPEED, SER_DATABIT,​ SER_STOPBIT,​ SER_PARITY, SER_FLOW);
 +    if (rc != 0) {
 +        nb_syslog("​ERROR:​ unable to set serial attributes (rc %d)", rc);
 +        exit(1);
 +    }
 +
 +    /* open serial port */
 +    fd = nb_serial_open(DEV);​
 +    if (fd < 0) {
 +        nb_syslog("​ERROR:​ unable to open serial device (%s)", DEV);
 +        exit(1);
 +    }
 +
 +    return fd;
 +}
 +
 +int stop_serial() ​
 +{
 +    if (fd > -1) {
 +        close(fd);
 +        fd = -1;
 +    }
 +    return 0; 
 +}
 +
 +void usage()
 +{
 +    nb_syslog("​usage:​ serial-tcp-broadcast.are <​remote-ip-1> ​ <​remote-ip-2>​ .... <​remote-ip-n>"​);​
 +    exit(1);
 +}
 +
 +
 +/* ------------------------ main ------------------------------- */
 +
 +
 +if (strlen(argv[1]) == 0) {
 +    nb_syslog("​ERROR:​ no remote host specified"​);​
 +    usage();
 +}
 +
 +/* create slaves */
 +nb_syslog("​creating slaves"​);​
 +for (i = 1; i < argc; i++) {
 +    slaves[i-1] = new slave(argv[i]);​
 +}
 +
 +/* connect slave */
 +for (i = 0; i < length(slaves);​ i++) {
 +    nb_syslog("​connecting slave %d", i);
 +    rc = slaves[i].connect();​
 +    if (rc < 0) {
 +        nb_syslog("​ERROR:​ could not connect %s", slaves[i].hostname); ​  
 +    }
 +}
 +
 +nb_syslog("​starting serial"​);​
 +serial_fd = start_serial();​
 +
 +/* create file descriptor array */
 +fds = mkarray();
 +tcp_fds = mkarray();
 +j = 0;
 +for (i = 0; i < length(slaves);​ i++) {
 +     if (slaves[i].state == "​up"​) {
 +        tcp_fds[j] = slaves[i].fd;​
 +        j++;   
 +    }
 +}
 +fds = array_merge(serial_fd,​ tcp_fds);
 +
 +
 +/* loop infinitely */
 +while (1) {
 +    buffer = "";​
 +    rc = select(fds, POLL_TIMEOUT);​
 +    if (rc == -1) {
 +        nb_syslog("​ERROR:​ select failed"​);​
 +    } else if (rc == serial_fd) {
 +        /* received something from serial device */
 +        data = read(serial_fd,​ 4096);
 +        if (data) {
 +            serialbuffer = strcat(serialbuffer,​ data);
 +            nb_syslog("​data on serial port: %s",​serialBuffer);​
 +        }
 +    } else if (rc != 0 && array_search(tcp_fds,​ rc) != NULL) {
 +        /* received something from TCP */
 +        data = recv(rc);
 +        len=strlen(data);​
 +        if (len > 0) {
 +            /* write to serial device */
 +            write(serial_fd,​ data, len);
 +        } else if(len == 0) {
 +            //​nb_syslog("​tcp connection lost, reconnecting"​);​
 +            for (i = 0; i < length(slaves);​ i++) {
 +                if (rc == slaves[i].fd) {
 +                    /* disconnect */
 +                    slaves[i].disconnect(); ​  
 +                }
 +            }
 +        }
 +    }
 +
 +
 +    /* check serial buffer and send message */
 +    len = strlen(serialbuffer);​
 +    msg = serialbuffer;​
 +    msglen = len;
 +    serialbuffer = "";​
 +
 +    /* send TCP packet to every slave */
 +    if (len > 0) {
 +        for (i = 0; i < length(slaves);​ i++) {
 +            if (slaves[i].state == "​up"​ ) {
 +                sent = send(slaves[i].fd,​ msg);
 +                if (sent == -1) {
 +                    nb_syslog("​ERROR:​ failed to send packet to %s", slaves[i].hostname);​
 +                    /* disconnect slave */
 +                    slaves[i].disconnect(); ​  
 +                }
 +            }
 +        }
 +    }
 +    /* check if we have an error on the socket */
 +    for (i = 0; i < length(slaves);​ i++) {
 +        if (slaves[i].state == "​up"​ ) {
 +            opt = getsockopt(slaves[i].fd,​ SOL_SOCKET, 4);
 +            if (opt != 0) {
 +               ​nb_syslog("​ERROR:​ getsockopt(%d) on slave %s failed, reconnecting",​ opt, slaves[i].hostname);​
 +               ​slaves[i].disconnect();​
 +            }
 +        }
 +    }
 +
 +    /* reconnect to disconnected slaves */
 +    for ( i=0; i < length(slaves);​ i++) {
 +        if (slaves[i].state == "​down"​ ) {
 +            if ( (slaves[i].since + RECOVER_INTERVAL) < slaves[i].jiffy() ) {
 +              slaves[i].connect();​
 +            }
 +        }
 +    }
 +
 +    /* re-create file descriptor array */
 +    fds = mkarray();
 +    tcp_fds = mkarray();
 +    j = 0;
 +    for (i = 0; i < length(slaves);​ i++) {
 +         if (slaves[i].state == "​up"​) {
 +             ​tcp_fds[j] = slaves[i].fd;​
 +             j++;
 +        }
 +    }
 +    fds = array_merge(serial_fd,​ tcp_fds);
 +}
 +
 +exit(0);
 +
 +
 +</​code>​