libftd2xx_cc1101_derive/
lib.rs

1extern crate proc_macro;
2use proc_macro::TokenStream;
3use quote::{quote, quote_spanned};
4use syn::spanned::Spanned as _;
5
6macro_rules! format_err {
7    ( $spanned:expr, $($msg:tt)* ) => {{
8        ::syn::Error::new(
9            <_ as ::syn::spanned::Spanned>::span(&$spanned),
10            format_args!($($msg)*)
11        )
12    }}
13}
14
15#[proc_macro_derive(CC1101Commands)]
16pub fn generate_cc1101_commands(input: TokenStream) -> TokenStream {
17    let input = syn::parse::<syn::DeriveInput>(input).unwrap();
18    match syn::Item::from(input) {
19        syn::Item::Enum(enum_item) => {
20            let span = enum_item.span();
21            let variants = enum_item.variants.iter().map(|variant| {
22                let enum_ident = &variant.ident;
23                let name = enum_ident.to_string().to_lowercase();
24                let ident = syn::Ident::new(&name, variant.ident.span());
25                quote!(
26                    ($passthru:tt {#ident(); $($tail:tt)*} -> [$($out:tt)*]) => {
27                        mpsse!($passthru {command_strobe(::libftd2xx_cc1101::Command::#enum_ident); $($tail)*} -> [$($out)*]);
28                    };
29                    ($passthru:tt {let $stat_id:ident = #ident(); $($tail:tt)*} -> [$($out:tt)*]) => {
30                        mpsse!($passthru {let $stat_id = command_strobe(::libftd2xx_cc1101::Command::#enum_ident); $($tail)*} -> [$($out)*]);
31                    };
32                )
33            });
34            TokenStream::from(quote_spanned!(span=>
35                /// Internally-shadowed macro to support generated [`mpsse`] macro.
36                #[macro_export]
37                macro_rules! __mpsse_base2 {
38                    #( #variants )*
39
40                    // Everything else handled by base implementation.
41                    ($($tokens:tt)*) => {
42                        ::libftd2xx_cc1101::__mpsse_base!($($tokens)*);
43                    };
44                }
45            ))
46        }
47        other_input => TokenStream::from(
48            format_err!(other_input, "only enum types supported").to_compile_error(),
49        ),
50    }
51}
52
53#[proc_macro_derive(CC1101Regs, attributes(gentype))]
54pub fn generate_cc1101_regs(input: TokenStream) -> TokenStream {
55    let input = syn::parse::<syn::DeriveInput>(input).unwrap();
56    match syn::Item::from(input) {
57        syn::Item::Enum(enum_item) => {
58            let span = enum_item.span();
59            let variants = enum_item.variants.iter().map(|variant| {
60                let enum_ident = &variant.ident;
61                let name = enum_ident.to_string().to_lowercase();
62                let ident = syn::Ident::new(&name, variant.ident.span());
63                let set_ident = syn::Ident::new(&format!("set_{}", name), variant.ident.span());
64                for attr in &variant.attrs {
65                    if attr.path.is_ident("gentype") {
66                        let path = &attr.path;
67                        let args = &attr.tokens;
68                        let gentype: syn::MetaList =
69                            syn::parse2::<_>(quote! { #path #args }).unwrap();
70                        let span = gentype.span();
71                        if let syn::NestedMeta::Meta(syn::Meta::Path(gentype_path)) = gentype.nested.first().unwrap() {
72                            return quote!(
73                                ($passthru:tt {let $data_id:ident = #ident(); $($tail:tt)*} -> [$($out:tt)*]) => {
74                                    mpsse!($passthru @{let $data_id = read_reg(::libftd2xx_cc1101::RegAddrs::#enum_ident as u8 + 0x80, #enum_ident, #gentype_path); $($tail)*} -> [$($out)*]);
75                                };
76                                ($passthru:tt {let ($stat_id:ident, $data_id:ident) = #ident(); $($tail:tt)*} -> [$($out:tt)*]) => {
77                                    mpsse!($passthru @{let ($stat_id, $data_id) = read_reg(::libftd2xx_cc1101::RegAddrs::#enum_ident as u8 + 0x80, #enum_ident, #gentype_path); $($tail)*} -> [$($out)*]);
78                                };
79                                ($passthru:tt {#set_ident($data:expr); $($tail:tt)*} -> [$($out:tt)*]) => {
80                                    mpsse!($passthru @{write_reg(::libftd2xx_cc1101::RegAddrs::#enum_ident as u8, #enum_ident, $data, #gentype_path); $($tail)*} -> [$($out)*]);
81                                };
82                                ($passthru:tt {let $stat_id:ident = #set_ident($data:expr); $($tail:tt)*} -> [$($out:tt)*]) => {
83                                    mpsse!($passthru @{let $stat_id = write_reg(::libftd2xx_cc1101::RegAddrs::#enum_ident as u8, #enum_ident, $data, #gentype_path); $($tail)*} -> [$($out)*]);
84                                };
85                            );
86                        }
87                        return format_err!(
88                            span,
89                            "encountered invalid value type for #[gentype(...)]"
90                        ).to_compile_error();
91                    }
92                }
93                format_err!(variant, "#[gentype(...)] attr not provided").to_compile_error()
94            });
95            TokenStream::from(quote_spanned!(span=>
96                /// Internally-shadowed macro to support generated [`mpsse`] macro.
97                #[macro_export]
98                macro_rules! __mpsse_base3 {
99                    #( #variants )*
100
101                    // Everything else handled by __mpsse_base2 implementation.
102                    ($($tokens:tt)*) => {
103                        ::libftd2xx_cc1101::__mpsse_base2!($($tokens)*);
104                    };
105                }
106            ))
107        }
108        other_input => TokenStream::from(
109            format_err!(other_input, "only enum types supported").to_compile_error(),
110        ),
111    }
112}
113
114#[proc_macro_derive(CC1101ReadRegs, attributes(gentype))]
115pub fn generate_cc1101_read_regs(input: TokenStream) -> TokenStream {
116    let input = syn::parse::<syn::DeriveInput>(input).unwrap();
117    match syn::Item::from(input) {
118        syn::Item::Enum(enum_item) => {
119            let span = enum_item.span();
120            let variants = enum_item.variants.iter().map(|variant| {
121                let enum_ident = &variant.ident;
122                let name = enum_ident.to_string().to_lowercase();
123                let ident = syn::Ident::new(&name, variant.ident.span());
124                for attr in &variant.attrs {
125                    if attr.path.is_ident("gentype") {
126                        let path = &attr.path;
127                        let args = &attr.tokens;
128                        let gentype: syn::MetaList =
129                            syn::parse2::<_>(quote! { #path #args }).unwrap();
130                        let span = gentype.span();
131                        if let syn::NestedMeta::Meta(syn::Meta::Path(gentype_path)) = gentype.nested.first().unwrap() {
132                            return quote!(
133                                ($passthru:tt {let $data_id:ident = #ident(); $($tail:tt)*} -> [$($out:tt)*]) => {
134                                    mpsse!($passthru @{let $data_id = read_reg(::libftd2xx_cc1101::ReadRegAddrs::#enum_ident as u8, #enum_ident, #gentype_path); $($tail)*} -> [$($out)*]);
135                                };
136                                ($passthru:tt {let ($stat_id:ident, $data_id:ident) = #ident(); $($tail:tt)*} -> [$($out:tt)*]) => {
137                                    mpsse!($passthru @{let ($stat_id, $data_id) = read_reg(::libftd2xx_cc1101::ReadRegAddrs::#enum_ident as u8, #enum_ident, #gentype_path); $($tail)*} -> [$($out)*]);
138                                };
139                            );
140                        }
141                        return format_err!(
142                            span,
143                            "encountered invalid value type for #[gentype(...)]"
144                        ).to_compile_error();
145                    }
146                }
147                format_err!(variant, "#[gentype(...)] attr not provided").to_compile_error()
148            });
149            TokenStream::from(quote_spanned!(span=>
150                /// Extended compile-time mpsse command array generation macro.
151                ///
152                /// See documentation of [`libftd2xx::mpsse`] for general information on how this
153                /// macro functions.
154                ///
155                /// # Commands
156                ///
157                /// In addition to the commands in [`libftd2xx::mpsse`], the following
158                /// CC1101-specific commands are available:
159                ///
160                /// * Command Strobes
161                ///     * [`sres()`][`crate::Command::SRES`]
162                ///     * [`sfstxon()`][`crate::Command::SFSTXON`]
163                ///     * [`sxoff()`][`crate::Command::SXOFF`]
164                ///     * [`scal()`][`crate::Command::SCAL`]
165                ///     * [`srx()`][`crate::Command::SRX`]
166                ///     * [`stx()`][`crate::Command::STX`]
167                ///     * [`sidle()`][`crate::Command::SIDLE`]
168                ///     * [`swor()`][`crate::Command::SWOR`]
169                ///     * [`spwd()`][`crate::Command::SPWD`]
170                ///     * [`sfrx()`][`crate::Command::SFRX`]
171                ///     * [`sftx()`][`crate::Command::SFTX`]
172                ///     * [`sworrst()`][`crate::Command::SWORRST`]
173                ///     * [`snop()`][`crate::Command::SNOP`]
174                /// * Configuration Register Access
175                ///     * `read_all_regs()` `->` [`Regs`][`crate::regs::Regs`]
176                ///     * `write_all_regs(regs: Regs)`
177                ///     * [`iocfg2()`][`crate::RegAddrs::IOCFG2`] `->` [`IOCFG2`][`crate::regs::IOCFG2`]
178                ///     * [`set_iocfg2(v: IOCFG2)`][`crate::RegAddrs::IOCFG2`]
179                ///     * [`iocfg1()`][`crate::RegAddrs::IOCFG1`] `->` [`IOCFG1`][`crate::regs::IOCFG1`]
180                ///     * [`set_iocfg1(v: IOCFG1)`][`crate::RegAddrs::IOCFG1`]
181                ///     * [`iocfg0()`][`crate::RegAddrs::IOCFG0`] `->` [`IOCFG0`][`crate::regs::IOCFG0`]
182                ///     * [`set_iocfg0(v: IOCFG0)`][`crate::RegAddrs::IOCFG0`]
183                ///     * [`fifothr()`][`crate::RegAddrs::FIFOTHR`] `->` [`FIFOTHR`][`crate::regs::FIFOTHR`]
184                ///     * [`set_fifothr(v: FIFOTHR)`][`crate::RegAddrs::FIFOTHR`]
185                ///     * [`sync()`][`crate::RegAddrs::SYNC`] `->` [`u16`]
186                ///     * [`set_sync(v: u16)`][`crate::RegAddrs::SYNC`]
187                ///     * [`pktlen()`][`crate::RegAddrs::PKTLEN`] `->` [`u8`]
188                ///     * [`set_pktlen(v: u8)`][`crate::RegAddrs::PKTLEN`]
189                ///     * [`pktctrl1()`][`crate::RegAddrs::PKTCTRL1`] `->` [`PKTCTRL1`][`crate::regs::PKTCTRL1`]
190                ///     * [`set_pktctrl1(v: PKTCTRL1)`][`crate::RegAddrs::PKTCTRL1`]
191                ///     * [`pktctrl0()`][`crate::RegAddrs::PKTCTRL0`] `->` [`PKTCTRL0`][`crate::regs::PKTCTRL0`]
192                ///     * [`set_pktctrl0(v: PKTCTRL0)`][`crate::RegAddrs::PKTCTRL0`]
193                ///     * [`addr()`][`crate::RegAddrs::ADDR`] `->` [`u8`]
194                ///     * [`set_addr(v: u8)`][`crate::RegAddrs::ADDR`]
195                ///     * [`channr()`][`crate::RegAddrs::CHANNR`] `->` [`u8`]
196                ///     * [`set_channr(v: u8)`][`crate::RegAddrs::CHANNR`]
197                ///     * [`fsctrl1()`][`crate::RegAddrs::FSCTRL1`] `->` [`FSCTRL1`][`crate::regs::FSCTRL1`]
198                ///     * [`set_fsctrl1(v: FSCTRL1)`][`crate::RegAddrs::FSCTRL1`]
199                ///     * [`fsctrl0()`][`crate::RegAddrs::FSCTRL0`] `->` [`FSCTRL0`][`crate::regs::FSCTRL0`]
200                ///     * [`set_fsctrl0(v: FSCTRL0)`][`crate::RegAddrs::FSCTRL0`]
201                ///     * [`freq()`][`crate::RegAddrs::FREQ`] `->` [`u32`]
202                ///     * [`set_freq(v: u32)`][`crate::RegAddrs::FREQ`]
203                ///     * [`mdmcfg4()`][`crate::RegAddrs::MDMCFG4`] `->` [`MDMCFG4`][`crate::regs::MDMCFG4`]
204                ///     * [`set_mdmcfg4(v: MDMCFG4)`][`crate::RegAddrs::MDMCFG4`]
205                ///     * [`mdmcfg3()`][`crate::RegAddrs::MDMCFG3`] `->` [`MDMCFG3`][`crate::regs::MDMCFG3`]
206                ///     * [`set_mdmcfg3(v: MDMCFG3)`][`crate::RegAddrs::MDMCFG3`]
207                ///     * [`mdmcfg2()`][`crate::RegAddrs::MDMCFG2`] `->` [`MDMCFG2`][`crate::regs::MDMCFG2`]
208                ///     * [`set_mdmcfg2(v: MDMCFG2)`][`crate::RegAddrs::MDMCFG2`]
209                ///     * [`mdmcfg1()`][`crate::RegAddrs::MDMCFG1`] `->` [`MDMCFG1`][`crate::regs::MDMCFG1`]
210                ///     * [`set_mdmcfg1(v: MDMCFG1)`][`crate::RegAddrs::MDMCFG1`]
211                ///     * [`mdmcfg0()`][`crate::RegAddrs::MDMCFG0`] `->` [`MDMCFG0`][`crate::regs::MDMCFG0`]
212                ///     * [`set_mdmcfg0(v: MDMCFG0)`][`crate::RegAddrs::MDMCFG0`]
213                ///     * [`deviatn()`][`crate::RegAddrs::DEVIATN`] `->` [`DEVIATN`][`crate::regs::DEVIATN`]
214                ///     * [`set_deviatn(v: DEVIATN)`][`crate::RegAddrs::DEVIATN`]
215                ///     * [`mcsm2()`][`crate::RegAddrs::MCSM2`] `->` [`MCSM2`][`crate::regs::MCSM2`]
216                ///     * [`set_mcsm2(v: MCSM2)`][`crate::RegAddrs::MCSM2`]
217                ///     * [`mcsm1()`][`crate::RegAddrs::MCSM1`] `->` [`MCSM1`][`crate::regs::MCSM1`]
218                ///     * [`set_mcsm1(v: MCSM1)`][`crate::RegAddrs::MCSM1`]
219                ///     * [`mcsm0()`][`crate::RegAddrs::MCSM0`] `->` [`MCSM0`][`crate::regs::MCSM0`]
220                ///     * [`set_mcsm0(v: MCSM0)`][`crate::RegAddrs::MCSM0`]
221                ///     * [`foccfg()`][`crate::RegAddrs::FOCCFG`] `->` [`FOCCFG`][`crate::regs::FOCCFG`]
222                ///     * [`set_foccfg(v: FOCCFG)`][`crate::RegAddrs::FOCCFG`]
223                ///     * [`bscfg()`][`crate::RegAddrs::BSCFG`] `->` [`BSCFG`][`crate::regs::BSCFG`]
224                ///     * [`set_bscfg(v: BSCFG)`][`crate::RegAddrs::BSCFG`]
225                ///     * [`agcctrl2()`][`crate::RegAddrs::AGCCTRL2`] `->` [`AGCCTRL2`][`crate::regs::AGCCTRL2`]
226                ///     * [`set_agcctrl2(v: AGCCTRL2)`][`crate::RegAddrs::AGCCTRL2`]
227                ///     * [`agcctrl1()`][`crate::RegAddrs::AGCCTRL1`] `->` [`AGCCTRL1`][`crate::regs::AGCCTRL1`]
228                ///     * [`set_agcctrl1(v: AGCCTRL1)`][`crate::RegAddrs::AGCCTRL1`]
229                ///     * [`agcctrl0()`][`crate::RegAddrs::AGCCTRL0`] `->` [`AGCCTRL0`][`crate::regs::AGCCTRL0`]
230                ///     * [`set_agcctrl0(v: AGCCTRL0)`][`crate::RegAddrs::AGCCTRL0`]
231                ///     * [`worevt()`][`crate::RegAddrs::WOREVT`] `->` [`u16`]
232                ///     * [`set_worevt(v: u16)`][`crate::RegAddrs::WOREVT`]
233                ///     * [`worctrl()`][`crate::RegAddrs::WORCTRL`] `->` [`WORCTRL`][`crate::regs::WORCTRL`]
234                ///     * [`set_worctrl(v: WORCTRL)`][`crate::RegAddrs::WORCTRL`]
235                ///     * [`frend1()`][`crate::RegAddrs::FREND1`] `->` [`FREND1`][`crate::regs::FREND1`]
236                ///     * [`set_frend1(v: FREND1)`][`crate::RegAddrs::FREND1`]
237                ///     * [`frend0()`][`crate::RegAddrs::FREND0`] `->` [`FREND0`][`crate::regs::FREND0`]
238                ///     * [`set_frend0(v: FREND0)`][`crate::RegAddrs::FREND0`]
239                ///     * [`fscal3()`][`crate::RegAddrs::FSCAL3`] `->` [`FSCAL3`][`crate::regs::FSCAL3`]
240                ///     * [`set_fscal3(v: FSCAL3)`][`crate::RegAddrs::FSCAL3`]
241                ///     * [`fscal2()`][`crate::RegAddrs::FSCAL2`] `->` [`FSCAL2`][`crate::regs::FSCAL2`]
242                ///     * [`set_fscal2(v: FSCAL2)`][`crate::RegAddrs::FSCAL2`]
243                ///     * [`fscal1()`][`crate::RegAddrs::FSCAL1`] `->` [`FSCAL1`][`crate::regs::FSCAL1`]
244                ///     * [`set_fscal1(v: FSCAL1)`][`crate::RegAddrs::FSCAL1`]
245                ///     * [`fscal0()`][`crate::RegAddrs::FSCAL0`] `->` [`FSCAL0`][`crate::regs::FSCAL0`]
246                ///     * [`set_fscal0(v: FSCAL0)`][`crate::RegAddrs::FSCAL0`]
247                ///     * [`rcctrl1()`][`crate::RegAddrs::RCCTRL1`] `->` [`RCCTRL1`][`crate::regs::RCCTRL1`]
248                ///     * [`set_rcctrl1(v: RCCTRL1)`][`crate::RegAddrs::RCCTRL1`]
249                ///     * [`rcctrl0()`][`crate::RegAddrs::RCCTRL0`] `->` [`RCCTRL0`][`crate::regs::RCCTRL0`]
250                ///     * [`set_rcctrl0(v: RCCTRL0)`][`crate::RegAddrs::RCCTRL0`]
251                ///     * [`fstest()`][`crate::RegAddrs::FSTEST`] `->` [`u8`]
252                ///     * [`set_fstest(v: u8)`][`crate::RegAddrs::FSTEST`]
253                ///     * [`ptest()`][`crate::RegAddrs::PTEST`] `->` [`u8`]
254                ///     * [`set_ptest(v: u8)`][`crate::RegAddrs::PTEST`]
255                ///     * [`agctest()`][`crate::RegAddrs::AGCTEST`] `->` [`u8`]
256                ///     * [`set_agctest(v: u8)`][`crate::RegAddrs::AGCTEST`]
257                ///     * [`test2()`][`crate::RegAddrs::TEST2`] `->` [`u8`]
258                ///     * [`set_test2(v: u8)`][`crate::RegAddrs::TEST2`]
259                ///     * [`test1()`][`crate::RegAddrs::TEST1`] `->` [`u8`]
260                ///     * [`set_test1(v: u8)`][`crate::RegAddrs::TEST1`]
261                ///     * [`test0()`][`crate::RegAddrs::TEST0`] `->` [`TEST0`][`crate::regs::TEST0`]
262                ///     * [`set_test0(v: TEST0)`][`crate::RegAddrs::TEST0`]
263                /// * Status Register Access
264                ///     * [`partnum()`][`crate::ReadRegAddrs::PARTNUM`] `->` [`u8`]
265                ///     * [`version()`][`crate::ReadRegAddrs::VERSION`] `->` [`u8`]
266                ///     * [`freqtest()`][`crate::ReadRegAddrs::FREQTEST`] `->` [`u8`]
267                ///     * [`lqi()`][`crate::ReadRegAddrs::LQI`] `->` [`LQI`][`crate::regs::LQI`]
268                ///     * [`rssi()`][`crate::ReadRegAddrs::RSSI`] `->` [`u8`]
269                ///     * [`marcstate()`][`crate::ReadRegAddrs::MARCSTATE`] `->` [`MARCSTATE`][`crate::regs::MARCSTATE`]
270                ///     * [`wortime()`][`crate::ReadRegAddrs::WORTIME`] `->` [`u8`]
271                ///     * [`pktstatus()`][`crate::ReadRegAddrs::PKTSTATUS`] `->` [`PKTSTATUS`][`crate::regs::PKTSTATUS`]
272                ///     * [`vco_vc_dac()`][`crate::ReadRegAddrs::VCO_VC_DAC`] `->` [`u8`]
273                ///     * [`txbytes()`][`crate::ReadRegAddrs::TXBYTES`] `->` [`TXBYTES`][`crate::regs::TXBYTES`]
274                ///     * [`rxbytes()`][`crate::ReadRegAddrs::RXBYTES`] `->` [`RXBYTES`][`crate::regs::RXBYTES`]
275                ///     * [`rcctrl1_status()`][`crate::ReadRegAddrs::RCCTRL1_STATUS`] `->` [`RCCTRL_STATUS`][`crate::regs::RCCTRL_STATUS`]
276                ///     * [`rcctrl0_status()`][`crate::ReadRegAddrs::RCCTRL0_STATUS`] `->` [`RCCTRL_STATUS`][`crate::regs::RCCTRL_STATUS`]
277                /// * FIFO Access
278                ///     * `read_rx_fifo(len: u16)` `->` `[u8; N]`
279                ///     * `write_tx_fifo(data: [u8; N])`
280                /// * PA Table Access
281                ///     * `read_pa_table(len: u16)` `->` `[u8; N]`
282                ///     * `write_pa_table(data: [u8; N])`
283                #[macro_export]
284                macro_rules! mpsse {
285                    #( #variants )*
286
287                    // Everything else handled by __mpsse_base3 implementation.
288                    ($($tokens:tt)*) => {
289                        ::libftd2xx_cc1101::__mpsse_base3!($($tokens)*);
290                    };
291                }
292            ))
293        }
294        other_input => TokenStream::from(
295            format_err!(other_input, "only enum types supported").to_compile_error(),
296        ),
297    }
298}