source: core/trunk/client/flarmclient.pl @ 225

Last change on this file since 225 was 225, checked in by smoser, 12 years ago

#139

  • Property svn:mime-type set to text/plain
File size: 6.6 KB
RevLine 
[130]1#!/usr/bin/perl
2#-------------------------------------------------------------------------------
3# This file is part of the FLARM¨-Radar Project.
4#   
5#   Copyright 2013 Netzschmiede GmbH (http://www.netzschmiede.ch)
6#
7# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
10#
11#   http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
18#
19#   Project Website: www.flarmradar.ch
20#   Email: info@flarmradar.ch
21#-------------------------------------------------------------------------------
22
23use strict;
24use warnings;
25use Getopt::Std;
26use File::Basename;
[224]27use Time::HiRes qw(gettimeofday);
[133]28use POSIX qw(strftime);
29use POSIX qw(setsid);
[130]30use LWP::UserAgent;
31
32my %config;
33my %options;
34my $ua;
[224]35my $debug = 0;
[204]36my $trace = 0;
[212]37my $interval = 1;
[130]38
39# default values
[204]40my $log = "$ENV{'HOME'}/.flarmclient/client.trace";
[211]41my $cfile = "$ENV{'HOME'}/.flarmclient/flarmclient.conf";
[130]42my $fifo = "$ENV{'HOME'}/.flarmclient/client.fifo";
43
44# functions
45sub usage {
46  print <<EOF;
47NAME
48  $0 -- stream flarm data to server
49
50SYNOPSIS
51  $0 [-c config_file] [-f data_file] [-h]
52
53DESCRIPTION
54  The following options are available:
55 
56  -c    Use the specified configuration file. Use the default configuration
57                file as a starting point for customization.
58               
[224]59  -d    Write debug information. The debug information is written to STDOUT
60                unless tracing (option -t) is turned on. With tracing switched on,
61                the debug information is written to the trace file (see below).
62               
[212]63  -i    Interval in seconds for sending data to the server. Defaults to one
64                second.
65               
[130]66  -f    Read the data from the specified data file. This is mainly used for
67                testing and development.
68               
[224]69  -t    Trace client operations. A trace file is created in
70                \$HOME/.flarmclient/client.trace
71                WARNING: Do not use that in Production, this option produces a big
72                much data and fill up the filesystem.
73               
[130]74  -h    Print this help.
75
76EOF
77  exit 0;
78}
79
[204]80# print statistic information to logfile
81$SIG{USR1} = sub {
82        if ($trace) {
83                $trace = 0;
84        } else {
85                $trace = 1;
86        }
87};
88
[224]89sub openlog {
90        if (tell(LOG) == -1) {
91                open(LOG, ">> $log") || print "Failed to open trace file $log: $!";
92        }
93        return 1;
94}
95
[204]96sub logit {
97        my ($level, $msg) = @_;
[224]98        if ($trace && $level eq "TRACE") {
99                openlog() && print LOG "$msg\n";
[204]100        }
[224]101        if ($debug && $level eq "DEBUG") {
[225]102                if ($trace) {
103                        openlog() && print LOG "$msg\n";
104                } else {
105                        print "$msg\n";
106                }
107               
[224]108        }
[204]109}
110
[130]111sub cleanup {
112        if (-e "$fifo") {
113                unlink($fifo) || die("unable to remove $fifo: $!");
114        }
[223]115        close(LOG);
[130]116}
117
118sub readconfig {
119        open(CONF, "< $cfile") || die("failed to open config file for reading: $!");
120        while(my $line = <CONF>) {
121                chomp($line);
122                next if $line =~ /^\s*#/;
123                next if $line =~ /^\s*$/;
124                if ($line =~ /^\s*(\S*)\s*=\s*(\S*)\s*$/) {
125                        $config{$1} = $2;
126                }
127        }
128        close(CONF);
129}
130
[224]131sub exact_time {
132        return strftime("%H:%M:%S", localtime()) . "." . (gettimeofday())[1];
133}
134
[130]135# send the records to the server. We don't make a request for each record for
136# performance reasons.
137sub flush {
138        my ($records, $url) = @_;
[224]139        logit("DEBUG", exact_time() . " Start flushing data to server");
140       
[217]141        my $date = `date -u +%Y/%m/%d`;
[224]142        chomp($date);
[130]143        my $resturl = $url . "/" . $date;
[224]144        logit("DEBUG", exact_time() . " Request resource: " . $resturl);
145       
146        # compose the request
[130]147        my $request = HTTP::Request->new('PUT');
148        $request->url($resturl);
149        $request->header('stationKey'=>$config{'key'});
[224]150        my $content = compress($records);
151        logit("DEBUG", exact_time() . " Put on wire: " . $content);
152        $request->content($content);
153       
[130]154        # run the request
[224]155        logit("DEBUG", exact_time() . " Start server push");
[130]156        my $response = $ua->request($request);
[224]157        logit("DEBUG", exact_time() . " End server push");
158       
[130]159        # analyze the response
160        my $code = $response->code;
[224]161        $response->code == 200 || logit("DEBUG", "Error processing records (" . $response->code . ") records=[" . $records . "]");
162        logit("DEBUG", exact_time() . " End flushing data");
[130]163}
164
[223]165# remove all unused records, debug information, etc.
166sub compress {
167        my ($records) = @_;
168        my $on_wire;
169        foreach my $record (split(';', $records)) {
170                if ($record =~ /^\$GPGGA,/ || $record =~ /^\$PFLAA,/) {
171                        $on_wire = (defined($on_wire)) ? $on_wire . ";" . $record : $record;
172                }               
173        }
174        return $on_wire;
175}
176
[130]177# parse options
[224]178getopts('c:di:f:th', \%options);
[130]179
180# read config file
181if (defined($options{'c'})) {
182        $cfile = $options{'c'};
183}
[224]184if (defined($options{'d'})) {
185        $debug = 1;
186}
[212]187if (defined($options{'i'})) {
188        $interval = $options{'i'};
189}
[130]190if (defined($options{'h'})) {
191        usage();
192}
[224]193if (defined($options{'t'})) {
194        $trace = 1;
195}
[204]196
197# read config file
[130]198readconfig();
199
200# validation: key must be present in config file
201die("no key found in config file (option: key)") unless defined($config{'key'});
202
203# remove old leftovers
204cleanup();
205
206# create pipe
207die("no fifo found in config file (option: fifo)") unless defined($fifo);
208if (! -d dirname($fifo)) {
209        system("mkdir", "-p", dirname($fifo)) == 0 || die("failed to create fifo directory " . dirname($fifo) . ": $!")
210}
211system("mkfifo", $fifo) == 0 || die("failed to create fifo: $!");
212
213# force a flush right away and after every write or print
214local $| = 1;
215
216# fork minicom and write to pipe
217defined( my $pid = fork() ) or die "can't fork: $!";
218unless ($pid) {
219        # we're the child
[133]220        # detach from session
[217]221    setsid() or die "can't start a new session: $!";
[133]222        close(STDIN);
223        close(STDOUT);
[217]224        #close(STDERR);
[130]225       
226        if (defined($options{'f'})) {
227                open(DATA, "< $options{'f'}") || die("failed to open data file $options{'f'}: $!");
228                open(FIFO, "> $fifo") || die("failed to open fifo for writing: $!");
229                while(my $line = <DATA>) {
230                        chomp($line);
231                        next if ($line =~ /^\s*$/);
232                        print FIFO $line, "\n" || die("failed to execute child command: $!");
233                }
234                close(DATA);
235                close(FIFO);
236        } else {
[133]237                exec("minicom", "-t", "xterm-color", "-C", $fifo) == 0 || die("failed to run minicom: $!");
[130]238        }
239        exit 0;
240}
241
242# create UserAgent object
243$ua = new LWP::UserAgent;
244my $buf;
245# read data from pipe
246open(FIFO, "< $fifo") || die("failed to open fifo for reading: $!");
[212]247my $i = 0;
[130]248while(my $record = <FIFO>) {
249        chomp($record);
[224]250        logit("TRACE", $record);
[130]251        $buf = (defined($buf)) ? "$buf;$record" : $record;
252        if ($record =~ /^\$GPGGA,/) {
[212]253                flush($buf, $config{'url'}) if ($i % $interval == 0);
[133]254                if (defined($options{'f'})) {
255                        sleep(1);
256                }
[130]257                $buf = undef;
[212]258                $i++;
[130]259        }
260}
261close(FIFO);
262
263cleanup();
264exit 0;
265
Note: See TracBrowser for help on using the repository browser.