no way to compare when less than two revisions

Differences

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


Last revision
sdk:scripts:serial-tcp-broadcast [2015/05/05 15:04] – external edit 127.0.0.1
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>