Skip to content

Commit

Permalink
static typing for commands
Browse files Browse the repository at this point in the history
  • Loading branch information
Igigog committed Oct 22, 2023
1 parent 113678d commit 1ad3990
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 42 deletions.
194 changes: 194 additions & 0 deletions src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@


use std::io::Write;

use crate::{Preprocessing, model::Filters, Codec};


pub trait Command {
fn as_buf(&self) -> Vec<u8>;
}

#[repr(u16)]
#[allow(dead_code)]
pub enum StructureTypes {
// Commands/Responses, these are container TLVs. The Value will be a set of TLV structures.
OK = 0, // Standard response when a command was successful
NOK, // Standard error response
FlashHeader, // A special container for the config stored in flash. Hopefully there is some useful
// metadata in here to allow us to migrate an old config to a new version.
GetVersion, // Returns the current config version, and the minimum supported version so clients
// can decide if they can talk to us or not.
SetConfiguration, // Updates the active configuration with the supplied TLVs
GetActiveConfiguration, // Retrieves the current active configuration TLVs from RAM
GetStoredConfiguration, // Retrieves the current stored configuration TLVs from Flash
SaveConfiguration, // Writes the active configuration to Flash
FactoryReset, // Invalidates the flash memory

// Configuration structures, these are returned in the body of a command/response
PreProcessingConfiguration = 0x200,
FilterConfiguration,
Pcm3060Configuration,

// Status structures, these are returned in the body of a command/response but they are
// not persisted as part of the configuration
VersionStatus = 0x400,
}

pub struct GetVersion();

impl GetVersion {
pub fn new() -> Self {
Self()
}
}

impl Command for GetVersion {
fn as_buf(&self) -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(&(StructureTypes::GetVersion as u16).to_le_bytes());
buf.extend_from_slice(&(4u16).to_le_bytes());
buf
}
}

pub struct SetPreprocessingConfiguration<'a>(&'a Preprocessing);

impl<'a> SetPreprocessingConfiguration<'a> {
pub fn new(preprocessing: &'a Preprocessing) -> Self {
Self(preprocessing)
}
}

impl Command for SetPreprocessingConfiguration<'_> {
fn as_buf(&self) -> Vec<u8> {
let payload = self.0.to_payload();
let mut buf = Vec::new();
buf.extend_from_slice(&(StructureTypes::PreProcessingConfiguration as u16).to_le_bytes());
buf.extend_from_slice(&((4 + payload.len()) as u16).to_le_bytes());
buf.extend_from_slice(&payload);
buf
}
}

pub struct SetFilterConfiguration<'a>(&'a Filters);

impl<'a> SetFilterConfiguration<'a> {
pub fn new(filters: &'a Filters) -> Self {
Self(filters)
}
}

impl Command for SetFilterConfiguration<'_> {
fn as_buf(&self) -> Vec<u8> {
let payload = self.0.to_payload();
let mut buf = Vec::new();
buf.extend_from_slice(&(StructureTypes::FilterConfiguration as u16).to_le_bytes());
buf.extend_from_slice(&((4 + payload.len()) as u16).to_le_bytes());
buf.extend_from_slice(&payload);
buf
}
}

pub struct SetPcm3060Configuration<'a>(&'a Codec);

impl<'a> SetPcm3060Configuration<'a> {
pub fn new(codec: &'a Codec) -> Self {
Self(codec)
}
}

impl Command for SetPcm3060Configuration<'_> {
fn as_buf(&self) -> Vec<u8> {
let payload = self.0.to_payload();
let mut buf = Vec::new();
buf.extend_from_slice(&(StructureTypes::Pcm3060Configuration as u16).to_le_bytes());
buf.extend_from_slice(&((4 + payload.len()) as u16).to_le_bytes());
buf.extend_from_slice(&payload);
buf
}
}

pub struct SetConfiguration<'a, 'b, 'c>{
preprocessing: SetPreprocessingConfiguration<'a>,
filter: SetFilterConfiguration<'b>,
codec: SetPcm3060Configuration<'c>
}

impl<'a, 'b, 'c> SetConfiguration<'a, 'b, 'c> {
pub fn new(preprocessing: SetPreprocessingConfiguration<'a>, filter: SetFilterConfiguration<'b>, codec: SetPcm3060Configuration<'c>) -> Self {
Self {
preprocessing,
filter,
codec
}
}
}

impl Command for SetConfiguration<'_, '_, '_> {
fn as_buf(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&(StructureTypes::SetConfiguration as u16).to_le_bytes());
buf.extend_from_slice(
&((16 + self.filter.0.to_payload().len()
+ self.preprocessing.0.to_payload().len()
+ self.codec.0.to_payload().len()) as u16)
.to_le_bytes(),
);
buf.extend_from_slice(&self.preprocessing.as_buf());
buf.extend_from_slice(&self.filter.as_buf());
buf.extend_from_slice(&self.codec.as_buf());
buf
}
}

pub struct FactoryReset();

impl FactoryReset {
pub fn new() -> Self {
Self()
}
}

impl Command for FactoryReset {
fn as_buf(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&(StructureTypes::FactoryReset as u16).to_le_bytes());
buf.extend_from_slice(&(4u16).to_le_bytes());
buf
}
}

pub struct SaveConfiguration();

impl SaveConfiguration {
pub fn new() -> Self {
Self()
}
}

impl Command for SaveConfiguration {
fn as_buf(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&(StructureTypes::SaveConfiguration as u16).to_le_bytes());
buf.extend_from_slice(&(4u16).to_le_bytes());
buf
}
}

pub struct GetStoredConfiguration();

impl GetStoredConfiguration {
pub fn new() -> Self {
Self()
}
}

impl Command for GetStoredConfiguration {
fn as_buf(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&(StructureTypes::GetStoredConfiguration as u16).to_le_bytes());
buf.extend_from_slice(&(4u16).to_le_bytes());
buf
}
}
64 changes: 23 additions & 41 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use byteorder::{LittleEndian, ReadBytesExt};
use commands::Command;
use commands::FactoryReset;
use commands::GetStoredConfiguration;
use commands::GetVersion;
use commands::SaveConfiguration;
use commands::SetConfiguration;
use commands::SetFilterConfiguration;
use commands::SetPcm3060Configuration;
use commands::SetPreprocessingConfiguration;
use model::Filter;
use model::Filters;
use model::StructureTypes;
Expand Down Expand Up @@ -30,6 +39,7 @@ use std::fs::File;
use tauri::PathResolver;

mod model;
mod commands;

pub const LIBUSB_RECIPIENT_DEVICE: u8 = 0x00;
pub const LIBUSB_REQUEST_TYPE_VENDOR: u8 = 0x02 << 5;
Expand Down Expand Up @@ -115,7 +125,7 @@ fn find_configuration_endpoints<T: UsbContext>(
}

#[derive(Serialize, Deserialize, Default, Debug)]
struct Preprocessing {
pub struct Preprocessing {
preamp: f32,
postEQGain: f32,
reverse_stereo: bool,
Expand Down Expand Up @@ -149,7 +159,7 @@ impl Preprocessing {
}

#[derive(Serialize, Deserialize, Default, Debug)]
struct Codec {
pub struct Codec {
oversampling: bool,
phase: bool,
rolloff: bool,
Expand Down Expand Up @@ -229,8 +239,9 @@ impl VersionInfo {

fn send_cmd(
connection_state: State<'_, Mutex<ConnectionState>>,
buf: &[u8],
cmd: impl Command,
) -> Result<[u8; MAX_CFG_LEN], String> {
let buf = cmd.as_buf();
let mut connection = connection_state.lock().unwrap();

let device = match &connection.connected {
Expand Down Expand Up @@ -289,37 +300,16 @@ fn write_config(
config: Config,
connection_state: State<'_, Mutex<ConnectionState>>,
) -> Result<bool, String> {
info!("write_config");
println!("write_config");
let filter_payload: Vec<u8> = config.filters.to_payload();
let preprocessing_payload: Vec<u8> = config.preprocessing.to_payload();
let codec_payload = config.codec.to_payload();

let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&(StructureTypes::SetConfiguration as u16).to_le_bytes());
buf.extend_from_slice(
&((16 + filter_payload.len() + preprocessing_payload.len() + codec_payload.len()) as u16)
.to_le_bytes(),
);
buf.extend_from_slice(&(StructureTypes::PreProcessingConfiguration as u16).to_le_bytes());
buf.extend_from_slice(&((4 + preprocessing_payload.len()) as u16).to_le_bytes());
buf.extend_from_slice(&preprocessing_payload);
buf.extend_from_slice(&(StructureTypes::FilterConfiguration as u16).to_le_bytes());
buf.extend_from_slice(&((4 + filter_payload.len()) as u16).to_le_bytes());
buf.extend_from_slice(&filter_payload);
buf.extend_from_slice(&(StructureTypes::Pcm3060Configuration as u16).to_le_bytes());
buf.extend_from_slice(&((4 + codec_payload.len()) as u16).to_le_bytes());
buf.extend_from_slice(&codec_payload);

send_cmd(connection_state, &buf).map(|_| true)
let prep = SetPreprocessingConfiguration::new(&config.preprocessing);
let filters = SetFilterConfiguration::new(&config.filters);
let codec = SetPcm3060Configuration::new(&config.codec);
let cmd = SetConfiguration::new(prep, filters, codec);
send_cmd(connection_state, cmd).map(|_| true)
}

#[tauri::command]
fn save_config(connection_state: State<'_, Mutex<ConnectionState>>) -> Result<bool, String> {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&(StructureTypes::SaveConfiguration as u16).to_le_bytes());
buf.extend_from_slice(&(4u16).to_le_bytes());
send_cmd(connection_state, &buf).map(|_| true)
send_cmd(connection_state, SaveConfiguration::new()).map(|_| true)
}

#[tauri::command]
Expand All @@ -328,7 +318,7 @@ fn load_config(connection_state: State<'_, Mutex<ConnectionState>>) -> Result<Co
buf.extend_from_slice(&(StructureTypes::GetStoredConfiguration as u16).to_le_bytes());
buf.extend_from_slice(&(4u16).to_le_bytes());

let binding = send_cmd(connection_state, &buf);
let binding = send_cmd(connection_state, GetStoredConfiguration::new());
let cfg = match &binding {
Ok(x) => x,
Err(e) => {
Expand Down Expand Up @@ -385,11 +375,7 @@ fn load_config(connection_state: State<'_, Mutex<ConnectionState>>) -> Result<Co

#[tauri::command]
fn factory_reset(connection_state: State<'_, Mutex<ConnectionState>>) -> Result<bool, String> {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&(StructureTypes::FactoryReset as u16).to_le_bytes());
buf.extend_from_slice(&(4u16).to_le_bytes());

send_cmd(connection_state, &buf).map(|_| true)
send_cmd(connection_state, FactoryReset::new()).map(|_| true)
}

#[tauri::command]
Expand All @@ -415,11 +401,7 @@ fn reboot_bootloader(connection_state: State<Mutex<ConnectionState>>) -> Result<

#[tauri::command]
fn read_version_info(connection_state: State<'_, Mutex<ConnectionState>>) -> Result<VersionInfo, String> {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(&(StructureTypes::GetVersion as u16).to_le_bytes());
buf.extend_from_slice(&(4u16).to_le_bytes());

let v = send_cmd(connection_state, &buf)?;
let v = send_cmd(connection_state, GetVersion::new())?;
let version = VersionInfo::from_buf(&v)?;
Ok(version)
}
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use byteorder::{LittleEndian, ReadBytesExt};
use serde::{Deserialize, Serialize};

#[repr(u16)]
#[allow(dead_code)]
// #[allow(dead_code)]
pub enum StructureTypes {
// Commands/Responses, these are container TLVs. The Value will be a set of TLV structures.
OK = 0, // Standard response when a command was successful
Expand Down

0 comments on commit 1ad3990

Please sign in to comment.