1use super::net_handle;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Level {
8 High,
10 Low,
12}
13
14impl Level {
15 pub fn as_str(&self) -> &'static str {
17 match self {
18 Level::High => "high",
19 Level::Low => "low",
20 }
21 }
22
23 pub fn is_high(&self) -> bool {
25 matches!(self, Level::High)
26 }
27}
28
29#[derive(Debug, Clone, Copy, Default)]
32pub struct WaitForLevelOptions {
33 pub timeout: Option<f64>,
37 pub scan_rate: Option<u32>,
39 pub scans_per_read: Option<u32>,
41 pub poll_interval: Option<f64>,
43}
44
45pub(crate) mod ops {
46 use std::time::Duration;
47
48 use serde_json::{json, Map, Value};
49
50 use super::{Level, WaitForLevelOptions};
51 use crate::error::Result;
52 use crate::wire::{net_command, unit, value_i64, CommandResponse, Op, Timeout};
53
54 const ROLE: &str = "gpio";
55
56 fn parse_level(resp: CommandResponse) -> Result<Level> {
57 value_i64(resp).map(|v| if v != 0 { Level::High } else { Level::Low })
58 }
59
60 pub(crate) fn input(name: &str) -> Op<Level> {
61 Op {
62 req: net_command(name, ROLE, "input", json!({}), Timeout::Default),
63 parse: parse_level,
64 }
65 }
66
67 pub(crate) fn output(name: &str, level: Level) -> Op<()> {
68 Op {
69 req: net_command(
70 name,
71 ROLE,
72 "output",
73 json!({ "level": level.as_str() }),
74 Timeout::Default,
75 ),
76 parse: unit,
77 }
78 }
79
80 pub(crate) fn output_high(name: &str) -> Op<()> {
81 Op {
82 req: net_command(name, ROLE, "output_high", json!({}), Timeout::Default),
83 parse: unit,
84 }
85 }
86
87 pub(crate) fn output_low(name: &str) -> Op<()> {
88 Op {
89 req: net_command(name, ROLE, "output_low", json!({}), Timeout::Default),
90 parse: unit,
91 }
92 }
93
94 pub(crate) fn toggle(name: &str) -> Op<Level> {
95 Op {
96 req: net_command(
97 name,
98 ROLE,
99 "output",
100 json!({ "level": "toggle" }),
101 Timeout::Default,
102 ),
103 parse: parse_level,
104 }
105 }
106
107 fn wait_params(level: Level, opts: &WaitForLevelOptions) -> Value {
108 let mut params = Map::new();
109 params.insert("level".to_string(), json!(level.as_str()));
110 if let Some(t) = opts.timeout {
111 params.insert("timeout".to_string(), json!(t));
112 }
113 if let Some(r) = opts.scan_rate {
114 params.insert("scan_rate".to_string(), json!(r));
115 }
116 if let Some(s) = opts.scans_per_read {
117 params.insert("scans_per_read".to_string(), json!(s));
118 }
119 if let Some(p) = opts.poll_interval {
120 params.insert("poll_interval".to_string(), json!(p));
121 }
122 Value::Object(params)
123 }
124
125 pub(crate) fn wait_for_level_with(
126 name: &str,
127 level: Level,
128 opts: &WaitForLevelOptions,
129 ) -> Op<f64> {
130 let timeout = match opts.timeout {
135 Some(t) => Timeout::After(Duration::from_secs_f64(t + 20.0)),
136 None => Timeout::Unbounded,
137 };
138 Op {
139 req: net_command(name, ROLE, "wait_for_level", wait_params(level, opts), timeout),
140 parse: crate::wire::value_f64,
141 }
142 }
143
144 pub(crate) fn wait_for_level(name: &str, level: Level, timeout_s: f64) -> Op<f64> {
145 wait_for_level_with(
146 name,
147 level,
148 &WaitForLevelOptions {
149 timeout: Some(timeout_s),
150 ..WaitForLevelOptions::default()
151 },
152 )
153 }
154}
155
156net_handle! {
157 sync: Gpio,
159 async: AsyncGpio,
160 methods: {
161 fn input() -> Level = ops::input;
163 fn output(level: Level) -> () = ops::output;
165 fn output_high() -> () = ops::output_high;
167 fn output_low() -> () = ops::output_low;
169 fn toggle() -> Level = ops::toggle;
171 fn wait_for_level(level: Level, timeout_s: f64) -> f64 = ops::wait_for_level;
175 fn wait_for_level_with(level: Level, opts: &WaitForLevelOptions) -> f64 = ops::wait_for_level_with;
178 }
179}