first commit
This commit is contained in:
10
tools/chain.conf
Normal file
10
tools/chain.conf
Normal file
@@ -0,0 +1,10 @@
|
||||
# chain.conf
|
||||
# config file for etherSimulator.pl
|
||||
# Specify the probability of correct delivery between nodea and nodeb (bidirectional)
|
||||
# probability:nodea:nodeb:probability
|
||||
# nodea and nodeb are integers 0 to 255
|
||||
# probability is a float range 0.0 to 1.0
|
||||
|
||||
# In this example, the probability of successful transmission
|
||||
# between nodes 10 and 2 (and vice versa) is given as 0.5 (ie 50% chance)
|
||||
probability:10:2:0.5
|
359
tools/createGPX.pl
Normal file
359
tools/createGPX.pl
Normal file
@@ -0,0 +1,359 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# createGPX.pl
|
||||
# Takes the dumps from rf95_client2 and rf95_server2, determines which messages
|
||||
# were received on both ends and produces 3 tracks that can be load as gpx-files
|
||||
# into google maps. This can be used to determine the range between client and
|
||||
# server or visualize where communication between server and client was possible.
|
||||
# The server gps data is not used, i.e. it is assumed that the server is stationary.
|
||||
#
|
||||
# 1) Track containing all points that were sent by rf95_client2, received by
|
||||
# rf95_server2 + the response of rf95_server2 was received by rf95_client2
|
||||
# 2) Track containng all points that were sent by rf95_client2, received by
|
||||
# rf95_server2, but the response of rf95_server2 was NOT recevied by
|
||||
# rf95_client2
|
||||
# 3) Track containg all points that were sent by rf95_client2, but not
|
||||
# received by rf95_server2. Consequently rf95_server did not sent a
|
||||
# response.
|
||||
#
|
||||
# To dump the output, the programs can be started as follows:
|
||||
# On server: rf95_server2 > dump_file_server
|
||||
# On client: rf95_client2 > dump_file_client
|
||||
|
||||
use Geo::Gpx;
|
||||
use Getopt::Long;
|
||||
use strict;
|
||||
|
||||
my %serverMessages;
|
||||
my %clientMessages;
|
||||
my %allMessages;
|
||||
my $sentOnlyMessages = Geo::Gpx->new();
|
||||
my $receivedOnlyMessages = Geo::Gpx->new();
|
||||
my $acknowledgedMessages = Geo::Gpx->new();
|
||||
my $help;
|
||||
my $serverFile;
|
||||
my $clientFile;
|
||||
my $resultFilePrefix;
|
||||
|
||||
my @options =
|
||||
(
|
||||
'h' => \$help, # Help, show usage
|
||||
's=s' => \$serverFile, # file containing dump of server
|
||||
'c=s' => \$clientFile, # file containing dump of client
|
||||
'p=s' => \$resultFilePrefix # prefix for 3 results files
|
||||
);
|
||||
|
||||
&GetOptions(@options) || &usage;
|
||||
&usage if $help;
|
||||
if ($serverFile ne "")
|
||||
{
|
||||
print "ServerFile: " . $serverFile . "\n";
|
||||
&readServerFile($serverFile);
|
||||
#&dumpServerData;
|
||||
}
|
||||
if ($clientFile ne "")
|
||||
{
|
||||
print "ClientFile: " . $clientFile . "\n";
|
||||
&readClientFile($clientFile);
|
||||
#&dumpClientData;
|
||||
}
|
||||
&classifyData if (($serverFile ne "") && ($clientFile ne ""));
|
||||
|
||||
if ($resultFilePrefix ne "")
|
||||
{
|
||||
print "Prefix of resulting gpx-files: " . $resultFilePrefix . "\n";
|
||||
open SENTONLYFILE, ">" . $resultFilePrefix . "_SentOnly.gpx";
|
||||
open RECEIVEDONLYFILE, ">" . $resultFilePrefix . "_ReceivedOnly.gpx";
|
||||
open ACKNOWLEDGEFILE, ">" . $resultFilePrefix . "_Acknowleded.gpx";
|
||||
|
||||
print SENTONLYFILE $sentOnlyMessages->xml( '1.1' );
|
||||
print RECEIVEDONLYFILE $receivedOnlyMessages->xml( '1.1' ) ;
|
||||
print ACKNOWLEDGEFILE $acknowledgedMessages->xml( '1.1' ) ;
|
||||
|
||||
close SENTONLYFILE;
|
||||
close RECEIVEDONLYFILE;
|
||||
close ACKNOWLEDGEFILE;
|
||||
}
|
||||
|
||||
sub usage
|
||||
{
|
||||
print "usage: $0 [-h] [-s serverfile] [-c clientfile] [-p prefix for result files] \n";
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
###################################################################################
|
||||
# classifyData
|
||||
#
|
||||
# Using the sequence number and the timpstamp of the client data, the messages
|
||||
# are classified in 3 groups:
|
||||
# (1) full contact, i.e. message and its reply was received on both ends
|
||||
# (2) received only, i.e. message was received by server, but reply to client
|
||||
# got lost
|
||||
# (3) no contact, i.e. message was sent, but not received by server
|
||||
#
|
||||
###################################################################################
|
||||
sub classifyData
|
||||
{
|
||||
my $item;
|
||||
my $seqNr;
|
||||
my $timestamp;
|
||||
my $longitude;
|
||||
my $latitude;
|
||||
my $reply;
|
||||
my $rssiAtServer;
|
||||
my $serverLongitude;
|
||||
my $serverLatitude;
|
||||
my $serverReply;
|
||||
|
||||
foreach $item (sort keys %clientMessages)
|
||||
{
|
||||
($latitude,$longitude,$reply) = split(/~/,$clientMessages{$item});
|
||||
($seqNr,$timestamp) = split(/~/,$item);
|
||||
|
||||
#print "$item => $clientMessages{$item}\n";
|
||||
if ($latitude =~ /(\d\d)(\d\d\.\d\d\d\d)/)
|
||||
{
|
||||
#print $latitude;
|
||||
$latitude = $1 + $2/60;
|
||||
#print "Latitude " . $latitude . "\n";
|
||||
}
|
||||
if ($longitude =~ /(\d\d\d)(\d\d\.\d\d\d\d)/)
|
||||
{
|
||||
#print $longitude;
|
||||
$longitude = $1 + $2/60;
|
||||
#print "Longitude " . $longitude . "\n";
|
||||
}
|
||||
|
||||
if ($serverMessages{$item})
|
||||
{
|
||||
# this item was received by the server
|
||||
# print "$item => $clientMessages{$item}\n";
|
||||
# print "$item => $serverMessages{$item}\n";
|
||||
# print "\n\n";
|
||||
($serverLatitude,$serverLongitude,$rssiAtServer, $serverReply) = split(/~/,$serverMessages{$item});
|
||||
|
||||
if ($reply eq "NULL")
|
||||
{
|
||||
# client message received, but server message lost
|
||||
#print "RECEIVED ONLY; $item => $clientMessages{$item}\n\n\n";
|
||||
|
||||
my $wpt = {
|
||||
lat => $latitude,
|
||||
lon => $longitude,
|
||||
name => $seqNr . "@" . $timestamp,
|
||||
cmt => 'sent and received with RSSI=' . $rssiAtServer . ', but response got lost',
|
||||
};
|
||||
$receivedOnlyMessages->add_waypoint( $wpt );
|
||||
}
|
||||
else
|
||||
{
|
||||
# client message received by server, client received acknowledge message sent by server
|
||||
# print "ACKNOWLEDGED; $item => $clientMessages{$item}\n\n\n";
|
||||
|
||||
# sanity check: the reply string should be identical
|
||||
if ($reply ne $serverReply)
|
||||
{
|
||||
print "WARNING: Sent and received messages not identical (Sent=$reply/Received=$serverReply)...\n";
|
||||
}
|
||||
my $wpt = {
|
||||
lat => $latitude,
|
||||
lon => $longitude,
|
||||
name => $seqNr . "@" . $timestamp,
|
||||
cmt => 'sent and received with RSSI=' . $rssiAtServer . ', acknowledge received by client',
|
||||
};
|
||||
$acknowledgedMessages->add_waypoint( $wpt );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# client message was sent but not received
|
||||
# print "SENTONLY; $item => $clientMessages{$item}\n\n\n";
|
||||
if ($reply eq "NULL")
|
||||
{
|
||||
my $wpt = {
|
||||
lat => $latitude,
|
||||
lon => $longitude,
|
||||
name => $seqNr . "@" . $timestamp,
|
||||
cmt => 'sent but not received',
|
||||
};
|
||||
$sentOnlyMessages->add_waypoint( $wpt );
|
||||
}
|
||||
else
|
||||
{
|
||||
my $seqNr;
|
||||
my $timestamp;
|
||||
($seqNr,$timestamp) = split (/~/, $item);
|
||||
print "WARNING: There should by no reply to message $seqNr @ $timestamp...\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# sanity check: Verify that each of the server message
|
||||
# was actually sent by the client
|
||||
foreach $item (sort keys %serverMessages)
|
||||
{
|
||||
if (not exists ($clientMessages{$item}) )
|
||||
{
|
||||
($seqNr,$timestamp) = split(/~/,$item);
|
||||
($serverLatitude,$serverLongitude,$rssiAtServer, $serverReply) = split(/~/,$serverMessages{$item});
|
||||
print "WARNING: Data inconistency in $seqNr @ $timestamp. Message received but never sent...\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
###################################################################################
|
||||
# readServerFile
|
||||
#
|
||||
# read data in format created by rf95_server2. To create file, standard output of
|
||||
# rf95_server2 needs to be redirected into a file, i.e. rf95_server2 > file.log
|
||||
###################################################################################
|
||||
sub readServerFile
|
||||
{
|
||||
my ($serverFile) = @_;
|
||||
if (open(SERVERFILE, $serverFile))
|
||||
{
|
||||
while (<SERVERFILE>)
|
||||
{
|
||||
# format: got request: "(00004):163213.000,4846.8686N,00912.2478E"
|
||||
# RSSI: -82
|
||||
# Sent a reply: "R:(00004):20191220163216RM,4846.8303N,00912.27"
|
||||
if (/^got request:\ \"\((\d{5})\):([\d|\.]+),([\d|\.]+)([N|S]),([\d|\.]+)([E|W])\"/)
|
||||
{
|
||||
my $seqNr = $1;
|
||||
my $timestamp= $2;
|
||||
my $latitude = $3;
|
||||
my $longitude = $5;
|
||||
my $rssi;
|
||||
my $reply;
|
||||
$longitude = (-1) * $longitude if ($6 eq "W");
|
||||
$latitude = (-1) * $latitude if ($4 eq "S");
|
||||
|
||||
# get RSSI
|
||||
my $line = <SERVERFILE>;
|
||||
if ($line =~ /RSSI:\ ([-|+|\d]+)/)
|
||||
{
|
||||
$rssi = $1;
|
||||
}
|
||||
|
||||
# get reply
|
||||
$line = <SERVERFILE>;
|
||||
if ($line =~ /Sent a reply:\ \"(.+)\"/)
|
||||
{
|
||||
$reply=$1;
|
||||
if ($reply =~ /R:\((\d{5})\)/)
|
||||
{
|
||||
if ($1 ne $seqNr)
|
||||
{
|
||||
print "WARNING: File structure seems to be broken. No matching reply for sequence numer '$seqNr'.";
|
||||
print "File name: $serverFile\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
$serverMessages{$seqNr ."~" . $timestamp} = $latitude . "~" . $longitude . "~" . $rssi ."~" . $reply ;
|
||||
}
|
||||
|
||||
}
|
||||
close(SERVERFILE);
|
||||
}
|
||||
else
|
||||
{
|
||||
print STDERR "Could not open config file $serverFile: $!\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
###################################################################################
|
||||
# readClientFile
|
||||
#
|
||||
# read data in format created by rf95_client2. To create file, standard output of
|
||||
# rf95_client2 needs to be redirected into a file, i.e. rf95_client2 > file.log
|
||||
###################################################################################
|
||||
sub readClientFile
|
||||
{
|
||||
my ($clientFile) = @_;
|
||||
if (open(CLIENTFILE, $clientFile))
|
||||
{
|
||||
while (<CLIENTFILE>)
|
||||
{
|
||||
# format: Message="(00004):165718.000,4846.8668N,00912.2344E"
|
||||
# got reply: "R:(00004):20191220165722RM,4846.8729N,00912.24"
|
||||
# or
|
||||
# Message="(00206):172330.000,4846.4587N,00912.3557E"
|
||||
# No reply, is rf95_server running?
|
||||
|
||||
if (/^\Message="\((\d{5})\):(.+),(.+)([N|S]),(.+)([E|W])\"/)
|
||||
{
|
||||
my $seqNr = $1;
|
||||
my $timestamp= $2;
|
||||
my $latitude = $3;
|
||||
my $longitude = $5;
|
||||
my $reply;
|
||||
$longitude = (-1) * $longitude if ($6 eq "W");
|
||||
$latitude = (-1) * $latitude if ($4 eq "S");
|
||||
|
||||
# get reply
|
||||
my $line = <CLIENTFILE>;
|
||||
if ($line =~ /got reply:\ \"(.+)\"/)
|
||||
{
|
||||
$reply=$1;
|
||||
if ($reply =~ /R:\((\d{5})\)/)
|
||||
{
|
||||
if ($1 ne $seqNr)
|
||||
{
|
||||
print "WARNING: File structure seems to be broken. No matching reply for sequence numer '$seqNr'.";
|
||||
print "File name: $clientFile\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($line =~ /No reply/)
|
||||
{
|
||||
$reply = "NULL";
|
||||
}
|
||||
$clientMessages{$seqNr ."~" . $timestamp} = $latitude . "~" . $longitude . "~" . $reply ;
|
||||
}
|
||||
|
||||
}
|
||||
close(CLIENTFILE);
|
||||
}
|
||||
else
|
||||
{
|
||||
print STDERR "Could not open config file $clientFile: $!\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
###################################################################################
|
||||
# dumpServerData
|
||||
#
|
||||
# Once the data file of rf95_server2 is successfully read, it can be dumped with
|
||||
# this routine. This routine is intended for debugging
|
||||
#
|
||||
###################################################################################
|
||||
sub dumpServerData()
|
||||
{
|
||||
my $item;
|
||||
foreach $item (sort keys %serverMessages)
|
||||
{
|
||||
print "$item => $serverMessages{$item}\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
###################################################################################
|
||||
# dumpClientData
|
||||
#
|
||||
# Once the data file of rf95_client2 is successfully read, it can be dumped with
|
||||
# this routine. This routine is intended for debugging
|
||||
#
|
||||
###################################################################################
|
||||
sub dumpClientData()
|
||||
{
|
||||
my $item;
|
||||
foreach $item (sort keys %clientMessages)
|
||||
{
|
||||
print "$item => $clientMessages{$item}\n";
|
||||
}
|
||||
}
|
224
tools/etherSimulator.pl
Normal file
224
tools/etherSimulator.pl
Normal file
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# etherSimulator.pl
|
||||
# Simulates the luminiferous ether for RH_Simulator.
|
||||
# Connects multiple instances of RH_Simulator clients together and passes
|
||||
# simulated messages between them.
|
||||
|
||||
use Getopt::Long;
|
||||
use strict;
|
||||
|
||||
# Configurable variables
|
||||
my $help;
|
||||
my $config;
|
||||
my $port = 4000;
|
||||
$port = $main::opt_p
|
||||
if $main::opt_p;
|
||||
my $bps = 10000;
|
||||
$bps = $main::opt_b
|
||||
if $main::opt_b;
|
||||
|
||||
# Config that shows probability of successful transmission between nodes
|
||||
# Read from config file
|
||||
my %netconfig;
|
||||
|
||||
use warnings;
|
||||
use POE qw(Component::Server::TCP Filter::Block);
|
||||
use strict;
|
||||
|
||||
my @options =
|
||||
(
|
||||
'h' => \$help, # Help, show usage
|
||||
'c=s' => \$config, # Config file
|
||||
'b=n' => \$bps, # Bits per second simulated baud rate
|
||||
'p=n' => \$port, # port number
|
||||
);
|
||||
|
||||
&GetOptions(@options) || &usage;
|
||||
&usage if $help;
|
||||
|
||||
readConfig($config) if defined $config;
|
||||
|
||||
sub usage
|
||||
{
|
||||
print "usage: $0 [-h] [-c configfile] [-b bitspersec] [-p portnumber]\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
# config file for etherSimulator.pl
|
||||
# Specify the probability of correct delivery between nodea and nodeb (bidirectional)
|
||||
# probability:nodea:nodeb:probability
|
||||
# nodea and nodeb are integers 0 to 255
|
||||
# probability is a float range 0.0 to 1.0
|
||||
# In this example, the probability of successful transmission
|
||||
# between nodes 10 and 2 (and vice versa) is given as 0.5 (ie 50% chance)
|
||||
# probability:10:2:0.5
|
||||
sub readConfig
|
||||
{
|
||||
my ($config) = @_;
|
||||
|
||||
if (open(CONFIG, $config))
|
||||
{
|
||||
while (<CONFIG>)
|
||||
{
|
||||
if (/^probability:(\d{1,3}):(\d{1,3}):(\d+(\.\d+))/)
|
||||
{
|
||||
$netconfig{$1}{$2} = $3;
|
||||
$netconfig{$2}{$1} = $3; # Bidirectional
|
||||
}
|
||||
}
|
||||
close(CONFIG);
|
||||
}
|
||||
else
|
||||
{
|
||||
print STDERR "Could not open config file $config: $!\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
# See RHTcpProtocol.h
|
||||
# messages to and from us are preceded by the payload length as uint32_t in network byte order
|
||||
sub encoder
|
||||
{
|
||||
my $stuff = shift;
|
||||
substr($$stuff, 0, 0) = pack('N', length($$stuff));
|
||||
return;
|
||||
}
|
||||
|
||||
sub decoder
|
||||
{
|
||||
my $stuff = shift;
|
||||
return if (length($$stuff) < 4);
|
||||
my ($length) = unpack('N', $$stuff);
|
||||
return if (length($$stuff) < $length+4);
|
||||
return $length + 4;
|
||||
}
|
||||
|
||||
# Filter to assemble and disassemble messages accordiong to precending length
|
||||
my $filter = POE::Filter::Block->new( LengthCodec => [ \&encoder, \&decoder ] );
|
||||
|
||||
# Message types
|
||||
# See RH_TcpProtocol.h
|
||||
my $RH_TCP_MESSAGE_TYPE_NOP = 0; # Not used
|
||||
my $RH_TCP_MESSAGE_TYPE_THISADDRESS = 1; # Specifies the thisAddress of the connected sketch
|
||||
my $RH_TCP_MESSAGE_TYPE_PACKET = 2; # Message to/from the connected sketch
|
||||
|
||||
my %clients;
|
||||
|
||||
# Look up the source and dest nodes in the netconfig and return the 0.0 to 1.0 probability
|
||||
# of successful delivery
|
||||
sub probabilityOfSuccessfulDelivery
|
||||
{
|
||||
my ($from, $to) = @_;
|
||||
|
||||
return $netconfig{$from}{$to}
|
||||
if exists $netconfig{$from}{$to};
|
||||
# If no explicit probability, use 1.0 (certainty)
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
# Return true if the message is simulted to have been received successfully
|
||||
# taking into account the probability of sucessful delivery
|
||||
sub willDeliverFromTo
|
||||
{
|
||||
my ($from, $to) = @_;
|
||||
|
||||
my $prob = probabilityOfSuccessfulDelivery($from, $to);
|
||||
return 1
|
||||
if rand() < $prob;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub deliverMessages
|
||||
{
|
||||
my ($key, $value);
|
||||
while (($key, $value) = each(%clients))
|
||||
{
|
||||
next unless defined $$value{'packet'}; # No packet waiting for delivery
|
||||
# Find how long since the message was transmitted and see it its time to
|
||||
# deliver it to the client.
|
||||
# We are waiting here for the transmission time of the message to elapse
|
||||
# given the message length and the bits per second
|
||||
my $elapsed = Time::HiRes::tv_interval([$$value{'packetreceived'}], [Time::HiRes::gettimeofday]);
|
||||
if ($elapsed > length($$value{'packet'}) * 8 / $bps)
|
||||
{
|
||||
$$value{'client'}->put(pack('Ca*', $RH_TCP_MESSAGE_TYPE_PACKET, $$value{'packet'}));
|
||||
delete $$value{'packet'}; # Delivered, forget it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
POE::Session->create(
|
||||
inline_states => {
|
||||
_start => sub {
|
||||
$_[KERNEL]->delay(tick => 1);
|
||||
},
|
||||
|
||||
tick => sub {
|
||||
deliverMessages();
|
||||
$_[KERNEL]->delay(tick => 0.001);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
POE::Component::Server::TCP->new(
|
||||
Port => $port,
|
||||
|
||||
ClientConnected => sub {
|
||||
my $client = $_[HEAP]{client};
|
||||
# Create a new object to hold data about RH_TCP messages to and from this client
|
||||
$clients{$client} = {'client' => $client};
|
||||
},
|
||||
|
||||
ClientInput => sub {
|
||||
my $client = $_[HEAP]{client};
|
||||
my $client_input = $_[ARG0];
|
||||
my $client_id = $_[ARG1];
|
||||
my ($length, $type) = unpack('NC', $client_input);
|
||||
if ($type == $RH_TCP_MESSAGE_TYPE_THISADDRESS)
|
||||
{
|
||||
# Client notifies us of its node ID
|
||||
my ($length, $type, $thisaddress) = unpack('NCC', $client_input);
|
||||
# Set the client objects thisaddress
|
||||
$clients{$client}{'thisaddress'} = $thisaddress;
|
||||
}
|
||||
elsif ($type == $RH_TCP_MESSAGE_TYPE_PACKET)
|
||||
{
|
||||
# New packet for transmission
|
||||
my ($length, $type, $packet) = unpack('NCa*', $client_input);
|
||||
# Try to deliver the packet to all the other clients
|
||||
my ($key, $value);
|
||||
while (($key, $value) = each(%clients))
|
||||
{
|
||||
next if ($key eq $client); # Dont deliver back to the same client
|
||||
|
||||
# Check the network config and see if delivery to this node is possible
|
||||
next unless willDeliverFromTo($clients{$client}{'thisaddress'}, $$value{thisaddress});
|
||||
|
||||
# The packet reached this destination, see if it collided with
|
||||
# another packet
|
||||
if (defined $$value{'packet'})
|
||||
{
|
||||
# Collision with waiting packet, delete it
|
||||
delete $$value{'packet'};
|
||||
}
|
||||
else
|
||||
{
|
||||
# New packet, queue it for delivery to the client after the
|
||||
# nominal transmission time is complete
|
||||
$$value{'packet'} = $packet;
|
||||
$$value{'packetreceived'} = Time::HiRes::gettimeofday();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ClientDisconnected => sub {
|
||||
my $client = $_[HEAP]{client};
|
||||
delete $clients{$client};
|
||||
},
|
||||
ClientFilter => $filter, # Handles prepended lengths to
|
||||
);
|
||||
|
||||
POE::Kernel->run;
|
||||
exit;
|
13
tools/simBuild
Normal file
13
tools/simBuild
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# simBuild
|
||||
# build a RadioHead example sketch for running as a simulated process
|
||||
# on Linux.
|
||||
#
|
||||
# usage: simBuild sketchname.pde
|
||||
# The executable will be saved in the current directory
|
||||
|
||||
INPUT=$1
|
||||
OUTPUT=$(basename $INPUT ".pde")
|
||||
|
||||
g++ -g -I . -I RHutil -x c++ $INPUT tools/simMain.cpp RHGenericDriver.cpp RHMesh.cpp RHRouter.cpp RHReliableDatagram.cpp RHDatagram.cpp RH_TCP.cpp RH_Serial.cpp RHCRC.cpp RHutil/HardwareSerial.cpp -o $OUTPUT
|
71
tools/simMain.cpp
Normal file
71
tools/simMain.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
// main.cpp
|
||||
// Lets Arduino RadioHead sketches run within a simulator on Linux as a single process
|
||||
// Copyright (C) 2014 Mike McCauley
|
||||
// $Id: simMain.cpp,v 1.3 2020/08/05 04:32:19 mikem Exp mikem $
|
||||
|
||||
#include <RadioHead.h>
|
||||
#if (RH_PLATFORM == RH_PLATFORM_UNIX)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <RHutil/simulator.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
SerialSimulator Serial;
|
||||
|
||||
// Functions we expect to find in the sketch
|
||||
extern void setup();
|
||||
extern void loop();
|
||||
|
||||
// Millis at the start of the process
|
||||
unsigned long start_millis;
|
||||
|
||||
int _simulator_argc;
|
||||
char** _simulator_argv;
|
||||
|
||||
// Returns milliseconds since beginning of day
|
||||
unsigned long time_in_millis()
|
||||
{
|
||||
struct timeval te;
|
||||
gettimeofday(&te, NULL); // get current time
|
||||
unsigned long milliseconds = te.tv_sec*1000LL + te.tv_usec/1000; // caclulate milliseconds
|
||||
return milliseconds;
|
||||
}
|
||||
|
||||
// Run the Arduino standard functions in the main loop
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// Let simulated program have access to argc and argv
|
||||
_simulator_argc = argc;
|
||||
_simulator_argv = argv;
|
||||
start_millis = time_in_millis();
|
||||
// Seed the random number generator
|
||||
srand(getpid() ^ (unsigned) time(NULL)/2);
|
||||
setup();
|
||||
while (1)
|
||||
loop();
|
||||
}
|
||||
|
||||
void delay(unsigned long ms)
|
||||
{
|
||||
usleep(ms * 1000);
|
||||
}
|
||||
|
||||
// Arduino equivalent, milliseconds since process start
|
||||
unsigned long millis()
|
||||
{
|
||||
return time_in_millis() - start_millis;
|
||||
}
|
||||
|
||||
long random(long from, long to)
|
||||
{
|
||||
return from + (random() % (to - from));
|
||||
}
|
||||
|
||||
long random(long to)
|
||||
{
|
||||
return random(0, to);
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user