Skip to content

Commit

Permalink
Merge pull request #26 from 12urenloop/hw_sim
Browse files Browse the repository at this point in the history
Script to test simulate hardware beacons
  • Loading branch information
abeforgit authored Nov 10, 2019
2 parents 467e7db + 2192839 commit a8089ea
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 44 deletions.
1 change: 1 addition & 0 deletions hw_sim/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
34 changes: 34 additions & 0 deletions hw_sim/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Hardware simulation script

## Requirements
Any versions of the below should work, but when in doubt, take the latest one

- `npm`
- `node`

## Setup

`npm install`

## Run

- First make sure an instance of telraam is running (see below how to specify the telraam address and port)

- Then run: `node main.js`

## Arguments

- `-h`: Show all the help messages.
- `-p`: What port to connect to (default: `4564`)
- `-a`: What address to connect to (default: `127.0.0.1`).
- `-r`: The amount of runners to spawn.
- `-b`: The amount of beacons to spawn.
- `-m`: The average time per round
- `-d`: Standard deviation for the average runner speed.
- `-D`: Standard deviation of round speed, global for all runners.
- `--miss-rate`: Missrate of runner detection.

### Todo: added bonusses

- Malformed message rate. We need closing and starting tags to properly detect this. So server code and code here. Look at the class `telraam.beacon.BeaconMessage`.
- Messages per beacon or something, because irl the beacons are probably gonna send more than 1 message for a runner passing by.
116 changes: 116 additions & 0 deletions hw_sim/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
'use strict';

const ArgumentParser = require('argparse').ArgumentParser;
const net = require('net');

var args;

// Standard Normal variate using Box-Muller transform.
function randn_bm(mean, dev) {
var u = 0,
v = 0;
while (u === 0) u = Math.random(); //Converting [0,1) to (0,1)
while (v === 0) v = Math.random();
const out = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
return out * dev + mean;
}

class Beacon {
constructor(id) {
this.socket = net.Socket();
this.socket.connect(args.port, args.address);
this.id = id;
}

send(id) {
console.log("Beacon", id, "Runner", this.id);

// This is so ugly
const start_tag = [60, 60, 60, 60];
const end_tag = [62, 62, 62, 62];
const actual_message_size = 10;

const buffer = Buffer.alloc(actual_message_size + start_tag.length + end_tag.length);

let offset = 0;
for (let tag of start_tag) {
buffer.writeInt8(tag, offset);
offset += 1; // '<'
}

buffer.writeInt8(this.id, offset);
offset += 1;
buffer.writeInt8(id, offset);
offset += 1;

buffer.writeBigInt64LE(BigInt(Date.now()), offset);
offset += 8;

for (let tag of end_tag) {
buffer.writeInt8(tag, offset);
offset += 1; // '<'
}
this.socket.write(buffer);
}
}

class Runner {
constructor(id, mean, beacons) {
this.mean = mean;
this.dev = args.round_deviation;
this.beacons = beacons;
this.at = 0;
this.id = id;

this.run = this.send.bind(this);

this.set_next();
}

send() {
if (Math.random() >= args.miss_rate) {
this.beacons[this.at].send(this.id);
}

this.at++;

if (this.at >= this.beacons.length) {
this.at = 0;
}

this.set_next();
}

set_next() {
const time_till_next = randn_bm(this.mean, this.dev);
setTimeout(this.run, time_till_next);
}
}

function main() {
const parser = new ArgumentParser({
addHelp: true,
description: 'Hardware simulation script for Telraam'
});

parser.addArgument(['-p', "--port"], { defaultValue: 4564, type: "int", help: "Port to use" });
parser.addArgument(['-a', "--address"], { defaultValue: "127.0.0.1", help: "Ip address to test" });
parser.addArgument(['-b', "--beacons"], { defaultValue: 2, type: "int", help: "Amount of beacons" });
parser.addArgument(['-r', "--runners"], { defaultValue: 5, type: "int", help: "Amount of runners" });
parser.addArgument(['-m', "--mean"], { defaultValue: 500, type: "int", help: "Mean of runner speed (ms per round)" });
parser.addArgument(['-d', "--runner-deviation"], { defaultValue: 10, type: "int", help: "Standard deviation of runner speed (per runner)" });
parser.addArgument(['-D', "--round-deviation"], { defaultValue: 0, type: "int", help: "Standard deviation of runner speed (per round)" });
parser.addArgument(['--miss-rate'], { defaultValue: 0, type: "float", help: "Missrate of runner detection." });
args = parser.parseArgs();

const beacons = [];
for (let i = 0; i < args.beacons; i++) {
beacons.push(new Beacon(i + 1));
}

const runners = [];
for (let i = 0; i < args.runners; i++) {
runners.push(new Runner(i + 1, randn_bm(args.mean, args.runner_deviation), beacons));
}
}
main();
23 changes: 23 additions & 0 deletions hw_sim/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions hw_sim/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "hw_sim",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {},
"devDependencies": {
"argparse": "^1.0.10"
}
}
18 changes: 13 additions & 5 deletions src/main/java/telraam/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,33 @@
import io.dropwizard.jdbi3.bundles.JdbiExceptionsBundle;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.jdbi.v3.core.Jdbi;
import telraam.api.BatonResource;
import telraam.api.HelloworldResource;
import telraam.beacon.BeaconAggregator;
import telraam.database.daos.BatonDAO;
import telraam.database.models.Baton;
import telraam.database.models.Id;
import telraam.healthchecks.TemplateHealthCheck;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;



public class App extends Application<AppConfiguration> {
private static Logger logger = Logger.getLogger(App.class.getName());

public static void main(String[] args) throws Exception {
new App().run(args);
BeaconAggregator ba = new BeaconAggregator(4564);
ba.onError((e) -> {logger.warning(e.getMessage()); return null;});
ba.onData((e) -> {logger.info(e.toString()); return null;});
ba.onConnect((_e) -> {logger.info("Connect"); return null;});
ba.onDisconnect((_e) -> {logger.info("Disconnected"); return null;});
// new App().run(args);
ba.run();
}

@Override
Expand Down
99 changes: 81 additions & 18 deletions src/main/java/telraam/beacon/Beacon.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@

import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.net.Socket;
import java.nio.Buffer;
import java.util.List;
import java.util.ArrayList;

/**
* Beacon is socket wrapper that listens to the sockets
* and emits BeaconMessages when enough bytes are read.
*
* Beacons are closed at the first Exception encountered.
* This could be changed if need be.
*
* @author Arthur Vercruysse
*/
* Beacon is socket wrapper that listens to the sockets and emits BeaconMessages
* when enough bytes are read.
*
* Beacons are closed at the first Exception encountered. This could be changed
* if need be.
*
* @author Arthur Vercruysse
*/
public class Beacon extends EventGenerator<BeaconMessage> implements Runnable {
private Socket s;
private int messageSize = BeaconMessage.MESSAGESIZE;
private byte[] startTag = BeaconMessage.STARTTAG;
private byte[] endTag = BeaconMessage.ENDTAG;

public Beacon(Socket socket, Callback<Void, Event<BeaconMessage>> h) {
super(h);
Expand All @@ -29,25 +35,82 @@ public Beacon(Socket socket, Callback<Void, Event<BeaconMessage>> h) {
public void run() {
this.connect();

byte[] buf = new byte[messageSize];
int at = 0;
InputStream is;
boolean readingMsg = false;

List<Byte> msgBuf = new ArrayList<>(messageSize);
int sTagIndex = 0;
int eTagIndex = 0;
byte[] buf = new byte[1024];

BufferedInputStream is;

try {
is = s.getInputStream();
is = new BufferedInputStream(s.getInputStream());
} catch (IOException e) {
error(e);
return;
}

try {
while (true) {
int c = is.read(buf, at, messageSize - at);
if (c < 0) throw new EOFException();
at += c;
if (at == messageSize) {
this.data(new BeaconMessage(buf));
at = 0;
int c = is.read(buf);
if (c < 0)
throw new EOFException();

for (int i = 0; i < c; i++) {
byte b = buf[i];
msgBuf.add(b);

if (b == startTag[sTagIndex]) {
sTagIndex++;

// A complete start tag is found
// Delete current msgBuf content and start over
if (sTagIndex == startTag.length) {
sTagIndex = 0;

if (readingMsg) {
// TODO: Maybe we want to reset msgBuf idk
this.error(new BeaconException.MsgStartWithNoEnd());
} else {
msgBuf.clear();
readingMsg = true;
}
}
} else {
sTagIndex = 0;
}

if (b == endTag[eTagIndex]) {
eTagIndex++;

// A complete end tag is found
// Flush the msgBuffer
if (eTagIndex == endTag.length) {
eTagIndex = 0;

if (readingMsg) {

// Remove end tag from message
for (int k = 0; k < endTag.length; k++) {
msgBuf.remove(msgBuf.size() - 1);
}

// Catch errors thrown at message decoding and propagate
try {
this.data(new BeaconMessage(msgBuf));
} catch (Exception e) {
this.error(e);
}

readingMsg = false;
} else {
this.error(new BeaconException.MsgEndWithNoStart());
}
}
} else {
eTagIndex = 0;
}
}
}
} catch (IOException e) {
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/telraam/beacon/BeaconException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package telraam.beacon;

public class BeaconException extends Exception {
protected BeaconException(String reason) {
super(reason);
}

public static class MsgEndWithNoStart extends BeaconException {
public MsgEndWithNoStart() {
super("Message end tag detected without a start tag");
}
}

public static class MsgStartWithNoEnd extends BeaconException {
public MsgStartWithNoEnd() {
super("2 message start tags detected.");
}
}
}
Loading

0 comments on commit a8089ea

Please sign in to comment.