source: core/trunk/client/adsbclient.pl @ 314

Last change on this file since 314 was 314, checked in by smoser, 11 years ago

Release 1.2.0

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