raspberry_web/
utilities.rs1use crate::errors::RpWebError;
2use crate::models;
3use crate::schema::gpio_state::dsl::*;
4use chrono::Local;
5use diesel::prelude::*;
6use std::collections::HashMap;
7use std::u8::{MAX, MIN};
8
9pub fn reset_table_gpio_state(connection: &SqliteConnection) -> Result<(), RpWebError> {
10 info!("Resetting all fields in table 'gpio_state'...");
11
12 use crate::schema::gpio_state::dsl::*;
14 let gpio_ids_db: Vec<i32> = gpio_state
15 .load::<models::Gpio>(connection)?
16 .into_iter()
17 .map(|element| element.gpio_id)
18 .collect();
19
20 for idx in gpio_ids_db.iter() {
21 let target = gpio_state.filter(gpio_id.eq(idx));
22
23 let n_updated = diesel::update(target)
24 .set((
25 in_use.eq(0),
26 last_change.eq(Local::now().naive_local().to_string()),
27 gpio_mode.eq(""),
29 gpio_level.eq(""),
30 ))
31 .execute(connection)?; if n_updated == 1 {
34 debug!("Reset values for GPIO #{}", idx);
35 } else {
36 let errs = format!(
37 "SQL for resetting table 'gpio_state' for GPIO #{} affects {} rows",
38 idx, n_updated
39 );
40 error!("{}", errs);
41 Err(RpWebError::new(&errs))?
42 }
43 }
44 Ok(())
45}
46
47pub fn get_allowed_states(
48 connection: &SqliteConnection, desired_type: &str,
49) -> Result<HashMap<&'static str, bool>, RpWebError> {
50 use crate::schema::allowed_states::dsl::*;
51
52 let res = allowed_states
53 .filter(state_type.eq(desired_type.to_lowercase()))
54 .load::<models::AllowedStates>(connection)? .pop()
56 .ok_or({ RpWebError::new("state_type not found") })? .to_hashmap();
58
59 Ok(res)
60}
61
62pub fn set_gpio_in_use_db(id: i32, state: i32, conn: &SqliteConnection) -> Result<(), RpWebError> {
63 let target = gpio_state.filter(gpio_id.eq(id));
64
65 let result = diesel::update(target)
66 .set((
67 in_use.eq(state),
68 last_change.eq(Local::now().naive_local().to_string()),
69 ))
70 .execute(conn);
71
72 match result {
73 Ok(val) => {
74 if val == 1 {
75 info!("Set 'in_use={}' for GPIO #{}", state, id);
76 } else {
77 let errs = format!(
78 "SQL statement 'in_use={}' for GPIO #{} affects {} rows",
79 state, id, val
80 );
81 Err(RpWebError::new(&errs))?;
82 }
83 }
84 Err(err) => {
85 error!(
86 "Failed to update 'in_use={}' for GPIO #{}: {:?}",
87 state, id, err
88 );
89 Err(err)?;
90 }
91 }
92 Ok(())
93}
94
95pub fn set_gpio_mode_db(id: i32, mode: &str, conn: &SqliteConnection) -> Result<(), RpWebError> {
96 let target = gpio_state.filter(gpio_id.eq(id));
97
98 let result = diesel::update(target)
99 .set((
100 gpio_mode.eq(mode),
101 last_change.eq(Local::now().naive_local().to_string()),
102 ))
103 .execute(conn);
104
105 match result {
106 Ok(val) => {
107 if val == 1 {
108 info!("Set 'gpio_mode={}' for GPIO #{}", mode, id);
109 } else {
110 let errs = format!(
111 "SQL statement 'gpio_mode={}' for GPIO #{} affects {} rows",
112 mode, id, val
113 );
114 Err(RpWebError::new(&errs))?;
115 }
116 }
117 Err(err) => {
118 error!(
119 "Failed to update 'gpio_mode={}' for GPIO #{}: {:?}",
120 mode, id, err
121 );
122 Err(err)?;
123 }
124 }
125 Ok(())
126}
127
128pub fn set_gpio_level_db(id: i32, level: &str, conn: &SqliteConnection) -> Result<(), RpWebError> {
129 let target = gpio_state.filter(gpio_id.eq(id));
130
131 let result = diesel::update(target)
132 .set((
133 gpio_level.eq(level),
134 last_change.eq(Local::now().naive_local().to_string()),
135 ))
136 .execute(conn);
137
138 match result {
139 Ok(val) => {
140 if val == 1 {
141 info!("Set 'gpio_level={}' for GPIO #{}", level, id);
142 } else {
143 let errs = format!(
144 "SQL statement 'gpio_level={}' for GPIO #{} affects {} rows",
145 level, id, val
146 );
147 Err(RpWebError::new(&errs))?;
148 }
149 }
150 Err(err) => {
151 error!(
152 "Failed to update 'gpio_level={}' for GPIO #{}: {:?}",
153 level, id, err
154 );
155 Err(err)?;
156 }
157 }
158 Ok(())
159}
160
161pub fn i32_to_u8(x: i32) -> Result<u8, RpWebError> {
163 if MIN as i32 <= x && x <= MAX as i32 {
164 Ok(x as u8)
165 } else {
166 let errs = format!("Not satisfied: {} <= {} <= {}", MIN, x, MAX);
167 Err(RpWebError::new(&errs))
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174
175 #[test]
176 pub fn below_u8_min_must_fail() {
177 assert!(i32_to_u8(MIN as i32 - 1).is_err())
178 }
179
180 #[test]
181 pub fn above_u8_max_must_fail() {
182 assert!(i32_to_u8(MAX as i32 + 1).is_err())
183 }
184
185 #[test]
186 pub fn within_range_must_succeed() {
187 let xi32: i32 = 17;
188 let resu8 = i32_to_u8(xi32).unwrap();
189 assert_eq!(xi32 as u8, resu8);
190 }
191}