Skip to content

Commit

Permalink
Standby/Transmit, rotation speed
Browse files Browse the repository at this point in the history
  • Loading branch information
keesverruijt committed Sep 16, 2024
1 parent 8383230 commit ca672fa
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 53 deletions.
15 changes: 15 additions & 0 deletions src/navico/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub const REQUEST_03_REPORT: [u8; 2] = [0x04, 0xc2]; // This causes the radar to
pub const REQUEST_MANY2_REPORT: [u8; 2] = [0x01, 0xc2]; // This causes the radar to report Report 02, 03, 04, 07 and 08
pub const _REQUEST_04_REPORT: [u8; 2] = [0x02, 0xc2]; // This causes the radar to report Report 4
pub const _REQUEST_02_08_REPORT: [u8; 2] = [0x03, 0xc2]; // This causes the radar to report Report 2 and Report 8
const COMMAND_STAY_ON_A: [u8; 2] = [0xa0, 0xc1];

pub struct Command {
key: String,
Expand Down Expand Up @@ -127,6 +128,13 @@ impl Command {
let mut cmd = Vec::with_capacity(6);

match cv.id {
ControlType::Status => {
cmd.extend_from_slice(&[0x00, 0xc1, 0x01]);
self.send(&cmd).await?;
cmd.clear();
cmd.extend_from_slice(&[0x01, 0xc1, value as u8 - 1]);
}

ControlType::Range => {
let decimeters: i32 = self.valid_range(value) * 10;
log::trace!("range {value} -> {decimeters}");
Expand Down Expand Up @@ -269,4 +277,11 @@ impl Command {
}
Ok(())
}

pub(super) async fn send_report_requests(&mut self) -> Result<(), RadarError> {
self.send(&REQUEST_03_REPORT).await?;
self.send(&REQUEST_MANY2_REPORT).await?;
self.send(&COMMAND_STAY_ON_A).await?;
Ok(())
}
}
86 changes: 43 additions & 43 deletions src/navico/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bincode::deserialize;
use log::{debug, trace, warn};
use protobuf::Message;
use serde::Deserialize;
use std::time::{SystemTime, UNIX_EPOCH};
use std::time::{Instant, SystemTime, UNIX_EPOCH};
use std::{io, time::Duration};
use tokio::net::UdpSocket;
use tokio::sync::mpsc::Receiver;
Expand All @@ -14,6 +14,7 @@ use crate::navico::NAVICO_SPOKE_LEN;
use crate::protos::RadarMessage::radar_message::Spoke;
use crate::protos::RadarMessage::RadarMessage;
use crate::radar::*;
use crate::settings::{ControlMessage, ControlType, ControlValue};
use crate::util::{create_multicast, PrintableSpoke};

use super::{
Expand Down Expand Up @@ -118,15 +119,17 @@ pub struct NavicoDataReceiver {
sock: Option<UdpSocket>,
rx: tokio::sync::mpsc::Receiver<DataUpdate>,
doppler: DopplerMode,
legend: Option<Legend>,
pixel_to_blob: Option<[[u8; BYTE_LOOKUP_LENGTH]; LOOKUP_SPOKE_LENGTH]>,
pixel_to_blob: [[u8; BYTE_LOOKUP_LENGTH]; LOOKUP_SPOKE_LENGTH],
replay: bool,
rotation_timestamp: Instant,
}

impl NavicoDataReceiver {
pub fn new(info: RadarInfo, rx: Receiver<DataUpdate>, replay: bool) -> NavicoDataReceiver {
let key = info.key();

let pixel_to_blob = Self::pixel_to_blob(&info.legend);

NavicoDataReceiver {
key,
statistics: Statistics { broken_packets: 0 },
Expand All @@ -135,9 +138,9 @@ impl NavicoDataReceiver {
sock: None,
rx,
doppler: DopplerMode::None,
legend: None,
pixel_to_blob: None,
pixel_to_blob,
replay,
rotation_timestamp: Instant::now(),
}
}

Expand All @@ -162,7 +165,7 @@ impl NavicoDataReceiver {
}
}

fn fill_pixel_to_blob(&mut self, legend: &Legend) {
fn pixel_to_blob(legend: &Legend) -> [[u8; BYTE_LOOKUP_LENGTH]; LOOKUP_SPOKE_LENGTH] {
let mut lookup: [[u8; BYTE_LOOKUP_LENGTH]; LOOKUP_SPOKE_LENGTH] =
[[0; BYTE_LOOKUP_LENGTH]; LOOKUP_SPOKE_LENGTH];
// Cannot use for() in const expr, so use while instead
Expand Down Expand Up @@ -193,7 +196,7 @@ impl NavicoDataReceiver {
};
j += 1;
}
self.pixel_to_blob = Some(lookup);
lookup
}

fn handle_data_update(&mut self, r: Option<DataUpdate>) {
Expand All @@ -202,8 +205,8 @@ impl NavicoDataReceiver {
self.doppler = doppler;
}
Some(DataUpdate::Legend(legend)) => {
self.fill_pixel_to_blob(&legend);
self.legend = Some(legend);
self.pixel_to_blob = Self::pixel_to_blob(&legend);
self.info.legend = legend;
}
None => {}
}
Expand Down Expand Up @@ -274,36 +277,38 @@ impl NavicoDataReceiver {

trace!("Received UDP frame with {} spokes", &scanlines_in_packet);

let mut mark_full_rotation = false;
let mut message = RadarMessage::new();
message.radar = 1;
if let Some(pixel_to_blob) = self.pixel_to_blob {
let mut offset: usize = FRAME_HEADER_LENGTH;
for scanline in 0..scanlines_in_packet {
let header_slice = &data[offset..offset + RADAR_LINE_HEADER_LENGTH];
let spoke_slice = &data[offset + RADAR_LINE_HEADER_LENGTH
..offset + RADAR_LINE_HEADER_LENGTH + RADAR_LINE_DATA_LENGTH];

if let Some((range, angle, heading)) = self.validate_header(header_slice, scanline)
{
trace!("range {} angle {} heading {:?}", range, angle, heading);
trace!(
"Received {:04} spoke {}",
scanline,
PrintableSpoke::new(spoke_slice)
);
message.spokes.push(self.process_spoke(
&pixel_to_blob,
range,
angle,
heading,
spoke_slice,
));
} else {
warn!("Invalid spoke: header {:02X?}", &header_slice);
self.statistics.broken_packets += 1;

let mut offset: usize = FRAME_HEADER_LENGTH;
for scanline in 0..scanlines_in_packet {
let header_slice = &data[offset..offset + RADAR_LINE_HEADER_LENGTH];
let spoke_slice = &data[offset + RADAR_LINE_HEADER_LENGTH
..offset + RADAR_LINE_HEADER_LENGTH + RADAR_LINE_DATA_LENGTH];

if let Some((range, angle, heading)) = self.validate_header(header_slice, scanline) {
trace!("range {} angle {} heading {:?}", range, angle, heading);
trace!(
"Received {:04} spoke {}",
scanline,
PrintableSpoke::new(spoke_slice)
);
message
.spokes
.push(self.process_spoke(range, angle, heading, spoke_slice));
if angle < 2 {
mark_full_rotation = true;
}
offset += RADAR_LINE_LENGTH;
} else {
warn!("Invalid spoke: header {:02X?}", &header_slice);
self.statistics.broken_packets += 1;
}
offset += RADAR_LINE_LENGTH;
}

if mark_full_rotation {
self.info.full_rotation();
}

let mut bytes = Vec::new();
Expand Down Expand Up @@ -406,14 +411,9 @@ impl NavicoDataReceiver {
Some((range, angle, heading))
}

fn process_spoke(
&self,
pixel_to_blob: &[[u8; BYTE_LOOKUP_LENGTH]; LOOKUP_SPOKE_LENGTH],
range: u32,
angle: u16,
heading: Option<u16>,
spoke: &[u8],
) -> Spoke {
fn process_spoke(&self, range: u32, angle: u16, heading: Option<u16>, spoke: &[u8]) -> Spoke {
let pixel_to_blob = &self.pixel_to_blob;

// Convert the spoke data to bytes
let mut generic_spoke: Vec<u8> = Vec::with_capacity(NAVICO_SPOKE_LEN);
let low_nibble_index = (match self.doppler {
Expand Down
12 changes: 6 additions & 6 deletions src/navico/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,17 +412,17 @@ impl NavicoReportReceiver {
self.info.set_refresh(&cv.id);
}
}
ControlMessage::SetValue(cv) => {
self.info.set_string(&cv.id, cv.value.clone()).unwrap();
self.radars.update(&self.info);
return Ok(());
}
}
Ok(())
}

async fn send_report_requests(&mut self) -> Result<(), RadarError> {
self.command_sender
.send(&command::REQUEST_03_REPORT)
.await?;
self.command_sender
.send(&command::REQUEST_MANY2_REPORT)
.await?;
self.command_sender.send_report_requests().await?;
self.report_request_timeout += self.report_request_interval;
Ok(())
}
Expand Down
7 changes: 7 additions & 0 deletions src/navico/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ impl NavicoControls {
.unit("h"),
);

controls.insert(
ControlType::RotationSpeed,
Control::new_numeric(ControlType::RotationSpeed, 0, 990)
.read_only(true)
.unit("dRPM"),
);

controls.insert(
ControlType::FirmwareVersion,
Control::new_string(ControlType::FirmwareVersion),
Expand Down
34 changes: 32 additions & 2 deletions src/radar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use log::info;
use protobuf::Message;
use serde::ser::{SerializeMap, Serializer};
use serde::Serialize;
use std::time::{Duration, Instant};
use std::{
collections::HashMap,
fmt::{self, Display, Write},
Expand Down Expand Up @@ -149,7 +150,7 @@ impl RangeDetection {
}
}
#[derive(Clone, Debug)]
pub struct RadarInfo {
pub(crate) struct RadarInfo {
key: String,
pub id: usize,
pub locator_id: LocatorId,
Expand All @@ -168,6 +169,7 @@ pub struct RadarInfo {
pub range_detection: Option<RangeDetection>, // if Some, then ranges are flexible, detected and persisted
pub controls: Controls, // Which controls there are, not complete in beginning
// pub update: fn(&mut RadarInfo), // When controls or model is updated
rotation_timestamp: Instant,

// Channels
pub message_tx: tokio::sync::broadcast::Sender<Vec<u8>>, // Serialized RadarMessage
Expand Down Expand Up @@ -234,6 +236,7 @@ impl RadarInfo {
protobuf_tx,
range_detection: None,
controls,
rotation_timestamp: Instant::now(),
}
}

Expand All @@ -245,6 +248,24 @@ impl RadarInfo {
self.legend = default_legend(doppler, self.pixel_values);
}

pub fn full_rotation(&mut self) {
let now = Instant::now();
let diff: Duration = now - self.rotation_timestamp;
let diff = diff.as_millis() as f64;
let rpm = format!("{:.0}", (600_000. / diff));

self.rotation_timestamp = now;

log::debug!("{}: rotation speed {} dRPM", self.key, rpm);

let _ = self
.command_tx
.send(ControlMessage::SetValue(ControlValue::new(
ControlType::RotationSpeed,
rpm,
)));
}

///
/// forward_output is activated in all starts of radars when cli args.output
/// is true:
Expand Down Expand Up @@ -354,7 +375,16 @@ impl RadarInfo {
) -> Result<Option<String>, ControlError> {
let control = {
if let Some(control) = self.controls.get_mut(control_type) {
Ok(control.set_string(value).map(|_| control.clone()))
if control.item().is_string_value {
Ok(control.set_string(value).map(|_| control.clone()))
} else {
let i = value
.parse::<i32>()
.map_err(|e| ControlError::Invalid(control_type.clone(), value))?;
control
.set_all(i, None, ControlState::Manual)
.map(|_| Some(control.clone()))
}
} else {
Err(ControlError::NotSupported(*control_type))
}
Expand Down
9 changes: 7 additions & 2 deletions src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ impl Controls {
pub enum ControlMessage {
Value(tokio::sync::mpsc::Sender<ControlValue>, ControlValue),
NewClient(tokio::sync::mpsc::Sender<ControlValue>),
SetValue(ControlValue),
}

// This is what we send back and forth to clients
Expand Down Expand Up @@ -446,7 +447,7 @@ pub(crate) struct ControlDefinition {
#[serde(flatten, skip_serializing_if = "Option::is_none")]
automatic: Option<AutomaticValue>,
#[serde(skip_serializing_if = "is_false")]
is_string_value: bool,
pub(crate) is_string_value: bool,
#[serde(skip)]
default_value: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -535,12 +536,13 @@ pub enum ControlType {
AntennaHeight,
// AntennaStarboard,
BearingAlignment,
// Orientation,
RotationSpeed,
OperatingHours,
ModelName,
FirmwareVersion,
SerialNumber,
UserName,
// Orientation,
}

impl Display for ControlType {
Expand Down Expand Up @@ -579,6 +581,7 @@ impl Display for ControlType {
// ControlType::Orientation => "Orientation",
ControlType::Rain => "Rain clutter",
ControlType::Range => "Range",
ControlType::RotationSpeed => "Rotation speed",
// ControlType::Scaling => "Scaling",
ControlType::ScanSpeed => "Fast scan",
ControlType::Sea => "Sea clutter",
Expand Down Expand Up @@ -612,6 +615,8 @@ pub enum ControlError {
TooLow(ControlType, i32, i32),
#[error("Control {0} value {1} is higher than maximum value {2}")]
TooHigh(ControlType, i32, i32),
#[error("Control {0} value {1} is not a legal value")]
Invalid(ControlType, String),
#[error("Control {0} does not support Auto")]
NoAuto(ControlType),
}
Expand Down

0 comments on commit ca672fa

Please sign in to comment.