tuneutils/definition/
mod.rs

1extern crate serde_yaml;
2
3use std::rc::Rc;
4use std::default;
5use std::collections::HashMap;
6
7use std::path::Path;
8use std::fs;
9use std::io::Read;
10
11use crate::error::Result;
12
13#[serde(rename_all = "lowercase")]
14#[derive(Debug, Serialize, Deserialize)]
15pub enum DownloadMode {
16	Mazda1,
17	None,
18}
19
20impl default::Default for DownloadMode {
21	fn default() -> DownloadMode {
22		DownloadMode::None
23	}
24}
25
26#[serde(rename_all = "lowercase")]
27#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
28pub enum FlashMode {
29	Mazda1,
30	None,
31}
32
33impl default::Default for FlashMode {
34	fn default() -> FlashMode {
35		FlashMode::None
36	}
37}
38
39#[serde(rename_all = "lowercase")]
40#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
41pub enum LogMode {
42	Uds,
43	None,
44}
45
46impl default::Default for LogMode {
47	fn default() -> LogMode {
48		LogMode::None
49	}
50}
51
52#[serde(rename_all = "lowercase")]
53#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
54pub enum Endianness {
55	Big,
56	Little,
57}
58
59#[serde(rename_all = "lowercase")]
60#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
61pub enum DataType {
62	Uint8,
63    Uint16,
64    Uint32,
65    Uint64,
66    Float32,
67    Float64,
68    Int8,
69    Int16,
70    Int32,
71    Int64,
72}
73
74#[derive(Debug, Serialize, Deserialize)]
75pub struct Identifier {
76	pub offset: u32,
77	pub data: Vec<u8>,
78}
79
80#[derive(Debug, Serialize, Deserialize)]
81pub struct Axis {
82	pub name: String,
83	pub id: String,
84	#[serde(rename = "type")]
85	pub axis_type: String,
86
87	#[serde(default)]
88	pub start: f64,
89	#[serde(default)]
90	pub increment: f64,
91}
92
93#[derive(Debug, Deserialize, Serialize)]
94pub struct Table {
95	pub id: usize,
96	pub name: String,
97	pub description: String,
98	pub category: String,
99	pub data_type: DataType,
100
101	#[serde(default = "default_table_dimension")]
102	pub width: usize,
103	#[serde(default = "default_table_dimension")]
104	pub height: usize,
105
106	#[serde(default = "max_table_constraint")]
107	pub maximum: f64,
108	#[serde(default = "min_table_constraint")]
109	pub minimum: f64,
110
111	#[serde(default)]
112	pub axis_x_id: String,
113	#[serde(default)]
114	pub axis_y_id: String,
115}
116
117#[derive(Debug, Deserialize, Serialize, Clone)]
118pub struct Pid {
119	pub name: String,
120	pub description: String,
121	pub formula: String,
122	pub unit: String,
123	pub datatype: DataType,
124	pub id: u32,
125	pub code: u16,
126}
127
128fn default_table_dimension() -> usize {
129	1
130}
131
132fn max_table_constraint() -> f64 {
133	use std::f64;
134	f64::MAX
135}
136
137fn min_table_constraint() -> f64 {
138	use std::f64;
139	f64::MIN
140}
141
142
143/// A specific model of an ECU e.g. Mazdaspeed6 made in 2006 for California
144#[derive(Debug, Deserialize, Serialize)]
145pub struct Model {
146	pub id: String,
147	pub name: String,
148
149	#[serde(rename = "tables")]
150	#[serde(default)]
151	// <id, offset>
152	pub table_offsets: HashMap<usize, usize>,
153
154	#[serde(rename = "axes")]
155	#[serde(default)]
156	// <id, offset>
157	pub axis_offsets: HashMap<String, usize>,
158
159	#[serde(default)]
160	pub identifiers: Vec<Identifier>,
161}
162
163#[derive(Debug, Deserialize, Serialize)]
164pub struct Transfer {
165	#[serde(default)]
166	pub download_mode: DownloadMode,
167	#[serde(default)]
168	pub flash_mode: FlashMode,
169	// Security key
170	pub key: String,
171	// Server ID for ISO-TP requests
172	pub server_id: u16,
173}
174
175/// A specific platform e.g. Mazdaspeed6
176#[derive(Debug, Deserialize, Serialize)]
177pub struct Main {
178	pub name: String,
179	pub id: String,
180
181	pub transfer: Transfer,
182	pub baudrate: u32,
183	#[serde(default)]
184	pub log_mode: LogMode,
185	pub endianness: Endianness,
186
187	// Flash region
188	pub flash_offset: usize,
189	pub flash_size: usize,
190
191	pub rom_size: usize,
192
193	pub tables: Vec<Table>,
194	pub pids: Vec<Pid>,
195	pub vins: Vec<String>,
196
197	#[serde(skip)]
198	pub models: Vec<Rc<Model>>,
199}
200
201impl Main {
202	/// Searches for a model that matches the id
203	pub fn find(&self, id: &str) -> Option<&Rc<Model>> {
204		self.models.iter().find(|&model| model.id == id)
205	}
206
207	/// Searches for a table definition
208	pub fn find_table(&self, id: usize) -> Option<&Table> {
209		// This could be better implemented with a hash table
210		self.tables.iter().find(|ref x| x.id == id)
211	}
212
213	/// Identifies the model of ROM data, or returns None if it could not be identified
214	pub fn identify(&self, data: &[u8]) -> Option<&Rc<Model>> {
215		self.models.iter().find(|&model| model.identify(data))
216	}
217}
218
219impl Model {
220	/// Returns true if the ROM data was identified as this model
221	pub fn identify(&self, data: &[u8]) -> bool {
222		for id in self.identifiers.iter() {
223			if data.len() < id.offset as usize + id.data.len() {
224				// data is too small
225				return false;
226			}
227			if id.data != &data[id.offset as usize..(id.offset as usize + id.data.len())] {
228				return false;
229			}
230		}
231		// All identifiers succeeded
232		return true;
233	}
234}
235
236pub struct Definitions {
237	pub definitions: Vec<Rc<Main>>,
238}
239
240impl default::Default for Definitions {
241	fn default() -> Definitions {
242		Definitions {definitions: Vec::new()}
243	}
244}
245
246impl Definitions {
247	pub fn load(&mut self, base: &Path) -> Result<()> {
248		if !base.exists() {
249			return Ok(());
250		}
251		for entry in fs::read_dir(base)? {
252			let entry = entry?;
253			let path = entry.path();
254			if path.is_dir() {
255				// Check for a main.toml
256				let main_path = path.join("main.yaml");
257				if !main_path.is_file() {
258					continue;
259				}
260
261				// Open it
262				let mut contents = fs::read_to_string(main_path)?;
263				let mut main: Main = serde_yaml::from_str(&contents)?;
264
265				// Load models
266				for entry in fs::read_dir(path)? {
267					let entry = entry?;
268					let path = entry.path();
269
270					if !path.is_file() { continue; }
271					if let Some(ext) = path.extension() {
272						if ext != "yaml" { continue; }
273					} else {
274						continue;
275					}
276					if let Some(name) = path.file_name() {
277						if name == "main.yaml" { continue; }
278					}
279
280					contents.clear();
281					{
282						let mut file = fs::File::open(path)?;
283						file.read_to_string(&mut contents)?;
284					}
285					let model: Model = serde_yaml::from_str(&contents)?;
286					main.models.push(Rc::new(model));
287				}
288
289				self.definitions.push(Rc::new(main));
290			}
291		}
292
293		Ok(())
294	}
295
296	/// Searches for the main definition with the matching id
297	pub fn find(&self, id: &str) -> Option<&Rc<Main>> {
298		self.definitions.iter().find(|&def| def.id == id)
299	}
300}