diff options
Diffstat (limited to 'embassy-net-esp-hosted/src/control.rs')
| -rw-r--r-- | embassy-net-esp-hosted/src/control.rs | 69 |
1 files changed, 37 insertions, 32 deletions
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index cbc194877..a7f5168c2 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | use embassy_net_driver_channel as ch; | 1 | use embassy_net_driver_channel as ch; |
| 2 | use embassy_net_driver_channel::driver::{HardwareAddress, LinkState}; | 2 | use embassy_net_driver_channel::driver::{HardwareAddress, LinkState}; |
| 3 | use heapless::String; | 3 | use heapless::String; |
| 4 | use micropb::{MessageDecode, MessageEncode, PbEncoder}; | ||
| 4 | 5 | ||
| 5 | use crate::ioctl::Shared; | 6 | use crate::ioctl::Shared; |
| 6 | use crate::proto::{self, CtrlMsg}; | 7 | use crate::proto::{self, CtrlMsg}; |
| @@ -38,7 +39,7 @@ enum WifiMode { | |||
| 38 | ApSta = 3, | 39 | ApSta = 3, |
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | pub use proto::CtrlWifiSecProt as Security; | 42 | pub use proto::Ctrl_WifiSecProt as Security; |
| 42 | 43 | ||
| 43 | /// WiFi status. | 44 | /// WiFi status. |
| 44 | #[derive(Clone, Debug)] | 45 | #[derive(Clone, Debug)] |
| @@ -59,18 +60,18 @@ pub struct Status { | |||
| 59 | macro_rules! ioctl { | 60 | macro_rules! ioctl { |
| 60 | ($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => { | 61 | ($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => { |
| 61 | let mut msg = proto::CtrlMsg { | 62 | let mut msg = proto::CtrlMsg { |
| 62 | msg_id: proto::CtrlMsgId::$req_variant as _, | 63 | r#msg_id: proto::CtrlMsgId::$req_variant, |
| 63 | msg_type: proto::CtrlMsgType::Req as _, | 64 | r#msg_type: proto::CtrlMsgType::Req, |
| 64 | payload: Some(proto::CtrlMsgPayload::$req_variant($req)), | 65 | r#payload: Some(proto::CtrlMsg_::Payload::$req_variant($req)), |
| 65 | }; | 66 | }; |
| 66 | $self.ioctl(&mut msg).await?; | 67 | $self.ioctl(&mut msg).await?; |
| 67 | #[allow(unused_mut)] | 68 | #[allow(unused_mut)] |
| 68 | let Some(proto::CtrlMsgPayload::$resp_variant(mut $resp)) = msg.payload else { | 69 | let Some(proto::CtrlMsg_::Payload::$resp_variant(mut $resp)) = msg.payload else { |
| 69 | warn!("unexpected response variant"); | 70 | warn!("unexpected response variant"); |
| 70 | return Err(Error::Internal); | 71 | return Err(Error::Internal); |
| 71 | }; | 72 | }; |
| 72 | if $resp.resp != 0 { | 73 | if $resp.resp != 0 { |
| 73 | return Err(Error::Failed($resp.resp)); | 74 | return Err(Error::Failed($resp.resp as u32)); |
| 74 | } | 75 | } |
| 75 | }; | 76 | }; |
| 76 | } | 77 | } |
| @@ -100,26 +101,28 @@ impl<'a> Control<'a> { | |||
| 100 | 101 | ||
| 101 | /// Get the current status. | 102 | /// Get the current status. |
| 102 | pub async fn get_status(&mut self) -> Result<Status, Error> { | 103 | pub async fn get_status(&mut self) -> Result<Status, Error> { |
| 103 | let req = proto::CtrlMsgReqGetApConfig {}; | 104 | let req = proto::CtrlMsg_Req_GetAPConfig {}; |
| 104 | ioctl!(self, ReqGetApConfig, RespGetApConfig, req, resp); | 105 | ioctl!(self, ReqGetApConfig, RespGetApConfig, req, resp); |
| 105 | trim_nulls(&mut resp.ssid); | 106 | let ssid = core::str::from_utf8(&resp.ssid).map_err(|_| Error::Internal)?; |
| 107 | let ssid = String::try_from(ssid.trim_end_matches('\0')).map_err(|_| Error::Internal)?; | ||
| 108 | let bssid_str = core::str::from_utf8(&resp.bssid).map_err(|_| Error::Internal)?; | ||
| 106 | Ok(Status { | 109 | Ok(Status { |
| 107 | ssid: resp.ssid, | 110 | ssid, |
| 108 | bssid: parse_mac(&resp.bssid)?, | 111 | bssid: parse_mac(bssid_str)?, |
| 109 | rssi: resp.rssi as _, | 112 | rssi: resp.rssi as _, |
| 110 | channel: resp.chnl, | 113 | channel: resp.chnl as u32, |
| 111 | security: resp.sec_prot, | 114 | security: resp.sec_prot, |
| 112 | }) | 115 | }) |
| 113 | } | 116 | } |
| 114 | 117 | ||
| 115 | /// Connect to the network identified by ssid using the provided password. | 118 | /// Connect to the network identified by ssid using the provided password. |
| 116 | pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> { | 119 | pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> { |
| 117 | let req = proto::CtrlMsgReqConnectAp { | 120 | let req = proto::CtrlMsg_Req_ConnectAP { |
| 118 | ssid: unwrap!(String::try_from(ssid)), | 121 | r#ssid: unwrap!(String::try_from(ssid)), |
| 119 | pwd: unwrap!(String::try_from(password)), | 122 | r#pwd: unwrap!(String::try_from(password)), |
| 120 | bssid: String::new(), | 123 | r#bssid: String::new(), |
| 121 | listen_interval: 3, | 124 | r#listen_interval: 3, |
| 122 | is_wpa3_supported: true, | 125 | r#is_wpa3_supported: true, |
| 123 | }; | 126 | }; |
| 124 | ioctl!(self, ReqConnectAp, RespConnectAp, req, resp); | 127 | ioctl!(self, ReqConnectAp, RespConnectAp, req, resp); |
| 125 | self.state_ch.set_link_state(LinkState::Up); | 128 | self.state_ch.set_link_state(LinkState::Up); |
| @@ -128,7 +131,7 @@ impl<'a> Control<'a> { | |||
| 128 | 131 | ||
| 129 | /// Disconnect from any currently connected network. | 132 | /// Disconnect from any currently connected network. |
| 130 | pub async fn disconnect(&mut self) -> Result<(), Error> { | 133 | pub async fn disconnect(&mut self) -> Result<(), Error> { |
| 131 | let req = proto::CtrlMsgReqGetStatus {}; | 134 | let req = proto::CtrlMsg_Req_GetStatus {}; |
| 132 | ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp); | 135 | ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp); |
| 133 | self.state_ch.set_link_state(LinkState::Down); | 136 | self.state_ch.set_link_state(LinkState::Down); |
| 134 | Ok(()) | 137 | Ok(()) |
| @@ -136,21 +139,25 @@ impl<'a> Control<'a> { | |||
| 136 | 139 | ||
| 137 | /// duration in seconds, clamped to [10, 3600] | 140 | /// duration in seconds, clamped to [10, 3600] |
| 138 | async fn set_heartbeat(&mut self, duration: u32) -> Result<(), Error> { | 141 | async fn set_heartbeat(&mut self, duration: u32) -> Result<(), Error> { |
| 139 | let req = proto::CtrlMsgReqConfigHeartbeat { enable: true, duration }; | 142 | let req = proto::CtrlMsg_Req_ConfigHeartbeat { |
| 143 | r#enable: true, | ||
| 144 | r#duration: duration as i32, | ||
| 145 | }; | ||
| 140 | ioctl!(self, ReqConfigHeartbeat, RespConfigHeartbeat, req, resp); | 146 | ioctl!(self, ReqConfigHeartbeat, RespConfigHeartbeat, req, resp); |
| 141 | Ok(()) | 147 | Ok(()) |
| 142 | } | 148 | } |
| 143 | 149 | ||
| 144 | async fn get_mac_addr(&mut self) -> Result<[u8; 6], Error> { | 150 | async fn get_mac_addr(&mut self) -> Result<[u8; 6], Error> { |
| 145 | let req = proto::CtrlMsgReqGetMacAddress { | 151 | let req = proto::CtrlMsg_Req_GetMacAddress { |
| 146 | mode: WifiMode::Sta as _, | 152 | r#mode: WifiMode::Sta as _, |
| 147 | }; | 153 | }; |
| 148 | ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp); | 154 | ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp); |
| 149 | parse_mac(&resp.mac) | 155 | let mac_str = core::str::from_utf8(&resp.mac).map_err(|_| Error::Internal)?; |
| 156 | parse_mac(mac_str) | ||
| 150 | } | 157 | } |
| 151 | 158 | ||
| 152 | async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> { | 159 | async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> { |
| 153 | let req = proto::CtrlMsgReqSetMode { mode }; | 160 | let req = proto::CtrlMsg_Req_SetMode { r#mode: mode as i32 }; |
| 154 | ioctl!(self, ReqSetWifiMode, RespSetWifiMode, req, resp); | 161 | ioctl!(self, ReqSetWifiMode, RespSetWifiMode, req, resp); |
| 155 | 162 | ||
| 156 | Ok(()) | 163 | Ok(()) |
| @@ -160,11 +167,15 @@ impl<'a> Control<'a> { | |||
| 160 | debug!("ioctl req: {:?}", &msg); | 167 | debug!("ioctl req: {:?}", &msg); |
| 161 | 168 | ||
| 162 | let mut buf = [0u8; 128]; | 169 | let mut buf = [0u8; 128]; |
| 170 | let buf_len = buf.len(); | ||
| 163 | 171 | ||
| 164 | let req_len = noproto::write(msg, &mut buf).map_err(|_| { | 172 | let mut encoder = PbEncoder::new(&mut buf[..]); |
| 173 | msg.encode(&mut encoder).map_err(|_| { | ||
| 165 | warn!("failed to serialize control request"); | 174 | warn!("failed to serialize control request"); |
| 166 | Error::Internal | 175 | Error::Internal |
| 167 | })?; | 176 | })?; |
| 177 | let remaining = encoder.into_writer(); | ||
| 178 | let req_len = buf_len - remaining.len(); | ||
| 168 | 179 | ||
| 169 | struct CancelOnDrop<'a>(&'a Shared); | 180 | struct CancelOnDrop<'a>(&'a Shared); |
| 170 | 181 | ||
| @@ -186,8 +197,8 @@ impl<'a> Control<'a> { | |||
| 186 | 197 | ||
| 187 | ioctl.defuse(); | 198 | ioctl.defuse(); |
| 188 | 199 | ||
| 189 | *msg = noproto::read(&buf[..resp_len]).map_err(|_| { | 200 | msg.decode_from_bytes(&buf[..resp_len]).map_err(|_| { |
| 190 | warn!("failed to serialize control request"); | 201 | warn!("failed to deserialize control response"); |
| 191 | Error::Internal | 202 | Error::Internal |
| 192 | })?; | 203 | })?; |
| 193 | debug!("ioctl resp: {:?}", msg); | 204 | debug!("ioctl resp: {:?}", msg); |
| @@ -221,9 +232,3 @@ fn parse_mac(mac: &str) -> Result<[u8; 6], Error> { | |||
| 221 | } | 232 | } |
| 222 | Ok(res) | 233 | Ok(res) |
| 223 | } | 234 | } |
| 224 | |||
| 225 | fn trim_nulls<const N: usize>(s: &mut String<N>) { | ||
| 226 | while s.chars().rev().next() == Some(0 as char) { | ||
| 227 | s.pop(); | ||
| 228 | } | ||
| 229 | } | ||
