-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #179 from geky/mcu-client
Add MCU client
- Loading branch information
Showing
45 changed files
with
4,281 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[package] | ||
name = "audio-event-triangulation" | ||
version = "0.3.0" | ||
authors = ["The Veracruz Development Team"] | ||
edition = "2018" | ||
description = "Triangulation via audio events" | ||
|
||
[dependencies] | ||
anyhow = "1.0.14" | ||
thiserror = "1.0.26" | ||
|
||
[profile.release] | ||
opt-level = 3 | ||
lto = true | ||
codegen-units = 1 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Example Makefile | ||
# | ||
# AUTHORS | ||
# | ||
# The Veracruz Development Team. | ||
# | ||
# COPYRIGHT AND LICENSING | ||
# | ||
# See the `LICENSING.markdown` file in the Veracruz root directory for | ||
# licensing and copyright information. | ||
|
||
.PHONY: all doc clean fmt | ||
|
||
all: | ||
cargo build --target wasm32-wasi --release | ||
|
||
doc: | ||
cargo doc | ||
|
||
fmt: | ||
cargo fmt | ||
|
||
clean: | ||
cargo clean | ||
rm -f Cargo.lock | ||
|
88 changes: 88 additions & 0 deletions
88
sdk/rust-examples/audio-event-triangulation/scripts/poll_for_result.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# Poll for audio event triangulation results | ||
# | ||
# AUTHORS | ||
# | ||
# The Veracruz Development Team. | ||
# | ||
# COPYRIGHT AND LICENSING | ||
# | ||
# See the `LICENSING.markdown` file in the Veracruz root directory for | ||
# licensing and copyright information. | ||
|
||
import argparse | ||
import json | ||
import re | ||
import struct | ||
import subprocess as sp | ||
import sys | ||
import time | ||
|
||
# Convert pair of signed 32-bit latitude+longitude coordinates into | ||
# a human readable representation | ||
def dump_gps(location): | ||
absy = abs(location[0]) | ||
absx = abs(location[1]) | ||
return '%d°%02d\'%02d.%02d"%c %d°%02d\'%02d.%02d"%c' % ( | ||
absy / (1024*1024), | ||
(absy / (1024*1024/60)) % 60, | ||
(absy / (1024*1024/60/60)) % 60, | ||
(absy / (1024*1024/60/60/100)) % 100, | ||
'N' if location[0] >= 0 else 'S', | ||
absx / (1024*1024), | ||
(absx / (1024*1024/60)) % 60, | ||
(absx / (1024*1024/60/60)) % 60, | ||
(absx / (1024*1024/60/60/100)) % 100, | ||
'E' if location[1] >= 0 else 'W') | ||
|
||
def main(args): | ||
# grab server addresses from policy file | ||
with open(args.policy) as f: | ||
policy_json = json.load(f) | ||
|
||
print('\033[0;32mstarting audio event triangulation service\033[m') | ||
print('veracruz_server: %s' % policy_json['veracruz_server_url']) | ||
print('proxy_attestation_server: %s' % policy_json['proxy_attestation_server_url']) | ||
print('waiting for triangulation results...') | ||
|
||
# poll until Veracruz returns a successful computation | ||
while True: | ||
try: | ||
output = sp.check_output([ | ||
'vc-client', | ||
args.policy, | ||
'--identity', args.identity, | ||
'--key', args.key, | ||
'--program', 'audio-event-triangulation.wasm=' + args.program, | ||
'--output', 'audio-event-triangulation.wasm=-']) | ||
except sp.CalledProcessError: | ||
time.sleep(5) | ||
continue | ||
|
||
# strip debug info | ||
output = re.sub(rb'post.*?\n', b'', output) | ||
|
||
# decode found coordinates | ||
location = struct.unpack('<ii', output) | ||
print() | ||
print('\033[1;33maudio event detected!\033[0m') | ||
print('\033[1;33mlocation:\033[0m %s' % dump_gps(location)) | ||
print('\033[1;33mtimestamp:\033[0m %u' % int(time.time())) | ||
print() | ||
|
||
break | ||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser( | ||
description='Poll for audio event triangulation results') | ||
parser.add_argument('policy', | ||
help='Veracruz policy file (.json)') | ||
parser.add_argument('--identity', required=True, | ||
help='Identity of client (.pem)') | ||
parser.add_argument('--key', required=True, | ||
help='Private key of client (.pem)') | ||
parser.add_argument('--program', required=True, | ||
help='Path to audio event triangulation binary (.wasm)') | ||
args = parser.parse_args() | ||
main(args) |
177 changes: 177 additions & 0 deletions
177
sdk/rust-examples/audio-event-triangulation/src/main.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
//! An implementation of triangulation of audio event data | ||
//! | ||
//! This demo takes in audio events in the form of a timestamp, | ||
//! GPS coordinates, and an analog rich audio sample, calculates the | ||
//! best effort triangulated location, returning the estimated location | ||
//! | ||
//! ## Authors | ||
//! | ||
//! The Veracruz Development Team. | ||
//! | ||
//! ## Copyright | ||
//! | ||
//! See the file `LICENSING.markdown` in the Veracruz root directory for licensing | ||
//! and copyright information. | ||
use anyhow; | ||
use std::{ | ||
convert::TryInto, | ||
fs, | ||
io, | ||
}; | ||
use thiserror::Error; | ||
|
||
/// An individual audio event | ||
struct AudioEvent { | ||
/// Timestamp of when even occured (currently unused) | ||
#[allow(dead_code)] | ||
timestamp: u32, | ||
/// Location in 32-bit signed GPS coordinates | ||
location: (i32, i32), | ||
/// Samples in signed 16-bit PCM, bitrate is assumed to be | ||
/// consistent for all samples | ||
samples: Vec<i16>, | ||
} | ||
|
||
#[derive(Error, Debug)] | ||
pub enum AudioEventError { | ||
#[error("Unable to decode audio event")] | ||
InvalidAudioEvent, | ||
} | ||
|
||
impl AudioEvent { | ||
/// Compute the power of the audio event, larger+closer audio | ||
/// events result in higher power | ||
fn power(&self) -> f64 { | ||
// compute as avg per single sample, assumes common bitrate | ||
let mut p: f64 = 0.0; | ||
for x in self.samples.iter() { | ||
p += x.abs() as f64; | ||
} | ||
|
||
p.checked_div(self.samples.len() as f64).unwrap_or(0) | ||
} | ||
} | ||
|
||
/// Decode an audio event from raw little-endian bytes | ||
/// | ||
/// This uses a simple fixed encoding scheme: | ||
/// [ u32 timestamp ] | ||
/// [ i32 device X GPS coord ] | ||
/// [ i32 device Y GPS coord ] | ||
/// [ i16 PCM audio window ] | ||
/// [ i16 ] | ||
/// [ i16 ] | ||
/// [ ... ] | ||
/// | ||
fn decode_audio_event(event: &[u8]) -> anyhow::Result<AudioEvent> { | ||
if event.len() < 12 || event.len() % 2 != 0 { | ||
Err(AudioEventError::InvalidAudioEvent)?; | ||
} | ||
|
||
Ok(AudioEvent{ | ||
timestamp: u32::from_le_bytes(event[0..4].try_into().unwrap()), | ||
location: ( | ||
i32::from_le_bytes(event[4.. 8].try_into().unwrap()), | ||
i32::from_le_bytes(event[8..12].try_into().unwrap()) | ||
), | ||
samples: (12..event.len()).step_by(2) | ||
.map(|i| i16::from_le_bytes(event[i..i+2].try_into().unwrap())) | ||
.collect::<Vec<_>>() | ||
}) | ||
} | ||
|
||
/// Find the best effort triangulation of audio events | ||
/// using measured signal power to estimate distance | ||
/// | ||
/// Note! This is a fairly naive solution, using only 3 events | ||
/// leaves us with farily low confidence. We also don't take | ||
/// things like the curvature of the earth into account, so | ||
/// this should only be used for demo purposes | ||
/// | ||
fn triangulate(events: &[AudioEvent]) -> (i32, i32) { | ||
// solving | ||
// (x−x1)^2 + (y−y1)^2 = d1^2 | ||
// (x−x2)^2 + (y−y2)^2 = d2^2 | ||
// (x−x3)^2 + (y−y3)^2 = d3^2 | ||
// | ||
// let | ||
// a = (-2x1 + 2x2) | ||
// b = (-2y1 + 2y2) | ||
// c = d1^2-d2^2 - x1^2+x2^2 - y1^2+y2^2 | ||
// d = (-2x2 + 2x3) | ||
// e = (-2y2 + 2y3) | ||
// f = d2^2-d3^2 - x2^2+x3^2 - y2^2+y3^2 | ||
// | ||
// gives us | ||
// x = (ce - fb) / (ea - bd) | ||
// y = (cd - af) / (bd - ae) | ||
// | ||
let (y1, x1) = events[0].location; | ||
let (y2, x2) = events[1].location; | ||
let (y3, x3) = events[2].location; | ||
let (y1, x1) = (y1 as f64, x1 as f64); | ||
let (y2, x2) = (y2 as f64, x2 as f64); | ||
let (y3, x3) = (y3 as f64, x3 as f64); | ||
let d1 = events[0].power(); | ||
let d2 = events[1].power(); | ||
let d3 = events[2].power(); | ||
|
||
let a = -2.0*x1 + 2.0*x2; | ||
let b = -2.0*y1 + 2.0*y2; | ||
let c = d1.powf(2.0)-d2.powf(2.0) - x1.powf(2.0)+x2.powf(2.0) - y1.powf(2.0)+y2.powf(2.0); | ||
let d = -2.0*x2 + 2.0*x3; | ||
let e = -2.0*y2 + 2.0*y3; | ||
let f = d2.powf(2.0)-d3.powf(2.0) - x2.powf(2.0)+x3.powf(2.0) - y2.powf(2.0)+y3.powf(2.0); | ||
|
||
let x = (c*e - f*b) / (e*a - b*d); | ||
let y = (c*d - a*f) / (b*d - a*e); | ||
|
||
(y as i32, x as i32) | ||
} | ||
|
||
/// Encode a pair of latitude/longitude GPS coordinates into | ||
/// little-endian bytes | ||
fn encode_location(location: (i32, i32)) -> Vec<u8> { | ||
location.0.to_le_bytes().iter() | ||
.chain(location.1.to_le_bytes().iter()) | ||
.map(|x| *x) | ||
.collect::<Vec<_>>() | ||
} | ||
|
||
/// entry point | ||
fn main() -> anyhow::Result<()> { | ||
// read all inputs, note we don't know | ||
// how many there are, so we keep trying until | ||
// an input errors | ||
let mut raw_events = Vec::new(); | ||
for i in 0.. { | ||
let filename = format!("/input-{}", i); | ||
let event = match fs::read(filename) { | ||
Ok(event) => event, | ||
Err(err) => { | ||
match err.kind() { | ||
io::ErrorKind::NotFound | io::ErrorKind::PermissionDenied => break, | ||
_ => Err(err)?, | ||
} | ||
} | ||
}; | ||
|
||
raw_events.push(event); | ||
} | ||
|
||
// decode | ||
let events = raw_events.iter() | ||
.map(|raw_event| decode_audio_event(&raw_event[..])) | ||
.collect::<Result<Vec<_>, _>>()?; | ||
|
||
// triangulate | ||
let location = triangulate(&events); | ||
|
||
// encode | ||
let raw_location = encode_location(location); | ||
|
||
// write our output through libveracruz | ||
fs::write("/output", &raw_location)?; | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# intermediary directories | ||
build/ | ||
example/ | ||
test-data/ | ||
# this must be copied over from the transport-protocol crate | ||
transport_protocol.proto | ||
# these are all autogenerated | ||
transport_protocol.pb.c | ||
transport_protocol.pb.h | ||
policy.c | ||
policy.h | ||
samples/audio-event-triangulation/clap.c | ||
samples/audio-event-triangulation/clap.h | ||
samples/shamir-secret-sharing/binary.h | ||
samples/shamir-secret-sharing/binary.c | ||
# output from reports | ||
massif.out | ||
rom_report.txt | ||
static_ram_report.txt | ||
dyn_ram_report.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "nanopb"] | ||
path = nanopb | ||
url = https://github.com/nanopb/nanopb |
Oops, something went wrong.