Differences

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

Link to this comparison view

sdk:serial-point-to-multipoint [2015/05/06 14:49] (current)
Line 1: Line 1:
 +====== Serial Point to Multipoint ======
 +This script reads messages coming from the local serial port and forwards them via TCP to a all remote host (and vice versa).
 +The local port can be the physical RS-232 (SERIAL1) or a virtual one using a USB adapter (SERIAL2).
 +<code c serial-point-to-multipoint.are>​
 +// DESC: This script reads messages coming from the serial port and forwards them via TCP to a all remote host (and vice versa).
 +// Copyright (C) 2014 NetModule AG
 +//  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 (Only changed if your device has more then one serial Interface (NB3710) */
 +DEV = "​SERIAL1";​
 +
 +/* TCP Options */
 +/* If the script try to connect to a tcp slave, how many retries should it make */
 +RETRY = 3;
 +/* The pause in seconds between the retries*/
 +RETRY_INTERVAL = 3;
 +/* How many seconds should the script wait to run a new set of retries after the client got lost, or the retries were not sucessfull */
 +RECOVER_INTERVAL = 120;
 +
 +
 +//################################################################​
 +//################################################################​
 +//################################################################​
 +/* Only changed things below this line if you know what you are doing */
 +//################################################################​
 +//################################################################​
 +//################################################################​
 +POLL_TIMEOUT = 10;            /* seconds */
 +REMOTE_PORT =2000; ​ /* port of the remote serial slaves 2000 is default on NB Products */ 
 +
 +
 +
 +template slave 
 +{
 +    hostname = "";​
 +    fd = -1;
 +    state = "​down";​
 +    downSince = 0; 
 +
 +
 +    void slave(string remotehost) ​
 +    { 
 +        nb_syslog("​creating slave %s",​remotehost);​
 +        if ( strlen(remotehost) > 0 ) {
 +            this.hostname=remotehost;​
 +        } else {
 +            nb_syslog("​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() {
 +        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("​Could not connect to %s (port %d)", this.hostname,​ REMOTE_PORT);​
 +                nb_syslog("​Retry connect, trial #%i, waiting %s sec", i, RETRY_INTERVAL);​
 +                sleep(RETRY_INTERVAL);​
 +            } else {
 +                nb_syslog("​TCP connection is opened - remote server %s:​%d",​ this.hostname,​ REMOTE_PORT);​
 +                this.fd=sock;​
 +                this.state="​up";​
 +                return 0;
 +            }
 +        }
 +        nb_syslog("​Max retries reached, giving up TCP connection to %s",​this.hostname);  ​
 +        this.downSince=this.jiffy();​
 +        this.state="​down";​
 +        close(this.fd);​
 +        return -1;
 +    }
 +
 +    int disconnect() {
 +        close(this.fd);​
 +        this.fd=-1;
 +        this.state="​down";​
 +        this.downSince=this.jiffy();​
 +        nb_syslog("​Host %s disconnected",​ this.hostname);  ​
 +        return 0;
 +    }
 +
 +
 +} // of template slave
 +
 +void usage()
 +{
 +    nb_syslog("​usage:​ serial-tcp-broadcast.are <​remote-ip-1> ​ <​remote-ip-2>​ .... <​remote-ip-n>"​);​
 +    exit(1);
 +}
 +
 +
 +
 +int start_serial() {
 +
 +    /* check serial port config */
 +    status = nb_config_get("​serial.0.status"​);​
 +    if (status != "​2"​) {
 +        nb_syslog("​Serial port is not enabled for us");
 +        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("​Unable to open serial device (%s)", DEV);
 +        exit(1);
 +    }
 +
 +    return fd;
 +}
 +
 +int stop_serial() {
 +
 +close(fd);
 +return 0; 
 +}
 +
 +
 +
 +
 +// ###################################################​
 +// ###################################################​
 +// ########​Begining of Program########################​
 +// ###################################################​
 +// ###################################################​
 +// ###################################################​
 +
 +/* check arguments */
 +if (strlen(argv[1]) == 0) {
 +    nb_syslog("​ERROR:​ no remote host specified"​);​
 +    usage();
 +}
 +
 +/* create slave host list and set  */
 +
 +
 +nb_syslog("​creating slaves"​);​
 +for (i=1; i < argc; i++) {
 +    slaves[i-1] = new slave(argv[i]);​
 +}
 +// connect to slave
 +//for ( i=0; i < length(slaves);​ i++) {
 +for ( i=0; i < length(slaves);​ i++) {
 +     ​nb_syslog("​connect to slave %i",​i);​
 +    rc = slaves[i].connect();​
 +    if (rc < 0) {
 +    nb_syslog("​could not create socket %s", slaves[i].hostname); ​  
 +    }
 +}
 +
 +nb_syslog("​starting serial"​);​
 +serial_fd = start_serial();​
 +
 +
 +
 +// Creating tcp fd array for select()
 +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);
 +
 +
 +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 is gone lets set the slave correctly"​);​
 +            for ( i=0; i < length(slaves);​ i++) {
 +                if (rc == slaves[i].fd) {
 +                /* lets put the socket on disable */
 +                    slaves[i].disconnect(); ​  
 +                }
 +            }
 +
 +        }
 +     }
 +
 +
 +    /* check serial buffer and send message */
 +    len = strlen(serialbuffer);​
 +    // we have data for the slaves lets sent it
 +    msg = serialbuffer;​
 +    msglen = len;
 +    serialbuffer = "";​
 +
 +    /* send TCP packet to every socket */
 +    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("​failed sending to host: %s fd: %i",​slaves[i].hostname,​slaves[i].fd);​
 +                    /* lets put the socket on disable */
 +                    slaves[i].disconnect(); ​  
 +                }
 +            }
 +        }
 +    }
 +    /* check if we have a error on the soocket */
 +    for ( i=0; i < length(slaves);​ i++) {
 +        if (slaves[i].state == "​up"​ ) {
 +            sockop=getsockopt(slaves[i].fd,​ SOL_SOCKET, 4);
 +            if (sockop != 0) {
 +               ​nb_syslog("​Error No %i on slave %s, Set Slave offline and try reconnect again",​ sockop, slaves[i].hostname);​
 +               ​slaves[i].disconnect();​
 +            }
 +        }
 +    }
 +
 +
 +    // reconnect to lost slaves ​   ​
 +    for ( i=0; i < length(slaves);​ i++) {
 +        if (slaves[i].state == "​down"​ ) {
 +            if ( (slaves[i].downSince + RECOVER_INTERVAL) < slaves[i].jiffy() ) {
 +              slaves[i].connect();​
 +            }
 +        }
 +    }
 +
 +    // recreate online fds
 +    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>​
 +