Skip to main content

st7305_lcd/cmd/
power.rs

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/// `GCTRL` (§8.2.10): gate voltages VGH and VGL.
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub struct GateVoltageControl {
34    vgha: Vgh,
35    vgla: Vgl,
36}
37
38impl GateVoltageControl {
39    /// Register default: VGH 15 V, VGL -10 V.
40    pub const DEFAULT: Self = Self {
41        vgha: Vgh::from_mv(15_000),
42        vgla: Vgl::from_mv(-10_000),
43    };
44
45    /// `VGHA[4:0]`.
46    #[must_use]
47    pub const fn with_vgh(mut self, v: Vgh) -> Self {
48        self.vgha = v;
49        self
50    }
51
52    /// `VGLA[4:0]`.
53    #[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    /// Gate high voltage VGH.
80    Vgh: 8_000..=17_000, zero = 8_000, step = 500
81);
82millivolt_value!(
83    /// Gate low voltage VGL.
84    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/// `VSHPCTRL` (§8.2.11): source high positive voltage of the four source
104/// voltage sets (see [`SourceVoltageSelect`]).
105#[derive(Clone, Copy, Debug, PartialEq, Eq)]
106pub struct SourceHighPositiveVoltageControl {
107    vshpa: [SourceHighPositiveVoltage; 4],
108}
109
110impl SourceHighPositiveVoltageControl {
111    /// Register default: 5.0 V in all four sets.
112    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    /// `VSHPA1..=4`.
122    #[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    /// Source high positive voltage VSHPAx.
154    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/// `VSLPCTRL` (§8.2.12): source low positive voltage of the four source
175/// voltage sets (see [`SourceVoltageSelect`]).
176#[derive(Clone, Copy, Debug, PartialEq, Eq)]
177pub struct SourceLowPositiveVoltageControl {
178    vslpa: [SourceLowPositiveVoltage; 4],
179}
180
181impl SourceLowPositiveVoltageControl {
182    /// Register default: 1.0 V in all four sets.
183    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    /// `VSLPA1..=4`.
193    #[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    /// Source low positive voltage VSLPAx.
225    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/// `VSHNCTRL` (§8.2.13): source high negative voltage of the four source
246/// voltage sets (see [`SourceVoltageSelect`]).
247#[derive(Clone, Copy, Debug, PartialEq, Eq)]
248pub struct SourceHighNegativeVoltageControl {
249    vshna: [SourceHighNegativeVoltage; 4],
250}
251
252impl SourceHighNegativeVoltageControl {
253    /// Register default: -3.9 V in all four sets.
254    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    /// `VSHNA1..=4`.
264    #[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    /// Source high negative voltage VSHNAx.
296    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/// `VSLNCTRL` (§8.2.14): source low negative voltage of the four source
317/// voltage sets (see [`SourceVoltageSelect`]).
318#[derive(Clone, Copy, Debug, PartialEq, Eq)]
319pub struct SourceLowNegativeVoltageControl {
320    vslna: [SourceLowNegativeVoltage; 4],
321}
322
323impl SourceLowNegativeVoltageControl {
324    /// Register default: -0.4 V in all four sets.
325    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    /// `VSLNA1..=4`.
335    #[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    /// Source low negative voltage VSLNAx.
367    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/// `VSIKCTRL` (§8.2.15): source gamma voltages.
388#[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    /// Register default: VSIP 3.6 V, VSKP 2.6 V, VSIN -2.4 V, VSKN -1.4 V.
398    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    /// `VSIP[7:0]`: positive gamma voltage 1.
406    #[must_use]
407    pub const fn with_vsip(mut self, v: VsipVoltage) -> Self {
408        self.vsip = v;
409        self
410    }
411
412    /// `VSKP[7:0]`: positive gamma voltage 2.
413    #[must_use]
414    pub const fn with_vskp(mut self, v: VskpVoltage) -> Self {
415        self.vskp = v;
416        self
417    }
418
419    /// `VSIN[7:0]`: negative gamma voltage 1.
420    #[must_use]
421    pub const fn with_vsin(mut self, v: VsinVoltage) -> Self {
422        self.vsin = v;
423        self
424    }
425
426    /// `VSKN[7:0]`: negative gamma voltage 2.
427    #[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    /// Positive gamma voltage 1 (VSIP).
454    VsipVoltage: 2_200..=5_000, zero = 2_200, step = 20
455);
456millivolt_value!(
457    /// Positive gamma voltage 2 (VSKP).
458    VskpVoltage: 1_200..=4_000, zero = 1_200, step = 20
459);
460millivolt_value!(
461    /// Negative gamma voltage 1 (VSIN).
462    VsinVoltage: -3_800..=-1_000, zero = -1_000, step = 20
463);
464millivolt_value!(
465    /// Negative gamma voltage 2 (VSKN).
466    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/// `VSHLSEL` (§8.2.16): which of the four source voltage sets is used.
494#[derive(Clone, Copy, Debug, PartialEq, Eq)]
495pub struct SourceVoltageSelect {
496    sdhlsel: SourceVoltage,
497}
498
499impl SourceVoltageSelect {
500    /// Register default: set 1.
501    pub const DEFAULT: Self = Self {
502        sdhlsel: SourceVoltage::Source1,
503    };
504
505    /// Uses the set `sdhlsel`.
506    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/// `VSHLSEL[1:0]`: a source voltage set.
530#[derive(Clone, Copy, Debug, PartialEq, Eq)]
531pub enum SourceVoltage {
532    /// VSHPA1/VSLPA1/VSHNA1/VSLNA1
533    Source1 = 0,
534    /// VSHPA2/VSLPA2/VSHNA2/VSLNA2
535    Source2 = 1,
536    /// VSHPA3/VSLPA3/VSHNA3/VSLNA3
537    Source3 = 2,
538    /// VSHPA4/VSLPA4/VSHNA4/VSLNA4
539    Source4 = 3,
540}
541
542const _: () = assert!(matches!(SourceVoltageSelect::DEFAULT.bytes(), [0x00]));
543
544/// `AUTOPWRCTRL` (§8.2.20): automatic power down on or off.
545#[derive(Clone, Copy, Debug, PartialEq, Eq)]
546pub struct AutoPowerDownControl {
547    autopwr: AutoPowerDown,
548}
549
550impl AutoPowerDownControl {
551    /// Register default `0xFF`: enabled.
552    pub const DEFAULT: Self = Self {
553        autopwr: AutoPowerDown::Enable,
554    };
555
556    /// `AUTOPWR` (D7) = `autopwr`.
557    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/// `AUTOPWR`: automatic power down.
582#[derive(Clone, Copy, Debug, PartialEq, Eq)]
583pub enum AutoPowerDown {
584    /// Off
585    Disable = 0,
586    /// On
587    Enable = 1,
588}
589
590const _: () = assert!(matches!(AutoPowerDownControl::DEFAULT.bytes(), [0xFF]));
591
592/// `BSTEN` (§8.2.21): booster on or off.
593#[derive(Clone, Copy, Debug, PartialEq, Eq)]
594pub struct BoosterControl {
595    bsten: Booster,
596}
597
598impl BoosterControl {
599    /// Register default `0x00`: booster off.
600    pub const DEFAULT: Self = Self {
601        bsten: Booster::Disable,
602    };
603
604    /// `BSTEN` (D0) = `bsten`.
605    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/// `BSTEN`: booster.
629#[derive(Clone, Copy, Debug, PartialEq, Eq)]
630pub enum Booster {
631    /// Off
632    Disable = 0,
633    /// On
634    Enable = 1,
635}
636
637const _: () = assert!(matches!(BoosterControl::DEFAULT.bytes(), [0x00]));
638
639/// `OSCSET` (§8.2.23): oscillator on/off and the maximum HPM frame rate.
640#[derive(Clone, Copy, Debug, PartialEq, Eq)]
641pub struct OscSetting {
642    oscen: OscEnable,
643    oscsw: OscSwitch,
644}
645
646impl OscSetting {
647    /// Register default `0x26, 0xE9`: oscillator off, 32 Hz maximum.
648    pub const DEFAULT: Self = Self {
649        oscen: OscEnable::Disable,
650        oscsw: OscSwitch::HpmMax32Hz,
651    };
652
653    /// `OSCEN` (D7).
654    #[must_use]
655    pub const fn with_osc_en(mut self, v: OscEnable) -> Self {
656        self.oscen = v;
657        self
658    }
659
660    /// `OSCSW[2:0]` (D5, D2, D1).
661    #[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/// `OSCEN`: oscillator.
695#[derive(Clone, Copy, Debug, PartialEq, Eq)]
696pub enum OscEnable {
697    /// Off
698    Disable = 0,
699    /// On
700    Enable = 1,
701}
702
703/// OSCSW\[2:0\]: selects the maximum HPM frame rate.
704/// The actual rate is this maximum at HFRA=1 and half of it at HFRA=0 (see FRCTRL).
705#[derive(Clone, Copy, Debug, PartialEq, Eq)]
706pub enum OscSwitch {
707    /// OSCSW = 000
708    HpmMax51Hz = 0b000,
709    /// OSCSW = 111
710    HpmMax32Hz = 0b111,
711}
712
713const _: () = assert!(matches!(OscSetting::DEFAULT.bytes(), [0x26, 0xE9]));