-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
be ready for hat hardware
- Loading branch information
Showing
21 changed files
with
1,090 additions
and
46 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ members = [ | |
"game", | ||
"data-struct-lib", | ||
"chart-recorder", | ||
"bidrum-hat", | ||
"controller-lib" | ||
] | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -225,6 +225,7 @@ fn main() { | |
args.bpm.into(), | ||
left_face, | ||
right_face, | ||
vec![], | ||
) | ||
.unwrap(); | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
Oops, something went wrong.