Skip to content

Commit 157f20c

Browse files
committed
Implement quick_reconnect
This switch makes the Bluetooth connection persistent across HU restarts when possible, speeding up reconnections because Bluetooth and Wi-Fi are effectively not reconnected (same Wi-Fi parameters are reused).
1 parent 2d5ffdc commit 157f20c

File tree

3 files changed

+106
-37
lines changed

3 files changed

+106
-37
lines changed

src/bluetooth.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ use bluer::{
1111
};
1212
use futures::StreamExt;
1313
use simplelog::*;
14+
use std::sync::atomic::AtomicBool;
15+
use std::sync::atomic::Ordering;
1416
use std::sync::Arc;
1517
use std::time::{Duration, Instant};
1618
use tokio::io::AsyncReadExt;
1719
use tokio::io::AsyncWriteExt;
20+
use tokio::sync::broadcast::Receiver as BroadcastReceiver;
1821
use tokio::sync::Notify;
1922
use tokio::time::timeout;
2023

@@ -563,6 +566,9 @@ impl Bluetooth {
563566
tcp_start: Arc<Notify>,
564567
bt_timeout: Duration,
565568
stopped: bool,
569+
quick_reconnect: bool,
570+
mut need_restart: BroadcastReceiver<()>,
571+
profile_connected: Arc<AtomicBool>,
566572
) -> Result<()> {
567573
// Use the provided session and adapter instead of creating new ones
568574
let (address, mut stream) = self
@@ -571,10 +577,40 @@ impl Bluetooth {
571577
Self::send_params(wifi_config.clone(), &mut stream).await?;
572578
tcp_start.notify_one();
573579

574-
// handshake complete, now disconnect the device so it should
575-
// connect to real HU for calls
576-
let device = self.adapter.device(bluer::Address(*address))?;
577-
let _ = device.disconnect().await;
580+
if quick_reconnect {
581+
// keep the bluetooth profile connection alive
582+
// and use it in a loop to restart handshake when necessary
583+
let _ = Some(tokio::spawn(async move {
584+
profile_connected.store(true, Ordering::Relaxed);
585+
loop {
586+
// wait for restart notification from main loop (eg when HU disconnected)
587+
let _ = need_restart.recv().await;
588+
589+
// now restart handshake with the same params
590+
match Self::send_params(wifi_config.clone(), &mut stream).await {
591+
Ok(_) => {
592+
tcp_start.notify_one();
593+
continue;
594+
}
595+
Err(e) => {
596+
error!(
597+
"{} handshake restart error: {}, doing full restart!",
598+
NAME, e
599+
);
600+
// this break should end this task
601+
break;
602+
}
603+
}
604+
}
605+
// we are now disconnected, redo bluetooth connection
606+
profile_connected.store(false, Ordering::Relaxed);
607+
}));
608+
} else {
609+
// handshake complete, now disconnect the device so it should
610+
// connect to real HU for calls
611+
let device = self.adapter.device(bluer::Address(*address))?;
612+
let _ = device.disconnect().await;
613+
}
578614

579615
info!("{} 🚀 Bluetooth launch sequence completed", NAME);
580616

src/io_uring.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ use simplelog::*;
44
use std::cell::RefCell;
55
use std::marker::PhantomData;
66
use std::rc::Rc;
7-
use std::sync::atomic::{AtomicUsize, Ordering};
7+
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
88
use std::sync::Arc;
99
use std::time::{Duration, Instant};
1010
use tokio::io::copy_bidirectional;
1111
use tokio::net::TcpStream as TokioTcpStream;
12+
use tokio::sync::broadcast::Sender as BroadcastSender;
1213
use tokio::sync::mpsc::{Receiver, Sender};
1314
use tokio::sync::{mpsc, Mutex, Notify};
1415
use tokio::task::JoinHandle;
@@ -284,11 +285,12 @@ async fn tcp_wait_for_connection(listener: &mut TcpListener) -> Result<TcpStream
284285
}
285286

286287
pub async fn io_loop(
287-
need_restart: Arc<Notify>,
288+
need_restart: BroadcastSender<()>,
288289
tcp_start: Arc<Notify>,
289290
config: SharedConfig,
290291
tx: Arc<Mutex<Option<Sender<Packet>>>>,
291292
sensor_channel: Arc<Mutex<Option<u8>>>,
293+
profile_connected: Arc<AtomicBool>,
292294
) -> Result<()> {
293295
let shared_config = config.clone();
294296
#[allow(unused_variables)]
@@ -331,7 +333,9 @@ pub async fn io_loop(
331333
Err(e) => {
332334
error!("{} 🔴 Enabling Android Auto: {}", NAME, e);
333335
// notify main loop to restart
334-
need_restart.notify_one();
336+
if !profile_connected.load(Ordering::Relaxed) {
337+
let _ = need_restart.send(());
338+
}
335339
continue;
336340
}
337341
Ok(s) => {
@@ -350,7 +354,9 @@ pub async fn io_loop(
350354
md_tcp = Some(s);
351355
} else {
352356
// notify main loop to restart
353-
need_restart.notify_one();
357+
if !profile_connected.load(Ordering::Relaxed) {
358+
let _ = need_restart.send(());
359+
}
354360
continue;
355361
}
356362
}
@@ -364,7 +370,9 @@ pub async fn io_loop(
364370
hu_tcp = Some(s);
365371
} else {
366372
// notify main loop to restart
367-
need_restart.notify_one();
373+
if !profile_connected.load(Ordering::Relaxed) {
374+
let _ = need_restart.send(());
375+
}
368376
continue;
369377
}
370378
} else {
@@ -383,7 +391,9 @@ pub async fn io_loop(
383391
Err(e) => {
384392
error!("{} 🔴 Error opening USB accessory: {}", NAME, e);
385393
// notify main loop to restart
386-
need_restart.notify_one();
394+
if !profile_connected.load(Ordering::Relaxed) {
395+
let _ = need_restart.send(());
396+
}
387397
continue;
388398
}
389399
}
@@ -543,7 +553,7 @@ pub async fn io_loop(
543553
format_duration(started.elapsed()).to_string()
544554
);
545555
// stream(s) closed, notify main loop to restart
546-
need_restart.notify_one();
556+
let _ = need_restart.send(());
547557
}
548558

549559
#[allow(unreachable_code)]

src/main.rs

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ use std::fs;
1919
use std::fs::OpenOptions;
2020
use std::path::PathBuf;
2121
use std::process::Command;
22+
use std::sync::atomic::AtomicBool;
23+
use std::sync::atomic::Ordering;
2224
use std::sync::Arc;
2325
use std::thread;
2426
use std::time::Duration;
2527
use tokio::runtime::Builder;
28+
use tokio::sync::broadcast;
29+
use tokio::sync::broadcast::Sender as BroadcastSender;
2630
use tokio::sync::mpsc::Sender;
2731
use tokio::sync::Mutex;
2832
use tokio::sync::Notify;
@@ -179,12 +183,13 @@ async fn action_handler(config: &mut SharedConfig) {
179183
async fn tokio_main(
180184
config: SharedConfig,
181185
config_json: SharedConfigJson,
182-
need_restart: Arc<Notify>,
186+
restart_tx: BroadcastSender<()>,
183187
tcp_start: Arc<Notify>,
184188
config_file: PathBuf,
185189
tx: Arc<Mutex<Option<Sender<Packet>>>>,
186190
sensor_channel: Arc<Mutex<Option<u8>>>,
187191
led_support: bool,
192+
profile_connected: Arc<AtomicBool>,
188193
) -> Result<()> {
189194
let accessory_started = Arc::new(Notify::new());
190195
let accessory_started_cloned = accessory_started.clone();
@@ -275,6 +280,7 @@ async fn tokio_main(
275280

276281
// main connection loop
277282
let change_usb_order = cfg.change_usb_order;
283+
let mut need_restart = restart_tx.subscribe();
278284
loop {
279285
if let Some(ref mut leds) = led_manager {
280286
leds.set_led(LedColor::Green, LedMode::Heartbeat).await;
@@ -289,21 +295,27 @@ async fn tokio_main(
289295
enable_usb_if_present(&mut usb, accessory_started.clone()).await;
290296
}
291297

292-
// bluetooth handshake
293-
if let Err(e) = bluetooth
294-
.aa_handshake(
295-
cfg.dongle_mode,
296-
cfg.connect.clone(),
297-
wifi_conf.clone().unwrap(),
298-
tcp_start.clone(),
299-
Duration::from_secs(cfg.bt_timeout_secs.into()),
300-
cfg.action_requested == Some(Action::Stop),
301-
)
302-
.await
303-
{
304-
error!("{} bluetooth AA handshake error: {}", NAME, e);
305-
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
306-
continue;
298+
// run only if not handling this in handshake task
299+
if !(cfg.quick_reconnect && profile_connected.load(Ordering::Relaxed)) {
300+
// bluetooth handshake
301+
if let Err(e) = bluetooth
302+
.aa_handshake(
303+
cfg.dongle_mode,
304+
cfg.connect.clone(),
305+
wifi_conf.clone().unwrap(),
306+
tcp_start.clone(),
307+
Duration::from_secs(cfg.bt_timeout_secs.into()),
308+
cfg.action_requested == Some(Action::Stop),
309+
cfg.quick_reconnect,
310+
restart_tx.subscribe(),
311+
profile_connected.clone(),
312+
)
313+
.await
314+
{
315+
error!("{} bluetooth AA handshake error: {}", NAME, e);
316+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
317+
continue;
318+
}
307319
}
308320

309321
if !change_usb_order {
@@ -315,14 +327,21 @@ async fn tokio_main(
315327
leds.set_led(LedColor::Blue, LedMode::On).await;
316328
}
317329
// wait for restart notification
318-
need_restart.notified().await;
330+
let _ = need_restart.recv().await;
331+
if !(cfg.quick_reconnect && profile_connected.load(Ordering::Relaxed)) {
332+
info!(
333+
"{} 📵 TCP/USB connection closed or not started, trying again...",
334+
NAME
335+
);
336+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
337+
} else {
338+
info!(
339+
"{} 📵 TCP/USB connection closed or not started, quick restart...",
340+
NAME
341+
);
342+
}
319343

320344
// TODO: make proper main loop with cancelation
321-
info!(
322-
"{} 📵 TCP/USB connection closed or not started, trying again...",
323-
NAME
324-
);
325-
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
326345
// re-read config
327346
cfg = config.read().await.clone();
328347
}
@@ -525,8 +544,7 @@ fn main() -> Result<()> {
525544
}
526545

527546
// notify for syncing threads
528-
let need_restart = Arc::new(Notify::new());
529-
let need_restart_cloned = need_restart.clone();
547+
let (restart_tx, _) = broadcast::channel(1);
530548
let tcp_start = Arc::new(Notify::new());
531549
let tcp_start_cloned = tcp_start.clone();
532550
let config = Arc::new(RwLock::new(config));
@@ -536,30 +554,35 @@ fn main() -> Result<()> {
536554
let tx_cloned = tx.clone();
537555
let sensor_channel = Arc::new(Mutex::new(None));
538556
let sensor_channel_cloned = sensor_channel.clone();
557+
let profile_connected = Arc::new(AtomicBool::new(false));
539558

540559
// build and spawn main tokio runtime
541560
let runtime = Builder::new_multi_thread().enable_all().build().unwrap();
561+
let restart_tx_cloned = restart_tx.clone();
562+
let profile_connected_cloned = profile_connected.clone();
542563
runtime.spawn(async move {
543564
tokio_main(
544565
config_cloned,
545566
config_json.clone(),
546-
need_restart,
567+
restart_tx_cloned,
547568
tcp_start,
548569
args.config.clone(),
549570
tx_cloned,
550571
sensor_channel_cloned,
551572
led_support,
573+
profile_connected_cloned,
552574
)
553575
.await
554576
});
555577

556578
// start tokio_uring runtime simultaneously
557579
let _ = tokio_uring::start(io_loop(
558-
need_restart_cloned,
580+
restart_tx,
559581
tcp_start_cloned,
560582
config,
561583
tx,
562584
sensor_channel,
585+
profile_connected,
563586
));
564587

565588
info!(

0 commit comments

Comments
 (0)