eculocate

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 2cfe436ac9e02c9bea7588041ace96ccb48580b0
parent 938cb4fda0d48015bf89033904cb9d6cf03a1eac
Author: Daniel Barlow <dan@telent.net>
Date:   Mon,  2 Feb 2026 21:19:39 +0000

scan wireless networks & publish over ble

does not actually connect yet

Diffstat:
Mclient/ble.py | 49+++++++++++++++++++++++++++++++++++++++++--------
Mecu-esp32/src/main.rs | 35+++++++++++++++++++++++++++++------
Mecu-esp32/src/wibble.rs | 35+++++++++++++++++++++++++++--------
Mecu-esp32/src/wifi.rs | 33+++++++++++++--------------------
4 files changed, 110 insertions(+), 42 deletions(-)

diff --git a/client/ble.py b/client/ble.py @@ -3,26 +3,59 @@ import readline import rlcompleter import asyncio from bleak import BleakClient,BleakScanner +import sys readline.parse_and_bind("tab: complete") address = "FF:E4:05:1A:8F:FF" -CURRENT_INDEX_UUID = "76be25c2-0803-44fc-a97c-bcb56c69c926" + +UUIDS = { + 'connection_state': "76be25c2-0801-44fc-a97c-bcb56c69c926", + 'max_index': "76be25c2-0802-44fc-a97c-bcb56c69c926", + 'current_index': "76be25c2-0803-44fc-a97c-bcb56c69c926", + 'current_network': "76be25c2-0804-44fc-a97c-bcb56c69c926", + 'secret': "76be25c2-0805-44fc-a97c-bcb56c69c926", +} + +networks = [] +max_index = 0 + +async def show_networks(client): + global max_index + global networks + max_index = ord(await client.read_gatt_char(UUIDS['max_index'])) + print(f"{max_index} networks available") + networks = [None] + + for i in range(1, max_index + 1): + await client.write_gatt_char(UUIDS['current_index'], bytes([i])) + current_network = await client.read_gatt_char(UUIDS['current_network']) + networks.append(current_network) + print(f"{i}: {current_network}") + +async def choose_network(client, name): + for i in range(1, max_index + 1): + if networks[i].find(name) >= 0: + print(f"found {name} in {networks[i]}") + chosen = i + break + if chosen: + await client.write_gatt_char(UUIDS['current_index'], bytes([chosen])) + new_index = await client.read_gatt_char(UUIDS['current_index']) + print(f"set to {new_index[0]}") async def main(address): - print("go") + preferred = sys.argv[1] if len(sys.argv) > 1 else None + print(f"choose {preferred}") devices = await BleakScanner.discover() for d in devices: print(d) async with BleakClient(address, timeout=30) as client: - current_index = await client.read_gatt_char(CURRENT_INDEX_UUID) - print(f"Model Number: {current_index}") - current_index = ord(current_index) + 1 - await client.write_gatt_char(CURRENT_INDEX_UUID, bytes([current_index])) - current_index = await client.read_gatt_char(CURRENT_INDEX_UUID) - print(f"Model Number: {current_index}") + await show_networks(client) + if preferred != None: + await choose_network(client, preferred.encode(encoding="utf-8")) asyncio.run(main(address)) diff --git a/ecu-esp32/src/main.rs b/ecu-esp32/src/main.rs @@ -10,6 +10,7 @@ use esp_backtrace as _; use esp_println as _; use esp_alloc as _; +use alloc::vec::Vec; pub mod ecu; pub mod wifi; @@ -27,15 +28,19 @@ use embassy_executor::Spawner; use embassy_futures::join::join3; use embassy_time::Timer; -use esp_radio::Controller; +use esp_radio::{ + Controller, + wifi::{ + ClientConfig, + ModeConfig, + } +}; use log::{info}; use crate::ecu::Ecu; use crate::ota::Flasher; - - extern crate alloc; // This creates a default app-descriptor required by the esp-idf bootloader. @@ -86,13 +91,31 @@ async fn main(s : Spawner) { let esp_radio_ctrl = // esp_radio::init().expect("esp_radio init failed"); &*mk_static!(Controller<'static>, esp_radio::init().unwrap()); + let (mut wifi_controller, interfaces) = + esp_radio::wifi::new(esp_radio_ctrl, peripherals.WIFI, Default::default()).unwrap(); + let wifi_interface = interfaces.sta; + let station_config = ModeConfig::Client(ClientConfig::default()); + wifi_controller.set_config(&station_config).expect("can't config wifi"); + wifi_controller.start_async().await.expect("wifi failed to start"); + + let wifi_networks : Vec<[u8;40]> = + crate::wifi::scan_networks(&mut wifi_controller).await.into_iter().map( + |ap| { + let mut s : [u8; 40] = [0u8; 40]; + s[0] = (ap.signal_strength & 0x7f) as u8; + s[1..7].copy_from_slice(&ap.bssid); + let name = ap.ssid.as_bytes(); + s[8..(8+name.len())].copy_from_slice(name); + s + } + ).collect(); + join3( crate::wifi::start_wifi(&s, - esp_radio_ctrl, + wifi_controller, wifi_interface, flasher, - peripherals.WIFI, &mut ecu), - wibble::run_ble(&esp_radio_ctrl, peripherals.BT), + wibble::run_ble(&esp_radio_ctrl, peripherals.BT, wifi_networks), async { loop { Timer::after_millis(1000).await; diff --git a/ecu-esp32/src/wibble.rs b/ecu-esp32/src/wibble.rs @@ -6,7 +6,7 @@ use log::{warn,info}; use embassy_futures::join::join; use embassy_futures::select::select; -use alloc::string::String; +use alloc::vec::Vec; /// Max number of connections const CONNECTIONS_MAX: usize = 1; @@ -48,7 +48,8 @@ struct WifiProvisioningService { pub async fn run_ble(radio_init: &RadioController<'static>, - peripheral: esp_hal::peripherals::BT<'_>) { + peripheral: esp_hal::peripherals::BT<'_>, + networks: Vec<[u8; 40]>) { // let radio_init = esp_radio::init().expect("Failed to initialize Wi-Fi/BLE controller"); let connector = BleConnector::new(&radio_init, peripheral, Default::default()).expect("connector"); let controller: ExternalController<_, 20> = ExternalController::new(connector); @@ -78,7 +79,7 @@ pub async fn run_ble(radio_init: &RadioController<'static>, match advertise("Eculocate", &mut peripheral, &server).await { Ok(conn) => { // set up tasks when the connection is established to a central, so they don't run when no one is connected. - let a = gatt_events_task(&server, &conn); + let a = gatt_events_task(&server, &conn, &networks); let b = custom_task(&server, &conn, &stack); // run until any task ends (usually because the connection has been closed), // then return to advertising state. @@ -107,8 +108,16 @@ async fn ble_task<C: Controller, P: PacketPool>(mut runner: Runner<'_, C, P>) { /// /// This function will handle the GATT events and process them. /// This is how we interact with read and write requests. -async fn gatt_events_task<P: PacketPool>(server: &Server<'_>, conn: &GattConnection<'_, '_, P>) -> Result<(), Error> { - let current_index = server.wifi_provisioning_service.current_network_index; +async fn gatt_events_task<P: PacketPool>(server: &Server<'_>, + conn: &GattConnection<'_, '_, P>, + networks: &Vec<[u8; 40]> ) -> Result<(), Error> { + let wps = &server.wifi_provisioning_service; + for ap in networks { + info!("ap {:?}", ap) + }; + let max_index : u8 = (networks.len() & 0xff).try_into().unwrap(); + server.set(&wps.max_network_index, &max_index); + let current_index = wps.current_network_index; let reason = loop { match conn.next().await { GattConnectionEvent::Disconnected { reason } => break reason, @@ -123,10 +132,20 @@ async fn gatt_events_task<P: PacketPool>(server: &Server<'_>, conn: &GattConnect // } // } GattEvent::Write(event) => { - info!("[gatt] write handle {:?}", event.handle()); + info!("[gatt] write handle {:?} {:?}", event.handle(), + event.data()); if event.handle() == current_index.handle { - info!("[gatt] switch current index: {:?}", event.data()); - } + let i = (event.data()[0]) as usize; + info!("[gatt] switch current index: {:?}", i); + if i == 0 { + server.set(&wps.current_network, &[0u8;40]); + } else if i <= networks.len() { + server.set(&wps.current_network, + &(networks[i - 1])); + } else { + warn!("index {:?} out of range", i); + } + } }, _ => {} }; diff --git a/ecu-esp32/src/wifi.rs b/ecu-esp32/src/wifi.rs @@ -28,7 +28,7 @@ use esp_hal::{ }; use esp_println::println; use esp_radio::{ - Controller, +// Controller, wifi::{ ClientConfig, ModeConfig, @@ -37,6 +37,7 @@ use esp_radio::{ WifiDevice, WifiEvent, WifiStaState, + AccessPointInfo }, }; @@ -130,26 +131,27 @@ impl SessionStore { } } +pub async fn scan_networks(controller: &mut WifiController<'_>) -> Vec<AccessPointInfo> { + println!("Scan"); + let scan_config = ScanConfig::default().with_max(10); + let result = controller + .scan_with_config_async(scan_config) + .await + .expect("scan failed"); + result +} pub async fn start_wifi(spawner: &Spawner, - esp_radio_ctrl: &'static Controller<'static>, + controller: WifiController<'static>, + wifi_interface: WifiDevice<'static>, flasher: crate::ota::Flasher<'_>, - wifi_peripheral: esp_hal::peripherals::WIFI<'static>, ecu: &mut crate::ecu::Ecu<'_>) { - - - let (controller, interfaces) = - esp_radio::wifi::new(esp_radio_ctrl, wifi_peripheral, Default::default()).unwrap(); - - let wifi_interface = interfaces.sta; - let config = embassy_net::Config::dhcpv4(Default::default()); let rng = Rng::new(); let seed = (rng.random() as u64) << 32 | rng.random() as u64; - // Init network stack let (stack, runner) = embassy_net::new( wifi_interface, @@ -227,15 +229,6 @@ async fn connection(mut controller: WifiController<'static>) { controller.set_config(&station_config).unwrap(); controller.start_async().await.expect("wifi controller failed to start"); - println!("Scan"); - let scan_config = ScanConfig::default().with_max(10); - let result = controller - .scan_with_config_async(scan_config) - .await - .unwrap(); - for ap in result { - println!("{:?}", ap); - } } println!("About to connect..."); let station_config = ModeConfig::Client(