Quaternion: adjust quaternion to take into account the sensor position

Refactor period interval for sensors
This commit is contained in:
Antonio 2020-03-13 19:06:46 +01:00
parent 44e4654301
commit 49b2508da4
22 changed files with 211 additions and 204 deletions

View file

@ -16,8 +16,6 @@ extension BlePeripheral {
private static let kAdafruitAccelerometerCharacteristicUUID = CBUUID(string: "ADAF0201-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitAccelerometerVersion = 1
static let kAdafruitAccelerometerDefaultPeriod: TimeInterval = 0.1
// Structs
/// Acceleration in m/s²
struct AccelerometerValue {
@ -43,7 +41,7 @@ extension BlePeripheral {
// MARK: - Actions
func adafruitAccelerometerEnable(responseHandler: @escaping(Result<(AccelerometerValue, UUID), Error>) -> Void, completion: ((Result<Void, Error>) -> Void)?) {
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitAccelerometerVersion, serviceUuid: BlePeripheral.kAdafruitAccelerometerServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitAccelerometerCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitAccelerometerDefaultPeriod, responseHandler: { response in
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitAccelerometerVersion, serviceUuid: BlePeripheral.kAdafruitAccelerometerServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitAccelerometerCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSensorDefaultPeriod, responseHandler: { response in
switch response {
case let .success((data, uuid)):

View file

@ -15,8 +15,6 @@ extension BlePeripheral {
private static let kAdafruitBarometricPressureCharacteristicUUID = CBUUID(string: "ADAF0801-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitBarometricPressureVersion = 1
static let kAdafruitBarometricPressureDefaultPeriod: TimeInterval = 0.1
// MARK: - Custom properties
private struct CustomPropertiesKeys {
static var adafruitBarometricPressureCharacteristic: CBCharacteristic?
@ -34,7 +32,7 @@ extension BlePeripheral {
// MARK: - Actions
func adafruitBarometricPressureEnable(responseHandler: @escaping(Result<(Float, UUID), Error>) -> Void, completion: ((Result<Void, Error>) -> Void)?) {
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitBarometricPressureVersion, serviceUuid: BlePeripheral.kAdafruitBarometricPressureServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitBarometricPressureCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitBarometricPressureDefaultPeriod, responseHandler: { response in
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitBarometricPressureVersion, serviceUuid: BlePeripheral.kAdafruitBarometricPressureServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitBarometricPressureCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSensorDefaultPeriod, responseHandler: { response in
switch response {
case let .success((data, uuid)):

View file

@ -15,9 +15,7 @@ extension BlePeripheral {
private static let kAdafruitColorSensorCharacteristicUUID = CBUUID(string: "ADAF0A01-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitColorSensorVersion = 1
private static let kAdafruitColorSensorDefaultPeriod: TimeInterval = 0.1
// MARK: - Custom properties
// MARK: - Custom properties
private struct CustomPropertiesKeys {
static var adafruitColorSensorCharacteristic: CBCharacteristic?
}
@ -34,7 +32,7 @@ extension BlePeripheral {
// MARK: - Actions
func adafruitColorSensorEnable(responseHandler: @escaping(Result<(UIColor, UUID), Error>) -> Void, completion: ((Result<Void, Error>) -> Void)?) {
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitColorSensorVersion, serviceUuid: BlePeripheral.kAdafruitColorSensorServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitColorSensorCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitColorSensorDefaultPeriod, responseHandler: { response in
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitColorSensorVersion, serviceUuid: BlePeripheral.kAdafruitColorSensorServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitColorSensorCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSensorDefaultPeriod, responseHandler: { response in
switch response {
case let .success((data, uuid)):

View file

@ -16,6 +16,9 @@ extension BlePeripheral {
private static let kAdafruitDefaultVersionValue = 1 // Used as default version value if version characteristic cannot be read
static let kAdafruitSensorDefaultPeriod: TimeInterval = 0.2
// MARK: - Errors
enum PeripheralAdafruitError: Error {
case invalidCharacteristic

View file

@ -16,8 +16,6 @@ extension BlePeripheral {
private static let kAdafruitGyroscopeCharacteristicUUID = CBUUID(string: "ADAF0401-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitGyroscopeVersion = 1
static let kAdafruitGyroscopeDefaultPeriod: TimeInterval = 0.1
// Structs
/// Values in rad/s
struct GyroscopeValue {
@ -43,7 +41,7 @@ extension BlePeripheral {
// MARK: - Actions
func adafruitGyroscopeEnable(responseHandler: @escaping(Result<(GyroscopeValue, UUID), Error>) -> Void, completion: ((Result<Void, Error>) -> Void)?) {
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitGyroscopeVersion, serviceUuid: BlePeripheral.kAdafruitGyroscopeServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitGyroscopeCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitGyroscopeDefaultPeriod, responseHandler: { response in
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitGyroscopeVersion, serviceUuid: BlePeripheral.kAdafruitGyroscopeServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitGyroscopeCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSensorDefaultPeriod, responseHandler: { response in
switch response {
case let .success((data, uuid)):

View file

@ -15,8 +15,6 @@ extension BlePeripheral {
private static let kAdafruitHumidityCharacteristicUUID = CBUUID(string: "ADAF0701-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitHumidityVersion = 1
static let kAdafruitHumidityDefaultPeriod: TimeInterval = 0.1
// MARK: - Custom properties
private struct CustomPropertiesKeys {
static var adafruitHumidityCharacteristic: CBCharacteristic?
@ -34,7 +32,7 @@ extension BlePeripheral {
// MARK: - Actions
func adafruitHumidityEnable(responseHandler: @escaping(Result<(Float, UUID), Error>) -> Void, completion: ((Result<Void, Error>) -> Void)?) {
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitHumidityVersion, serviceUuid: BlePeripheral.kAdafruitHumidityServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitHumidityCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitHumidityDefaultPeriod, responseHandler: { response in
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitHumidityVersion, serviceUuid: BlePeripheral.kAdafruitHumidityServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitHumidityCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSensorDefaultPeriod, responseHandler: { response in
switch response {
case let .success((data, uuid)):

View file

@ -15,7 +15,6 @@ extension BlePeripheral {
private static let kAdafruitLightCharacteristicUUID = CBUUID(string: "ADAF0301-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitLightVersion = 1
static let kAdafruitLightDefaultPeriod: TimeInterval = 0.1
// MARK: - Custom properties
private struct CustomPropertiesKeys {
@ -34,7 +33,7 @@ extension BlePeripheral {
// MARK: - Actions
func adafruitLightEnable(responseHandler: @escaping(Result<(Float, UUID), Error>) -> Void, completion: ((Result<Void, Error>) -> Void)?) {
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitLightVersion, serviceUuid: BlePeripheral.kAdafruitLightServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitLightCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitLightDefaultPeriod, responseHandler: { response in
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitLightVersion, serviceUuid: BlePeripheral.kAdafruitLightServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitLightCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSensorDefaultPeriod, responseHandler: { response in
switch response {
case let .success((data, uuid)):

View file

@ -16,8 +16,6 @@ extension BlePeripheral {
private static let kAdafruitMagnetometerCharacteristicUUID = CBUUID(string: "ADAF0501-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitMagnetometerVersion = 1
static let kAdafruitMagnetometerDefaultPeriod: TimeInterval = 0.1
// Structs
/// Values in microTesla (μT)
struct MagnetometerValue {
@ -43,7 +41,7 @@ extension BlePeripheral {
// MARK: - Actions
func adafruitMagnetometerEnable(responseHandler: @escaping(Result<(MagnetometerValue, UUID), Error>) -> Void, completion: ((Result<Void, Error>) -> Void)?) {
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitMagnetometerVersion, serviceUuid: BlePeripheral.kAdafruitMagnetometerServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitMagnetometerCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitMagnetometerDefaultPeriod, responseHandler: { response in
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitMagnetometerVersion, serviceUuid: BlePeripheral.kAdafruitMagnetometerServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitMagnetometerCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSensorDefaultPeriod, responseHandler: { response in
switch response {
case let .success((data, uuid)):

View file

@ -18,14 +18,12 @@ extension BlePeripheral {
private static let kAdafruitQuaternionCalibrationOutCharacteristicUUID = CBUUID(string: "ADAFD003-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitQuaternionVersion = 1
static let kAdafruitQuaternionDefaultPeriod: TimeInterval = 0.1
// Structs
struct QuaternionValue {
var qx: Float
var qy: Float
var qz: Float
var qw: Float
var x: Float
var y: Float
var z: Float
var w: Float
}
// MARK: - Custom properties
@ -45,7 +43,7 @@ extension BlePeripheral {
// MARK: - Actions
func adafruitQuaternionEnable(responseHandler: @escaping(Result<(QuaternionValue, UUID), Error>) -> Void, completion: ((Result<Void, Error>) -> Void)?) {
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitQuaternionVersion, serviceUuid: BlePeripheral.kAdafruitQuaternionServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitQuaternionCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitQuaternionDefaultPeriod, responseHandler: { response in
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitQuaternionVersion, serviceUuid: BlePeripheral.kAdafruitQuaternionServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitQuaternionCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSensorDefaultPeriod, responseHandler: { response in
switch response {
case let .success((data, uuid)):
@ -97,6 +95,6 @@ extension BlePeripheral {
guard let bytes = adafruitDataToFloatArray(data) else { return nil }
guard bytes.count >= 4 else { return nil }
// return QuaternionValue(qx: bytes[0], qy: bytes[1], qz: bytes[2], qw: bytes[3])
return QuaternionValue(qx: bytes[1], qy: bytes[2], qz: bytes[3], qw: bytes[0])
return QuaternionValue(x: bytes[1], y: bytes[2], z: bytes[3], w: bytes[0])
}
}

View file

@ -16,7 +16,6 @@ extension BlePeripheral {
private static let kAdafruitSoundNumberOfChannelsCharacteristicUUID = CBUUID(string: "ADAF0B02-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitSoundSensorVersion = 1
static let kAdafruitSoundSensorDefaultPeriod: TimeInterval = 0.1
static let kAdafruitSoundSensorMaxAmplitude = 32767
// MARK: - Custom properties
@ -46,7 +45,7 @@ extension BlePeripheral {
// MARK: - Actions
func adafruitSoundEnable(responseHandler: @escaping(Result<([Double], UUID), Error>) -> Void, completion: ((Result<Int, Error>) -> Void)?) {
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitSoundSensorVersion, serviceUuid: BlePeripheral.kAdafruitSoundSensorServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitSoundSamplesCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSoundSensorDefaultPeriod, responseHandler: { [weak self] response in
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitSoundSensorVersion, serviceUuid: BlePeripheral.kAdafruitSoundSensorServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitSoundSamplesCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSensorDefaultPeriod, responseHandler: { [weak self] response in
guard self?.adafruitSoundNumChannels ?? 0 > 0 else { return } // Ignore received data until sound channels are defined
// TODO: read sound channels BEFORE enabling notify

View file

@ -15,8 +15,6 @@ extension BlePeripheral {
private static let kAdafruitTemperatureCharacteristicUUID = CBUUID(string: "ADAF0101-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitTemperatureVersion = 1
private static let kAdafruitTemperatureDefaultPeriod: TimeInterval = 0.1
// MARK: - Custom properties
private struct CustomPropertiesKeys {
static var adafruitTemperatureCharacteristic: CBCharacteristic?
@ -34,7 +32,7 @@ extension BlePeripheral {
// MARK: - Actions
func adafruitTemperatureEnable(responseHandler: @escaping(Result<(Float, UUID), Error>) -> Void, completion: ((Result<Void, Error>) -> Void)?) {
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitTemperatureVersion, serviceUuid: BlePeripheral.kAdafruitTemperatureServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitTemperatureCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitTemperatureDefaultPeriod, responseHandler: { response in
self.adafruitServiceEnableIfVersion(version: BlePeripheral.kAdafruitTemperatureVersion, serviceUuid: BlePeripheral.kAdafruitTemperatureServiceUUID, mainCharacteristicUuid: BlePeripheral.kAdafruitTemperatureCharacteristicUUID, timePeriod: BlePeripheral.kAdafruitSensorDefaultPeriod, responseHandler: { response in
switch response {
case let .success((data, uuid)):

View file

@ -15,7 +15,6 @@ extension BlePeripheral {
private static let kAdafruitToneGeneratorCharacteristicUUID = CBUUID(string: "ADAF0C01-C332-42A8-93BD-25E905756CB8")
private static let kAdafruitToneGeneratorVersion = 1
// MARK: - Custom properties
private struct CustomPropertiesKeys {
static var adafruitToneGeneratorCharacteristic: CBCharacteristic?

View file

@ -86,6 +86,22 @@ class AdafruitBoard {
case sound
case gyroscope
case quaternion
var debugName: String {
switch self {
case .neopixels: return "Neopixels"
case .light: return "Light"
case .buttons: return "Buttons"
case .toneGenerator: return "ToneGenerator"
case .accelerometer: return "Accelerometer"
case .temperature: return "Temperature"
case .humidity: return "Humidity"
case .barometricPressure: return "Barometric Pressure"
case .sound: return "Sound"
case .gyroscope: return "Gyroscope"
case .quaternion: return "Quaternion"
}
}
}
// Notifications
@ -94,7 +110,7 @@ class AdafruitBoard {
case value = "value"
}
// Params
// Params - Delegates
weak var temperatureDelegate: AdafruitTemperatureDelegate?
weak var lightDelegate: AdafruitLightDelegate?
weak var buttonsDelegate: AdafruitButtonsDelegate?
@ -105,9 +121,21 @@ class AdafruitBoard {
weak var gyroscopeDelegate: AdafruitGyroscopeDelegate?
weak var quaternionDelegate: AdafruitQuaternionDelegate?
// Params - Data Series
var isLightDataSeriesEnabled = true
var isAccelerometerDataSeriesEnabled = false
var isTemperatureDataSeriesEnabled = true
var isHumidityDataSeriesEnabled = true
var isBarometricPressureDataSeriesEnabled = true
var isSoundAmplitudePressureDataSeriesEnabled = true
var isGyroscopeDataSeriesEnabled = false
var isQuaternioDataSeriesEnabled = false
// Params - Specific behaviour
var accelerometerAutoAdjustOrientation = true // If true, the orientation will be modified to show the board correctly taking into account where the sensor is located in the board
var quaternionAutoAdjustOrientation = true // If true, the orientation will be modified to show the board correctly taking into account where the sensor is located in the board
// Data
private(set) weak var blePeripheral: BlePeripheral?
var model: BlePeripheral.AdafruitManufacturerData.BoardModel? {
@ -116,7 +144,7 @@ class AdafruitBoard {
// Data - DataSeries
private(set) var lightDataSeries = SensorDataSeries<Float>()
//private(set) var accelerometerDataSeries = SensorDataSeries<BlePeripheral.AccelerometerValue>()
private(set) var accelerometerDataSeries = SensorDataSeries<BlePeripheral.AccelerometerValue>()
private(set) var temperatureDataSeries = SensorDataSeries<Float>()
private(set) var humidityDataSeries = SensorDataSeries<Float>()
private(set) var barometricPressureDataSeries = SensorDataSeries<Float>()
@ -180,27 +208,15 @@ class AdafruitBoard {
if services.contains(.neopixels), let numPixels = blePeripheral.adafruitManufacturerData()?.boardModel?.neoPixelsNumPixels, numPixels > 0 {
servicesGroup.enter()
blePeripheral.adafruitNeoPixelsEnable(numPixels: numPixels) { result in
if case .success = result {
DLog("NeoPixels enabled")
} else {
DLog("Warning: NeoPixels enable failed")
}
blePeripheral.adafruitNeoPixelsEnable(numPixels: numPixels) { _ in
servicesGroup.leave()
}
}
// Light Service: Enable receiving data
if services.contains(.light) {
servicesGroup.enter()
blePeripheral.adafruitLightEnable(responseHandler: self.receiveLightData) { result in
if case .success = result {
DLog("Light reading enabled")
} else {
DLog("Warning: Light reading enable failed")
}
blePeripheral.adafruitLightEnable(responseHandler: self.receiveLightData) { _ in
servicesGroup.leave()
}
}
@ -208,13 +224,7 @@ class AdafruitBoard {
// Buttons Service: Enable receiving data
if services.contains(.buttons) {
servicesGroup.enter()
blePeripheral.adafruitButtonsEnable(responseHandler: self.receiveButtonsData) { result in
if case .success = result {
DLog("Buttons reading enabled")
} else {
DLog("Warning: Buttons reading enable failed")
}
blePeripheral.adafruitButtonsEnable(responseHandler: self.receiveButtonsData) { _ in
servicesGroup.leave()
}
}
@ -222,13 +232,7 @@ class AdafruitBoard {
// ToneGenerator Service: Enable
if services.contains(.toneGenerator) {
servicesGroup.enter()
blePeripheral.adafruitToneGeneratorEnable { result in
if case .success = result {
DLog("ToneGenerator enabled")
} else {
DLog("Warning: ToneGenerator enable failed")
}
blePeripheral.adafruitToneGeneratorEnable { _ in
servicesGroup.leave()
}
}
@ -236,13 +240,7 @@ class AdafruitBoard {
// Accelerometer Service: Enable receiving data
if services.contains(.accelerometer) {
servicesGroup.enter()
blePeripheral.adafruitAccelerometerEnable(responseHandler: self.receiveAccelerometerData, completion: { result in
if case .success = result {
DLog("Accelerometer enabled")
} else {
DLog("Warning: Accelerometer enable failed")
}
blePeripheral.adafruitAccelerometerEnable(responseHandler: self.receiveAccelerometerData, completion: { _ in
servicesGroup.leave()
})
}
@ -250,13 +248,7 @@ class AdafruitBoard {
// Temperature Service: Enable receiving data
if services.contains(.temperature) {
servicesGroup.enter()
blePeripheral.adafruitTemperatureEnable(responseHandler: self.receiveTemperatureData) { result in
if case .success = result {
DLog("Temperature reading enabled")
} else {
DLog("Warning: Temperature reading enable failed")
}
blePeripheral.adafruitTemperatureEnable(responseHandler: self.receiveTemperatureData) { _ in
servicesGroup.leave()
}
}
@ -264,13 +256,7 @@ class AdafruitBoard {
// Humidity Service: Enable receiving data
if services.contains(.humidity) {
servicesGroup.enter()
blePeripheral.adafruitHumidityEnable(responseHandler: self.receiveHumidityData) { result in
if case .success = result {
DLog("Humidity reading enabled")
} else {
DLog("Warning: Humidity reading enable failed")
}
blePeripheral.adafruitHumidityEnable(responseHandler: self.receiveHumidityData) { _ in
servicesGroup.leave()
}
}
@ -278,13 +264,7 @@ class AdafruitBoard {
// Barometric Pressure Service: Enable receiving data
if services.contains(.barometricPressure) {
servicesGroup.enter()
blePeripheral.adafruitBarometricPressureEnable(responseHandler: self.receiveBarometricPressureData) { result in
if case .success = result {
DLog("Barometric Pressure reading enabled")
} else {
DLog("Warning: Barometric Pressure reading enable failed")
}
blePeripheral.adafruitBarometricPressureEnable(responseHandler: self.receiveBarometricPressureData) { _ in
servicesGroup.leave()
}
}
@ -292,29 +272,15 @@ class AdafruitBoard {
// Sound Service: Enable receiving data
if services.contains(.sound) {
servicesGroup.enter()
blePeripheral.adafruitSoundEnable(responseHandler: self.receiveSoundData) { result in
if case .success = result {
DLog("Sound reading enabled")
} else {
DLog("Warning: Sound reading enable failed")
}
blePeripheral.adafruitSoundEnable(responseHandler: self.receiveSoundData) { _ in
servicesGroup.leave()
}
}
// Gyroscope Service: Enable receiving data
if services.contains(.gyroscope) {
servicesGroup.enter()
blePeripheral.adafruitGyroscopeEnable(responseHandler: self.receiveGyroscopeData) { result in
if case .success = result {
DLog("Gyroscope reading enabled")
} else {
DLog("Warning: Gyroscope reading enable failed")
}
blePeripheral.adafruitGyroscopeEnable(responseHandler: self.receiveGyroscopeData) { _ in
servicesGroup.leave()
}
}
@ -322,68 +288,86 @@ class AdafruitBoard {
// Quaternion Service: Enable receiving data
if services.contains(.quaternion) {
servicesGroup.enter()
blePeripheral.adafruitQuaternionEnable(responseHandler: self.receiveQuaternionData) { result in
if case .success = result {
DLog("Quaternion reading enabled")
} else {
DLog("Warning: Quaternion reading enable failed")
}
blePeripheral.adafruitQuaternionEnable(responseHandler: self.receiveQuaternionData) { _ in
servicesGroup.leave()
}
}
// Wait for all finished
servicesGroup.notify(queue: DispatchQueue.main) {
servicesGroup.notify(queue: DispatchQueue.main) { [unowned self] in
DLog("setupServices finished")
if Config.isDebugEnabled {
for service in services {
DLog(self.isEnabled(service: service) ? "\(service.debugName) reading enabled":"\(service.debugName) service not available")
}
}
completion(.success(()))
}
}
// MARK: - Sensor availability
var isNeopixelsAvailable: Bool {
var isNeopixelsEnabled: Bool {
return blePeripheral?.adafruitNeoPixelsIsEnabled() ?? false
}
var isLightAvailable: Bool {
var isLightEnabled: Bool {
return blePeripheral?.adafruitLightIsEnabled() ?? false
}
var isButtonsAvailable: Bool {
var isButtonsEnabled: Bool {
return blePeripheral?.adafruitButtonsIsEnabled() ?? false
}
var isToneGeneratorAvailable: Bool {
var isToneGeneratorEnabled: Bool {
return blePeripheral?.adafruitToneGeneratorIsEnabled() ?? false
}
var isAccelerometerAvailable: Bool {
var isAccelerometerEnabled: Bool {
return blePeripheral?.adafruitAccelerometerIsEnabled() ?? false
}
var isTemperatureAvailable: Bool {
var isTemperatureEnabled: Bool {
return blePeripheral?.adafruitTemperatureIsEnabled() ?? false
}
var isHumidityAvailable: Bool {
var isHumidityEnabled: Bool {
return blePeripheral?.adafruitHumidityIsEnabled() ?? false
}
var isBarometricPressureAvailable: Bool {
var isBarometricPressureEnabled: Bool {
return blePeripheral?.adafruitBarometricPressureIsEnabled() ?? false
}
var isSoundAvailable: Bool {
var isSoundEnabled: Bool {
return blePeripheral?.adafruitSoundIsEnabled() ?? false
}
var isGyroscopeAvailable: Bool {
var isGyroscopeEnabled: Bool {
return blePeripheral?.adafruitGyroscopeIsEnabled() ?? false
}
var isQuaternionAvailable: Bool {
var isQuaternionEnabled: Bool {
return blePeripheral?.adafruitQuaternionIsEnabled() ?? false
}
func isEnabled(service: BoardService) -> Bool {
switch service {
case .neopixels: return isNeopixelsEnabled
case .light: return isLightEnabled
case .buttons: return isButtonsEnabled
case .toneGenerator: return isToneGeneratorEnabled
case .accelerometer: return isAccelerometerEnabled
case .temperature: return isTemperatureEnabled
case .humidity: return isHumidityEnabled
case .barometricPressure: return isBarometricPressureEnabled
case .sound: return isSoundEnabled
case .gyroscope: return isGyroscopeEnabled
case .quaternion: return isQuaternionEnabled
}
}
// MARK: - Read Data
func lightLastValue() -> Float? {
@ -439,10 +423,13 @@ class AdafruitBoard {
private func receiveLightData(response: Result<(Float, UUID), Error>) {
switch response {
case let .success(light, uuid):
// Save value
let entry = SensorDataSeries.Entry(value: light, timestamp: CFAbsoluteTimeGetCurrent())
lightDataSeries.addValue(entry)
//DLog("Light (lux): \(light)")
if isLightDataSeriesEnabled {
// Save value
let entry = SensorDataSeries.Entry(value: light, timestamp: CFAbsoluteTimeGetCurrent())
lightDataSeries.addValue(entry)
//DLog("Light (lux): \(light)")
}
// Send to delegate
if let lightDelegate = lightDelegate {
@ -489,20 +476,20 @@ class AdafruitBoard {
switch response {
case let .success(value, uuid):
var adjustedAcceleration = value
if accelerometerAutoAdjustOrientation {
if model == .clue_nRF52840 { // Clue has the accelerometer in the back
adjustedAcceleration.x = -value.x
adjustedAcceleration.z = -value.z
}
}
/*
// Save value
let entry = SensorDataSeries.Entry(value: adjustedAcceleration, timestamp: CFAbsoluteTimeGetCurrent())
accelerometerDataSeries.addValue(entry)
//DLog("Accelerometer x: \(adjustedAcceleration.x), y: \(adjustedAcceleration.y) z: \(adjustedAcceleration.z)")
*/
if isAccelerometerDataSeriesEnabled {
// Save value
let entry = SensorDataSeries.Entry(value: adjustedAcceleration, timestamp: CFAbsoluteTimeGetCurrent())
accelerometerDataSeries.addValue(entry)
//DLog("Accelerometer x: \(adjustedAcceleration.x), y: \(adjustedAcceleration.y) z: \(adjustedAcceleration.z)")
}
// Send to delegate
if let accelerometerDelegate = accelerometerDelegate {
@ -525,10 +512,13 @@ class AdafruitBoard {
private func receiveTemperatureData(response: Result<(Float, UUID), Error>) {
switch response {
case let .success(value, uuid):
// Save value
let entry = SensorDataSeries.Entry(value: value, timestamp: CFAbsoluteTimeGetCurrent())
temperatureDataSeries.addValue(entry)
//DLog("Temperature (ºC): \(temperature)")
if isTemperatureDataSeriesEnabled {
// Save value
let entry = SensorDataSeries.Entry(value: value, timestamp: CFAbsoluteTimeGetCurrent())
temperatureDataSeries.addValue(entry)
//DLog("Temperature (ºC): \(temperature)")
}
// Send to delegate
if let temperatureDelegate = temperatureDelegate {
@ -551,10 +541,13 @@ class AdafruitBoard {
private func receiveHumidityData(response: Result<(Float, UUID), Error>) {
switch response {
case let .success(value, uuid):
// Save value
let entry = SensorDataSeries.Entry(value: value, timestamp: CFAbsoluteTimeGetCurrent())
humidityDataSeries.addValue(entry)
//DLog("Humidity: \(humidity)%")
if isHumidityDataSeriesEnabled {
// Save value
let entry = SensorDataSeries.Entry(value: value, timestamp: CFAbsoluteTimeGetCurrent())
humidityDataSeries.addValue(entry)
//DLog("Humidity: \(humidity)%")
}
// Send to delegate
if let humidityDelegate = humidityDelegate {
@ -577,10 +570,13 @@ class AdafruitBoard {
private func receiveBarometricPressureData(response: Result<(Float, UUID), Error>) {
switch response {
case let .success(value, uuid):
// Save value
let entry = SensorDataSeries.Entry(value: value, timestamp: CFAbsoluteTimeGetCurrent())
barometricPressureDataSeries.addValue(entry)
//DLog("Pressure: \(pressure)hPa")
if isBarometricPressureDataSeriesEnabled {
// Save value
let entry = SensorDataSeries.Entry(value: value, timestamp: CFAbsoluteTimeGetCurrent())
barometricPressureDataSeries.addValue(entry)
//DLog("Pressure: \(pressure)hPa")
}
// Send to delegate
if let barometricPressureDelegate = barometricPressureDelegate {
@ -603,11 +599,14 @@ class AdafruitBoard {
private func receiveSoundData(response: Result<([Double], UUID), Error>) {
switch response {
case let .success(amplitudesPerChannel, uuid):
// Save value
if let amplitude = amplitudesPerChannel.first, !amplitude.isNaN {
let entry = SensorDataSeries.Entry(value: Float(amplitude), timestamp: CFAbsoluteTimeGetCurrent())
soundAmplitudeDataSeries.addValue(entry)
//DLog("Amplitude: \(amplitude)dBFS")
if isSoundAmplitudePressureDataSeriesEnabled {
// Save value
if let amplitude = amplitudesPerChannel.first, !amplitude.isNaN {
let entry = SensorDataSeries.Entry(value: Float(amplitude), timestamp: CFAbsoluteTimeGetCurrent())
soundAmplitudeDataSeries.addValue(entry)
//DLog("Amplitude: \(amplitude)dBFS")
}
}
// Send to delegate
@ -631,11 +630,14 @@ class AdafruitBoard {
private func receiveGyroscopeData(response: Result<(BlePeripheral.GyroscopeValue, UUID), Error>) {
switch response {
case let .success(value, uuid):
// Save value
let entry = SensorDataSeries.Entry(value: value, timestamp: CFAbsoluteTimeGetCurrent())
gyroscopeDataSeries.addValue(entry)
DLog("Gyroscope x: \(value.x), y: \(value.y) z: \(value.z)")
if isGyroscopeDataSeriesEnabled {
// Save value
let entry = SensorDataSeries.Entry(value: value, timestamp: CFAbsoluteTimeGetCurrent())
gyroscopeDataSeries.addValue(entry)
DLog("Gyroscope x: \(value.x), y: \(value.y) z: \(value.z)")
}
// Send to delegate
if let gyroscopeDelegate = gyroscopeDelegate {
DispatchQueue.main.async { // Delegates are called in the main thread
@ -657,21 +659,30 @@ class AdafruitBoard {
private func receiveQuaternionData(response: Result<(BlePeripheral.QuaternionValue, UUID), Error>) {
switch response {
case let .success(value, uuid):
// Save value
let entry = SensorDataSeries.Entry(value: value, timestamp: CFAbsoluteTimeGetCurrent())
quaternionDataSeries.addValue(entry)
//DLog("Quaternion qx: \(value.qx), qy: \(value.qy) qz: \(value.qz) qw: \(value.qw)")
var adjustedQuaternion = value
if quaternionAutoAdjustOrientation {
if model == .clue_nRF52840 { // Clue has the quaternion sensor in the back
adjustedQuaternion = QuaternionUtils.quaternionRotated(quaternion: value, angle: .pi, axis: (x: Float(0), y: Float(1), z: Float(0)))
}
}
if isQuaternioDataSeriesEnabled {
// Save value
let entry = SensorDataSeries.Entry(value: adjustedQuaternion, timestamp: CFAbsoluteTimeGetCurrent())
quaternionDataSeries.addValue(entry)
//DLog("Quaternion qx: \(value.qx), qy: \(value.qy) qz: \(value.qz) qw: \(value.qw)")
}
// Send to delegate
if let quaternionDelegate = quaternionDelegate {
DispatchQueue.main.async { // Delegates are called in the main thread
quaternionDelegate.adafruitQuaternionReceived(value)
quaternionDelegate.adafruitQuaternionReceived(adjustedQuaternion)
}
}
// Send notification
NotificationCenter.default.post(name: .didReceiveQuaternionData, object: nil, userInfo: [
NotificationUserInfoKey.value.rawValue: value,
NotificationUserInfoKey.value.rawValue: adjustedQuaternion,
NotificationUserInfoKey.uuid.rawValue: uuid
])

View file

@ -10,9 +10,8 @@ import Foundation
import SceneKit
struct QuaternionUtils {
static func quaternionToEuler(quaternion q: BlePeripheral.QuaternionValue) -> SCNVector3 {
let eurlerAngles = quaternionToEuler(x: q.qx, y: q.qy, z: q.qz, w: q.qw)
return SCNVector3(eurlerAngles.x, eurlerAngles.y, eurlerAngles.z)
static func quaternionToEuler(quaternion q: BlePeripheral.QuaternionValue) -> (x: Float, y: Float, z: Float) {
return quaternionToEuler(x: q.x, y: q.y, z: q.z, w: q.w)
}
static func quaternionToEuler(x: Float, y: Float, z: Float, w: Float) -> (x: Float, y: Float, z: Float) {
@ -22,4 +21,13 @@ struct QuaternionUtils {
return (pitch, yaw, roll)
}
static func quaternionRotated(quaternion q: BlePeripheral.QuaternionValue, angle: Float, axis: (x: Float, y: Float, z: Float)) -> BlePeripheral.QuaternionValue {
let quaternion = simd_quatf(ix: q.x, iy: q.y, iz: q.z, r: q.w)
let rotationYQuaternion = simd_quatf(angle: angle, axis: simd_float3(axis.x, axis.y, axis.z))
let result = quaternion * rotationYQuaternion
let vector = result.vector
return BlePeripheral.QuaternionValue(x: vector.x, y: vector.y, z: vector.z, w: vector.w)
}
}

View file

@ -74,7 +74,7 @@ class AccelerometerViewController: ModuleViewController {
//DLog("Euler: pitch: \(eulerAngles.x) yaw: \(eulerAngles.y) roll: \(eulerAngles.z)")
// Update circuit model orientation
SCNTransaction.animationDuration = BlePeripheral.kAdafruitAccelerometerDefaultPeriod
SCNTransaction.animationDuration = BlePeripheral.kAdafruitSensorDefaultPeriod
circuitNode?.eulerAngles = eulerAngles
// Update panel

View file

@ -97,7 +97,7 @@ class BarometricPressureViewController: ModuleViewController {
//testAngle = testAngle + 2
UIView.animate(withDuration: BlePeripheral.kAdafruitBarometricPressureDefaultPeriod, delay: 0, options: .curveLinear, animations: {
UIView.animate(withDuration: BlePeripheral.kAdafruitSensorDefaultPeriod, delay: 0, options: .curveLinear, animations: {
self.handImageView.transform = CGAffineTransform(rotationAngle: CGFloat(angle))
//self.handImageView.transform = CGAffineTransform(rotationAngle: CGFloat(self.testAngle * .pi / 180))
}, completion: nil)

View file

@ -151,37 +151,37 @@ class HomeViewController: UIViewController {
guard let board = AdafruitBoardsManager.shared.currentBoard else { return result }
if board.isNeopixelsAvailable {
if board.isNeopixelsEnabled {
result.append(.neopixels)
}
if board.isLightAvailable {
if board.isLightEnabled {
result.append(.light)
}
if board.isButtonsAvailable {
if board.isButtonsEnabled {
result.append(.button)
}
if board.isToneGeneratorAvailable {
if board.isToneGeneratorEnabled {
result.append(.tone)
}
if (!board.isQuaternionAvailable || Config.isDebugEnabled) && board.isAccelerometerAvailable {
if (!board.isQuaternionEnabled || Config.isDebugEnabled) && board.isAccelerometerEnabled {
result.append(.accelerometer)
}
if board.isQuaternionAvailable {
if board.isQuaternionEnabled {
result.append(.quaternion)
}
if board.isTemperatureAvailable {
if board.isTemperatureEnabled {
result.append(.temperature)
}
if board.isHumidityAvailable {
if board.isHumidityEnabled {
result.append(.humidity)
}
if board.isBarometricPressureAvailable {
if board.isBarometricPressureEnabled {
result.append(.pressure)
}
if board.isSoundAvailable {
if board.isSoundEnabled {
result.append(.sound)
}
if board.isAccelerometerAvailable && board.isButtonsAvailable {
if board.isAccelerometerEnabled && board.isButtonsEnabled {
result.append(.puppet)
}
return result

View file

@ -86,7 +86,7 @@ class HumidityViewController: ModuleViewController {
//DLog("progress: \(adjustedValue)")
let height = humidityFillImageView.bounds.height * CGFloat(adjustedValue)
UIView.animate(withDuration: BlePeripheral.kAdafruitHumidityDefaultPeriod, delay: 0, options: .curveLinear, animations: {
UIView.animate(withDuration: BlePeripheral.kAdafruitSensorDefaultPeriod, delay: 0, options: .curveLinear, animations: {
self.fillMaskView.frame = CGRect(x: 0, y: self.humidityFillImageView.bounds.height - height, width: self.humidityFillImageView.bounds.width, height: height)
})
}

View file

@ -44,7 +44,7 @@ class LightSensorPanelViewController: ModulePanelViewController {
//DLog("progress: \(adjustedValue)")
NSLayoutConstraint.setMultiplier(multiplier: CGFloat(adjustedValue), constraint: &self.maskViewWidthConstraint)
UIView.animate(withDuration: BlePeripheral.kAdafruitLightDefaultPeriod, delay: 0, options: .curveLinear, animations: {
UIView.animate(withDuration: BlePeripheral.kAdafruitSensorDefaultPeriod, delay: 0, options: .curveLinear, animations: {
self.scaleImageView.layoutIfNeeded()
})
}

View file

@ -253,7 +253,7 @@ class PuppetViewController: UIViewController {
// Update sparky rotation (only if the intro animation is not currently playing)
if !isPlayingIntroAnimation {
SCNTransaction.animationDuration = BlePeripheral.kAdafruitAccelerometerDefaultPeriod
SCNTransaction.animationDuration = BlePeripheral.kAdafruitSensorDefaultPeriod
let accelAngleX = atan2(acceleration.y, acceleration.z)
filteredAccelAngleX.update(newValue: accelAngleX)

View file

@ -36,12 +36,13 @@ class QuaternionPanelViewController: ModulePanelViewController {
quaternionEulerAnglesTitleLabel.text = localizationManager.localizedString("quaternion_panel_eulerangles_title")
}
func accelerationReceived(quaternion: BlePeripheral.QuaternionValue, eulerAngles: SCNVector3) {
func accelerationReceived(quaternion: simd_quatf, eulerAngles: simd_float3) {
quaternionXLabel.text = String(format: "%.1f", quaternion.qx)
quaternionYLabel.text = String(format: "%.1f", quaternion.qy)
quaternionZLabel.text = String(format: "%.1f", quaternion.qz)
quaternionWLabel.text = String(format: "%.1f", quaternion.qw)
let quatVector = quaternion.vector
quaternionXLabel.text = String(format: "%.1f", quatVector.x)
quaternionYLabel.text = String(format: "%.1f", quatVector.y)
quaternionZLabel.text = String(format: "%.1f", quatVector.z)
quaternionWLabel.text = String(format: "%.1f", quatVector.w)
let xDeg = eulerAngles.x * 180 / .pi
let yDeg = eulerAngles.y * 180 / .pi

View file

@ -17,8 +17,8 @@ class QuaternionViewController: ModuleViewController {
@IBOutlet weak var sceneView: SCNView!
// Data
private var quaternion = BlePeripheral.QuaternionValue(qx: 0, qy: 0, qz: 0, qw: 1)
private var circuitNode: SCNNode?
private var quaternion = BlePeripheral.QuaternionValue(x: 0, y: 0, z: 0, w: 1)
private var boardNode: SCNNode?
private var valuesPanelViewController: QuaternionPanelViewController!
// MARK: - Lifecycle
@ -30,7 +30,7 @@ class QuaternionViewController: ModuleViewController {
// Load scene
if let scene = AdafruitBoardsManager.shared.currentBoard?.assetScene {
circuitNode = scene.rootNode.childNode(withName: "root", recursively: false)!
boardNode = scene.rootNode.childNode(withName: "root", recursively: false)!
// Setup scene
sceneView.scene = scene
@ -68,16 +68,19 @@ class QuaternionViewController: ModuleViewController {
// MARK: - UI
private func updateValueUI() {
// Calculate Euler Angles
let eulerAngles = QuaternionUtils.quaternionToEuler(quaternion: quaternion)
//DLog("Euler: pitch: \(eulerAngles.x) yaw: \(eulerAngles.y) roll: \(eulerAngles.z)")
// Update circuit model orientation
SCNTransaction.animationDuration = BlePeripheral.kAdafruitQuaternionDefaultPeriod
circuitNode?.eulerAngles = eulerAngles
SCNTransaction.animationDuration = BlePeripheral.kAdafruitSensorDefaultPeriod
// let scnQuaternion = SCNQuaternion(quaternion.qx, quaternion.qy, quaternion.qz, quaternion.qw)
let scnQuaternion = simd_quatf(ix: quaternion.x, iy: quaternion.y, iz: quaternion.z, r: quaternion.w)
//boardNode?.orientation = scnQuaternion
boardNode?.simdOrientation = scnQuaternion
// Update panel
valuesPanelViewController.accelerationReceived(quaternion: self.quaternion, eulerAngles: eulerAngles)
let (x, y, z) = QuaternionUtils.quaternionToEuler(quaternion: quaternion)
let eulerAngles = simd_float3(x, y, z)
//DLog("Euler: pitch: \(eulerAngles.xquaternionToEuler) yaw: \(eulerAngles.y) roll: \(eulerAngles.z)")
valuesPanelViewController.accelerationReceived(quaternion: scnQuaternion, eulerAngles: eulerAngles)
}
}