Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e2691f2
feat: add bluetooth manager/listener
reyvababtista Oct 10, 2024
0000b15
refactor: enable bluetooth
reyvababtista Oct 10, 2024
1c43116
fix: bluetooth permission and store type
reyvababtista Oct 10, 2024
46f3078
fix: remove unused print
reyvababtista Oct 10, 2024
068dce3
refactor: add access modifier
reyvababtista Oct 10, 2024
036c985
refactor: remove unused var, add conditional on bluetooth collection
reyvababtista Oct 10, 2024
053f475
feat: initial commit on omniring manager
reyvababtista Oct 10, 2024
9929d0d
feat: add omniring peripheral logic
reyvababtista Oct 10, 2024
18b56b4
refactor: add omniring
reyvababtista Oct 10, 2024
cba01bd
refactor: add bluetooth init
reyvababtista Oct 10, 2024
d6ab298
refactor: edge cases conditionals
reyvababtista Oct 10, 2024
7618de4
refactor: remove unused print statement
reyvababtista Oct 10, 2024
3898263
fix: data service initialization and study setting update logic
reyvababtista Oct 10, 2024
ec48074
feat: implement omniring store logic
reyvababtista Oct 10, 2024
d0c6e36
fix: deal with edge cases
reyvababtista Oct 11, 2024
18f702c
fix: recline conflict
reyvababtista Nov 14, 2024
c5b6bc5
Merge branch 'survey-uuids' into feature-omniring
reyvababtista Dec 2, 2024
14be772
fix: add files to project
reyvababtista Dec 2, 2024
6fb65af
refactor: add temperature
reyvababtista Dec 2, 2024
03127e3
fix: change omniring data model
reyvababtista Dec 2, 2024
fadc072
refactor: change omniring name
reyvababtista Dec 3, 2024
92a3502
refactor: add info strings
reyvababtista Jan 13, 2025
6fe35dc
chore: header doc
reyvababtista Jan 13, 2025
92cb3ea
refactor: omniring doc
reyvababtista Jan 13, 2025
0be9a83
refactor: CB state management
reyvababtista Jan 13, 2025
5b75eb4
fix: remove early bluetooth initialization
reyvababtista Jan 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Beiwe.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
32E1436324869B38009FAE5A /* TestNotificationRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32E1436224869B38009FAE5A /* TestNotificationRequest.swift */; };
59912EB3230EF09400CAF7EB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 59912EB1230EF09400CAF7EB /* Localizable.strings */; };
59912EB92311A33A00CAF7EB /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 59912EBB2311A33A00CAF7EB /* InfoPlist.strings */; };
7329930D2CFE5BB900166A05 /* BluetoothManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7329930B2CFE5BB900166A05 /* BluetoothManager.swift */; };
7329930E2CFE5BB900166A05 /* OmniringManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7329930C2CFE5BB900166A05 /* OmniringManager.swift */; };
831CC5801F79AF6400CDEFB0 /* AppEventManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 831CC57F1F79AF6400CDEFB0 /* AppEventManager.swift */; };
832FFC1E1CC8506900F2E1EF /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 832FFC1D1CC8506900F2E1EF /* GradientView.swift */; };
832FFC221CC85A7C00F2E1EF /* BWButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 832FFC211CC85A7C00F2E1EF /* BWButton.swift */; };
Expand Down Expand Up @@ -108,6 +110,8 @@
59912EB6230EF3D100CAF7EB /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "Beiwe/zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
59912EBA2311A33A00CAF7EB /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
59912EBD2311A66B00CAF7EB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
7329930B2CFE5BB900166A05 /* BluetoothManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothManager.swift; sourceTree = "<group>"; };
7329930C2CFE5BB900166A05 /* OmniringManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniringManager.swift; sourceTree = "<group>"; };
831CC57F1F79AF6400CDEFB0 /* AppEventManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppEventManager.swift; sourceTree = "<group>"; };
832FFC1D1CC8506900F2E1EF /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = "<group>"; };
832FFC211CC85A7C00F2E1EF /* BWButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BWButton.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -355,6 +359,8 @@
83F6C95E1CA0895000B85914 /* Managers */ = {
isa = PBXGroup;
children = (
7329930B2CFE5BB900166A05 /* BluetoothManager.swift */,
7329930C2CFE5BB900166A05 /* OmniringManager.swift */,
83AF04261CADA02A00A37225 /* AccelerometerManager.swift */,
831CC57F1F79AF6400CDEFB0 /* AppEventManager.swift */,
83AF043E1CB360F300A37225 /* ConsentManager.swift */,
Expand Down Expand Up @@ -740,6 +746,8 @@
832FFC221CC85A7C00F2E1EF /* BWButton.swift in Sources */,
832FFC241CC863F400F2E1EF /* AppColors.swift in Sources */,
83B2BDF31CC1D5AA007FAE91 /* UIColor.swift in Sources */,
7329930D2CFE5BB900166A05 /* BluetoothManager.swift in Sources */,
7329930E2CFE5BB900166A05 /* OmniringManager.swift in Sources */,
83AF042F1CB0D48D00A37225 /* MagnetometerManager.swift in Sources */,
83E3DE8E1CA477D200EB5349 /* ApiManager.swift in Sources */,
83AF04291CAF748C00A37225 /* PowerStateManager.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions Beiwe/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate
NetworkAccessMonitor.start_monitor()

// start some background looping for core app functionality
FirebaseApp.configure()
self.firebaseLoop()
BACKGROUND_DEVICE_INFO_QUEUE.asyncAfter(deadline: .now() + 60, execute: self.deviceInfoUpdateLoop)

Expand Down
2 changes: 2 additions & 0 deletions Beiwe/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ let DEVICE_MOTION_CACHE_SIZE = 100
let GPS_CACHE_SIZE = 100
let GYRO_CACHE_SIZE = 100
let MAGNETOMETER_CACHE_SIZE = 100
let BLUETOOTH_CACHE_SIZE = 100
let OMNIRING_CACHE_SIZE = 100

struct Ephemerals {
// device info statuses
Expand Down
4 changes: 4 additions & 0 deletions Beiwe/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Beiwe needs the list of your surrounding Bluetooth peripheral to properly conduct medical research.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Beiwe needs the list of your surrounding Bluetooth peripheral to properly conduct medical research.</string>
<key>NSCameraUsageDescription</key>
<string>For medical research with ResearchKit</string>
<key>NSHealthShareUsageDescription</key>
Expand Down
117 changes: 117 additions & 0 deletions Beiwe/Managers/BluetoothManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//
// BluetoothManager.swift
// Beiwe
//
// Created by Babtista, Reyva on 10/9/24.
// Copyright © 2024 Reyva Babtista. All rights reserved.
//

import CoreBluetooth

private let bluetooth_headers = [
"timestamp",
"hashed MAC",
"RSSI",
]

private struct BluetoothDataPoint {
var timestamp: TimeInterval
var hashedMAC: String
var RSSI: String
}

class BluetoothManager: NSObject, CBCentralManagerDelegate, DataServiceProtocol {
private var bluetoothManager: CBCentralManager?
private let storeType = "bluetoothLog"
private var dataStorage: DataStorage?
private var datapoints = [BluetoothDataPoint]()
// See (01/13/24): https://developer.apple.com/documentation/corebluetooth/cbmanagerstate
private var currentCBState: CBManagerState?
private let cacheLock = NSLock()
private var collecting = false

func centralManagerDidUpdateState(_ central: CBCentralManager) {
self.currentCBState = central.state

switch self.currentCBState {
case .poweredOn:
self.startCollecting()
default:
self.finishCollecting()
}
}

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
guard self.collecting else {
return
}

let data = BluetoothDataPoint(
timestamp: Date().timeIntervalSince1970 * 1000,
hashedMAC: peripheral.identifier.uuidString,
RSSI: RSSI.stringValue
)
self.cacheLock.lock()
self.datapoints.append(data)
self.cacheLock.unlock()

if self.datapoints.count > BLUETOOTH_CACHE_SIZE {
self.flush()
}
}

func initCollecting() -> Bool {
print("init bluetooth")
self.dataStorage = DataStorageManager.sharedInstance.createStore(self.storeType, headers: bluetooth_headers)
return true
}

func startCollecting() {
print("start bluetooth")
switch self.bluetoothManager?.state {
case .poweredOff:
self.bluetoothManager = CBCentralManager.init(delegate: self, queue: nil)
return
case .poweredOn:
self.bluetoothManager?.scanForPeripherals(withServices: nil, options: ["CBCentralManagerScanOptionAllowDuplicatesKey": false])
self.collecting = true
AppEventManager.sharedInstance.logAppEvent(event: "bt_on", msg: "Bluetooth scanning on")
default:
return
}
}

func pauseCollecting() {
print("pause bluetooth")
self.bluetoothManager?.stopScan()
self.collecting = false
AppEventManager.sharedInstance.logAppEvent(event: "bt_off", msg: "Bluetooth scanning off")
}

func finishCollecting() {
print("finish bluetooth")
self.pauseCollecting()
self.createNewFile()
}

func createNewFile() {
self.flush()
self.dataStorage?.reset()
}

func flush() {
self.cacheLock.lock()
let data_to_write = self.datapoints
self.datapoints = []
self.cacheLock.unlock()
for data in data_to_write {
self.dataStorage?.store([
String(Int64(data.timestamp)),
data.hashedMAC,
data.RSSI
])
}
}


}
Loading