Skip to content

Commit

Permalink
merge: hat
Browse files Browse the repository at this point in the history
be ready for hat hardware
  • Loading branch information
LiteHell authored Jun 13, 2024
2 parents 606bd27 + 861c2f5 commit f285b3f
Show file tree
Hide file tree
Showing 21 changed files with 1,090 additions and 46 deletions.
471 changes: 467 additions & 4 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"game",
"data-struct-lib",
"chart-recorder",
"bidrum-hat",
"controller-lib"
]

Expand Down
12 changes: 12 additions & 0 deletions bidrum-hat/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "bidrum-hat"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
btleplug = "0.11.5"
futures = "0.3.30"
tokio = { version = "1.37.0", features = ["rt", "rt-multi-thread"] }
uuid = "1.8.0"
174 changes: 174 additions & 0 deletions bidrum-hat/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::{f32, thread};

use btleplug::api::{Central, CentralEvent, Manager as _, Peripheral, ScanFilter};
use btleplug::platform::Manager;
use futures::stream::StreamExt;
use futures::{executor, FutureExt};
use uuid::Uuid;

pub struct BidrumHat {
spinning: Arc<AtomicBool>,
dropping: Arc<AtomicBool>,
}

async fn get_data(spinning: Arc<AtomicBool>, dropping: Arc<AtomicBool>) {
let service_uuid = Uuid::parse_str("8e191920-dda8-4f40-b2bc-f8f99f680c94").unwrap();
let characteristic_uuid = Uuid::parse_str("2a89fe67-88ff-4bac-8e42-d122d6995ad1").unwrap();

let manager = Manager::new().await.expect("Failed to get manager");
let adapter_list = manager
.adapters()
.await
.expect("Failed to get adapter list");
if adapter_list.is_empty() {
eprintln!("No Bluetooth adapters found");
}

'adapter_loop: for adapter in adapter_list.iter() {
// println!("Starting scan...");
let mut events = adapter
.events()
.await
.expect("Failed to get adapter event stream");

adapter
.start_scan(ScanFilter::default())
.await
.expect("Can't scan BLE adapter for connected devices...");

let mut event_join_handle = events.next();
loop {
let event_option = loop {
if dropping.load(Ordering::Relaxed) {
break 'adapter_loop;
}
if let Some(v) = (&mut event_join_handle).now_or_never() {
break v;
}
};

if let Some(event) = event_option {
match event {
CentralEvent::DeviceDiscovered(id) | CentralEvent::DeviceUpdated(id) => {
let peripheral = {
let peripheral = adapter.peripheral(&id).await;
if let Ok(peripheral) = peripheral {
peripheral
} else {
break;
}
};

let local_name = peripheral.properties().await.unwrap().unwrap().local_name;

if local_name.is_some_and(|x| x.contains("bidrum-hat")) {
if !peripheral.is_connected().await.unwrap_or(false) {
let connect_result = peripheral.connect().await;
if connect_result.is_err() {
break;
}
}

peripheral
.discover_services()
.await
.expect("Failed to discover services");

if let Some(characteristic) =
peripheral.characteristics().iter().find(|x| {
x.uuid == characteristic_uuid && x.service_uuid == service_uuid
})
{
peripheral
.subscribe(characteristic)
.await
.expect("Failed to subscribe characteristic");

let mut notification_stream = peripheral
.notifications()
.await
.expect("Failed to make notification stream");

// Process while the BLE connection is not broken or stopped.
loop {
let notification = notification_stream.next();
let timeouted_notification = tokio::time::timeout(
Duration::from_millis(100),
notification,
)
.await;

if !peripheral.is_connected().await.unwrap_or(false) {
break;
}

if let Ok(unwrapped) = timeouted_notification {
if let Some(data) = &unwrapped {
let norm = std::str::from_utf8(data.value.as_slice())
.unwrap_or("0.0")
.parse::<f32>()
.unwrap();

spinning.store(norm > 1.0, Ordering::Relaxed);
println!("spin norm: {:#}", norm);
}
}
}
}
}
}
_ => {}
}
}
}
}
}

impl BidrumHat {
pub fn new() -> BidrumHat {
let spinning = Arc::new(AtomicBool::new(false));
let spinning_for_thread = spinning.clone();
let dropping = Arc::new(AtomicBool::new(false));
let dropping_for_thread = dropping.clone();

thread::spawn(move || {
let handle = tokio::runtime::Runtime::new().unwrap();
let _guard = handle.enter();
executor::block_on(get_data(spinning_for_thread, dropping_for_thread));
});

let result = BidrumHat {
spinning: spinning,
dropping: dropping,
};

return result;
}
pub fn spinning(&self) -> bool {
self.spinning.load(Ordering::Relaxed)
}
}

impl Drop for BidrumHat {
fn drop(&mut self) {
self.dropping.store(true, Ordering::Relaxed);
}
}

// "-- --nocapture" is needed when running test
#[test]
fn test() {
let hat = BidrumHat::new();

println!("Running test");
loop {
if hat.spinning() {
println!("spinning");
} else {
println!("not spinning");
}
}
}
1 change: 1 addition & 0 deletions chart-recorder/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ fn main() {
args.bpm.into(),
left_face,
right_face,
vec![],
)
.unwrap();

Expand Down
13 changes: 13 additions & 0 deletions controllers/hat/circuit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Required things
- ESP32(or ESP32-*) dev board with BLE Support
- MPU6050 GY-521 module

# Circuit
| GY-521 | ESP32/ESP32-* |
| ------ | ------------- |
| VCC | 3V3 |
| GND | GND |
| SCL | Pin 22 |
| SDA | Pin 21 |

Done!
126 changes: 126 additions & 0 deletions controllers/hat/controller.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Basic demo for accelerometer readings from Adafruit MPU6050

// ESP32 Guide: https://RandomNerdTutorials.com/esp32-mpu-6050-accelerometer-gyroscope-arduino/
// ESP8266 Guide: https://RandomNerdTutorials.com/esp8266-nodemcu-mpu-6050-accelerometer-gyroscope-arduino/
// Arduino Guide: https://RandomNerdTutorials.com/arduino-mpu-6050-accelerometer-gyroscope/

#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>

#define SERVICE_UUID "8e191920-dda8-4f40-b2bc-f8f99f680c94"
#define CHARACTERISTIC_UUID "2a89fe67-88ff-4bac-8e42-d122d6995ad1"
Adafruit_MPU6050 mpu;

bool deviceConnected = false;
bool oldDeviceConnected = false;

class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer *pServer) {
deviceConnected = true;
};

void onDisconnect(BLEServer *pServer) {
deviceConnected = false;
}
};

void initMPU() {
if (!mpu.begin()) {
while (1) {
delay(10);
}
}

mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_5_HZ);
}

BLECharacteristic *pCharacteristic;
BLEServer *pServer;
void initBLE() {
// init BLE
BLEDevice::init("bidrum-hat-1234");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());

BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE|
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_INDICATE
);

pCharacteristic->addDescriptor(new BLE2902());
pService->start();

BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(false);
BLEDevice::startAdvertising();
}

void setup(void) {
initMPU();
initBLE();

delay(100);
}

void loop() {
/* Get new sensor events with the readings */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);


if (deviceConnected) {
float norm = g.gyro.x * g.gyro.x + g.gyro.y * g.gyro.y + g.gyro.z * g.gyro.z;
char normStrBuf[90];
sprintf(normStrBuf, "%f", norm);
char *normStr = (char*)malloc(sizeof(char) * (strlen(normStrBuf) + 1));
strcpy(normStr, normStrBuf);
normStr[strlen(normStrBuf)] = 0;

pCharacteristic->setValue(normStr);
free(normStr);
pCharacteristic->notify();
}

if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
/* Print out the values
Serial.print("Acceleration X: ");
Serial.print(a.acceleration.x);
Serial.print(", Y: ");
Serial.print(a.acceleration.y);
Serial.print(", Z: ");
Serial.print(a.acceleration.z);
Serial.println(" m/s^2");
Serial.print("Rotation X: ");
Serial.print(g.gyro.x);
Serial.print(", Y: ");
Serial.print(g.gyro.y);
Serial.print(", Z: ");
Serial.print(g.gyro.z);
Serial.println(" rad/s");
Serial.print("Temperature: ");
Serial.print(temp.temperature);
Serial.println(" degC");*/
}
File renamed without changes
File renamed without changes.
Loading

0 comments on commit f285b3f

Please sign in to comment.