Skip to main content

uxn_tal/
devicemap.rs

1//! Device map parsing and representation for TAL
2
3#[derive(Debug, Clone, PartialEq)]
4pub struct DeviceField {
5    pub name: String,
6    pub size: u8,
7}
8
9#[derive(Debug, Clone, PartialEq)]
10pub struct Device {
11    pub address: u16,
12    pub name: String,
13    pub fields: Vec<DeviceField>,
14}
15
16impl Device {
17    /// Extend the fields of this DeviceMap with another set of fields
18    pub fn extend_fields(&mut self, other: Vec<DeviceField>) {
19        self.fields.extend(other);
20    }
21    /// Get the address of a field by name, using field offsets and sizes
22    pub fn get_field_address(&self, field_name: &str) -> Option<u16> {
23        let mut offset = 0u16;
24        for field in &self.fields {
25            if field.name == field_name {
26                return Some(self.address + offset);
27            }
28            offset += field.size as u16;
29        }
30        None
31    }
32}
33
34/// Parse a device map line, e.g.:
35/// |00 @System &vector $2 &wst $1 ...
36pub fn parse_device_map_line(line: &str) -> Option<Device> {
37    let mut tokens = line.split_whitespace();
38    let addr_token = tokens.next()?;
39    if !addr_token.starts_with('|') {
40        return None;
41    }
42    let address = u16::from_str_radix(&addr_token[1..], 16).ok()?;
43    let name_token = tokens.next()?;
44    let name = if let Some(stripped) = name_token.strip_prefix('@') {
45        stripped.to_string()
46    } else {
47        return None;
48    };
49    let mut fields = Vec::new();
50    while let Some(field_token) = tokens.next() {
51        if let Some(stripped) = field_token.strip_prefix('&') {
52            let field_name = stripped.to_string();
53            if let Some(size_token) = tokens.next() {
54                if let Some(stripped) = size_token.strip_prefix('$') {
55                    if let Ok(size) = u8::from_str_radix(stripped, 16) {
56                        fields.push(DeviceField {
57                            name: field_name,
58                            size,
59                        });
60                    }
61                }
62            }
63        }
64    }
65    Some(Device {
66        address,
67        name,
68        fields,
69    })
70}
71
72/// Parse multiple device map lines from a TAL file
73pub fn parse_device_maps(source: &str) -> Vec<Device> {
74    source.lines().filter_map(parse_device_map_line).collect()
75}
76
77use once_cell::sync::Lazy;
78
79pub static DEVICES_DEFAULT: Lazy<Vec<Device>> = Lazy::new(|| {
80    vec![
81        Device {
82            address: 0x00,
83            name: "System".into(),
84            fields: vec![
85                DeviceField {
86                    name: "vector".into(),
87                    size: 2,
88                },
89                DeviceField {
90                    name: "wst".into(),
91                    size: 1,
92                },
93                DeviceField {
94                    name: "rst".into(),
95                    size: 1,
96                },
97                DeviceField {
98                    name: "eaddr".into(),
99                    size: 2,
100                },
101                DeviceField {
102                    name: "ecode".into(),
103                    size: 1,
104                },
105                DeviceField {
106                    name: "pad".into(),
107                    size: 1,
108                },
109                DeviceField {
110                    name: "r".into(),
111                    size: 2,
112                },
113                DeviceField {
114                    name: "g".into(),
115                    size: 2,
116                },
117                DeviceField {
118                    name: "b".into(),
119                    size: 2,
120                },
121                DeviceField {
122                    name: "debug".into(),
123                    size: 1,
124                },
125                DeviceField {
126                    name: "halt".into(),
127                    size: 1,
128                },
129                DeviceField {
130                    name: "state".into(),
131                    size: 1,
132                },
133            ],
134        },
135        Device {
136            address: 0x10,
137            name: "Console".into(),
138            fields: vec![
139                DeviceField {
140                    name: "vector".into(),
141                    size: 2,
142                },
143                DeviceField {
144                    name: "read".into(),
145                    size: 1,
146                },
147                DeviceField {
148                    name: "pad".into(),
149                    size: 5,
150                },
151                DeviceField {
152                    name: "write".into(),
153                    size: 1,
154                },
155                DeviceField {
156                    name: "error".into(),
157                    size: 1,
158                },
159            ],
160        },
161        Device {
162            address: 0x20,
163            name: "Screen".into(),
164            fields: vec![
165                DeviceField {
166                    name: "vector".into(),
167                    size: 2,
168                },
169                DeviceField {
170                    name: "width".into(),
171                    size: 2,
172                },
173                DeviceField {
174                    name: "height".into(),
175                    size: 2,
176                },
177                DeviceField {
178                    name: "auto".into(),
179                    size: 1,
180                },
181                DeviceField {
182                    name: "pad".into(),
183                    size: 1,
184                },
185                DeviceField {
186                    name: "x".into(),
187                    size: 2,
188                },
189                DeviceField {
190                    name: "y".into(),
191                    size: 2,
192                },
193                DeviceField {
194                    name: "addr".into(),
195                    size: 2,
196                },
197                DeviceField {
198                    name: "pixel".into(),
199                    size: 1,
200                },
201                DeviceField {
202                    name: "sprite".into(),
203                    size: 1,
204                },
205            ],
206        },
207        Device {
208            address: 0x30,
209            name: "Audio0".into(),
210            fields: vec![
211                DeviceField {
212                    name: "vector".into(),
213                    size: 2,
214                },
215                DeviceField {
216                    name: "position".into(),
217                    size: 2,
218                },
219                DeviceField {
220                    name: "output".into(),
221                    size: 1,
222                },
223                DeviceField {
224                    name: "pad".into(),
225                    size: 3,
226                },
227                DeviceField {
228                    name: "adsr".into(),
229                    size: 2,
230                },
231                DeviceField {
232                    name: "length".into(),
233                    size: 2,
234                },
235                DeviceField {
236                    name: "addr".into(),
237                    size: 2,
238                },
239                DeviceField {
240                    name: "volume".into(),
241                    size: 1,
242                },
243                DeviceField {
244                    name: "pitch".into(),
245                    size: 1,
246                },
247            ],
248        },
249        Device {
250            address: 0x40,
251            name: "Audio1".into(),
252            fields: vec![
253                DeviceField {
254                    name: "vector".into(),
255                    size: 2,
256                },
257                DeviceField {
258                    name: "position".into(),
259                    size: 2,
260                },
261                DeviceField {
262                    name: "output".into(),
263                    size: 1,
264                },
265                DeviceField {
266                    name: "pad".into(),
267                    size: 3,
268                },
269                DeviceField {
270                    name: "adsr".into(),
271                    size: 2,
272                },
273                DeviceField {
274                    name: "length".into(),
275                    size: 2,
276                },
277                DeviceField {
278                    name: "addr".into(),
279                    size: 2,
280                },
281                DeviceField {
282                    name: "volume".into(),
283                    size: 1,
284                },
285                DeviceField {
286                    name: "pitch".into(),
287                    size: 1,
288                },
289            ],
290        },
291        Device {
292            address: 0x50,
293            name: "Audio2".into(),
294            fields: vec![
295                DeviceField {
296                    name: "vector".into(),
297                    size: 2,
298                },
299                DeviceField {
300                    name: "position".into(),
301                    size: 2,
302                },
303                DeviceField {
304                    name: "output".into(),
305                    size: 1,
306                },
307                DeviceField {
308                    name: "pad".into(),
309                    size: 3,
310                },
311                DeviceField {
312                    name: "adsr".into(),
313                    size: 2,
314                },
315                DeviceField {
316                    name: "length".into(),
317                    size: 2,
318                },
319                DeviceField {
320                    name: "addr".into(),
321                    size: 2,
322                },
323                DeviceField {
324                    name: "volume".into(),
325                    size: 1,
326                },
327                DeviceField {
328                    name: "pitch".into(),
329                    size: 1,
330                },
331            ],
332        },
333        Device {
334            address: 0x60,
335            name: "Audio3".into(),
336            fields: vec![
337                DeviceField {
338                    name: "vector".into(),
339                    size: 2,
340                },
341                DeviceField {
342                    name: "position".into(),
343                    size: 2,
344                },
345                DeviceField {
346                    name: "output".into(),
347                    size: 1,
348                },
349                DeviceField {
350                    name: "pad".into(),
351                    size: 3,
352                },
353                DeviceField {
354                    name: "adsr".into(),
355                    size: 2,
356                },
357                DeviceField {
358                    name: "length".into(),
359                    size: 2,
360                },
361                DeviceField {
362                    name: "addr".into(),
363                    size: 2,
364                },
365                DeviceField {
366                    name: "volume".into(),
367                    size: 1,
368                },
369                DeviceField {
370                    name: "pitch".into(),
371                    size: 1,
372                },
373            ],
374        },
375        Device {
376            address: 0x80,
377            name: "Controller".into(),
378            fields: vec![
379                DeviceField {
380                    name: "vector".into(),
381                    size: 2,
382                },
383                DeviceField {
384                    name: "button".into(),
385                    size: 1,
386                },
387                DeviceField {
388                    name: "key".into(),
389                    size: 1,
390                },
391                DeviceField {
392                    name: "func".into(),
393                    size: 1,
394                },
395            ],
396        },
397        Device {
398            address: 0x90,
399            name: "Mouse".into(),
400            fields: vec![
401                DeviceField {
402                    name: "vector".into(),
403                    size: 2,
404                },
405                DeviceField {
406                    name: "x".into(),
407                    size: 2,
408                },
409                DeviceField {
410                    name: "y".into(),
411                    size: 2,
412                },
413                DeviceField {
414                    name: "state".into(),
415                    size: 1,
416                },
417                DeviceField {
418                    name: "pad".into(),
419                    size: 3,
420                },
421                DeviceField {
422                    name: "scrollx".into(),
423                    size: 2,
424                },
425                DeviceField {
426                    name: "scrolly".into(),
427                    size: 2,
428                },
429            ],
430        },
431        Device {
432            address: 0xa0,
433            name: "File".into(),
434            fields: vec![
435                DeviceField {
436                    name: "vector".into(),
437                    size: 2,
438                },
439                DeviceField {
440                    name: "success".into(),
441                    size: 2,
442                },
443                DeviceField {
444                    name: "stat".into(),
445                    size: 2,
446                },
447                DeviceField {
448                    name: "delete".into(),
449                    size: 1,
450                },
451                DeviceField {
452                    name: "append".into(),
453                    size: 1,
454                },
455                DeviceField {
456                    name: "name".into(),
457                    size: 2,
458                },
459                DeviceField {
460                    name: "length".into(),
461                    size: 2,
462                },
463                DeviceField {
464                    name: "read".into(),
465                    size: 2,
466                },
467                DeviceField {
468                    name: "write".into(),
469                    size: 2,
470                },
471            ],
472        },
473        Device {
474            address: 0xb0,
475            name: "File1".into(),
476            fields: vec![
477                DeviceField {
478                    name: "vector".into(),
479                    size: 2,
480                },
481                DeviceField {
482                    name: "success".into(),
483                    size: 2,
484                },
485                DeviceField {
486                    name: "stat".into(),
487                    size: 2,
488                },
489                DeviceField {
490                    name: "delete".into(),
491                    size: 1,
492                },
493                DeviceField {
494                    name: "append".into(),
495                    size: 1,
496                },
497                DeviceField {
498                    name: "name".into(),
499                    size: 2,
500                },
501                DeviceField {
502                    name: "length".into(),
503                    size: 2,
504                },
505                DeviceField {
506                    name: "read".into(),
507                    size: 2,
508                },
509                DeviceField {
510                    name: "write".into(),
511                    size: 2,
512                },
513            ],
514        },
515        Device {
516            address: 0xc0,
517            name: "DateTime".into(),
518            fields: vec![
519                DeviceField {
520                    name: "year".into(),
521                    size: 2,
522                },
523                DeviceField {
524                    name: "month".into(),
525                    size: 1,
526                },
527                DeviceField {
528                    name: "day".into(),
529                    size: 1,
530                },
531                DeviceField {
532                    name: "hour".into(),
533                    size: 1,
534                },
535                DeviceField {
536                    name: "minute".into(),
537                    size: 1,
538                },
539                DeviceField {
540                    name: "second".into(),
541                    size: 1,
542                },
543                DeviceField {
544                    name: "dotw".into(),
545                    size: 1,
546                },
547                DeviceField {
548                    name: "doty".into(),
549                    size: 2,
550                },
551                DeviceField {
552                    name: "isdst".into(),
553                    size: 1,
554                },
555            ],
556        },
557    ]
558});