1extern crate proc_macro;
82use can_dbc::{
83 AttributeValuedForObjectType, ByteOrder, MessageId, Signal, ValueType, DBC,
84};
85use proc_macro2::TokenStream;
86use quote::{quote, TokenStreamExt};
87use std::{collections::BTreeMap, fs::read};
88use syn::{
89 parse_macro_input, spanned::Spanned, Attribute, Data, DeriveInput, Expr,
90 Field, Fields, Ident, Lit, Meta, Result, Type,
91};
92
93struct DeriveData<'a> {
94 #[allow(dead_code)]
96 name: &'a Ident,
97 dbc: can_dbc::DBC,
99 messages: BTreeMap<String, MessageInfo<'a>>,
101}
102
103struct MessageInfo<'a> {
104 id: u32,
105 extended: bool,
106 index: usize,
107 ident: &'a Ident,
108 attrs: &'a Vec<Attribute>,
109 cycle_time: Option<usize>,
110}
111
112struct SignalFilter {
114 names: Vec<String>,
115}
116
117impl SignalFilter {
118 fn new(message: &MessageInfo) -> Self {
120 let mut names: Vec<String> = vec![];
121 if let Some(attrs) = parse_attr(message.attrs, "dbc_signals") {
122 let list = attrs.split(",");
123 for name in list {
124 let name = name.trim();
125 names.push(name.to_string());
126 }
127 }
128 Self { names }
129 }
130
131 fn use_signal(&self, name: impl Into<String>) -> bool {
134 if self.names.is_empty() {
135 return true;
136 }
137 let name = name.into();
138 self.names.contains(&name)
139 }
140}
141
142struct SignalInfo<'a> {
144 signal: &'a Signal,
145 ident: Ident,
146 ntype: Ident,
147 utype: Ident,
148 start: usize,
149 width: usize,
150 nwidth: usize,
151 scale: f32,
152 signed: bool,
153}
154
155impl<'a> SignalInfo<'a> {
156 fn new(signal: &'a Signal, message: &MessageInfo) -> Self {
157 let name = signal.name();
159 let signed = matches!(signal.value_type(), ValueType::Signed);
160 let width = *signal.signal_size() as usize;
161 let scale = *signal.factor() as f32;
162
163 let nwidth = match width {
165 1 => 1,
166 2..=8 => 8,
167 9..=16 => 16,
168 17..=32 => 32,
169 _ => 64,
170 };
171
172 let utype = if width == 1 {
173 "bool"
174 } else {
175 &format!("{}{}", if signed { "i" } else { "u" }, nwidth)
176 };
177
178 let ntype = if scale == 1.0 { utype } else { "f32" };
180
181 Self {
182 signal,
183 ident: Ident::new(name, message.ident.span()),
184 ntype: Ident::new(ntype, message.ident.span()),
185 utype: Ident::new(utype, message.ident.span()),
186 start: *signal.start_bit() as usize,
187 scale,
188 signed,
189 width,
190 nwidth,
191 }
192 }
193
194 fn extract_bits(&self) -> TokenStream {
196 let low = self.start / 8;
197 let left = self.start % 8;
198 let high = (self.start + self.width - 1) / 8;
199 let right = (self.start + self.width) % 8;
200 let utype = &self.utype;
201 let le = self.signal.byte_order() == &ByteOrder::LittleEndian;
202
203 let mut ts = TokenStream::new();
204 if self.width == self.nwidth && left == 0 {
205 let ext = if le {
207 Ident::new("from_le_bytes", utype.span())
208 } else {
209 Ident::new("from_be_bytes", utype.span())
210 };
211 let tokens = match self.width {
212 8 => quote! {
213 #utype::#ext([pdu[#low]])
214 },
215 16 => quote! {
216 #utype::#ext([pdu[#low],
217 pdu[#low + 1]])
218 },
219 32 => quote! {
220 #utype::#ext([pdu[#low + 0],
221 pdu[#low + 1],
222 pdu[#low + 2],
223 pdu[#low + 3]])
224 },
225 64 => quote! {
230 #utype::#ext([pdu[#low + 0],
231 pdu[#low + 1],
232 pdu[#low + 2],
233 pdu[#low + 3],
234 pdu[#low + 4],
235 pdu[#low + 5],
236 pdu[#low + 6],
237 pdu[#low + 7],
238 ])
239 },
240 _ => unimplemented!(),
241 };
242 ts.append_all(tokens);
243 } else {
244 if le {
245 let count = high - low;
246 for o in 0..=count {
247 let byte = low + o;
248 if o == 0 {
249 ts.append_all(quote! {
251 let v = pdu[#byte] as #utype;
252 });
253 if left != 0 {
254 if count == 0 {
255 ts.append_all(quote! {
256 let v = (v >> #left) & ((1 << #left) - 1);
257 });
258 } else {
259 ts.append_all(quote! {
260 let v = v >> #left;
261 });
262 }
263 }
264 } else {
265 let shift = (o * 8) - left;
266 if o == count && right != 0 {
267 ts.append_all(quote! {
268 let v = v | (((pdu[#byte]
269 & ((1 << #right) - 1))
270 as #utype) << #shift);
271 });
272 } else {
273 ts.append_all(quote! {
274 let v = v | ((pdu[#byte] as #utype) << #shift);
275 });
276 }
277 }
278 }
279 } else {
280 let mut rem = self.width;
282 let mut byte = low;
283 while rem > 0 {
284 if byte == low {
285 ts.append_all(quote! {
287 let v = pdu[#byte] as #utype;
288 });
289 if rem < 8 {
290 let mask = rem - 1;
292 let shift = left + 1 - rem;
293 ts.append_all(quote! {
294 let mask: #utype = (1 << #mask)
295 | ((1 << #mask) - 1);
296 let v = (v >> #shift) & mask;
297 });
298 rem = 0;
299 } else {
300 let mask = left;
302 let shift = rem - left - 1;
303 if mask < 7 {
304 ts.append_all(quote! {
305 let mask: #utype = (1 << #mask)
306 | ((1 << #mask) - 1);
307 let v = (v & mask) << #shift;
308 });
309 } else {
310 ts.append_all(quote! {
311 let v = v << #shift;
312 });
313 }
314 rem -= left + 1;
315 }
316 byte += 1;
317 } else {
318 if rem < 8 {
319 let shift = 8 - rem;
321 ts.append_all(quote! {
322 let v = v |
323 ((pdu[#byte] as #utype) >> #shift);
324 });
325 rem = 0;
326 } else {
327 rem -= 8;
328 ts.append_all(quote! {
329 let v = v |
330 ((pdu[#byte] as #utype) << #rem);
331 });
332 byte += 1;
333 }
334 };
335 }
336 }
337 if self.signed && self.width < self.nwidth {
340 let mask = self.width - 1;
341 ts.append_all(quote! {
342 let mask: #utype = (1 << #mask);
343 let v = if (v & mask) != 0 {
344 let mask = mask | (mask - 1);
345 v | !mask
346 } else {
347 v
348 };
349 });
350 }
351 ts.append_all(quote! { v });
352 }
353 quote! { { #ts } }
354 }
355
356 fn gen_decoder(&self) -> TokenStream {
357 let name = &self.ident;
358 if self.width == 1 {
359 let byte = self.start / 8;
361 let bit = self.start % 8;
362 quote! {
363 self.#name = (pdu[#byte] & (1 << #bit)) != 0;
364 }
365 } else {
366 let value = self.extract_bits();
367 let ntype = &self.ntype;
368 if !self.is_float() {
369 quote! {
370 self.#name = #value as #ntype;
371 }
372 } else {
373 let scale = self.scale;
374 let offset = *self.signal.offset() as f32;
375 quote! {
376 self.#name = ((#value as f32) * #scale) + #offset;
377 }
378 }
379 }
380 }
381
382 fn gen_encoder(&self) -> TokenStream {
383 let name = &self.ident;
384 let low = self.start / 8;
385 let mut byte = low;
386 let bit = self.start % 8;
387 if self.width == 1 {
388 quote! {
390 let mask: u8 = (1 << #bit);
391 if self.#name {
392 pdu[#byte] |= mask;
393 } else {
394 pdu[#byte] &= !mask;
395 }
396 }
397 } else {
398 let utype = &self.utype;
399 let left = self.start % 8;
400 let le = self.signal.byte_order() == &ByteOrder::LittleEndian;
402
403 let mut ts = TokenStream::new();
404 if self.is_float() {
405 let scale = self.scale;
406 let offset = self.signal.offset as f32;
407 ts.append_all(quote! {
408 let v = ((self.#name - #offset) / #scale) as #utype;
409 });
410 } else {
411 ts.append_all(quote! {
412 let v = self.#name;
413 });
414 }
415 if le {
416 if self.width == self.nwidth && left == 0 {
417 let mut bits = self.nwidth;
419 let mut shift = 0;
420 while bits >= 8 {
421 ts.append_all(quote! {
422 pdu[#byte] = ((v >> #shift) as u8) & 0xff;
423 });
424 bits -= 8;
425 byte += 1;
426 shift += 8;
427 }
428 } else {
429 let mut rem = self.width;
431 let mut lshift = left;
432 let mut rshift = 0;
433 while rem > 0 {
434 if rem < 8 {
435 let mask: u8 = (1 << rem) - 1;
436 let mask = mask << lshift;
437 ts.append_all(quote! {
438 pdu[#byte] = (pdu[#byte] & !#mask) |
439 ((((v >> #rshift) << (#lshift)) as u8) & #mask);
440 });
441 break;
442 }
443
444 if lshift != 0 {
445 let mask: u8 = (1 << (8 - left)) - 1;
446 let mask = mask << lshift;
447 ts.append_all(quote! {
448 pdu[#byte] = (pdu[#byte] & !#mask) |
449 ((((v >> #rshift) << (#lshift)) as u8) & #mask);
450 });
451 } else {
452 ts.append_all(quote! {
453 pdu[#byte] = ((v >> #rshift) & 0xff) as u8;
454 });
455 }
456
457 if byte == low {
458 rem -= 8 - left;
459 rshift += 8 - left;
460 } else {
461 rem -= 8;
462 rshift += 8;
463 }
464 byte += 1;
465 lshift = 0;
466 }
467 }
468 } else {
469 if self.width == self.nwidth && left == 7 {
470 let mut bits = self.nwidth;
472 let mut shift = bits - 8;
473 let mut byte = (self.start - 7) / 8;
474 while bits >= 8 {
475 ts.append_all(quote! {
476 pdu[#byte] = ((v >> #shift) as u8) & 0xff;
477 });
478 bits -= 8;
479 byte += 1;
480 if shift >= 8 {
481 shift -= 8;
482 }
483 }
484 } else {
485 }
487 }
488 ts
489 }
490 }
491
492 fn is_float(&self) -> bool {
493 self.scale != 1.0
494 }
495}
496
497impl<'a> MessageInfo<'a> {
498 fn new(dbc: &DBC, field: &'a Field) -> Option<Self> {
499 let stype = match &field.ty {
500 Type::Path(v) => v,
501 _ => unimplemented!(),
502 };
503 let ident = &stype.path.segments[0].ident;
504 let name = ident.to_string();
505
506 for (index, message) in dbc.messages().iter().enumerate() {
507 if message.message_name() == &name {
508 let id = message.message_id();
509 let (id32, extended) = match *id {
510 MessageId::Standard(id) => (id as u32, false),
511 MessageId::Extended(id) => (id, true),
512 };
513 let mut cycle_time: Option<usize> = None;
514 for attr in dbc.attribute_values().iter() {
515 let value = attr.attribute_value();
516 use AttributeValuedForObjectType as AV;
517 match value {
518 AV::MessageDefinitionAttributeValue(aid, Some(av)) => {
519 if aid == id
520 && attr.attribute_name() == "GenMsgCycleTime"
521 {
522 cycle_time = Some(Self::attr_value(av));
523 }
524 }
525 _ => {}
526 }
527 }
528
529 return Some(Self {
530 id: id32,
531 extended,
532 index,
533 ident,
534 cycle_time,
535 attrs: &field.attrs,
536 });
537 }
538 }
539 None
540 }
541
542 fn attr_value(v: &can_dbc::AttributeValue) -> usize {
545 use can_dbc::AttributeValue as AV;
546 match v {
547 AV::AttributeValueU64(x) => *x as usize,
548 AV::AttributeValueI64(x) => *x as usize,
549 AV::AttributeValueF64(x) => *x as usize,
550 AV::AttributeValueCharString(_) => 0usize, }
552 }
553}
554
555impl<'a> DeriveData<'a> {
556 fn from(input: &'a DeriveInput) -> Result<Self> {
557 let dbc_file = parse_attr(&input.attrs, "dbc_file")
559 .expect("No DBC file specified");
560 let contents = read(&dbc_file).expect("Could not read DBC");
561 let dbc = DBC::from_slice(&contents).expect("Could not parse DBC");
562
563 let mut messages: BTreeMap<String, MessageInfo<'_>> =
565 Default::default();
566 match &input.data {
567 Data::Struct(data) => match &data.fields {
568 Fields::Named(fields) => {
569 for field in &fields.named {
570 if let Some(info) = MessageInfo::new(&dbc, &field) {
571 messages.insert(info.ident.to_string(), info);
572 } else {
573 return Err(syn::Error::new(
574 field.span(),
575 format!("Unknown message"),
576 ));
577 }
578 }
579 }
580 Fields::Unnamed(_) | Fields::Unit => unimplemented!(),
581 },
582 _ => unimplemented!(),
583 }
584
585 Ok(Self {
586 name: &input.ident,
587 dbc,
588 messages,
589 })
590 }
591
592 fn build(self) -> TokenStream {
593 let mut out = TokenStream::new();
594
595 for (name, message) in self.messages.iter() {
596 let m = self
597 .dbc
598 .messages()
599 .get(message.index)
600 .unwrap_or_else(|| panic!("Unknown message {name}"));
601
602 let filter = SignalFilter::new(message);
603
604 let mut signals: Vec<Ident> = vec![];
605 let mut types: Vec<Ident> = vec![];
606 let mut infos: Vec<SignalInfo> = vec![];
607 for s in m.signals().iter() {
608 if !filter.use_signal(s.name()) {
609 continue;
610 }
611
612 let signal = SignalInfo::new(s, message);
613 signals.push(signal.ident.clone());
614 types.push(signal.ntype.clone());
615 infos.push(signal);
616 }
617
618 let id = message.id;
619 let extended = message.extended;
620
621 let dlc = *m.message_size() as usize;
622 let dlc8 = dlc as u8;
623 let ident = message.ident;
624
625 let mut decoders = TokenStream::new();
627 let mut encoders = TokenStream::new();
628 for info in infos.iter() {
629 decoders.append_all(info.gen_decoder());
630 encoders.append_all(info.gen_encoder());
631 }
632 let cycle_time = if let Some(c) = message.cycle_time {
633 quote! {
634 const CYCLE_TIME: usize = #c;
635 }
636 } else {
637 quote! {}
638 };
639
640 out.append_all(quote! {
641 #[allow(dead_code)]
642 #[allow(non_snake_case)]
643 #[derive(Default)]
644 pub struct #ident {
645 #(
646 pub #signals: #types
647 ),*
648 }
649
650 impl #ident {
651 const ID: u32 = #id;
652 const DLC: u8 = #dlc8;
653 const EXTENDED: bool = #extended;
654 #cycle_time
655
656 pub fn decode(&mut self, pdu: &[u8])
657 -> bool {
658 if pdu.len() != #dlc {
659 return false
660 }
661 #decoders
662 true
663 }
664
665 pub fn encode(&mut self, pdu: &mut [u8])
666 -> bool {
667 if pdu.len() != #dlc {
668 return false
669 }
670 #encoders
671 true
672 }
673 }
674 });
675 }
676 out
677 }
678}
679
680#[proc_macro_derive(DbcData, attributes(dbc_file, dbc_signals))]
681pub fn dbc_data_derive(
682 input: proc_macro::TokenStream,
683) -> proc_macro::TokenStream {
684 derive_data(&parse_macro_input!(input as DeriveInput))
685 .unwrap_or_else(|err| err.to_compile_error())
686 .into()
687}
688
689fn derive_data(input: &DeriveInput) -> Result<TokenStream> {
690 Ok(DeriveData::from(input)?.build())
691}
692
693fn parse_attr(attrs: &[Attribute], name: &str) -> Option<String> {
694 let attr = attrs
695 .iter()
696 .filter(|a| {
697 a.path().segments.len() == 1 && a.path().segments[0].ident == name
698 })
699 .nth(0)?;
700
701 let expr = match &attr.meta {
702 Meta::NameValue(n) => Some(&n.value),
703 _ => None,
704 };
705
706 match &expr {
707 Some(Expr::Lit(e)) => match &e.lit {
708 Lit::Str(s) => Some(s.value()),
709 _ => None,
710 },
711 _ => None,
712 }
713}