Adding support for os display
This commit is contained in:
1231
Cargo.lock
generated
1231
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
17
Cargo.toml
@@ -6,21 +6,26 @@ edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[target.armv7-unknown-linux-gnueabihf.dependencies]
|
||||
rppal = "0.13.1"
|
||||
|
||||
[target.x86_64-apple-darwin.dependencies]
|
||||
minifb = "0.20"
|
||||
|
||||
[dependencies]
|
||||
rppal = "0.11.3"
|
||||
image = "*"
|
||||
imageproc = "*"
|
||||
image = "0.23.14"
|
||||
imageproc = "0.22.0"
|
||||
arrayref = "*"
|
||||
chrono = { version = "*", features = [ "serde" ] }
|
||||
chrono-tz = "*"
|
||||
euclid = "*"
|
||||
log = "*"
|
||||
log4rs = { version = "*", features = ["file", "yaml_format", "console_appender"] }
|
||||
xml-rs = "0.8"
|
||||
text_io = "0.1.8"
|
||||
xml-rs = "*"
|
||||
text_io = "*"
|
||||
serde = { version = "*", features = ["derive"] }
|
||||
serde_json = "*"
|
||||
rusttype = "0.9.2"
|
||||
rusttype = "*"
|
||||
tungstenite = { version = "*", default-features = false }
|
||||
url = "*"
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<svg baseProfile="tiny" height="1000" version="1.2" width="1000" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink"><defs /><line stroke="rgb(255,255,255)" stroke-width="6" x1="500.0" x2="500.0" y1="800.0" y2="900.0" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="712.132" x2="782.8427" y1="712.132" y2="782.8427" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="800.0" x2="900.0" y1="500.0" y2="500.0" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="712.132" x2="782.8427" y1="287.868" y2="217.1573" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="500.0" x2="500.0" y1="200.0" y2="100.0" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="287.868" x2="217.1573" y1="287.868" y2="217.1573" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="200.0" x2="100.0" y1="500.0" y2="500.0" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="287.868" x2="217.1573" y1="712.132" y2="782.8427" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="614.805" x2="637.766" y1="777.1639" y2="832.5966" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="777.1639" x2="832.5966" y1="614.805" y2="637.766" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="777.1639" x2="832.5966" y1="385.195" y2="362.234" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="614.805" x2="637.766" y1="222.8361" y2="167.4034" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="385.195" x2="362.234" y1="222.8361" y2="167.4034" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="222.8361" x2="167.4034" y1="385.195" y2="362.234" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="222.8361" x2="167.4034" y1="614.805" y2="637.766" /><line stroke="rgb(255,255,255)" stroke-width="6" x1="385.195" x2="362.234" y1="777.1639" y2="832.5966" /></svg>
|
||||
<svg baseProfile="tiny" height="1000" version="1.2" width="1000" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink"><defs /><line stroke="rgb(255,255,255)" stroke-width="2" x1="500.0" x2="500.0" y1="750.0" y2="830.0" /><line stroke="rgb(255,255,255)" stroke-width="2" x1="676.7767" x2="733.3452" y1="676.7767" y2="733.3452" /><line stroke="rgb(255,255,255)" stroke-width="2" x1="750.0" x2="830.0" y1="500.0" y2="500.0" /><line stroke="rgb(255,255,255)" stroke-width="2" x1="676.7767" x2="733.3452" y1="323.2233" y2="266.6548" /><line stroke="rgb(255,255,255)" stroke-width="2" x1="500.0" x2="500.0" y1="250.0" y2="170.0" /><line stroke="rgb(255,255,255)" stroke-width="2" x1="323.2233" x2="266.6548" y1="323.2233" y2="266.6548" /><line stroke="rgb(255,255,255)" stroke-width="2" x1="250.0" x2="170.0" y1="500.0" y2="500.0" /><line stroke="rgb(255,255,255)" stroke-width="2" x1="323.2233" x2="266.6548" y1="676.7767" y2="733.3452" /><line stroke="rgb(205,205,205)" stroke-width="2" x1="595.6709" x2="618.6319" y1="730.9699" y2="786.4027" /><line stroke="rgb(205,205,205)" stroke-width="2" x1="730.9699" x2="786.4027" y1="595.6709" y2="618.6319" /><line stroke="rgb(205,205,205)" stroke-width="2" x1="730.9699" x2="786.4027" y1="404.3291" y2="381.3681" /><line stroke="rgb(205,205,205)" stroke-width="2" x1="595.6709" x2="618.6319" y1="269.0301" y2="213.5973" /><line stroke="rgb(205,205,205)" stroke-width="2" x1="404.3291" x2="381.3681" y1="269.0301" y2="213.5973" /><line stroke="rgb(205,205,205)" stroke-width="2" x1="269.0301" x2="213.5973" y1="404.3291" y2="381.3681" /><line stroke="rgb(205,205,205)" stroke-width="2" x1="269.0301" x2="213.5973" y1="595.6709" y2="618.6319" /><line stroke="rgb(205,205,205)" stroke-width="2" x1="404.3291" x2="381.3681" y1="730.9699" y2="786.4027" /><polyline points="476,10 476,82" stroke="rgb(255,255,255)" stroke-width="2" /><polyline points="476,10 524,82" stroke="rgb(255,255,255)" stroke-width="2" /><polyline points="524,10 524,82" stroke="rgb(255,255,255)" stroke-width="2" /><polyline points="524,918 508,910 492,910 476,918 476,926 484,934 516,950 524,958 524,974 508,982 492,982 476,974" stroke="rgb(205,205,205)" stroke-width="2" /><polyline points="926,460 926,532" stroke="rgb(205,205,205)" stroke-width="2" /><polyline points="926,460 974,460" stroke="rgb(205,205,205)" stroke-width="2" /><polyline points="926,492 958,492" stroke="rgb(205,205,205)" stroke-width="2" /><polyline points="926,532 974,532" stroke="rgb(205,205,205)" stroke-width="2" /><polyline points="18,460 34,532" stroke="rgb(205,205,205)" stroke-width="2" /><polyline points="50,460 34,532" stroke="rgb(205,205,205)" stroke-width="2" /><polyline points="50,460 66,532" stroke="rgb(205,205,205)" stroke-width="2" /><polyline points="82,460 66,532" stroke="rgb(205,205,205)" stroke-width="2" /></svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.9 KiB |
69
src/fbdisplay.rs
Normal file
69
src/fbdisplay.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
use std::error::Error;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use minifb::{Key, ScaleMode, Window, WindowOptions};
|
||||
|
||||
use image::RgbImage;
|
||||
|
||||
pub struct MiniFB {
|
||||
buffer: Vec<u32>,
|
||||
window: Window,
|
||||
}
|
||||
|
||||
impl MiniFB {
|
||||
|
||||
|
||||
// Initialize an IliDisplay struct with defaults
|
||||
|
||||
pub fn init() -> Result<MiniFB, Box<dyn Error>> {
|
||||
|
||||
let mut buffer: Vec<u32> = Vec::with_capacity(480*320);
|
||||
buffer.resize(480*320, 0u32);
|
||||
let mut window = Window::new(
|
||||
"Helms Display ⛵️",
|
||||
480, 320,
|
||||
WindowOptions {
|
||||
resize: true,
|
||||
scale_mode: ScaleMode::AspectRatioStretch,
|
||||
..WindowOptions::default()
|
||||
},
|
||||
).unwrap();
|
||||
|
||||
return Ok(MiniFB {
|
||||
buffer, window
|
||||
});
|
||||
}
|
||||
|
||||
pub fn init_chip(&mut self) {
|
||||
}
|
||||
|
||||
pub fn turn_on (&mut self) {
|
||||
}
|
||||
|
||||
pub fn turn_off (&mut self) {
|
||||
}
|
||||
|
||||
pub fn put_image(&mut self, image: &RgbImage, (x, y): (u32, u32)) -> () {
|
||||
let (w, h) = image.dimensions();
|
||||
let imagedata = image.as_raw();
|
||||
let mut offset: usize = x as usize + ((y as usize)*480);
|
||||
let mut i = 0;
|
||||
for line in 0..h {
|
||||
let toffset = offset;
|
||||
for p in 0..w {
|
||||
self.buffer[offset] = ((imagedata[i] as u32) << 16) | ((imagedata[i+1] as u32) << 8) | imagedata[i+2] as u32;
|
||||
i = i + 3;
|
||||
offset += 1;
|
||||
}
|
||||
offset = toffset + 480;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self) -> () {
|
||||
self.window.update_with_buffer(&self.buffer, 480, 320);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::cmp;
|
||||
use euclid::{Angle, Scale, Transform2D, Vector2D};
|
||||
use image::{Rgb, RgbImage};
|
||||
use image::{Rgb, GenericImage, RgbImage};
|
||||
use imageproc::drawing::{draw_line_segment_mut, draw_text_mut};
|
||||
|
||||
use std::str::FromStr;
|
||||
@@ -105,7 +105,7 @@ impl Screen {
|
||||
|
||||
pub fn text (&mut self, font: &Font, text: &str, scale: f32, x: u16, y: u16) {
|
||||
let scale = rusttype::Scale { x: scale, y: scale };
|
||||
draw_text_mut(&mut self.image, Rgb([255, 255, 255]), x as u32, y as u32, scale, &font, text);
|
||||
draw_text_mut(&mut self.image, Rgb([255u8, 255u8, 255u8]), x as u32, y as u32, scale, &font, text);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -155,4 +155,9 @@ impl IliDisplay {
|
||||
self.spi.write(imagedata_ref).map_err(|err| println!("SPI error in send_image: {}", err.to_string())).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self) -> () {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
101
src/main.rs
101
src/main.rs
@@ -2,6 +2,7 @@
|
||||
extern crate arrayref;
|
||||
use std::error::Error;
|
||||
use std::thread;
|
||||
use std::time::SystemTime;
|
||||
use std::time::Duration;
|
||||
use std::f32::consts::PI;
|
||||
use chrono::{DateTime, Utc};
|
||||
@@ -19,11 +20,18 @@ use image::{
|
||||
use imageproc::rect::Rect;
|
||||
use imageproc::drawing::draw_filled_rect_mut;
|
||||
|
||||
#[cfg(target = "armv7-unknown-linux-gnueabihf")]
|
||||
mod ilidisplay;
|
||||
|
||||
#[cfg(not(target = "armv7-unknown-linux-gnueabihf"))]
|
||||
mod fbdisplay;
|
||||
|
||||
mod forms;
|
||||
mod signalk;
|
||||
mod vesseldata;
|
||||
use vesseldata::VesselDataEventSource;
|
||||
use vesseldata::VesselDataEvent;
|
||||
use vesseldata::VesselDataState;
|
||||
|
||||
pub struct HelmsDisplay {
|
||||
font: Font<'static>,
|
||||
@@ -41,12 +49,12 @@ impl HelmsDisplay {
|
||||
pub fn new() -> HelmsDisplay {
|
||||
// in the future, this method should probably take some sort of
|
||||
// configuration object.
|
||||
let mut loader = forms::Loader::new("/root/helms-display".to_string());
|
||||
let mut loader = forms::Loader::new("/Users/jdalsgaard/src/helms-display/media".to_string());
|
||||
let boat = loader.load_form("boat.svg").unwrap();
|
||||
let compassrose = loader.load_form("compass-rose.svg").unwrap();
|
||||
let cog = loader.load_form("cog.svg").unwrap();
|
||||
let wind = loader.load_form("wind.svg").unwrap();
|
||||
let font = loader.load_font("font.ttf").unwrap();
|
||||
let font = loader.load_font("DejaVuSans-2_37.ttf").unwrap();
|
||||
|
||||
HelmsDisplay {
|
||||
font: font,
|
||||
@@ -69,46 +77,48 @@ impl HelmsDisplay {
|
||||
self.gps_screen.clear();
|
||||
|
||||
// format with unicodes for degrees, minutes and seconds.
|
||||
let (latitude, lat_ew) = {
|
||||
let (latitude, lat_ns) = {
|
||||
if lat < 0.0 {
|
||||
(-lat, 'W')
|
||||
(-lat, 'S')
|
||||
} else if lat > 0.0 {
|
||||
(lat, 'E')
|
||||
(lat, 'N')
|
||||
} else {
|
||||
(0.0, '-')
|
||||
}
|
||||
};
|
||||
|
||||
let (longitude, long_ns) = {
|
||||
let (longitude, long_ew) = {
|
||||
if lon < 0.0 {
|
||||
(-lon, 'S')
|
||||
(-lon, 'W')
|
||||
} else if lon > 0.0 {
|
||||
(lon, 'N')
|
||||
(lon, 'E')
|
||||
} else {
|
||||
(0.0, '-')
|
||||
}
|
||||
};
|
||||
|
||||
let lat_d: u8 = latitude.trunc() as u8;
|
||||
let latitude = latitude.fract() * 60.0;
|
||||
let lat_m: u8 = latitude.trunc() as u8;
|
||||
let latitude = latitude.fract() * 60.0;
|
||||
let lat_s: u8 = latitude.round() as u8;
|
||||
|
||||
let long_d: u8 = longitude.trunc() as u8;
|
||||
let longitude = longitude.fract() * 60.0;
|
||||
let long_m: u8 = longitude.trunc() as u8;
|
||||
let longitude = longitude.fract() * 60.0;
|
||||
let long_s: u8 = longitude.round() as u8;
|
||||
|
||||
let lat_d: u8 = latitude.trunc() as u8;
|
||||
let latitude = latitude.fract() * 60.0;
|
||||
let lat_m: u8 = latitude.trunc() as u8;
|
||||
let latitude = latitude.fract() * 60.0;
|
||||
let lat_s: u8 = latitude.round() as u8;
|
||||
self.gps_screen.text_c(&self.font,
|
||||
format!("{}{:02}\u{00B0}{:02}\u{2032}{:02}\u{2033} {}{:02}\u{00B0}{:02}\u{2032}{:02}\u{2033}",
|
||||
long_ns, long_d, long_m, long_s, lat_ew, lat_d, lat_m, lat_s).as_str(), 32.0, 200, 5);
|
||||
lat_ns, lat_d, lat_m, lat_s, long_ew, long_d, long_m, long_s).as_str(), 32.0, 200, 5);
|
||||
}
|
||||
|
||||
|
||||
pub fn render_time (&mut self) {
|
||||
let tz: Tz = "Europe/Copenhagen".parse().unwrap();
|
||||
let now = Utc::now().with_timezone(&tz);
|
||||
self.time_screen.clear();
|
||||
self.time_screen.text_c(&self.font, now.format("%H:%M:%S %Z").to_string().as_str(), 24.0, 100, 1);
|
||||
self.time_screen.text_c(&self.font, "Europe/Copenhagen", 16.0, 100, 25);
|
||||
self.time_screen.text_c(&self.font, now.format("%Y-%m-%d").to_string().as_str(), 16.0, 100, 43);
|
||||
@@ -156,48 +166,19 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut sog_screen = forms::Screen::new(160,60);
|
||||
let mut time_screen = forms::Screen::new(200, 60);
|
||||
|
||||
let mut loader = forms::Loader::new("/root/helms-display".to_string());
|
||||
|
||||
let c = loader.load_form("compass-rose.svg").unwrap();
|
||||
let b = loader.load_form("boat.svg").unwrap();
|
||||
let cog = loader.load_form("cog.svg").unwrap();
|
||||
let wind = loader.load_form("wind.svg").unwrap();
|
||||
//let font = loader.load_font("font.ttf").unwrap();
|
||||
let f2 = loader.load_font("font.ttf").unwrap();
|
||||
|
||||
let mut helms = HelmsDisplay::new();
|
||||
/*
|
||||
let mut img = RgbImage::new(480, 320);
|
||||
let thickness = 10;
|
||||
draw_filled_rect_mut(&mut img, Rect::at(0,0).of_size(240, 160), Rgb([255,0,0]));
|
||||
draw_filled_rect_mut(&mut img, Rect::at(0,160).of_size(240, 160), Rgb([0, 255, 0]));
|
||||
draw_filled_rect_mut(&mut img, Rect::at(240,0).of_size(240, 160), Rgb([0, 0, 255]));
|
||||
*/
|
||||
|
||||
#[cfg(target = "armv7-unknown-linux-gnueabihf")]
|
||||
let mut e = ilidisplay::IliDisplay::init()?;
|
||||
|
||||
#[cfg(not(target = "armv7-unknown-linux-gnueabihf"))]
|
||||
let mut e = fbdisplay::MiniFB::init()?;
|
||||
|
||||
e.init_chip();
|
||||
e.turn_on();
|
||||
|
||||
|
||||
course_screen.clear();
|
||||
let rad = (6 as f32) * 2.0*PI / 100.0;
|
||||
course_screen.clear();
|
||||
course_screen.render(&cog, -rad*2.0, 500, 500);
|
||||
course_screen.render(&wind, rad*2.0, 500, 500);
|
||||
course_screen.render(&c, rad, 500, 500);
|
||||
course_screen.render(&b, 0.0, 500, 500);
|
||||
e.put_image(&(course_screen.image), (140, (160-110)));
|
||||
|
||||
/*
|
||||
sog_screen.clear();
|
||||
sog_screen.text(&font, "SOG", 32.0, 5, 5);
|
||||
sog_screen.text(&font, "speed over ground", 12.0, 5, 38);
|
||||
let speed_over_ground = 5.0; // in m/s
|
||||
let speed_over_ground = speed_over_ground * 1.9438612860586; // now in nautic miles per hour
|
||||
sog_screen.text_rj(&font, format!("{:.1}", speed_over_ground).as_str(), 32.0, 138, 5);
|
||||
sog_screen.fraction(&font, "nm", "h", 14.0, 140, 6);
|
||||
e.put_image(&(sog_screen.image), (0, 50));
|
||||
*/
|
||||
helms.render_course(None, None, None);
|
||||
e.put_image(&(helms.course_screen.image), (140, (160-110)));
|
||||
|
||||
helms.render_no_gps();
|
||||
e.put_image(&(helms.gps_screen.image), (40,0));
|
||||
@@ -207,13 +188,23 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
|
||||
println!("Display has been rendered now, sleeping for 5s");
|
||||
let vd = signalk::SignalK::connect();
|
||||
for i in 0..9 {
|
||||
|
||||
let vd = signalk::SignalK::connect("109.57.77.80".to_string());
|
||||
let mut state = VesselDataState::init(vd);
|
||||
let mut cog: Option<f32> = None;
|
||||
let mut mag: Option<f32> = None;
|
||||
for i in 0..1000 {
|
||||
state.read_events();
|
||||
helms.render_gps(state.latitude, state.longitude);
|
||||
e.put_image(&(helms.gps_screen.image), (40,0));
|
||||
helms.render_course(Some(state.course_over_ground), Some(state.true_compass_course), Some(state.speed_through_water));
|
||||
e.put_image(&(helms.course_screen.image), (140, (160-110)));
|
||||
helms.render_time();
|
||||
e.put_image(&(helms.time_screen.image), (140,260));
|
||||
e.update();
|
||||
let passed_millis = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().subsec_millis();
|
||||
thread::sleep(Duration::from_millis(1000-passed_millis as u64))
|
||||
};
|
||||
|
||||
|
||||
thread::sleep(Duration::from_millis(15000));
|
||||
e.turn_off();
|
||||
Ok(())
|
||||
|
||||
|
||||
59
src/screen.rs
Normal file
59
src/screen.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
|
||||
trait ScreenElement {
|
||||
|
||||
/**
|
||||
* Returns whether this element has an updated value since last render.
|
||||
*/
|
||||
fn has_update(&self) -> bool;
|
||||
|
||||
/**
|
||||
* Render this element and update into Display.
|
||||
*/
|
||||
fn update(&self, Display);
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct MeterElement {
|
||||
label: String,
|
||||
value: String,
|
||||
height: u32,
|
||||
width: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
has_update: bool,
|
||||
}
|
||||
|
||||
impl MeterElement {
|
||||
|
||||
pub fn new (label: String, init_value: String, height: u32, width: u32, x: u32, y: u32) -> MeterElement {
|
||||
MeterElement {
|
||||
label, init_value, height, width, x, y, true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_value (&self, new_value: String) {
|
||||
if self.value == new_value {
|
||||
// do nothing
|
||||
return;
|
||||
} else {
|
||||
self.value = new_value;
|
||||
self.has_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl ScreenElement for MeterElement {
|
||||
|
||||
pub fn has_update(&self) -> bool {
|
||||
self.has_update
|
||||
}
|
||||
|
||||
pub fn update(&self, disp: Display) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ impl SignalK {
|
||||
"navigation.headingMagnetic" => return Some(VesselDataEvent::TrueCompassCourse(val.value.as_f64().unwrap() as f32)),
|
||||
"navigation.courseOverGroundTrue" => return Some(VesselDataEvent::CourseOverGround(val.value.as_f64().unwrap() as f32)),
|
||||
"navigation.speedOverGround" => return Some(VesselDataEvent::SpeedOverGround(val.value.as_f64().unwrap() as f32)),
|
||||
"electrical.batteries.housebattery.voltage" => return Some(VesselDataEvent::BatteryVoltage(0, val.value.as_f64().unwrap() as f32)),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
@@ -84,13 +85,13 @@ impl SignalK {
|
||||
|
||||
impl VesselDataEventSource for SignalK {
|
||||
|
||||
fn connect() -> Receiver<VesselDataEvent> {
|
||||
fn connect(host: String) -> Receiver<VesselDataEvent> {
|
||||
let (tx, rx): (Sender<VesselDataEvent>, Receiver<VesselDataEvent>) = mpsc::channel();
|
||||
let handle = thread::spawn(move || {
|
||||
let (mut socket, response) = connect(Url::parse("ws://localhost:3000/signalk/v1/stream?subscribe=self").unwrap()).expect("Can't connect");
|
||||
let (mut socket, response) = connect(Url::parse(format!("ws://{}:3000/signalk/v1/stream?subscribe=self", host).as_str()).unwrap()).expect("Can't connect");
|
||||
let header: SignalKHeader = serde_json::from_str(socket.read_message().unwrap().to_text().unwrap()).unwrap();
|
||||
if header.version != "1.33.0" {
|
||||
warn!("SignalK parser has only been tested with Signal K Server version 1.33.0");
|
||||
if header.version != "1.41.0" {
|
||||
warn!("SignalK parser has only been tested with Signal K Server version 1.41.0");
|
||||
}
|
||||
loop {
|
||||
let message = socket.read_message().unwrap();
|
||||
|
||||
@@ -17,12 +17,13 @@ pub enum VesselDataEvent {
|
||||
TrueCompassCourse(f32),
|
||||
AISVessel(String, f32, f32, f32), // Name, lat, long, speed
|
||||
BatteryLevel(u8, u8), // Bank#, percentage
|
||||
BatteryVoltage(u8, f32), // Bank#, voltage
|
||||
FuelLevel(u8), // percentage
|
||||
}
|
||||
|
||||
pub trait VesselDataEventSource {
|
||||
|
||||
fn connect() -> Receiver<VesselDataEvent>;
|
||||
fn connect(host: String) -> Receiver<VesselDataEvent>;
|
||||
}
|
||||
|
||||
impl fmt::Debug for VesselDataEvent {
|
||||
@@ -35,6 +36,7 @@ impl fmt::Debug for VesselDataEvent {
|
||||
VesselDataEvent::TrueCompassCourse(c) => f.debug_tuple("TrueCompassCourse").field(c).finish(),
|
||||
VesselDataEvent::AISVessel(name, lat, lon, speed) => f.debug_tuple("AISVessel").field(name).field(lat).field(lon).field(speed).finish(),
|
||||
VesselDataEvent::BatteryLevel(bank, level) => f.debug_tuple("BatteryLevel").field(bank).field(level).finish(),
|
||||
VesselDataEvent::BatteryVoltage(bank, voltage) => f.debug_tuple("BatteryVoltage").field(bank).field(voltage).finish(),
|
||||
VesselDataEvent::FuelLevel(level) => f.debug_tuple("FuelLevel").field(level).finish(),
|
||||
VesselDataEvent::WindOrigin(c) => f.debug_tuple("WindOrigin").field(c).finish(),
|
||||
}
|
||||
@@ -52,6 +54,7 @@ pub struct VesselDataState {
|
||||
pub true_compass_course: f32,
|
||||
pub course_over_ground: f32,
|
||||
pub position_timestamp: u64,
|
||||
pub battery_voltage: f32,
|
||||
}
|
||||
|
||||
impl VesselDataState {
|
||||
@@ -65,6 +68,7 @@ impl VesselDataState {
|
||||
true_compass_course: 0.0,
|
||||
course_over_ground: 0.0,
|
||||
position_timestamp: 0,
|
||||
battery_voltage: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +80,7 @@ impl VesselDataState {
|
||||
VesselDataEvent::Location(lat, lon) => { self.latitude = lat; self.longitude = lon; },
|
||||
VesselDataEvent::CourseOverGround(c) => self.course_over_ground = c,
|
||||
VesselDataEvent::TrueCompassCourse(c) => self.true_compass_course = c,
|
||||
VesselDataEvent::BatteryVoltage(_, u) => self.battery_voltage = u,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user