Skip to content

Commit cfb5e33

Browse files
committed
Initial commit
0 parents  commit cfb5e33

File tree

9 files changed

+277
-0
lines changed

9 files changed

+277
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target
2+
**/*.rs.bk

Cargo.lock

+106
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "frakegps"
3+
version = "0.1.0"
4+
authors = ["Francesco Frassinelli <fraph24@gmail.com>"]
5+
edition = "2018"
6+
7+
[dependencies]
8+
time = "0.1"
9+
web-view = "0.4.1"

README.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Description
2+
3+
FrakeGPS simulates a simple GPS receiver which emits NMEA codes. The location is selected clicking on a map, using [web-view](https://github.com/Boscop/web-view) and [Leaflet](http://leafletjs.com/).
4+
5+
![frakegps-gpsmon](https://user-images.githubusercontent.com/4068/58375414-ba3b3900-7f52-11e9-88bb-c6db1299eff0.png)
6+
7+
# Build
8+
9+
## Dependencies
10+
11+
- cargo
12+
- gpsd
13+
- webkit2gtk (devel)
14+
15+
### Fedora
16+
17+
```
18+
dnf install cargo gpsd webkit2gtk3-devel
19+
```
20+
21+
## Compile
22+
23+
```
24+
cargo build
25+
```
26+
27+
# Usage
28+
29+
## Usage with gpsd
30+
31+
```
32+
./target/debug/frakegps |& gpsd -n -N /dev/stdin
33+
```
34+
35+
## Usage with geoclue
36+
37+
```
38+
./target/debug/frakegps |& nc -kl 10110
39+
avahi-publish -s "FrakeGPS for $(hostname)" _nmea-0183._tcp 10110 "FrakeGPS service"
40+
```
41+
42+
Note: Unreliable results with avahi.

src/dist/map.css

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
body {
2+
margin: 0;
3+
height: 100vh;
4+
display: flex;
5+
flex-direction: column;
6+
}
7+
#map {
8+
flex-grow: 1;
9+
width: 100%;
10+
}

src/dist/map.html

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>FrakeGPS</title>
5+
<meta charset="utf-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
8+
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
9+
<script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js" integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og==" crossorigin=""></script>
10+
{styles}
11+
</head>
12+
<body>
13+
<div id="map"></div>
14+
{scripts}
15+
</body>
16+
</html>
17+

src/dist/map.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
var map = L.map('map').setView([63.42682, 10.40163], 13);
2+
3+
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
4+
maxZoom: 18,
5+
attribution: 'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors',
6+
id: 'osm.standard'
7+
}).addTo(map);
8+
9+
var maker = L.marker();
10+
map.on('click', function(event) {
11+
maker.remove()
12+
maker = L.marker(event.latlng);
13+
maker.addTo(map);
14+
external.invoke([event.latlng.lat, event.latlng.lng]);
15+
});

src/main.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
mod nmea;
2+
3+
extern crate web_view;
4+
use web_view::*;
5+
6+
fn main() -> WVResult {
7+
let html = format!(include_str!("dist/map.html"),
8+
styles = inline_style(include_str!("dist/map.css")),
9+
scripts = inline_script(include_str!("dist/map.js")),
10+
);
11+
let webview = web_view::builder()
12+
.title("FrakeGPS")
13+
.content(Content::Html(html))
14+
.size(800, 600)
15+
.resizable(true)
16+
.debug(true)
17+
.user_data(())
18+
.invoke_handler(|_webview, arg| {
19+
let latlon: Vec<&str> = arg.split(",").collect();
20+
let lat: f64 = latlon[0].parse().unwrap();
21+
let lon: f64 = latlon[1].parse().unwrap();
22+
println!("{}", nmea::rmc(lat, lon));
23+
Ok(())
24+
})
25+
.build()?;
26+
webview.run()
27+
}
28+
29+
fn inline_style(s: &str) -> String {
30+
format!(r#"<style type="text/css">{}</style>"#, s)
31+
}
32+
33+
fn inline_script(s: &str) -> String {
34+
format!(r#"<script type="text/javascript">{}</script>"#, s)
35+
}

src/nmea.rs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
extern crate time;
2+
3+
fn dec_to_dm(dec: f64) -> f64 {
4+
let deg = dec.abs().floor();
5+
let min = (dec-deg)*60.0/100.0;
6+
deg+min
7+
}
8+
9+
fn checksum(message: &String) -> String {
10+
let mut checksum = 0;
11+
for character in message.bytes() {
12+
checksum ^= character;
13+
}
14+
format!("{:02X}", checksum)
15+
}
16+
17+
pub fn rmc(lat: f64, lon: f64) -> String {
18+
let lat_nmea = format!("{:08.3}", dec_to_dm(lat)*100.0);
19+
let lon_nmea = format!("{:09.3}", dec_to_dm(lon)*100.0);
20+
let ns = if lat.is_sign_negative() { 'S' } else { 'N' };
21+
let ew = if lon.is_sign_negative() { 'W' } else { 'E' };
22+
let now = time::now_utc();
23+
let date = now.strftime("%d%m%y").unwrap();
24+
let timestamp = now.strftime("%H%M%S").unwrap();
25+
let message = [
26+
"GPRMC",
27+
&timestamp.to_string(),
28+
"A", // A: valid, V: invalid
29+
&lat_nmea,
30+
&ns.to_string(),
31+
&lon_nmea,
32+
&ew.to_string(),
33+
"0", // speed over ground (knots)
34+
"0", // course over ground (degrees)
35+
&date.to_string(),
36+
"", // magnetic variation (degrees)
37+
"", // E/W (east/west)
38+
].join(",");
39+
let checksum = checksum(&message);
40+
format!("${}*{}", message, checksum)
41+
}

0 commit comments

Comments
 (0)