1use crate::{command::WriteCommand, instr::Instr};
2
3macro_rules! millivolt_value {
4 (
5 $(#[$meta:meta])*
6 $name:ident: $min:literal ..= $max:literal,
7 zero = $zero:literal,
8 step = $step:literal
9 ) => {
10 $(#[$meta])*
11 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
12 pub struct $name(u8);
13
14 impl $name {
15 #[doc = concat!(
16 "Voltage in millivolts, ", stringify!($min), " to ", stringify!($max),
17 " in steps of ", stringify!($step), " mV.\n\n# Panics\n\n",
18 "If `mv` is out of range or not on a step (at compile time in a `const`)."
19 )]
20 pub const fn from_mv(mv: i16) -> Self {
21 assert!(
22 mv >= $min && mv <= $max && (mv - $zero) % $step == 0,
23 concat!(stringify!($name), " out of range")
24 );
25 Self(((mv - $zero).unsigned_abs() / $step) as u8)
26 }
27 }
28 };
29}
30
31#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub struct GateVoltageControl {
34 vgha: Vgh,
35 vgla: Vgl,
36}
37
38impl GateVoltageControl {
39 pub const DEFAULT: Self = Self {
41 vgha: Vgh::from_mv(15_000),
42 vgla: Vgl::from_mv(-10_000),
43 };
44
45 #[must_use]
47 pub const fn with_vgh(mut self, v: Vgh) -> Self {
48 self.vgha = v;
49 self
50 }
51
52 #[must_use]
54 pub const fn with_vgl(mut self, v: Vgl) -> Self {
55 self.vgla = v;
56 self
57 }
58
59 const fn bytes(&self) -> [u8; 2] {
60 [self.vgha.0, self.vgla.0]
61 }
62}
63
64impl Default for GateVoltageControl {
65 fn default() -> Self {
66 Self::DEFAULT
67 }
68}
69
70impl WriteCommand for GateVoltageControl {
71 const OPCODE: Instr = Instr::GCTRL;
72 type Params = [u8; 2];
73 fn params(&self) -> Self::Params {
74 self.bytes()
75 }
76}
77
78millivolt_value!(
79 Vgh: 8_000..=17_000, zero = 8_000, step = 500
81);
82millivolt_value!(
83 Vgl: -15_000..=-6_000, zero = -5_000, step = 500
85);
86
87const _: () = assert!(matches!(GateVoltageControl::DEFAULT.bytes(), [0x0E, 0x0A]));
88const _: () = assert!(matches!(
89 GateVoltageControl::DEFAULT
90 .with_vgh(Vgh::from_mv(8_000))
91 .with_vgl(Vgl::from_mv(-6_000))
92 .bytes(),
93 [0x00, 0x02]
94));
95const _: () = assert!(matches!(
96 GateVoltageControl::DEFAULT
97 .with_vgh(Vgh::from_mv(17_000))
98 .with_vgl(Vgl::from_mv(-15_000))
99 .bytes(),
100 [0x12, 0x14]
101));
102
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
106pub struct SourceHighPositiveVoltageControl {
107 vshpa: [SourceHighPositiveVoltage; 4],
108}
109
110impl SourceHighPositiveVoltageControl {
111 pub const DEFAULT: Self = Self {
113 vshpa: [
114 SourceHighPositiveVoltage::from_mv(5_000),
115 SourceHighPositiveVoltage::from_mv(5_000),
116 SourceHighPositiveVoltage::from_mv(5_000),
117 SourceHighPositiveVoltage::from_mv(5_000),
118 ],
119 };
120
121 #[must_use]
123 pub const fn with_vshpa(mut self, v: [SourceHighPositiveVoltage; 4]) -> Self {
124 self.vshpa = v;
125 self
126 }
127
128 const fn bytes(&self) -> [u8; 4] {
129 [
130 self.vshpa[0].0,
131 self.vshpa[1].0,
132 self.vshpa[2].0,
133 self.vshpa[3].0,
134 ]
135 }
136}
137
138impl Default for SourceHighPositiveVoltageControl {
139 fn default() -> Self {
140 Self::DEFAULT
141 }
142}
143
144impl WriteCommand for SourceHighPositiveVoltageControl {
145 const OPCODE: Instr = Instr::VSHPCTRL;
146 type Params = [u8; 4];
147 fn params(&self) -> Self::Params {
148 self.bytes()
149 }
150}
151
152millivolt_value!(
153 SourceHighPositiveVoltage: 3_700..=6_200, zero = 3_700, step = 20
155);
156
157const _: () = assert!(matches!(
158 SourceHighPositiveVoltageControl::DEFAULT.bytes(),
159 [0x41, 0x41, 0x41, 0x41]
160));
161const _: () = assert!(matches!(
162 SourceHighPositiveVoltageControl {
163 vshpa: [
164 SourceHighPositiveVoltage::from_mv(3_700),
165 SourceHighPositiveVoltage::from_mv(6_200),
166 SourceHighPositiveVoltage::from_mv(5_800),
167 SourceHighPositiveVoltage::from_mv(5_820)
168 ]
169 }
170 .bytes(),
171 [0x00, 0x7D, 0x69, 0x6A]
172));
173
174#[derive(Clone, Copy, Debug, PartialEq, Eq)]
177pub struct SourceLowPositiveVoltageControl {
178 vslpa: [SourceLowPositiveVoltage; 4],
179}
180
181impl SourceLowPositiveVoltageControl {
182 pub const DEFAULT: Self = Self {
184 vslpa: [
185 SourceLowPositiveVoltage::from_mv(1_000),
186 SourceLowPositiveVoltage::from_mv(1_000),
187 SourceLowPositiveVoltage::from_mv(1_000),
188 SourceLowPositiveVoltage::from_mv(1_000),
189 ],
190 };
191
192 #[must_use]
194 pub const fn with_vslpa(mut self, v: [SourceLowPositiveVoltage; 4]) -> Self {
195 self.vslpa = v;
196 self
197 }
198
199 const fn bytes(&self) -> [u8; 4] {
200 [
201 self.vslpa[0].0,
202 self.vslpa[1].0,
203 self.vslpa[2].0,
204 self.vslpa[3].0,
205 ]
206 }
207}
208
209impl Default for SourceLowPositiveVoltageControl {
210 fn default() -> Self {
211 Self::DEFAULT
212 }
213}
214
215impl WriteCommand for SourceLowPositiveVoltageControl {
216 const OPCODE: Instr = Instr::VSLPCTRL;
217 type Params = [u8; 4];
218 fn params(&self) -> Self::Params {
219 self.bytes()
220 }
221}
222
223millivolt_value!(
224 SourceLowPositiveVoltage: 0..=2_000, zero = 0, step = 20
226);
227
228const _: () = assert!(matches!(
229 SourceLowPositiveVoltageControl::DEFAULT.bytes(),
230 [0x32, 0x32, 0x32, 0x32]
231));
232const _: () = assert!(matches!(
233 SourceLowPositiveVoltageControl {
234 vslpa: [
235 SourceLowPositiveVoltage::from_mv(0),
236 SourceLowPositiveVoltage::from_mv(2_000),
237 SourceLowPositiveVoltage::from_mv(500),
238 SourceLowPositiveVoltage::from_mv(520)
239 ]
240 }
241 .bytes(),
242 [0x00, 0x64, 0x19, 0x1A]
243));
244
245#[derive(Clone, Copy, Debug, PartialEq, Eq)]
248pub struct SourceHighNegativeVoltageControl {
249 vshna: [SourceHighNegativeVoltage; 4],
250}
251
252impl SourceHighNegativeVoltageControl {
253 pub const DEFAULT: Self = Self {
255 vshna: [
256 SourceHighNegativeVoltage::from_mv(-3_900),
257 SourceHighNegativeVoltage::from_mv(-3_900),
258 SourceHighNegativeVoltage::from_mv(-3_900),
259 SourceHighNegativeVoltage::from_mv(-3_900),
260 ],
261 };
262
263 #[must_use]
265 pub const fn with_vshna(mut self, v: [SourceHighNegativeVoltage; 4]) -> Self {
266 self.vshna = v;
267 self
268 }
269
270 const fn bytes(&self) -> [u8; 4] {
271 [
272 self.vshna[0].0,
273 self.vshna[1].0,
274 self.vshna[2].0,
275 self.vshna[3].0,
276 ]
277 }
278}
279
280impl Default for SourceHighNegativeVoltageControl {
281 fn default() -> Self {
282 Self::DEFAULT
283 }
284}
285
286impl WriteCommand for SourceHighNegativeVoltageControl {
287 const OPCODE: Instr = Instr::VSHNCTRL;
288 type Params = [u8; 4];
289 fn params(&self) -> Self::Params {
290 self.bytes()
291 }
292}
293
294millivolt_value!(
295 SourceHighNegativeVoltage: -5_200..=-2_500, zero = -2_500, step = 20
297);
298
299const _: () = assert!(matches!(
300 SourceHighNegativeVoltageControl::DEFAULT.bytes(),
301 [0x46, 0x46, 0x46, 0x46]
302));
303const _: () = assert!(matches!(
304 SourceHighNegativeVoltageControl {
305 vshna: [
306 SourceHighNegativeVoltage::from_mv(-2_500),
307 SourceHighNegativeVoltage::from_mv(-5_200),
308 SourceHighNegativeVoltage::from_mv(-4_000),
309 SourceHighNegativeVoltage::from_mv(-4_020),
310 ]
311 }
312 .bytes(),
313 [0x00, 0x87, 0x4B, 0x4C]
314));
315
316#[derive(Clone, Copy, Debug, PartialEq, Eq)]
319pub struct SourceLowNegativeVoltageControl {
320 vslna: [SourceLowNegativeVoltage; 4],
321}
322
323impl SourceLowNegativeVoltageControl {
324 pub const DEFAULT: Self = Self {
326 vslna: [
327 SourceLowNegativeVoltage::from_mv(-400),
328 SourceLowNegativeVoltage::from_mv(-400),
329 SourceLowNegativeVoltage::from_mv(-400),
330 SourceLowNegativeVoltage::from_mv(-400),
331 ],
332 };
333
334 #[must_use]
336 pub const fn with_vslna(mut self, v: [SourceLowNegativeVoltage; 4]) -> Self {
337 self.vslna = v;
338 self
339 }
340
341 const fn bytes(&self) -> [u8; 4] {
342 [
343 self.vslna[0].0,
344 self.vslna[1].0,
345 self.vslna[2].0,
346 self.vslna[3].0,
347 ]
348 }
349}
350
351impl Default for SourceLowNegativeVoltageControl {
352 fn default() -> Self {
353 Self::DEFAULT
354 }
355}
356
357impl WriteCommand for SourceLowNegativeVoltageControl {
358 const OPCODE: Instr = Instr::VSLNCTRL;
359 type Params = [u8; 4];
360 fn params(&self) -> Self::Params {
361 self.bytes()
362 }
363}
364
365millivolt_value!(
366 SourceLowNegativeVoltage: -1_800..=1_000, zero = 1_000, step = 20
368);
369
370const _: () = assert!(matches!(
371 SourceLowNegativeVoltageControl::DEFAULT.bytes(),
372 [0x46, 0x46, 0x46, 0x46]
373));
374const _: () = assert!(matches!(
375 SourceLowNegativeVoltageControl {
376 vslna: [
377 SourceLowNegativeVoltage::from_mv(1_000),
378 SourceLowNegativeVoltage::from_mv(-1_800),
379 SourceLowNegativeVoltage::from_mv(500),
380 SourceLowNegativeVoltage::from_mv(480),
381 ]
382 }
383 .bytes(),
384 [0x00, 0x8C, 0x19, 0x1A]
385));
386
387#[derive(Clone, Copy, Debug, PartialEq, Eq)]
389pub struct SourceGammaVoltageControl {
390 vsip: VsipVoltage,
391 vskp: VskpVoltage,
392 vsin: VsinVoltage,
393 vskn: VsknVoltage,
394}
395
396impl SourceGammaVoltageControl {
397 pub const DEFAULT: Self = Self {
399 vsip: VsipVoltage::from_mv(3_600),
400 vskp: VskpVoltage::from_mv(2_600),
401 vsin: VsinVoltage::from_mv(-2_400),
402 vskn: VsknVoltage::from_mv(-1_400),
403 };
404
405 #[must_use]
407 pub const fn with_vsip(mut self, v: VsipVoltage) -> Self {
408 self.vsip = v;
409 self
410 }
411
412 #[must_use]
414 pub const fn with_vskp(mut self, v: VskpVoltage) -> Self {
415 self.vskp = v;
416 self
417 }
418
419 #[must_use]
421 pub const fn with_vsin(mut self, v: VsinVoltage) -> Self {
422 self.vsin = v;
423 self
424 }
425
426 #[must_use]
428 pub const fn with_vskn(mut self, v: VsknVoltage) -> Self {
429 self.vskn = v;
430 self
431 }
432
433 const fn bytes(&self) -> [u8; 4] {
434 [self.vsip.0, self.vskp.0, self.vsin.0, self.vskn.0]
435 }
436}
437
438impl Default for SourceGammaVoltageControl {
439 fn default() -> Self {
440 Self::DEFAULT
441 }
442}
443
444impl WriteCommand for SourceGammaVoltageControl {
445 const OPCODE: Instr = Instr::VSIKCTRL;
446 type Params = [u8; 4];
447 fn params(&self) -> Self::Params {
448 self.bytes()
449 }
450}
451
452millivolt_value!(
453 VsipVoltage: 2_200..=5_000, zero = 2_200, step = 20
455);
456millivolt_value!(
457 VskpVoltage: 1_200..=4_000, zero = 1_200, step = 20
459);
460millivolt_value!(
461 VsinVoltage: -3_800..=-1_000, zero = -1_000, step = 20
463);
464millivolt_value!(
465 VsknVoltage: -2_800..=0, zero = 0, step = 20
467);
468
469const _: () = assert!(matches!(
470 SourceGammaVoltageControl::DEFAULT.bytes(),
471 [0x46, 0x46, 0x46, 0x46]
472));
473const _: () = assert!(matches!(
474 SourceGammaVoltageControl {
475 vsip: VsipVoltage::from_mv(2_200),
476 vskp: VskpVoltage::from_mv(1_200),
477 vsin: VsinVoltage::from_mv(-1_000),
478 vskn: VsknVoltage::from_mv(0),
479 }
480 .bytes(),
481 [0x00, 0x00, 0x00, 0x00]
482));
483const _: () = assert!(matches!(
484 SourceGammaVoltageControl::DEFAULT
485 .with_vsip(VsipVoltage::from_mv(5_000))
486 .with_vskp(VskpVoltage::from_mv(4_000))
487 .with_vsin(VsinVoltage::from_mv(-3_800))
488 .with_vskn(VsknVoltage::from_mv(-2_800))
489 .bytes(),
490 [0x8C, 0x8C, 0x8C, 0x8C]
491));
492
493#[derive(Clone, Copy, Debug, PartialEq, Eq)]
495pub struct SourceVoltageSelect {
496 sdhlsel: SourceVoltage,
497}
498
499impl SourceVoltageSelect {
500 pub const DEFAULT: Self = Self {
502 sdhlsel: SourceVoltage::Source1,
503 };
504
505 pub const fn new(sdhlsel: SourceVoltage) -> Self {
507 Self { sdhlsel }
508 }
509
510 const fn bytes(&self) -> [u8; 1] {
511 [self.sdhlsel as u8]
512 }
513}
514
515impl Default for SourceVoltageSelect {
516 fn default() -> Self {
517 Self::DEFAULT
518 }
519}
520
521impl WriteCommand for SourceVoltageSelect {
522 const OPCODE: Instr = Instr::VSHLSEL;
523 type Params = [u8; 1];
524 fn params(&self) -> Self::Params {
525 self.bytes()
526 }
527}
528
529#[derive(Clone, Copy, Debug, PartialEq, Eq)]
531pub enum SourceVoltage {
532 Source1 = 0,
534 Source2 = 1,
536 Source3 = 2,
538 Source4 = 3,
540}
541
542const _: () = assert!(matches!(SourceVoltageSelect::DEFAULT.bytes(), [0x00]));
543
544#[derive(Clone, Copy, Debug, PartialEq, Eq)]
546pub struct AutoPowerDownControl {
547 autopwr: AutoPowerDown,
548}
549
550impl AutoPowerDownControl {
551 pub const DEFAULT: Self = Self {
553 autopwr: AutoPowerDown::Enable,
554 };
555
556 pub const fn new(autopwr: AutoPowerDown) -> Self {
558 Self { autopwr }
559 }
560
561 #[allow(clippy::identity_op, reason = "readability")]
562 const fn bytes(&self) -> [u8; 1] {
563 [0xFF & !(1 << 7) | (self.autopwr as u8) << 7]
564 }
565}
566
567impl Default for AutoPowerDownControl {
568 fn default() -> Self {
569 Self::DEFAULT
570 }
571}
572
573impl WriteCommand for AutoPowerDownControl {
574 const OPCODE: Instr = Instr::AUTOPWRCTRL;
575 type Params = [u8; 1];
576 fn params(&self) -> Self::Params {
577 self.bytes()
578 }
579}
580
581#[derive(Clone, Copy, Debug, PartialEq, Eq)]
583pub enum AutoPowerDown {
584 Disable = 0,
586 Enable = 1,
588}
589
590const _: () = assert!(matches!(AutoPowerDownControl::DEFAULT.bytes(), [0xFF]));
591
592#[derive(Clone, Copy, Debug, PartialEq, Eq)]
594pub struct BoosterControl {
595 bsten: Booster,
596}
597
598impl BoosterControl {
599 pub const DEFAULT: Self = Self {
601 bsten: Booster::Disable,
602 };
603
604 pub const fn new(bsten: Booster) -> Self {
606 Self { bsten }
607 }
608
609 const fn bytes(&self) -> [u8; 1] {
610 [self.bsten as u8]
611 }
612}
613
614impl Default for BoosterControl {
615 fn default() -> Self {
616 Self::DEFAULT
617 }
618}
619
620impl WriteCommand for BoosterControl {
621 const OPCODE: Instr = Instr::BSTEN;
622 type Params = [u8; 1];
623 fn params(&self) -> Self::Params {
624 self.bytes()
625 }
626}
627
628#[derive(Clone, Copy, Debug, PartialEq, Eq)]
630pub enum Booster {
631 Disable = 0,
633 Enable = 1,
635}
636
637const _: () = assert!(matches!(BoosterControl::DEFAULT.bytes(), [0x00]));
638
639#[derive(Clone, Copy, Debug, PartialEq, Eq)]
641pub struct OscSetting {
642 oscen: OscEnable,
643 oscsw: OscSwitch,
644}
645
646impl OscSetting {
647 pub const DEFAULT: Self = Self {
649 oscen: OscEnable::Disable,
650 oscsw: OscSwitch::HpmMax32Hz,
651 };
652
653 #[must_use]
655 pub const fn with_osc_en(mut self, v: OscEnable) -> Self {
656 self.oscen = v;
657 self
658 }
659
660 #[must_use]
662 pub const fn with_osc_switch(mut self, v: OscSwitch) -> Self {
663 self.oscsw = v;
664 self
665 }
666
667 #[allow(clippy::identity_op, reason = "readability")]
668 const fn bytes(&self) -> [u8; 2] {
669 let sw = match self.oscsw {
670 OscSwitch::HpmMax32Hz => 1 << 5 | 1 << 2 | 1 << 1,
671 OscSwitch::HpmMax51Hz => 0,
672 };
673 [
674 0x26 & !(1 << 7 | 1 << 5 | 0b11 << 1) | (self.oscen as u8) << 7 | sw,
675 0xE9,
676 ]
677 }
678}
679
680impl Default for OscSetting {
681 fn default() -> Self {
682 Self::DEFAULT
683 }
684}
685
686impl WriteCommand for OscSetting {
687 const OPCODE: Instr = Instr::OSCSET;
688 type Params = [u8; 2];
689 fn params(&self) -> Self::Params {
690 self.bytes()
691 }
692}
693
694#[derive(Clone, Copy, Debug, PartialEq, Eq)]
696pub enum OscEnable {
697 Disable = 0,
699 Enable = 1,
701}
702
703#[derive(Clone, Copy, Debug, PartialEq, Eq)]
706pub enum OscSwitch {
707 HpmMax51Hz = 0b000,
709 HpmMax32Hz = 0b111,
711}
712
713const _: () = assert!(matches!(OscSetting::DEFAULT.bytes(), [0x26, 0xE9]));