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}