This shows you the differences between two versions of the page.
sdk:serial-point-to-multipoint [2015/05/06 12:49] |
sdk:serial-point-to-multipoint [2015/05/06 12: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> | ||
+ | |||