commit cdf7209c218e275763367d00fd55b25b3b1d56c9
parent 8e74d2221936e1ff03621fcd3276f24d4cd918a8
Author: Daniel Barlow <dan@telent.net>
Date: Sun, 11 Jan 2026 20:20:00 +0000
rename project
Diffstat:
5 files changed, 11 insertions(+), 230 deletions(-)
diff --git a/README.md b/README.md
@@ -1,4 +1,4 @@
-# ECU-logical
+# Eculocate
Read data from the K-line of a Honda motorbike ECU and publish it
-using Bluetooth LE
+using UDP over Wifi
diff --git a/android-termux-client/shore.py b/android-termux-client/shore.py
@@ -17,9 +17,9 @@ bytes_recorded = 0
started = False
hosts = {
- "eculogical.local" : None,
- "eculogical2.local" : None,
- "eculogical3.local" : None
+ "eculocate.local" : None,
+ "eculocate2.local" : None,
+ "eculocate3.local" : None
}
def output_pathname():
@@ -111,9 +111,9 @@ with tg.Connection() as c:
instances = tg.LinearLayout(a)
- add_host(a, "eculogical.local", instances)
- add_host(a, "eculogical2.local", instances)
- add_host(a, "eculogical3.local", instances)
+ add_host(a, "eculocate.local", instances)
+ add_host(a, "eculocate2.local", instances)
+ add_host(a, "eculocate3.local", instances)
tg.Space(a, instances)
diff --git a/ecu-esp32/src/wibble.rs b/ecu-esp32/src/wibble.rs
@@ -1,219 +0,0 @@
-use embassy_time::Timer;
-use trouble_host::prelude::*;
-use esp_radio::ble::controller::BleConnector;
-use log::{warn,info};
-use embassy_futures::join::join;
-use embassy_futures::select::select;
-
-
-/// Max number of connections
-const CONNECTIONS_MAX: usize = 1;
-
-/// Max number of L2CAP channels.
-const L2CAP_CHANNELS_MAX: usize = 2; // Signal + att
-
-// GATT Server definition
-#[gatt_server]
-struct Server {
- battery_service: BatteryService,
- engine_speed_service: EngineSpeedService,
-}
-
-/// Battery service
-#[gatt_service(uuid = service::BATTERY)]
-struct BatteryService {
- /// Battery Level
- #[descriptor(uuid = descriptors::VALID_RANGE, read, value = [0, 100])]
- #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "hello", read, value = "Battery Level")]
- #[characteristic(uuid = characteristic::BATTERY_LEVEL, read, notify, value = 10)]
- level: u8,
- #[characteristic(uuid = "408813df-5dd4-1f87-ec11-cdb001100000", write, read, notify)]
- status: bool,
-}
-
-#[gatt_service(uuid = "e000adbf-3508-435b-9638-eaff1d5e7c7e")]
-struct EngineSpeedService {
- /// Battery Level
- // #[descriptor(uuid = descriptors::VALID_RANGE, read, value = [0, 100])]
- // #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "hello", read, value = "Battery Level")]
- #[characteristic(uuid = characteristic::ROTATIONAL_SPEED, read, notify, value = 1200)]
- rpm: i32,
-}
-
-
-pub async fn run_ble(peripheral : esp_hal::peripherals::BT<'_>) {
- 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);
-
- // Using a fixed "random" address can be useful for testing. In real scenarios, one would
- // use e.g. the MAC 6 byte array as the address (how to get that varies by the platform).
- let address: Address = Address::random([0xff, 0x8f, 0x1a, 0x05, 0xe4, 0xff]);
- info!("Our address = {:?}", address);
-
- let mut resources: HostResources<DefaultPacketPool, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX> = HostResources::new();
- let stack = trouble_host::new(controller, &mut resources).set_random_address(address);
- let Host {
- mut peripheral, runner, ..
- } = stack.build();
-
- info!("Starting advertising and GATT service");
- let server = Server::new_with_config(GapConfig::Peripheral(PeripheralConfig {
- name: "ECUlogical",
- appearance: &appearance::power_device::GENERIC_POWER_DEVICE,
- }))
- .unwrap();
-
- let _ = join(
- ble_task(runner),
- async {
- loop {
- match advertise("Trouble Example", &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 b = custom_task(&server, &conn, &stack);
- // run until any task ends (usually because the connection has been closed),
- // then return to advertising state.
- select(a, b).await;
- }
- Err(e) => {
- panic!("[adv] error: {:?}", e);
- }
- }
- }
- })
- .await;
-}
-
-/// This is a background task that is required to run forever alongside any other BLE tasks.
-///
-/// ## Alternative
-///
-/// If you didn't require this to be generic for your application, you could statically spawn this with i.e.
-///
-/// ```rust,ignore
-///
-/// #[embassy_executor::task]
-/// async fn ble_task(mut runner: Runner<'static, SoftdeviceController<'static>>) {
-/// runner.run().await;
-/// }
-///
-/// spawner.must_spawn(ble_task(runner));
-/// ```
-async fn ble_task<C: Controller, P: PacketPool>(mut runner: Runner<'_, C, P>) {
- loop {
- if let Err(e) = runner.run().await {
- panic!("[ble_task] error: {:?}", e);
- }
- }
-}
-
-/// Stream Events until the connection closes.
-///
-/// 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 level = server.battery_service.level;
- let reason = loop {
- match conn.next().await {
- GattConnectionEvent::Disconnected { reason } => break reason,
- GattConnectionEvent::Gatt { event } => {
- match &event {
- // are these clauses important? they don't do anything
- // except log
- GattEvent::Read(event) => {
- if event.handle() == level.handle {
- let value = server.get(&level);
- info!("[gatt] Read Event to Level Characteristic: {:?}", value);
- }
- }
- GattEvent::Write(event) => {
- if event.handle() == level.handle {
- info!("[gatt] Write Event to Level Characteristic: {:?}", event.data());
- }
- }
- _ => {}
- };
- // This step is also performed at drop(), but writing it explicitly is necessary
- // in order to ensure reply is sent.
- match event.accept() {
- Ok(reply) => reply.send().await,
- Err(e) => warn!("[gatt] error sending response: {:?}", e),
- };
- }
- _ => {} // ignore other Gatt Connection Events
- }
- };
- info!("[gatt] disconnected: {:?}", reason);
- Ok(())
-}
-
-/// Create an advertiser to use to connect to a BLE Central, and wait for it to connect.
-async fn advertise<'values, 'server, C: Controller>(
- name: &'values str,
- peripheral: &mut Peripheral<'values, C, DefaultPacketPool>,
- server: &'server Server<'values>,
-) -> Result<GattConnection<'values, 'server, DefaultPacketPool>, BleHostError<C::Error>> {
- let mut advertiser_data = [0; 31];
- let len = AdStructure::encode_slice(
- &[
- AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED),
- AdStructure::ServiceUuids16(&[[0x0f, 0x18]]),
- AdStructure::CompleteLocalName(name.as_bytes()),
- ],
- &mut advertiser_data[..],
- )?;
- let advertiser = peripheral
- .advertise(
- &Default::default(),
- Advertisement::ConnectableScannableUndirected {
- adv_data: &advertiser_data[..len],
- scan_data: &[],
- },
- )
- .await?;
- info!("[adv] advertising");
- let conn = advertiser.accept().await?.with_attribute_server(server)?;
- info!("[adv] connection established");
- Ok(conn)
-}
-
-/// Example task to use the BLE notifier interface.
-/// This task will notify the connected central of a counter value every 2 seconds.
-/// It will also read the RSSI value every 2 seconds.
-/// and will stop when the connection is closed by the central or an error occurs.
-async fn custom_task<C: Controller, P: PacketPool>(
- server: &Server<'_>,
- conn: &GattConnection<'_, '_, P>,
- stack: &Stack<'_, C, P>,
-) {
- let mut tick: u8 = 0;
- let level = server.battery_service.level;
- let rpm = server.engine_speed_service.rpm;
- loop {
- tick = tick.wrapping_add(1);
- info!("[custom_task] notifying connection of tick {}", tick);
-
- // if the characteristic does not support notifications,
- // this would return an error. Use `set` instead, in that case.
- // See inline comments in trouble-host/src/attribute.rs around
- // line 631
-
- if level.notify(conn, &tick).await.is_err() {
- info!("[custom_task] error notifying connection");
- break;
- };
- // read RSSI (Received Signal Strength Indicator) of the connection.
- if let Ok(rssi) = conn.raw().rssi(stack).await {
- info!("[custom_task] RSSI: {:?}", rssi);
- } else {
- info!("[custom_task] error getting RSSI");
- break;
- };
- let new_rpm = 1200 + 20 * i32::from(tick);
- rpm.notify(conn, &new_rpm).await.expect("failed to notify");
-
- Timer::after_secs(2).await;
- }
-}
diff --git a/ecu-esp32/src/wifi.rs b/ecu-esp32/src/wifi.rs
@@ -59,11 +59,11 @@ fn dns_records(my_ip_address: [u8;4], serial: Option<usize>) -> Vec<mdns::Resour
let (hostname, ptr_name) =
match serial {
None => (
- String::from("eculogical.local"),
+ String::from("eculocate.local"),
String::from("Bike._keihin._udp.local")
),
Some(number) => (
- format!("eculogical{number}.local"),
+ format!("eculocate{number}.local"),
format!("Bike ({number})._keihin._udp.local")
)
};
diff --git a/streamclient.rb b/streamclient.rb
@@ -6,7 +6,7 @@ def subscribe(interval, table, start, finish)
[interval, "T", table, start, finish].pack("s>ACCC")
end
-sock.connect("eculogical.local", 5000)
+sock.connect("eculocate.local", 5000)
sock.send(subscribe(500, 0x11, 0, 25), 0)
finish = Time.now + 60