diff --git a/firmware/BRIDGE-PROTOCOL b/firmware/BRIDGE-PROTOCOL index 4e8a6c6..9f0fcb4 100644 --- a/firmware/BRIDGE-PROTOCOL +++ b/firmware/BRIDGE-PROTOCOL @@ -8,12 +8,17 @@ r->h: \2\0 Settings: h->r:\3\0 r->h: \2\0 + h->r:\4\0 r->h: \2\0 + h->r:\5\0 r->h: \2\0 -h->r:\6\0 + +h->r:\6\0 r->h: \2\0 + h->r:\7\0 r->h: \7\0 +r->h: \2\0 diff --git a/firmware/applications/bridge.c b/firmware/applications/bridge.c index c3b1b98..db1b3e1 100644 --- a/firmware/applications/bridge.c +++ b/firmware/applications/bridge.c @@ -60,6 +60,8 @@ void main_bridge(void) GLOBAL(lcdbacklight)=10; GLOBAL(privacy) = 3; char input[64]; + char led1=0; + char led2=0; usbCDCInit(); delayms(500); @@ -71,6 +73,7 @@ void main_bridge(void) int l, i, status; CDC_OutBufAvailChar (&l); if(l>0){ + gpioSetValue (RB_LED0, led1);led1=1-led1; CDC_RdOutBuf (input, &l); for(i=0; i 0 ){ + gpioSetValue (RB_LED2, led2);led2=1-led2; puts("\\1"); dump_encoded(len, buf); puts("\\0"); diff --git a/firmware/l0dable/files/fahrplan.scd b/firmware/l0dable/files/fahrplan.scd index 287c261..ef5a97f 100644 Binary files a/firmware/l0dable/files/fahrplan.scd and b/firmware/l0dable/files/fahrplan.scd differ diff --git a/tools/mesh/lib/r0ket.pm b/tools/mesh/lib/r0ket.pm index 013630f..33ea8c5 100755 --- a/tools/mesh/lib/r0ket.pm +++ b/tools/mesh/lib/r0ket.pm @@ -4,11 +4,12 @@ use strict; -use IO::Select; package r0ket; +use IO::Select; +use Socket; use Digest::CRC qw(crcccitt); -use POSIX qw(strftime VTIME VMIN TCSANOW); +use POSIX qw(strftime :termios_h); use Time::HiRes; our $verbose=0; @@ -98,14 +99,16 @@ sub writebeacon{ ### Packet mgmt -our $buffer; +my $buffer; our $firstpkt=1; sub get_data{ my $filter=shift||0; my $rin=''; # Select vector + my $ein=''; # Select vector my ($rout,$eout); vec($rin,fileno($bridge),1) = 1; + vec($ein,fileno($bridge),1) = 1; while(1){ @@ -118,6 +121,7 @@ sub get_data{ }elsif($filter==$type){ return $str; }; + print "got a 2: ",length($str)," $str \n" if ($type==2); next; # If rejected, look for next packet. }; @@ -132,9 +136,8 @@ sub get_data{ redo; # Try parsing the rest. }; }; - my ($nfound,$timeleft) = - select($rout=$rin, undef, $eout=$rin, 1); + select($rout=$rin, undef, $eout=$ein, 1); if($nfound==0){ if($filter==0){ return (0,''); @@ -142,17 +145,18 @@ sub get_data{ print STDERR "No packets for 1 second...\n"; }; }; - if($eout eq $rin){ + if($eout eq $ein){ # Doesn't get triggered? die "Error on bridge socket: $!\n"; }; if($rout eq $rin){ - my $rr; + my $rr=""; sysread($bridge,$rr,1024); # print "len=",length($rr),"\n"; $buffer.=$rr; + die "Nothing to read?" if(length($rr)==0); # Probably device gone. +# print "recv: ",unpack("H*",$rr),"\n"; }; -# print "recv: ",unpack("H*",$rr),"\n"; }; }; @@ -330,6 +334,25 @@ sub r0ket_init{ $ser=$ENV{R0KETBRIDGE} }; }; +if($ser =~ /:/){ + my ($remote, $port, $iaddr, $paddr, $proto, $line); + + $ser =~ /(.*):(.*)/; + $remote = $1; + $port = $2; + $iaddr = inet_aton($remote) || die "no host: $remote"; + $paddr = sockaddr_in($port, $iaddr); + + $proto = getprotobyname("tcp"); + use Fcntl; + socket($bridge, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; + connect($bridge, $paddr) || die "connect: $!"; + + my $old_flags = fcntl($bridge, F_GETFL, 0) + or die "can't get flags: $!"; + fcntl($bridge, F_SETFL, $old_flags | O_NONBLOCK) + or die "can't set non blocking: $!"; +}else{ if(!defined $ser){ do {$ser=$_ if ( -e $_ ) } for qw(/dev/ttyACM0); }; @@ -343,7 +366,9 @@ sub r0ket_init{ $term->getattr(fileno($bridge)); $term->setcc(VTIME,1); $term->setcc(VMIN,0); + $term->setcc(ECHO,0); $term->setattr(fileno($bridge),TCSANOW); +}; #empty buffer, in case there is old data my $dummy; @@ -389,7 +414,7 @@ sub set_rxlen { }; sub get_id { send_pkt_num("",7); - my $id=get_data(7); + my $id=unpack("H*",get_data(7)); wait_ok(1); return $id; }; diff --git a/tools/mesh/rf b/tools/mesh/rf index e0695d9..bb0029c 100755 --- a/tools/mesh/rf +++ b/tools/mesh/rf @@ -73,6 +73,17 @@ $r0ket::verbose=1; my @fh; my $read; +my @args=@ARGV; +my $sidx=0; +for my $eidx (0..$#args){ + if($args[$eidx] eq ","){ + dwim(@args[$sidx..$eidx-1]); + $sidx=$eidx+1; + } +}; +dwim(@args[$sidx..$#args]); + +sub dwim{ my $cmd=shift; if($cmd =~ /^r/){ @@ -170,7 +181,7 @@ if($cmd =~ /^r/){ r0ket::set_rxlen(shift); }elsif ($set =~ /^id/){ my $id=r0ket::get_id(); - print "r0ket id: ",r0ket::hprint($id),"\n"; + print "r0ket id: ",$id,"\n"; }else{ die "Unknown config argument $set\n"; }; @@ -271,6 +282,7 @@ if($cmd =~ /^r/){ }else{ die "Option not understood\n"; }; +}; #if (@fh = $sel->can_read(10)) { # sysread($fh[0],$read,1024); diff --git a/tools/reader/Makefile b/tools/reader/Makefile new file mode 100644 index 0000000..a5281de --- /dev/null +++ b/tools/reader/Makefile @@ -0,0 +1,33 @@ +ifneq "$(TUPLE)" "" +PREFIX=$(TUPLE)- +ARCH=$(shell echo $(TUPLE)|sed 's/-.*//') +else +PREFIX= +ARCH=$(shell uname -m) +endif + +CC = $(PREFIX)gcc +STRIP = $(PREFIX)strip + +CFLAGS = -Wall -O2 +EXE = obreader +FILES = obreader.c + +$(ARCH)-$(EXE): $(FILES) + $(CC) $(CFLAGS) -o $@ $(FILES) + $(STRIP) $@ + + +# Using OpenWRT crossbuild environment, see +# +# for setup instructions. +WRT=~/r0ket/openwrt/trunk/staging_dir +STAGING_DIR=$(WRT)/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2 + +mips: + STAGING_DIR=$(STAGING_DIR) \ + PATH=${PATH}:$(STAGING_DIR)/bin \ + $(MAKE) TUPLE=mips-openwrt-linux + +clean: + rm -f *-$(EXE) diff --git a/tools/mesh/beacon-udp.pl b/tools/reader/beacon-udp.pl similarity index 96% rename from tools/mesh/beacon-udp.pl rename to tools/reader/beacon-udp.pl index c54e869..57bd0f0 100755 --- a/tools/mesh/beacon-udp.pl +++ b/tools/reader/beacon-udp.pl @@ -10,6 +10,7 @@ use Digest::CRC qw(crcccitt); use FindBin; use lib "$FindBin::Bin/lib"; +use lib "$FindBin::Bin/../mesh/lib"; use r0ket; $|=1; @@ -162,14 +163,15 @@ while(1){ if(length($pkt) != 16){ # Sanity check $errors++; + print STDERR "Length check\n"; next; }; $ctr++; my $idoff=0; - if(substr($pkt,12,1) eq "\xee"){ - $idoff=1000; - }; +# if(substr($pkt,12,1) eq "\xee"){ +# $idoff=1000; +# }; my $hdr= pack("CCnnNN", 1, # proto (BEACONLOG_SIGHTING) @@ -198,8 +200,8 @@ while(1){ }else{ $typeunknown++; }; - if($idoff){ - $typeunknown++; - }; +# if($idoff){ +# $typeunknown++; +# }; }; r0ket::rest(); diff --git a/tools/reader/listen-log.pl b/tools/reader/listen-log.pl new file mode 100755 index 0000000..367e997 --- /dev/null +++ b/tools/reader/listen-log.pl @@ -0,0 +1,33 @@ +#!/usr/bin/perl +# +# vim:set ts=4 sw=4: + +use strict; +use warnings; +use Socket; + +our $port=514; +my $hispaddr; + +my $socket; + +my($iaddr,$proto,$paddr); +$iaddr = pack('C4', 0,0,0,0); +$proto = getprotobyname('udp'); +$paddr = sockaddr_in($port, $iaddr); # 0 means let kernel pick + +socket($socket, PF_INET, SOCK_DGRAM, $proto) || die "socket: $!"; +bind($socket, $paddr) || die "bind: $!"; + +my ($hisiaddr,$host); +my $buf; +while (1){ + $hispaddr = recv($socket, $buf, 2048, 0) || die "recv: $!"; + ($port, $hisiaddr) = sockaddr_in($hispaddr); +# $host = gethostbyaddr($hisiaddr, AF_INET); + $host=join(".",unpack("CCCC",$hisiaddr)); + chomp($buf); + $buf =~ y!a-zA-Z0-9.:,; _()[]{}<>/?-!!cd; + print substr(scalar(localtime),11,8)," ",$host," ",$buf,"\n"; +}; + diff --git a/tools/reader/netlink-notifier.pl b/tools/reader/netlink-notifier.pl new file mode 100755 index 0000000..61fe08b --- /dev/null +++ b/tools/reader/netlink-notifier.pl @@ -0,0 +1,79 @@ +#!/usr/bin/perl +# +# vim:set ts=4 sw=4: + +use strict; +use POSIX; +use Socket; + +use FindBin; +use lib "$FindBin::Bin/lib"; +use l0gger; + +l0gger::init(); + + +use constant AF_NETLINK => 16; +#use Socket::Netlink; + +# Netlink setup +socket my $sock,AF_NETLINK,SOCK_RAW,0 #(domain, type, bus//protocol) + or die "socket: $!\n"; +bind $sock, pack("vvVV",AF_NETLINK,0,0,1) #(domain, zero , pid, group); + or die "bind: $!\n"; + +while(1){ + sysread($sock,my $msg, 65535) or die "recv: $!"; + my ($ifname,$state)=(undef,undef); + +# print unpack("H*",substr($message,0,16)),"\n"; # ifi_type etc. + $msg=substr($msg,16); + + my (undef,undef,undef,undef,undef,$type)=unpack("nnnnCC",$msg); + $msg=substr($msg,16); +# print "Type=$type\n"; + next if($type!=16); # RTM_NEWLINK + + while(length($msg)){ + my($len,$type)=unpack("vv",$msg); +# print "len= $len,type=$type\n"; + last if($len<4); + + $msg=substr($msg,4); + if ($type == 3){ # IFLA_IFNAME + $ifname=unpack("Z*",$msg); + }elsif($type == 16){ # IFLA_OPERSTATE + $state=unpack("v",$msg); + }else{ +# print "content=",unpack("H*",substr($msg,0,$len-4)),"\n"; + }; + + $len=(int(($len-1)/4))*4; # 4-byte alignment + $msg=substr($msg,$len); + }; + next if(!defined($ifname) || !defined($state)); +# print "ifname=$ifname, state=$state\n"; +# IF_OPER_UNKNOWN (0): +# Interface is in unknown state, neither driver nor userspace has set +# operational state. Interface must be considered for user data as +# setting operational state has not been implemented in every driver. +# IF_OPER_NOTPRESENT (1): +# Unused in current kernel (notpresent interfaces normally disappear), +# just a numerical placeholder. +# IF_OPER_DOWN (2): +# Interface is unable to transfer data on L1, f.e. ethernet is not +# plugged or interface is ADMIN down. +# IF_OPER_LOWERLAYERDOWN (3): +# Interfaces stacked on an interface that is IF_OPER_DOWN show this +# state (f.e. VLAN). +# IF_OPER_TESTING (4): +# Unused in current kernel. +# IF_OPER_DORMANT (5): +# Interface is L1 up, but waiting for an external event, f.e. for a +# protocol to establish. (802.1X) +# IF_OPER_UP (6): +# Interface is operational up and can be used. + if($state==6){ + l0gger::send("$ifname up"); + }; +} diff --git a/tools/reader/obreader.c b/tools/reader/obreader.c new file mode 100644 index 0000000..542d1a4 --- /dev/null +++ b/tools/reader/obreader.c @@ -0,0 +1,514 @@ +/* obreader.c by Sec + * vim:set cin sm ts=4: + * + * Do whatever you want with this code, but give credit + * + * This program reads packets from an USB-Serial R0ket + * and sends them off via TCP/UDP to a central host + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INTERVAL 1 + +#define BUFSIZE 100 +#define PORT 2342 +char *SRV_IP="127.0.0.1"; + +#define TYPE_UDP +#undef TYPE_TCP + +/* rotating buffer */ +#define ELEMSIZE 32 +unsigned int bufstart=0,bufend=0; /* rotating buffer */ +#define BUFIDX(a) (a*ELEMSIZE) +#define BUFPUSH() do{ bufend++; if(bufend==BUFSIZE){ bufend=0; }; if(bufend==bufstart){ BUFPOP();}; }while(0) +#define BUFPOP() do{ bufstart++; if(bufstart==BUFSIZE){ bufstart=0; }; }while(0) +unsigned char buffer[BUFIDX(BUFSIZE)]; + +time_t the_time; + +static u_int16_t +crc16 (const unsigned char *buffer, int size) +{ + u_int16_t crc = 0xFFFF; + + if (buffer && size) + while (size--) + { + crc = (crc >> 8) | (crc << 8); + crc ^= *buffer++; + crc ^= ((unsigned char) crc) >> 4; + crc ^= crc << 12; + crc ^= (crc & 0xFF) << 5; + } + + return crc; +} + +void setnonblocking(int fd) { + int opts; + + opts = fcntl(fd,F_GETFL); + if (opts < 0) { + perror("fcntl(F_GETFL)"); + exit(EXIT_FAILURE); + } + opts = (opts | O_NONBLOCK); + if (fcntl(fd,F_SETFL,opts) < 0) { + perror("fcntl(F_SETFL)"); + exit(EXIT_FAILURE); + } + return; +} + +void setupserial(int fd){ + struct termios config; + + if(!isatty(fd)) { + fprintf(stderr,"fd %d is not a tty?",fd); + exit(EXIT_FAILURE); + }; + if(tcgetattr(fd, &config) < 0) { + perror("tcgetattr"); + exit(EXIT_FAILURE); + }; + // + // Input flags - Turn off input processing + // convert break to null byte, no CR to NL translation, + // no NL to CR translation, don't mark parity errors or breaks + // no input parity check, don't strip high bit off, + // no XON/XOFF software flow control + // + config.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | + INLCR | PARMRK | INPCK | ISTRIP | IXON); + // + // Output flags - Turn off output processing + // no CR to NL translation, no NL to CR-NL translation, + // no NL to CR translation, no column 0 CR suppression, + // no Ctrl-D suppression, no fill characters, no case mapping, + // no local output processing + // + // config.c_oflag &= ~(OCRNL | ONLCR | ONLRET | + // ONOCR | ONOEOT| OFILL | OLCUC | OPOST); + config.c_oflag = 0; + // + // No line processing: + // echo off, echo newline off, canonical mode off, + // extended input processing off, signal chars off + // + config.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); + // + // Turn off character processing + // clear current char size mask, no parity checking, + // no output processing, force 8 bit input + // + config.c_cflag &= ~(CSIZE | PARENB); + config.c_cflag |= CS8; + // + // One input byte is enough to return from read() + // Inter-character timer off + // + config.c_cc[VMIN] = 1; + config.c_cc[VTIME] = 0; + // + // Communication speed (simple version, using the predefined + // constants) + // + /* + if(cfsetispeed(&config, B9600) < 0 || cfsetospeed(&config, B9600) < 0) { + perror("cfset[io]speed"); + exit(EXIT_FAILURE); + } + */ + // + // Finally, apply the configuration + // + if(tcsetattr(fd, TCSAFLUSH, &config) < 0) { + perror("tcsetattr"); + exit(EXIT_FAILURE); + }; +}; + +/* Reference is https://r0ket.badge.events.ccc.de/tracking:reader */ +void pkt_cleanup(int idx){ + static u_int32_t ctr; + + buffer[BUFIDX(idx)+2]=1; // BEACONLOG_SIGHTING + buffer[BUFIDX(idx)+3]=0; // interface 0 + *(u_int16_t*)(buffer+BUFIDX(idx)+4)=htons(1234); // reader id + *(u_int16_t*)(buffer+BUFIDX(idx)+6)=htons(32); // size + *(u_int32_t*)(buffer+BUFIDX(idx)+8)=htonl(ctr++); + *(u_int32_t*)(buffer+BUFIDX(idx)+12)=htonl(the_time); + + *(u_int16_t*)(buffer+BUFIDX(idx)+0)=htons(0xffff ^ crc16(buffer+BUFIDX(idx)+2,30)); +} + +void write_r0ket(int fd,char * buf,int len){ + int r; + r=write(fd,buf,len); + if(r!=len){ + printf("wrote only %d bytes of %d to device\n",r,len); + exit(EXIT_FAILURE); + }; +} + +void setup_r0ket(int fd){ + unsigned char buf[256]; + int x,r; + u_int32_t uuid=0; + + write_r0ket(fd,"\\7\\0",4); /* Get UUID */ + write_r0ket(fd,"\\4\001\002\003\002\001\\0",9); /* Set rx_mac */ + write_r0ket(fd,"\\5\x51\\0",5); /* Set channel */ + write_r0ket(fd,"\\6\x10\\0",5); /* Set rx_len */ + + usleep(100000); /* wait 100ms for an answer */ + r=read(fd,buf,sizeof(buf)); + /* try to find uuid in reply. Could be nicer, but it works. */ + if(r>7){ + for(x=0;x0){ + if(!firstread) + printf("ignoring garbage: %02X\n",data[0]); + memmove(data,data+1,sizeof(data)-1); + r--; + }; + if(r==0){ /* no data left */ + return 0; + }; + + if(data[1]=='1'){ + firstread=0; + /* find frame end */ + for(x=2;x=r-1){ /* no EOF found */ + if(r>60){ + printf("serial frame content overflow\n"); + return 0; + }; + offset=r; /* keep unused data for next round */ + return 0; + }; + +// printf("consume %d: ",x); + o=16; + BUFPUSH(); + for(t=2;t=ELEMSIZE) /* "buffer" overflow protection */ + break; + buffer[BUFIDX(bufend)+o]=data[t]; + if(data[t]!='\\') + o++; +// printf("%02x",data[t]); + }; + pkt_cleanup(bufend); + x+=2; /* also consume end of frame marker */ +// printf("\n"); + }else if(data[1]=='7'){ /* beaconid frame */ + /* find frame end */ + for(x=2;x=r-1){ /* no EOF found */ + if(r>60){ + printf("serial frame content overflow\n"); + return 0; + }; + offset=r; /* keep unused data for next round */ + return 0; + }; + /* XXX: do something with beaconid */ + BUFPUSH(); + for(t=0;t<16;t++){ /* clear buffer */ + buffer[BUFIDX(bufend)+16+t]=0; + }; + buffer[BUFIDX(bufend)+16]=22; // RFBPROTO_READER_ANNOUNCE + *(u_int16_t*)(buffer+BUFIDX(bufend)+16+14)= \ + htons(crc16(buffer+BUFIDX(bufend)+16,14)); + pkt_cleanup(bufend); + x=8; + }else if(data[1]=='2'){ /* command ack frame */ + x=4; /* just consume, and do nothing */ + }else{ + if(!firstread) + printf("invalid frame type: %02x\n",data[1]); + x=2; + }; + if(x==r) /* all data consumed */ + return 0; + /* keep unconsumed data */ + memmove(data,data+x,r-x); + offset=r-x; + return 0; +} + +void write_socket(int sockfd){ + BUFPOP(); + if (send(sockfd, buffer+BUFIDX(bufstart), ELEMSIZE, 0)==-1){ + perror("send"); +// exit(EXIT_FAILURE); + }; +} + +int main(int argc, char ** argv){ + int c; /* getopt return value */ + char *device="/dev/ttyACM0"; + int devfd=-1,sockfd=-1,listenfd=-1; /* FD for device & socket */ + int maxfd=0; + int cnt; + fd_set rset,wset; /* file descriptors for select() */ + struct timeval timeout; /* Timeout for select */ + struct sockaddr_in si_other; /* target socket */ + time_t ot,heartbeat=0; + + time(&ot); + + /* The big getopt loop */ + while ((c = getopt(argc, argv, "s:d:")) != EOF) + switch (c) + { + case 'd': + device=(char *)malloc(strlen(optarg)+2); + strcpy(device,optarg); + break; + + case 's': + SRV_IP=(char *)malloc(strlen(optarg)+2); + strcpy(SRV_IP,optarg); + break; + + default: + fprintf(stderr, "Usage: %s [options] \n\n\ +This program reads packets from an USB-Serial R0ket\n\ +and sends them off via TCP/UDP to a central host\n\n\ + -d Open a different device instead of '%s'\n\ + -h This help\n", + argv[0], + device + ); + exit(255); + } + +/* argc -= optind; argv += optind; *//* only if we want more args */ + + /* Open & prep input device */ + if((devfd=open(device,O_RDWR)) == -1){ + perror("open(device)"); + exit(EXIT_FAILURE); + }; + setupserial(devfd); + setnonblocking(devfd); + setup_r0ket(devfd); + + /* Open & prep outout device */ +#ifdef TYPE_UDP + if ((sockfd=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1){ + perror("socket(udp)"); + exit(EXIT_FAILURE); + }; + memset((char *) &si_other, 0, sizeof(si_other)); + si_other.sin_family = AF_INET; + si_other.sin_port = htons(PORT); + if (inet_aton(SRV_IP, &si_other.sin_addr)==0) { + perror("inet_aton()"); + exit(EXIT_FAILURE); + } + if(connect(sockfd,(struct sockaddr*)&si_other,sizeof(si_other))<0){ + perror("connect"); + exit(EXIT_FAILURE); + }; + setnonblocking(sockfd); +#endif +#ifdef TYPE_TCP + if((listenfd = socket(AF_INET, SOCK_STREAM, 0))<0){ + perror("socket(tcpserver)"); + exit(EXIT_FAILURE); + }; + memset((char *) &si_other, 0, sizeof(si_other)); + si_other.sin_family = AF_INET; + si_other.sin_addr.s_addr = INADDR_ANY; + si_other.sin_port = htons(PORT); + if(bind(listenfd,(struct sockaddr*)&si_other,sizeof(si_other))<0){ + perror("bind"); + exit(EXIT_FAILURE); + }; + if(listen(listenfd,1)!=0){ + perror("listen"); + exit(EXIT_FAILURE); + }; +#endif + + while(1){ + /* prepare stuff for select */ + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + if(devfd>maxfd) + maxfd=devfd; + if(sockfd>maxfd) + maxfd=sockfd; + if(listenfd>maxfd) + maxfd=listenfd; + + FD_ZERO(&rset); + if(devfd==-1){ + fprintf(stderr,"Can't yet deal with disappearing device\n"); + exit(EXIT_FAILURE); + }; + FD_SET(devfd,&rset); + if(sockfd!=-1){ +#ifdef TYPE_TCP + FD_SET(sockfd,&rset); +#endif + }else if(listenfd!=-1){ + FD_SET(listenfd,&rset); + }; + + FD_ZERO(&wset); + if(bufstart!=bufend && sockfd!=-1){ + FD_SET(sockfd,&wset); + }; + + cnt = select(maxfd+1, &rset, &wset, NULL, &timeout); + + + /* First run timer stuff */ + time(&the_time); + if(the_time-ot>=INTERVAL){ + ot=the_time; + printf("[running: buf=%d, sockfd=%d]\n",(BUFSIZE+bufend-bufstart)%BUFSIZE,sockfd); + }; + + if(the_time-heartbeat>=1){ + heartbeat=the_time; + write_r0ket(devfd,"\\7\\0",4); /* Get UUID */ + }; + + /* Now check select / fds*/ + if (cnt<0){ + perror("select"); + exit(EXIT_FAILURE); + }; + + if (cnt==0){ /* timeout */ + printf("[timeout]\n"); + continue; + }; + + if (FD_ISSET(devfd,&rset)){ + if(read_r0ket(devfd)<0){ + close(devfd); + devfd=-1; + }; + if(--cnt ==0) continue; + }; + + if (sockfd!=-1 && FD_ISSET(sockfd,&rset)){ + int r; + unsigned char dummy[32]; + r=read(sockfd,dummy,32); + if(r<0){ + perror("read(socket)"); + exit(EXIT_FAILURE); + }; + if(r==0){ + printf("eof() on socket\n"); + close(sockfd); + sockfd=-1; + }; + if(r>0){ + printf("read [%d] bytes from socket and ignored them.\n",r); + }; + + if(--cnt ==0) continue; + }; + + if (sockfd!=-1 && FD_ISSET(sockfd,&wset)){ + write_socket(sockfd); + if(--cnt ==0) continue; + }; + + if (listenfd!=-1 && FD_ISSET(listenfd,&rset)){ + if(sockfd!=-1){ // close old connection + close(sockfd); + }; + unsigned int size=sizeof(si_other); + if((sockfd=accept(listenfd,(struct sockaddr*)&si_other,&size))<0){ + perror("accept"); + continue; // Do not exit, we can handle this :-) + }; + printf("New connection from %s (fd %d)\n", inet_ntoa(si_other.sin_addr), sockfd); + if(--cnt ==0) continue; + }; + + printf("unknwon select left over: cnt=%d, ",cnt); + printf("rset: "); + for(cnt=0;cnt){ + chomp; + next unless /(.*?)=(.*)/; + $config{$1}=$2; + }; + close(R); + @exec=$config{"prog"},split(/\s+/,$config{"args"}); + delete $config{prog}; + delete $config{args}; +}; + +readcfg(); +l0gger::init(); + +while(1){ + opendir(my $dh, $DEV); + my @paths=grep {/^ttyACM/} readdir($dh); + close $dh; +# print "f: ",join(",",@files),"\n"; + for my $path (@paths){ + next if $run{$path}; + + my $id = eval { + r0ket::r0ket_init($DEV."/".$path); + return r0ket::get_id(); + }; +# print "r0id: $id\n"; + if(!defined $config{$id}){ + print "No config for r0ket $id @ $path, skipping...\n"; + next; + }; + $run{$path}=$id; + + my $pid = fork(); + die "cannot fork" unless defined $pid; + if ($pid == 0) { + exec @exec,'-d',$DEV."/".$path,'-i',$config{$id}; + } else { + print "Started $path : $id @ $pid\n"; + l0gger::send("started $path : $id @ $pid"); + $childs{$pid}=$path; + } + }; + sleep(1); + print join(",",map {$run{$childs{$_}}."@".$childs{$_}."[$_]"} sort {$childs{$a}cmp$childs{$b}} keys %childs),"\n"; +};