Files
adcs_api
cbor_protocol
channel_protocol
clyde_3g_eps_api
clyde_3g_eps_service
comms_service
db_test
eps_api
example_rust_c_service
example_rust_service
extern_lib
file_protocol
file_service
iobc_supervisor_service
isis_ants
isis_ants_api
isis_ants_service
isis_imtq_api
isis_iobc_supervisor
kubos_app
kubos_app_service
kubos_build_helper
kubos_file_client
kubos_service
kubos_shell_client
kubos_system
kubos_telemetry_db
large_download
large_upload
local_comms_service
mai400
mai400_api
mai400_service
monitor_service
novatel_oem6_api
novatel_oem6_service
nsl_duplex_d2
nsl_duplex_d2_comms_service
obc_hs
radio_api
rust_i2c
rust_mission_app
rust_uart
scheduler_service
serial_comms_service
shell_protocol
shell_service
telemetry_service
uart_comms_client
udp_client
utils
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//
// Copyright (C) 2018 Kubos Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License")
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use kubos_telemetry_db::Database;
use log::{error, info};
use serde::Deserialize;
use std::net::{SocketAddr, UdpSocket};
use std::sync::{Arc, Mutex};

pub struct DirectUdp {
    db: Arc<Mutex<Database>>,
}

#[derive(Debug, Deserialize)]
struct DataPoint {
    timestamp: Option<f64>,
    subsystem: String,
    parameter: String,
    value: String,
}

impl DirectUdp {
    pub fn new(db: Arc<Mutex<Database>>) -> Self {
        DirectUdp { db }
    }

    pub fn start(&self, url: String) {
        let socket = UdpSocket::bind(url.parse::<SocketAddr>().unwrap_or_else(|err| {
            error!(
                "Couldn't start direct UDP connection. Failed to parse {}: {:?}",
                url, err
            );
            panic!()
        }))
        .unwrap_or_else(|err| {
            error!(
                "Couldn't start direct UDP connection. Failed to bind {}: {:?}",
                url, err
            );
            panic!()
        });

        info!("Direct UDP listening on: {}", socket.local_addr().unwrap());

        loop {
            // Wait for an incoming message
            let mut buf = [0; 4096];
            let (size, _peer) = socket
                .recv_from(&mut buf)
                .map_err(|err| format!("Failed to receive a message: {}", err))
                .unwrap();

            if let Ok(val) = serde_json::from_slice::<DataPoint>(&buf[0..(size)]) {
                if let Err(err) = self.process(&val) {
                    error!("Error {:?} storing message {:?}", err, val);
                }
            } else if let Ok(vec) = serde_json::from_slice::<Vec<DataPoint>>(&buf[0..(size)]) {
                for val in vec.iter() {
                    if let Err(err) = self.process(&val) {
                        error!("Error {:?} storing message {:?}", err, val);
                    }
                }
            } else {
                error!(
                    "Couldn't deserialize JSON object or object array from {:?}",
                    String::from_utf8_lossy(&buf[0..(size)].to_vec())
                );
            }
        }
    }

    fn process(&self, message: &DataPoint) -> Result<(), String> {
        if let Some(time) = message.timestamp {
            self.db
                .lock()
                .map_err(|err| {
                    error!("udp - Failed to get lock on database: {}", err);
                    format!("{}", err)
                })?
                .insert(time, &message.subsystem, &message.parameter, &message.value)
                .map_err(|err| {
                    error!("udp - Failed to get lock on database: {}", err);
                    format!("{}", err)
                })?;
        } else {
            self.db
                .lock()
                .map_err(|err| {
                    error!("udp - Failed to get lock on database: {}", err);
                    format!("{}", err)
                })?
                .insert_systime(&message.subsystem, &message.parameter, &message.value)
                .map_err(|err| {
                    error!("udp - Failed to get lock on database: {}", err);
                    format!("{}", err)
                })?;
        }

        Ok(())
    }
}